|
8 | 8 | import static org.mockito.ArgumentMatchers.any;
|
9 | 9 | import static org.mockito.ArgumentMatchers.anyLong;
|
10 | 10 | import static org.mockito.ArgumentMatchers.argThat;
|
| 11 | +import static org.mockito.Mockito.doAnswer; |
11 | 12 | import static org.mockito.Mockito.mock;
|
12 | 13 | import static org.mockito.Mockito.mockStatic;
|
13 | 14 | import static org.mockito.Mockito.times;
|
|
21 | 22 | import java.util.Map;
|
22 | 23 | import java.util.concurrent.TimeUnit;
|
23 | 24 | import java.util.function.Supplier;
|
| 25 | +import java.util.concurrent.LinkedBlockingQueue; |
24 | 26 |
|
25 | 27 | import org.junit.jupiter.api.BeforeAll;
|
26 | 28 | import org.junit.jupiter.api.Test;
|
| 29 | +import org.mockito.ArgumentMatchers; |
27 | 30 | import org.mockito.MockedStatic;
|
| 31 | +import org.mockito.Mockito; |
28 | 32 |
|
29 | 33 | import com.google.protobuf.Struct;
|
30 | 34 |
|
31 | 35 | import dev.openfeature.contrib.providers.flagd.resolver.Resolver;
|
32 | 36 | import dev.openfeature.contrib.providers.flagd.resolver.grpc.GrpcConnector;
|
33 | 37 | import dev.openfeature.contrib.providers.flagd.resolver.grpc.GrpcResolver;
|
34 | 38 | import dev.openfeature.contrib.providers.flagd.resolver.grpc.cache.Cache;
|
| 39 | +import dev.openfeature.contrib.providers.flagd.resolver.process.InProcessResolver; |
| 40 | +import dev.openfeature.contrib.providers.flagd.resolver.process.MockStorage; |
| 41 | +import dev.openfeature.contrib.providers.flagd.resolver.process.model.FeatureFlag; |
| 42 | +import dev.openfeature.contrib.providers.flagd.resolver.process.storage.StorageState; |
| 43 | +import dev.openfeature.flagd.grpc.Schema.EventStreamResponse; |
35 | 44 | import dev.openfeature.flagd.grpc.evaluation.ServiceGrpc;
|
| 45 | +import dev.openfeature.flagd.grpc.evaluation.Evaluation.EventStreamRequest; |
36 | 46 | import dev.openfeature.flagd.grpc.evaluation.Evaluation.ResolveBooleanRequest;
|
37 | 47 | import dev.openfeature.flagd.grpc.evaluation.Evaluation.ResolveBooleanResponse;
|
38 | 48 | import dev.openfeature.flagd.grpc.evaluation.Evaluation.ResolveFloatResponse;
|
|
52 | 62 | import dev.openfeature.sdk.Reason;
|
53 | 63 | import dev.openfeature.sdk.Structure;
|
54 | 64 | import dev.openfeature.sdk.Value;
|
| 65 | +import io.cucumber.core.stepexpression.ArgumentMatcher; |
55 | 66 | import io.cucumber.java.AfterAll;
|
56 | 67 | import io.grpc.Channel;
|
57 | 68 | import io.grpc.Deadline;
|
| 69 | +import io.grpc.stub.StreamObserver; |
58 | 70 |
|
59 | 71 | class FlagdProviderTest {
|
60 | 72 | private static final String FLAG_KEY = "some-key";
|
@@ -824,6 +836,43 @@ void initializationAndShutdown() throws Exception{
|
824 | 836 | verify(resolverMock, times(1)).shutdown();
|
825 | 837 | }
|
826 | 838 |
|
| 839 | + @Test |
| 840 | + void test_state_on_grpc_resolver_shutdown() throws Exception { |
| 841 | + // setup mock provider |
| 842 | + final FlagdProvider grpcProvider = Mockito.spy(FlagdProvider.class); |
| 843 | + try { |
| 844 | + doAnswer(invocation -> { |
| 845 | + final Field stateField = FlagdProvider.class.getDeclaredField("state"); |
| 846 | + stateField.setAccessible(true); |
| 847 | + stateField.set(grpcProvider, ProviderState.READY); |
| 848 | + |
| 849 | + final Field intializedField = FlagdProvider.class.getDeclaredField("initialized"); |
| 850 | + intializedField.setAccessible(true); |
| 851 | + intializedField.set(grpcProvider, true); |
| 852 | + |
| 853 | + return null; |
| 854 | + }).when(grpcProvider).initialize(any()); |
| 855 | + } catch (Exception e) { |
| 856 | + throw new RuntimeException(e); |
| 857 | + } |
| 858 | + |
| 859 | + grpcProvider.initialize(new ImmutableContext()); |
| 860 | + assertEquals(ProviderState.READY, grpcProvider.getState()); |
| 861 | + grpcProvider.shutdown(); |
| 862 | + assertEquals(ProviderState.NOT_READY, grpcProvider.getState()); |
| 863 | + } |
| 864 | + |
| 865 | + @Test |
| 866 | + void test_state_on_in_process_resolver_shutdown() throws Exception { |
| 867 | + // setup mock in-process provider |
| 868 | + FlagdProvider inProcessProvider = createInProcessProvider(); |
| 869 | + |
| 870 | + inProcessProvider.initialize(new ImmutableContext()); |
| 871 | + assertEquals(ProviderState.READY, inProcessProvider.getState()); |
| 872 | + inProcessProvider.shutdown(); |
| 873 | + assertEquals(ProviderState.NOT_READY, inProcessProvider.getState()); |
| 874 | + } |
| 875 | + |
827 | 876 |
|
828 | 877 | // test helper
|
829 | 878 |
|
@@ -863,4 +912,29 @@ private FlagdProvider createProvider(GrpcConnector grpc, Cache cache, Supplier<P
|
863 | 912 | return provider;
|
864 | 913 | }
|
865 | 914 |
|
| 915 | + // Create an in process provider |
| 916 | + private FlagdProvider createInProcessProvider() { |
| 917 | + |
| 918 | + final FlagdOptions flagdOptions = FlagdOptions.builder() |
| 919 | + .resolverType(Config.Resolver.IN_PROCESS) |
| 920 | + .deadline(1000) |
| 921 | + .build(); |
| 922 | + final FlagdProvider provider = new FlagdProvider(flagdOptions); |
| 923 | + final MockStorage mockStorage = new MockStorage(new HashMap<String, FeatureFlag>(), new LinkedBlockingQueue<StorageState>(List.of(StorageState.OK))); |
| 924 | + |
| 925 | + try { |
| 926 | + final Field flagResolver = FlagdProvider.class.getDeclaredField("flagResolver"); |
| 927 | + flagResolver.setAccessible(true); |
| 928 | + final Resolver resolver = (Resolver) flagResolver.get(provider); |
| 929 | + |
| 930 | + final Field flagStore = InProcessResolver.class.getDeclaredField("flagStore"); |
| 931 | + flagStore.setAccessible(true); |
| 932 | + flagStore.set(resolver, mockStorage); |
| 933 | + } catch (NoSuchFieldException | IllegalAccessException e) { |
| 934 | + throw new RuntimeException(e); |
| 935 | + } |
| 936 | + |
| 937 | + return provider; |
| 938 | + } |
| 939 | + |
866 | 940 | }
|
0 commit comments