22
33import static android .os .Looper .getMainLooper ;
44import static junit .framework .Assert .assertFalse ;
5+ import static junit .framework .Assert .assertNotNull ;
56import static junit .framework .Assert .assertTrue ;
67import static org .robolectric .Shadows .shadowOf ;
78
2021import java .io .IOException ;
2122import java .util .concurrent .TimeUnit ;
2223import java .util .concurrent .atomic .AtomicBoolean ;
24+ import java .util .concurrent .atomic .AtomicInteger ;
2325import java .util .concurrent .atomic .AtomicReference ;
2426
2527import okhttp3 .mockwebserver .MockResponse ;
@@ -243,6 +245,7 @@ public void testCriteriaCallbackOnFailure() throws Exception {
243245
244246 AtomicBoolean succeeded = new AtomicBoolean (false );
245247 AtomicBoolean failed = new AtomicBoolean (false );
248+ AtomicReference <String > failureReason = new AtomicReference <>(null );
246249 IterableConfig config = new IterableConfig .Builder ()
247250 .setEnableUnknownUserActivation (true )
248251 .setUnknownUserHandler (new IterableUnknownUserHandler () {
@@ -255,6 +258,7 @@ public void onCriteriaReceived(JSONObject criteria) {
255258 @ Override
256259 public void onCriteriaFetchFailed (String reason ) {
257260 failed .set (true );
261+ failureReason .set (reason );
258262 }
259263 })
260264 .build ();
@@ -265,5 +269,46 @@ public void onCriteriaFetchFailed(String reason) {
265269
266270 assertTrue ("onCriteriaFetchFailed should be called when the criteria fetch fails" , failed .get ());
267271 assertFalse ("onCriteriaReceived should not be called on a failed fetch" , succeeded .get ());
272+ assertNotNull ("onCriteriaFetchFailed should receive a failure reason" , failureReason .get ());
273+ assertFalse ("Failure reason should not be empty" , failureReason .get ().isEmpty ());
274+ }
275+
276+ @ Test
277+ public void testCriteriaCallbackFiresOnEveryFetch () throws Exception {
278+ // Flush the criteria fetch triggered by setUp() while no callback is installed,
279+ // then reset tracking so only the callback-observed fetches below are counted.
280+ shadowOf (getMainLooper ()).idle ();
281+ IterableApi .getInstance ().setVisitorUsageTracked (false );
282+
283+ String criteriaJson = "{\" criteriaSets\" :[{\" criteriaId\" :\" 1\" }]}" ;
284+ // One response per fetch.
285+ dispatcher .enqueueResponse ("/" + IterableConstants .ENDPOINT_CRITERIA_LIST ,
286+ new MockResponse ().setResponseCode (200 ).setBody (criteriaJson ));
287+ dispatcher .enqueueResponse ("/" + IterableConstants .ENDPOINT_CRITERIA_LIST ,
288+ new MockResponse ().setResponseCode (200 ).setBody (criteriaJson ));
289+
290+ AtomicInteger receivedCount = new AtomicInteger (0 );
291+ IterableConfig config = new IterableConfig .Builder ()
292+ .setEnableUnknownUserActivation (true )
293+ .setUnknownUserHandler (new IterableUnknownUserHandler () {
294+ @ Override
295+ public void onUnknownUserCreated (String userId ) {}
296+ @ Override
297+ public void onCriteriaReceived (JSONObject criteria ) {
298+ receivedCount .incrementAndGet ();
299+ }
300+ })
301+ .build ();
302+
303+ IterableApi .initialize (getContext (), "apiKey" , config );
304+
305+ // Each enable of visitor usage tracking triggers a criteria fetch; the callback
306+ // should fire once per fetch, matching the documented "fires on every fetch" contract.
307+ IterableApi .getInstance ().setVisitorUsageTracked (true );
308+ shadowOf (getMainLooper ()).idle ();
309+ IterableApi .getInstance ().setVisitorUsageTracked (true );
310+ shadowOf (getMainLooper ()).idle ();
311+
312+ Assert .assertEquals ("onCriteriaReceived should fire once per fetch" , 2 , receivedCount .get ());
268313 }
269314}
0 commit comments