diff --git a/firebase-segmentation/src/androidTest/java/com/google/firebase/segmentation/FirebaseSegmentationInstrumentedTest.java b/firebase-segmentation/src/androidTest/java/com/google/firebase/segmentation/FirebaseSegmentationInstrumentedTest.java index 19498782a78..034ee1eb339 100644 --- a/firebase-segmentation/src/androidTest/java/com/google/firebase/segmentation/FirebaseSegmentationInstrumentedTest.java +++ b/firebase-segmentation/src/androidTest/java/com/google/firebase/segmentation/FirebaseSegmentationInstrumentedTest.java @@ -127,7 +127,8 @@ public void testUpdateCustomInstallationId_CacheOk_BackendOk() throws Exception } @Test - public void testUpdateCustomInstallationId_CacheOk_BackendError() throws InterruptedException { + public void testUpdateCustomInstallationId_CacheOk_BackendError_Retryable() + throws InterruptedException { FirebaseSegmentation firebaseSegmentation = new FirebaseSegmentation( firebaseApp, firebaseInstanceId, actualCache, backendClientReturnsError); @@ -150,6 +151,31 @@ public void testUpdateCustomInstallationId_CacheOk_BackendError() throws Interru .isEqualTo(CustomInstallationIdCache.CacheStatus.PENDING_UPDATE); } + @Test + public void testUpdateCustomInstallationId_CacheOk_BackendError_NotRetryable() + throws InterruptedException { + when(backendClientReturnsError.updateCustomInstallationId( + anyLong(), anyString(), anyString(), anyString(), anyString())) + .thenReturn(SegmentationServiceClient.Code.CONFLICT); + FirebaseSegmentation firebaseSegmentation = + new FirebaseSegmentation( + firebaseApp, firebaseInstanceId, actualCache, backendClientReturnsError); + + // Expect exception + try { + Tasks.await(firebaseSegmentation.setCustomInstallationId(CUSTOM_INSTALLATION_ID)); + fail(); + } catch (ExecutionException expected) { + Throwable cause = expected.getCause(); + assertThat(cause).isInstanceOf(SetCustomInstallationIdException.class); + assertThat(((SetCustomInstallationIdException) cause).getStatus()) + .isEqualTo(SetCustomInstallationIdException.Status.DUPLICATED_CUSTOM_INSTALLATION_ID); + } + + CustomInstallationIdCacheEntryValue entryValue = actualCache.readCacheEntryValue(); + assertThat(entryValue).isNull(); + } + @Test public void testUpdateCustomInstallationId_CacheError_BackendOk() throws InterruptedException { FirebaseSegmentation firebaseSegmentation = diff --git a/firebase-segmentation/src/main/java/com/google/firebase/segmentation/FirebaseSegmentation.java b/firebase-segmentation/src/main/java/com/google/firebase/segmentation/FirebaseSegmentation.java index 2008ea09359..85adf2fb708 100644 --- a/firebase-segmentation/src/main/java/com/google/firebase/segmentation/FirebaseSegmentation.java +++ b/firebase-segmentation/src/main/java/com/google/firebase/segmentation/FirebaseSegmentation.java @@ -128,7 +128,7 @@ private Void updateCustomInstallationId(String customInstallationId) instanceIdResult = Tasks.await(firebaseInstanceId.getInstanceId()); } catch (ExecutionException | InterruptedException e) { throw new SetCustomInstallationIdException( - "Failed to get Firebase instance id", Status.CLIENT_ERROR); + Status.CLIENT_ERROR, "Failed to get Firebase instance id"); } boolean firstUpdateCacheResult = @@ -140,7 +140,7 @@ private Void updateCustomInstallationId(String customInstallationId) if (!firstUpdateCacheResult) { throw new SetCustomInstallationIdException( - "Failed to update client side cache", Status.CLIENT_ERROR); + Status.CLIENT_ERROR, "Failed to update client side cache"); } // Start requesting backend when first cache updae is done. @@ -164,11 +164,22 @@ private Void updateCustomInstallationId(String customInstallationId) instanceIdResult.getId(), CustomInstallationIdCache.CacheStatus.SYNCED)); break; - case HTTP_CLIENT_ERROR: - throw new SetCustomInstallationIdException(Status.CLIENT_ERROR); + case UNAUTHORIZED: + localCache.clear(); + throw new SetCustomInstallationIdException( + Status.CLIENT_ERROR, "Instance id token is invalid."); case CONFLICT: - throw new SetCustomInstallationIdException(Status.DUPLICATED_CUSTOM_INSTALLATION_ID); + localCache.clear(); + throw new SetCustomInstallationIdException( + Status.DUPLICATED_CUSTOM_INSTALLATION_ID, + "The custom installation id is used by another Firebase installation in your project."); + case HTTP_CLIENT_ERROR: + localCache.clear(); + throw new SetCustomInstallationIdException(Status.CLIENT_ERROR, "Http client error(4xx)"); + case NETWORK_ERROR: + case SERVER_ERROR: default: + // These are considered retryable errors, so not to clean up the cache. throw new SetCustomInstallationIdException(Status.BACKEND_ERROR); } @@ -176,7 +187,7 @@ private Void updateCustomInstallationId(String customInstallationId) return null; } else { throw new SetCustomInstallationIdException( - "Failed to update client side cache", Status.CLIENT_ERROR); + Status.CLIENT_ERROR, "Failed to update client side cache"); } } @@ -204,7 +215,7 @@ private Void clearCustomInstallationId() throws SetCustomInstallationIdException instanceIdResult = Tasks.await(firebaseInstanceId.getInstanceId()); } catch (ExecutionException | InterruptedException e) { throw new SetCustomInstallationIdException( - "Failed to get Firebase instance id", Status.CLIENT_ERROR); + Status.CLIENT_ERROR, "Failed to get Firebase instance id"); } boolean firstUpdateCacheResult = @@ -214,7 +225,7 @@ private Void clearCustomInstallationId() throws SetCustomInstallationIdException if (!firstUpdateCacheResult) { throw new SetCustomInstallationIdException( - "Failed to update client side cache", Status.CLIENT_ERROR); + Status.CLIENT_ERROR, "Failed to update client side cache"); } String iid = instanceIdResult.getId(); @@ -231,9 +242,15 @@ private Void clearCustomInstallationId() throws SetCustomInstallationIdException case OK: finalUpdateCacheResult = localCache.clear(); break; + case UNAUTHORIZED: + throw new SetCustomInstallationIdException( + Status.CLIENT_ERROR, "Instance id token is invalid."); case HTTP_CLIENT_ERROR: - throw new SetCustomInstallationIdException(Status.CLIENT_ERROR); + throw new SetCustomInstallationIdException(Status.CLIENT_ERROR, "Http client error(4xx)"); + case NETWORK_ERROR: + case SERVER_ERROR: default: + // These are considered retryable errors, so not to clean up the cache. throw new SetCustomInstallationIdException(Status.BACKEND_ERROR); } @@ -241,7 +258,7 @@ private Void clearCustomInstallationId() throws SetCustomInstallationIdException return null; } else { throw new SetCustomInstallationIdException( - "Failed to update client side cache", Status.CLIENT_ERROR); + Status.CLIENT_ERROR, "Failed to update client side cache"); } } } diff --git a/firebase-segmentation/src/main/java/com/google/firebase/segmentation/SetCustomInstallationIdException.java b/firebase-segmentation/src/main/java/com/google/firebase/segmentation/SetCustomInstallationIdException.java index 3c957ce3294..2291c078a03 100644 --- a/firebase-segmentation/src/main/java/com/google/firebase/segmentation/SetCustomInstallationIdException.java +++ b/firebase-segmentation/src/main/java/com/google/firebase/segmentation/SetCustomInstallationIdException.java @@ -45,13 +45,13 @@ public enum Status { this.status = status; } - SetCustomInstallationIdException(@NonNull String message, @NonNull Status status) { + SetCustomInstallationIdException(@NonNull Status status, @NonNull String message) { super(message); this.status = status; } SetCustomInstallationIdException( - @NonNull String message, @NonNull Status status, Throwable cause) { + @NonNull Status status, @NonNull String message, Throwable cause) { super(message, cause); this.status = status; } diff --git a/firebase-segmentation/src/main/java/com/google/firebase/segmentation/remote/SegmentationServiceClient.java b/firebase-segmentation/src/main/java/com/google/firebase/segmentation/remote/SegmentationServiceClient.java index 86b5f945205..6d0436d8b24 100644 --- a/firebase-segmentation/src/main/java/com/google/firebase/segmentation/remote/SegmentationServiceClient.java +++ b/firebase-segmentation/src/main/java/com/google/firebase/segmentation/remote/SegmentationServiceClient.java @@ -41,15 +41,15 @@ public class SegmentationServiceClient { public enum Code { OK, - HTTP_CLIENT_ERROR, - CONFLICT, + UNAUTHORIZED, + NETWORK_ERROR, - SERVER_ERROR, + HTTP_CLIENT_ERROR, - UNAUTHORIZED, + SERVER_ERROR, } @NonNull @@ -100,6 +100,9 @@ public Code updateCustomInstallationId( case 409: return Code.CONFLICT; default: + if (httpResponseCode / 100 == 4) { + return Code.HTTP_CLIENT_ERROR; + } return Code.SERVER_ERROR; } } catch (IOException e) { @@ -158,6 +161,9 @@ public Code clearCustomInstallationId( case 401: return Code.UNAUTHORIZED; default: + if (httpResponseCode / 100 == 4) { + return Code.HTTP_CLIENT_ERROR; + } return Code.SERVER_ERROR; } } catch (IOException e) {