diff --git a/core-api/src/main/java/com/optimizely/ab/odp/ODPApiManager.java b/core-api/src/main/java/com/optimizely/ab/odp/ODPApiManager.java index 6385d2b7b..b45bd937f 100644 --- a/core-api/src/main/java/com/optimizely/ab/odp/ODPApiManager.java +++ b/core-api/src/main/java/com/optimizely/ab/odp/ODPApiManager.java @@ -1,5 +1,5 @@ /** - * Copyright 2022, Optimizely Inc. and contributors + * Copyright 2022-2023, Optimizely Inc. and contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,10 +15,11 @@ */ package com.optimizely.ab.odp; +import java.util.List; import java.util.Set; public interface ODPApiManager { - String fetchQualifiedSegments(String apiKey, String apiEndpoint, String userKey, String userValue, Set segmentsToCheck); + List fetchQualifiedSegments(String apiKey, String apiEndpoint, String userKey, String userValue, Set segmentsToCheck); Integer sendEvents(String apiKey, String apiEndpoint, String eventPayload); } diff --git a/core-api/src/main/java/com/optimizely/ab/odp/ODPEventManager.java b/core-api/src/main/java/com/optimizely/ab/odp/ODPEventManager.java index fbd39ffaf..ce218ed9d 100644 --- a/core-api/src/main/java/com/optimizely/ab/odp/ODPEventManager.java +++ b/core-api/src/main/java/com/optimizely/ab/odp/ODPEventManager.java @@ -108,7 +108,11 @@ public void identifyUser(@Nullable String vuid, @Nullable String userId) { identifiers.put(ODPUserKey.VUID.getKeyString(), vuid); } if (userId != null) { - identifiers.put(ODPUserKey.FS_USER_ID.getKeyString(), userId); + if (isVuid(userId)) { + identifiers.put(ODPUserKey.VUID.getKeyString(), userId); + } else { + identifiers.put(ODPUserKey.FS_USER_ID.getKeyString(), userId); + } } ODPEvent event = new ODPEvent("fullstack", "identified", identifiers, null); sendEvent(event); @@ -125,7 +129,7 @@ public void sendEvent(ODPEvent event) { } @VisibleForTesting - Map augmentCommonData(Map sourceData) { + protected Map augmentCommonData(Map sourceData) { // priority: sourceData > userCommonData > sdkCommonData Map data = new HashMap<>(); @@ -140,7 +144,7 @@ Map augmentCommonData(Map sourceData) { } @VisibleForTesting - Map augmentCommonIdentifiers(Map sourceIdentifiers) { + protected Map augmentCommonIdentifiers(Map sourceIdentifiers) { // priority: sourceIdentifiers > userCommonIdentifiers Map identifiers = new HashMap<>(); @@ -149,6 +153,10 @@ Map augmentCommonIdentifiers(Map sourceIdentifie return identifiers; } + private boolean isVuid(String userId) { + return userId.startsWith("vuid_"); + } + private void processEvent(ODPEvent event) { if (!isRunning) { logger.warn("Failed to Process ODP Event. ODPEventManager is not running"); diff --git a/core-api/src/main/java/com/optimizely/ab/odp/ODPSegmentManager.java b/core-api/src/main/java/com/optimizely/ab/odp/ODPSegmentManager.java index 90a36fa5d..275c45ee1 100644 --- a/core-api/src/main/java/com/optimizely/ab/odp/ODPSegmentManager.java +++ b/core-api/src/main/java/com/optimizely/ab/odp/ODPSegmentManager.java @@ -1,6 +1,6 @@ /** * - * Copyright 2022, Optimizely + * Copyright 2022-2023, Optimizely * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -89,16 +89,7 @@ public List getQualifiedSegments(ODPUserKey userKey, String userValue, L logger.debug("ODP Cache Miss. Making a call to ODP Server."); - ResponseJsonParser parser = ResponseJsonParserFactory.getParser(); - String qualifiedSegmentsResponse = apiManager.fetchQualifiedSegments(odpConfig.getApiKey(), odpConfig.getApiHost() + SEGMENT_URL_PATH, userKey.getKeyString(), userValue, odpConfig.getAllSegments()); - try { - qualifiedSegments = parser.parseQualifiedSegments(qualifiedSegmentsResponse); - } catch (Exception e) { - logger.error("Audience segments fetch failed (Error Parsing Response)"); - logger.debug(e.getMessage()); - qualifiedSegments = null; - } - + qualifiedSegments = apiManager.fetchQualifiedSegments(odpConfig.getApiKey(), odpConfig.getApiHost() + SEGMENT_URL_PATH, userKey.getKeyString(), userValue, odpConfig.getAllSegments()); if (qualifiedSegments != null && !options.contains(ODPSegmentOption.IGNORE_CACHE)) { segmentsCache.save(cacheKey, qualifiedSegments); } diff --git a/core-api/src/test/java/com/optimizely/ab/odp/ODPManagerTest.java b/core-api/src/test/java/com/optimizely/ab/odp/ODPManagerTest.java index 02abe88a1..9673bfa69 100644 --- a/core-api/src/test/java/com/optimizely/ab/odp/ODPManagerTest.java +++ b/core-api/src/test/java/com/optimizely/ab/odp/ODPManagerTest.java @@ -1,6 +1,6 @@ /** * - * Copyright 2022, Optimizely + * Copyright 2022-2023, Optimizely * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,13 +24,14 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import static org.mockito.Matchers.*; import static org.mockito.Mockito.*; import static org.junit.Assert.*; public class ODPManagerTest { - private static final String API_RESPONSE = "{\"data\":{\"customer\":{\"audiences\":{\"edges\":[{\"node\":{\"name\":\"segment1\",\"state\":\"qualified\"}},{\"node\":{\"name\":\"segment2\",\"state\":\"qualified\"}}]}}}}"; + private static final List API_RESPONSE = Arrays.asList(new String[]{"segment1", "segment2"}); @Mock ODPApiManager mockApiManager; diff --git a/core-api/src/test/java/com/optimizely/ab/odp/ODPSegmentManagerTest.java b/core-api/src/test/java/com/optimizely/ab/odp/ODPSegmentManagerTest.java index 4d34d49b9..2e6aa611e 100644 --- a/core-api/src/test/java/com/optimizely/ab/odp/ODPSegmentManagerTest.java +++ b/core-api/src/test/java/com/optimizely/ab/odp/ODPSegmentManagerTest.java @@ -1,6 +1,6 @@ /** * - * Copyright 2022, Optimizely + * Copyright 2022-2023, Optimizely * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ public class ODPSegmentManagerTest { @Mock ODPApiManager mockApiManager; - private static final String API_RESPONSE = "{\"data\":{\"customer\":{\"audiences\":{\"edges\":[{\"node\":{\"name\":\"segment1\",\"state\":\"qualified\"}},{\"node\":{\"name\":\"segment2\",\"state\":\"qualified\"}}]}}}}"; + private static final List API_RESPONSE = Arrays.asList(new String[]{"segment1", "segment2"}); @Before public void setup() { diff --git a/core-httpclient-impl/src/main/java/com/optimizely/ab/odp/DefaultODPApiManager.java b/core-httpclient-impl/src/main/java/com/optimizely/ab/odp/DefaultODPApiManager.java index 636ed8eec..040709d39 100644 --- a/core-httpclient-impl/src/main/java/com/optimizely/ab/odp/DefaultODPApiManager.java +++ b/core-httpclient-impl/src/main/java/com/optimizely/ab/odp/DefaultODPApiManager.java @@ -1,5 +1,5 @@ /** - * Copyright 2022, Optimizely Inc. and contributors + * Copyright 2022-2023, Optimizely Inc. and contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,8 @@ import com.optimizely.ab.OptimizelyHttpClient; import com.optimizely.ab.annotations.VisibleForTesting; +import com.optimizely.ab.odp.parser.ResponseJsonParser; +import com.optimizely.ab.odp.parser.ResponseJsonParserFactory; import org.apache.http.StatusLine; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; @@ -28,6 +30,7 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Iterator; +import java.util.List; import java.util.Set; public class DefaultODPApiManager implements ODPApiManager { @@ -144,7 +147,7 @@ String getSegmentsStringForRequest(Set segmentsList) { } */ @Override - public String fetchQualifiedSegments(String apiKey, String apiEndpoint, String userKey, String userValue, Set segmentsToCheck) { + public List fetchQualifiedSegments(String apiKey, String apiEndpoint, String userKey, String userValue, Set segmentsToCheck) { HttpPost request = new HttpPost(apiEndpoint); String segmentsString = getSegmentsStringForRequest(segmentsToCheck); @@ -174,11 +177,14 @@ public String fetchQualifiedSegments(String apiKey, String apiEndpoint, String u closeHttpResponse(response); return null; } - + ResponseJsonParser parser = ResponseJsonParserFactory.getParser(); try { - return EntityUtils.toString(response.getEntity()); + return parser.parseQualifiedSegments(EntityUtils.toString(response.getEntity())); } catch (IOException e) { logger.error("Error converting ODP segments response to string", e); + } catch (Exception e) { + logger.error("Audience segments fetch failed (Error Parsing Response)"); + logger.debug(e.getMessage()); } finally { closeHttpResponse(response); } @@ -201,7 +207,6 @@ public String fetchQualifiedSegments(String apiKey, String apiEndpoint, String u "type": "fullstack" } ] - Returns: 1. null, When there was a non-recoverable error and no retry is needed. 2. 0 If an unexpected error occurred and retrying can be useful. diff --git a/core-httpclient-impl/src/test/java/com/optimizely/ab/odp/DefaultODPApiManagerTest.java b/core-httpclient-impl/src/test/java/com/optimizely/ab/odp/DefaultODPApiManagerTest.java index 93b728fba..a268cacc7 100644 --- a/core-httpclient-impl/src/test/java/com/optimizely/ab/odp/DefaultODPApiManagerTest.java +++ b/core-httpclient-impl/src/test/java/com/optimizely/ab/odp/DefaultODPApiManagerTest.java @@ -1,5 +1,5 @@ /** - * Copyright 2022, Optimizely Inc. and contributors + * Copyright 2022-2023, Optimizely Inc. and contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,13 +30,15 @@ import java.util.Arrays; import java.util.HashSet; +import java.util.List; import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; public class DefaultODPApiManagerTest { - private static final String validResponse = "{\"data\":{\"customer\":{\"audiences\":{\"edges\":[{\"node\":{\"name\":\"has_email\",\"state\":\"qualified\"}},{\"node\":{\"name\":\"has_email_opted_in\",\"state\":\"qualified\"}}]}}}}"; + private static final List validResponse = Arrays.asList(new String[] {"has_email", "has_email_opted_in"}); + private static final String validRequestResponse = "{\"data\":{\"customer\":{\"audiences\":{\"edges\":[{\"node\":{\"name\":\"has_email\",\"state\":\"qualified\"}},{\"node\":{\"name\":\"has_email_opted_in\",\"state\":\"qualified\"}}]}}}}"; @Rule public LogbackVerifier logbackVerifier = new LogbackVerifier(); @@ -55,7 +57,7 @@ private void setupHttpClient(int statusCode) throws Exception { when(statusLine.getStatusCode()).thenReturn(statusCode); when(httpResponse.getStatusLine()).thenReturn(statusLine); - when(httpResponse.getEntity()).thenReturn(new StringEntity(validResponse)); + when(httpResponse.getEntity()).thenReturn(new StringEntity(validRequestResponse)); when(mockHttpClient.execute(any(HttpPost.class))) .thenReturn(httpResponse); @@ -99,19 +101,19 @@ public void generateCorrectRequestBody() throws Exception { @Test public void returnResponseStringWhenStatusIs200() throws Exception { ODPApiManager apiManager = new DefaultODPApiManager(mockHttpClient); - String responseString = apiManager.fetchQualifiedSegments("key", "endPoint", "fs_user_id", "test_user", new HashSet<>(Arrays.asList("segment_1", "segment_2"))); + List response = apiManager.fetchQualifiedSegments("key", "endPoint", "fs_user_id", "test_user", new HashSet<>(Arrays.asList("segment_1", "segment_2"))); verify(mockHttpClient, times(1)).execute(any(HttpPost.class)); - assertEquals(validResponse, responseString); + assertEquals(validResponse, response); } @Test public void returnNullWhenStatusIsNot200AndLogError() throws Exception { setupHttpClient(500); ODPApiManager apiManager = new DefaultODPApiManager(mockHttpClient); - String responseString = apiManager.fetchQualifiedSegments("key", "endPoint", "fs_user_id", "test_user", new HashSet<>(Arrays.asList("segment_1", "segment_2"))); + List response = apiManager.fetchQualifiedSegments("key", "endPoint", "fs_user_id", "test_user", new HashSet<>(Arrays.asList("segment_1", "segment_2"))); verify(mockHttpClient, times(1)).execute(any(HttpPost.class)); logbackVerifier.expectMessage(Level.ERROR, "Unexpected response from ODP server, Response code: 500, null"); - assertNull(responseString); + assertNull(response); } @Test