Skip to content

Refresh Auth token if expired during getId call. #809

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

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion firebase-installations/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ package com.google.firebase.installations.local {
}

public enum PersistedFid.RegistrationStatus {
enum_constant public static final com.google.firebase.installations.local.PersistedFid.RegistrationStatus NOT_GENERATED;
enum_constant public static final com.google.firebase.installations.local.PersistedFid.RegistrationStatus PENDING;
enum_constant public static final com.google.firebase.installations.local.PersistedFid.RegistrationStatus REGISTERED;
enum_constant public static final com.google.firebase.installations.local.PersistedFid.RegistrationStatus REGISTER_ERROR;
Expand All @@ -44,10 +45,14 @@ package com.google.firebase.installations.local {
method @NonNull public static com.google.firebase.installations.local.PersistedFidEntry.Builder builder();
method @Nullable public abstract String getAuthToken();
method public abstract long getExpiresInSecs();
method @NonNull public abstract String getFirebaseInstallationId();
method @Nullable public abstract String getFirebaseInstallationId();
method @Nullable public abstract String getRefreshToken();
method @NonNull public abstract com.google.firebase.installations.local.PersistedFid.RegistrationStatus getRegistrationStatus();
method public abstract long getTokenCreationEpochInSecs();
method public boolean isErrored();
method public boolean isNotGenerated();
method public boolean isRegistered();
method public boolean isUnregistered();
method @NonNull public abstract com.google.firebase.installations.local.PersistedFidEntry.Builder toBuilder();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package com.google.firebase.installations;

import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.firebase.installations.FisAndroidTestConstants.DEFAULT_PERSISTED_FID_ENTRY;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_API_KEY;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_APP_ID_1;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_AUTH_TOKEN;
Expand Down Expand Up @@ -89,7 +90,7 @@ public class FirebaseInstallationsInstrumentedTest {
.setFirebaseInstallationId(TEST_FID_1)
.setAuthToken(TEST_AUTH_TOKEN)
.setRefreshToken(TEST_REFRESH_TOKEN)
.setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_2)
.setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_1)
.setExpiresInSecs(TEST_TOKEN_EXPIRATION_TIMESTAMP)
.setRegistrationStatus(PersistedFid.RegistrationStatus.REGISTERED)
.build();
Expand All @@ -99,7 +100,7 @@ public class FirebaseInstallationsInstrumentedTest {
.setFirebaseInstallationId(TEST_FID_1)
.setAuthToken(TEST_AUTH_TOKEN)
.setRefreshToken(TEST_REFRESH_TOKEN)
.setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_2)
.setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_1)
.setExpiresInSecs(TEST_TOKEN_EXPIRATION_TIMESTAMP_2)
.setRegistrationStatus(PersistedFid.RegistrationStatus.REGISTERED)
.build();
Expand All @@ -109,7 +110,7 @@ public class FirebaseInstallationsInstrumentedTest {
.setFirebaseInstallationId(TEST_FID_1)
.setAuthToken("")
.setRefreshToken("")
.setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_2)
.setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_1)
.setExpiresInSecs(0)
.setRegistrationStatus(PersistedFid.RegistrationStatus.UNREGISTERED)
.build();
Expand Down Expand Up @@ -163,7 +164,8 @@ public void setUp() throws FirebaseInstallationServiceException {
new FirebaseInstallationServiceException(
"SDK Error", FirebaseInstallationServiceException.Status.SERVER_ERROR));
when(persistedFidReturnsError.insertOrUpdatePersistedFidEntry(any())).thenReturn(false);
when(persistedFidReturnsError.readPersistedFidEntryValue()).thenReturn(null);
when(persistedFidReturnsError.readPersistedFidEntryValue())
.thenReturn(DEFAULT_PERSISTED_FID_ENTRY);
when(mockUtils.createRandomFid()).thenReturn(TEST_FID_1);
when(mockClock.currentTimeMillis()).thenReturn(TEST_CREATION_TIMESTAMP_1);
// Mocks success on FIS deletion
Expand All @@ -190,7 +192,7 @@ public void testGetId_PersistedFidOk_BackendOk() throws Exception {
mockClock, executor, firebaseApp, backendClientReturnsOk, persistedFid, mockUtils);

