-
Notifications
You must be signed in to change notification settings - Fork 3
[CDX-387] Support passing seed item ids to recommendations events #163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0b34a85
5d1d573
6492d26
d621bec
8e49a95
a766d8a
1e1caab
7d2fe8d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2191,14 +2191,16 @@ object ConstructorIo { | |
| * @param resultCount The total number of recommendation results | ||
| * @param resultPositionOnPage The position of the recommendation result that was clicked on | ||
| * @param analyticsTags Additional analytics tags to pass | ||
| * @param seedItemIds The seed item ID(s) used to generate the recommendation results | ||
| */ | ||
| fun trackRecommendationResultClick(podId: String, strategyId: String, customerId: String, variationId: String? = null, sectionName: String? = null, resultId: String? = null, numResultsPerPage: Int? = null, resultPage: Int? = null, resultCount: Int? = null, resultPositionOnPage: Int? = null, analyticsTags: Map<String, String>? = null) { | ||
| var completable = trackRecommendationResultClickInternal(podId, strategyId, customerId, variationId, sectionName, resultId, numResultsPerPage, resultPage, resultCount, resultPositionOnPage, analyticsTags) | ||
| fun trackRecommendationResultClick(podId: String, strategyId: String, customerId: String, variationId: String? = null, sectionName: String? = null, resultId: String? = null, numResultsPerPage: Int? = null, resultPage: Int? = null, resultCount: Int? = null, resultPositionOnPage: Int? = null, analyticsTags: Map<String, String>? = null, seedItemIds: List<String>? = null) { | ||
| var completable = trackRecommendationResultClickInternal(podId, strategyId, customerId, variationId, sectionName, resultId, numResultsPerPage, resultPage, resultCount, resultPositionOnPage, analyticsTags, seedItemIds) | ||
|
Comment on lines
+2196
to
+2197
|
||
| disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { | ||
| t -> e("Recommendation Result Click error: ${t.message}") | ||
| })) | ||
| } | ||
| internal fun trackRecommendationResultClickInternal(podId: String, strategyId: String, customerId: String, variationId: String? = null, sectionName: String? = null, resultId: String? = null, numResultsPerPage: Int? = null, resultPage: Int? = null, resultCount: Int? = null, resultPositionOnPage: Int? = null, analyticsTags: Map<String, String>? = null): Completable { | ||
|
|
||
| internal fun trackRecommendationResultClickInternal(podId: String, strategyId: String, customerId: String, variationId: String? = null, sectionName: String? = null, resultId: String? = null, numResultsPerPage: Int? = null, resultPage: Int? = null, resultCount: Int? = null, resultPositionOnPage: Int? = null, analyticsTags: Map<String, String>? = null, seedItemIds: List<String>? = null): Completable { | ||
| preferenceHelper.getSessionId(sessionIncrementHandler) | ||
| val section = sectionName ?: preferenceHelper.defaultItemSection | ||
| val recommendationsResultClickRequestBody = RecommendationResultClickRequestBody( | ||
|
|
@@ -2220,7 +2222,8 @@ object ConstructorIo { | |
| mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), | ||
| true, | ||
| section, | ||
| System.currentTimeMillis() | ||
| System.currentTimeMillis(), | ||
| seedItemIds?.takeIf { it.isNotEmpty() } | ||
| ) | ||
|
|
||
| return dataManager.trackRecommendationResultClick( | ||
|
|
@@ -2244,9 +2247,10 @@ object ConstructorIo { | |
| * @param resultId The result ID of the recommendation response that the selection came from | ||
| * @param sectionName The section that the results came from, i.e. "Products" | ||
| * @param analyticsTags Additional analytics tags to pass | ||
| * @param seedItemIds The seed item ID(s) used to generate the recommendation results | ||
| */ | ||
| fun trackRecommendationResultsView(podId: String, itemIds: Array<String>, numResultsViewed: Int, resultPage: Int? = null, resultCount: Int? = null, resultId: String? = null, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map<String, String>? = null) { | ||
| var completable = trackRecommendationResultsViewInternal(podId, itemIds, numResultsViewed, resultPage, resultCount, resultId, sectionName, url, analyticsTags) | ||
| fun trackRecommendationResultsView(podId: String, itemIds: Array<String>, numResultsViewed: Int, resultPage: Int? = null, resultCount: Int? = null, resultId: String? = null, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map<String, String>? = null, seedItemIds: List<String>? = null) { | ||
| var completable = trackRecommendationResultsViewInternal(podId, itemIds, numResultsViewed, resultPage, resultCount, resultId, sectionName, url, analyticsTags, seedItemIds) | ||
|
Comment on lines
+2252
to
+2253
|
||
| disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { | ||
| t -> e("Recommendation Results View error: ${t.message}") | ||
| })) | ||
|
|
@@ -2266,14 +2270,16 @@ object ConstructorIo { | |
| * @param resultId The result ID of the recommendation response that the selection came from | ||
| * @param sectionName The section that the results came from, i.e. "Products" | ||
| * @param analyticsTags Additional analytics tags to pass | ||
| * @param seedItemIds The seed item ID(s) used to generate the recommendation results | ||
| */ | ||
| fun trackRecommendationResultsView(podId: String, numResultsViewed: Int, resultPage: Int? = null, resultCount: Int? = null, resultId: String? = null, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map<String, String>? = null) { | ||
| var completable = trackRecommendationResultsViewInternal(podId, null, numResultsViewed, resultPage, resultCount, resultId, sectionName, url, analyticsTags) | ||
| fun trackRecommendationResultsView(podId: String, numResultsViewed: Int, resultPage: Int? = null, resultCount: Int? = null, resultId: String? = null, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map<String, String>? = null, seedItemIds: List<String>? = null) { | ||
| var completable = trackRecommendationResultsViewInternal(podId, null, numResultsViewed, resultPage, resultCount, resultId, sectionName, url, analyticsTags, seedItemIds) | ||
|
Comment on lines
+2275
to
+2276
|
||
| disposable.add(completable.subscribeOn(Schedulers.io()).subscribe({}, { | ||
| t -> e("Recommendation Results View error: ${t.message}") | ||
| })) | ||
| } | ||
| internal fun trackRecommendationResultsViewInternal(podId: String, itemIds: Array<String>? = null, numResultsViewed: Int, resultPage: Int? = null, resultCount: Int? = null, resultId: String? = null, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map<String, String>? = null): Completable { | ||
|
|
||
| internal fun trackRecommendationResultsViewInternal(podId: String, itemIds: Array<String>? = null, numResultsViewed: Int, resultPage: Int? = null, resultCount: Int? = null, resultId: String? = null, sectionName: String? = null, url: String = "Not Available", analyticsTags: Map<String, String>? = null, seedItemIds: List<String>? = null): Completable { | ||
| preferenceHelper.getSessionId(sessionIncrementHandler) | ||
| val section = sectionName ?: preferenceHelper.defaultItemSection | ||
| val items = itemIds?.map{ item -> TrackingItem(item, null, null, null)} | ||
|
|
@@ -2294,7 +2300,8 @@ object ConstructorIo { | |
| mergeAnalyticsTags(configMemoryHolder.defaultAnalyticsTags, analyticsTags), | ||
| true, | ||
| section, | ||
| System.currentTimeMillis() | ||
| System.currentTimeMillis(), | ||
| seedItemIds?.takeIf { it.isNotEmpty() } | ||
| ) | ||
|
|
||
| return dataManager.trackRecommendationResultsView( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ import java.net.URLEncoder | |
| import java.util.* | ||
| import java.util.concurrent.TimeUnit | ||
| import kotlin.test.assertEquals | ||
| import kotlin.test.assertNull | ||
|
|
||
| internal fun getRequestBody(request: RecordedRequest): Map<String, String> { | ||
| val requestBodyString = request.body.readUtf8().drop(1).dropLast(1).replace("\"", "") | ||
|
|
@@ -1133,6 +1134,7 @@ class ConstructorIoTrackingTest { | |
| assertEquals("pdp5", requestBody["pod_id"]) | ||
| assertEquals("User Featured", requestBody["strategy_id"]) | ||
| assertEquals("TIT-REP-1997", requestBody["item_id"]) | ||
| assertNull(requestBody["seed_item_ids"]) | ||
| assertEquals("POST", request.method) | ||
| assert(request.path!!.startsWith(path)) | ||
| } | ||
|
|
@@ -1170,6 +1172,57 @@ class ConstructorIoTrackingTest { | |
| assert(request.path!!.startsWith(path)) | ||
| } | ||
|
|
||
| @Test | ||
| fun trackRecommendationResultClickWithSingleSeedItemId() { | ||
constructor-claude-bedrock[bot] marked this conversation as resolved.
Show resolved
Hide resolved
constructor-claude-bedrock[bot] marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: The new tests for |
||
| val mockResponse = MockResponse().setResponseCode(204) | ||
| mockServer.enqueue(mockResponse) | ||
| val observer = ConstructorIo.trackRecommendationResultClickInternal("pdp5", "User Featured","TIT-REP-1997", seedItemIds = listOf("seed-item-123")).test() | ||
constructor-claude-bedrock[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| observer.assertComplete() | ||
| val request = mockServer.takeRequest() | ||
| val requestBody = getRequestBody(request) | ||
| val path = "/v2/behavioral_action/recommendation_result_click?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.39.0&_dt=" | ||
| assertEquals("pdp5", requestBody["pod_id"]) | ||
| assertEquals("User Featured", requestBody["strategy_id"]) | ||
| assertEquals("TIT-REP-1997", requestBody["item_id"]) | ||
| assertEquals("[seed-item-123]", requestBody["seed_item_ids"]) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Important Issue: The test asserts It would be clearer and more robust to verify this field is present and non-null, and separately test the actual JSON body format. At minimum, a comment explaining why the expected value includes brackets would help future readers understand the intent: // Moshi serializes List<String> as a JSON array; getRequestBody strips quotes
// so "[\"seed-item-123\"]" becomes "[seed-item-123]"
assertEquals("[seed-item-123]", requestBody["seed_item_ids"]) |
||
| assertEquals("POST", request.method) | ||
| assert(request.path!!.startsWith(path)) | ||
| } | ||
|
|
||
| @Test | ||
| fun trackRecommendationResultClickWithMultipleSeedItemIds() { | ||
| val mockResponse = MockResponse().setResponseCode(204) | ||
| mockServer.enqueue(mockResponse) | ||
| val observer = ConstructorIo.trackRecommendationResultClickInternal("pdp5", "User Featured","TIT-REP-1997", seedItemIds = listOf("seed-item-1", "seed-item-2", "seed-item-3")).test() | ||
| observer.assertComplete() | ||
| val request = mockServer.takeRequest() | ||
| val requestBody = getRequestBody(request) | ||
| val path = "/v2/behavioral_action/recommendation_result_click?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.39.0&_dt=" | ||
| assertEquals("pdp5", requestBody["pod_id"]) | ||
| assertEquals("User Featured", requestBody["strategy_id"]) | ||
| assertEquals("TIT-REP-1997", requestBody["item_id"]) | ||
| assertEquals("[seed-item-1,seed-item-2,seed-item-3]", requestBody["seed_item_ids"]) | ||
| assertEquals("POST", request.method) | ||
| assert(request.path!!.startsWith(path)) | ||
| } | ||
|
|
||
| @Test | ||
| fun trackRecommendationResultClickWithEmptySeedItemIds() { | ||
| val mockResponse = MockResponse().setResponseCode(204) | ||
| mockServer.enqueue(mockResponse) | ||
| val observer = ConstructorIo.trackRecommendationResultClickInternal("pdp5", "User Featured", "TIT-REP-1997", seedItemIds = listOf()).test() | ||
| observer.assertComplete() | ||
| val request = mockServer.takeRequest() | ||
| val requestBody = getRequestBody(request) | ||
| val path = "/v2/behavioral_action/recommendation_result_click?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.39.0&_dt=" | ||
| assertEquals("pdp5", requestBody["pod_id"]) | ||
| assertEquals("User Featured", requestBody["strategy_id"]) | ||
| assertEquals("TIT-REP-1997", requestBody["item_id"]) | ||
| assertNull(requestBody["seed_item_ids"]) | ||
| assertEquals("POST", request.method) | ||
| assert(request.path!!.startsWith(path)) | ||
| } | ||
|
|
||
| @Test | ||
| fun trackRecommendationResultClick500() { | ||
| val mockResponse = MockResponse().setResponseCode(500).setBody("Internal server error") | ||
|
|
@@ -1208,6 +1261,7 @@ class ConstructorIoTrackingTest { | |
| val path = "/v2/behavioral_action/recommendation_result_view?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.39.0&_dt=" | ||
| assertEquals("pdp5", requestBody["pod_id"]) | ||
| assertEquals("4", requestBody["num_results_viewed"]) | ||
| assertNull(requestBody["seed_item_ids"]) | ||
| assertEquals("POST", request.method) | ||
| assert(request.path!!.startsWith(path)) | ||
| } | ||
|
|
@@ -1264,6 +1318,54 @@ class ConstructorIoTrackingTest { | |
| assert(request.path!!.startsWith(path)) | ||
| } | ||
|
|
||
| @Test | ||
| fun trackRecommendationResultsViewWithSingleSeedItemId() { | ||
constructor-claude-bedrock[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| val mockResponse = MockResponse().setResponseCode(204) | ||
| mockServer.enqueue(mockResponse) | ||
| val observer = ConstructorIo.trackRecommendationResultsViewInternal("pdp5", null, 4, seedItemIds = listOf("seed-item-123")).test() | ||
constructor-claude-bedrock[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| observer.assertComplete() | ||
| val request = mockServer.takeRequest() | ||
| val requestBody = getRequestBody(request) | ||
| val path = "/v2/behavioral_action/recommendation_result_view?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.39.0&_dt=" | ||
| assertEquals("pdp5", requestBody["pod_id"]) | ||
| assertEquals("4", requestBody["num_results_viewed"]) | ||
| assertEquals("[seed-item-123]", requestBody["seed_item_ids"]) | ||
| assertEquals("POST", request.method) | ||
| assert(request.path!!.startsWith(path)) | ||
| } | ||
|
|
||
| @Test | ||
| fun trackRecommendationResultsViewWithMultipleSeedItemIds() { | ||
| val mockResponse = MockResponse().setResponseCode(204) | ||
| mockServer.enqueue(mockResponse) | ||
| val observer = ConstructorIo.trackRecommendationResultsViewInternal("pdp5", null, 4, seedItemIds = listOf("seed-item-1", "seed-item-2", "seed-item-3")).test() | ||
| observer.assertComplete() | ||
| val request = mockServer.takeRequest() | ||
| val requestBody = getRequestBody(request) | ||
| val path = "/v2/behavioral_action/recommendation_result_view?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.39.0&_dt=" | ||
| assertEquals("pdp5", requestBody["pod_id"]) | ||
| assertEquals("4", requestBody["num_results_viewed"]) | ||
| assertEquals("[seed-item-1,seed-item-2,seed-item-3]", requestBody["seed_item_ids"]) | ||
| assertEquals("POST", request.method) | ||
| assert(request.path!!.startsWith(path)) | ||
| } | ||
|
|
||
| @Test | ||
| fun trackRecommendationResultsViewWithEmptySeedItemIds() { | ||
| val mockResponse = MockResponse().setResponseCode(204) | ||
| mockServer.enqueue(mockResponse) | ||
| val observer = ConstructorIo.trackRecommendationResultsViewInternal("pdp5", null, 4, seedItemIds = listOf()).test() | ||
| observer.assertComplete() | ||
| val request = mockServer.takeRequest() | ||
| val requestBody = getRequestBody(request) | ||
| val path = "/v2/behavioral_action/recommendation_result_view?section=Products&key=copper-key&i=wacko-the-guid&ui=player-three&s=67&c=cioand-2.39.0&_dt=" | ||
| assertEquals("pdp5", requestBody["pod_id"]) | ||
| assertEquals("4", requestBody["num_results_viewed"]) | ||
| assertNull(requestBody["seed_item_ids"]) | ||
| assertEquals("POST", request.method) | ||
| assert(request.path!!.startsWith(path)) | ||
| } | ||
|
|
||
| @Test | ||
| fun trackRecommendationResultsView500() { | ||
| val mockResponse = MockResponse().setResponseCode(500).setBody("Internal server error") | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.