Skip to content

Commit cedf49b

Browse files
authored
Add option to add caching library through the server SDK (#235)
1 parent 3c2a55f commit cedf49b

3 files changed

Lines changed: 107 additions & 25 deletions

File tree

extensions/Bitwarden.Server.Sdk/src/Content/HostBuilderExtensions.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
using OpenTelemetry.Trace;
1010
using OpenTelemetry.Resources;
1111
#endif
12+
#if BIT_INCLUDE_CACHING
13+
using Bitwarden.Server.Sdk.Caching;
14+
#endif
1215

1316
namespace Microsoft.Extensions.Hosting;
1417

@@ -44,6 +47,10 @@ public static TBuilder UseBitwardenSdk<TBuilder>(this TBuilder builder)
4447
builder.Services.AddBitwardenAuthentication();
4548
#endif
4649

50+
#if BIT_INCLUDE_CACHING
51+
builder.Services.AddBitwardenCaching();
52+
#endif
53+
4754
return builder;
4855
}
4956

@@ -83,6 +90,13 @@ public static IHostBuilder UseBitwardenSdk(this IHostBuilder hostBuilder)
8390
});
8491
#endif
8592

93+
#if BIT_INCLUDE_CACHING
94+
hostBuilder.ConfigureServices((_, services) =>
95+
{
96+
services.AddBitwardenCaching();
97+
});
98+
#endif
99+
86100
return hostBuilder;
87101
}
88102

@@ -176,6 +190,10 @@ private static void AddMetrics(
176190

177191
metrics.AddMeter("Bitwarden.*");
178192
metrics.AddMeter("Bit.*");
193+
194+
#if BIT_INCLUDE_CACHING
195+
metrics.AddFusionCacheInstrumentation();
196+
#endif
179197
})
180198
.WithTracing(tracing =>
181199
{
@@ -188,6 +206,10 @@ private static void AddMetrics(
188206
tracing.AddHttpClientInstrumentation();
189207
tracing.AddEntityFrameworkCoreInstrumentation();
190208
tracing.AddSqlClientInstrumentation();
209+
210+
#if BIT_INCLUDE_CACHING
211+
tracing.AddFusionCacheInstrumentation();
212+
#endif
191213
});
192214

193215
if (configuration.GetValue(OtelDebuggingConfigKey, false))

extensions/Bitwarden.Server.Sdk/src/Sdk/Sdk.targets

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
<!-- Authentication defaults to on -->
3232
<BitIncludeAuthentication Condition="'$(BitIncludeAuthentication)' == ''">true</BitIncludeAuthentication>
3333
<DefineConstants Condition="'$(BitIncludeAuthentication)' == 'true'">$(DefineConstants);BIT_INCLUDE_AUTHENTICATION</DefineConstants>
34+
<!-- Caching defaults to off -->
35+
<BitIncludeCaching Condition="'$(BitIncludeCaching)' == ''">false</BitIncludeCaching>
36+
<DefineConstants Condition="'$(BitIncludeCaching)' == 'true'">$(DefineConstants);BIT_INCLUDE_CACHING</DefineConstants>
3437
</PropertyGroup>
3538

3639
<ItemGroup Condition="'$(BitIncludeTelemetry)' == 'true'">
@@ -42,6 +45,9 @@
4245
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.14.0" />
4346
<PackageReference Include="OpenTelemetry.Instrumentation.SqlClient" Version="1.12.0-beta.3" />
4447

48+
<!-- Add the Fusion cache open telemetry library when telemetry and caching are being used. -->
49+
<PackageReference Condition="'$(BitIncludeCaching)' == 'true'" Include="ZiggyCreatures.FusionCache.OpenTelemetry" Version="2.5.0" />
50+
4551
<Compile Include="$(SdkContentRoot)/OtelDebuggingHostedService.cs" />
4652
</ItemGroup>
4753

@@ -52,4 +58,8 @@
5258
<ItemGroup Condition="'$(BitIncludeAuthentication)' == 'true'">
5359
<PackageReference Include="Bitwarden.Server.Sdk.Authentication" Version="0.6.0" />
5460
</ItemGroup>
61+
62+
<ItemGroup Condition="'$(BitIncludeCaching)' == 'true'">
63+
<PackageReference Include="Bitwarden.Server.Sdk.Caching" Version="0.1.0" />
64+
</ItemGroup>
5565
</Project>

extensions/Bitwarden.Server.Sdk/tests/Bitwarden.Server.Sdk.IntegrationTests/SdkTests.cs

Lines changed: 75 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Diagnostics;
12
using Microsoft.Build.Utilities.ProjectCreation;
23
using Microsoft.Extensions.Logging;
34

@@ -8,16 +9,22 @@ public class SdkTests : MSBuildTestBase
89
[Fact]
910
public void NoOverridingProperties_CanCompile()
1011
{
11-
ProjectCreator.Templates.SdkProject(out var result, out var buildOutput)
12-
.TryGetConstant("BIT_INCLUDE_TELEMETRY", out var hasTelementryConstant)
13-
.TryGetConstant("BIT_INCLUDE_FEATURES", out var hasFeaturesConstant)
14-
.TryGetConstant("BIT_INCLUDE_AUTHENTICATION", out var hasAuthenticationConstant);
12+
IEnumerable<(string Feature, bool DefaultValue)> featuresAndDefaults = [
13+
("TELEMETRY", true),
14+
("FEATURES", true),
15+
("AUTHENTICATION", true),
16+
("CACHING", false),
17+
];
18+
19+
var project = ProjectCreator.Templates.SdkProject(out var result, out var buildOutput);
1520

1621
Assert.True(result, buildOutput.GetConsoleLog());
1722

18-
Assert.True(hasTelementryConstant);
19-
Assert.True(hasFeaturesConstant);
20-
Assert.True(hasAuthenticationConstant);
23+
foreach (var (feature, expectedDefault) in featuresAndDefaults)
24+
{
25+
project.TryGetConstant($"BIT_INCLUDE_{feature}", out var actualValue);
26+
Assert.Equal(expectedDefault, actualValue);
27+
}
2128
}
2229

2330
[Fact]
@@ -123,6 +130,24 @@ public void FeaturesTurnedOn_CanUseFeatureService()
123130
Assert.True(result, buildOutput.GetConsoleLog());
124131
}
125132