// No exception, means success.
assertWithMessage("getId Task fails.")
assertWithMessage("getId Task failed")
.that(Tasks.await(firebaseInstallations.getId()))
.isNotEmpty();
PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue();
Expand All @@ -217,7 +219,7 @@ public void testGetId_multipleCalls_sameFIDReturned() throws Exception {
mockClock, executor, firebaseApp, backendClientReturnsOk, persistedFid, mockUtils);

// No exception, means success.
assertWithMessage("getId Task fails.")
assertWithMessage("getId Task failed")
.that(Tasks.await(firebaseInstallations.getId()))
.isNotEmpty();
PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue();
Expand Down Expand Up @@ -290,6 +292,36 @@ public void testGetId_PersistedFidError_BackendOk() throws InterruptedException
}
}

@Test
public void testGetId_expiredAuthToken_refreshesAuthToken() throws Exception {
// Update local storage with fid entry that has auth token expired.
persistedFid.insertOrUpdatePersistedFidEntry(EXPIRED_AUTH_TOKEN_ENTRY);
FirebaseInstallations firebaseInstallations =
new FirebaseInstallations(
mockClock, executor, firebaseApp, backendClientReturnsOk, persistedFid, mockUtils);

assertWithMessage("getId Task failed")
.that(Tasks.await(firebaseInstallations.getId()))
.isNotEmpty();
PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue();
assertWithMessage("Persisted Fid doesn't match")
.that(entryValue.getFirebaseInstallationId())
.isEqualTo(TEST_FID_1);

// Waiting for Task that generates auth token with the FIS Servers
executor.awaitTermination(500, TimeUnit.MILLISECONDS);

// Validate that registration is complete with updated auth token
PersistedFidEntry updatedFidEntry = persistedFid.readPersistedFidEntryValue();
assertWithMessage("Persisted Fid doesn't match")
.that(updatedFidEntry)
.isEqualTo(UPDATED_AUTH_TOKEN_FID_ENTRY);
verify(backendClientReturnsOk, never())
.createFirebaseInstallation(TEST_API_KEY, TEST_FID_1, TEST_PROJECT_ID, TEST_APP_ID_1);
verify(backendClientReturnsOk, times(1))
.generateAuthToken(TEST_API_KEY, TEST_FID_1, TEST_PROJECT_ID, TEST_REFRESH_TOKEN);
}

