From 519d146a50d0e449a8e6b2d8c907de0ff39086b6 Mon Sep 17 00:00:00 2001 From: NomanShoaib Date: Thu, 20 Apr 2023 06:10:13 +0500 Subject: [PATCH 1/3] [FSSDK-9056] fix: add config check in odp methods --- .../java/com/optimizely/ab/Optimizely.java | 21 ++++++ .../com/optimizely/ab/OptimizelyTest.java | 27 +++++++ .../ab/OptimizelyUserContextTest.java | 73 +++++++++++++++++++ 3 files changed, 121 insertions(+) diff --git a/core-api/src/main/java/com/optimizely/ab/Optimizely.java b/core-api/src/main/java/com/optimizely/ab/Optimizely.java index fe28a8bb4..afb5ff10e 100644 --- a/core-api/src/main/java/com/optimizely/ab/Optimizely.java +++ b/core-api/src/main/java/com/optimizely/ab/Optimizely.java @@ -1445,6 +1445,11 @@ public int addNotificationHandler(Class clazz, NotificationHandler han } public List fetchQualifiedSegments(String userId, @Nonnull List segmentOptions) { + ProjectConfig projectConfig = getProjectConfig(); + if (projectConfig == null) { + logger.error("Optimizely instance is not valid, failing fetchQualifiedSegments call."); + return null; + } if (odpManager != null) { synchronized (odpManager) { return odpManager.getSegmentManager().getQualifiedSegments(userId, segmentOptions); @@ -1455,6 +1460,12 @@ public List fetchQualifiedSegments(String userId, @Nonnull List segmentOptions) { + ProjectConfig projectConfig = getProjectConfig(); + if (projectConfig == null) { + logger.error("Optimizely instance is not valid, failing fetchQualifiedSegments call."); + callback.onCompleted(null); + return; + } if (odpManager == null) { logger.error("Audience segments fetch failed (ODP is not enabled)."); callback.onCompleted(null); @@ -1478,6 +1489,11 @@ public ODPManager getODPManager() { * @param data a dictionary for associated data. The default event data will be added to this data before sending to the ODP server. */ public void sendODPEvent(@Nullable String type, @Nonnull String action, @Nullable Map identifiers, @Nullable Map data) { + ProjectConfig projectConfig = getProjectConfig(); + if (projectConfig == null) { + logger.error("Optimizely instance is not valid, failing sendODPEvent call."); + return; + } if (odpManager != null) { ODPEvent event = new ODPEvent(type, action, identifiers, data); odpManager.getEventManager().sendEvent(event); @@ -1487,6 +1503,11 @@ public void sendODPEvent(@Nullable String type, @Nonnull String action, @Nullabl } public void identifyUser(@Nonnull String userId) { + ProjectConfig projectConfig = getProjectConfig(); + if (projectConfig == null) { + logger.error("Optimizely instance is not valid, failing identifyUser call."); + return; + } ODPManager odpManager = getODPManager(); if (odpManager != null) { odpManager.getEventManager().identifyUser(userId); diff --git a/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java b/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java index 705ce1cb6..0b43565d5 100644 --- a/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java +++ b/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java @@ -4762,6 +4762,33 @@ public void sendODPEvent() { assertEquals(data, eventArgument.getValue().getData()); } + @Test + public void sendODPEventInvalidConfig() { + ProjectConfigManager mockProjectConfigManager = mock(ProjectConfigManager.class); + Mockito.when(mockProjectConfigManager.getConfig()).thenReturn(null); + ODPEventManager mockODPEventManager = mock(ODPEventManager.class); + ODPManager mockODPManager = mock(ODPManager.class); + + Mockito.when(mockODPManager.getEventManager()).thenReturn(mockODPEventManager); + Optimizely optimizely = Optimizely.builder() + .withConfigManager(mockProjectConfigManager) + .withODPManager(mockODPManager) + .build(); + + verify(mockODPEventManager).start(); + + Map identifiers = new HashMap<>(); + identifiers.put("id1", "value1"); + identifiers.put("id2", "value2"); + + Map data = new HashMap<>(); + data.put("sdk", "java"); + data.put("revision", 52); + + optimizely.sendODPEvent("fullstack", "identify", identifiers, data); + logbackVerifier.expectMessage(Level.ERROR, "Optimizely instance is not valid, failing sendODPEvent call."); + } + @Test public void sendODPEventError() { ProjectConfigManager mockProjectConfigManager = mock(ProjectConfigManager.class); diff --git a/core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java b/core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java index 8f8bae834..a83589236 100644 --- a/core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java +++ b/core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java @@ -1640,6 +1640,28 @@ public void fetchQualifiedSegments() { verify(mockODPSegmentManager).getQualifiedSegments("test-user", Collections.singletonList(ODPSegmentOption.RESET_CACHE)); } + @Test + public void fetchQualifiedSegmentsErrorWhenConfigIsInvalid() { + ProjectConfigManager mockProjectConfigManager = mock(ProjectConfigManager.class); + Mockito.when(mockProjectConfigManager.getConfig()).thenReturn(null); + ODPEventManager mockODPEventManager = mock(ODPEventManager.class); + ODPSegmentManager mockODPSegmentManager = mock(ODPSegmentManager.class); + ODPManager mockODPManager = mock(ODPManager.class); + + Mockito.when(mockODPManager.getEventManager()).thenReturn(mockODPEventManager); + Mockito.when(mockODPManager.getSegmentManager()).thenReturn(mockODPSegmentManager); + + Optimizely optimizely = Optimizely.builder() + .withConfigManager(mockProjectConfigManager) + .withODPManager(mockODPManager) + .build(); + + OptimizelyUserContext userContext = optimizely.createUserContext("test-user"); + + assertFalse(userContext.fetchQualifiedSegments()); + logbackVerifier.expectMessage(Level.ERROR, "Optimizely instance is not valid, failing fetchQualifiedSegments call."); + } + @Test public void fetchQualifiedSegmentsError() { Optimizely optimizely = Optimizely.builder() @@ -1713,6 +1735,57 @@ public void fetchQualifiedSegmentsAsyncError() throws InterruptedException { logbackVerifier.expectMessage(Level.ERROR, "Audience segments fetch failed (ODP is not enabled)."); } + @Test + public void fetchQualifiedSegmentsAsyncErrorWhenConfigIsInvalid() throws InterruptedException { + ProjectConfigManager mockProjectConfigManager = mock(ProjectConfigManager.class); + Mockito.when(mockProjectConfigManager.getConfig()).thenReturn(null); + ODPEventManager mockODPEventManager = mock(ODPEventManager.class); + ODPSegmentManager mockODPSegmentManager = mock(ODPSegmentManager.class); + ODPManager mockODPManager = mock(ODPManager.class); + + Mockito.when(mockODPManager.getEventManager()).thenReturn(mockODPEventManager); + Mockito.when(mockODPManager.getSegmentManager()).thenReturn(mockODPSegmentManager); + + Optimizely optimizely = Optimizely.builder() + .withConfigManager(mockProjectConfigManager) + .withODPManager(mockODPManager) + .build(); + + OptimizelyUserContext userContext = optimizely.createUserContext("test-user"); + + CountDownLatch countDownLatch = new CountDownLatch(1); + userContext.fetchQualifiedSegments((Boolean isFetchSuccessful) -> { + assertFalse(isFetchSuccessful); + countDownLatch.countDown(); + }); + + countDownLatch.await(); + assertEquals(null, userContext.getQualifiedSegments()); + logbackVerifier.expectMessage(Level.ERROR, "Optimizely instance is not valid, failing fetchQualifiedSegments call."); + } + + @Test + public void identifyUserErrorWhenConfigIsInvalid() { + ODPEventManager mockODPEventManager = mock(ODPEventManager.class); + ODPSegmentManager mockODPSegmentManager = mock(ODPSegmentManager.class); + ODPManager mockODPManager = mock(ODPManager.class); + ProjectConfigManager mockProjectConfigManager = mock(ProjectConfigManager.class); + Mockito.when(mockProjectConfigManager.getConfig()).thenReturn(null); + Mockito.when(mockODPManager.getEventManager()).thenReturn(mockODPEventManager); + Mockito.when(mockODPManager.getSegmentManager()).thenReturn(mockODPSegmentManager); + + Optimizely optimizely = Optimizely.builder() + .withConfigManager(mockProjectConfigManager) + .withODPManager(mockODPManager) + .build(); + + OptimizelyUserContext userContext = optimizely.createUserContext("test-user"); + verify(mockODPEventManager, never()).identifyUser("test-user"); + Mockito.reset(mockODPEventManager); + + logbackVerifier.expectMessage(Level.ERROR, "Optimizely instance is not valid, failing identifyUser call."); + } + @Test public void identifyUser() { ODPEventManager mockODPEventManager = mock(ODPEventManager.class); From 98e0aa16f2df094acbb7f0c6834b6b76cb0610ab Mon Sep 17 00:00:00 2001 From: NomanShoaib Date: Thu, 20 Apr 2023 06:26:50 +0500 Subject: [PATCH 2/3] Fixed tests by passing valid config --- .../test/java/com/optimizely/ab/OptimizelyTest.java | 4 +++- .../com/optimizely/ab/OptimizelyUserContextTest.java | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java b/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java index 0b43565d5..4697ba32c 100644 --- a/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java +++ b/core-api/src/test/java/com/optimizely/ab/OptimizelyTest.java @@ -4733,6 +4733,7 @@ public void initODPManagerWithProjectConfig() throws IOException { @Test public void sendODPEvent() { ProjectConfigManager mockProjectConfigManager = mock(ProjectConfigManager.class); + Mockito.when(mockProjectConfigManager.getConfig()).thenReturn(validProjectConfig); ODPEventManager mockODPEventManager = mock(ODPEventManager.class); ODPManager mockODPManager = mock(ODPManager.class); @@ -4792,7 +4793,7 @@ public void sendODPEventInvalidConfig() { @Test public void sendODPEventError() { ProjectConfigManager mockProjectConfigManager = mock(ProjectConfigManager.class); - + Mockito.when(mockProjectConfigManager.getConfig()).thenReturn(validProjectConfig); Optimizely optimizely = Optimizely.builder() .withConfigManager(mockProjectConfigManager) .build(); @@ -4812,6 +4813,7 @@ public void sendODPEventError() { @Test public void identifyUser() { ProjectConfigManager mockProjectConfigManager = mock(ProjectConfigManager.class); + Mockito.when(mockProjectConfigManager.getConfig()).thenReturn(validProjectConfig); ODPEventManager mockODPEventManager = mock(ODPEventManager.class); ODPManager mockODPManager = mock(ODPManager.class); diff --git a/core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java b/core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java index a83589236..71a3978b2 100644 --- a/core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java +++ b/core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java @@ -1628,6 +1628,8 @@ public void fetchQualifiedSegments() { Mockito.when(mockODPManager.getSegmentManager()).thenReturn(mockODPSegmentManager); Optimizely optimizely = Optimizely.builder() + .withDatafile(datafile) + .withEventProcessor(new ForwardingEventProcessor(eventHandler, null)) .withODPManager(mockODPManager) .build(); @@ -1665,6 +1667,8 @@ public void fetchQualifiedSegmentsErrorWhenConfigIsInvalid() { @Test public void fetchQualifiedSegmentsError() { Optimizely optimizely = Optimizely.builder() + .withDatafile(datafile) + .withEventProcessor(new ForwardingEventProcessor(eventHandler, null)) .build(); OptimizelyUserContext userContext = optimizely.createUserContext("test-user"); @@ -1689,6 +1693,8 @@ public void fetchQualifiedSegmentsAsync() throws InterruptedException { Mockito.when(mockODPManager.getSegmentManager()).thenReturn(mockODPSegmentManager); Optimizely optimizely = Optimizely.builder() + .withDatafile(datafile) + .withEventProcessor(new ForwardingEventProcessor(eventHandler, null)) .withODPManager(mockODPManager) .build(); @@ -1720,6 +1726,8 @@ public void fetchQualifiedSegmentsAsync() throws InterruptedException { @Test public void fetchQualifiedSegmentsAsyncError() throws InterruptedException { Optimizely optimizely = Optimizely.builder() + .withDatafile(datafile) + .withEventProcessor(new ForwardingEventProcessor(eventHandler, null)) .build(); OptimizelyUserContext userContext = optimizely.createUserContext("test-user"); @@ -1796,6 +1804,8 @@ public void identifyUser() { Mockito.when(mockODPManager.getSegmentManager()).thenReturn(mockODPSegmentManager); Optimizely optimizely = Optimizely.builder() + .withDatafile(datafile) + .withEventProcessor(new ForwardingEventProcessor(eventHandler, null)) .withODPManager(mockODPManager) .build(); From 05c63d9be2d65bd36c16055c67e146dce2094a4e Mon Sep 17 00:00:00 2001 From: NomanShoaib Date: Thu, 20 Apr 2023 06:34:12 +0500 Subject: [PATCH 3/3] spotbug fix --- .../test/java/com/optimizely/ab/OptimizelyUserContextTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java b/core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java index 71a3978b2..7c479f147 100644 --- a/core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java +++ b/core-api/src/test/java/com/optimizely/ab/OptimizelyUserContextTest.java @@ -1787,7 +1787,7 @@ public void identifyUserErrorWhenConfigIsInvalid() { .withODPManager(mockODPManager) .build(); - OptimizelyUserContext userContext = optimizely.createUserContext("test-user"); + optimizely.createUserContext("test-user"); verify(mockODPEventManager, never()).identifyUser("test-user"); Mockito.reset(mockODPEventManager);