133+
[Fact]
134+
public void CachingTurnedOn_CanUseFusionCache()
135+
{
136+
ProjectCreator.Templates.SdkProject(
137+
out var result,
138+
out var buildOutput,
139+
customAction: (project) =>
140+
{
141+
project.Property("BitIncludeCaching", bool.TrueString);
142+
},
143+
additional: """
144+
app.MapGet("/test", ([FromKeyedServices("Test")] ZiggyCreatures.Caching.Fusion.IFusionCache cache) => cache.GetOrSetAsync("Key", true));
145+
"""
146+
);
147+
148+
Assert.True(result, buildOutput.GetConsoleLog());
149+
}
150+
126151
[Fact]
127152
public void AuthenticationTurnedOff_CanCompile()
128153
{
@@ -138,34 +163,59 @@ public void AuthenticationTurnedOff_CanCompile()
138163
Assert.True(result, buildOutput.GetConsoleLog());
139164
}
140165

141-
public static TheoryData<bool, bool, bool> MatrixData
142-
=> new MatrixTheoryData<bool, bool, bool>([true, false], [true, false], [true, false]);
166+
public static TheoryData<string> PossibleVariantData()
167+
{
168+
string[] features = ["Telemetry", "Features", "Authentication", "Caching"];
169+
var totalCombinations = (int)Math.Pow(2, features.Length);
143170

144-
// There will be some variants that disallow the use of feature Y if feature X is not also enabled.
145-
// Use this set to exclude those known variants from being tested.
146-
public static HashSet<(bool, bool, bool)> ExcludedVariants => [];
171+
var theory = new TheoryData<string>();
147172

148-
[Theory, MemberData(nameof(MatrixData))]
149-
public void AllVariants_Work(bool includeTelemetry, bool includeFeatures, bool includeAuthentication)
150-
{
151-
if (ExcludedVariants.Contains((includeTelemetry, includeFeatures, includeAuthentication)))
173+
for (var i = 0; i < totalCombinations; i++)
174+
{
175+
var variant = new Dictionary<string, bool>();
176+
177+
for (var j = 0; j < features.Length; j++)
178+
{
179+
// Check if the j-th bit is set in i
180+
variant[features[j]] = (i & (1 << j)) != 0;
181+
}
182+
183+
// TODO: When there are variants that need to be skipped do so here but still add
184+
// a row with a skip message
185+
theory.Add(Serialize(variant));
186+
}
187+
188+
return theory;
189+
190+
// We serialize it into a simple string so that it can be easily viewed in test explorer
191+
static string Serialize(Dictionary<string, bool> features)
152192
{
153-
Assert.Skip($"""
154-
Excluded Variant Skipped:
155-
IncludeTelemetry = {includeTelemetry}
156-
IncludeFeatures = {includeFeatures}
157-
IncludeAuthentication = {includeAuthentication}
158-
""");
193+
return string.Join(',', features.Select(feature => $"{feature.Key}={feature.Value}"));
159194
}
195+
}
196+
197+
[Theory, MemberData(nameof(PossibleVariantData))]
198+
public void AllVariants_Work(string featureSets)
199+
{
200+
// Deserialize from simple string into dictionary
201+
var features = featureSets.Split(",")
202+
.Select(featureSet =>
203+
{
204+
var split = featureSet.Split("=");
205+
Debug.Assert(split.Length == 2, "Invalid format");
206+
return new KeyValuePair<string, bool>(split[0], bool.Parse(split[1]));
207+
})
208+
.ToDictionary();
160209

161210
ProjectCreator.Templates.SdkProject(
162211
out var result,
163212
out var buildOutput,
164213
customAction: (project) =>
165214
{
166-
project.Property("BitIncludeTelemetry", includeTelemetry.ToString());
167-
project.Property("BitIncludeFeatures", includeFeatures.ToString());
168-
project.Property("BitIncludeAuthentication", includeAuthentication.ToString());
215+
foreach (var feature in features)
216+
{
217+
project.Property($"BitInclude{feature.Key}", feature.Value.ToString());
218+
}
169219
}
170220
);
171221

0 commit comments

Comments
 (0)