@Test
public void testGetAuthToken_fidDoesNotExist_successful() throws Exception {
FirebaseInstallations firebaseInstallations =
Expand Down Expand Up @@ -418,18 +450,13 @@ public void testGetAuthToken_serverError_failure() throws Exception {
@Test
public void testGetAuthToken_multipleCallsDoNotForceRefresh_fetchedNewTokenOnce()
throws Exception {
// Using mockPersistedFid to ensure the order of returning persistedFidEntry to 2 tasks
// triggered simultaneously. Task2 waits for Task1 to complete. On Task1 completion, task2 reads
// the UPDATED_AUTH_TOKEN_FID_ENTRY by Task1 on execution.
when(mockPersistedFid.readPersistedFidEntryValue())
.thenReturn(
EXPIRED_AUTH_TOKEN_ENTRY,
EXPIRED_AUTH_TOKEN_ENTRY,
EXPIRED_AUTH_TOKEN_ENTRY,
UPDATED_AUTH_TOKEN_FID_ENTRY);
// Update local storage with fid entry that has auth token expired. When 2 tasks are triggered
// simultaneously, Task2 waits for Task1 to complete. On Task1 completion, task2 reads the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "reads the" has too many (two) spaces

// UPDATED_AUTH_TOKEN_FID_ENTRY by Task1 on execution.
persistedFid.insertOrUpdatePersistedFidEntry(EXPIRED_AUTH_TOKEN_ENTRY);
FirebaseInstallations firebaseInstallations =
new FirebaseInstallations(
mockClock, executor, firebaseApp, backendClientReturnsOk, mockPersistedFid, mockUtils);
mockClock, executor, firebaseApp, backendClientReturnsOk, persistedFid, mockUtils);

// Call getAuthToken multiple times with DO_NOT_FORCE_REFRESH option
Task<InstallationTokenResult> task1 =
Expand Down Expand Up @@ -508,7 +535,9 @@ public void testDelete_registeredFID_successful() throws Exception {
Tasks.await(firebaseInstallations.delete());

PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue();
assertWithMessage("Persisted Fid Entry is not null.").that(entryValue).isNull();
assertWithMessage("Persisted Fid Entry is not null.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the "is not null" message isn't correct any more

.that(entryValue)
.isEqualTo(DEFAULT_PERSISTED_FID_ENTRY);
verify(backendClientReturnsOk, times(1))
.deleteFirebaseInstallation(TEST_API_KEY, TEST_FID_1, TEST_PROJECT_ID, TEST_REFRESH_TOKEN);
}
Expand All @@ -524,7 +553,9 @@ public void testDelete_unregisteredFID_successful() throws Exception {
Tasks.await(firebaseInstallations.delete());

PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue();
assertWithMessage("Persisted Fid Entry is not null.").that(entryValue).isNull();
assertWithMessage("Persisted Fid Entry is not null.")
.that(entryValue)
.isEqualTo(DEFAULT_PERSISTED_FID_ENTRY);
verify(backendClientReturnsOk, never())
.deleteFirebaseInstallation(TEST_API_KEY, TEST_FID_1, TEST_PROJECT_ID, TEST_REFRESH_TOKEN);
}
Expand All @@ -538,7 +569,9 @@ public void testDelete_emptyPersistedFidEntry_successful() throws Exception {
Tasks.await(firebaseInstallations.delete());

PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue();
assertWithMessage("Persisted Fid Entry is not null.").that(entryValue).isNull();
assertWithMessage("Persisted Fid Entry is not null.")
.that(entryValue)
.isEqualTo(DEFAULT_PERSISTED_FID_ENTRY);
verify(backendClientReturnsOk, never())
.deleteFirebaseInstallation(TEST_API_KEY, TEST_FID_1, TEST_PROJECT_ID, TEST_REFRESH_TOKEN);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package com.google.firebase.installations;

import com.google.firebase.installations.local.PersistedFidEntry;

public final class FisAndroidTestConstants {
public static final String TEST_FID_1 = "cccccccccccccccccccccc";

Expand All @@ -35,5 +37,8 @@ public final class FisAndroidTestConstants {
public static final long TEST_TOKEN_EXPIRATION_TIMESTAMP_2 = 2000L;

public static final long TEST_CREATION_TIMESTAMP_1 = 2000L;
public static final long TEST_CREATION_TIMESTAMP_2 = 2000L;
public static final long TEST_CREATION_TIMESTAMP_2 = 2L;

public static final PersistedFidEntry DEFAULT_PERSISTED_FID_ENTRY =
PersistedFidEntry.builder().build();
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

package com.google.firebase.installations.local;

import static com.google.firebase.installations.FisAndroidTestConstants.DEFAULT_PERSISTED_FID_ENTRY;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_APP_ID_1;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_APP_ID_2;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_AUTH_TOKEN;
Expand All @@ -23,7 +24,6 @@
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_REFRESH_TOKEN;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_TOKEN_EXPIRATION_TIMESTAMP;
import static com.google.firebase.installations.local.PersistedFidEntrySubject.assertThat;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import androidx.test.core.app.ApplicationProvider;
Expand Down Expand Up @@ -68,9 +68,9 @@ public void cleanUp() throws Exception {
}

@Test
public void testReadPersistedFidEntry_Null() {
assertNull(persistedFid0.readPersistedFidEntryValue());
assertNull(persistedFid1.readPersistedFidEntryValue());
public void testReadPersistedFidEntry_returnsDefault() {
assertThat(persistedFid0.readPersistedFidEntryValue()).isEqualTo(DEFAULT_PERSISTED_FID_ENTRY);
assertThat(persistedFid1.readPersistedFidEntryValue()).isEqualTo(DEFAULT_PERSISTED_FID_ENTRY);
}

@Test
Expand Down
Loading