20
20
21
21
import android .content .res .AssetManager ;
22
22
import android .util .Log ;
23
+ import androidx .annotation .Nullable ;
23
24
import androidx .test .core .app .ApplicationProvider ;
24
25
import cloud .eppo .android .helpers .AssignmentTestCase ;
25
26
import cloud .eppo .android .helpers .AssignmentTestCaseDeserializer ;
37
38
import java .io .File ;
38
39
import java .io .IOException ;
39
40
import java .io .InputStream ;
40
- import java .lang .reflect .Field ;
41
41
import java .text .ParseException ;
42
42
import java .text .SimpleDateFormat ;
43
43
import java .util .Date ;
@@ -62,44 +62,50 @@ public class EppoClientTest {
62
62
"https://us-central1-eppo-qa.cloudfunctions.net/serveGitHubRacTestFile" ;
63
63
private static final String INVALID_HOST = "https://thisisabaddomainforthistest.com" ;
64
64
private final ObjectMapper mapper = new ObjectMapper ().registerModule (module ());
65
-
66
65
private AssignmentLogger mockAssignmentLogger ;
67
66
68
67
private void initClient (
69
68
String host ,
70
69
boolean throwOnCallbackError ,
71
70
boolean shouldDeleteCacheFiles ,
72
71
boolean isGracefulMode ,
72
+ boolean obfuscateConfig ,
73
+ @ Nullable EppoHttpClient httpClientOverride ,
74
+ @ Nullable ConfigurationStore configurationStoreOverride ,
73
75
String apiKey ) {
74
76
if (shouldDeleteCacheFiles ) {
75
77
clearCacheFile (apiKey );
76
78
}
77
79
mockAssignmentLogger = mock (AssignmentLogger .class );
78
80
CountDownLatch lock = new CountDownLatch (1 );
79
81
82
+ InitializationCallback callback =
83
+ new InitializationCallback () {
84
+ @ Override
85
+ public void onCompleted () {
86
+ Log .i (TAG , "Test client onCompleted callback" );
87
+ lock .countDown ();
88
+ }
89
+
90
+ @ Override
91
+ public void onError (String errorMessage ) {
92
+ Log .w (TAG , "Test client onError callback" );
93
+ if (throwOnCallbackError ) {
94
+ throw new RuntimeException ("Unable to initialize: " + errorMessage );
95
+ }
96
+ lock .countDown ();
97
+ }
98
+ };
80
99
new EppoClient .Builder ()
81
100
.application (ApplicationProvider .getApplicationContext ())
82
101
.apiKey (apiKey )
83
102
.isGracefulMode (isGracefulMode )
84
103
.host (host )
85
104
.assignmentLogger (mockAssignmentLogger )
86
- .callback (
87
- new InitializationCallback () {
88
- @ Override
89
- public void onCompleted () {
90
- Log .w (TAG , "Test client onCompleted callback" );
91
- lock .countDown ();
92
- }
93
-
94
- @ Override
95
- public void onError (String errorMessage ) {
96
- Log .w (TAG , "Test client onError callback" );
97
- if (throwOnCallbackError ) {
98
- throw new RuntimeException ("Unable to initialize: " + errorMessage );
99
- }
100
- lock .countDown ();
101
- }
102
- })
105
+ .obfuscateConfig (obfuscateConfig )
106
+ .httpClient (httpClientOverride )
107
+ .configStore (configurationStoreOverride )
108
+ .callback (callback )
103
109
.buildAndInit ();
104
110
105
111
// Wait for initialization to succeed or fail, up to 10 seconds, before continuing
@@ -120,10 +126,6 @@ public void cleanUp() {
120
126
for (String apiKey : apiKeys ) {
121
127
clearCacheFile (apiKey );
122
128
}
123
- // Reset any development overrides
124
- setIsConfigObfuscatedField (true );
125
- setHttpClientOverrideField (null );
126
- setConfigurationStoreOverrideField (null );
127
129
}
128
130
129
131
private void clearCacheFile (String apiKey ) {
@@ -135,20 +137,19 @@ private void clearCacheFile(String apiKey) {
135
137
136
138
@ Test
137
139
public void testUnobfuscatedAssignments () {
138
- setIsConfigObfuscatedField (false );
139
- initClient (TEST_HOST , true , true , false , DUMMY_API_KEY );
140
+ initClient (TEST_HOST , true , true , false , false , null , null , DUMMY_API_KEY );
140
141
runTestCases ();
141
142
}
142
143
143
144
@ Test
144
145
public void testAssignments () {
145
- initClient (TEST_HOST , true , true , false , DUMMY_API_KEY );
146
+ initClient (TEST_HOST , true , true , false , true , null , null , DUMMY_API_KEY );
146
147
runTestCases ();
147
148
}
148
149
149
150
@ Test
150
151
public void testErrorGracefulModeOn () throws JSONException {
151
- initClient (TEST_HOST , false , true , true , DUMMY_API_KEY );
152
+ initClient (TEST_HOST , false , true , true , true , null , null , DUMMY_API_KEY );
152
153
153
154
EppoClient realClient = EppoClient .getInstance ();
154
155
EppoClient spyClient = spy (realClient );
@@ -200,7 +201,7 @@ public void testErrorGracefulModeOn() throws JSONException {
200
201
201
202
@ Test
202
203
public void testErrorGracefulModeOff () {
203
- initClient (TEST_HOST , false , true , false , DUMMY_API_KEY );
204
+ initClient (TEST_HOST , false , true , false , true , null , null , DUMMY_API_KEY );
204
205
205
206
EppoClient realClient = EppoClient .getInstance ();
206
207
EppoClient spyClient = spy (realClient );
@@ -277,15 +278,30 @@ private void runTestCases() {
277
278
@ Test
278
279
public void testCachedAssignments () {
279
280
// First initialize successfully
280
- initClient (TEST_HOST , true , true , false , DUMMY_API_KEY ); // ensure cache is populated
281
+ initClient (
282
+ TEST_HOST ,
283
+ true ,
284
+ true ,
285
+ false ,
286
+ false ,
287
+ null ,
288
+ null ,
289
+ DUMMY_API_KEY ); // ensure cache is populated
281
290
282
291
// wait for a bit since cache file is written asynchronously
283
292
waitForPopulatedCache ();
284
293
285
294
// Then reinitialize with a bad host so we know it's using the cached UFC built from the first
286
295
// initialization
287
296
initClient (
288
- INVALID_HOST , false , false , false , DUMMY_API_KEY ); // invalid host to force to use cache
297
+ INVALID_HOST ,
298
+ false ,
299
+ false ,
300
+ false ,
301
+ false ,
302
+ null ,
303
+ null ,
304
+ DUMMY_API_KEY ); // invalid host to force to use cache
289
305
290
306
runTestCases ();
291
307
}
@@ -414,8 +430,7 @@ public void testInvalidConfigJSON() {
414
430
.when (mockHttpClient )
415
431
.get (anyString (), any (RequestCallback .class ));
416
432
417
- setHttpClientOverrideField (mockHttpClient );
418
- initClient (TEST_HOST , true , true , false , DUMMY_API_KEY );
433
+ initClient (TEST_HOST , true , true , false , false , mockHttpClient , null , DUMMY_API_KEY );
419
434
420
435
String result =
421
436
EppoClient .getInstance ()
@@ -431,7 +446,7 @@ public void testCachedBadResponseRequiresFetch() {
431
446
ApplicationProvider .getApplicationContext (), safeCacheKey (DUMMY_API_KEY ));
432
447
cacheFile .setContents ("{ invalid }" );
433
448
434
- initClient (TEST_HOST , true , false , false , DUMMY_API_KEY );
449
+ initClient (TEST_HOST , true , false , false , true , null , null , DUMMY_API_KEY );
435
450
436
451
double assignment = EppoClient .getInstance ().getDoubleAssignment ("numeric_flag" , "alice" , 0.0 );
437
452
assertEquals (3.1415926 , assignment , 0.0000001 );
@@ -445,14 +460,14 @@ public void testEmptyFlagsResponseRequiresFetch() {
445
460
ApplicationProvider .getApplicationContext (), safeCacheKey (DUMMY_API_KEY ));
446
461
cacheFile .setContents ("{\" flags\" : {}}" );
447
462
448
- initClient (TEST_HOST , true , false , false , DUMMY_API_KEY );
463
+ initClient (TEST_HOST , true , false , false , true , null , null , DUMMY_API_KEY );
449
464
double assignment = EppoClient .getInstance ().getDoubleAssignment ("numeric_flag" , "alice" , 0.0 );
450
465
assertEquals (3.1415926 , assignment , 0.0000001 );
451
466
}
452
467
453
468
@ Test
454
469
public void testDifferentCacheFilesPerKey () {
455
- initClient (TEST_HOST , true , true , false , DUMMY_API_KEY );
470
+ initClient (TEST_HOST , true , true , false , true , null , null , DUMMY_API_KEY );
456
471
// API Key 1 will fetch and then populate its cache with the usual test data
457
472
double apiKey1Assignment =
458
473
EppoClient .getInstance ().getDoubleAssignment ("numeric_flag" , "alice" , 0.0 );
@@ -495,15 +510,15 @@ public void testDifferentCacheFilesPerKey() {
495
510
+ " }\n "
496
511
+ "}" );
497
512
498
- initClient (TEST_HOST , true , false , false , DUMMY_OTHER_API_KEY );
513
+ initClient (TEST_HOST , true , false , false , true , null , null , DUMMY_OTHER_API_KEY );
499
514
500
515
// Ensure API key 2 uses its cache
501
516
double apiKey2Assignment =
502
517
EppoClient .getInstance ().getDoubleAssignment ("numeric_flag" , "alice" , 0.0 );
503
518
assertEquals (1.2345 , apiKey2Assignment , 0.0000001 );
504
519
505
520
// Reinitialize API key 1 to be sure it used its cache
506
- initClient (TEST_HOST , true , false , false , DUMMY_API_KEY );
521
+ initClient (TEST_HOST , true , false , false , true , null , null , DUMMY_API_KEY );
507
522
// API Key 1 will fetch and then populate its cache with the usual test data
508
523
apiKey1Assignment = EppoClient .getInstance ().getDoubleAssignment ("numeric_flag" , "alice" , 0.0 );
509
524
assertEquals (3.1415926 , apiKey1Assignment , 0.0000001 );
@@ -531,8 +546,7 @@ protected FlagConfigResponse readCacheFile() {
531
546
}
532
547
};
533
548
534
- setConfigurationStoreOverrideField (slowStore );
535
- initClient (TEST_HOST , true , false , false , DUMMY_API_KEY );
549
+ initClient (TEST_HOST , true , false , false , true , null , slowStore , DUMMY_API_KEY );
536
550
537
551
// Give time for async slow cache read to finish
538
552
try {
@@ -574,7 +588,7 @@ private void waitForPopulatedCache() {
574
588
@ Test
575
589
public void testAssignmentEventCorrectlyCreated () {
576
590
Date testStart = new Date ();
577
- initClient (TEST_HOST , true , false , false , DUMMY_API_KEY );
591
+ initClient (TEST_HOST , true , false , false , true , null , null , DUMMY_API_KEY );
578
592
SubjectAttributes subjectAttributes = new SubjectAttributes ();
579
593
subjectAttributes .put ("age" , EppoValue .valueOf (30 ));
580
594
subjectAttributes .put ("employer" , EppoValue .valueOf ("Eppo" ));
@@ -619,33 +633,6 @@ public void testAssignmentEventCorrectlyCreated() {
619
633
assertEquals (expectedMeta , capturedAssignment .getMetaData ());
620
634
}
621
635
622
- private void setHttpClientOverrideField (EppoHttpClient httpClient ) {
623
- setOverrideField ("httpClientOverride" , httpClient );
624
- }
625
-
626
- private void setConfigurationStoreOverrideField (ConfigurationStore configurationStore ) {
627
- setOverrideField ("configurationStoreOverride" , configurationStore );
628
- }
629
-
630
- /**
631
- * @noinspection SameParameterValue
632
- */
633
- private void setIsConfigObfuscatedField (boolean isConfigObfuscated ) {
634
- setOverrideField ("isConfigObfuscated" , isConfigObfuscated );
635
- }
636
-
637
- private <T > void setOverrideField (String fieldName , T override ) {
638
- try {
639
- // Use reflection to set the httpClientOverride field
640
- Field httpClientOverrideField = EppoClient .class .getDeclaredField (fieldName );
641
- httpClientOverrideField .setAccessible (true );
642
- httpClientOverrideField .set (null , override );
643
- httpClientOverrideField .setAccessible (false );
644
- } catch (NoSuchFieldException | IllegalAccessException e ) {
645
- throw new RuntimeException (e );
646
- }
647
- }
648
-
649
636
private static SimpleModule module () {
650
637
SimpleModule module = new SimpleModule ();
651
638
module .addDeserializer (AssignmentTestCase .class , new AssignmentTestCaseDeserializer ());
0 commit comments