diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml
new file mode 100644
index 00000000..11a1e86c
--- /dev/null
+++ b/.github/workflows/code-coverage.yml
@@ -0,0 +1,48 @@
+name: "Code Coverage"
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ main ]
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'csharp' ]
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ - name: Coverlet coverage test
+ uses: b3b00/coverlet-action@1.2.4
+ with:
+ testProject: 'src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj'
+ excludes: '[Arcus.Security.Tests.*]*,[Arcus.Security.Providers.*]*'
+ threshold: 80
+ output: 'lcov.info'
+ outputFormat: 'lcov'
+
+ - name: ReportGenerator
+ uses: danielpalme/ReportGenerator-GitHub-Action@5.1.13
+ if: always()
+ with:
+ reports: 'src/Arcus.Security.Tests.Unit/lcov.info'
+ targetdir: 'coveragereport'
+
+ - name: Upload coverage report artifact
+ uses: actions/upload-artifact@v2.2.3
+ if: always()
+ with:
+ name: CoverageReport
+ path: coveragereport
\ No newline at end of file
diff --git a/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs b/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs
index 6ba70ec2..50c36631 100644
--- a/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs
+++ b/src/Arcus.Security.Core/Extensions/ISecretProviderExtensions.Deprecated.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
using GuardNet;
@@ -10,6 +11,7 @@ namespace Arcus.Security.Core.Extensions
/// Extensions on the to retrieve several secret values based on configured allowed versions.
///
// ReSharper disable once InconsistentNaming
+ [ExcludeFromCodeCoverage]
public static class ISecretProviderExtensions
{
///
diff --git a/src/Arcus.Security.Providers.AzureKeyVault/KeyVaultSecretProvider.cs b/src/Arcus.Security.Providers.AzureKeyVault/KeyVaultSecretProvider.cs
index 3eab9c8d..71c37601 100644
--- a/src/Arcus.Security.Providers.AzureKeyVault/KeyVaultSecretProvider.cs
+++ b/src/Arcus.Security.Providers.AzureKeyVault/KeyVaultSecretProvider.cs
@@ -454,7 +454,7 @@ private TResponse InteractWithKeyVault(
}
throw new InvalidOperationException(
- "Old Azure Key Vault client does not support asynchronous operations, please use the new Azure Key Vault secret provider overloads that uses the new Azure SDK");
+ "Old Azure Key Vault client does not support synchronous operations, please use the new Azure Key Vault secret provider overloads that uses the new Azure SDK");
});
isSuccessful = true;
diff --git a/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj b/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj
index 383bdc4b..1de08105 100644
--- a/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj
+++ b/src/Arcus.Security.Tests.Unit/Arcus.Security.Tests.Unit.csproj
@@ -1,13 +1,21 @@
-
+
- net6.0;netcoreapp3.1
+ net6.0
false
CS0618
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/src/Arcus.Security.Tests.Unit/AzureFunctions/IFunctionsHostBuilderTests.cs b/src/Arcus.Security.Tests.Unit/AzureFunctions/IFunctionsHostBuilderTests.cs
index 17c91757..c9608b9e 100644
--- a/src/Arcus.Security.Tests.Unit/AzureFunctions/IFunctionsHostBuilderTests.cs
+++ b/src/Arcus.Security.Tests.Unit/AzureFunctions/IFunctionsHostBuilderTests.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Text;
using System.Threading.Tasks;
using Arcus.Security.Core;
using Arcus.Security.Core.Caching;
@@ -8,11 +6,11 @@
using Arcus.Security.Tests.Unit.Core.Stubs;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
using Xunit;
namespace Arcus.Security.Tests.Unit.AzureFunctions
{
+ // ReSharper disable once InconsistentNaming
public class IFunctionsHostBuilderTests
{
[Fact]
@@ -30,6 +28,21 @@ public async Task ConfigureSecretStore_WithoutSecretProviders_ThrowsException()
await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("ignored-key"));
}
+ [Fact]
+ public async Task ConfigureSecretStoreWithConfig_WithoutSecretProviders_ThrowsException()
+ {
+ // Arrange
+ var builder = new StubFunctionsHostBuilder();
+
+ // Act
+ builder.ConfigureSecretStore((context, config, stores) => { });
+
+ // Assert
+ IServiceProvider serviceProvider = builder.Build();
+ var secretProvider = serviceProvider.GetRequiredService();
+ await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("ignored-key"));
+ }
+
[Fact]
public async Task ConfigureSecretStore_WithoutFoundSecretProvider_ThrowsException()
{
@@ -46,6 +59,22 @@ public async Task ConfigureSecretStore_WithoutFoundSecretProvider_ThrowsExceptio
await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("ignored-key"));
}
+ [Fact]
+ public async Task ConfigureSecretStoreWithConfig_WithoutFoundSecretProvider_ThrowsException()
+ {
+ // Arrange
+ var builder = new StubFunctionsHostBuilder();
+ var emptyProvider = new InMemorySecretProvider();
+
+ // Act
+ builder.ConfigureSecretStore((context, config, stores) => stores.AddProvider(emptyProvider));
+
+ // Assert
+ IServiceProvider serviceProvider = builder.Build();
+ var secretProvider = serviceProvider.GetRequiredService();
+ await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("ignored-key"));
+ }
+
[Fact]
public async Task ConfigureSecretStore_WithoutFoundCachedProvider_ThrowsException()
{
diff --git a/src/Arcus.Security.Tests.Unit/CommandLine/SecretStoreBuilderExtensionsTests.cs b/src/Arcus.Security.Tests.Unit/CommandLine/SecretStoreBuilderExtensionsTests.cs
index 482e7215..4e0fb938 100644
--- a/src/Arcus.Security.Tests.Unit/CommandLine/SecretStoreBuilderExtensionsTests.cs
+++ b/src/Arcus.Security.Tests.Unit/CommandLine/SecretStoreBuilderExtensionsTests.cs
@@ -73,6 +73,52 @@ public void AddCommandLine_WithMutateSecretWithoutArguments_Fails()
// Assert
Assert.ThrowsAny(() => builder.Build());
}
+
+ [Fact]
+ public void AddCommandLine_WithMutateSecretWithArguments_Fails()
+ {
+ // Arrange
+ string secretName = "MySecret", expected = "P@ssw0rd";
+ var arguments = new[] {$"--{secretName}={expected}"};
+ var builder = new HostBuilder();
+
+ // Act
+ builder.ConfigureSecretStore((config, stores) =>
+ {
+ stores.AddCommandLine(arguments, mutateSecretName: name => name);
+ });
+
+ // Assert
+ using (IHost host = builder.Build())
+ {
+ var secretProvider = host.Services.GetRequiredService();
+ Assert.Equal(expected, secretProvider.GetSecret(secretName).Value);
+ Assert.Equal(expected, secretProvider.GetRawSecret(secretName));
+ }
+ }
+
+ [Fact]
+ public void AddCommandLine_WithMutateSecretWithArgumentsWithUnknownSecretName_Fails()
+ {
+ // Arrange
+ string secretName = "MySecret", expected = "P@ssw0rd";
+ var arguments = new[] {$"--{secretName}={expected}"};
+ var builder = new HostBuilder();
+
+ // Act
+ builder.ConfigureSecretStore((config, stores) =>
+ {
+ stores.AddCommandLine(arguments, mutateSecretName: name => name);
+ });
+
+ // Assert
+ using (IHost host = builder.Build())
+ {
+ var secretProvider = host.Services.GetRequiredService();
+ Assert.Throws(() => secretProvider.GetSecret("NotExisting"));
+ Assert.Throws(() => secretProvider.GetRawSecret("NotExisting"));
+ }
+ }
[Fact]
public void AddCommandLine_WithNameWithMutateSecretWithoutArguments_Fails()
diff --git a/src/Arcus.Security.Tests.Unit/Core/CriticalExceptionsTests.cs b/src/Arcus.Security.Tests.Unit/Core/CriticalExceptionsTests.cs
new file mode 100644
index 00000000..ca4a3138
--- /dev/null
+++ b/src/Arcus.Security.Tests.Unit/Core/CriticalExceptionsTests.cs
@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Arcus.Security.Core;
+using Arcus.Security.Tests.Unit.Core.Stubs;
+using Microsoft.Extensions.DependencyInjection;
+using Xunit;
+
+namespace Arcus.Security.Tests.Unit.Core
+{
+ public class CriticalExceptionsTests
+ {
+ [Fact]
+ public async Task GetSecret_WithThrownCriticalException_FailsWithCriticalException()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+
+ // Act
+ services.AddSecretStore(stores =>
+ {
+ stores.AddProvider(new SaboteurSecretProvider(new IOException("Something happened!")))
+ .AddCriticalException();
+ });
+
+ // Assert
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var secretProvider = serviceProvider.GetRequiredService();
+ Assert.Throws(() => secretProvider.GetSecret("Some.Secret"));
+ Assert.Throws(() => secretProvider.GetRawSecret("Some.Secret"));
+ await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("Some.Secret"));
+ await Assert.ThrowsAsync(() => secretProvider.GetRawSecretAsync("Some.Secret"));
+ }
+
+ [Fact]
+ public async Task GetSecret_WithThrownNonCriticalException_FailsWithSecretNotFoundException()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+
+ // Act
+ services.AddSecretStore(stores =>
+ {
+ stores.AddProvider(new SaboteurSecretProvider(new AccessViolationException("Something happened!")))
+ .AddCriticalException();
+ });
+
+ // Assert
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var secretProvider = serviceProvider.GetRequiredService();
+ Assert.Throws(() => secretProvider.GetSecret("Some.Secret"));
+ Assert.Throws(() => secretProvider.GetRawSecret("Some.Secret"));
+ await Assert.ThrowsAsync(() => secretProvider.GetSecretAsync("Some.Secret"));
+ await Assert.ThrowsAsync(() => secretProvider.GetRawSecretAsync("Some.Secret"));
+ }
+ }
+}
diff --git a/src/Arcus.Security.Tests.Unit/Core/Extensions/IHostBuilderExtensionsTests.cs b/src/Arcus.Security.Tests.Unit/Core/Extensions/IHostBuilderExtensionsTests.cs
index 23d66dcc..d6c33730 100644
--- a/src/Arcus.Security.Tests.Unit/Core/Extensions/IHostBuilderExtensionsTests.cs
+++ b/src/Arcus.Security.Tests.Unit/Core/Extensions/IHostBuilderExtensionsTests.cs
@@ -877,7 +877,7 @@ public void ConfigureSecretStore_WithDuplicateNames_FailsWhenRetrievingTypedCach
using (IHost host = builder.Build())
{
var store = host.Services.GetRequiredService();
- Assert.Throws(() => store.GetProvider(name));
+ Assert.Throws(() => store.GetCachedProvider(name));
}
}
diff --git a/src/Arcus.Security.Tests.Unit/Core/MutatedSecretNameCachedSecretProviderTests.cs b/src/Arcus.Security.Tests.Unit/Core/MutatedSecretNameCachedSecretProviderTests.cs
index de031941..517d8423 100644
--- a/src/Arcus.Security.Tests.Unit/Core/MutatedSecretNameCachedSecretProviderTests.cs
+++ b/src/Arcus.Security.Tests.Unit/Core/MutatedSecretNameCachedSecretProviderTests.cs
@@ -79,6 +79,26 @@ public async Task InvalidateSecret_WithMutation_Succeeds()
await provider.InvalidateSecretAsync("Arcus:KeyVault:Secret");
}
+ [Fact]
+ public void ConfigureSecretStore_WithDefault_FailsToRetrieveCacheConfiguration()
+ {
+ // Arrange
+ var builder = new HostBuilder();
+
+ // Act
+ builder.ConfigureSecretStore((config, stores) =>
+ {
+ stores.AddProvider(new InMemorySecretProvider());
+ });
+
+ // Assert
+ using (IHost host = builder.Build())
+ {
+ var provider = host.Services.GetRequiredService();
+ Assert.Throws(() => provider.Configuration);
+ }
+ }
+
[Fact]
public void CreateCachedProvider_WithoutImplementation_Throws()
{
diff --git a/src/Arcus.Security.Tests.Unit/Core/NamedSecretProviderTests.cs b/src/Arcus.Security.Tests.Unit/Core/NamedSecretProviderTests.cs
new file mode 100644
index 00000000..93585f30
--- /dev/null
+++ b/src/Arcus.Security.Tests.Unit/Core/NamedSecretProviderTests.cs
@@ -0,0 +1,34 @@
+using System;
+using Arcus.Security.Core;
+using Arcus.Security.Providers.AzureKeyVault;
+using Arcus.Security.Tests.Unit.Core.Stubs;
+using Microsoft.Extensions.DependencyInjection;
+using Xunit;
+
+namespace Arcus.Security.Tests.Unit.Core
+{
+ public class NamedSecretProviderTests
+ {
+ [Fact]
+ public void GetCachedProvider_WithWrongCastType_Fails()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+ var name = "TestProvider";
+
+ // Act
+ services.AddSecretStore(stores =>
+ {
+ stores.AddProvider(
+ new InMemoryCachedSecretProvider(("Secret.Name", "Secret.Value")),
+ options => options.Name = name);
+ });
+
+ // Assert
+ IServiceProvider serviceProvider = services.BuildServiceProvider();
+ var secretProvider = serviceProvider.GetRequiredService();
+ Assert.ThrowsAny(
+ () => secretProvider.GetCachedProvider(name));
+ }
+ }
+}
diff --git a/src/Arcus.Security.Tests.Unit/Core/SecretProviderCachingExtensionsTests.cs b/src/Arcus.Security.Tests.Unit/Core/SecretProviderCachingExtensionsTests.cs
index e8737ddf..bb84f270 100644
--- a/src/Arcus.Security.Tests.Unit/Core/SecretProviderCachingExtensionsTests.cs
+++ b/src/Arcus.Security.Tests.Unit/Core/SecretProviderCachingExtensionsTests.cs
@@ -2,6 +2,8 @@
using Arcus.Security.Tests.Unit.Core.Stubs;
using System;
using System.Threading.Tasks;
+using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.Options;
using Xunit;
namespace Arcus.Security.Tests.Unit.Core
@@ -9,18 +11,64 @@ namespace Arcus.Security.Tests.Unit.Core
public class SecretProviderCachingExtensionsTests
{
[Fact]
- public async Task SecretProviderCachingExtensions_TwoCallsWithinCacheInterval_ShouldGetSameValueTwice()
+ public async Task WithCachingTimeSpanMemoryCache_TwoCallsWithinCacheInterval_ShouldGetSameValueTwice()
{
// Arrange
- string secretKeyValue = Guid.NewGuid().ToString("N");
+ var secretKeyValue = Guid.NewGuid().ToString("N");
var testSecretProvider = new TestSecretProviderStub(secretKeyValue);
- string keyName = "MyValue";
+ var keyName = "MyValue";
+ var cache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
+
+ // Act
+ ICachedSecretProvider cachedSecretProvider = testSecretProvider.WithCaching(TimeSpan.FromSeconds(3), cache);
+ string firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
+
+ ChangeInternalCachedSecret(testSecretProvider);
+ string secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
+
+ // Assert
+ Assert.Equal(firstValue, secondValue);
+ Assert.Equal(1, testSecretProvider.CallsMadeSinceCreation);
+ }
+
+ [Fact]
+ public async Task WithCachingTimeSpanMemoryCache_TwoCallsOutsideCacheInterval_ShouldGetDifferentValue()
+ {
+ // Arrange
+ var secretKeyValue = Guid.NewGuid().ToString("N");
+ var testSecretProvider = new TestSecretProviderStub(secretKeyValue);
+ var keyName = "MyValue";
+ var cache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
+
+ // Act
+ ICachedSecretProvider cachedSecretProvider = testSecretProvider.WithCaching(TimeSpan.FromMilliseconds(100), cache);
+ string firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
+
+ await Task.Delay(TimeSpan.FromMilliseconds(150));
+ string newSecretValue = Guid.NewGuid().ToString("N");
+ ChangeInternalCachedSecret(testSecretProvider, newSecretValue);
+ string secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
+
+ // Assert
+ Assert.Equal(secretKeyValue, firstValue);
+ Assert.Equal(newSecretValue, secondValue);
+ Assert.Equal(2, testSecretProvider.CallsMadeSinceCreation);
+ }
+
+ [Fact]
+ public async Task WithCachingTimeSpan_TwoCallsWithinCacheInterval_ShouldGetSameValueTwice()
+ {
+ // Arrange
+ var secretKeyValue = Guid.NewGuid().ToString("N");
+ var testSecretProvider = new TestSecretProviderStub(secretKeyValue);
+ var keyName = "MyValue";
// Act
ICachedSecretProvider cachedSecretProvider = testSecretProvider.WithCaching(TimeSpan.FromSeconds(3));
- var firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
- testSecretProvider.SecretValue = Guid.NewGuid().ToString("N"); // Change actual value on the internal secret provider !
- var secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
+ string firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
+
+ ChangeInternalCachedSecret(testSecretProvider);
+ string secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
// Assert
Assert.Equal(firstValue, secondValue);
@@ -28,26 +76,56 @@ public async Task SecretProviderCachingExtensions_TwoCallsWithinCacheInterval_Sh
}
[Fact]
- public async Task SecretProviderCachingExtensions_TwoCallsOutsideCacheInterval_ShouldGetDifferentValue()
+ public async Task WithCachingTimeSpan_TwoCallsOutsideCacheInterval_ShouldGetDifferentValue()
{
// Arrange
- string secretKeyValue = Guid.NewGuid().ToString("N");
+ var secretKeyValue = Guid.NewGuid().ToString("N");
var testSecretProvider = new TestSecretProviderStub(secretKeyValue);
-
- string keyName = "MyValue";
+ var keyName = "MyValue";
// Act
ICachedSecretProvider cachedSecretProvider = testSecretProvider.WithCaching(TimeSpan.FromMilliseconds(100));
- var firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
+ string firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
+
await Task.Delay(TimeSpan.FromMilliseconds(150));
string newSecretValue = Guid.NewGuid().ToString("N");
- testSecretProvider.SecretValue = newSecretValue; // Change actual value on the internal secret provider !
- var secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
+ ChangeInternalCachedSecret(testSecretProvider, newSecretValue);
+ string secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
// Assert
Assert.Equal(secretKeyValue, firstValue);
Assert.Equal(newSecretValue, secondValue);
Assert.Equal(2, testSecretProvider.CallsMadeSinceCreation);
}
+
+ [Fact]
+ public async Task WithCachingDefault_TwoCallsWithinCacheInterval_ShouldGetSameValueTwice()
+ {
+ // Arrange
+ var secretKeyValue = Guid.NewGuid().ToString("N");
+ var testSecretProvider = new TestSecretProviderStub(secretKeyValue);
+ var keyName = "MyValue";
+
+ // Act
+ ICachedSecretProvider cachedSecretProvider = testSecretProvider.WithCaching();
+ string firstValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
+
+ ChangeInternalCachedSecret(testSecretProvider);
+ string secondValue = await cachedSecretProvider.GetRawSecretAsync(keyName);
+
+ // Assert
+ Assert.Equal(firstValue, secondValue);
+ Assert.Equal(1, testSecretProvider.CallsMadeSinceCreation);
+ }
+
+ private static void ChangeInternalCachedSecret(TestSecretProviderStub testSecretProvider)
+ {
+ ChangeInternalCachedSecret(testSecretProvider, Guid.NewGuid().ToString("N"));
+ }
+
+ private static void ChangeInternalCachedSecret(TestSecretProviderStub testSecretProvider, string secretValue)
+ {
+ testSecretProvider.SecretValue = secretValue;
+ }
}
}
diff --git a/src/Arcus.Security.Tests.Unit/Core/Stubs/SaboteurSecretProvider.cs b/src/Arcus.Security.Tests.Unit/Core/Stubs/SaboteurSecretProvider.cs
index 24e75e27..329f6f62 100644
--- a/src/Arcus.Security.Tests.Unit/Core/Stubs/SaboteurSecretProvider.cs
+++ b/src/Arcus.Security.Tests.Unit/Core/Stubs/SaboteurSecretProvider.cs
@@ -8,7 +8,7 @@ namespace Arcus.Security.Tests.Unit.Core.Stubs
///
/// Represents a that 'sabotage' the secret retrieval by throwing a user-defined exception.
///
- public class SaboteurSecretProvider: ISecretProvider
+ public class SaboteurSecretProvider: ISyncSecretProvider
{
private readonly Exception _exception;
@@ -48,5 +48,29 @@ public Task GetSecretAsync(string secretName)
{
throw _exception;
}
+
+ ///
+ /// Retrieves the secret value, based on the given name
+ ///
+ /// The name of the secret key
+ /// Returns the secret key.
+ /// Thrown when the is blank.
+ /// Thrown when the secret was not found, using the given name.
+ public string GetRawSecret(string secretName)
+ {
+ throw _exception;
+ }
+
+ ///
+ /// Retrieves the secret value, based on the given name
+ ///
+ /// The name of the secret key
+ /// Returns a that contains the secret key
+ /// Thrown when the is blank.
+ /// Thrown when the secret was not found, using the given name.
+ public Secret GetSecret(string secretName)
+ {
+ throw _exception;
+ }
}
}
diff --git a/src/Arcus.Security.Tests.Unit/Core/VersionedSecretTests.cs b/src/Arcus.Security.Tests.Unit/Core/VersionedSecretTests.cs
index a0525a7b..56a8830c 100644
--- a/src/Arcus.Security.Tests.Unit/Core/VersionedSecretTests.cs
+++ b/src/Arcus.Security.Tests.Unit/Core/VersionedSecretTests.cs
@@ -23,7 +23,8 @@ public async Task GetRawSecret_WithVersion_ReturnsAll()
var services = new ServiceCollection();
var secretName = "MySecret";
var amountOfVersions = 2;
- var inMemory = new InMemorySecretVersionProvider(secretName, "secretValue", amountOfVersions);
+ var secretValue = "secretValue";
+ var inMemory = new InMemorySecretVersionProvider(secretName, secretValue, amountOfVersions);
services.AddSecretStore(stores =>
{
stores.AddProvider(inMemory, options => options.AddVersionedSecret(secretName, amountOfVersions));
@@ -31,9 +32,17 @@ public async Task GetRawSecret_WithVersion_ReturnsAll()
IServiceProvider serviceProvider = services.BuildServiceProvider();
var secretProvider = serviceProvider.GetRequiredService();
+ var versionedProvider = (IVersionedSecretProvider) secretProvider;
- IEnumerable secretValues = await secretProvider.GetRawSecretsAsync(secretName);
- Assert.Equal(amountOfVersions, secretValues.Count());
+ AssertCollectionCount(await secretProvider.GetSecretsAsync(secretName), amountOfVersions, secret => Assert.Equal(secretValue, secret.Value));
+ AssertCollectionCount(await secretProvider.GetRawSecretsAsync(secretName), amountOfVersions, value => Assert.Equal(secretValue, value));
+ AssertCollectionCount(await versionedProvider.GetSecretsAsync(secretName, amountOfVersions), amountOfVersions, secret => Assert.Equal(secretValue, secret.Value));
+ AssertCollectionCount(await versionedProvider.GetRawSecretsAsync(secretName, amountOfVersions), amountOfVersions, value => Assert.Equal(secretValue, value));
+ }
+
+ private static void AssertCollectionCount(IEnumerable sequence, int assertionLength, Action assertion)
+ {
+ Assert.Collection(sequence, Enumerable.Repeat(assertion, assertionLength).ToArray());
}
[Fact]
diff --git a/src/Arcus.Security.Tests.Unit/KeyVault/KeyVaultSecretProviderTests.cs b/src/Arcus.Security.Tests.Unit/KeyVault/KeyVaultSecretProviderTests.cs
index 47499593..4e1bc79c 100644
--- a/src/Arcus.Security.Tests.Unit/KeyVault/KeyVaultSecretProviderTests.cs
+++ b/src/Arcus.Security.Tests.Unit/KeyVault/KeyVaultSecretProviderTests.cs
@@ -94,7 +94,7 @@ public async Task KeyVaultSecretProvider_GetsRawSecretAsync_AfterRetriedTooManyR
// Arrange
string expected = $"secret-value-{Guid.NewGuid()}";
string secretName = $"secret-name-{Guid.NewGuid()}";
- KeyVaultSecretProvider provider = CreateSecretProviderWithTooManyRequestSimulation(expected);
+ KeyVaultSecretProvider provider = CreateOldSecretProviderWithTooManyRequestSimulation(expected);
// Act
string actual = await provider.GetRawSecretAsync(secretName);
@@ -110,19 +110,19 @@ public async Task KeyVaultSecretProvider_GetsSecretAsync_AfterRetriedTooManyRequ
string expected = $"secret-value-{Guid.NewGuid()}";
string secretName = $"secret-name-{Guid.NewGuid()}";
DateTime expirationDate = DateTime.UtcNow;
- KeyVaultSecretProvider provider = CreateSecretProviderWithTooManyRequestSimulation(expected, expirationDate);
// Act
- Secret actual = await provider.GetSecretAsync(secretName);
+ KeyVaultSecretProvider provider = CreateOldSecretProviderWithTooManyRequestSimulation(expected, expirationDate);
// Assert
- Assert.NotNull(actual);
- Assert.Equal(expected, actual.Value);
- Assert.NotNull(actual.Version);
- Assert.Equal(expirationDate, actual.Expires);
+ Secret actualFromAsync = await provider.GetSecretAsync(secretName);
+ Assert.NotNull(actualFromAsync);
+ Assert.Equal(expected, actualFromAsync.Value);
+ Assert.NotNull(actualFromAsync.Version);
+ Assert.Equal(expirationDate, actualFromAsync.Expires);
}
- private static KeyVaultSecretProvider CreateSecretProviderWithTooManyRequestSimulation(string expected, DateTime? expirationDate = null)
+ private static KeyVaultSecretProvider CreateOldSecretProviderWithTooManyRequestSimulation(string expected, DateTime? expirationDate = null)
{
// Arrange
var keyVaultClient = new SimulatedKeyVaultClient(