2
2
3
3
import com .google .common .collect .ImmutableMap ;
4
4
import dev .openfeature .sdk .Client ;
5
+ import dev .openfeature .sdk .EventDetails ;
5
6
import dev .openfeature .sdk .ImmutableContext ;
6
7
import dev .openfeature .sdk .OpenFeatureAPI ;
7
8
import dev .openfeature .sdk .Value ;
8
9
import dev .openfeature .sdk .exceptions .FlagNotFoundError ;
9
10
import dev .openfeature .sdk .exceptions .ProviderNotReadyError ;
10
11
import dev .openfeature .sdk .exceptions .TypeMismatchError ;
11
12
import lombok .SneakyThrows ;
12
- import org .junit .jupiter .api .BeforeAll ;
13
+ import org .junit .jupiter .api .BeforeEach ;
13
14
import org .junit .jupiter .api .Test ;
14
15
16
+ import java .util .ArrayList ;
15
17
import java .util .HashMap ;
18
+ import java .util .List ;
16
19
import java .util .Map ;
20
+ import java .util .concurrent .Callable ;
17
21
import java .util .concurrent .ExecutorService ;
18
22
import java .util .concurrent .Executors ;
23
+ import java .util .function .Consumer ;
19
24
20
25
import static dev .openfeature .sdk .Structure .mapToStructure ;
21
26
import static dev .openfeature .sdk .testutils .TestFlagsUtils .buildFlags ;
22
27
import static org .junit .jupiter .api .Assertions .assertEquals ;
23
28
import static org .junit .jupiter .api .Assertions .assertThrows ;
24
29
import static org .junit .jupiter .api .Assertions .assertTrue ;
25
30
import static org .mockito .ArgumentMatchers .any ;
31
+ import static org .mockito .ArgumentMatchers .argThat ;
32
+ import static org .mockito .Mockito .mock ;
26
33
import static org .mockito .Mockito .spy ;
27
34
import static org .mockito .Mockito .times ;
28
35
import static org .mockito .Mockito .verify ;
@@ -34,8 +41,8 @@ class InMemoryProviderTest {
34
41
private static InMemoryProvider provider ;
35
42
36
43
@ SneakyThrows
37
- @ BeforeAll
38
- static void beforeAll () {
44
+ @ BeforeEach
45
+ void beforeEach () {
39
46
Map <String , Flag <?>> flags = buildFlags ();
40
47
provider = spy (new InMemoryProvider (flags ));
41
48
OpenFeatureAPI .getInstance ().onProviderConfigurationChanged (eventDetails -> {});
@@ -108,20 +115,39 @@ void shouldThrowIfNotInitialized() {
108
115
assertThrows (ProviderNotReadyError .class , ()-> inMemoryProvider .getBooleanEvaluation ("fail_not_initialized" , false , new ImmutableContext ()));
109
116
}
110
117
118
+ @ SuppressWarnings ("unchecked" )
111
119
@ Test
112
- void multithreadedTest () {
120
+ void emitChangedFlagsOnlyIfThereAreChangedFlags () {
121
+ Consumer <EventDetails > handler = mock (Consumer .class );
122
+ Map <String , Flag <?>> flags = buildFlags ();
123
+
124
+ OpenFeatureAPI .getInstance ().onProviderConfigurationChanged (handler );
125
+ OpenFeatureAPI .getInstance ().setProviderAndWait (provider );
126
+
127
+ provider .updateFlags (flags );
128
+
129
+ verify (handler , times (1 ))
130
+ .accept (argThat (details -> details .getFlagsChanged ().isEmpty ()));
131
+ }
132
+
133
+ @ Test
134
+ void multithreadedTest () throws InterruptedException {
113
135
ExecutorService executorService = Executors .newFixedThreadPool (100 );
136
+ List <Callable <Void >> updates = new ArrayList <>();
114
137
for (int i = 0 ; i < 10000 ; i ++) {
115
138
String flagKey = "multithreadedFlag" + i ;
116
- executorService . submit (() -> {
139
+ updates . add (() -> {
117
140
provider .updateFlag (flagKey , Flag .builder ()
118
141
.variant ("on" , true )
119
142
.variant ("off" , false )
120
143
.defaultVariant ("on" )
121
144
.build ());
145
+ return null ;
122
146
});
123
147
}
124
148
149
+ executorService .invokeAll (updates );
150
+
125
151
for (int i = 0 ; i < 10000 ; i ++) {
126
152
assertTrue (client .getBooleanValue ("multithreadedFlag" + i , false ));
127
153
}
0 commit comments