diff --git a/src/OpenFeature/Api.cs b/src/OpenFeature/Api.cs index e2690a7a..af302e7e 100644 --- a/src/OpenFeature/Api.cs +++ b/src/OpenFeature/Api.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -36,17 +37,40 @@ static Api() { } private Api() { } /// - /// Sets the feature provider. In order to wait for the provider to be set, and initialization to complete, + /// Sets the default feature provider to given clientName without awaiting its initialization. + /// + /// The provider cannot be set to null. Attempting to set the provider to null has no effect. + /// Implementation of + [Obsolete("Will be removed in later versions; use SetProviderAsync, which can be awaited")] + public void SetProvider(FeatureProvider featureProvider) + { + this._eventExecutor.RegisterDefaultFeatureProvider(featureProvider); + _ = this._repository.SetProvider(featureProvider, this.GetContext()); + } + + /// + /// Sets the default feature provider. In order to wait for the provider to be set, and initialization to complete, /// await the returned task. /// /// The provider cannot be set to null. Attempting to set the provider to null has no effect. /// Implementation of - public async Task SetProvider(FeatureProvider featureProvider) + public async Task SetProviderAsync(FeatureProvider featureProvider) { this._eventExecutor.RegisterDefaultFeatureProvider(featureProvider); await this._repository.SetProvider(featureProvider, this.GetContext()).ConfigureAwait(false); } + /// + /// Sets the feature provider to given clientName without awaiting its initialization. + /// + /// Name of client + /// Implementation of + [Obsolete("Will be removed in later versions; use SetProviderAsync, which can be awaited")] + public void SetProvider(string clientName, FeatureProvider featureProvider) + { + this._eventExecutor.RegisterClientFeatureProvider(clientName, featureProvider); + _ = this._repository.SetProvider(clientName, featureProvider, this.GetContext()); + } /// /// Sets the feature provider to given clientName. In order to wait for the provider to be set, and @@ -54,7 +78,7 @@ public async Task SetProvider(FeatureProvider featureProvider) /// /// Name of client /// Implementation of - public async Task SetProvider(string clientName, FeatureProvider featureProvider) + public async Task SetProviderAsync(string clientName, FeatureProvider featureProvider) { this._eventExecutor.RegisterClientFeatureProvider(clientName, featureProvider); await this._repository.SetProvider(clientName, featureProvider, this.GetContext()).ConfigureAwait(false); diff --git a/test/OpenFeature.E2ETests/Steps/EvaluationStepDefinitions.cs b/test/OpenFeature.E2ETests/Steps/EvaluationStepDefinitions.cs index 4847bfb2..d2cd483d 100644 --- a/test/OpenFeature.E2ETests/Steps/EvaluationStepDefinitions.cs +++ b/test/OpenFeature.E2ETests/Steps/EvaluationStepDefinitions.cs @@ -42,7 +42,7 @@ public EvaluationStepDefinitions(ScenarioContext scenarioContext) { _scenarioContext = scenarioContext; var flagdProvider = new FlagdProvider(); - Api.Instance.SetProvider(flagdProvider).Wait(); + Api.Instance.SetProviderAsync(flagdProvider).Wait(); client = Api.Instance.GetClient(); } diff --git a/test/OpenFeature.Tests/ClearOpenFeatureInstanceFixture.cs b/test/OpenFeature.Tests/ClearOpenFeatureInstanceFixture.cs index a70921f7..5f31c71a 100644 --- a/test/OpenFeature.Tests/ClearOpenFeatureInstanceFixture.cs +++ b/test/OpenFeature.Tests/ClearOpenFeatureInstanceFixture.cs @@ -7,7 +7,7 @@ public ClearOpenFeatureInstanceFixture() { Api.Instance.SetContext(null); Api.Instance.ClearHooks(); - Api.Instance.SetProvider(new NoOpFeatureProvider()).Wait(); + Api.Instance.SetProviderAsync(new NoOpFeatureProvider()).Wait(); } } } diff --git a/test/OpenFeature.Tests/OpenFeatureClientTests.cs b/test/OpenFeature.Tests/OpenFeatureClientTests.cs index 30bee168..86c61f83 100644 --- a/test/OpenFeature.Tests/OpenFeatureClientTests.cs +++ b/test/OpenFeature.Tests/OpenFeatureClientTests.cs @@ -75,7 +75,7 @@ public async Task OpenFeatureClient_Should_Allow_Flag_Evaluation() var defaultStructureValue = fixture.Create(); var emptyFlagOptions = new FlagEvaluationOptions(ImmutableList.Empty, ImmutableDictionary.Empty); - await Api.Instance.SetProvider(new NoOpFeatureProvider()); + await Api.Instance.SetProviderAsync(new NoOpFeatureProvider()); var client = Api.Instance.GetClient(clientName, clientVersion); (await client.GetBooleanValue(flagName, defaultBoolValue)).Should().Be(defaultBoolValue); @@ -121,7 +121,7 @@ public async Task OpenFeatureClient_Should_Allow_Details_Flag_Evaluation() var defaultStructureValue = fixture.Create(); var emptyFlagOptions = new FlagEvaluationOptions(ImmutableList.Empty, ImmutableDictionary.Empty); - await Api.Instance.SetProvider(new NoOpFeatureProvider()); + await Api.Instance.SetProviderAsync(new NoOpFeatureProvider()); var client = Api.Instance.GetClient(clientName, clientVersion); var boolFlagEvaluationDetails = new FlagEvaluationDetails(flagName, defaultBoolValue, ErrorType.None, NoOpProvider.ReasonNoOp, NoOpProvider.Variant); @@ -172,7 +172,7 @@ public async Task OpenFeatureClient_Should_Return_DefaultValue_When_Type_Mismatc mockedFeatureProvider.GetMetadata().Returns(new Metadata(fixture.Create())); mockedFeatureProvider.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProvider(mockedFeatureProvider); + await Api.Instance.SetProviderAsync(mockedFeatureProvider); var client = Api.Instance.GetClient(clientName, clientVersion, mockedLogger); var evaluationDetails = await client.GetObjectDetails(flagName, defaultValue); @@ -202,7 +202,7 @@ public async Task Should_Resolve_BooleanValue() featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProvider(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock); var client = Api.Instance.GetClient(clientName, clientVersion); (await client.GetBooleanValue(flagName, defaultValue)).Should().Be(defaultValue); @@ -224,7 +224,7 @@ public async Task Should_Resolve_StringValue() featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProvider(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock); var client = Api.Instance.GetClient(clientName, clientVersion); (await client.GetStringValue(flagName, defaultValue)).Should().Be(defaultValue); @@ -246,7 +246,7 @@ public async Task Should_Resolve_IntegerValue() featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProvider(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock); var client = Api.Instance.GetClient(clientName, clientVersion); (await client.GetIntegerValue(flagName, defaultValue)).Should().Be(defaultValue); @@ -268,7 +268,7 @@ public async Task Should_Resolve_DoubleValue() featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProvider(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock); var client = Api.Instance.GetClient(clientName, clientVersion); (await client.GetDoubleValue(flagName, defaultValue)).Should().Be(defaultValue); @@ -290,7 +290,7 @@ public async Task Should_Resolve_StructureValue() featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProvider(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock); var client = Api.Instance.GetClient(clientName, clientVersion); (await client.GetObjectValue(flagName, defaultValue)).Should().Be(defaultValue); @@ -313,7 +313,7 @@ public async Task When_Error_Is_Returned_From_Provider_Should_Return_Error() featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProvider(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock); var client = Api.Instance.GetClient(clientName, clientVersion); var response = await client.GetObjectDetails(flagName, defaultValue); @@ -338,7 +338,7 @@ public async Task When_Exception_Occurs_During_Evaluation_Should_Return_Error() featureProviderMock.GetMetadata().Returns(new Metadata(fixture.Create())); featureProviderMock.GetProviderHooks().Returns(ImmutableList.Empty); - await Api.Instance.SetProvider(featureProviderMock); + await Api.Instance.SetProviderAsync(featureProviderMock); var client = Api.Instance.GetClient(clientName, clientVersion); var response = await client.GetObjectDetails(flagName, defaultValue); @@ -351,7 +351,7 @@ public async Task When_Exception_Occurs_During_Evaluation_Should_Return_Error() [Fact] public async Task Should_Use_No_Op_When_Provider_Is_Null() { - await Api.Instance.SetProvider(null); + await Api.Instance.SetProviderAsync(null); var client = new FeatureClient("test", "test"); (await client.GetIntegerValue("some-key", 12)).Should().Be(12); } diff --git a/test/OpenFeature.Tests/OpenFeatureEventTests.cs b/test/OpenFeature.Tests/OpenFeatureEventTests.cs index 42558e88..525241fc 100644 --- a/test/OpenFeature.Tests/OpenFeatureEventTests.cs +++ b/test/OpenFeature.Tests/OpenFeatureEventTests.cs @@ -70,7 +70,7 @@ public async Task API_Level_Event_Handlers_Should_Be_Registered() Api.Instance.AddHandler(ProviderEventTypes.ProviderStale, eventHandler); var testProvider = new TestProvider(); - await Api.Instance.SetProvider(testProvider); + await Api.Instance.SetProviderAsync(testProvider); testProvider.SendEvent(ProviderEventTypes.ProviderConfigurationChanged); testProvider.SendEvent(ProviderEventTypes.ProviderError); @@ -117,7 +117,33 @@ public async Task API_Level_Event_Handlers_Should_Be_Informed_About_Ready_State_ var eventHandler = Substitute.For(); var testProvider = new TestProvider(); - await Api.Instance.SetProvider(testProvider); + await Api.Instance.SetProviderAsync(testProvider); + + Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); + + await Utils.AssertUntilAsync(_ => eventHandler + .Received() + .Invoke( + Arg.Is( + payload => payload.ProviderName == testProvider.GetMetadata().Name && payload.Type == ProviderEventTypes.ProviderReady + ))); + } + + [Fact] + [Specification("5.1.2", "When a `provider` signals the occurrence of a particular `event`, the associated `client` and `API` event handlers MUST run.")] + [Specification("5.2.2", "The `API` MUST provide a function for associating `handler functions` with a particular `provider event type`.")] + [Specification("5.2.3", "The `event details` MUST contain the `provider name` associated with the event.")] + [Specification("5.2.4", "The `handler function` MUST accept a `event details` parameter.")] + [Specification("5.3.1", "If the provider's `initialize` function terminates normally, `PROVIDER_READY` handlers MUST run.")] + [Specification("5.3.3", "Handlers attached after the provider is already in the associated state, MUST run immediately.")] + public async Task API_Level_Event_Handlers_Should_Be_Informed_About_Ready_State_After_Registering_Provider_Ready_Sync() + { + var eventHandler = Substitute.For(); + + var testProvider = new TestProvider(); +#pragma warning disable CS0618 // Type or member is obsolete + Api.Instance.SetProvider(testProvider); +#pragma warning restore CS0618 // Type or member is obsolete Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); @@ -141,7 +167,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.SetProvider(testProvider); + await Api.Instance.SetProviderAsync(testProvider); testProvider.SetStatus(ProviderStatus.Error); @@ -166,7 +192,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.SetProvider(testProvider); + await Api.Instance.SetProviderAsync(testProvider); testProvider.SetStatus(ProviderStatus.Stale); @@ -194,12 +220,12 @@ public async Task API_Level_Event_Handlers_Should_Be_Exchangeable() Api.Instance.AddHandler(ProviderEventTypes.ProviderConfigurationChanged, eventHandler); var testProvider = new TestProvider(); - await Api.Instance.SetProvider(testProvider); + await Api.Instance.SetProviderAsync(testProvider); testProvider.SendEvent(ProviderEventTypes.ProviderConfigurationChanged); var newTestProvider = new TestProvider(); - await Api.Instance.SetProvider(newTestProvider); + await Api.Instance.SetProviderAsync(newTestProvider); newTestProvider.SendEvent(ProviderEventTypes.ProviderConfigurationChanged); @@ -223,13 +249,13 @@ public async Task API_Level_Event_Handlers_Should_Be_Removable() Api.Instance.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); var testProvider = new TestProvider(); - await Api.Instance.SetProvider(testProvider); + await Api.Instance.SetProviderAsync(testProvider); Thread.Sleep(1000); Api.Instance.RemoveHandler(ProviderEventTypes.ProviderReady, eventHandler); var newTestProvider = new TestProvider(); - await Api.Instance.SetProvider(newTestProvider); + await Api.Instance.SetProviderAsync(newTestProvider); eventHandler.Received(1).Invoke(Arg.Is(payload => payload.ProviderName == testProvider.GetMetadata().Name)); } @@ -254,7 +280,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.SetProvider(testProvider); + await Api.Instance.SetProviderAsync(testProvider); await Utils.AssertUntilAsync( _ => failingEventHandler.Received().Invoke(Arg.Is(payload => payload.ProviderName == testProvider.GetMetadata().Name)) @@ -277,7 +303,7 @@ public async Task Client_Level_Event_Handlers_Should_Be_Registered() var myClient = Api.Instance.GetClient(fixture.Create()); var testProvider = new TestProvider(); - await Api.Instance.SetProvider(myClient.GetMetadata().Name, testProvider); + await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name, testProvider); myClient.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); @@ -306,7 +332,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.SetProvider(myClient.GetMetadata().Name, testProvider); + await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name, testProvider); await Utils.AssertUntilAsync( _ => failingEventHandler.Received().Invoke(Arg.Is(payload => payload.ProviderName == testProvider.GetMetadata().Name)) @@ -335,9 +361,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.SetProvider(apiProvider); + await Api.Instance.SetProviderAsync(apiProvider); // set the other provider specifically for the client - await Api.Instance.SetProvider(myClientWithBoundProvider.GetMetadata().Name, clientProvider); + await Api.Instance.SetProviderAsync(myClientWithBoundProvider.GetMetadata().Name, clientProvider); myClientWithNoBoundProvider.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); myClientWithBoundProvider.AddHandler(ProviderEventTypes.ProviderReady, clientEventHandler); @@ -367,7 +393,7 @@ 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.SetProvider(defaultProvider); + await Api.Instance.SetProviderAsync(defaultProvider); client.AddHandler(ProviderEventTypes.ProviderConfigurationChanged, clientEventHandler); @@ -379,7 +405,7 @@ await Utils.AssertUntilAsync( ); // set the other provider specifically for the client - await Api.Instance.SetProvider(client.GetMetadata().Name, clientProvider); + await Api.Instance.SetProviderAsync(client.GetMetadata().Name, clientProvider); // now, send another event for the default handler defaultProvider.SendEvent(ProviderEventTypes.ProviderConfigurationChanged); @@ -410,7 +436,7 @@ public async Task Client_Level_Event_Handlers_Should_Be_Informed_About_Ready_Sta var myClient = Api.Instance.GetClient(fixture.Create()); var testProvider = new TestProvider(); - await Api.Instance.SetProvider(myClient.GetMetadata().Name, testProvider); + await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name, testProvider); // add the event handler after the provider has already transitioned into the ready state myClient.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); @@ -435,7 +461,7 @@ public async Task Client_Level_Event_Handlers_Should_Be_Removable() myClient.AddHandler(ProviderEventTypes.ProviderReady, eventHandler); var testProvider = new TestProvider(); - await Api.Instance.SetProvider(myClient.GetMetadata().Name, testProvider); + await Api.Instance.SetProviderAsync(myClient.GetMetadata().Name, testProvider); // wait for the first event to be received await Utils.AssertUntilAsync(_ => myClient.RemoveHandler(ProviderEventTypes.ProviderReady, eventHandler)); diff --git a/test/OpenFeature.Tests/OpenFeatureHookTests.cs b/test/OpenFeature.Tests/OpenFeatureHookTests.cs index b3aee4d8..b4cb958c 100644 --- a/test/OpenFeature.Tests/OpenFeatureHookTests.cs +++ b/test/OpenFeature.Tests/OpenFeatureHookTests.cs @@ -51,7 +51,7 @@ public async Task Hooks_Should_Be_Called_In_Order() var testProvider = new TestProvider(); testProvider.AddHook(providerHook); Api.Instance.AddHooks(apiHook); - await Api.Instance.SetProvider(testProvider); + await Api.Instance.SetProviderAsync(testProvider); var client = Api.Instance.GetClient(clientName, clientVersion); client.AddHooks(clientHook); @@ -197,7 +197,7 @@ public async Task Evaluation_Context_Must_Be_Merged_In_Correct_Order() provider.ResolveBooleanValue(Arg.Any(), Arg.Any(), Arg.Any()).Returns(new ResolutionDetails("test", true)); - await Api.Instance.SetProvider(provider); + await Api.Instance.SetProviderAsync(provider); var hook = Substitute.For(); hook.Before(Arg.Any>(), Arg.Any>()).Returns(hookContext); @@ -269,7 +269,7 @@ public async Task Hook_Should_Execute_In_Correct_Order() _ = hook.After(Arg.Any>(), Arg.Any>(), Arg.Any>()); _ = hook.Finally(Arg.Any>(), Arg.Any>()); - await Api.Instance.SetProvider(featureProvider); + await Api.Instance.SetProviderAsync(featureProvider); var client = Api.Instance.GetClient(); client.AddHooks(hook); @@ -301,7 +301,7 @@ 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.SetProvider(testProvider); + await Api.Instance.SetProviderAsync(testProvider); var client = Api.Instance.GetClient(); client.AddHooks(hook2); await client.GetBooleanValue("test", false, null, @@ -332,7 +332,7 @@ public async Task Finally_Hook_Should_Be_Executed_Even_If_Abnormal_Termination() hook2.Finally(Arg.Any>(), null).Returns(Task.CompletedTask); hook1.Finally(Arg.Any>(), null).Throws(new Exception()); - await Api.Instance.SetProvider(featureProvider); + await Api.Instance.SetProviderAsync(featureProvider); var client = Api.Instance.GetClient(); client.AddHooks(new[] { hook1, hook2 }); client.GetHooks().Count().Should().Be(2); @@ -377,7 +377,7 @@ public async Task Error_Hook_Should_Be_Executed_Even_If_Abnormal_Termination() hook2.Error(Arg.Any>(), Arg.Any(), null).Returns(Task.CompletedTask); hook1.Error(Arg.Any>(), Arg.Any(), null).Returns(Task.CompletedTask); - await Api.Instance.SetProvider(featureProvider1); + await Api.Instance.SetProviderAsync(featureProvider1); var client = Api.Instance.GetClient(); client.AddHooks(new[] { hook1, hook2 }); @@ -414,7 +414,7 @@ public async Task Error_Occurs_During_Before_After_Evaluation_Should_Not_Invoke_ _ = hook1.Error(Arg.Any>(), Arg.Any(), null); _ = hook2.Error(Arg.Any>(), Arg.Any(), null); - await Api.Instance.SetProvider(featureProvider); + await Api.Instance.SetProviderAsync(featureProvider); var client = Api.Instance.GetClient(); client.AddHooks(new[] { hook1, hook2 }); @@ -459,7 +459,7 @@ public async Task Hook_Hints_May_Be_Optional() hook.Finally(Arg.Any>(), Arg.Any>()) .Returns(Task.CompletedTask); - await Api.Instance.SetProvider(featureProvider); + await Api.Instance.SetProviderAsync(featureProvider); var client = Api.Instance.GetClient(); await client.GetBooleanValue("test", false, EvaluationContext.Empty, flagOptions); @@ -537,7 +537,7 @@ public async Task When_Error_Occurs_In_After_Hook_Should_Invoke_Error_Hook() hook.Finally(Arg.Any>(), Arg.Any>()) .Returns(Task.CompletedTask); - await Api.Instance.SetProvider(featureProvider); + await Api.Instance.SetProviderAsync(featureProvider); var client = Api.Instance.GetClient(); var resolvedFlag = await client.GetBooleanValue("test", true, config: flagOptions); diff --git a/test/OpenFeature.Tests/OpenFeatureTests.cs b/test/OpenFeature.Tests/OpenFeatureTests.cs index 28ba9f42..d43bf045 100644 --- a/test/OpenFeature.Tests/OpenFeatureTests.cs +++ b/test/OpenFeature.Tests/OpenFeatureTests.cs @@ -28,13 +28,13 @@ public async Task OpenFeature_Should_Initialize_Provider() var providerMockDefault = Substitute.For(); providerMockDefault.GetStatus().Returns(ProviderStatus.NotReady); - await Api.Instance.SetProvider(providerMockDefault).ConfigureAwait(false); + await Api.Instance.SetProviderAsync(providerMockDefault).ConfigureAwait(false); await providerMockDefault.Received(1).Initialize(Api.Instance.GetContext()).ConfigureAwait(false); var providerMockNamed = Substitute.For(); providerMockNamed.GetStatus().Returns(ProviderStatus.NotReady); - await Api.Instance.SetProvider("the-name", providerMockNamed).ConfigureAwait(false); + await Api.Instance.SetProviderAsync("the-name", providerMockNamed).ConfigureAwait(false); await providerMockNamed.Received(1).Initialize(Api.Instance.GetContext()).ConfigureAwait(false); } @@ -46,26 +46,26 @@ public async Task OpenFeature_Should_Shutdown_Unused_Provider() var providerA = Substitute.For(); providerA.GetStatus().Returns(ProviderStatus.NotReady); - await Api.Instance.SetProvider(providerA).ConfigureAwait(false); + await Api.Instance.SetProviderAsync(providerA).ConfigureAwait(false); await providerA.Received(1).Initialize(Api.Instance.GetContext()).ConfigureAwait(false); var providerB = Substitute.For(); providerB.GetStatus().Returns(ProviderStatus.NotReady); - await Api.Instance.SetProvider(providerB).ConfigureAwait(false); + await Api.Instance.SetProviderAsync(providerB).ConfigureAwait(false); await providerB.Received(1).Initialize(Api.Instance.GetContext()).ConfigureAwait(false); await providerA.Received(1).Shutdown().ConfigureAwait(false); var providerC = Substitute.For(); providerC.GetStatus().Returns(ProviderStatus.NotReady); - await Api.Instance.SetProvider("named", providerC).ConfigureAwait(false); + await Api.Instance.SetProviderAsync("named", providerC).ConfigureAwait(false); await providerC.Received(1).Initialize(Api.Instance.GetContext()).ConfigureAwait(false); var providerD = Substitute.For(); providerD.GetStatus().Returns(ProviderStatus.NotReady); - await Api.Instance.SetProvider("named", providerD).ConfigureAwait(false); + await Api.Instance.SetProviderAsync("named", providerD).ConfigureAwait(false); await providerD.Received(1).Initialize(Api.Instance.GetContext()).ConfigureAwait(false); await providerC.Received(1).Shutdown().ConfigureAwait(false); } @@ -80,8 +80,8 @@ public async Task OpenFeature_Should_Support_Shutdown() var providerB = Substitute.For(); providerB.GetStatus().Returns(ProviderStatus.NotReady); - await Api.Instance.SetProvider(providerA).ConfigureAwait(false); - await Api.Instance.SetProvider("named", providerB).ConfigureAwait(false); + await Api.Instance.SetProviderAsync(providerA).ConfigureAwait(false); + await Api.Instance.SetProviderAsync("named", providerB).ConfigureAwait(false); await Api.Instance.Shutdown().ConfigureAwait(false); @@ -91,12 +91,12 @@ public async Task OpenFeature_Should_Support_Shutdown() [Fact] [Specification("1.1.3", "The `API` MUST provide a function to bind a given `provider` to one or more client `name`s. If the client-name already has a bound provider, it is overwritten with the new mapping.")] - public void OpenFeature_Should_Not_Change_Named_Providers_When_Setting_Default_Provider() + public async Task OpenFeature_Should_Not_Change_Named_Providers_When_Setting_Default_Provider() { var openFeature = Api.Instance; - openFeature.SetProvider(new NoOpFeatureProvider()); - openFeature.SetProvider(TestProvider.DefaultName, new TestProvider()); + await openFeature.SetProviderAsync(new NoOpFeatureProvider()).ConfigureAwait(false); + await openFeature.SetProviderAsync(TestProvider.DefaultName, new TestProvider()).ConfigureAwait(false); var defaultClient = openFeature.GetProviderMetadata(); var namedClient = openFeature.GetProviderMetadata(TestProvider.DefaultName); @@ -107,11 +107,11 @@ public void OpenFeature_Should_Not_Change_Named_Providers_When_Setting_Default_P [Fact] [Specification("1.1.3", "The `API` MUST provide a function to bind a given `provider` to one or more client `name`s. If the client-name already has a bound provider, it is overwritten with the new mapping.")] - public void OpenFeature_Should_Set_Default_Provide_When_No_Name_Provided() + public async Task OpenFeature_Should_Set_Default_Provide_When_No_Name_Provided() { var openFeature = Api.Instance; - openFeature.SetProvider(new TestProvider()); + await openFeature.SetProviderAsync(new TestProvider()).ConfigureAwait(false); var defaultClient = openFeature.GetProviderMetadata(); @@ -120,26 +120,26 @@ public void OpenFeature_Should_Set_Default_Provide_When_No_Name_Provided() [Fact] [Specification("1.1.3", "The `API` MUST provide a function to bind a given `provider` to one or more client `name`s. If the client-name already has a bound provider, it is overwritten with the new mapping.")] - public void OpenFeature_Should_Assign_Provider_To_Existing_Client() + public async Task OpenFeature_Should_Assign_Provider_To_Existing_Client() { const string name = "new-client"; var openFeature = Api.Instance; - openFeature.SetProvider(name, new TestProvider()); - openFeature.SetProvider(name, new NoOpFeatureProvider()); + await openFeature.SetProviderAsync(name, new TestProvider()).ConfigureAwait(true); + await openFeature.SetProviderAsync(name, new NoOpFeatureProvider()).ConfigureAwait(true); openFeature.GetProviderMetadata(name).Name.Should().Be(NoOpProvider.NoOpProviderName); } [Fact] [Specification("1.1.3", "The `API` MUST provide a function to bind a given `provider` to one or more client `name`s. If the client-name already has a bound provider, it is overwritten with the new mapping.")] - public void OpenFeature_Should_Allow_Multiple_Client_Names_Of_Same_Instance() + public async Task OpenFeature_Should_Allow_Multiple_Client_Names_Of_Same_Instance() { var openFeature = Api.Instance; var provider = new TestProvider(); - openFeature.SetProvider("a", provider); - openFeature.SetProvider("b", provider); + await openFeature.SetProviderAsync("a", provider).ConfigureAwait(true); + await openFeature.SetProviderAsync("b", provider).ConfigureAwait(true); var clientA = openFeature.GetProvider("a"); var clientB = openFeature.GetProvider("b"); @@ -180,7 +180,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 void OpenFeature_Should_Get_Metadata() { - Api.Instance.SetProvider(new NoOpFeatureProvider()).Wait(); + Api.Instance.SetProviderAsync(new NoOpFeatureProvider()).Wait(); var openFeature = Api.Instance; var metadata = openFeature.GetProviderMetadata(); @@ -226,12 +226,12 @@ public void Should_Always_Have_Provider() } [Fact] - public void OpenFeature_Should_Allow_Multiple_Client_Mapping() + public async Task OpenFeature_Should_Allow_Multiple_Client_Mapping() { var openFeature = Api.Instance; - openFeature.SetProvider("client1", new TestProvider()); - openFeature.SetProvider("client2", new NoOpFeatureProvider()); + await openFeature.SetProviderAsync("client1", new TestProvider()).ConfigureAwait(true); + await openFeature.SetProviderAsync("client2", new NoOpFeatureProvider()).ConfigureAwait(true); var client1 = openFeature.GetClient("client1"); var client2 = openFeature.GetClient("client2"); diff --git a/test/OpenFeature.Tests/ProviderRepositoryTests.cs b/test/OpenFeature.Tests/ProviderRepositoryTests.cs index 6d2ff310..62cbe9d6 100644 --- a/test/OpenFeature.Tests/ProviderRepositoryTests.cs +++ b/test/OpenFeature.Tests/ProviderRepositoryTests.cs @@ -16,24 +16,24 @@ namespace OpenFeature.Tests public class ProviderRepositoryTests { [Fact] - public void Default_Provider_Is_Set_Without_Await() + public async Task Default_Provider_Is_Set_Without_Await() { var repository = new ProviderRepository(); var provider = new NoOpFeatureProvider(); var context = new EvaluationContextBuilder().Build(); - repository.SetProvider(provider, context); + await repository.SetProvider(provider, context); Assert.Equal(provider, repository.GetProvider()); } [Fact] - public void AfterSet_Is_Invoked_For_Setting_Default_Provider() + public async void AfterSet_Is_Invoked_For_Setting_Default_Provider() { var repository = new ProviderRepository(); var provider = new NoOpFeatureProvider(); var context = new EvaluationContextBuilder().Build(); var callCount = 0; // The setting of the provider is synchronous, so the afterSet should be as well. - repository.SetProvider(provider, context, afterSet: (theProvider) => + await repository.SetProvider(provider, context, afterSet: (theProvider) => { callCount++; Assert.Equal(provider, theProvider); @@ -182,24 +182,24 @@ await repository.SetProvider(provider2, context, afterError: (provider, ex) => } [Fact] - public void Named_Provider_Provider_Is_Set_Without_Await() + public async Task Named_Provider_Provider_Is_Set_Without_Await() { var repository = new ProviderRepository(); var provider = new NoOpFeatureProvider(); var context = new EvaluationContextBuilder().Build(); - repository.SetProvider("the-name", provider, context); + await repository.SetProvider("the-name", provider, context); Assert.Equal(provider, repository.GetProvider("the-name")); } [Fact] - public void AfterSet_Is_Invoked_For_Setting_Named_Provider() + public async Task AfterSet_Is_Invoked_For_Setting_Named_Provider() { var repository = new ProviderRepository(); var provider = new NoOpFeatureProvider(); var context = new EvaluationContextBuilder().Build(); var callCount = 0; // The setting of the provider is synchronous, so the afterSet should be as well. - repository.SetProvider("the-name", provider, context, afterSet: (theProvider) => + await repository.SetProvider("the-name", provider, context, afterSet: (theProvider) => { callCount++; Assert.Equal(provider, theProvider);