diff --git a/Directory.Packages.props b/Directory.Packages.props index b856f939..384be972 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -43,9 +43,9 @@ - - - + + + diff --git a/global.json b/global.json index d8d11dbe..4e257725 100644 --- a/global.json +++ b/global.json @@ -3,5 +3,8 @@ "rollForward": "latestFeature", "version": "10.0.100", "allowPrerelease": false + }, + "test": { + "runner": "Microsoft.Testing.Platform" } } diff --git a/test/OpenFeature.E2ETests/OpenFeature.E2ETests.csproj b/test/OpenFeature.E2ETests/OpenFeature.E2ETests.csproj index 11120976..60c293f6 100644 --- a/test/OpenFeature.E2ETests/OpenFeature.E2ETests.csproj +++ b/test/OpenFeature.E2ETests/OpenFeature.E2ETests.csproj @@ -2,6 +2,7 @@ OpenFeature.E2ETests + Exe @@ -14,10 +15,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/OpenFeature.E2ETests/Steps/ExcludedTagsStep.cs b/test/OpenFeature.E2ETests/Steps/ExcludedTagsStep.cs index 1037c189..cac03e3b 100644 --- a/test/OpenFeature.E2ETests/Steps/ExcludedTagsStep.cs +++ b/test/OpenFeature.E2ETests/Steps/ExcludedTagsStep.cs @@ -11,6 +11,6 @@ public class ExcludedTagsStep [BeforeScenario] public static void BeforeScenario() { - Skip.If(true, "Tag is not supported"); + Assert.SkipWhen(true, "Tag is not supported"); } } diff --git a/test/OpenFeature.Hosting.Tests/Internal/FeatureLifecycleManagerTests.cs b/test/OpenFeature.Hosting.Tests/Internal/FeatureLifecycleManagerTests.cs index 2d379fc4..94bcf1f3 100644 --- a/test/OpenFeature.Hosting.Tests/Internal/FeatureLifecycleManagerTests.cs +++ b/test/OpenFeature.Hosting.Tests/Internal/FeatureLifecycleManagerTests.cs @@ -26,7 +26,7 @@ public async Task EnsureInitializedAsync_SetsProvider() // Act using var serviceProvider = services.BuildServiceProvider(); var lifecycleManager = new FeatureLifecycleManager(api, serviceProvider, NullLogger.Instance); - await lifecycleManager.EnsureInitializedAsync(); + await lifecycleManager.EnsureInitializedAsync(TestContext.Current.CancellationToken); // Assert var actualProvider = api.GetProvider(); @@ -53,7 +53,7 @@ public async Task EnsureInitializedAsync_SetsMultipleProvider() // Act using var serviceProvider = services.BuildServiceProvider(); var lifecycleManager = new FeatureLifecycleManager(api, serviceProvider, NullLogger.Instance); - await lifecycleManager.EnsureInitializedAsync(); + await lifecycleManager.EnsureInitializedAsync(TestContext.Current.CancellationToken); // Assert Assert.Equal(provider1, api.GetProvider("provider1")); @@ -80,7 +80,7 @@ public async Task EnsureInitializedAsync_AddsHooks() // Act using var serviceProvider = services.BuildServiceProvider(); var lifecycleManager = new FeatureLifecycleManager(api, serviceProvider, NullLogger.Instance); - await lifecycleManager.EnsureInitializedAsync(); + await lifecycleManager.EnsureInitializedAsync(TestContext.Current.CancellationToken); // Assert var actualHooks = api.GetHooks(); @@ -108,7 +108,7 @@ public async Task EnsureInitializedAsync_AddHandlers() // Act using var serviceProvider = services.BuildServiceProvider(); var lifecycleManager = new FeatureLifecycleManager(api, serviceProvider, NullLogger.Instance); - await lifecycleManager.EnsureInitializedAsync(); + await lifecycleManager.EnsureInitializedAsync(TestContext.Current.CancellationToken); // Assert Assert.True(hookExecuted); @@ -122,13 +122,13 @@ public async Task ShutdownAsync_ResetsApi() var provider = new NoOpFeatureProvider(); var api = Api.Instance; - await api.SetProviderAsync(provider); + await api.SetProviderAsync(provider, TestContext.Current.CancellationToken); api.AddHooks(new NoOpHook()); // Act using var serviceProvider = services.BuildServiceProvider(); var lifecycleManager = new FeatureLifecycleManager(api, serviceProvider, NullLogger.Instance); - await lifecycleManager.ShutdownAsync(); + await lifecycleManager.ShutdownAsync(TestContext.Current.CancellationToken); // Assert var actualProvider = api.GetProvider(); @@ -154,7 +154,7 @@ public async Task EnsureInitializedAsync_LogStartingInitialization() // Act using var serviceProvider = services.BuildServiceProvider(); var lifecycleManager = new FeatureLifecycleManager(api, serviceProvider, logger); - await lifecycleManager.EnsureInitializedAsync(); + await lifecycleManager.EnsureInitializedAsync(TestContext.Current.CancellationToken); // Assert var log = logger.LatestRecord; @@ -181,7 +181,7 @@ public async Task ShutdownAsync_LogShuttingDown() // Act using var serviceProvider = services.BuildServiceProvider(); var lifecycleManager = new FeatureLifecycleManager(api, serviceProvider, logger); - await lifecycleManager.ShutdownAsync(); + await lifecycleManager.ShutdownAsync(TestContext.Current.CancellationToken); // Assert var log = logger.LatestRecord; @@ -190,13 +190,13 @@ public async Task ShutdownAsync_LogShuttingDown() Assert.Equal(LogLevel.Information, log.Level); } - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { await Api.Instance.ShutdownAsync(); } // Make sure the singleton is cleared between tests - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { await Api.Instance.ShutdownAsync().ConfigureAwait(false); } diff --git a/test/OpenFeature.Hosting.Tests/OpenFeature.Hosting.Tests.csproj b/test/OpenFeature.Hosting.Tests/OpenFeature.Hosting.Tests.csproj index 88251769..d86f8641 100644 --- a/test/OpenFeature.Hosting.Tests/OpenFeature.Hosting.Tests.csproj +++ b/test/OpenFeature.Hosting.Tests/OpenFeature.Hosting.Tests.csproj @@ -2,6 +2,7 @@ OpenFeature.Hosting.Tests + Exe @@ -17,7 +18,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/OpenFeature.Hosting.Tests/Providers/Memory/FeatureBuilderExtensionsTests.cs b/test/OpenFeature.Hosting.Tests/Providers/Memory/FeatureBuilderExtensionsTests.cs index b36dc82d..b87f097a 100644 --- a/test/OpenFeature.Hosting.Tests/Providers/Memory/FeatureBuilderExtensionsTests.cs +++ b/test/OpenFeature.Hosting.Tests/Providers/Memory/FeatureBuilderExtensionsTests.cs @@ -48,7 +48,7 @@ public async Task AddInMemoryProvider_WithFlags_AddsProvider() Assert.NotNull(featureProvider); Assert.IsType(featureProvider); - var result = await featureProvider.ResolveBooleanValueAsync("feature1", false); + var result = await featureProvider.ResolveBooleanValueAsync("feature1", false, cancellationToken: TestContext.Current.CancellationToken); Assert.True(result.Value); } @@ -130,7 +130,7 @@ public async Task AddInMemoryProvider_WithDomainAndFlags_AddsProvider() Assert.IsType(featureProvider); var context = EvaluationContext.Builder().Set("group", "alpha").Build(); - var result = await featureProvider.ResolveBooleanValueAsync("feature2", false, context); + var result = await featureProvider.ResolveBooleanValueAsync("feature2", false, context, TestContext.Current.CancellationToken); Assert.True(result.Value); } @@ -178,7 +178,7 @@ public async Task AddInMemoryProvider_WithOptions_AddsProvider() Assert.NotNull(featureProvider); Assert.IsType(featureProvider); - var result = await featureProvider.ResolveBooleanValueAsync("new-feature", true); + var result = await featureProvider.ResolveBooleanValueAsync("new-feature", true, cancellationToken: TestContext.Current.CancellationToken); Assert.False(result.Value); } @@ -208,7 +208,7 @@ public async Task AddInMemoryProvider_WithDomainAndOptions_AddsProvider() Assert.NotNull(featureProvider); Assert.IsType(featureProvider); - var result = await featureProvider.ResolveBooleanValueAsync("new-feature", true); + var result = await featureProvider.ResolveBooleanValueAsync("new-feature", true, cancellationToken: TestContext.Current.CancellationToken); Assert.False(result.Value); } diff --git a/test/OpenFeature.IntegrationTests/FeatureFlagIntegrationTest.cs b/test/OpenFeature.IntegrationTests/FeatureFlagIntegrationTest.cs index 9638ff8c..d8271748 100644 --- a/test/OpenFeature.IntegrationTests/FeatureFlagIntegrationTest.cs +++ b/test/OpenFeature.IntegrationTests/FeatureFlagIntegrationTest.cs @@ -54,8 +54,8 @@ public async Task VerifyFeatureFlagBehaviorAcrossServiceLifetimesAsync(string us var requestUri = $"/features/{userId}/flags/{FeatureA}"; // Act - var response = await client.GetAsync(requestUri).ConfigureAwait(true); - var responseContent = await response.Content.ReadFromJsonAsync>().ConfigureAwait(true); + var response = await client.GetAsync(requestUri, TestContext.Current.CancellationToken).ConfigureAwait(true); + var responseContent = await response.Content.ReadFromJsonAsync>(cancellationToken: TestContext.Current.CancellationToken).ConfigureAwait(true); // Assert Assert.True(response.IsSuccessStatusCode, "Expected HTTP status code 200 OK."); @@ -85,7 +85,7 @@ public async Task VerifyLoggingHookIsRegisteredAsync() var requestUri = $"/features/{TestUserId}/flags/{FeatureA}"; // Act - var response = await client.GetAsync(requestUri).ConfigureAwait(true); + var response = await client.GetAsync(requestUri, TestContext.Current.CancellationToken).ConfigureAwait(true); var logs = logger.Collector.GetSnapshot(); // Assert @@ -120,7 +120,7 @@ public async Task VerifyHandlerIsRegisteredAsync() var requestUri = $"/features/{TestUserId}/flags/{FeatureA}"; // Act - var response = await client.GetAsync(requestUri).ConfigureAwait(true); + var response = await client.GetAsync(requestUri, TestContext.Current.CancellationToken).ConfigureAwait(true); // Assert Assert.True(response.IsSuccessStatusCode, "Expected HTTP status code 200 OK."); @@ -152,7 +152,7 @@ public async Task VerifyMultipleHandlersAreRegisteredAsync() var requestUri = $"/features/{TestUserId}/flags/{FeatureA}"; // Act - var response = await client.GetAsync(requestUri).ConfigureAwait(true); + var response = await client.GetAsync(requestUri, TestContext.Current.CancellationToken).ConfigureAwait(true); // Assert Assert.True(response.IsSuccessStatusCode, "Expected HTTP status code 200 OK."); @@ -191,7 +191,7 @@ public async Task VerifyHandlersAreRegisteredWithServiceProviderAsync() var requestUri = $"/features/{TestUserId}/flags/{FeatureA}"; // Act - var response = await client.GetAsync(requestUri).ConfigureAwait(true); + var response = await client.GetAsync(requestUri, TestContext.Current.CancellationToken).ConfigureAwait(true); // Assert Assert.True(response.IsSuccessStatusCode, "Expected HTTP status code 200 OK."); diff --git a/test/OpenFeature.IntegrationTests/OpenFeature.IntegrationTests.csproj b/test/OpenFeature.IntegrationTests/OpenFeature.IntegrationTests.csproj index 35d85dfd..da2ef563 100644 --- a/test/OpenFeature.IntegrationTests/OpenFeature.IntegrationTests.csproj +++ b/test/OpenFeature.IntegrationTests/OpenFeature.IntegrationTests.csproj @@ -2,6 +2,7 @@ net8.0;net9.0;net10.0 + Exe @@ -16,7 +17,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/OpenFeature.Providers.MultiProvider.Tests/MultiProviderEventTests.cs b/test/OpenFeature.Providers.MultiProvider.Tests/MultiProviderEventTests.cs index d41e91cf..a1f5eb22 100644 --- a/test/OpenFeature.Providers.MultiProvider.Tests/MultiProviderEventTests.cs +++ b/test/OpenFeature.Providers.MultiProvider.Tests/MultiProviderEventTests.cs @@ -38,7 +38,7 @@ public async Task InitializeAsync_OnSuccess_EmitsProviderReadyEvent() var multiProvider = CreateMultiProvider(_provider1, _provider2); // Act - await multiProvider.InitializeAsync(_context); + await multiProvider.InitializeAsync(_context, TestContext.Current.CancellationToken); // Assert var events = await ReadEvents(multiProvider.GetEventChannel()); @@ -54,7 +54,7 @@ public async Task InitializeAsync_OnProviderFailure_EmitsProviderErrorEvent() var multiProvider = CreateMultiProvider(failedProvider, _provider2); // Act & Assert - await Assert.ThrowsAsync(() => multiProvider.InitializeAsync(_context)); + await Assert.ThrowsAsync(() => multiProvider.InitializeAsync(_context, TestContext.Current.CancellationToken)); // Verify the error event was emitted var events = await ReadEvents(multiProvider.GetEventChannel()); @@ -70,7 +70,7 @@ public async Task EvaluateAsync_OnUnsupportedRunMode_EmitsProviderErrorEvent() _strategy.RunMode.Returns((RunMode)999); // Invalid run mode // Act - var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, false, _context); + var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, false, _context, TestContext.Current.CancellationToken); // Assert Assert.Equal(ErrorType.ProviderFatal, result.ErrorType); @@ -92,7 +92,7 @@ public async Task EvaluateAsync_OnGeneralException_EmitsProviderErrorEvent() .Throws(new InvalidOperationException("Evaluation failed")); // Act - var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, false, _context); + var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, false, _context, TestContext.Current.CancellationToken); // Assert Assert.Equal(ErrorType.General, result.ErrorType); @@ -119,7 +119,7 @@ public async Task HandleProviderEvent_OnConfigurationChanged_ReEmitsEventWithCor // Act - Simulate child provider emitting configuration changed event await EmitEventToProvider(_provider1, configEvent); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); // Assert var events = await ReadEvents(multiProvider.GetEventChannel()); @@ -138,7 +138,7 @@ public async Task HandleProviderEvent_OnProviderReady_EmitsMultiProviderReadyWhe // Act - Simulate both child providers becoming ready await EmitEventToProvider(_provider1, CreateEvent(ProviderEventTypes.ProviderReady)); await EmitEventToProvider(_provider2, CreateEvent(ProviderEventTypes.ProviderReady)); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); // Assert - Should emit MultiProvider ready event when all providers are ready var events = await ReadEvents(multiProvider.GetEventChannel(), expectedCount: 2); @@ -156,7 +156,7 @@ public async Task HandleProviderEvent_OnProviderError_EmitsMultiProviderErrorEve // Act - Simulate child provider emitting error event await EmitEventToProvider(_provider1, CreateEvent(ProviderEventTypes.ProviderError, ErrorType.ProviderFatal)); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); // Assert var events = await ReadEvents(multiProvider.GetEventChannel()); @@ -173,7 +173,7 @@ public async Task HandleProviderEvent_OnProviderStale_EmitsMultiProviderStaleEve // Act - Simulate child provider emitting stale event await EmitEventToProvider(_provider1, CreateEvent(ProviderEventTypes.ProviderStale)); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); // Assert var events = await ReadEvents(multiProvider.GetEventChannel()); @@ -190,7 +190,7 @@ public async Task HandleProviderEvent_OnSameStatus_DoesNotEmitEvent() // Act - Simulate child provider emitting ready event when MultiProvider is already ready await EmitEventToProvider(_provider1, CreateEvent(ProviderEventTypes.ProviderReady)); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); // Assert - Should not emit any events since status didn't change var events = await ReadEvents(multiProvider.GetEventChannel(), expectedCount: 0, timeoutMs: 300); @@ -202,15 +202,15 @@ public async Task MultipleProviders_WithStatusTransitions_EmitsCorrectAggregateE { // Arrange var multiProvider = CreateMultiProvider(_provider1, _provider2); - await multiProvider.InitializeAsync(_context); - await Task.Delay(50); + await multiProvider.InitializeAsync(_context, TestContext.Current.CancellationToken); + await Task.Delay(50, TestContext.Current.CancellationToken); // Act - Simulate one provider going to error state await EmitEventToProvider(_provider1, CreateEvent(ProviderEventTypes.ProviderError, ErrorType.General)); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); // Simulate the error provider recovering await EmitEventToProvider(_provider1, CreateEvent(ProviderEventTypes.ProviderReady)); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); // Assert - Should see: Init Ready -> Error -> Ready var events = await ReadEvents(multiProvider.GetEventChannel(), expectedCount: 3); @@ -233,7 +233,7 @@ public async Task HandleProviderEvent_WithEventMetadata_PropagatesMetadata() // Act await EmitEventToProvider(_provider1, eventPayload); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); // Assert var events = await ReadEvents(multiProvider.GetEventChannel()); @@ -247,14 +247,14 @@ public async Task ShutdownAsync_StopsEventProcessing() { // Arrange var multiProvider = CreateMultiProvider(_provider1); - await multiProvider.InitializeAsync(_context); + await multiProvider.InitializeAsync(_context, TestContext.Current.CancellationToken); // Act - await multiProvider.ShutdownAsync(); + await multiProvider.ShutdownAsync(TestContext.Current.CancellationToken); // Try to emit an event after shutdown - it should not be processed await EmitEventToProvider(_provider1, CreateEvent(ProviderEventTypes.ProviderReady)); - await Task.Delay(50); + await Task.Delay(50, TestContext.Current.CancellationToken); // Assert - Should not process any events after shutdown var events = await ReadEvents(multiProvider.GetEventChannel(), expectedCount: 0, timeoutMs: 300); @@ -267,10 +267,10 @@ public async Task ShutdownAsync_WithProviderFailures_ThrowsAggregateException() // Arrange var failingProvider = new TestProvider("failing", shutdownException: new InvalidOperationException("Shutdown failed")); var multiProvider = CreateMultiProvider(failingProvider, _provider2); - await multiProvider.InitializeAsync(_context); + await multiProvider.InitializeAsync(_context, TestContext.Current.CancellationToken); // Act & Assert - Should throw AggregateException due to provider shutdown failure - var exception = await Assert.ThrowsAsync(() => multiProvider.ShutdownAsync()); + var exception = await Assert.ThrowsAsync(() => multiProvider.ShutdownAsync(TestContext.Current.CancellationToken)); Assert.Contains("Failed to shutdown providers", exception.Message); } @@ -279,17 +279,17 @@ public async Task DisposeAsync_CleansUpEventProcessing() { // Arrange var multiProvider = CreateMultiProvider(_provider1); - await multiProvider.InitializeAsync(_context); + await multiProvider.InitializeAsync(_context, TestContext.Current.CancellationToken); // Act await multiProvider.DisposeAsync(); // Assert - Should not throw and should handle disposal gracefully - await Task.Delay(100); // Give time for any potential processing + await Task.Delay(100, TestContext.Current.CancellationToken); // Give time for any potential processing // Verify that subsequent operations on disposed provider throw await Assert.ThrowsAsync(() => - multiProvider.ResolveBooleanValueAsync(TestFlagKey, false)); + multiProvider.ResolveBooleanValueAsync(TestFlagKey, false, cancellationToken: TestContext.Current.CancellationToken)); } // Helper methods diff --git a/test/OpenFeature.Providers.MultiProvider.Tests/MultiProviderTests.cs b/test/OpenFeature.Providers.MultiProvider.Tests/MultiProviderTests.cs index 615b67c7..b8e0131b 100644 --- a/test/OpenFeature.Providers.MultiProvider.Tests/MultiProviderTests.cs +++ b/test/OpenFeature.Providers.MultiProvider.Tests/MultiProviderTests.cs @@ -119,7 +119,7 @@ public async Task ResolveBooleanValueAsync_CallsEvaluateAsync() .Returns(finalResult); // Act - var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, defaultValue, this._evaluationContext); + var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, defaultValue, this._evaluationContext, TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedDetails, result); @@ -142,7 +142,7 @@ public async Task ResolveStringValueAsync_CallsEvaluateAsync() .Returns(finalResult); // Act - var result = await multiProvider.ResolveStringValueAsync(TestFlagKey, defaultValue, this._evaluationContext); + var result = await multiProvider.ResolveStringValueAsync(TestFlagKey, defaultValue, this._evaluationContext, TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedDetails, result); @@ -163,7 +163,7 @@ public async Task InitializeAsync_WithAllSuccessfulProviders_InitializesAllProvi this._mockProvider2.InitializeAsync(this._evaluationContext, Arg.Any()).Returns(Task.CompletedTask); // Act - await multiProvider.InitializeAsync(this._evaluationContext); + await multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken); // Assert await this._mockProvider1.Received(1).InitializeAsync(this._evaluationContext, Arg.Any()); @@ -186,7 +186,7 @@ public async Task InitializeAsync_WithSomeFailingProviders_ThrowsAggregateExcept this._mockProvider2.InitializeAsync(this._evaluationContext, Arg.Any()).ThrowsAsync(expectedException); // Act & Assert - var exception = await Assert.ThrowsAsync(() => multiProvider.InitializeAsync(this._evaluationContext)); + var exception = await Assert.ThrowsAsync(() => multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken)); Assert.Contains("Failed to initialize providers", exception.Message); Assert.Contains(Provider2Name, exception.Message); Assert.Contains(expectedException, exception.InnerExceptions); @@ -208,7 +208,7 @@ public async Task ShutdownAsync_WithAllSuccessfulProviders_ShutsDownAllProviders this._mockProvider2.ShutdownAsync(Arg.Any()).Returns(Task.CompletedTask); // Act - await multiProvider.ShutdownAsync(); + await multiProvider.ShutdownAsync(TestContext.Current.CancellationToken); // Assert await this._mockProvider1.Received(1).ShutdownAsync(Arg.Any()); @@ -231,7 +231,7 @@ public async Task ShutdownAsync_WithFatalProvider_ShutsDownAllProviders() this._mockProvider2.ShutdownAsync(Arg.Any()).Returns(Task.CompletedTask); // Act - await multiProvider.ShutdownAsync(); + await multiProvider.ShutdownAsync(TestContext.Current.CancellationToken); // Assert await this._mockProvider1.Received(1).ShutdownAsync(Arg.Any()); @@ -255,7 +255,7 @@ public async Task ShutdownAsync_WithSomeFailingProviders_ThrowsAggregateExceptio this._mockProvider2.ShutdownAsync(Arg.Any()).ThrowsAsync(expectedException); // Act & Assert - var exception = await Assert.ThrowsAsync(() => multiProvider.ShutdownAsync()); + var exception = await Assert.ThrowsAsync(() => multiProvider.ShutdownAsync(TestContext.Current.CancellationToken)); Assert.Contains("Failed to shutdown providers", exception.Message); Assert.Contains(Provider2Name, exception.Message); Assert.Contains(expectedException, exception.InnerExceptions); @@ -292,7 +292,7 @@ public async Task ResolveDoubleValueAsync_CallsEvaluateAsync() .Returns(finalResult); // Act - var result = await multiProvider.ResolveDoubleValueAsync(TestFlagKey, defaultValue, this._evaluationContext); + var result = await multiProvider.ResolveDoubleValueAsync(TestFlagKey, defaultValue, this._evaluationContext, TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedDetails, result); @@ -315,7 +315,7 @@ public async Task ResolveIntegerValueAsync_CallsEvaluateAsync() .Returns(finalResult); // Act - var result = await multiProvider.ResolveIntegerValueAsync(TestFlagKey, defaultValue, this._evaluationContext); + var result = await multiProvider.ResolveIntegerValueAsync(TestFlagKey, defaultValue, this._evaluationContext, TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedDetails, result); @@ -337,7 +337,7 @@ public async Task ResolveStructureValueAsync_CallsEvaluateAsync() .Returns(finalResult); // Act - var result = await multiProvider.ResolveStructureValueAsync(TestFlagKey, defaultValue, this._evaluationContext); + var result = await multiProvider.ResolveStructureValueAsync(TestFlagKey, defaultValue, this._evaluationContext, TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedDetails, result); @@ -369,7 +369,7 @@ public async Task EvaluateAsync_WithSequentialMode_EvaluatesProvidersSequentiall .Returns(expectedDetails); // Act - var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, defaultValue, this._evaluationContext); + var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, defaultValue, this._evaluationContext, TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedDetails, result); @@ -404,7 +404,7 @@ public async Task EvaluateAsync_WithParallelMode_EvaluatesProvidersInParallel() .Returns(expectedDetails); // Act - var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, defaultValue, this._evaluationContext); + var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, defaultValue, this._evaluationContext, TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedDetails, result); @@ -423,7 +423,7 @@ public async Task EvaluateAsync_WithUnsupportedRunMode_ReturnsErrorDetails() this._mockStrategy.RunMode.Returns((RunMode)999); // Invalid enum value // Act & Assert - var details = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, defaultValue, this._evaluationContext); + var details = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, defaultValue, this._evaluationContext, TestContext.Current.CancellationToken); Assert.Equal(ErrorType.ProviderFatal, details.ErrorType); Assert.Equal(Reason.Error, details.Reason); Assert.Contains("Unsupported run mode", details.ErrorMessage); @@ -459,7 +459,7 @@ public async Task EvaluateAsync_WithStrategySkippingProvider_DoesNotCallSkippedP .Returns(expectedDetails); // Act - var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, defaultValue, this._evaluationContext); + var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, defaultValue, this._evaluationContext, TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedDetails, result); @@ -613,7 +613,7 @@ public async Task InitializeAsync_WithAllSuccessfulProviders_CompletesWithoutExc this._mockProvider3.InitializeAsync(this._evaluationContext, Arg.Any()).Returns(Task.CompletedTask); // Act & Assert - await multiProvider.InitializeAsync(this._evaluationContext); + await multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken); // Verify all providers were called await this._mockProvider1.Received(1).InitializeAsync(this._evaluationContext, Arg.Any()); @@ -639,7 +639,7 @@ public async Task ShutdownAsync_WithAllSuccessfulProviders_CompletesWithoutExcep this._mockProvider3.ShutdownAsync(Arg.Any()).Returns(Task.CompletedTask); // Act & Assert - await multiProvider.ShutdownAsync(); + await multiProvider.ShutdownAsync(TestContext.Current.CancellationToken); // Verify all providers were called await this._mockProvider1.Received(1).ShutdownAsync(Arg.Any()); @@ -757,7 +757,7 @@ public async Task InitializeAsync_AfterDispose_ShouldThrowObjectDisposedExceptio // Assert var exception = await Assert.ThrowsAsync(() => - multiProvider.InitializeAsync(this._evaluationContext)); + multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken)); Assert.Equal(nameof(MultiProvider), exception.ObjectName); } @@ -773,7 +773,7 @@ public async Task ShutdownAsync_AfterDispose_ShouldThrowObjectDisposedException( // Assert var exception = await Assert.ThrowsAsync(() => - multiProvider.ShutdownAsync()); + multiProvider.ShutdownAsync(TestContext.Current.CancellationToken)); Assert.Equal(nameof(MultiProvider), exception.ObjectName); } @@ -789,7 +789,7 @@ public async Task InitializeAsync_WhenAlreadyDisposed_DuringExecution_ShouldExit // Act & Assert await Assert.ThrowsAsync(() => - multiProvider.InitializeAsync(this._evaluationContext)); + multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken)); // Verify that the underlying provider was never called since the object was disposed await this._mockProvider1.DidNotReceive().InitializeAsync(Arg.Any(), Arg.Any()); @@ -807,7 +807,7 @@ public async Task ShutdownAsync_WhenAlreadyDisposed_DuringExecution_ShouldExitEa // Act & Assert await Assert.ThrowsAsync(() => - multiProvider.ShutdownAsync()); + multiProvider.ShutdownAsync(TestContext.Current.CancellationToken)); // Verify that the underlying provider was never called since the object was disposed await this._mockProvider1.DidNotReceive().ShutdownAsync(Arg.Any()); @@ -825,23 +825,23 @@ public async Task EvaluateAsync_AfterDispose_ShouldThrowObjectDisposedException( // Assert - All evaluate methods should throw ObjectDisposedException var boolException = await Assert.ThrowsAsync(() => - multiProvider.ResolveBooleanValueAsync(TestFlagKey, false)); + multiProvider.ResolveBooleanValueAsync(TestFlagKey, false, cancellationToken: TestContext.Current.CancellationToken)); Assert.Equal(nameof(MultiProvider), boolException.ObjectName); var stringException = await Assert.ThrowsAsync(() => - multiProvider.ResolveStringValueAsync(TestFlagKey, "default")); + multiProvider.ResolveStringValueAsync(TestFlagKey, "default", cancellationToken: TestContext.Current.CancellationToken)); Assert.Equal(nameof(MultiProvider), stringException.ObjectName); var intException = await Assert.ThrowsAsync(() => - multiProvider.ResolveIntegerValueAsync(TestFlagKey, 0)); + multiProvider.ResolveIntegerValueAsync(TestFlagKey, 0, cancellationToken: TestContext.Current.CancellationToken)); Assert.Equal(nameof(MultiProvider), intException.ObjectName); var doubleException = await Assert.ThrowsAsync(() => - multiProvider.ResolveDoubleValueAsync(TestFlagKey, 0.0)); + multiProvider.ResolveDoubleValueAsync(TestFlagKey, 0.0, cancellationToken: TestContext.Current.CancellationToken)); Assert.Equal(nameof(MultiProvider), doubleException.ObjectName); var structureException = await Assert.ThrowsAsync(() => - multiProvider.ResolveStructureValueAsync(TestFlagKey, new Value())); + multiProvider.ResolveStructureValueAsync(TestFlagKey, new Value(), cancellationToken: TestContext.Current.CancellationToken)); Assert.Equal(nameof(MultiProvider), structureException.ObjectName); } @@ -952,7 +952,7 @@ public async Task EvaluateAsync_WithProviderHooks_ExecutesHooksForEachProvider() var multiProvider = new MultiProvider(providerEntries, this._mockStrategy); // Act - var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, false, this._evaluationContext); + var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, false, this._evaluationContext, TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedValue, result.Value); @@ -1022,7 +1022,7 @@ public async Task EvaluateAsync_WithHookContextModification_IsolatesContextBetwe var multiProvider = new MultiProvider(providerEntries, this._mockStrategy); // Act - await multiProvider.ResolveBooleanValueAsync(TestFlagKey, false, this._evaluationContext); + await multiProvider.ResolveBooleanValueAsync(TestFlagKey, false, this._evaluationContext, TestContext.Current.CancellationToken); // Assert - Verify context isolation Assert.NotNull(capturedContext1); @@ -1079,7 +1079,7 @@ public async Task EvaluateAsync_WithHookError_HandlesErrorAndContinuesEvaluation var multiProvider = new MultiProvider(providerEntries, this._mockStrategy); // Act - var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, false, this._evaluationContext); + var result = await multiProvider.ResolveBooleanValueAsync(TestFlagKey, false, this._evaluationContext, TestContext.Current.CancellationToken); // Assert Assert.Equal(expectedValue, result.Value); diff --git a/test/OpenFeature.Providers.MultiProvider.Tests/MultiProviderTrackingTests.cs b/test/OpenFeature.Providers.MultiProvider.Tests/MultiProviderTrackingTests.cs index d0d9d3d5..7f703ada 100644 --- a/test/OpenFeature.Providers.MultiProvider.Tests/MultiProviderTrackingTests.cs +++ b/test/OpenFeature.Providers.MultiProvider.Tests/MultiProviderTrackingTests.cs @@ -32,7 +32,7 @@ public async Task Track_WithMultipleReadyProviders_CallsTrackOnAllReadyProviders }; var multiProvider = new MultiProvider(providerEntries, new FirstMatchStrategy()); - await multiProvider.InitializeAsync(this._evaluationContext); + await multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken); var trackingDetails = TrackingEventDetails.Builder().SetValue(99.99).Build(); @@ -68,7 +68,7 @@ public async Task Track_WithNullEvaluationContext_CallsTrackWithNullContext() }; var multiProvider = new MultiProvider(providerEntries, new FirstMatchStrategy()); - await multiProvider.InitializeAsync(this._evaluationContext); + await multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken); // Act multiProvider.Track(TestTrackingEventName); @@ -95,7 +95,7 @@ public async Task Track_WithNullTrackingDetails_CallsTrackWithNullDetails() }; var multiProvider = new MultiProvider(providerEntries, new FirstMatchStrategy()); - await multiProvider.InitializeAsync(this._evaluationContext); + await multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken); // Act multiProvider.Track(TestTrackingEventName, this._evaluationContext); @@ -131,7 +131,7 @@ public async Task Track_WhenProviderThrowsException_ContinuesWithOtherProviders( }; var multiProvider = new MultiProvider(providerEntries, new FirstMatchStrategy()); - await multiProvider.InitializeAsync(this._evaluationContext); + await multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken); // Manually set all providers to Ready status throwingProvider.Status.Returns(ProviderStatus.Ready); @@ -161,7 +161,7 @@ public async Task Track_WhenDisposed_ThrowsObjectDisposedException() }; var multiProvider = new MultiProvider(providerEntries, new FirstMatchStrategy()); - await multiProvider.InitializeAsync(this._evaluationContext); + await multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken); await multiProvider.DisposeAsync(); // Act & Assert @@ -198,7 +198,7 @@ public async Task Track_WithCustomStrategy_RespectsStrategyDecision() }; var multiProvider = new MultiProvider(providerEntries, customStrategy); - await multiProvider.InitializeAsync(this._evaluationContext); + await multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken); var trackingDetails = TrackingEventDetails.Builder().SetValue(99.99).Build(); @@ -233,7 +233,7 @@ public async Task Track_WithComplexTrackingDetails_PropagatesAllDetails() }; var multiProvider = new MultiProvider(providerEntries, new FirstMatchStrategy()); - await multiProvider.InitializeAsync(this._evaluationContext); + await multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken); var trackingDetails = TrackingEventDetails.Builder() .SetValue(199.99) @@ -285,7 +285,7 @@ public async Task Track_WhenInvalidTrackingEventName_DoesNotCallProviders(string }; var multiProvider = new MultiProvider(providerEntries, new FirstMatchStrategy()); - await multiProvider.InitializeAsync(this._evaluationContext); + await multiProvider.InitializeAsync(this._evaluationContext, TestContext.Current.CancellationToken); // Act & Assert multiProvider.Track(trackingEventName!, this._evaluationContext, TrackingEventDetails.Empty); diff --git a/test/OpenFeature.Providers.MultiProvider.Tests/OpenFeature.Providers.MultiProvider.Tests.csproj b/test/OpenFeature.Providers.MultiProvider.Tests/OpenFeature.Providers.MultiProvider.Tests.csproj index 1a7dae71..c790a5d7 100644 --- a/test/OpenFeature.Providers.MultiProvider.Tests/OpenFeature.Providers.MultiProvider.Tests.csproj +++ b/test/OpenFeature.Providers.MultiProvider.Tests/OpenFeature.Providers.MultiProvider.Tests.csproj @@ -2,6 +2,7 @@ OpenFeature.Providers.MultiProvider.Tests + Exe @@ -19,7 +20,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/OpenFeature.Tests/ClearOpenFeatureInstanceFixture.cs b/test/OpenFeature.Tests/ClearOpenFeatureInstanceFixture.cs index 7ef471e4..14850be9 100644 --- a/test/OpenFeature.Tests/ClearOpenFeatureInstanceFixture.cs +++ b/test/OpenFeature.Tests/ClearOpenFeatureInstanceFixture.cs @@ -2,15 +2,15 @@ namespace OpenFeature.Tests; public class ClearOpenFeatureInstanceFixture : IAsyncLifetime { - public Task InitializeAsync() + public ValueTask InitializeAsync() { Api.ResetApi(); - return Task.CompletedTask; + return ValueTask.CompletedTask; } // Make sure the singleton is cleared between tests - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { await Api.Instance.ShutdownAsync().ConfigureAwait(false); } diff --git a/test/OpenFeature.Tests/FeatureProviderTests.cs b/test/OpenFeature.Tests/FeatureProviderTests.cs index 8bea7037..8be88ac5 100644 --- a/test/OpenFeature.Tests/FeatureProviderTests.cs +++ b/test/OpenFeature.Tests/FeatureProviderTests.cs @@ -39,23 +39,23 @@ public async Task Provider_Must_Resolve_Flag_Values() var boolResolutionDetails = new ResolutionDetails(flagName, defaultBoolValue, ErrorType.None, NoOpProvider.ReasonNoOp, NoOpProvider.Variant); - Assert.Equivalent(boolResolutionDetails, await provider.ResolveBooleanValueAsync(flagName, defaultBoolValue)); + Assert.Equivalent(boolResolutionDetails, await provider.ResolveBooleanValueAsync(flagName, defaultBoolValue, cancellationToken: TestContext.Current.CancellationToken)); var integerResolutionDetails = new ResolutionDetails(flagName, defaultIntegerValue, ErrorType.None, NoOpProvider.ReasonNoOp, NoOpProvider.Variant); - Assert.Equivalent(integerResolutionDetails, await provider.ResolveIntegerValueAsync(flagName, defaultIntegerValue)); + Assert.Equivalent(integerResolutionDetails, await provider.ResolveIntegerValueAsync(flagName, defaultIntegerValue, cancellationToken: TestContext.Current.CancellationToken)); var doubleResolutionDetails = new ResolutionDetails(flagName, defaultDoubleValue, ErrorType.None, NoOpProvider.ReasonNoOp, NoOpProvider.Variant); - Assert.Equivalent(doubleResolutionDetails, await provider.ResolveDoubleValueAsync(flagName, defaultDoubleValue)); + Assert.Equivalent(doubleResolutionDetails, await provider.ResolveDoubleValueAsync(flagName, defaultDoubleValue, cancellationToken: TestContext.Current.CancellationToken)); var stringResolutionDetails = new ResolutionDetails(flagName, defaultStringValue, ErrorType.None, NoOpProvider.ReasonNoOp, NoOpProvider.Variant); - Assert.Equivalent(stringResolutionDetails, await provider.ResolveStringValueAsync(flagName, defaultStringValue)); + Assert.Equivalent(stringResolutionDetails, await provider.ResolveStringValueAsync(flagName, defaultStringValue, cancellationToken: TestContext.Current.CancellationToken)); var structureResolutionDetails = new ResolutionDetails(flagName, defaultStructureValue, ErrorType.None, NoOpProvider.ReasonNoOp, NoOpProvider.Variant); - Assert.Equivalent(structureResolutionDetails, await provider.ResolveStructureValueAsync(flagName, defaultStructureValue)); + Assert.Equivalent(structureResolutionDetails, await provider.ResolveStructureValueAsync(flagName, defaultStructureValue, cancellationToken: TestContext.Current.CancellationToken)); } [Fact] @@ -74,59 +74,52 @@ public async Task Provider_Must_ErrorType() var providerMock = Substitute.For(); const string testMessage = "An error message"; - providerMock.ResolveBooleanValueAsync(flagName, defaultBoolValue, Arg.Any()) - .Returns(new ResolutionDetails(flagName, defaultBoolValue, ErrorType.General, + providerMock.ResolveBooleanValueAsync(flagName, defaultBoolValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails(flagName, defaultBoolValue, ErrorType.General, NoOpProvider.ReasonNoOp, NoOpProvider.Variant, testMessage)); - providerMock.ResolveIntegerValueAsync(flagName, defaultIntegerValue, Arg.Any()) - .Returns(new ResolutionDetails(flagName, defaultIntegerValue, ErrorType.ParseError, + providerMock.ResolveIntegerValueAsync(flagName, defaultIntegerValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails(flagName, defaultIntegerValue, ErrorType.ParseError, NoOpProvider.ReasonNoOp, NoOpProvider.Variant, testMessage)); - providerMock.ResolveDoubleValueAsync(flagName, defaultDoubleValue, Arg.Any()) - .Returns(new ResolutionDetails(flagName, defaultDoubleValue, ErrorType.InvalidContext, + providerMock.ResolveDoubleValueAsync(flagName, defaultDoubleValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails(flagName, defaultDoubleValue, ErrorType.InvalidContext, NoOpProvider.ReasonNoOp, NoOpProvider.Variant, testMessage)); - providerMock.ResolveStringValueAsync(flagName, defaultStringValue, Arg.Any()) - .Returns(new ResolutionDetails(flagName, defaultStringValue, ErrorType.TypeMismatch, + providerMock.ResolveStringValueAsync(flagName, defaultStringValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails(flagName, defaultStringValue, ErrorType.TypeMismatch, NoOpProvider.ReasonNoOp, NoOpProvider.Variant, testMessage)); - providerMock.ResolveStructureValueAsync(flagName, defaultStructureValue, Arg.Any()) - .Returns(new ResolutionDetails(flagName, defaultStructureValue, ErrorType.FlagNotFound, + providerMock.ResolveStructureValueAsync(flagName, defaultStructureValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails(flagName, defaultStructureValue, ErrorType.FlagNotFound, NoOpProvider.ReasonNoOp, NoOpProvider.Variant, testMessage)); - providerMock.ResolveStructureValueAsync(flagName2, defaultStructureValue, Arg.Any()) - .Returns(new ResolutionDetails(flagName2, defaultStructureValue, ErrorType.ProviderNotReady, + providerMock.ResolveStructureValueAsync(flagName2, defaultStructureValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails(flagName2, defaultStructureValue, ErrorType.ProviderNotReady, NoOpProvider.ReasonNoOp, NoOpProvider.Variant, testMessage)); - providerMock.ResolveBooleanValueAsync(flagName2, defaultBoolValue, Arg.Any()) - .Returns(new ResolutionDetails(flagName2, defaultBoolValue, ErrorType.TargetingKeyMissing, + providerMock.ResolveBooleanValueAsync(flagName2, defaultBoolValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails(flagName2, defaultBoolValue, ErrorType.TargetingKeyMissing, NoOpProvider.ReasonNoOp, NoOpProvider.Variant)); - var boolRes = await providerMock.ResolveBooleanValueAsync(flagName, defaultBoolValue); + var boolRes = await providerMock.ResolveBooleanValueAsync(flagName, defaultBoolValue, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(ErrorType.General, boolRes.ErrorType); Assert.Equal(testMessage, boolRes.ErrorMessage); - var intRes = await providerMock.ResolveIntegerValueAsync(flagName, defaultIntegerValue); + var intRes = await providerMock.ResolveIntegerValueAsync(flagName, defaultIntegerValue, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(ErrorType.ParseError, intRes.ErrorType); Assert.Equal(testMessage, intRes.ErrorMessage); - var doubleRes = await providerMock.ResolveDoubleValueAsync(flagName, defaultDoubleValue); + var doubleRes = await providerMock.ResolveDoubleValueAsync(flagName, defaultDoubleValue, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(ErrorType.InvalidContext, doubleRes.ErrorType); Assert.Equal(testMessage, doubleRes.ErrorMessage); - var stringRes = await providerMock.ResolveStringValueAsync(flagName, defaultStringValue); + var stringRes = await providerMock.ResolveStringValueAsync(flagName, defaultStringValue, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(ErrorType.TypeMismatch, stringRes.ErrorType); Assert.Equal(testMessage, stringRes.ErrorMessage); - var structRes1 = await providerMock.ResolveStructureValueAsync(flagName, defaultStructureValue); + var structRes1 = await providerMock.ResolveStructureValueAsync(flagName, defaultStructureValue, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(ErrorType.FlagNotFound, structRes1.ErrorType); Assert.Equal(testMessage, structRes1.ErrorMessage); - var structRes2 = await providerMock.ResolveStructureValueAsync(flagName2, defaultStructureValue); + var structRes2 = await providerMock.ResolveStructureValueAsync(flagName2, defaultStructureValue, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(ErrorType.ProviderNotReady, structRes2.ErrorType); Assert.Equal(testMessage, structRes2.ErrorMessage); - var boolRes2 = await providerMock.ResolveBooleanValueAsync(flagName2, defaultBoolValue); + var boolRes2 = await providerMock.ResolveBooleanValueAsync(flagName2, defaultBoolValue, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(ErrorType.TargetingKeyMissing, boolRes2.ErrorType); Assert.Null(boolRes2.ErrorMessage); } diff --git a/test/OpenFeature.Tests/Hooks/LoggingHookTests.cs b/test/OpenFeature.Tests/Hooks/LoggingHookTests.cs index 5c27959b..70bad07a 100644 --- a/test/OpenFeature.Tests/Hooks/LoggingHookTests.cs +++ b/test/OpenFeature.Tests/Hooks/LoggingHookTests.cs @@ -22,7 +22,7 @@ public async Task BeforeAsync_Without_EvaluationContext_Generates_Debug_Log() var hook = new LoggingHook(logger, includeContext: false); // Act - await hook.BeforeAsync(context); + await hook.BeforeAsync(context, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(1, logger.Collector.Count); @@ -57,7 +57,7 @@ public async Task BeforeAsync_Without_EvaluationContext_Generates_Correct_Log_Me var hook = new LoggingHook(logger, includeContext: false); // Act - await hook.BeforeAsync(context); + await hook.BeforeAsync(context, cancellationToken: TestContext.Current.CancellationToken); // Assert var record = logger.LatestRecord; @@ -98,7 +98,7 @@ public async Task BeforeAsync_With_EvaluationContext_Generates_Correct_Log_Messa var hook = new LoggingHook(logger, includeContext: true); // Act - await hook.BeforeAsync(context); + await hook.BeforeAsync(context, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(1, logger.Collector.Count); @@ -130,7 +130,7 @@ public async Task BeforeAsync_With_No_EvaluationContext_Generates_Correct_Log_Me // Act var hook = new LoggingHook(logger, includeContext: true); - await hook.BeforeAsync(context); + await hook.BeforeAsync(context, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(1, logger.Collector.Count); @@ -168,7 +168,7 @@ public async Task ErrorAsync_Without_EvaluationContext_Generates_Error_Log() var exception = new Exception("Error within hook!"); // Act - await hook.ErrorAsync(context, exception); + await hook.ErrorAsync(context, exception, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(1, logger.Collector.Count); @@ -194,7 +194,7 @@ public async Task ErrorAsync_Without_EvaluationContext_Generates_Correct_Log_Mes var exception = new Exception("Error within hook!"); // Act - await hook.ErrorAsync(context, exception); + await hook.ErrorAsync(context, exception, cancellationToken: TestContext.Current.CancellationToken); // Assert var record = logger.LatestRecord; @@ -238,7 +238,7 @@ public async Task ErrorAsync_With_EvaluationContext_Generates_Correct_Log_Messag var exception = new Exception("Error within hook!"); // Act - await hook.ErrorAsync(context, exception); + await hook.ErrorAsync(context, exception, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(1, logger.Collector.Count); @@ -271,7 +271,7 @@ public async Task ErrorAsync_With_No_EvaluationContext_Generates_Correct_Log_Mes var exception = new Exception("Error within hook!"); // Act - await hook.ErrorAsync(context, exception); + await hook.ErrorAsync(context, exception, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(1, logger.Collector.Count); @@ -309,7 +309,7 @@ public async Task AfterAsync_Without_EvaluationContext_Generates_Debug_Log() var hook = new LoggingHook(logger, includeContext: false); // Act - await hook.AfterAsync(context, details); + await hook.AfterAsync(context, details, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(1, logger.Collector.Count); @@ -334,7 +334,7 @@ public async Task AfterAsync_Without_EvaluationContext_Generates_Correct_Log_Mes var hook = new LoggingHook(logger, includeContext: false); // Act - await hook.AfterAsync(context, details); + await hook.AfterAsync(context, details, cancellationToken: TestContext.Current.CancellationToken); // Assert var record = logger.LatestRecord; @@ -376,7 +376,7 @@ public async Task AfterAsync_With_EvaluationContext_Generates_Correct_Log_Messag var hook = new LoggingHook(logger, includeContext: true); // Act - await hook.AfterAsync(context, details); + await hook.AfterAsync(context, details, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(1, logger.Collector.Count); @@ -416,7 +416,7 @@ public async Task AfterAsync_With_No_EvaluationContext_Generates_Correct_Log_Mes var hook = new LoggingHook(logger, includeContext: true); // Act - await hook.AfterAsync(context, details); + await hook.AfterAsync(context, details, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(1, logger.Collector.Count); @@ -464,7 +464,7 @@ public async Task With_Structure_Type_In_Context_Returns_Qualified_Name_Of_Value var hook = new LoggingHook(logger, includeContext: true); // Act - await hook.AfterAsync(context, details); + await hook.AfterAsync(context, details, cancellationToken: TestContext.Current.CancellationToken); // Assert var record = logger.LatestRecord; @@ -507,7 +507,7 @@ public async Task Without_Domain_Returns_Missing() var hook = new LoggingHook(logger, includeContext: true); // Act - await hook.AfterAsync(context, details); + await hook.AfterAsync(context, details, cancellationToken: TestContext.Current.CancellationToken); // Assert var record = logger.LatestRecord; @@ -548,7 +548,7 @@ public async Task Without_Provider_Returns_Missing() var hook = new LoggingHook(logger, includeContext: true); // Act - await hook.AfterAsync(context, details); + await hook.AfterAsync(context, details, cancellationToken: TestContext.Current.CancellationToken); // Assert var record = logger.LatestRecord; @@ -589,7 +589,7 @@ public async Task Without_DefaultValue_Returns_Missing() var hook = new LoggingHook(logger, includeContext: true); // Act - await hook.AfterAsync(context, details); + await hook.AfterAsync(context, details, cancellationToken: TestContext.Current.CancellationToken); // Assert var record = logger.LatestRecord; @@ -630,7 +630,7 @@ public async Task Without_EvaluationContextValue_Returns_Nothing() var hook = new LoggingHook(logger, includeContext: true); // Act - await hook.AfterAsync(context, details); + await hook.AfterAsync(context, details, cancellationToken: TestContext.Current.CancellationToken); // Assert var record = logger.LatestRecord; diff --git a/test/OpenFeature.Tests/Hooks/MetricsHookTests.cs b/test/OpenFeature.Tests/Hooks/MetricsHookTests.cs index f1c3be3a..30fb46f0 100644 --- a/test/OpenFeature.Tests/Hooks/MetricsHookTests.cs +++ b/test/OpenFeature.Tests/Hooks/MetricsHookTests.cs @@ -20,9 +20,7 @@ public async Task After_Test() new ClientMetadata("my-client", "1.0"), new Metadata("my-provider"), evaluationContext); // Act - await metricsHook.AfterAsync(ctx, - new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default"), - new Dictionary()).ConfigureAwait(true); + await metricsHook.AfterAsync(ctx, new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default"), new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); var measurements = collector.LastMeasurement; @@ -47,9 +45,7 @@ public async Task Without_Reason_After_Test_Defaults_To_Unknown() new ClientMetadata("my-client", "1.0"), new Metadata("my-provider"), evaluationContext); // Act - await metricsHook.AfterAsync(ctx, - new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, reason: null, "default"), - new Dictionary()).ConfigureAwait(true); + await metricsHook.AfterAsync(ctx, new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, reason: null, "default"), new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); var measurements = collector.LastMeasurement; @@ -78,9 +74,7 @@ public async Task With_CustomDimensions_After_Test() new ClientMetadata("my-client", "1.0"), new Metadata("my-provider"), evaluationContext); // Act - await metricsHook.AfterAsync(ctx, - new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default"), - new Dictionary()).ConfigureAwait(true); + await metricsHook.AfterAsync(ctx, new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default"), new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); var measurements = collector.LastMeasurement; @@ -116,9 +110,7 @@ public async Task With_FlagMetadataCallback_After_Test() }); // Act - await metricsHook.AfterAsync(ctx, - new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default", errorMessage: null, flagMetadata), - new Dictionary()).ConfigureAwait(true); + await metricsHook.AfterAsync(ctx, new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default", errorMessage: null, flagMetadata), new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); var measurements = collector.LastMeasurement; @@ -146,7 +138,7 @@ public async Task Error_Test() var errorMessage = "An error occurred during evaluation"; // Act - await metricsHook.ErrorAsync(ctx, new Exception(errorMessage), new Dictionary()).ConfigureAwait(true); + await metricsHook.ErrorAsync(ctx, new Exception(errorMessage), new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); var measurements = collector.LastMeasurement; @@ -177,7 +169,7 @@ public async Task With_CustomDimensions_Error_Test() var errorMessage = "An error occurred during evaluation"; // Act - await metricsHook.ErrorAsync(ctx, new Exception(errorMessage), new Dictionary()).ConfigureAwait(true); + await metricsHook.ErrorAsync(ctx, new Exception(errorMessage), new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); var measurements = collector.LastMeasurement; @@ -204,7 +196,7 @@ public async Task Finally_Test() var evaluationDetails = new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default"); // Act - await metricsHook.FinallyAsync(ctx, evaluationDetails, new Dictionary()).ConfigureAwait(true); + await metricsHook.FinallyAsync(ctx, evaluationDetails, new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); var measurements = collector.LastMeasurement; @@ -234,7 +226,7 @@ public async Task With_CustomDimensions_Finally_Test() var evaluationDetails = new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default"); // Act - await metricsHook.FinallyAsync(ctx, evaluationDetails, new Dictionary()).ConfigureAwait(true); + await metricsHook.FinallyAsync(ctx, evaluationDetails, new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); var measurements = collector.LastMeasurement; @@ -270,7 +262,7 @@ public async Task With_FlagMetadataCallback_Finally_Test() var evaluationDetails = new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default", flagMetadata: flagMetadata); // Act - await metricsHook.FinallyAsync(ctx, evaluationDetails, new Dictionary()).ConfigureAwait(true); + await metricsHook.FinallyAsync(ctx, evaluationDetails, new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); var measurements = collector.LastMeasurement; @@ -297,7 +289,7 @@ public async Task Before_Test() new ClientMetadata("my-client", "1.0"), new Metadata("my-provider"), evaluationContext); // Act - await metricsHook.BeforeAsync(ctx, new Dictionary()).ConfigureAwait(true); + await metricsHook.BeforeAsync(ctx, new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); var measurements = collector1.LastMeasurement; @@ -327,7 +319,7 @@ public async Task With_CustomDimensions_Before_Test() new ClientMetadata("my-client", "1.0"), new Metadata("my-provider"), evaluationContext); // Act - await metricsHook.BeforeAsync(ctx, new Dictionary()).ConfigureAwait(true); + await metricsHook.BeforeAsync(ctx, new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); var measurements = collector1.LastMeasurement; diff --git a/test/OpenFeature.Tests/Hooks/TraceEnricherHookTests.cs b/test/OpenFeature.Tests/Hooks/TraceEnricherHookTests.cs index 5f0b617d..b0bca631 100644 --- a/test/OpenFeature.Tests/Hooks/TraceEnricherHookTests.cs +++ b/test/OpenFeature.Tests/Hooks/TraceEnricherHookTests.cs @@ -47,9 +47,7 @@ public async Task TestFinally() // Act var span = this._tracer.StartActiveSpan("my-span"); - await traceEnricherHook.FinallyAsync(ctx, - new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default"), - new Dictionary()).ConfigureAwait(true); + await traceEnricherHook.FinallyAsync(ctx, new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default"), new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); span.End(); this._tracerProvider.ForceFlush(); @@ -83,9 +81,7 @@ public async Task TestFinally_WithCustomDimension() // Act var span = this._tracer.StartActiveSpan("my-span"); - await traceEnricherHook.FinallyAsync(ctx, - new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default"), - new Dictionary()).ConfigureAwait(true); + await traceEnricherHook.FinallyAsync(ctx, new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default"), new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); span.End(); this._tracerProvider.ForceFlush(); @@ -126,9 +122,7 @@ public async Task TestFinally_WithFlagEvaluationMetadata() // Act var span = this._tracer.StartActiveSpan("my-span"); - await traceEnricherHook.FinallyAsync(ctx, - new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default", flagMetadata: flagMetadata), - new Dictionary()).ConfigureAwait(true); + await traceEnricherHook.FinallyAsync(ctx, new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default", flagMetadata: flagMetadata), new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); span.End(); this._tracerProvider.ForceFlush(); @@ -157,9 +151,7 @@ public async Task TestFinally_NoSpan() new ClientMetadata("my-client", "1.0"), new Metadata("my-provider"), evaluationContext); // Act - await traceEnricherHook.FinallyAsync(ctx, - new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default"), - new Dictionary()).ConfigureAwait(true); + await traceEnricherHook.FinallyAsync(ctx, new FlagEvaluationDetails("my-flag", "foo", Constant.ErrorType.None, "STATIC", "default"), new Dictionary(), TestContext.Current.CancellationToken).ConfigureAwait(true); this._tracerProvider.ForceFlush(); diff --git a/test/OpenFeature.Tests/OpenFeature.Tests.csproj b/test/OpenFeature.Tests/OpenFeature.Tests.csproj index 7a529650..e79aa09b 100644 --- a/test/OpenFeature.Tests/OpenFeature.Tests.csproj +++ b/test/OpenFeature.Tests/OpenFeature.Tests.csproj @@ -2,6 +2,7 @@ OpenFeature.Tests + Exe @@ -19,7 +20,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/test/OpenFeature.Tests/OpenFeatureClientTests.cs b/test/OpenFeature.Tests/OpenFeatureClientTests.cs index 9ea3f0dc..13d8ad6d 100644 --- a/test/OpenFeature.Tests/OpenFeatureClientTests.cs +++ b/test/OpenFeature.Tests/OpenFeatureClientTests.cs @@ -70,28 +70,28 @@ public async Task OpenFeatureClient_Should_Allow_Flag_Evaluation() var defaultStructureValue = fixture.Create(); var emptyFlagOptions = new FlagEvaluationOptions(ImmutableList.Empty, ImmutableDictionary.Empty); - await Api.Instance.SetProviderAsync(new NoOpFeatureProvider()); + await Api.Instance.SetProviderAsync(new NoOpFeatureProvider(), TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion); - Assert.Equal(defaultBoolValue, await client.GetBooleanValueAsync(flagName, defaultBoolValue)); - Assert.Equal(defaultBoolValue, await client.GetBooleanValueAsync(flagName, defaultBoolValue, EvaluationContext.Empty)); - Assert.Equal(defaultBoolValue, await client.GetBooleanValueAsync(flagName, defaultBoolValue, EvaluationContext.Empty, emptyFlagOptions)); + Assert.Equal(defaultBoolValue, await client.GetBooleanValueAsync(flagName, defaultBoolValue, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equal(defaultBoolValue, await client.GetBooleanValueAsync(flagName, defaultBoolValue, EvaluationContext.Empty, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equal(defaultBoolValue, await client.GetBooleanValueAsync(flagName, defaultBoolValue, EvaluationContext.Empty, emptyFlagOptions, TestContext.Current.CancellationToken)); - Assert.Equal(defaultIntegerValue, await client.GetIntegerValueAsync(flagName, defaultIntegerValue)); - Assert.Equal(defaultIntegerValue, await client.GetIntegerValueAsync(flagName, defaultIntegerValue, EvaluationContext.Empty)); - Assert.Equal(defaultIntegerValue, await client.GetIntegerValueAsync(flagName, defaultIntegerValue, EvaluationContext.Empty, emptyFlagOptions)); + Assert.Equal(defaultIntegerValue, await client.GetIntegerValueAsync(flagName, defaultIntegerValue, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equal(defaultIntegerValue, await client.GetIntegerValueAsync(flagName, defaultIntegerValue, EvaluationContext.Empty, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equal(defaultIntegerValue, await client.GetIntegerValueAsync(flagName, defaultIntegerValue, EvaluationContext.Empty, emptyFlagOptions, TestContext.Current.CancellationToken)); - Assert.Equal(defaultDoubleValue, await client.GetDoubleValueAsync(flagName, defaultDoubleValue)); - Assert.Equal(defaultDoubleValue, await client.GetDoubleValueAsync(flagName, defaultDoubleValue, EvaluationContext.Empty)); - Assert.Equal(defaultDoubleValue, await client.GetDoubleValueAsync(flagName, defaultDoubleValue, EvaluationContext.Empty, emptyFlagOptions)); + Assert.Equal(defaultDoubleValue, await client.GetDoubleValueAsync(flagName, defaultDoubleValue, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equal(defaultDoubleValue, await client.GetDoubleValueAsync(flagName, defaultDoubleValue, EvaluationContext.Empty, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equal(defaultDoubleValue, await client.GetDoubleValueAsync(flagName, defaultDoubleValue, EvaluationContext.Empty, emptyFlagOptions, TestContext.Current.CancellationToken)); - Assert.Equal(defaultStringValue, await client.GetStringValueAsync(flagName, defaultStringValue)); - Assert.Equal(defaultStringValue, await client.GetStringValueAsync(flagName, defaultStringValue, EvaluationContext.Empty)); - Assert.Equal(defaultStringValue, await client.GetStringValueAsync(flagName, defaultStringValue, EvaluationContext.Empty, emptyFlagOptions)); + Assert.Equal(defaultStringValue, await client.GetStringValueAsync(flagName, defaultStringValue, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equal(defaultStringValue, await client.GetStringValueAsync(flagName, defaultStringValue, EvaluationContext.Empty, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equal(defaultStringValue, await client.GetStringValueAsync(flagName, defaultStringValue, EvaluationContext.Empty, emptyFlagOptions, TestContext.Current.CancellationToken)); - Assert.Equivalent(defaultStructureValue, await client.GetObjectValueAsync(flagName, defaultStructureValue)); - Assert.Equivalent(defaultStructureValue, await client.GetObjectValueAsync(flagName, defaultStructureValue, EvaluationContext.Empty)); - Assert.Equivalent(defaultStructureValue, await client.GetObjectValueAsync(flagName, defaultStructureValue, EvaluationContext.Empty, emptyFlagOptions)); + Assert.Equivalent(defaultStructureValue, await client.GetObjectValueAsync(flagName, defaultStructureValue, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equivalent(defaultStructureValue, await client.GetObjectValueAsync(flagName, defaultStructureValue, EvaluationContext.Empty, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equivalent(defaultStructureValue, await client.GetObjectValueAsync(flagName, defaultStructureValue, EvaluationContext.Empty, emptyFlagOptions, TestContext.Current.CancellationToken)); } [Fact] @@ -116,33 +116,33 @@ public async Task OpenFeatureClient_Should_Allow_Details_Flag_Evaluation() var defaultStructureValue = fixture.Create(); var emptyFlagOptions = new FlagEvaluationOptions(ImmutableList.Empty, ImmutableDictionary.Empty); - await Api.Instance.SetProviderAsync(new NoOpFeatureProvider()); + await Api.Instance.SetProviderAsync(new NoOpFeatureProvider(), TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion); var boolFlagEvaluationDetails = new FlagEvaluationDetails(flagName, defaultBoolValue, ErrorType.None, NoOpProvider.ReasonNoOp, NoOpProvider.Variant); - Assert.Equivalent(boolFlagEvaluationDetails, await client.GetBooleanDetailsAsync(flagName, defaultBoolValue)); - Assert.Equivalent(boolFlagEvaluationDetails, await client.GetBooleanDetailsAsync(flagName, defaultBoolValue, EvaluationContext.Empty)); - Assert.Equivalent(boolFlagEvaluationDetails, await client.GetBooleanDetailsAsync(flagName, defaultBoolValue, EvaluationContext.Empty, emptyFlagOptions)); + Assert.Equivalent(boolFlagEvaluationDetails, await client.GetBooleanDetailsAsync(flagName, defaultBoolValue, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equivalent(boolFlagEvaluationDetails, await client.GetBooleanDetailsAsync(flagName, defaultBoolValue, EvaluationContext.Empty, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equivalent(boolFlagEvaluationDetails, await client.GetBooleanDetailsAsync(flagName, defaultBoolValue, EvaluationContext.Empty, emptyFlagOptions, TestContext.Current.CancellationToken)); var integerFlagEvaluationDetails = new FlagEvaluationDetails(flagName, defaultIntegerValue, ErrorType.None, NoOpProvider.ReasonNoOp, NoOpProvider.Variant); - Assert.Equivalent(integerFlagEvaluationDetails, await client.GetIntegerDetailsAsync(flagName, defaultIntegerValue)); - Assert.Equivalent(integerFlagEvaluationDetails, await client.GetIntegerDetailsAsync(flagName, defaultIntegerValue, EvaluationContext.Empty)); - Assert.Equivalent(integerFlagEvaluationDetails, await client.GetIntegerDetailsAsync(flagName, defaultIntegerValue, EvaluationContext.Empty, emptyFlagOptions)); + Assert.Equivalent(integerFlagEvaluationDetails, await client.GetIntegerDetailsAsync(flagName, defaultIntegerValue, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equivalent(integerFlagEvaluationDetails, await client.GetIntegerDetailsAsync(flagName, defaultIntegerValue, EvaluationContext.Empty, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equivalent(integerFlagEvaluationDetails, await client.GetIntegerDetailsAsync(flagName, defaultIntegerValue, EvaluationContext.Empty, emptyFlagOptions, TestContext.Current.CancellationToken)); var doubleFlagEvaluationDetails = new FlagEvaluationDetails(flagName, defaultDoubleValue, ErrorType.None, NoOpProvider.ReasonNoOp, NoOpProvider.Variant); - Assert.Equivalent(doubleFlagEvaluationDetails, await client.GetDoubleDetailsAsync(flagName, defaultDoubleValue)); - Assert.Equivalent(doubleFlagEvaluationDetails, await client.GetDoubleDetailsAsync(flagName, defaultDoubleValue, EvaluationContext.Empty)); - Assert.Equivalent(doubleFlagEvaluationDetails, await client.GetDoubleDetailsAsync(flagName, defaultDoubleValue, EvaluationContext.Empty, emptyFlagOptions)); + Assert.Equivalent(doubleFlagEvaluationDetails, await client.GetDoubleDetailsAsync(flagName, defaultDoubleValue, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equivalent(doubleFlagEvaluationDetails, await client.GetDoubleDetailsAsync(flagName, defaultDoubleValue, EvaluationContext.Empty, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equivalent(doubleFlagEvaluationDetails, await client.GetDoubleDetailsAsync(flagName, defaultDoubleValue, EvaluationContext.Empty, emptyFlagOptions, TestContext.Current.CancellationToken)); var stringFlagEvaluationDetails = new FlagEvaluationDetails(flagName, defaultStringValue, ErrorType.None, NoOpProvider.ReasonNoOp, NoOpProvider.Variant); - Assert.Equivalent(stringFlagEvaluationDetails, await client.GetStringDetailsAsync(flagName, defaultStringValue)); - Assert.Equivalent(stringFlagEvaluationDetails, await client.GetStringDetailsAsync(flagName, defaultStringValue, EvaluationContext.Empty)); - Assert.Equivalent(stringFlagEvaluationDetails, await client.GetStringDetailsAsync(flagName, defaultStringValue, EvaluationContext.Empty, emptyFlagOptions)); + Assert.Equivalent(stringFlagEvaluationDetails, await client.GetStringDetailsAsync(flagName, defaultStringValue, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equivalent(stringFlagEvaluationDetails, await client.GetStringDetailsAsync(flagName, defaultStringValue, EvaluationContext.Empty, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equivalent(stringFlagEvaluationDetails, await client.GetStringDetailsAsync(flagName, defaultStringValue, EvaluationContext.Empty, emptyFlagOptions, TestContext.Current.CancellationToken)); var structureFlagEvaluationDetails = new FlagEvaluationDetails(flagName, defaultStructureValue, ErrorType.None, NoOpProvider.ReasonNoOp, NoOpProvider.Variant); - Assert.Equivalent(structureFlagEvaluationDetails, await client.GetObjectDetailsAsync(flagName, defaultStructureValue)); - Assert.Equivalent(structureFlagEvaluationDetails, await client.GetObjectDetailsAsync(flagName, defaultStructureValue, EvaluationContext.Empty)); - Assert.Equivalent(structureFlagEvaluationDetails, await client.GetObjectDetailsAsync(flagName, defaultStructureValue, EvaluationContext.Empty, emptyFlagOptions)); + Assert.Equivalent(structureFlagEvaluationDetails, await client.GetObjectDetailsAsync(flagName, defaultStructureValue, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equivalent(structureFlagEvaluationDetails, await client.GetObjectDetailsAsync(flagName, defaultStructureValue, EvaluationContext.Empty, cancellationToken: TestContext.Current.CancellationToken)); + Assert.Equivalent(structureFlagEvaluationDetails, await client.GetObjectDetailsAsync(flagName, defaultStructureValue, EvaluationContext.Empty, emptyFlagOptions, TestContext.Current.CancellationToken)); } [Fact] @@ -163,18 +163,18 @@ public async Task OpenFeatureClient_Should_Return_DefaultValue_When_Type_Mismatc var mockedLogger = Substitute.For>(); // This will fail to case a String to TestStructure - mockedFeatureProvider.ResolveStructureValueAsync(flagName, defaultValue, Arg.Any()).Throws(); + mockedFeatureProvider.ResolveStructureValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken).Throws(); mockedFeatureProvider.GetMetadata().Returns(new Metadata(fixture.Create())); mockedFeatureProvider.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProviderAsync(mockedFeatureProvider); + await Api.Instance.SetProviderAsync(mockedFeatureProvider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion, mockedLogger); - var evaluationDetails = await client.GetObjectDetailsAsync(flagName, defaultValue); + var evaluationDetails = await client.GetObjectDetailsAsync(flagName, defaultValue, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(ErrorType.TypeMismatch, evaluationDetails.ErrorType); Assert.Equal(new InvalidCastException().Message, evaluationDetails.ErrorMessage); - _ = mockedFeatureProvider.Received(1).ResolveStructureValueAsync(flagName, defaultValue, Arg.Any()); + _ = mockedFeatureProvider.Received(1).ResolveStructureValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken); mockedLogger.Received(0).IsEnabled(LogLevel.Error); } @@ -189,7 +189,7 @@ public async Task Provider_Status_Should_Be_Ready_If_Init_Succeeds() var provider = new TestProvider(); FeatureClient client = Api.Instance.GetClient(name); Assert.Equal(ProviderStatus.NotReady, provider.Status); - await Api.Instance.SetProviderAsync(name, provider); + await Api.Instance.SetProviderAsync(name, provider, TestContext.Current.CancellationToken); // after init fails fatally, status should be READY Assert.Equal(ProviderStatus.Ready, client.ProviderStatus); @@ -205,7 +205,7 @@ public async Task Provider_Status_Should_Be_Error_If_Init_Fails() var provider = new TestProvider("some-name", new GeneralException("fake")); FeatureClient client = Api.Instance.GetClient(name); Assert.Equal(ProviderStatus.NotReady, provider.Status); - await Api.Instance.SetProviderAsync(name, provider); + await Api.Instance.SetProviderAsync(name, provider, TestContext.Current.CancellationToken); // after init fails fatally, status should be ERROR Assert.Equal(ProviderStatus.Error, client.ProviderStatus); @@ -221,7 +221,7 @@ public async Task Provider_Status_Should_Be_Fatal_If_Init_Fatal() var provider = new TestProvider(name, new ProviderFatalException("fatal")); FeatureClient client = Api.Instance.GetClient(name); Assert.Equal(ProviderStatus.NotReady, provider.Status); - await Api.Instance.SetProviderAsync(name, provider); + await Api.Instance.SetProviderAsync(name, provider, TestContext.Current.CancellationToken); // after init fails fatally, status should be FATAL Assert.Equal(ProviderStatus.Fatal, client.ProviderStatus); @@ -238,9 +238,9 @@ public async Task Must_Short_Circuit_Not_Ready() var provider = new TestProvider(name, null, int.MaxValue); FeatureClient client = Api.Instance.GetClient(name); Assert.Equal(ProviderStatus.NotReady, provider.Status); - _ = Api.Instance.SetProviderAsync(name, provider); + _ = Api.Instance.SetProviderAsync(name, provider, TestContext.Current.CancellationToken); - var details = await client.GetStringDetailsAsync("some-flag", defaultStr); + var details = await client.GetStringDetailsAsync("some-flag", defaultStr, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(defaultStr, details.Value); Assert.Equal(ErrorType.ProviderNotReady, details.ErrorType); Assert.Equal(Reason.Error, details.Reason); @@ -257,9 +257,9 @@ public async Task Must_Short_Circuit_Fatal() var provider = new TestProvider(name, new ProviderFatalException("fake")); FeatureClient client = Api.Instance.GetClient(name); Assert.Equal(ProviderStatus.NotReady, provider.Status); - _ = Api.Instance.SetProviderAsync(name, provider); + _ = Api.Instance.SetProviderAsync(name, provider, TestContext.Current.CancellationToken); - var details = await client.GetStringDetailsAsync("some-flag", defaultStr); + var details = await client.GetStringDetailsAsync("some-flag", defaultStr, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(defaultStr, details.Value); Assert.Equal(ErrorType.ProviderFatal, details.ErrorType); Assert.Equal(Reason.Error, details.Reason); @@ -275,16 +275,16 @@ public async Task Should_Resolve_BooleanValue() var defaultValue = fixture.Create(); var featureProviderMock = Substitute.For(); - featureProviderMock.ResolveBooleanValueAsync(flagName, defaultValue, Arg.Any()).Returns(new ResolutionDetails(flagName, defaultValue)); + featureProviderMock.ResolveBooleanValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails(flagName, defaultValue)); featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProviderAsync(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion); - Assert.Equal(defaultValue, await client.GetBooleanValueAsync(flagName, defaultValue)); + Assert.Equal(defaultValue, await client.GetBooleanValueAsync(flagName, defaultValue, cancellationToken: TestContext.Current.CancellationToken)); - _ = featureProviderMock.Received(1).ResolveBooleanValueAsync(flagName, defaultValue, Arg.Any()); + _ = featureProviderMock.Received(1).ResolveBooleanValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken); } [Fact] @@ -297,16 +297,16 @@ public async Task Should_Resolve_StringValue() var defaultValue = fixture.Create(); var featureProviderMock = Substitute.For(); - featureProviderMock.ResolveStringValueAsync(flagName, defaultValue, Arg.Any()).Returns(new ResolutionDetails(flagName, defaultValue)); + featureProviderMock.ResolveStringValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails(flagName, defaultValue)); featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProviderAsync(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion); - Assert.Equal(defaultValue, await client.GetStringValueAsync(flagName, defaultValue)); + Assert.Equal(defaultValue, await client.GetStringValueAsync(flagName, defaultValue, cancellationToken: TestContext.Current.CancellationToken)); - _ = featureProviderMock.Received(1).ResolveStringValueAsync(flagName, defaultValue, Arg.Any()); + _ = featureProviderMock.Received(1).ResolveStringValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken); } [Fact] @@ -319,16 +319,16 @@ public async Task Should_Resolve_IntegerValue() var defaultValue = fixture.Create(); var featureProviderMock = Substitute.For(); - featureProviderMock.ResolveIntegerValueAsync(flagName, defaultValue, Arg.Any()).Returns(new ResolutionDetails(flagName, defaultValue)); + featureProviderMock.ResolveIntegerValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails(flagName, defaultValue)); featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProviderAsync(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion); - Assert.Equal(defaultValue, await client.GetIntegerValueAsync(flagName, defaultValue)); + Assert.Equal(defaultValue, await client.GetIntegerValueAsync(flagName, defaultValue, cancellationToken: TestContext.Current.CancellationToken)); - _ = featureProviderMock.Received(1).ResolveIntegerValueAsync(flagName, defaultValue, Arg.Any()); + _ = featureProviderMock.Received(1).ResolveIntegerValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken); } [Fact] @@ -341,16 +341,16 @@ public async Task Should_Resolve_DoubleValue() var defaultValue = fixture.Create(); var featureProviderMock = Substitute.For(); - featureProviderMock.ResolveDoubleValueAsync(flagName, defaultValue, Arg.Any()).Returns(new ResolutionDetails(flagName, defaultValue)); + featureProviderMock.ResolveDoubleValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails(flagName, defaultValue)); featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProviderAsync(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion); - Assert.Equal(defaultValue, await client.GetDoubleValueAsync(flagName, defaultValue)); + Assert.Equal(defaultValue, await client.GetDoubleValueAsync(flagName, defaultValue, cancellationToken: TestContext.Current.CancellationToken)); - _ = featureProviderMock.Received(1).ResolveDoubleValueAsync(flagName, defaultValue, Arg.Any()); + _ = featureProviderMock.Received(1).ResolveDoubleValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken); } [Fact] @@ -363,16 +363,16 @@ public async Task Should_Resolve_StructureValue() var defaultValue = fixture.Create(); var featureProviderMock = Substitute.For(); - featureProviderMock.ResolveStructureValueAsync(flagName, defaultValue, Arg.Any()).Returns(new ResolutionDetails(flagName, defaultValue)); + featureProviderMock.ResolveStructureValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails(flagName, defaultValue)); featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProviderAsync(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion); - Assert.Equal(defaultValue, await client.GetObjectValueAsync(flagName, defaultValue)); + Assert.Equal(defaultValue, await client.GetObjectValueAsync(flagName, defaultValue, cancellationToken: TestContext.Current.CancellationToken)); - _ = featureProviderMock.Received(1).ResolveStructureValueAsync(flagName, defaultValue, Arg.Any()); + _ = featureProviderMock.Received(1).ResolveStructureValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken); } [Fact] @@ -386,18 +386,18 @@ public async Task When_Error_Is_Returned_From_Provider_Should_Return_Error() const string testMessage = "Couldn't parse flag data."; var featureProviderMock = Substitute.For(); - featureProviderMock.ResolveStructureValueAsync(flagName, defaultValue, Arg.Any()).Returns(Task.FromResult(new ResolutionDetails(flagName, defaultValue, ErrorType.ParseError, "ERROR", null, testMessage))); + featureProviderMock.ResolveStructureValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(Task.FromResult(new ResolutionDetails(flagName, defaultValue, ErrorType.ParseError, "ERROR", null, testMessage))); featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProviderAsync(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion); - var response = await client.GetObjectDetailsAsync(flagName, defaultValue); + var response = await client.GetObjectDetailsAsync(flagName, defaultValue, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(ErrorType.ParseError, response.ErrorType); Assert.Equal(Reason.Error, response.Reason); Assert.Equal(testMessage, response.ErrorMessage); - _ = featureProviderMock.Received(1).ResolveStructureValueAsync(flagName, defaultValue, Arg.Any()); + _ = featureProviderMock.Received(1).ResolveStructureValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken); } [Fact] @@ -411,18 +411,18 @@ public async Task When_Exception_Occurs_During_Evaluation_Should_Return_Error() const string testMessage = "Couldn't parse flag data."; var featureProviderMock = Substitute.For(); - featureProviderMock.ResolveStructureValueAsync(flagName, defaultValue, Arg.Any()).Throws(new FeatureProviderException(ErrorType.ParseError, testMessage)); + featureProviderMock.ResolveStructureValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken).Throws(new FeatureProviderException(ErrorType.ParseError, testMessage)); featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProviderAsync(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion); - var response = await client.GetObjectDetailsAsync(flagName, defaultValue); + var response = await client.GetObjectDetailsAsync(flagName, defaultValue, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(ErrorType.ParseError, response.ErrorType); Assert.Equal(Reason.Error, response.Reason); Assert.Equal(testMessage, response.ErrorMessage); - _ = featureProviderMock.Received(1).ResolveStructureValueAsync(flagName, defaultValue, Arg.Any()); + _ = featureProviderMock.Received(1).ResolveStructureValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken); } [Fact] @@ -436,23 +436,22 @@ public async Task When_Error_Is_Returned_From_Provider_Should_Not_Run_After_Hook const string testMessage = "Couldn't parse flag data."; var featureProviderMock = Substitute.For(); - featureProviderMock.ResolveStructureValueAsync(flagName, defaultValue, Arg.Any()) - .Returns(Task.FromResult(new ResolutionDetails(flagName, defaultValue, ErrorType.ParseError, + featureProviderMock.ResolveStructureValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken).Returns(Task.FromResult(new ResolutionDetails(flagName, defaultValue, ErrorType.ParseError, "ERROR", null, testMessage))); featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProviderAsync(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion); var testHook = new TestHook(); client.AddHooks(testHook); - var response = await client.GetObjectDetailsAsync(flagName, defaultValue); + var response = await client.GetObjectDetailsAsync(flagName, defaultValue, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(ErrorType.ParseError, response.ErrorType); Assert.Equal(Reason.Error, response.Reason); Assert.Equal(testMessage, response.ErrorMessage); _ = featureProviderMock.Received(1) - .ResolveStructureValueAsync(flagName, defaultValue, Arg.Any()); + .ResolveStructureValueAsync(flagName, defaultValue, Arg.Any(), TestContext.Current.CancellationToken); Assert.Equal(1, testHook.BeforeCallCount); Assert.Equal(0, testHook.AfterCallCount); @@ -479,7 +478,7 @@ public async Task Cancellation_Token_Added_Is_Passed_To_Provider() var token = args.ArgAt(3); while (!token.IsCancellationRequested) { - await Task.Delay(10); // artificially delay until cancelled + await Task.Delay(10, TestContext.Current.CancellationToken); // artificially delay until cancelled } return new ResolutionDetails(flagName, defaultString, ErrorType.None, cancelledReason); @@ -487,7 +486,7 @@ public async Task Cancellation_Token_Added_Is_Passed_To_Provider() featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProviderAsync(domain, featureProviderMock); + await Api.Instance.SetProviderAsync(domain, featureProviderMock, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion); var task = client.GetStringDetailsAsync(flagName, defaultString, EvaluationContext.Empty, null, cts.Token); cts.Cancel(); // cancel before awaiting @@ -540,7 +539,7 @@ public void ToFlagEvaluationDetails_Should_Convert_All_Properties() public async Task TheClient_ImplementsATrackingFunction() { var provider = new TestProvider(); - await Api.Instance.SetProviderAsync(provider); + await Api.Instance.SetProviderAsync(provider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); const string trackingEventName = "trackingEventName"; @@ -581,7 +580,7 @@ public async Task TheClient_ImplementsATrackingFunction() public async Task PassingAnEmptyStringAsTrackingEventName_ThrowsArgumentException() { var provider = new TestProvider(); - await Api.Instance.SetProviderAsync(provider); + await Api.Instance.SetProviderAsync(provider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); Assert.Throws(() => client.Track("")); @@ -591,7 +590,7 @@ public async Task PassingAnEmptyStringAsTrackingEventName_ThrowsArgumentExceptio public async Task PassingABlankStringAsTrackingEventName_ThrowsArgumentException() { var provider = new TestProvider(); - await Api.Instance.SetProviderAsync(provider); + await Api.Instance.SetProviderAsync(provider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); Assert.Throws(() => client.Track(" \n ")); @@ -604,7 +603,7 @@ public async Task PassingABlankStringAsTrackingEventName_ThrowsArgumentException public async Task PassingBlankClientName_DoesNotThrowArgumentNullException(string? clientName) { var provider = new TestProvider(); - await Api.Instance.SetProviderAsync(provider); + await Api.Instance.SetProviderAsync(provider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(clientName); var ex = Record.Exception(() => client.AddHandler(ProviderEventTypes.ProviderReady, (args) => { })); @@ -648,7 +647,7 @@ public async Task PassingBlankClientName_DoesNotThrowArgumentNullException(strin public async Task TheClient_MergesTheEvaluationContextInTheCorrectOrder(string key, EvaluationContext? globalEvaluationContext, EvaluationContext? clientEvaluationContext, EvaluationContext? invocationEvaluationContext, string expectedResult) { var provider = new TestProvider(); - await Api.Instance.SetProviderAsync(provider); + await Api.Instance.SetProviderAsync(provider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); const string trackingEventName = "trackingEventName"; @@ -672,15 +671,15 @@ public async Task FinallyHook_IncludesEvaluationDetails() var provider = new TestProvider(); var providerHook = Substitute.For(); provider.AddHook(providerHook); - await Api.Instance.SetProviderAsync(provider); + await Api.Instance.SetProviderAsync(provider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); const string flagName = "flagName"; // Act - var evaluationDetails = await client.GetBooleanDetailsAsync(flagName, true); + var evaluationDetails = await client.GetBooleanDetailsAsync(flagName, true, cancellationToken: TestContext.Current.CancellationToken); // Assert - await providerHook.Received(1).FinallyAsync(Arg.Any>(), evaluationDetails); + await providerHook.Received(1).FinallyAsync(Arg.Any>(), evaluationDetails, cancellationToken: TestContext.Current.CancellationToken); } } diff --git a/test/OpenFeature.Tests/OpenFeatureEventTests.cs b/test/OpenFeature.Tests/OpenFeatureEventTests.cs index 45821899..b32eb9bc 100644 --- a/test/OpenFeature.Tests/OpenFeatureEventTests.cs +++ b/test/OpenFeature.Tests/OpenFeatureEventTests.cs @@ -69,11 +69,11 @@ public async Task API_Level_Event_Handlers_Should_Be_Registered() Api.Instance.AddHandler(ProviderEventTypes.ProviderStale, eventHandler); var testProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(testProvider); + await Api.Instance.SetProviderAsync(testProvider, TestContext.Current.CancellationToken); - await testProvider.SendEventAsync(ProviderEventTypes.ProviderConfigurationChanged); - await testProvider.SendEventAsync(ProviderEventTypes.ProviderError); - await testProvider.SendEventAsync(ProviderEventTypes.ProviderStale); + await testProvider.SendEventAsync(ProviderEventTypes.ProviderConfigurationChanged, TestContext.Current.CancellationToken); + await testProvider.SendEventAsync(ProviderEventTypes.ProviderError, TestContext.Current.CancellationToken); + await testProvider.SendEventAsync(ProviderEventTypes.ProviderStale, TestContext.Current.CancellationToken); await Utils.AssertUntilAsync(_ => eventHandler .Received() @@ -116,7 +116,7 @@ public async Task API_Level_Event_Handlers_Should_Be_Informed_About_Ready_State_ var eventHandler = Substitute.For(); var testProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(testProvider); + await Api.Instance.SetProviderAsync(testProvider, TestContext.Current.CancellationToken); Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); @@ -140,7 +140,7 @@ public async Task API_Level_Event_Handlers_Should_Be_Informed_About_Ready_State_ var eventHandler = Substitute.For(); var testProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(testProvider); + await Api.Instance.SetProviderAsync(testProvider, TestContext.Current.CancellationToken); Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); @@ -164,7 +164,7 @@ public async Task API_Level_Event_Handlers_Should_Be_Informed_About_Error_State_ var eventHandler = Substitute.For(); var testProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(testProvider); + await Api.Instance.SetProviderAsync(testProvider, TestContext.Current.CancellationToken); testProvider.Status = ProviderStatus.Error; @@ -189,7 +189,7 @@ public async Task API_Level_Event_Handlers_Should_Be_Informed_About_Stale_State_ var eventHandler = Substitute.For(); var testProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(testProvider); + await Api.Instance.SetProviderAsync(testProvider, TestContext.Current.CancellationToken); testProvider.Status = ProviderStatus.Stale; @@ -217,14 +217,14 @@ public async Task API_Level_Event_Handlers_Should_Be_Exchangeable() Api.Instance.AddHandler(ProviderEventTypes.ProviderConfigurationChanged, eventHandler); var testProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(testProvider); + await Api.Instance.SetProviderAsync(testProvider, TestContext.Current.CancellationToken); - await testProvider.SendEventAsync(ProviderEventTypes.ProviderConfigurationChanged); + await testProvider.SendEventAsync(ProviderEventTypes.ProviderConfigurationChanged, TestContext.Current.CancellationToken); var newTestProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(newTestProvider); + await Api.Instance.SetProviderAsync(newTestProvider, TestContext.Current.CancellationToken); - await newTestProvider.SendEventAsync(ProviderEventTypes.ProviderConfigurationChanged); + await newTestProvider.SendEventAsync(ProviderEventTypes.ProviderConfigurationChanged, TestContext.Current.CancellationToken); await Utils.AssertUntilAsync( _ => eventHandler.Received(2).Invoke(Arg.Is(payload => payload.ProviderName == testProvider.GetMetadata().Name && payload.Type == ProviderEventTypes.ProviderReady)) @@ -246,13 +246,13 @@ public async Task API_Level_Event_Handlers_Should_Be_Removable() Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); var testProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(testProvider); + await Api.Instance.SetProviderAsync(testProvider, TestContext.Current.CancellationToken); Thread.Sleep(1000); Api.Instance.RemoveHandler(ProviderEventTypes.ProviderReady, eventHandler); var newTestProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(newTestProvider); + await Api.Instance.SetProviderAsync(newTestProvider, TestContext.Current.CancellationToken); eventHandler.Received(1).Invoke(Arg.Is(payload => payload.ProviderName == testProvider.GetMetadata().Name)); } @@ -277,7 +277,7 @@ public async Task API_Level_Event_Handlers_Should_Be_Executed_When_Other_Handler Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); var testProvider = new TestProvider(fixture.Create()); - await Api.Instance.SetProviderAsync(testProvider); + await Api.Instance.SetProviderAsync(testProvider, TestContext.Current.CancellationToken); await Utils.AssertUntilAsync( _ => failingEventHandler.Received().Invoke(Arg.Is(payload => payload.ProviderName == testProvider.GetMetadata().Name)) @@ -302,7 +302,7 @@ public async Task Client_Level_Event_Handlers_Should_Be_Registered() var myClient = Api.Instance.GetClient(domain, clientVersion); var testProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name!, testProvider); + await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name!, testProvider, TestContext.Current.CancellationToken); myClient.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); @@ -333,7 +333,7 @@ public async Task Client_Level_Event_Handlers_Should_Be_Executed_When_Other_Hand myClient.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); var testProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name!, testProvider); + await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name!, testProvider, TestContext.Current.CancellationToken); await Utils.AssertUntilAsync( _ => failingEventHandler.Received().Invoke(Arg.Is(payload => payload.ProviderName == testProvider.GetMetadata().Name)) @@ -362,9 +362,9 @@ public async Task Client_Level_Event_Handlers_Should_Be_Registered_To_Default_Pr var clientProvider = new TestProvider(fixture.Create()); // set the default provider on API level, but not specifically to the client - await Api.Instance.SetProviderAsync(apiProvider); + await Api.Instance.SetProviderAsync(apiProvider, TestContext.Current.CancellationToken); // set the other provider specifically for the client - await Api.Instance.SetProviderAsync(myClientWithBoundProvider.GetMetadata().Name!, clientProvider); + await Api.Instance.SetProviderAsync(myClientWithBoundProvider.GetMetadata().Name!, clientProvider, TestContext.Current.CancellationToken); myClientWithNoBoundProvider.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); myClientWithBoundProvider.AddHandler(ProviderEventTypes.ProviderReady, clientEventHandler); @@ -394,11 +394,11 @@ public async Task Client_Level_Event_Handlers_Should_Be_Receive_Events_From_Name var clientProvider = new TestProvider(fixture.Create()); // set the default provider - await Api.Instance.SetProviderAsync(defaultProvider); + await Api.Instance.SetProviderAsync(defaultProvider, TestContext.Current.CancellationToken); client.AddHandler(ProviderEventTypes.ProviderConfigurationChanged, clientEventHandler); - await defaultProvider.SendEventAsync(ProviderEventTypes.ProviderConfigurationChanged); + await defaultProvider.SendEventAsync(ProviderEventTypes.ProviderConfigurationChanged, TestContext.Current.CancellationToken); // verify that the client received the event from the default provider as there is no named provider registered yet await Utils.AssertUntilAsync( @@ -407,11 +407,11 @@ await Utils.AssertUntilAsync( ); // set the other provider specifically for the client - await Api.Instance.SetProviderAsync(client.GetMetadata().Name!, clientProvider); + await Api.Instance.SetProviderAsync(client.GetMetadata().Name!, clientProvider, TestContext.Current.CancellationToken); // now, send another event for the default handler - await defaultProvider.SendEventAsync(ProviderEventTypes.ProviderConfigurationChanged); - await clientProvider.SendEventAsync(ProviderEventTypes.ProviderConfigurationChanged); + await defaultProvider.SendEventAsync(ProviderEventTypes.ProviderConfigurationChanged, TestContext.Current.CancellationToken); + await clientProvider.SendEventAsync(ProviderEventTypes.ProviderConfigurationChanged, TestContext.Current.CancellationToken); // now the client should have received only the event from the named provider await Utils.AssertUntilAsync( @@ -439,7 +439,7 @@ public async Task Client_Level_Event_Handlers_Should_Be_Informed_About_Ready_Sta var myClient = Api.Instance.GetClient(fixture.Create(), fixture.Create()); var testProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name!, testProvider); + await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name!, testProvider, TestContext.Current.CancellationToken); // add the event handler after the provider has already transitioned into the ready state myClient.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); @@ -464,7 +464,7 @@ public async Task Client_Level_Event_Handlers_Should_Be_Removable() myClient.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); var testProvider = new TestProvider(); - await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name!, testProvider); + await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name!, testProvider, TestContext.Current.CancellationToken); // wait for the first event to be received await Utils.AssertUntilAsync( @@ -474,7 +474,7 @@ await Utils.AssertUntilAsync( myClient.RemoveHandler(ProviderEventTypes.ProviderReady, eventHandler); // send another event from the provider - this one should not be received - await testProvider.SendEventAsync(ProviderEventTypes.ProviderReady); + await testProvider.SendEventAsync(ProviderEventTypes.ProviderReady, TestContext.Current.CancellationToken); // wait a bit and make sure we only have received the first event, but nothing after removing the event handler await Utils.AssertUntilAsync( @@ -505,8 +505,8 @@ public void RegisterClientFeatureProvider_WhenCalledWithNullProvider_DoesNotThro public async Task Provider_Events_Should_Update_ProviderStatus(ProviderEventTypes type, ProviderStatus status) { var provider = new TestProvider(); - await Api.Instance.SetProviderAsync("5.3.5", provider); - _ = provider.SendEventAsync(type); + await Api.Instance.SetProviderAsync("5.3.5", provider, TestContext.Current.CancellationToken); + _ = provider.SendEventAsync(type, TestContext.Current.CancellationToken); await Utils.AssertUntilAsync(_ => Assert.True(provider.Status == status)); } } diff --git a/test/OpenFeature.Tests/OpenFeatureHookTests.cs b/test/OpenFeature.Tests/OpenFeatureHookTests.cs index 22a0b17a..8b149cc5 100644 --- a/test/OpenFeature.Tests/OpenFeatureHookTests.cs +++ b/test/OpenFeature.Tests/OpenFeatureHookTests.cs @@ -28,57 +28,56 @@ public async Task Hooks_Should_Be_Called_In_Order() var providerHook = Substitute.For(); // Sequence - apiHook.BeforeAsync(Arg.Any>(), Arg.Any>()).Returns(EvaluationContext.Empty); - clientHook.BeforeAsync(Arg.Any>(), Arg.Any>()).Returns(EvaluationContext.Empty); - invocationHook.BeforeAsync(Arg.Any>(), Arg.Any>()).Returns(EvaluationContext.Empty); - providerHook.BeforeAsync(Arg.Any>(), Arg.Any>()).Returns(EvaluationContext.Empty); - providerHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()).Returns(new ValueTask()); - invocationHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()).Returns(new ValueTask()); - clientHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()).Returns(new ValueTask()); - apiHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()).Returns(new ValueTask()); - providerHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()).Returns(new ValueTask()); - invocationHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()).Returns(new ValueTask()); - clientHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()).Returns(new ValueTask()); - apiHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()).Returns(new ValueTask()); + apiHook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty); + clientHook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty); + invocationHook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty); + providerHook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty); + providerHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); + invocationHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); + clientHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); + apiHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); + providerHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); + invocationHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); + clientHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); + apiHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); var testProvider = new TestProvider(); testProvider.AddHook(providerHook); Api.Instance.AddHooks(apiHook); - await Api.Instance.SetProviderAsync(testProvider); + await Api.Instance.SetProviderAsync(testProvider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(domain, clientVersion); client.AddHooks(clientHook); - await client.GetBooleanValueAsync(flagName, defaultValue, EvaluationContext.Empty, - new FlagEvaluationOptions(invocationHook, ImmutableDictionary.Empty)); + await client.GetBooleanValueAsync(flagName, defaultValue, EvaluationContext.Empty, new FlagEvaluationOptions(invocationHook, ImmutableDictionary.Empty), TestContext.Current.CancellationToken); Received.InOrder(() => { - apiHook.BeforeAsync(Arg.Any>(), Arg.Any>()); - clientHook.BeforeAsync(Arg.Any>(), Arg.Any>()); - invocationHook.BeforeAsync(Arg.Any>(), Arg.Any>()); - providerHook.BeforeAsync(Arg.Any>(), Arg.Any>()); - providerHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - invocationHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - clientHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - apiHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - providerHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - invocationHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - clientHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - apiHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); + apiHook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + clientHook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + invocationHook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + providerHook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + providerHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + invocationHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + clientHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + apiHook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + providerHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + invocationHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + clientHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + apiHook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); }); - _ = apiHook.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>()); - _ = clientHook.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>()); - _ = invocationHook.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>()); - _ = providerHook.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>()); - _ = providerHook.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - _ = invocationHook.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - _ = clientHook.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - _ = apiHook.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - _ = providerHook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - _ = invocationHook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - _ = clientHook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - _ = apiHook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); + _ = apiHook.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = clientHook.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = invocationHook.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = providerHook.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = providerHook.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = invocationHook.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = clientHook.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = apiHook.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = providerHook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = invocationHook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = clientHook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = apiHook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); } [Fact] @@ -145,15 +144,14 @@ public async Task Evaluation_Context_Must_Be_Mutable_Before_Hook() FlagValueType.Boolean, new ClientMetadata("test", "1.0.0"), new Metadata(NoOpProvider.NoOpProviderName), evaluationContext); - hook1.BeforeAsync(Arg.Any>(), Arg.Any>()).Returns(evaluationContext); - hook2.BeforeAsync(hookContext, Arg.Any>()).Returns(evaluationContext); + hook1.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(evaluationContext); + hook2.BeforeAsync(hookContext, Arg.Any>(), TestContext.Current.CancellationToken).Returns(evaluationContext); var client = Api.Instance.GetClient("test", "1.0.0"); - await client.GetBooleanValueAsync("test", false, EvaluationContext.Empty, - new FlagEvaluationOptions(ImmutableList.Create(hook1, hook2), ImmutableDictionary.Empty)); + await client.GetBooleanValueAsync("test", false, EvaluationContext.Empty, new FlagEvaluationOptions(ImmutableList.Create(hook1, hook2), ImmutableDictionary.Empty), TestContext.Current.CancellationToken); - _ = hook1.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>()); - _ = hook2.Received(1).BeforeAsync(Arg.Is>(a => a.EvaluationContext.GetValue("test").AsString == "test"), Arg.Any>()); + _ = hook1.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = hook2.Received(1).BeforeAsync(Arg.Is>(a => a.EvaluationContext.GetValue("test").AsString == "test"), Arg.Any>(), TestContext.Current.CancellationToken); } [Fact] @@ -162,29 +160,26 @@ public async Task HookData_Must_Be_Mutable() { var hook = Substitute.For(); - hook.BeforeAsync(Arg.Any>(), Arg.Any>()) - .Returns(EvaluationContext.Empty).AndDoes(info => + hook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty).AndDoes(info => { info.Arg>().Data.Set("test-a", true); }); - hook.AfterAsync(Arg.Any>(), Arg.Any>(), - Arg.Any>()).Returns(new ValueTask()).AndDoes(info => + hook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()).AndDoes(info => { info.Arg>().Data.Set("test-b", "test-value"); }); - await Api.Instance.SetProviderAsync(new NoOpFeatureProvider()); + await Api.Instance.SetProviderAsync(new NoOpFeatureProvider(), TestContext.Current.CancellationToken); var client = Api.Instance.GetClient("test", "1.0.0"); - await client.GetBooleanValueAsync("test", false, EvaluationContext.Empty, - new FlagEvaluationOptions(ImmutableList.Create(hook), ImmutableDictionary.Empty)); + await client.GetBooleanValueAsync("test", false, EvaluationContext.Empty, new FlagEvaluationOptions(ImmutableList.Create(hook), ImmutableDictionary.Empty), TestContext.Current.CancellationToken); _ = hook.Received(1).AfterAsync(Arg.Is>(hookContext => (bool)hookContext.Data.Get("test-a") == true - ), Arg.Any>(), Arg.Any>()); + ), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); _ = hook.Received(1).FinallyAsync(Arg.Is>(hookContext => (bool)hookContext.Data.Get("test-a") == true && (string)hookContext.Data.Get("test-b") == "test-value" - ), Arg.Any>(), Arg.Any>()); + ), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); } [Fact] @@ -195,54 +190,49 @@ public async Task HookData_Must_Be_Unique_Per_Hook() var hook1 = Substitute.For(); var hook2 = Substitute.For(); - hook1.BeforeAsync(Arg.Any>(), Arg.Any>()) - .Returns(EvaluationContext.Empty).AndDoes(info => + hook1.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty).AndDoes(info => { info.Arg>().Data.Set("hook-1-value-a", true); info.Arg>().Data.Set("same", true); }); - hook1.AfterAsync(Arg.Any>(), Arg.Any>(), - Arg.Any>()).Returns(new ValueTask()).AndDoes(info => + hook1.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()).AndDoes(info => { info.Arg>().Data.Set("hook-1-value-b", "test-value-hook-1"); }); - hook2.BeforeAsync(Arg.Any>(), Arg.Any>()) - .Returns(EvaluationContext.Empty).AndDoes(info => + hook2.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty).AndDoes(info => { info.Arg>().Data.Set("hook-2-value-a", false); info.Arg>().Data.Set("same", false); }); - hook2.AfterAsync(Arg.Any>(), Arg.Any>(), - Arg.Any>()).Returns(new ValueTask()).AndDoes(info => + hook2.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()).AndDoes(info => { info.Arg>().Data.Set("hook-2-value-b", "test-value-hook-2"); }); - await Api.Instance.SetProviderAsync(new NoOpFeatureProvider()); + await Api.Instance.SetProviderAsync(new NoOpFeatureProvider(), TestContext.Current.CancellationToken); var client = Api.Instance.GetClient("test", "1.0.0"); - await client.GetBooleanValueAsync("test", false, EvaluationContext.Empty, - new FlagEvaluationOptions(ImmutableList.Create(hook1, hook2), - ImmutableDictionary.Empty)); + await client.GetBooleanValueAsync("test", false, EvaluationContext.Empty, new FlagEvaluationOptions(ImmutableList.Create(hook1, hook2), + ImmutableDictionary.Empty), TestContext.Current.CancellationToken); _ = hook1.Received(1).AfterAsync(Arg.Is>(hookContext => (bool)hookContext.Data.Get("hook-1-value-a") == true && (bool)hookContext.Data.Get("same") == true - ), Arg.Any>(), Arg.Any>()); + ), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); _ = hook1.Received(1).FinallyAsync(Arg.Is>(hookContext => (bool)hookContext.Data.Get("hook-1-value-a") == true && (bool)hookContext.Data.Get("same") == true && (string)hookContext.Data.Get("hook-1-value-b") == "test-value-hook-1" && hookContext.Data.Count == 3 - ), Arg.Any>(), Arg.Any>()); + ), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); _ = hook2.Received(1).AfterAsync(Arg.Is>(hookContext => (bool)hookContext.Data.Get("hook-2-value-a") == false && (bool)hookContext.Data.Get("same") == false - ), Arg.Any>(), Arg.Any>()); + ), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); _ = hook2.Received(1).FinallyAsync(Arg.Is>(hookContext => (bool)hookContext.Data.Get("hook-2-value-a") == false && (bool)hookContext.Data.Get("same") == false && (string)hookContext.Data.Get("hook-2-value-b") == "test-value-hook-2" && hookContext.Data.Count == 3 - ), Arg.Any>(), Arg.Any>()); + ), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); } [Fact] @@ -305,16 +295,16 @@ public async Task Evaluation_Context_Must_Be_Merged_In_Correct_Order() provider.GetProviderHooks().Returns(ImmutableList.Empty); - provider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any()).Returns(new ResolutionDetails("test", true)); + provider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails("test", true)); - await Api.Instance.SetProviderAsync(provider); + await Api.Instance.SetProviderAsync(provider, TestContext.Current.CancellationToken); var hook = Substitute.For(); - hook.BeforeAsync(Arg.Any>(), Arg.Any>()).Returns(hookContext); + hook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(hookContext); var client = Api.Instance.GetClient("test", "1.0.0", null, clientContext); - await client.GetBooleanValueAsync("test", false, invocationContext, new FlagEvaluationOptions(ImmutableList.Create(hook), ImmutableDictionary.Empty)); + await client.GetBooleanValueAsync("test", false, invocationContext, new FlagEvaluationOptions(ImmutableList.Create(hook), ImmutableDictionary.Empty), TestContext.Current.CancellationToken); // after proper merging, all properties should equal true _ = provider.Received(1).ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Is(y => @@ -327,7 +317,7 @@ public async Task Evaluation_Context_Must_Be_Merged_In_Correct_Order() && (y.GetValue(propClientToOverwrite).AsBoolean ?? false) && (y.GetValue(propHook).AsBoolean ?? false) && (y.GetValue(propInvocationToOverwrite).AsBoolean ?? false) - )); + ), TestContext.Current.CancellationToken); } [Fact] @@ -352,10 +342,10 @@ public async Task Hook_Should_Return_No_Errors() var evaluationDetails = new FlagEvaluationDetails("test", false, ErrorType.None, "testing", "testing"); - await hook.BeforeAsync(hookContext, hookHints); - await hook.AfterAsync(hookContext, evaluationDetails, hookHints); - await hook.FinallyAsync(hookContext, evaluationDetails, hookHints); - await hook.ErrorAsync(hookContext, new Exception(), hookHints); + await hook.BeforeAsync(hookContext, hookHints, TestContext.Current.CancellationToken); + await hook.AfterAsync(hookContext, evaluationDetails, hookHints, TestContext.Current.CancellationToken); + await hook.FinallyAsync(hookContext, evaluationDetails, hookHints, TestContext.Current.CancellationToken); + await hook.ErrorAsync(hookContext, new Exception(), hookHints, TestContext.Current.CancellationToken); Assert.Null(hookContext.ClientMetadata.Name); Assert.Null(hookContext.ClientMetadata.Version); @@ -378,29 +368,29 @@ public async Task Hook_Should_Execute_In_Correct_Order() featureProvider.GetProviderHooks().Returns(ImmutableList.Empty); // Sequence - hook.BeforeAsync(Arg.Any>(), Arg.Any>()).Returns(EvaluationContext.Empty); - featureProvider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any()).Returns(new ResolutionDetails("test", false)); - _ = hook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - _ = hook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); + hook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty); + featureProvider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails("test", false)); + _ = hook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = hook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); - await Api.Instance.SetProviderAsync(featureProvider); + await Api.Instance.SetProviderAsync(featureProvider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); client.AddHooks(hook); - await client.GetBooleanValueAsync("test", false); + await client.GetBooleanValueAsync("test", false, cancellationToken: TestContext.Current.CancellationToken); Received.InOrder(() => { - hook.BeforeAsync(Arg.Any>(), Arg.Any>()); - featureProvider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any()); - hook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - hook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); + hook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + featureProvider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any(), TestContext.Current.CancellationToken); + hook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + hook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); }); - _ = hook.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>()); - _ = hook.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - _ = hook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - _ = featureProvider.Received(1).ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any()); + _ = hook.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = hook.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = hook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = featureProvider.Received(1).ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any(), TestContext.Current.CancellationToken); } [Fact] @@ -415,11 +405,10 @@ public async Task Register_Hooks_Should_Be_Available_At_All_Levels() var testProvider = new TestProvider(); testProvider.AddHook(hook4); Api.Instance.AddHooks(hook1); - await Api.Instance.SetProviderAsync(testProvider); + await Api.Instance.SetProviderAsync(testProvider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); client.AddHooks(hook2); - await client.GetBooleanValueAsync("test", false, null, - new FlagEvaluationOptions(hook3, ImmutableDictionary.Empty)); + await client.GetBooleanValueAsync("test", false, null, new FlagEvaluationOptions(hook3, ImmutableDictionary.Empty), TestContext.Current.CancellationToken); Assert.Single(Api.Instance.GetHooks()); Assert.Single(client.GetHooks()); @@ -438,39 +427,39 @@ public async Task Finally_Hook_Should_Be_Executed_Even_If_Abnormal_Termination() featureProvider.GetProviderHooks().Returns(ImmutableList.Empty); // Sequence - hook1.BeforeAsync(Arg.Any>(), null).Returns(EvaluationContext.Empty); - hook2.BeforeAsync(Arg.Any>(), null).Returns(EvaluationContext.Empty); - featureProvider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any()).Returns(new ResolutionDetails("test", false)); - hook2.AfterAsync(Arg.Any>(), Arg.Any>(), null).Returns(new ValueTask()); - hook1.AfterAsync(Arg.Any>(), Arg.Any>(), null).Returns(new ValueTask()); - hook2.FinallyAsync(Arg.Any>(), Arg.Any>(), null).Returns(new ValueTask()); - hook1.FinallyAsync(Arg.Any>(), Arg.Any>(), null).Throws(new Exception()); - - await Api.Instance.SetProviderAsync(featureProvider); + hook1.BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty); + hook2.BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty); + featureProvider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails("test", false)); + hook2.AfterAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken).Returns(new ValueTask()); + hook1.AfterAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken).Returns(new ValueTask()); + hook2.FinallyAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken).Returns(new ValueTask()); + hook1.FinallyAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken).Throws(new Exception()); + + await Api.Instance.SetProviderAsync(featureProvider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); client.AddHooks(new[] { hook1, hook2 }); Assert.Equal(2, client.GetHooks().Count()); - await client.GetBooleanValueAsync("test", false); + await client.GetBooleanValueAsync("test", false, cancellationToken: TestContext.Current.CancellationToken); Received.InOrder(() => { - hook1.BeforeAsync(Arg.Any>(), null); - hook2.BeforeAsync(Arg.Any>(), null); - featureProvider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any()); - hook2.AfterAsync(Arg.Any>(), Arg.Any>(), null); - hook1.AfterAsync(Arg.Any>(), Arg.Any>(), null); - hook2.FinallyAsync(Arg.Any>(), Arg.Any>(), null); - hook1.FinallyAsync(Arg.Any>(), Arg.Any>(), null); + hook1.BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken); + hook2.BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken); + featureProvider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any(), TestContext.Current.CancellationToken); + hook2.AfterAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken); + hook1.AfterAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken); + hook2.FinallyAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken); + hook1.FinallyAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken); }); - _ = hook1.Received(1).BeforeAsync(Arg.Any>(), null); - _ = hook2.Received(1).BeforeAsync(Arg.Any>(), null); - _ = featureProvider.Received(1).ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any()); - _ = hook2.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), null); - _ = hook1.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), null); - _ = hook2.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), null); - _ = hook1.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), null); + _ = hook1.Received(1).BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken); + _ = hook2.Received(1).BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken); + _ = featureProvider.Received(1).ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any(), TestContext.Current.CancellationToken); + _ = hook2.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken); + _ = hook1.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken); + _ = hook2.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken); + _ = hook1.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken); } [Fact] @@ -485,31 +474,31 @@ public async Task Error_Hook_Should_Be_Executed_Even_If_Abnormal_Termination() featureProvider1.GetProviderHooks().Returns(ImmutableList.Empty); // Sequence - hook1.BeforeAsync(Arg.Any>(), null).Returns(EvaluationContext.Empty); - hook2.BeforeAsync(Arg.Any>(), null).Returns(EvaluationContext.Empty); - featureProvider1.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any()).Throws(new Exception()); - hook2.ErrorAsync(Arg.Any>(), Arg.Any(), null).Throws(new Exception()); - hook1.ErrorAsync(Arg.Any>(), Arg.Any(), null).Returns(new ValueTask()); + hook1.BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty); + hook2.BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty); + featureProvider1.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any(), TestContext.Current.CancellationToken).Throws(new Exception()); + hook2.ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken).Throws(new Exception()); + hook1.ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken).Returns(new ValueTask()); - await Api.Instance.SetProviderAsync(featureProvider1); + await Api.Instance.SetProviderAsync(featureProvider1, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); client.AddHooks(new[] { hook1, hook2 }); - await client.GetBooleanValueAsync("test", false); + await client.GetBooleanValueAsync("test", false, cancellationToken: TestContext.Current.CancellationToken); Received.InOrder(() => { - hook1.BeforeAsync(Arg.Any>(), null); - hook2.BeforeAsync(Arg.Any>(), null); - featureProvider1.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any()); - hook2.ErrorAsync(Arg.Any>(), Arg.Any(), null); - hook1.ErrorAsync(Arg.Any>(), Arg.Any(), null); + hook1.BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken); + hook2.BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken); + featureProvider1.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any(), TestContext.Current.CancellationToken); + hook2.ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken); + hook1.ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken); }); - _ = hook1.Received(1).BeforeAsync(Arg.Any>(), null); - _ = hook2.Received(1).BeforeAsync(Arg.Any>(), null); - _ = hook1.Received(1).ErrorAsync(Arg.Any>(), Arg.Any(), null); - _ = hook2.Received(1).ErrorAsync(Arg.Any>(), Arg.Any(), null); + _ = hook1.Received(1).BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken); + _ = hook2.Received(1).BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken); + _ = hook1.Received(1).ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken); + _ = hook2.Received(1).ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken); } [Fact] @@ -524,27 +513,27 @@ public async Task Error_Occurs_During_Before_After_Evaluation_Should_Not_Invoke_ featureProvider.GetProviderHooks().Returns(ImmutableList.Empty); // Sequence - hook1.BeforeAsync(Arg.Any>(), Arg.Any>()).Throws(new Exception()); - _ = hook1.ErrorAsync(Arg.Any>(), Arg.Any(), null); - _ = hook2.ErrorAsync(Arg.Any>(), Arg.Any(), null); + hook1.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Throws(new Exception()); + _ = hook1.ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken); + _ = hook2.ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken); - await Api.Instance.SetProviderAsync(featureProvider); + await Api.Instance.SetProviderAsync(featureProvider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); client.AddHooks(new[] { hook1, hook2 }); - await client.GetBooleanValueAsync("test", false); + await client.GetBooleanValueAsync("test", false, cancellationToken: TestContext.Current.CancellationToken); Received.InOrder(() => { - hook1.BeforeAsync(Arg.Any>(), Arg.Any>()); - hook2.ErrorAsync(Arg.Any>(), Arg.Any(), null); - hook1.ErrorAsync(Arg.Any>(), Arg.Any(), null); + hook1.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + hook2.ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken); + hook1.ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken); }); - _ = hook1.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>()); - _ = hook2.DidNotReceive().BeforeAsync(Arg.Any>(), Arg.Any>()); - _ = hook1.Received(1).ErrorAsync(Arg.Any>(), Arg.Any(), null); - _ = hook2.Received(1).ErrorAsync(Arg.Any>(), Arg.Any(), null); + _ = hook1.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = hook2.DidNotReceive().BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + _ = hook1.Received(1).ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken); + _ = hook2.Received(1).ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken); } [Fact] @@ -561,29 +550,25 @@ public async Task Hook_Hints_May_Be_Optional() featureProvider.GetProviderHooks() .Returns(ImmutableList.Empty); - hook.BeforeAsync(Arg.Any>(), Arg.Any>()) - .Returns(EvaluationContext.Empty); + hook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty); - featureProvider.ResolveBooleanValueAsync("test", false, Arg.Any()) - .Returns(new ResolutionDetails("test", false)); + featureProvider.ResolveBooleanValueAsync("test", false, Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails("test", false)); - hook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()) - .Returns(new ValueTask()); + hook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); - hook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()) - .Returns(new ValueTask()); + hook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); - await Api.Instance.SetProviderAsync(featureProvider); + await Api.Instance.SetProviderAsync(featureProvider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); - await client.GetBooleanValueAsync("test", false, EvaluationContext.Empty, flagOptions); + await client.GetBooleanValueAsync("test", false, EvaluationContext.Empty, flagOptions, TestContext.Current.CancellationToken); Received.InOrder(() => { - hook.Received().BeforeAsync(Arg.Any>(), Arg.Any>()); - featureProvider.Received().ResolveBooleanValueAsync("test", false, Arg.Any()); - hook.Received().AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - hook.Received().FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); + hook.Received().BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + featureProvider.Received().ResolveBooleanValueAsync("test", false, Arg.Any(), TestContext.Current.CancellationToken); + hook.Received().AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + hook.Received().FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); }); } @@ -599,26 +584,26 @@ public async Task When_Error_Occurs_In_Before_Hook_Should_Return_Default_Value() featureProvider.GetMetadata().Returns(new Metadata(null)); // Sequence - hook.BeforeAsync(Arg.Any>(), Arg.Any>()).Throws(exceptionToThrow); - hook.ErrorAsync(Arg.Any>(), Arg.Any(), null).Returns(new ValueTask()); - hook.FinallyAsync(Arg.Any>(), Arg.Any>(), null).Returns(new ValueTask()); + hook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Throws(exceptionToThrow); + hook.ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken).Returns(new ValueTask()); + hook.FinallyAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken).Returns(new ValueTask()); var client = Api.Instance.GetClient(); client.AddHooks(hook); - var resolvedFlag = await client.GetBooleanValueAsync("test", true); + var resolvedFlag = await client.GetBooleanValueAsync("test", true, cancellationToken: TestContext.Current.CancellationToken); Received.InOrder(() => { - hook.BeforeAsync(Arg.Any>(), Arg.Any>()); - hook.ErrorAsync(Arg.Any>(), Arg.Any(), null); - hook.FinallyAsync(Arg.Any>(), Arg.Any>(), null); + hook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + hook.ErrorAsync(Arg.Any>(), Arg.Any(), null, TestContext.Current.CancellationToken); + hook.FinallyAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken); }); Assert.True(resolvedFlag); - _ = hook.Received(1).BeforeAsync(Arg.Any>(), null); - _ = hook.Received(1).ErrorAsync(Arg.Any>(), exceptionToThrow, null); - _ = hook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), null); + _ = hook.Received(1).BeforeAsync(Arg.Any>(), null, TestContext.Current.CancellationToken); + _ = hook.Received(1).ErrorAsync(Arg.Any>(), exceptionToThrow, null, TestContext.Current.CancellationToken); + _ = hook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), null, TestContext.Current.CancellationToken); } [Fact] @@ -636,36 +621,31 @@ public async Task When_Error_Occurs_In_After_Hook_Should_Invoke_Error_Hook() featureProvider.GetProviderHooks() .Returns(ImmutableList.Empty); - hook.BeforeAsync(Arg.Any>(), Arg.Any>()) - .Returns(EvaluationContext.Empty); + hook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty); - featureProvider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any()) - .Returns(new ResolutionDetails("test", false)); + featureProvider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any(), TestContext.Current.CancellationToken).Returns(new ResolutionDetails("test", false)); - hook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()) - .Throws(exceptionToThrow); + hook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Throws(exceptionToThrow); - hook.ErrorAsync(Arg.Any>(), Arg.Any(), Arg.Any>()) - .Returns(new ValueTask()); + hook.ErrorAsync(Arg.Any>(), Arg.Any(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); - hook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()) - .Returns(new ValueTask()); + hook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); - await Api.Instance.SetProviderAsync(featureProvider); + await Api.Instance.SetProviderAsync(featureProvider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); - var resolvedFlag = await client.GetBooleanValueAsync("test", true, config: flagOptions); + var resolvedFlag = await client.GetBooleanValueAsync("test", true, config: flagOptions, cancellationToken: TestContext.Current.CancellationToken); Assert.True(resolvedFlag); Received.InOrder(() => { - hook.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>()); - hook.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); - hook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()); + hook.Received(1).BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + hook.Received(1).AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); + hook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken); }); - await featureProvider.DidNotReceive().ResolveBooleanValueAsync("test", false, Arg.Any()); + await featureProvider.DidNotReceive().ResolveBooleanValueAsync("test", false, Arg.Any(), TestContext.Current.CancellationToken); } [Fact] @@ -683,7 +663,7 @@ public async Task Successful_Resolution_Should_Pass_Cancellation_Token() _ = hook.AfterAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), cts.Token); _ = hook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), cts.Token); - await Api.Instance.SetProviderAsync(featureProvider); + await Api.Instance.SetProviderAsync(featureProvider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); client.AddHooks(hook); @@ -709,19 +689,15 @@ public async Task Failed_Resolution_Should_Pass_Cancellation_Token() featureProvider.GetProviderHooks() .Returns(ImmutableList.Empty); - hook.BeforeAsync(Arg.Any>(), Arg.Any>()) - .Returns(EvaluationContext.Empty); + hook.BeforeAsync(Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(EvaluationContext.Empty); - featureProvider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any()) - .Throws(exceptionToThrow); + featureProvider.ResolveBooleanValueAsync(Arg.Any(), Arg.Any(), Arg.Any(), TestContext.Current.CancellationToken).Throws(exceptionToThrow); - hook.ErrorAsync(Arg.Any>(), Arg.Any(), Arg.Any>()) - .Returns(new ValueTask()); + hook.ErrorAsync(Arg.Any>(), Arg.Any(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); - hook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>()) - .Returns(new ValueTask()); + hook.FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), TestContext.Current.CancellationToken).Returns(new ValueTask()); - await Api.Instance.SetProviderAsync(featureProvider); + await Api.Instance.SetProviderAsync(featureProvider, TestContext.Current.CancellationToken); var client = Api.Instance.GetClient(); await client.GetBooleanValueAsync("test", true, EvaluationContext.Empty, flagOptions, cts.Token); @@ -730,7 +706,7 @@ public async Task Failed_Resolution_Should_Pass_Cancellation_Token() _ = hook.Received(1).ErrorAsync(Arg.Any>(), Arg.Any(), Arg.Any>(), cts.Token); _ = hook.Received(1).FinallyAsync(Arg.Any>(), Arg.Any>(), Arg.Any>(), cts.Token); - await featureProvider.DidNotReceive().ResolveBooleanValueAsync("test", false, Arg.Any()); + await featureProvider.DidNotReceive().ResolveBooleanValueAsync("test", false, Arg.Any(), TestContext.Current.CancellationToken); } [Fact] diff --git a/test/OpenFeature.Tests/OpenFeatureTests.cs b/test/OpenFeature.Tests/OpenFeatureTests.cs index 835406ef..4f8dc0b4 100644 --- a/test/OpenFeature.Tests/OpenFeatureTests.cs +++ b/test/OpenFeature.Tests/OpenFeatureTests.cs @@ -24,14 +24,14 @@ public async Task OpenFeature_Should_Initialize_Provider() var providerMockDefault = Substitute.For(); providerMockDefault.Status.Returns(ProviderStatus.NotReady); - await Api.Instance.SetProviderAsync(providerMockDefault); - await providerMockDefault.Received(1).InitializeAsync(Api.Instance.GetContext()); + await Api.Instance.SetProviderAsync(providerMockDefault, TestContext.Current.CancellationToken); + await providerMockDefault.Received(1).InitializeAsync(Api.Instance.GetContext(), TestContext.Current.CancellationToken); var providerMockNamed = Substitute.For(); providerMockNamed.Status.Returns(ProviderStatus.NotReady); - await Api.Instance.SetProviderAsync("the-name", providerMockNamed); - await providerMockNamed.Received(1).InitializeAsync(Api.Instance.GetContext()); + await Api.Instance.SetProviderAsync("the-name", providerMockNamed, TestContext.Current.CancellationToken); + await providerMockNamed.Received(1).InitializeAsync(Api.Instance.GetContext(), TestContext.Current.CancellationToken); } [Fact] @@ -79,28 +79,28 @@ public async Task OpenFeature_Should_Shutdown_Unused_Provider() var providerA = Substitute.For(); providerA.Status.Returns(ProviderStatus.NotReady); - await Api.Instance.SetProviderAsync(providerA); - await providerA.Received(1).InitializeAsync(Api.Instance.GetContext()); + await Api.Instance.SetProviderAsync(providerA, TestContext.Current.CancellationToken); + await providerA.Received(1).InitializeAsync(Api.Instance.GetContext(), TestContext.Current.CancellationToken); var providerB = Substitute.For(); providerB.Status.Returns(ProviderStatus.NotReady); - await Api.Instance.SetProviderAsync(providerB); - await providerB.Received(1).InitializeAsync(Api.Instance.GetContext()); - await providerA.Received(1).ShutdownAsync(); + await Api.Instance.SetProviderAsync(providerB, TestContext.Current.CancellationToken); + await providerB.Received(1).InitializeAsync(Api.Instance.GetContext(), TestContext.Current.CancellationToken); + await providerA.Received(1).ShutdownAsync(TestContext.Current.CancellationToken); var providerC = Substitute.For(); providerC.Status.Returns(ProviderStatus.NotReady); - await Api.Instance.SetProviderAsync("named", providerC); - await providerC.Received(1).InitializeAsync(Api.Instance.GetContext()); + await Api.Instance.SetProviderAsync("named", providerC, TestContext.Current.CancellationToken); + await providerC.Received(1).InitializeAsync(Api.Instance.GetContext(), TestContext.Current.CancellationToken); var providerD = Substitute.For(); providerD.Status.Returns(ProviderStatus.NotReady); - await Api.Instance.SetProviderAsync("named", providerD); - await providerD.Received(1).InitializeAsync(Api.Instance.GetContext()); - await providerC.Received(1).ShutdownAsync(); + await Api.Instance.SetProviderAsync("named", providerD, TestContext.Current.CancellationToken); + await providerD.Received(1).InitializeAsync(Api.Instance.GetContext(), TestContext.Current.CancellationToken); + await providerC.Received(1).ShutdownAsync(TestContext.Current.CancellationToken); } [Fact] @@ -113,13 +113,15 @@ public async Task OpenFeature_Should_Support_Shutdown() var providerB = Substitute.For(); providerB.Status.Returns(ProviderStatus.NotReady); - await Api.Instance.SetProviderAsync(providerA); - await Api.Instance.SetProviderAsync("named", providerB); + await Api.Instance.SetProviderAsync(providerA, TestContext.Current.CancellationToken); + await Api.Instance.SetProviderAsync("named", providerB, TestContext.Current.CancellationToken); await Api.Instance.ShutdownAsync(); +#pragma warning disable xUnit1051 // Possible a oversight but Api.Instance.ShutdownAsync does not accept CancellationToken parameter await providerA.Received(1).ShutdownAsync(); await providerB.Received(1).ShutdownAsync(); +#pragma warning restore xUnit1051 } [Fact] @@ -128,8 +130,8 @@ public async Task OpenFeature_Should_Not_Change_Named_Providers_When_Setting_Def { var openFeature = Api.Instance; - await openFeature.SetProviderAsync(new NoOpFeatureProvider()); - await openFeature.SetProviderAsync(TestProvider.DefaultName, new TestProvider()); + await openFeature.SetProviderAsync(new NoOpFeatureProvider(), TestContext.Current.CancellationToken); + await openFeature.SetProviderAsync(TestProvider.DefaultName, new TestProvider(), TestContext.Current.CancellationToken); var defaultClient = openFeature.GetProviderMetadata(); var domainScopedClient = openFeature.GetProviderMetadata(TestProvider.DefaultName); @@ -144,7 +146,7 @@ public async Task OpenFeature_Should_Set_Default_Provide_When_No_Name_Provided() { var openFeature = Api.Instance; - await openFeature.SetProviderAsync(new TestProvider()); + await openFeature.SetProviderAsync(new TestProvider(), TestContext.Current.CancellationToken); var defaultClient = openFeature.GetProviderMetadata(); @@ -158,8 +160,8 @@ public async Task OpenFeature_Should_Assign_Provider_To_Existing_Client() const string name = "new-client"; var openFeature = Api.Instance; - await openFeature.SetProviderAsync(name, new TestProvider()); - await openFeature.SetProviderAsync(name, new NoOpFeatureProvider()); + await openFeature.SetProviderAsync(name, new TestProvider(), TestContext.Current.CancellationToken); + await openFeature.SetProviderAsync(name, new NoOpFeatureProvider(), TestContext.Current.CancellationToken); Assert.Equal(NoOpProvider.NoOpProviderName, openFeature.GetProviderMetadata(name)?.Name); } @@ -171,8 +173,8 @@ public async Task OpenFeature_Should_Allow_Multiple_Client_Names_Of_Same_Instanc var openFeature = Api.Instance; var provider = new TestProvider(); - await openFeature.SetProviderAsync("a", provider); - await openFeature.SetProviderAsync("b", provider); + await openFeature.SetProviderAsync("a", provider, TestContext.Current.CancellationToken); + await openFeature.SetProviderAsync("b", provider, TestContext.Current.CancellationToken); var clientA = openFeature.GetProvider("a"); var clientB = openFeature.GetProvider("b"); @@ -213,7 +215,7 @@ public void OpenFeature_Should_Add_Hooks() [Specification("1.1.5", "The API MUST provide a function for retrieving the metadata field of the configured `provider`.")] public async Task OpenFeature_Should_Get_Metadata() { - await Api.Instance.SetProviderAsync(new NoOpFeatureProvider()); + await Api.Instance.SetProviderAsync(new NoOpFeatureProvider(), TestContext.Current.CancellationToken); var openFeature = Api.Instance; var metadata = openFeature.GetProviderMetadata(); @@ -263,8 +265,8 @@ public async Task OpenFeature_Should_Allow_Multiple_Client_Mapping() { var openFeature = Api.Instance; - await openFeature.SetProviderAsync("client1", new TestProvider()); - await openFeature.SetProviderAsync("client2", new NoOpFeatureProvider()); + await openFeature.SetProviderAsync("client1", new TestProvider(), TestContext.Current.CancellationToken); + await openFeature.SetProviderAsync("client2", new NoOpFeatureProvider(), TestContext.Current.CancellationToken); var client1 = openFeature.GetClient("client1"); var client2 = openFeature.GetClient("client2"); @@ -272,8 +274,8 @@ public async Task OpenFeature_Should_Allow_Multiple_Client_Mapping() Assert.Equal("client1", client1.GetMetadata().Name); Assert.Equal("client2", client2.GetMetadata().Name); - Assert.True(await client1.GetBooleanValueAsync("test", false)); - Assert.False(await client2.GetBooleanValueAsync("test", false)); + Assert.True(await client1.GetBooleanValueAsync("test", false, cancellationToken: TestContext.Current.CancellationToken)); + Assert.False(await client2.GetBooleanValueAsync("test", false, cancellationToken: TestContext.Current.CancellationToken)); } [Fact] diff --git a/test/OpenFeature.Tests/ProviderRepositoryTests.cs b/test/OpenFeature.Tests/ProviderRepositoryTests.cs index 43fc7135..76899b3e 100644 --- a/test/OpenFeature.Tests/ProviderRepositoryTests.cs +++ b/test/OpenFeature.Tests/ProviderRepositoryTests.cs @@ -15,7 +15,7 @@ public async Task Default_Provider_Is_Set_Without_Await() var repository = new ProviderRepository(); var provider = new NoOpFeatureProvider(); var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync(provider, context); + await repository.SetProviderAsync(provider, context, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(provider, repository.GetProvider()); } @@ -26,9 +26,9 @@ public async Task Initialization_Provider_Method_Is_Invoked_For_Setting_Default_ var providerMock = Substitute.For(); providerMock.Status.Returns(ProviderStatus.NotReady); var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync(providerMock, context); - providerMock.Received(1).InitializeAsync(context); - providerMock.DidNotReceive().ShutdownAsync(); + await repository.SetProviderAsync(providerMock, context, cancellationToken: TestContext.Current.CancellationToken); + providerMock.Received(1).InitializeAsync(context, TestContext.Current.CancellationToken); + providerMock.DidNotReceive().ShutdownAsync(TestContext.Current.CancellationToken); } [Fact] @@ -44,7 +44,7 @@ await repository.SetProviderAsync(providerMock, context, afterInitSuccess: (theP Assert.Equal(providerMock, theProvider); callCount++; return Task.CompletedTask; - }); + }, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(1, callCount); } @@ -89,7 +89,7 @@ await repository.SetProviderAsync(providerMock, context, afterInitError: (thePro callCount++; receivedError = error; return Task.CompletedTask; - }); + }, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal("BAD THINGS", receivedError?.Message); Assert.Equal(1, callCount); } @@ -130,8 +130,8 @@ internal async Task Initialize_Is_Not_Called_For_Ready_Provider(ProviderStatus s var providerMock = Substitute.For(); providerMock.Status.Returns(status); var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync(providerMock, context); - providerMock.DidNotReceive().InitializeAsync(context); + await repository.SetProviderAsync(providerMock, context, cancellationToken: TestContext.Current.CancellationToken); + providerMock.DidNotReceive().InitializeAsync(context, TestContext.Current.CancellationToken); } [Theory] @@ -149,7 +149,7 @@ await repository.SetProviderAsync(providerMock, context, afterInitSuccess: (prov { callCount++; return Task.CompletedTask; - }); + }, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(0, callCount); } @@ -164,10 +164,10 @@ public async Task Replaced_Default_Provider_Is_Shutdown() provider2.Status.Returns(ProviderStatus.NotReady); var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync(provider1, context); - await repository.SetProviderAsync(provider2, context); - provider1.Received(1).ShutdownAsync(); - provider2.DidNotReceive().ShutdownAsync(); + await repository.SetProviderAsync(provider1, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync(provider2, context, cancellationToken: TestContext.Current.CancellationToken); + provider1.Received(1).ShutdownAsync(TestContext.Current.CancellationToken); + provider2.DidNotReceive().ShutdownAsync(TestContext.Current.CancellationToken); } [Fact] @@ -177,7 +177,7 @@ public async Task Named_Provider_Provider_Is_Set_Without_Await() var provider = new NoOpFeatureProvider(); var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync("the-name", provider, context); + await repository.SetProviderAsync("the-name", provider, context, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(provider, repository.GetProvider("the-name")); } @@ -188,9 +188,9 @@ public async Task Initialization_Provider_Method_Is_Invoked_For_Setting_Named_Pr var providerMock = Substitute.For(); providerMock.Status.Returns(ProviderStatus.NotReady); var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync("the-name", providerMock, context); - providerMock.Received(1).InitializeAsync(context); - providerMock.DidNotReceive().ShutdownAsync(); + await repository.SetProviderAsync("the-name", providerMock, context, cancellationToken: TestContext.Current.CancellationToken); + providerMock.Received(1).InitializeAsync(context, TestContext.Current.CancellationToken); + providerMock.DidNotReceive().ShutdownAsync(TestContext.Current.CancellationToken); } [Fact] @@ -206,7 +206,7 @@ await repository.SetProviderAsync("the-name", providerMock, context, afterInitSu Assert.Equal(providerMock, theProvider); callCount++; return Task.CompletedTask; - }); + }, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(1, callCount); } @@ -250,7 +250,7 @@ await repository.SetProviderAsync("the-provider", providerMock, context, afterIn callCount++; receivedError = error; return Task.CompletedTask; - }); + }, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal("BAD THINGS", receivedError?.Message); Assert.Equal(1, callCount); } @@ -291,8 +291,8 @@ internal async Task Initialize_Is_Not_Called_For_Ready_Named_Provider(ProviderSt var providerMock = Substitute.For(); providerMock.Status.Returns(status); var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync("the-name", providerMock, context); - providerMock.DidNotReceive().InitializeAsync(context); + await repository.SetProviderAsync("the-name", providerMock, context, cancellationToken: TestContext.Current.CancellationToken); + providerMock.DidNotReceive().InitializeAsync(context, TestContext.Current.CancellationToken); } [Theory] @@ -306,12 +306,11 @@ internal async Task AfterInitialize_Is_Not_Called_For_Ready_Named_Provider(Provi providerMock.Status.Returns(status); var context = new EvaluationContextBuilder().Build(); var callCount = 0; - await repository.SetProviderAsync("the-name", providerMock, context, - afterInitSuccess: (provider, ct) => + await repository.SetProviderAsync("the-name", providerMock, context, afterInitSuccess: (provider, ct) => { callCount++; return Task.CompletedTask; - }); + }, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(0, callCount); } @@ -326,10 +325,10 @@ public async Task Replaced_Named_Provider_Is_Shutdown() provider2.Status.Returns(ProviderStatus.NotReady); var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync("the-name", provider1, context); - await repository.SetProviderAsync("the-name", provider2, context); - provider1.Received(1).ShutdownAsync(); - provider2.DidNotReceive().ShutdownAsync(); + await repository.SetProviderAsync("the-name", provider1, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync("the-name", provider2, context, cancellationToken: TestContext.Current.CancellationToken); + provider1.Received(1).ShutdownAsync(TestContext.Current.CancellationToken); + provider2.DidNotReceive().ShutdownAsync(TestContext.Current.CancellationToken); } [Fact] @@ -344,12 +343,12 @@ public async Task In_Use_Provider_Named_And_Default_Is_Not_Shutdown() var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync(provider1, context); - await repository.SetProviderAsync("A", provider1, context); + await repository.SetProviderAsync(provider1, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync("A", provider1, context, cancellationToken: TestContext.Current.CancellationToken); // Provider one is replaced for "A", but not default. - await repository.SetProviderAsync("A", provider2, context); + await repository.SetProviderAsync("A", provider2, context, cancellationToken: TestContext.Current.CancellationToken); - provider1.DidNotReceive().ShutdownAsync(); + provider1.DidNotReceive().ShutdownAsync(TestContext.Current.CancellationToken); } [Fact] @@ -364,12 +363,12 @@ public async Task In_Use_Provider_Two_Named_Is_Not_Shutdown() var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync("B", provider1, context); - await repository.SetProviderAsync("A", provider1, context); + await repository.SetProviderAsync("B", provider1, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync("A", provider1, context, cancellationToken: TestContext.Current.CancellationToken); // Provider one is replaced for "A", but not "B". - await repository.SetProviderAsync("A", provider2, context); + await repository.SetProviderAsync("A", provider2, context, cancellationToken: TestContext.Current.CancellationToken); - provider1.DidNotReceive().ShutdownAsync(); + provider1.DidNotReceive().ShutdownAsync(TestContext.Current.CancellationToken); } [Fact] @@ -384,13 +383,13 @@ public async Task When_All_Instances_Are_Removed_Shutdown_Is_Called() var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync("B", provider1, context); - await repository.SetProviderAsync("A", provider1, context); + await repository.SetProviderAsync("B", provider1, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync("A", provider1, context, cancellationToken: TestContext.Current.CancellationToken); - await repository.SetProviderAsync("A", provider2, context); - await repository.SetProviderAsync("B", provider2, context); + await repository.SetProviderAsync("A", provider2, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync("B", provider2, context, cancellationToken: TestContext.Current.CancellationToken); - provider1.Received(1).ShutdownAsync(); + provider1.Received(1).ShutdownAsync(TestContext.Current.CancellationToken); } [Fact] @@ -405,8 +404,8 @@ public async Task Can_Get_Providers_By_Name() var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync("A", provider1, context); - await repository.SetProviderAsync("B", provider2, context); + await repository.SetProviderAsync("A", provider1, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync("B", provider2, context, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(provider1, repository.GetProvider("A")); Assert.Equal(provider2, repository.GetProvider("B")); @@ -424,8 +423,8 @@ public async Task Replaced_Named_Provider_Gets_Latest_Set() var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync("A", provider1, context); - await repository.SetProviderAsync("A", provider2, context); + await repository.SetProviderAsync("A", provider1, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync("A", provider2, context, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(provider2, repository.GetProvider("A")); } @@ -445,17 +444,17 @@ public async Task Can_Shutdown_All_Providers() var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync(provider1, context); - await repository.SetProviderAsync("provider1", provider1, context); - await repository.SetProviderAsync("provider2", provider2, context); - await repository.SetProviderAsync("provider2a", provider2, context); - await repository.SetProviderAsync("provider3", provider3, context); + await repository.SetProviderAsync(provider1, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync("provider1", provider1, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync("provider2", provider2, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync("provider2a", provider2, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync("provider3", provider3, context, cancellationToken: TestContext.Current.CancellationToken); - await repository.ShutdownAsync(); + await repository.ShutdownAsync(cancellationToken: TestContext.Current.CancellationToken); - provider1.Received(1).ShutdownAsync(); - provider2.Received(1).ShutdownAsync(); - provider3.Received(1).ShutdownAsync(); + provider1.Received(1).ShutdownAsync(TestContext.Current.CancellationToken); + provider2.Received(1).ShutdownAsync(TestContext.Current.CancellationToken); + provider3.Received(1).ShutdownAsync(TestContext.Current.CancellationToken); } [Fact] @@ -465,12 +464,12 @@ public async Task Setting_Same_Default_Provider_Has_No_Effect() var provider = Substitute.For(); provider.Status.Returns(ProviderStatus.NotReady); var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync(provider, context); - await repository.SetProviderAsync(provider, context); + await repository.SetProviderAsync(provider, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync(provider, context, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(provider, repository.GetProvider()); - provider.Received(1).InitializeAsync(context); - provider.DidNotReceive().ShutdownAsync(); + provider.Received(1).InitializeAsync(context, TestContext.Current.CancellationToken); + provider.DidNotReceive().ShutdownAsync(TestContext.Current.CancellationToken); } [Fact] @@ -480,12 +479,12 @@ public async Task Setting_Null_Default_Provider_Has_No_Effect() var provider = Substitute.For(); provider.Status.Returns(ProviderStatus.NotReady); var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync(provider, context); - await repository.SetProviderAsync(null, context); + await repository.SetProviderAsync(provider, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync(null, context, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(provider, repository.GetProvider()); - provider.Received(1).InitializeAsync(context); - provider.DidNotReceive().ShutdownAsync(); + provider.Received(1).InitializeAsync(context, TestContext.Current.CancellationToken); + provider.DidNotReceive().ShutdownAsync(TestContext.Current.CancellationToken); } [Fact] @@ -500,10 +499,10 @@ public async Task Setting_Null_Named_Provider_Removes_It() defaultProvider.Status.Returns(ProviderStatus.NotReady); var context = new EvaluationContextBuilder().Build(); - await repository.SetProviderAsync(defaultProvider, context); + await repository.SetProviderAsync(defaultProvider, context, cancellationToken: TestContext.Current.CancellationToken); - await repository.SetProviderAsync("named-provider", namedProvider, context); - await repository.SetProviderAsync("named-provider", null, context); + await repository.SetProviderAsync("named-provider", namedProvider, context, cancellationToken: TestContext.Current.CancellationToken); + await repository.SetProviderAsync("named-provider", null, context, cancellationToken: TestContext.Current.CancellationToken); Assert.Equal(defaultProvider, repository.GetProvider("named-provider")); } diff --git a/test/OpenFeature.Tests/Providers/Memory/InMemoryProviderTests.cs b/test/OpenFeature.Tests/Providers/Memory/InMemoryProviderTests.cs index 52eace28..69103187 100644 --- a/test/OpenFeature.Tests/Providers/Memory/InMemoryProviderTests.cs +++ b/test/OpenFeature.Tests/Providers/Memory/InMemoryProviderTests.cs @@ -174,7 +174,7 @@ public InMemoryProviderTests() [Fact] public async Task GetBoolean_ShouldEvaluateWithReasonAndVariant() { - ResolutionDetails details = await this.commonProvider.ResolveBooleanValueAsync("boolean-flag", false, EvaluationContext.Empty); + ResolutionDetails details = await this.commonProvider.ResolveBooleanValueAsync("boolean-flag", false, EvaluationContext.Empty, TestContext.Current.CancellationToken); Assert.True(details.Value); Assert.Equal(Reason.Static, details.Reason); Assert.Equal("on", details.Variant); @@ -184,7 +184,7 @@ public async Task GetBoolean_ShouldEvaluateWithReasonAndVariant() public async Task GetBoolean_WithNoEvaluationContext_ShouldEvaluateWithReasonAndVariant() { // Act - ResolutionDetails details = await this.commonProvider.ResolveBooleanValueAsync("boolean-flag", false); + ResolutionDetails details = await this.commonProvider.ResolveBooleanValueAsync("boolean-flag", false, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.True(details.Value); @@ -196,7 +196,7 @@ public async Task GetBoolean_WithNoEvaluationContext_ShouldEvaluateWithReasonAnd public async Task GetBoolean_WhenDisabled_ShouldEvaluateWithDefaultReason() { // Act - ResolutionDetails details = await this.commonProvider.ResolveBooleanValueAsync("boolean-disabled-flag", false, EvaluationContext.Empty); + ResolutionDetails details = await this.commonProvider.ResolveBooleanValueAsync("boolean-disabled-flag", false, EvaluationContext.Empty, TestContext.Current.CancellationToken); // Assert Assert.False(details.Value); @@ -207,7 +207,7 @@ public async Task GetBoolean_WhenDisabled_ShouldEvaluateWithDefaultReason() [Fact] public async Task GetString_ShouldEvaluateWithReasonAndVariant() { - ResolutionDetails details = await this.commonProvider.ResolveStringValueAsync("string-flag", "nope", EvaluationContext.Empty); + ResolutionDetails details = await this.commonProvider.ResolveStringValueAsync("string-flag", "nope", EvaluationContext.Empty, TestContext.Current.CancellationToken); Assert.Equal("hi", details.Value); Assert.Equal(Reason.Static, details.Reason); Assert.Equal("greeting", details.Variant); @@ -217,7 +217,7 @@ public async Task GetString_ShouldEvaluateWithReasonAndVariant() public async Task GetString_WithNoEvaluationContext_ShouldEvaluateWithReasonAndVariant() { // Act - ResolutionDetails details = await this.commonProvider.ResolveStringValueAsync("string-flag", "nope"); + ResolutionDetails details = await this.commonProvider.ResolveStringValueAsync("string-flag", "nope", cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal("hi", details.Value); @@ -229,7 +229,7 @@ public async Task GetString_WithNoEvaluationContext_ShouldEvaluateWithReasonAndV public async Task GetString_WhenDisabled_ShouldEvaluateWithDefaultReason() { // Act - ResolutionDetails details = await this.commonProvider.ResolveStringValueAsync("string-disabled-flag", "nope"); + ResolutionDetails details = await this.commonProvider.ResolveStringValueAsync("string-disabled-flag", "nope", cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal("nope", details.Value); @@ -240,7 +240,7 @@ public async Task GetString_WhenDisabled_ShouldEvaluateWithDefaultReason() [Fact] public async Task GetInt_ShouldEvaluateWithReasonAndVariant() { - ResolutionDetails details = await this.commonProvider.ResolveIntegerValueAsync("integer-flag", 13, EvaluationContext.Empty); + ResolutionDetails details = await this.commonProvider.ResolveIntegerValueAsync("integer-flag", 13, EvaluationContext.Empty, TestContext.Current.CancellationToken); Assert.Equal(10, details.Value); Assert.Equal(Reason.Static, details.Reason); Assert.Equal("ten", details.Variant); @@ -250,7 +250,7 @@ public async Task GetInt_ShouldEvaluateWithReasonAndVariant() public async Task GetInt_WithNoEvaluationContext_ShouldEvaluateWithReasonAndVariant() { // Act - ResolutionDetails details = await this.commonProvider.ResolveIntegerValueAsync("integer-flag", 13); + ResolutionDetails details = await this.commonProvider.ResolveIntegerValueAsync("integer-flag", 13, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(10, details.Value); @@ -262,7 +262,7 @@ public async Task GetInt_WithNoEvaluationContext_ShouldEvaluateWithReasonAndVari public async Task GetInt_WhenDisabled_ShouldEvaluateWithDefaultReason() { // Act - ResolutionDetails details = await this.commonProvider.ResolveIntegerValueAsync("integer-disabled-flag", 13); + ResolutionDetails details = await this.commonProvider.ResolveIntegerValueAsync("integer-disabled-flag", 13, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(13, details.Value); @@ -273,7 +273,7 @@ public async Task GetInt_WhenDisabled_ShouldEvaluateWithDefaultReason() [Fact] public async Task GetDouble_ShouldEvaluateWithReasonAndVariant() { - ResolutionDetails details = await this.commonProvider.ResolveDoubleValueAsync("float-flag", 13, EvaluationContext.Empty); + ResolutionDetails details = await this.commonProvider.ResolveDoubleValueAsync("float-flag", 13, EvaluationContext.Empty, TestContext.Current.CancellationToken); Assert.Equal(0.5, details.Value); Assert.Equal(Reason.Static, details.Reason); Assert.Equal("half", details.Variant); @@ -283,7 +283,7 @@ public async Task GetDouble_ShouldEvaluateWithReasonAndVariant() public async Task GetDouble_WithNoEvaluationContext_ShouldEvaluateWithReasonAndVariant() { // Arrange - ResolutionDetails details = await this.commonProvider.ResolveDoubleValueAsync("float-flag", 13); + ResolutionDetails details = await this.commonProvider.ResolveDoubleValueAsync("float-flag", 13, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(0.5, details.Value); @@ -295,7 +295,7 @@ public async Task GetDouble_WithNoEvaluationContext_ShouldEvaluateWithReasonAndV public async Task GetDouble_WhenDisabled_ShouldEvaluateWithDefaultReason() { // Act - ResolutionDetails details = await this.commonProvider.ResolveDoubleValueAsync("float-disabled-flag", 1.3); + ResolutionDetails details = await this.commonProvider.ResolveDoubleValueAsync("float-disabled-flag", 1.3, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(1.3, details.Value); @@ -306,7 +306,7 @@ public async Task GetDouble_WhenDisabled_ShouldEvaluateWithDefaultReason() [Fact] public async Task GetStruct_ShouldEvaluateWithReasonAndVariant() { - ResolutionDetails details = await this.commonProvider.ResolveStructureValueAsync("object-flag", new Value(), EvaluationContext.Empty); + ResolutionDetails details = await this.commonProvider.ResolveStructureValueAsync("object-flag", new Value(), EvaluationContext.Empty, TestContext.Current.CancellationToken); Assert.Equal(true, details.Value.AsStructure?["showImages"].AsBoolean); Assert.Equal("Check out these pics!", details.Value.AsStructure?["title"].AsString); Assert.Equal(100, details.Value.AsStructure?["imagesPerPage"].AsInteger); @@ -318,7 +318,7 @@ public async Task GetStruct_ShouldEvaluateWithReasonAndVariant() public async Task GetStruct_WithNoEvaluationContext_ShouldEvaluateWithReasonAndVariant() { // Act - ResolutionDetails details = await this.commonProvider.ResolveStructureValueAsync("object-flag", new Value()); + ResolutionDetails details = await this.commonProvider.ResolveStructureValueAsync("object-flag", new Value(), cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(true, details.Value.AsStructure?["showImages"].AsBoolean); @@ -339,7 +339,7 @@ public async Task GetStruct_WhenDisabled_ShouldEvaluateWithDefaultReason() ); // Act - ResolutionDetails details = await this.commonProvider.ResolveStructureValueAsync("object-disabled-flag", defaultValue); + ResolutionDetails details = await this.commonProvider.ResolveStructureValueAsync("object-disabled-flag", defaultValue, cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal(true, details.Value.AsStructure?["default"].AsBoolean); @@ -351,7 +351,7 @@ public async Task GetStruct_WhenDisabled_ShouldEvaluateWithDefaultReason() public async Task GetString_ContextSensitive_ShouldEvaluateWithReasonAndVariant() { EvaluationContext context = EvaluationContext.Builder().Set("email", "me@faas.com").Build(); - ResolutionDetails details = await this.commonProvider.ResolveStringValueAsync("context-aware", "nope", context); + ResolutionDetails details = await this.commonProvider.ResolveStringValueAsync("context-aware", "nope", context, TestContext.Current.CancellationToken); Assert.Equal("INTERNAL", details.Value); Assert.Equal(Reason.TargetingMatch, details.Reason); Assert.Equal("internal", details.Variant); @@ -361,7 +361,7 @@ public async Task GetString_ContextSensitive_ShouldEvaluateWithReasonAndVariant( public async Task GetString_ContextSensitive_WithNoEvaluationContext_ShouldEvaluateWithReasonAndVariant() { // Act - ResolutionDetails details = await this.commonProvider.ResolveStringValueAsync("context-aware", "nope"); + ResolutionDetails details = await this.commonProvider.ResolveStringValueAsync("context-aware", "nope", cancellationToken: TestContext.Current.CancellationToken); // Assert Assert.Equal("EXTERNAL", details.Value); @@ -381,7 +381,7 @@ public async Task EmptyFlags_ShouldWork() public async Task MissingFlag_ShouldReturnFlagNotFoundEvaluationFlag() { // Act - var result = await this.commonProvider.ResolveBooleanValueAsync("missing-flag", false, EvaluationContext.Empty); + var result = await this.commonProvider.ResolveBooleanValueAsync("missing-flag", false, EvaluationContext.Empty, TestContext.Current.CancellationToken); // Assert Assert.Equal(Reason.Error, result.Reason); @@ -392,7 +392,7 @@ public async Task MissingFlag_ShouldReturnFlagNotFoundEvaluationFlag() public async Task MismatchedFlag_ShouldReturnTypeMismatchError() { // Act - var result = await this.commonProvider.ResolveStringValueAsync("boolean-flag", "nope", EvaluationContext.Empty); + var result = await this.commonProvider.ResolveStringValueAsync("boolean-flag", "nope", EvaluationContext.Empty, TestContext.Current.CancellationToken); // Assert Assert.Equal(Reason.Error, result.Reason); @@ -402,14 +402,14 @@ public async Task MismatchedFlag_ShouldReturnTypeMismatchError() [Fact] public async Task MissingDefaultVariant_ShouldThrow() { - await Assert.ThrowsAsync(() => this.commonProvider.ResolveBooleanValueAsync("invalid-flag", false, EvaluationContext.Empty)); + await Assert.ThrowsAsync(() => this.commonProvider.ResolveBooleanValueAsync("invalid-flag", false, EvaluationContext.Empty, TestContext.Current.CancellationToken)); } [Fact] public async Task MissingEvaluatedVariant_ReturnsDefaultVariant() { // Act - var result = await this.commonProvider.ResolveBooleanValueAsync("invalid-evaluator-flag", false, EvaluationContext.Empty); + var result = await this.commonProvider.ResolveBooleanValueAsync("invalid-evaluator-flag", false, EvaluationContext.Empty, TestContext.Current.CancellationToken); // Assert Assert.True(result.Value); @@ -421,7 +421,7 @@ public async Task MissingEvaluatedVariant_ReturnsDefaultVariant() public async Task ContextEvaluatorThrows_ReturnsDefaultVariant() { // Act - var result = await this.commonProvider.ResolveBooleanValueAsync("evaluator-throws-flag", false, EvaluationContext.Empty); + var result = await this.commonProvider.ResolveBooleanValueAsync("evaluator-throws-flag", false, EvaluationContext.Empty, TestContext.Current.CancellationToken); // Assert Assert.True(result.Value); @@ -443,7 +443,7 @@ public async Task PutConfiguration_shouldUpdateConfigAndRunHandlers() ) }}); - ResolutionDetails details = await provider.ResolveBooleanValueAsync("old-flag", false, EvaluationContext.Empty); + ResolutionDetails details = await provider.ResolveBooleanValueAsync("old-flag", false, EvaluationContext.Empty, TestContext.Current.CancellationToken); Assert.True(details.Value); // update flags @@ -458,17 +458,17 @@ await provider.UpdateFlagsAsync(new Dictionary(){ ) }}); - var res = await provider.GetEventChannel().Reader.ReadAsync() as ProviderEventPayload; + var res = await provider.GetEventChannel().Reader.ReadAsync(TestContext.Current.CancellationToken) as ProviderEventPayload; Assert.Equal(ProviderEventTypes.ProviderConfigurationChanged, res?.Type); // old flag should be gone - var oldFlag = await provider.ResolveBooleanValueAsync("old-flag", false, EvaluationContext.Empty); + var oldFlag = await provider.ResolveBooleanValueAsync("old-flag", false, EvaluationContext.Empty, TestContext.Current.CancellationToken); Assert.Equal(Reason.Error, oldFlag.Reason); Assert.Equal(ErrorType.FlagNotFound, oldFlag.ErrorType); // new flag should be present, old gone (defaults), handler run. - ResolutionDetails detailsAfter = await provider.ResolveStringValueAsync("new-flag", "nope", EvaluationContext.Empty); + ResolutionDetails detailsAfter = await provider.ResolveStringValueAsync("new-flag", "nope", EvaluationContext.Empty, TestContext.Current.CancellationToken); Assert.True(details.Value); Assert.Equal("hi", detailsAfter.Value); }