Skip to content

Commit 9e02c7e

Browse files
authored
fix(odp): check odp identifiers not empty before sending (#509)
1 parent d9f19b3 commit 9e02c7e

File tree

4 files changed

+46
-9
lines changed

4 files changed

+46
-9
lines changed

core-api/src/main/java/com/optimizely/ab/Optimizely.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,15 @@ public ODPManager getODPManager() {
14681468
return odpManager;
14691469
}
14701470

1471+
1472+
/**
1473+
* Send an event to the ODP server.
1474+
*
1475+
* @param type the event type (default = "fullstack").
1476+
* @param action the event action name.
1477+
* @param identifiers a dictionary for identifiers. The caller must provide at least one key-value pair unless non-empty common identifiers have been set already with {@link ODPManager.Builder#withUserCommonIdentifiers(Map) }.
1478+
* @param data a dictionary for associated data. The default event data will be added to this data before sending to the ODP server.
1479+
*/
14711480
public void sendODPEvent(@Nullable String type, @Nonnull String action, @Nullable Map<String, String> identifiers, @Nullable Map<String, Object> data) {
14721481
if (odpManager != null) {
14731482
ODPEvent event = new ODPEvent(type, action, identifiers, data);

core-api/src/main/java/com/optimizely/ab/odp/ODPEvent.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@
2424
public class ODPEvent {
2525
public static final String EVENT_TYPE_FULLSTACK = "fullstack";
2626

27-
private String type;
28-
private String action;
29-
private Map<String, String> identifiers;
30-
private Map<String, Object> data;
27+
@Nonnull private String type;
28+
@Nonnull private String action;
29+
@Nonnull private Map<String, String> identifiers;
30+
@Nonnull private Map<String, Object> data;
3131

3232
public ODPEvent(@Nullable String type, @Nonnull String action, @Nullable Map<String, String> identifiers, @Nullable Map<String, Object> data) {
3333
this.type = type == null ? EVENT_TYPE_FULLSTACK : type;
@@ -84,4 +84,10 @@ public Boolean isDataValid() {
8484
}
8585
return true;
8686
}
87+
88+
@Transient
89+
public Boolean isIdentifiersValid() {
90+
return !identifiers.isEmpty();
91+
}
92+
8793
}

core-api/src/main/java/com/optimizely/ab/odp/ODPEventManager.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,19 @@ public void identifyUser(@Nullable String vuid, @Nullable String userId) {
119119
}
120120

121121
public void sendEvent(ODPEvent event) {
122+
event.setData(augmentCommonData(event.getData()));
123+
event.setIdentifiers(augmentCommonIdentifiers(event.getIdentifiers()));
124+
125+
if (!event.isIdentifiersValid()) {
126+
logger.error("ODP event send failed (event identifiers must have at least one key-value pair)");
127+
return;
128+
}
129+
122130
if (!event.isDataValid()) {
123-
logger.error("ODP event send failed (ODP data is not valid)");
131+
logger.error("ODP event send failed (event data is not valid)");
124132
return;
125133
}
126-
event.setData(augmentCommonData(event.getData()));
127-
event.setIdentifiers(augmentCommonIdentifiers(event.getIdentifiers()));
134+
128135
processEvent(event);
129136
}
130137

core-api/src/test/java/com/optimizely/ab/odp/ODPEventManagerTest.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public void logAndDiscardEventWhenEventManagerIsNotRunning() {
6161
ODPConfig odpConfig = new ODPConfig("key", "host", null);
6262
ODPEventManager eventManager = new ODPEventManager(mockApiManager);
6363
eventManager.updateSettings(odpConfig);
64-
ODPEvent event = new ODPEvent("test-type", "test-action", Collections.emptyMap(), Collections.emptyMap());
64+
ODPEvent event = new ODPEvent("test-type", "test-action", Collections.singletonMap("any-key", "any-value"), Collections.emptyMap());
6565
eventManager.sendEvent(event);
6666
logbackVerifier.expectMessage(Level.WARN, "Failed to Process ODP Event. ODPEventManager is not running");
6767
}
@@ -72,7 +72,7 @@ public void logAndDiscardEventWhenODPConfigNotReady() {
7272
ODPEventManager eventManager = new ODPEventManager(mockApiManager);
7373
eventManager.updateSettings(odpConfig);
7474
eventManager.start();
75-
ODPEvent event = new ODPEvent("test-type", "test-action", Collections.emptyMap(), Collections.emptyMap());
75+
ODPEvent event = new ODPEvent("test-type", "test-action", Collections.singletonMap("any-key", "any-value"), Collections.emptyMap());
7676
eventManager.sendEvent(event);
7777
logbackVerifier.expectMessage(Level.DEBUG, "Unable to Process ODP Event. ODPConfig is not ready.");
7878
}
@@ -92,6 +92,21 @@ public void dispatchEventsInCorrectNumberOfBatches() throws InterruptedException
9292
Mockito.verify(mockApiManager, times(3)).sendEvents(eq("key"), eq("http://www.odp-host.com/v3/events"), any());
9393
}
9494

95+
@Test
96+
public void logAndDiscardEventWhenIdentifiersEmpty() throws InterruptedException {
97+
int flushInterval = 0;
98+
ODPConfig odpConfig = new ODPConfig("key", "http://www.odp-host.com", null);
99+
ODPEventManager eventManager = new ODPEventManager(mockApiManager, null, flushInterval);
100+
eventManager.updateSettings(odpConfig);
101+
eventManager.start();
102+
103+
ODPEvent event = new ODPEvent("test-type", "test-action", Collections.emptyMap(), Collections.emptyMap());
104+
eventManager.sendEvent(event);
105+
Thread.sleep(500);
106+
Mockito.verify(mockApiManager, never()).sendEvents(eq("key"), eq("http://www.odp-host.com/v3/events"), any());
107+
logbackVerifier.expectMessage(Level.ERROR, "ODP event send failed (event identifiers must have at least one key-value pair)");
108+
}
109+
95110
@Test
96111
public void dispatchEventsWithCorrectPayload() throws InterruptedException {
97112
Mockito.reset(mockApiManager);

0 commit comments

Comments
 (0)