From 25704fd4a1c9f091edcee089abaaecb13e86a07d Mon Sep 17 00:00:00 2001 From: Tim Kim <95260439+timkimadobe@users.noreply.github.com> Date: Tue, 25 Feb 2025 13:40:19 -0800 Subject: [PATCH 1/2] Unrevert "Update recoverable error codes (#170)" (#174) * Update recoverable error codes (#170) * add 507 error code as recoverable, handle negative retry-after, tests * minor fix - comment * Fix format of EdgeNetworkService and tests * minor text updates * fix network mock after rebase with dev --------- Co-authored-by: Kevin Lind * Add exclusion for Edge back for Edge Consent dependency * Use $mavenEdgeConsentVersion instead of hardcoded value --------- Co-authored-by: Emilia Dobrin <33132425+emdobrin@users.noreply.github.com> Co-authored-by: Kevin Lind --- code/edge/build.gradle.kts | 3 +- .../marketing/mobile/EdgeNetworkService.java | 25 +++++--- .../mobile/EdgeNetworkServiceTest.java | 64 +++++++++++++++++++ 3 files changed, 82 insertions(+), 10 deletions(-) diff --git a/code/edge/build.gradle.kts b/code/edge/build.gradle.kts index 7ea28733..6be1f204 100644 --- a/code/edge/build.gradle.kts +++ b/code/edge/build.gradle.kts @@ -39,8 +39,7 @@ dependencies { testImplementation("com.github.adobe:aepsdk-testutils-android:$mavenTestUtilsVersion") androidTestImplementation("com.github.adobe:aepsdk-testutils-android:$mavenTestUtilsVersion") - androidTestImplementation("com.adobe.marketing.mobile:edgeconsent:$mavenEdgeConsentVersion") - { + androidTestImplementation("com.adobe.marketing.mobile:edgeconsent:$mavenEdgeConsentVersion") { exclude(group = "com.adobe.marketing.mobile", module = "edge") } } \ No newline at end of file diff --git a/code/edge/src/main/java/com/adobe/marketing/mobile/EdgeNetworkService.java b/code/edge/src/main/java/com/adobe/marketing/mobile/EdgeNetworkService.java index bc60ba45..683bd46a 100644 --- a/code/edge/src/main/java/com/adobe/marketing/mobile/EdgeNetworkService.java +++ b/code/edge/src/main/java/com/adobe/marketing/mobile/EdgeNetworkService.java @@ -18,18 +18,20 @@ import com.adobe.marketing.mobile.services.Log; import com.adobe.marketing.mobile.services.NetworkRequest; import com.adobe.marketing.mobile.services.Networking; +import com.adobe.marketing.mobile.services.NetworkingConstants; import com.adobe.marketing.mobile.util.StringUtils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Scanner; +import java.util.Set; import java.util.concurrent.CountDownLatch; import org.json.JSONException; import org.json.JSONObject; @@ -98,14 +100,13 @@ interface ResponseCallback { private static final String DEFAULT_GENERIC_ERROR_MESSAGE = "Request to Edge Network failed with an unknown exception"; - static final List recoverableNetworkErrorCodes = new ArrayList<>( + static final Set recoverableNetworkErrorCodes = mergeUnique( + NetworkingConstants.RECOVERABLE_ERROR_CODES, Arrays.asList( -1, // returned for SocketTimeoutException 429, // too many requests - The user has sent too many requests in a given amount of time ("rate limiting"). - HttpURLConnection.HTTP_CLIENT_TIMEOUT, - HttpURLConnection.HTTP_BAD_GATEWAY, - HttpURLConnection.HTTP_UNAVAILABLE, - HttpURLConnection.HTTP_GATEWAY_TIMEOUT + 507, // insufficient storage + HttpURLConnection.HTTP_BAD_GATEWAY ) ); @@ -258,9 +259,10 @@ RetryResult doRequest( private int computeRetryInterval(final HttpConnecting connection) { String header = connection.getResponsePropertyValue(EdgeConstants.NetworkKeys.HEADER_KEY_RETRY_AFTER); + int retryAfter = EdgeConstants.Defaults.RETRY_INTERVAL_SECONDS; if (header != null && header.matches("\\d+")) { try { - return Integer.parseInt(header); + retryAfter = Integer.parseInt(header); } catch (NumberFormatException e) { Log.debug( LOG_TAG, @@ -272,7 +274,7 @@ private int computeRetryInterval(final HttpConnecting connection) { } } - return EdgeConstants.Defaults.RETRY_INTERVAL_SECONDS; + return retryAfter > 0 ? retryAfter : EdgeConstants.Defaults.RETRY_INTERVAL_SECONDS; } /** @@ -577,4 +579,11 @@ private String readInputStream(final InputStream inputStream) { return composeGenericErrorAsJson(e.getMessage()); } } + + private static Set mergeUnique(final List arr1, final List arr2) { + Set merged = new HashSet<>(); + merged.addAll(arr1); + merged.addAll(arr2); + return merged; + } } diff --git a/code/edge/src/test/java/com/adobe/marketing/mobile/EdgeNetworkServiceTest.java b/code/edge/src/test/java/com/adobe/marketing/mobile/EdgeNetworkServiceTest.java index 8370a81c..df8303a6 100644 --- a/code/edge/src/test/java/com/adobe/marketing/mobile/EdgeNetworkServiceTest.java +++ b/code/edge/src/test/java/com/adobe/marketing/mobile/EdgeNetworkServiceTest.java @@ -20,15 +20,19 @@ import com.adobe.marketing.mobile.services.HttpMethod; import com.adobe.marketing.mobile.services.NetworkRequest; +import com.adobe.marketing.mobile.services.NetworkingConstants; import com.adobe.marketing.mobile.util.MockConnection; import com.adobe.marketing.mobile.util.MockNetworkService; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.json.JSONException; @@ -50,6 +54,7 @@ public class EdgeNetworkServiceTest { private static final String TEST_URL = "https://test.com"; private static final String HEADER_CONTENT_TYPE = "Content-Type"; private static final String HEADER_CONTENT_TYPE_JSON_VALUE = "application/json"; + private static final String HEADER_RETRY_AFTER = "Retry-After"; private final Map requestHeaders = new HashMap() { { put("key1", "value1"); @@ -360,6 +365,65 @@ public void testDoRequest_whenConnection_RecoverableResponseCode_504_ReturnsRetr testRecoverableNetworkResponse(504, "Gateway Timeout"); } + @Test + public void testDoRequest_whenConnection_RecoverableResponseCode_507_ReturnsRetryYes_AndNoResponseCallback_AndNoErrorCallback() { + testRecoverableNetworkResponse(507, "Insufficient Storage"); + } + + @Test + public void testDoRequest_whenConnection_RecoverableResponseCodeAndRetryAfter_ReturnsRetryTimeout() { + Set recoverableNetworkErrorCodes = new HashSet<>(); + recoverableNetworkErrorCodes.addAll(NetworkingConstants.RECOVERABLE_ERROR_CODES); + recoverableNetworkErrorCodes.addAll(Arrays.asList(429, 502, 507, -1)); + + for (int responseCode : recoverableNetworkErrorCodes) { + testRecoverableWithRetryAfter(responseCode, "30", 30); + } + } + + @Test + public void testDoRequest_whenConnection_InvalidRetryAfter_ReturnsDefaultRetryTimeout() { + testRecoverableNetworkResponse(507, "Insufficient Storage"); + String[] invalidRetryAfter = { "InvalidRetryAfter", "A", "", "-1", "0", " " }; + + for (String retryAfter : invalidRetryAfter) { + testRecoverableWithRetryAfter(503, retryAfter, 5); // expecting default timeout + } + } + + @Test + public void testDoRequest_whenConnection_ValidRetryAfter_ReturnsCorrectRetryTimeout() { + testRecoverableNetworkResponse(507, "Insufficient Storage"); + String[] invalidRetryAfter = { "1", "5", "30", "60", "180", "300" }; + + for (String retryAfter : invalidRetryAfter) { + testRecoverableWithRetryAfter(503, retryAfter, Integer.parseInt(retryAfter)); // expecting provided timeout + } + } + + private void testRecoverableWithRetryAfter( + final int responseCode, + final String retryAfter, + final int expectedRetryAfter + ) { + // setup + final String url = "https://test.com"; + final String jsonRequest = "{}"; + final Map headers = new HashMap<>(); + headers.put(HEADER_RETRY_AFTER, retryAfter); + MockConnection mockConnection = new MockConnection(responseCode, null, "error", headers); + mockNetworkService.reset(); + mockNetworkService.setMockResponseFor(url, mockConnection); + networkService = new EdgeNetworkService(mockNetworkService); + + // test + DoRequestResult result = doRequestSync(url, jsonRequest); + + // verify + assertEquals(EdgeNetworkService.Retry.YES, result.retryResult.getShouldRetry()); + assertEquals(expectedRetryAfter, result.retryResult.getRetryIntervalSeconds()); + } + private void testRecoverableNetworkResponse(final int responseCode, final String errorString) { // setup final String url = "https://test.com"; From 1386a4204e6e91ceaed8559b60c5b7087bd533fb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 25 Feb 2025 21:46:14 +0000 Subject: [PATCH 2/2] Updating version to 3.0.2 --- .../src/main/java/com/adobe/marketing/mobile/EdgeConstants.java | 2 +- code/gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/edge/src/main/java/com/adobe/marketing/mobile/EdgeConstants.java b/code/edge/src/main/java/com/adobe/marketing/mobile/EdgeConstants.java index b786345e..8b109aff 100644 --- a/code/edge/src/main/java/com/adobe/marketing/mobile/EdgeConstants.java +++ b/code/edge/src/main/java/com/adobe/marketing/mobile/EdgeConstants.java @@ -14,7 +14,7 @@ final class EdgeConstants { static final String EDGE_DATA_STORAGE = "EdgeDataStorage"; - static final String EXTENSION_VERSION = "3.0.0"; + static final String EXTENSION_VERSION = "3.0.2"; static final String EXTENSION_NAME = "com.adobe.edge"; static final String FRIENDLY_NAME = "Edge"; static final String LOG_TAG = FRIENDLY_NAME; diff --git a/code/gradle.properties b/code/gradle.properties index e9242982..301c4d15 100644 --- a/code/gradle.properties +++ b/code/gradle.properties @@ -16,7 +16,7 @@ org.gradle.configureondemand=false org.gradle.caching=true moduleName=edge -moduleVersion=3.0.0 +moduleVersion=3.0.2 mavenCoreVersion=3.0.0 mavenEdgeIdentityVersion=3.0.0 mavenEdgeConsentVersion=3.0.0