@@ -2291,173 +2291,6 @@ public void testDecide_withDefaultDecideOptions() throws IOException {
22912291        assertTrue (decision .getReasons ().size () > 0 );
22922292    }
22932293
2294-     // Holdout Tests 
2295- 
2296-     private  OptimizelyClient  createOptimizelyClientWithHoldouts (Context  context ) throws  IOException  {
2297-         String  holdoutDatafile  = loadRawResource (context , R .raw .holdouts_project_config );
2298-         OptimizelyManager  optimizelyManager  = OptimizelyManager .builder (testProjectId ).build (context );
2299-         optimizelyManager .initialize (context , holdoutDatafile );
2300-         return  optimizelyManager .getOptimizely ();
2301-     }
2302- 
2303-     @ Test 
2304-     public  void  testDecide_withHoldout () throws  IOException  {
2305-         assumeTrue (datafileVersion  == Integer .parseInt (ProjectConfig .Version .V4 .toString ()));
2306- 
2307-         Context  context  = InstrumentationRegistry .getInstrumentation ().getTargetContext ();
2308-         OptimizelyClient  optimizelyClient  = createOptimizelyClientWithHoldouts (context );
2309- 
2310-         String  flagKey  = "boolean_feature" ;
2311-         String  userId  = "user123" ;
2312-         String  variationKey  = "ho_off_key" ;
2313-         String  ruleKey  = "basic_holdout" ;
2314- 
2315-         Map <String , Object > attributes  = new  HashMap <>();
2316-         attributes .put ("$opt_bucketing_id" , "ppid160000" );  // deterministic bucketing into basic_holdout 
2317-         attributes .put ("nationality" , "English" );           // non-reserved attribute 
2318- 
2319-         OptimizelyUserContext  userContext  = optimizelyClient .createUserContext (userId , attributes );
2320-         OptimizelyDecision  decision  = userContext .decide (flagKey , Collections .singletonList (OptimizelyDecideOption .INCLUDE_REASONS ));
2321- 
2322-         // Validate holdout decision 
2323-         assertEquals (flagKey , decision .getFlagKey ());
2324-         assertEquals (variationKey , decision .getVariationKey ());
2325-         assertEquals (ruleKey , decision .getRuleKey ());
2326-         assertFalse (decision .getEnabled ());
2327-         assertTrue (decision .getVariables ().toMap ().isEmpty ());
2328-         assertTrue ("Expected holdout reason" , decision .getReasons ().stream ()
2329-             .anyMatch (reason  -> reason .contains ("holdout" )));
2330-     }
2331- 
2332-     @ Test 
2333-     public  void  testDecideForKeys_withHoldout () throws  IOException  {
2334-         assumeTrue (datafileVersion  == Integer .parseInt (ProjectConfig .Version .V4 .toString ()));
2335- 
2336-         Context  context  = InstrumentationRegistry .getInstrumentation ().getTargetContext ();
2337-         OptimizelyClient  optimizelyClient  = createOptimizelyClientWithHoldouts (context );
2338- 
2339-         String  userId  = "user123" ;
2340-         String  variationKey  = "ho_off_key" ;
2341-         String  ruleKey  = "basic_holdout" ;
2342- 
2343-         Map <String , Object > attributes  = new  HashMap <>();
2344-         attributes .put ("$opt_bucketing_id" , "ppid160000" );  // deterministic bucketing into basic_holdout 
2345- 
2346-         List <String > flagKeys  = Arrays .asList (
2347-             "boolean_feature" ,
2348-             "double_single_variable_feature" ,
2349-             "integer_single_variable_feature" 
2350-         );
2351- 
2352-         OptimizelyUserContext  userContext  = optimizelyClient .createUserContext (userId , attributes );
2353-         Map <String , OptimizelyDecision > decisions  = userContext .decideForKeys (flagKeys , Collections .singletonList (OptimizelyDecideOption .INCLUDE_REASONS ));
2354- 
2355-         assertEquals (3 , decisions .size ());
2356- 
2357-         for  (String  flagKey  : flagKeys ) {
2358-             OptimizelyDecision  decision  = decisions .get (flagKey );
2359-             assertNotNull ("Missing decision for flag "  + flagKey , decision );
2360-             assertEquals (flagKey , decision .getFlagKey ());
2361-             assertEquals (variationKey , decision .getVariationKey ());
2362-             assertEquals (ruleKey , decision .getRuleKey ());
2363-             assertFalse (decision .getEnabled ());
2364-             assertTrue ("Expected holdout reason for flag "  + flagKey , decision .getReasons ().stream ()
2365-                 .anyMatch (reason  -> reason .contains ("holdout" )));
2366-         }
2367-     }
2368- 
2369-     @ Test 
2370-     public  void  testDecideAll_withHoldout () throws  IOException  {
2371-         assumeTrue (datafileVersion  == Integer .parseInt (ProjectConfig .Version .V4 .toString ()));
2372- 
2373-         Context  context  = InstrumentationRegistry .getInstrumentation ().getTargetContext ();
2374-         OptimizelyClient  optimizelyClient  = createOptimizelyClientWithHoldouts (context );
2375- 
2376-         String  userId  = "user123" ;
2377-         String  variationKey  = "ho_off_key" ;
2378- 
2379-         Map <String , Object > attributes  = new  HashMap <>();
2380-         // ppid120000 buckets user into holdout_included_flags (selective holdout) 
2381-         attributes .put ("$opt_bucketing_id" , "ppid120000" );
2382- 
2383-         // Flags INCLUDED in holdout_included_flags (only these should be holdout decisions) 
2384-         List <String > includedInHoldout  = Arrays .asList (
2385-             "boolean_feature" ,
2386-             "double_single_variable_feature" ,
2387-             "integer_single_variable_feature" 
2388-         );
2389- 
2390-         OptimizelyUserContext  userContext  = optimizelyClient .createUserContext (userId , attributes );
2391-         Map <String , OptimizelyDecision > decisions  = userContext .decideAll (Arrays .asList (
2392-             OptimizelyDecideOption .INCLUDE_REASONS ,
2393-             OptimizelyDecideOption .DISABLE_DECISION_EVENT 
2394-         ));
2395- 
2396-         assertTrue ("Should have multiple decisions" , decisions .size () > 0 );
2397- 
2398-         String  expectedReason  = "User ("  + userId  + ") is in variation ("  + variationKey  + ") of holdout (holdout_included_flags)." ;
2399- 
2400-         int  holdoutCount  = 0 ;
2401-         for  (Map .Entry <String , OptimizelyDecision > entry  : decisions .entrySet ()) {
2402-             String  flagKey  = entry .getKey ();
2403-             OptimizelyDecision  decision  = entry .getValue ();
2404-             assertNotNull ("Missing decision for flag "  + flagKey , decision );
2405- 
2406-             if  (includedInHoldout .contains (flagKey )) {
2407-                 // Should be holdout decision 
2408-                 assertEquals (variationKey , decision .getVariationKey ());
2409-                 assertFalse (decision .getEnabled ());
2410-                 assertTrue ("Expected holdout reason for flag "  + flagKey , decision .getReasons ().contains (expectedReason ));
2411-                 holdoutCount ++;
2412-             } else  {
2413-                 // Should NOT be a holdout decision 
2414-                 assertFalse ("Non-included flag should not have holdout reason: "  + flagKey , 
2415-                     decision .getReasons ().contains (expectedReason ));
2416-             }
2417-         }
2418-         assertEquals ("Expected exactly the included flags to be in holdout" , includedInHoldout .size (), holdoutCount );
2419-     }
2420- 
2421-     @ Test 
2422-     public  void  testDecisionNotificationHandler_withHoldout () throws  IOException  {
2423-         assumeTrue (datafileVersion  == Integer .parseInt (ProjectConfig .Version .V4 .toString ()));
2424- 
2425-         Context  context  = InstrumentationRegistry .getInstrumentation ().getTargetContext ();
2426-         OptimizelyClient  optimizelyClient  = createOptimizelyClientWithHoldouts (context );
2427- 
2428-         String  flagKey  = "boolean_feature" ;
2429-         String  userId  = "user123" ;
2430-         String  variationKey  = "ho_off_key" ;
2431-         String  ruleKey  = "basic_holdout" ;
2432- 
2433-         Map <String , Object > attributes  = new  HashMap <>();
2434-         attributes .put ("$opt_bucketing_id" , "ppid160000" );  // deterministic bucketing into basic_holdout 
2435-         attributes .put ("nationality" , "English" );           // non-reserved attribute 
2436- 
2437-         final  boolean [] listenerCalled  = {false };
2438-         optimizelyClient .addDecisionNotificationHandler (decisionNotification  -> {
2439-             assertEquals ("FLAG" , decisionNotification .getType ());
2440-             assertEquals (userId , decisionNotification .getUserId ());
2441-             assertEquals (attributes , decisionNotification .getAttributes ());
2442- 
2443-             Map <String , ?> info  = decisionNotification .getDecisionInfo ();
2444-             assertEquals (flagKey , info .get ("flagKey" ));
2445-             assertEquals (variationKey , info .get ("variationKey" ));
2446-             assertEquals (false , info .get ("enabled" ));
2447-             assertEquals (ruleKey , info .get ("ruleKey" ));
2448-             assertTrue (((Map <?, ?>) info .get ("variables" )).isEmpty ());
2449- 
2450-             listenerCalled [0 ] = true ;
2451-         });
2452- 
2453-         OptimizelyUserContext  userContext  = optimizelyClient .createUserContext (userId , attributes );
2454-         OptimizelyDecision  decision  = userContext .decide (flagKey , Collections .singletonList (OptimizelyDecideOption .INCLUDE_REASONS ));
2455- 
2456-         assertTrue ("Decision notification handler should have been called" , listenerCalled [0 ]);
2457-         assertEquals (variationKey , decision .getVariationKey ());
2458-         assertFalse (decision .getEnabled ());
2459-     }
2460- 
24612294    // Utils 
24622295
24632296    private  boolean  compareJsonStrings (String  str1 , String  str2 ) {
0 commit comments