2828import pluggable .CustomStorageWrapper ;
2929
3030import java .net .URISyntaxException ;
31- import java .util .AbstractMap ;
32- import java .util .ArrayList ;
33- import java .util .HashMap ;
34- import java .util .List ;
35- import java .util .Optional ;
31+ import java .util .*;
3632import java .util .stream .Collectors ;
3733import java .util .stream .Stream ;
3834
@@ -850,4 +846,181 @@ public void testCounterConsumerModeNoneMode() {
850846 manager .start ();
851847 Assert .assertNotNull (manager .getCounter ());
852848 }
849+
850+ @ Test
851+ public void testImpressionToggleStandaloneOptimizedMode () {
852+ SplitClientConfig config = SplitClientConfig .builder ()
853+ .impressionsQueueSize (10 )
854+ .endpoint ("nowhere.com" , "nowhere.com" )
855+ .impressionsMode (ImpressionsManager .Mode .OPTIMIZED )
856+ .build ();
857+ ImpressionsStorage storage = new InMemoryImpressionsStorage (config .impressionsQueueSize ());
858+
859+ ImpressionsSender senderMock = Mockito .mock (ImpressionsSender .class );
860+ ImpressionCounter impressionCounter = new ImpressionCounter ();
861+ ImpressionObserver impressionObserver = new ImpressionObserver (200 );
862+ TelemetryStorageProducer telemetryStorageProducer = new InMemoryTelemetryStorage ();
863+ TelemetrySynchronizer telemetrySynchronizer = Mockito .mock (TelemetryInMemorySubmitter .class );
864+ UniqueKeysTracker uniqueKeysTracker = new UniqueKeysTrackerImp (telemetrySynchronizer , 1000 , 1000 , null );
865+ uniqueKeysTracker .start ();
866+
867+ ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionOptimized (false , impressionObserver , impressionCounter , telemetryStorageProducer );
868+ ProcessImpressionNone processImpressionNone = new ProcessImpressionNone (false , uniqueKeysTracker , impressionCounter );
869+
870+ ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl .instanceForTest (config , senderMock , TELEMETRY_STORAGE , storage , storage , processImpressionNone , processImpressionStrategy , impressionCounter , null );
871+ treatmentLog .start ();
872+
873+ // These 4 unique test name will cause 4 entries but we are caping at the first 3.
874+ KeyImpression ki1 = keyImpression ("test1" , "adil" , "on" , 1L , 1L );
875+ KeyImpression ki2 = keyImpression ("test1" , "mati" , "on" , 2L , 1L );
876+ KeyImpression ki3 = keyImpression ("test1" , "pato" , "on" , 3L , 1L );
877+ KeyImpression ki4 = keyImpression ("test1" , "bilal" , "on" , 4L , 1L );
878+
879+ treatmentLog .track (Stream .of (new DecoratedImpression (new Impression (ki1 .keyName , null , ki1 .feature , ki1 .treatment , ki1 .time , null , 1L , null ), true )).collect (Collectors .toList ()));
880+ treatmentLog .track (Stream .of (new DecoratedImpression (new Impression (ki2 .keyName , null , ki2 .feature , ki2 .treatment , ki2 .time , null , 1L , null ), false )).collect (Collectors .toList ()));
881+ treatmentLog .track (Stream .of (new DecoratedImpression (new Impression (ki3 .keyName , null , ki3 .feature , ki3 .treatment , ki3 .time , null , 1L , null ), true )).collect (Collectors .toList ()));
882+ treatmentLog .track (Stream .of (new DecoratedImpression (new Impression (ki4 .keyName , null , ki4 .feature , ki4 .treatment , ki4 .time , null , 1L , null ), false )).collect (Collectors .toList ()));
883+ treatmentLog .sendImpressions ();
884+
885+ verify (senderMock ).postImpressionsBulk (impressionsCaptor .capture ());
886+
887+ List <TestImpressions > captured = impressionsCaptor .getValue ();
888+ Assert .assertEquals (2 , captured .get (0 ).keyImpressions .size ());
889+ for (TestImpressions testImpressions : captured ) {
890+ for (KeyImpression keyImpression : testImpressions .keyImpressions ) {
891+ Assert .assertEquals (null , keyImpression .previousTime );
892+ }
893+ }
894+ // Only the first 2 impressions make it to the server
895+ Assert .assertTrue (captured .get (0 ).keyImpressions .contains (keyImpression ("test1" , "adil" , "on" , 1L , 1L )));
896+ Assert .assertTrue (captured .get (0 ).keyImpressions .contains (keyImpression ("test1" , "pato" , "on" , 3L , 1L )));
897+
898+ HashMap <String , HashSet <String >> trackedKeys = ((UniqueKeysTrackerImp ) uniqueKeysTracker ).popAll ();
899+ HashSet <String > keys = new HashSet <>();
900+ keys .add ("mati" );
901+ keys .add ("bilal" );
902+ Assert .assertEquals (1 , trackedKeys .size ());
903+ Assert .assertEquals (keys , trackedKeys .get ("test1" ));
904+
905+ treatmentLog .sendImpressionCounters ();
906+ verify (senderMock ).postCounters (impressionCountCaptor .capture ());
907+ HashMap <ImpressionCounter .Key , Integer > capturedCounts = impressionCountCaptor .getValue ();
908+ Assert .assertEquals (1 , capturedCounts .size ());
909+ Assert .assertTrue (capturedCounts .entrySet ().contains (new AbstractMap .SimpleEntry <>(new ImpressionCounter .Key ("test1" , 0 ), 2 )));
910+
911+ // Assert that the sender is never called if the counters are empty.
912+ Mockito .reset (senderMock );
913+ treatmentLog .sendImpressionCounters ();
914+ verify (senderMock , times (0 )).postCounters (Mockito .any ());
915+ }
916+
917+ @ Test
918+ public void testImpressionToggleStandaloneModeDebugMode () {
919+ SplitClientConfig config = SplitClientConfig .builder ()
920+ .impressionsQueueSize (10 )
921+ .endpoint ("nowhere.com" , "nowhere.com" )
922+ .impressionsMode (ImpressionsManager .Mode .DEBUG )
923+ .build ();
924+ ImpressionsStorage storage = new InMemoryImpressionsStorage (config .impressionsQueueSize ());
925+
926+ ImpressionsSender senderMock = Mockito .mock (ImpressionsSender .class );
927+ ImpressionCounter impressionCounter = Mockito .mock (ImpressionCounter .class );
928+ ImpressionObserver impressionObserver = new ImpressionObserver (200 );
929+ ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionDebug (false , impressionObserver );
930+ TelemetrySynchronizer telemetrySynchronizer = Mockito .mock (TelemetryInMemorySubmitter .class );
931+ UniqueKeysTracker uniqueKeysTracker = new UniqueKeysTrackerImp (telemetrySynchronizer , 1000 , 1000 , null );
932+ uniqueKeysTracker .start ();
933+ ProcessImpressionNone processImpressionNone = new ProcessImpressionNone (false , uniqueKeysTracker , impressionCounter );
934+
935+ ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl .instanceForTest (config , senderMock , TELEMETRY_STORAGE , storage , storage , processImpressionNone , processImpressionStrategy , impressionCounter , null );
936+ treatmentLog .start ();
937+
938+ // These 4 unique test name will cause 4 entries but we are caping at the first 3.
939+ KeyImpression ki1 = keyImpression ("test1" , "adil" , "on" , 1L , 1L );
940+ KeyImpression ki2 = keyImpression ("test1" , "mati" , "on" , 2L , 1L );
941+ KeyImpression ki3 = keyImpression ("test1" , "pato" , "on" , 3L , 1L );
942+ KeyImpression ki4 = keyImpression ("test1" , "bilal" , "on" , 4L , 1L );
943+
944+ treatmentLog .track (Stream .of (new DecoratedImpression (new Impression (ki1 .keyName , null , ki1 .feature , ki1 .treatment , ki1 .time , null , 1L , null ), true )).collect (Collectors .toList ()));
945+ treatmentLog .track (Stream .of (new DecoratedImpression (new Impression (ki2 .keyName , null , ki2 .feature , ki2 .treatment , ki2 .time , null , 1L , null ), false )).collect (Collectors .toList ()));
946+ treatmentLog .track (Stream .of (new DecoratedImpression (new Impression (ki3 .keyName , null , ki3 .feature , ki3 .treatment , ki3 .time , null , 1L , null ), true )).collect (Collectors .toList ()));
947+ treatmentLog .track (Stream .of (new DecoratedImpression (new Impression (ki4 .keyName , null , ki4 .feature , ki4 .treatment , ki4 .time , null , 1L , null ), false )).collect (Collectors .toList ()));
948+ treatmentLog .sendImpressions ();
949+
950+ HashMap <String , HashSet <String >> trackedKeys = ((UniqueKeysTrackerImp ) uniqueKeysTracker ).popAll ();
951+ HashSet <String > keys = new HashSet <>();
952+ keys .add ("mati" );
953+ keys .add ("bilal" );
954+ Assert .assertEquals (1 , trackedKeys .size ());
955+ Assert .assertEquals (keys , trackedKeys .get ("test1" ));
956+
957+ verify (senderMock ).postImpressionsBulk (impressionsCaptor .capture ());
958+
959+ List <TestImpressions > captured = impressionsCaptor .getValue ();
960+ Assert .assertEquals (2 , captured .get (0 ).keyImpressions .size ());
961+ for (TestImpressions testImpressions : captured ) {
962+ KeyImpression keyImpression1 = testImpressions .keyImpressions .get (0 );
963+ KeyImpression keyImpression3 = testImpressions .keyImpressions .get (1 );
964+ Assert .assertEquals (null , keyImpression1 .previousTime );
965+ Assert .assertEquals (null , keyImpression3 .previousTime );
966+ }
967+ // Only the first 2 impressions make it to the server
968+ Assert .assertTrue (captured .get (0 ).keyImpressions .contains (keyImpression ("test1" , "adil" , "on" , 1L , 1L )));
969+ Assert .assertTrue (captured .get (0 ).keyImpressions .contains (keyImpression ("test1" , "pato" , "on" , 3L , 1L )));
970+ }
971+
972+ @ Test
973+ public void testImpressionToggleStandaloneModeNoneMode () {
974+ SplitClientConfig config = SplitClientConfig .builder ()
975+ .impressionsQueueSize (10 )
976+ .endpoint ("nowhere.com" , "nowhere.com" )
977+ .impressionsMode (ImpressionsManager .Mode .NONE )
978+ .build ();
979+ ImpressionsStorage storage = new InMemoryImpressionsStorage (config .impressionsQueueSize ());
980+
981+ ImpressionsSender senderMock = Mockito .mock (ImpressionsSender .class );
982+ TelemetrySynchronizer telemetrySynchronizer = Mockito .mock (TelemetryInMemorySubmitter .class );
983+ ImpressionCounter impressionCounter = new ImpressionCounter ();
984+ UniqueKeysTracker uniqueKeysTracker = new UniqueKeysTrackerImp (telemetrySynchronizer , 1000 , 1000 , null );
985+ uniqueKeysTracker .start ();
986+
987+ ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionNone (false , uniqueKeysTracker , impressionCounter );
988+ ProcessImpressionNone processImpressionNone = (ProcessImpressionNone ) processImpressionStrategy ;
989+
990+ ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl .instanceForTest (config , senderMock , TELEMETRY_STORAGE , storage , storage , processImpressionNone , processImpressionStrategy , impressionCounter , null );
991+ treatmentLog .start ();
992+
993+ // These 4 unique test name will cause 4 entries but we are caping at the first 3.
994+ KeyImpression ki1 = keyImpression ("test1" , "adil" , "on" , 1L , 1L );
995+ KeyImpression ki2 = keyImpression ("test1" , "mati" , "on" , 2L , 1L );
996+ KeyImpression ki3 = keyImpression ("test1" , "pato" , "on" , 3L , 1L );
997+ KeyImpression ki4 = keyImpression ("test1" , "bilal" , "on" , 4L , 1L );
998+
999+ treatmentLog .track (Stream .of (new DecoratedImpression (new Impression (ki1 .keyName , null , ki1 .feature , ki1 .treatment , ki1 .time , null , 1L , null ), true )).collect (Collectors .toList ()));
1000+ treatmentLog .track (Stream .of (new DecoratedImpression (new Impression (ki2 .keyName , null , ki2 .feature , ki2 .treatment , ki2 .time , null , 1L , null ), false )).collect (Collectors .toList ()));
1001+ treatmentLog .track (Stream .of (new DecoratedImpression (new Impression (ki3 .keyName , null , ki3 .feature , ki3 .treatment , ki3 .time , null , 1L , null ), true )).collect (Collectors .toList ()));
1002+ treatmentLog .track (Stream .of (new DecoratedImpression (new Impression (ki4 .keyName , null , ki4 .feature , ki4 .treatment , ki4 .time , null , 1L , null ), false )).collect (Collectors .toList ()));
1003+ treatmentLog .close ();
1004+ HashMap <String , HashSet <String >> trackedKeys = ((UniqueKeysTrackerImp ) uniqueKeysTracker ).popAll ();
1005+ uniqueKeysTracker .stop ();
1006+
1007+ HashSet <String > keys = new HashSet <>();
1008+ keys .add ("adil" );
1009+ keys .add ("mati" );
1010+ keys .add ("pato" );
1011+ keys .add ("bilal" );
1012+ Assert .assertEquals (1 , trackedKeys .size ());
1013+ Assert .assertEquals (keys , trackedKeys .get ("test1" ));
1014+
1015+ //treatmentLog.sendImpressionCounters();
1016+ verify (senderMock ).postCounters (impressionCountCaptor .capture ());
1017+ HashMap <ImpressionCounter .Key , Integer > capturedCounts = impressionCountCaptor .getValue ();
1018+ Assert .assertEquals (1 , capturedCounts .size ());
1019+ Assert .assertTrue (capturedCounts .entrySet ().contains (new AbstractMap .SimpleEntry <>(new ImpressionCounter .Key ("test1" , 0 ), 4 )));
1020+
1021+ // Assert that the sender is never called if the counters are empty.
1022+ Mockito .reset (senderMock );
1023+ treatmentLog .sendImpressionCounters ();
1024+ verify (senderMock , times (0 )).postCounters (Mockito .any ());
1025+ }
8531026}
0 commit comments