Skip to content

FIS getAuthToken implementation. #769

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

Merged
merged 31 commits into from
Sep 16, 2019
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c54292e
FIS getAuthToken implementation.
ankitaj224 Sep 5, 2019
b4b6ba8
FIS getAuthToken implementation.
ankitaj224 Sep 5, 2019
b8bfc1a
Merge branch 'fis_auth' of github.com:firebase/firebase-android-sdk i…
ankitaj224 Sep 5, 2019
7a2a112
Merge branch 'fis_auth' of github.com:firebase/firebase-android-sdk i…
ankitaj224 Sep 5, 2019
42c20f6
Merge branch 'fis_auth' of github.com:firebase/firebase-android-sdk i…
ankitaj224 Sep 5, 2019
46d936c
Merge branch 'fis_sdk' of github.com:firebase/firebase-android-sdk in…
ankitaj224 Sep 5, 2019
48fd7fe
Merge branch 'fis_sdk' of github.com:firebase/firebase-android-sdk in…
ankitaj224 Sep 5, 2019
82fb69e
1. Addressing Ciaran's comments
ankitaj224 Sep 6, 2019
fe04e15
1. Addressing Ciaran's comments
ankitaj224 Sep 6, 2019
e91cb7e
Merge branch 'fis_auth' of github.com:firebase/firebase-android-sdk i…
ankitaj224 Sep 6, 2019
8569952
Merge branch 'fis_auth' of github.com:firebase/firebase-android-sdk i…
ankitaj224 Sep 6, 2019
b74b163
Merge branch 'fis_auth' of github.com:firebase/firebase-android-sdk i…
ankitaj224 Sep 6, 2019
58a30e3
Updated IntDef usage in firebase-installations
ankitaj224 Sep 6, 2019
96e30c2
Using CountDownLatch to await instead of executor.awaitTermination
ankitaj224 Sep 7, 2019
9e3e34d
Addressing Di's comments.
ankitaj224 Sep 10, 2019
824cb63
Addressing Di's comments.
ankitaj224 Sep 10, 2019
90673c3
Merge branch 'fis_auth' of github.com:firebase/firebase-android-sdk i…
ankitaj224 Sep 10, 2019
f5b4f8c
Addressing Ciaran's comments to replace latch with a custom listener.
ankitaj224 Sep 10, 2019
3e29941
Adding onSuccess to AwaitListener.
ankitaj224 Sep 10, 2019
75f2581
Cleaning up the code as per the ciaran's comments.
ankitaj224 Sep 11, 2019
91e49bc
Addressing Di's comments.
ankitaj224 Sep 11, 2019
4578880
1. Handling multiple calls to getAUthToken()
ankitaj224 Sep 13, 2019
7d19b50
Fixing api-information presubmit check.
ankitaj224 Sep 13, 2019
fe04884
Merge branch 'fis_sdk' of github.com:firebase/firebase-android-sdk in…
ankitaj224 Sep 13, 2019
f1d1d37
Merge branch 'fis_sdk' of github.com:firebase/firebase-android-sdk in…
ankitaj224 Sep 13, 2019
ec65040
updating api.txt for firbase-installations-interop
ankitaj224 Sep 13, 2019
396d273
Merge branch 'fis_sdk' of github.com:firebase/firebase-android-sdk in…
ankitaj224 Sep 13, 2019
81b4aeb
Addressing Ciaran's comments.
ankitaj224 Sep 13, 2019
3932d3b
Fixing check-changed - GoogleJavaFormat error.
ankitaj224 Sep 16, 2019
8d4d811
Addressing ciaran`s comments
ankitaj224 Sep 16, 2019
3f44b77
nit fixes to executor : use unblocking queue.
ankitaj224 Sep 16, 2019
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
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@

package com.google.firebase.installations;

import static java.lang.annotation.RetentionPolicy.SOURCE;

import androidx.annotation.IntDef;
import com.google.android.gms.tasks.Task;
import java.lang.annotation.Retention;

/**
* This is an interface of {@code FirebaseInstallations} that is only exposed to 2p via component
Expand All @@ -24,14 +28,29 @@
*/
public interface FirebaseInstallationsApi {

/** Specifies the options to get a FIS AuthToken. */
@IntDef({DO_NOT_FORCE_REFRESH, FORCE_REFRESH})
@Retention(SOURCE)
@interface AuthTokenOption {}
/**
* AuthToken is not refreshed until requested by the developer or if one doesn't exist, is expired
* or about to expire.
*/
int DO_NOT_FORCE_REFRESH = 0;
/**
* AuthToken is forcefully refreshed on calling the {@link
* FirebaseInstallationsApi#getAuthToken(int)}.
*/
int FORCE_REFRESH = 1;

/**
* Async function that returns a globally unique identifier of this Firebase app installation.
* This is a url-safe base64 string of a 128-bit integer.
*/
Task<String> getId();

/** Async function that returns a auth token(public key) of this Firebase app installation. */
Task<InstallationTokenResult> getAuthToken(boolean forceRefresh);
Task<InstallationTokenResult> getAuthToken(@AuthTokenOption int authTokenOption);

/**
* Async function that deletes this Firebase app installation from Firebase backend. This call
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@ public abstract class InstallationTokenResult {
@NonNull
public abstract String getToken();
/**
* The amount of time, in milliseconds, before the auth-token expires for this Firebase
* Installation.
* The amount of time, in seconds, before the auth-token expires for this Firebase Installation.
*/
@NonNull
public abstract long getTokenExpirationTimestampMillis();
public abstract long getTokenExpirationInSecs();

@NonNull
public abstract Builder toBuilder();
Expand All @@ -46,7 +45,7 @@ public abstract static class Builder {
public abstract Builder setToken(@NonNull String value);

@NonNull
public abstract Builder setTokenExpirationTimestampMillis(@NonNull long value);
public abstract Builder setTokenExpirationInSecs(@NonNull long value);

@NonNull
public abstract InstallationTokenResult build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_APP_ID_1;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_AUTH_TOKEN;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_AUTH_TOKEN_2;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_CREATION_TIMESTAMP_1;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_CREATION_TIMESTAMP_2;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_FID_1;
import static com.google.firebase.installations.FisAndroidTestConstants.TEST_PROJECT_ID;
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.FisAndroidTestConstants.TEST_TOKEN_EXPIRATION_TIMESTAMP_2;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
Expand Down Expand Up @@ -68,6 +71,37 @@ public class FirebaseInstallationsInstrumentedTest {
@Mock private PersistedFid persistedFidReturnsError;
@Mock private Utils mockUtils;
@Mock private Clock mockClock;
@Mock private PersistedFid mockPersistedFid;

private static final PersistedFidEntry REGISTERED_FID_ENTRY =
PersistedFidEntry.builder()
.setFirebaseInstallationId(TEST_FID_1)
.setAuthToken(TEST_AUTH_TOKEN)
.setRefreshToken(TEST_REFRESH_TOKEN)
.setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_2)
.setExpiresInSecs(TEST_TOKEN_EXPIRATION_TIMESTAMP)
.setRegistrationStatus(PersistedFid.RegistrationStatus.REGISTERED)
.build();

private static final PersistedFidEntry EXPIRED_AUTH_TOKEN_ENTRY =
PersistedFidEntry.builder()
.setFirebaseInstallationId(TEST_FID_1)
.setAuthToken(TEST_AUTH_TOKEN)
.setRefreshToken(TEST_REFRESH_TOKEN)
.setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_2)
.setExpiresInSecs(TEST_TOKEN_EXPIRATION_TIMESTAMP_2)
.setRegistrationStatus(PersistedFid.RegistrationStatus.REGISTERED)
.build();

private static final PersistedFidEntry UNREGISTERED_FID_ENTRY =
PersistedFidEntry.builder()
.setFirebaseInstallationId(TEST_FID_1)
.setAuthToken("")
.setRefreshToken("")
.setTokenCreationEpochInSecs(TEST_CREATION_TIMESTAMP_2)
.setExpiresInSecs(0)
.setRegistrationStatus(PersistedFid.RegistrationStatus.UNREGISTERED)
.build();

@Before
public void setUp() throws FirebaseInstallationServiceException {
Expand All @@ -92,9 +126,16 @@ public void setUp() throws FirebaseInstallationServiceException {
.setAuthToken(
InstallationTokenResult.builder()
.setToken(TEST_AUTH_TOKEN)
.setTokenExpirationTimestampMillis(TEST_TOKEN_EXPIRATION_TIMESTAMP)
.setTokenExpirationInSecs(TEST_TOKEN_EXPIRATION_TIMESTAMP)
.build())
.build());
when(backendClientReturnsOk.generateAuthToken(
anyString(), anyString(), anyString(), anyString()))
.thenReturn(
InstallationTokenResult.builder()
.setToken(TEST_AUTH_TOKEN_2)
.setTokenExpirationInSecs(TEST_TOKEN_EXPIRATION_TIMESTAMP)
.build());
when(backendClientReturnsError.createFirebaseInstallation(
anyString(), anyString(), anyString(), anyString()))
.thenThrow(
Expand Down Expand Up @@ -217,4 +258,126 @@ public void testGetId_PersistedFidError_BackendOk() throws InterruptedException
.isEqualTo(FirebaseInstallationsException.Status.CLIENT_ERROR);
}
}

@Test
public void testGetAuthToken_fidDoesNotExist_successful() throws Exception {
FirebaseInstallations firebaseInstallations =
new FirebaseInstallations(
mockClock, executor, firebaseApp, backendClientReturnsOk, persistedFid, mockUtils);

Tasks.await(firebaseInstallations.getAuthToken(FirebaseInstallationsApi.DO_NOT_FORCE_REFRESH));

PersistedFidEntry entryValue = persistedFid.readPersistedFidEntryValue();
assertWithMessage("Persisted Auth Token doesn't match")
.that(entryValue.getAuthToken())
.isEqualTo(TEST_AUTH_TOKEN);
}

@Test
public void testGetAuthToken_PersistedFidError_failure() throws Exception {
FirebaseInstallations firebaseInstallations =
new FirebaseInstallations(
mockClock,
executor,
firebaseApp,
backendClientReturnsOk,
persistedFidReturnsError,
mockUtils);

// Expect exception
try {
Tasks.await(
firebaseInstallations.getAuthToken(FirebaseInstallationsApi.DO_NOT_FORCE_REFRESH));
fail();
} catch (ExecutionException expected) {
Throwable cause = expected.getCause();
assertWithMessage("Exception class doesn't match")
.that(cause)
.isInstanceOf(FirebaseInstallationsException.class);
Copy link
Contributor

Choose a reason for hiding this comment

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

Truth has built-in support for unpacking exceptions

assertWithMessage("w/e").that(expected).hasCauseThat().isInstanceOf(FirebaseInstallationsException.class)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Did you also want the status to be changed? I tried but dint find a easy way.

Copy link
Contributor

Choose a reason for hiding this comment

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

You'd have to create a custom truth subject for that and tbh I don't think it's worth it atm

assertWithMessage("Exception status doesn't match")
.that(((FirebaseInstallationsException) cause).getStatus())
.isEqualTo(FirebaseInstallationsException.Status.SDK_INTERNAL_ERROR);
}
}

@Test
public void testGetAuthToken_fidExists_successful() throws Exception {
when(mockPersistedFid.readPersistedFidEntryValue()).thenReturn(REGISTERED_FID_ENTRY);
FirebaseInstallations firebaseInstallations =
new FirebaseInstallations(
mockClock, executor, firebaseApp, backendClientReturnsOk, mockPersistedFid, mockUtils);

InstallationTokenResult installationTokenResult =
Tasks.await(
firebaseInstallations.getAuthToken(FirebaseInstallationsApi.DO_NOT_FORCE_REFRESH));

assertWithMessage("Persisted Auth Token doesn't match")
.that(installationTokenResult.getToken())
.isEqualTo(TEST_AUTH_TOKEN);
}

@Test
public void testGetAuthToken_expiredAuthToken_fetchedNewTokenFromFIS() throws Exception {
when(mockPersistedFid.readPersistedFidEntryValue()).thenReturn(EXPIRED_AUTH_TOKEN_ENTRY);
FirebaseInstallations firebaseInstallations =
new FirebaseInstallations(
mockClock, executor, firebaseApp, backendClientReturnsOk, mockPersistedFid, mockUtils);

InstallationTokenResult installationTokenResult =
Tasks.await(
firebaseInstallations.getAuthToken(FirebaseInstallationsApi.DO_NOT_FORCE_REFRESH));

assertWithMessage("Persisted Auth Token doesn't match")
.that(installationTokenResult.getToken())
.isEqualTo(TEST_AUTH_TOKEN_2);
}

@Test
public void testGetAuthToken_unregisteredFid_fetchedNewTokenFromFIS() throws Exception {
when(mockPersistedFid.readPersistedFidEntryValue())
Copy link
Contributor

Choose a reason for hiding this comment

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

imo this test could do with some comments explaining what you're testing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. PTAL.

.thenReturn(UNREGISTERED_FID_ENTRY, REGISTERED_FID_ENTRY);
FirebaseInstallations firebaseInstallations =
new FirebaseInstallations(
mockClock, executor, firebaseApp, backendClientReturnsOk, mockPersistedFid, mockUtils);

InstallationTokenResult installationTokenResult =
Tasks.await(
firebaseInstallations.getAuthToken(FirebaseInstallationsApi.DO_NOT_FORCE_REFRESH));

assertWithMessage("Persisted Auth Token doesn't match")
.that(installationTokenResult.getToken())
.isEqualTo(TEST_AUTH_TOKEN);
}

@Test
public void testGetAuthToken_serverError_failure() throws Exception {
when(mockPersistedFid.readPersistedFidEntryValue()).thenReturn(REGISTERED_FID_ENTRY);
when(backendClientReturnsError.generateAuthToken(
anyString(), anyString(), anyString(), anyString()))
.thenThrow(
new FirebaseInstallationServiceException(
"Server Error", FirebaseInstallationServiceException.Status.SERVER_ERROR));
FirebaseInstallations firebaseInstallations =
new FirebaseInstallations(
mockClock,
executor,
firebaseApp,
backendClientReturnsError,
mockPersistedFid,
mockUtils);

// Expect exception
try {
Tasks.await(firebaseInstallations.getAuthToken(FirebaseInstallationsApi.FORCE_REFRESH));
fail();
} catch (ExecutionException expected) {
Throwable cause = expected.getCause();
assertWithMessage("Exception class doesn't match")
.that(cause)
.isInstanceOf(FirebaseInstallationsException.class);
assertWithMessage("Exception status doesn't match")
.that(((FirebaseInstallationsException) cause).getStatus())
.isEqualTo(FirebaseInstallationsException.Status.SDK_INTERNAL_ERROR);
Copy link
Contributor

Choose a reason for hiding this comment

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

Truth

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ public final class FisAndroidTestConstants {
public static final String TEST_PROJECT_ID = "777777777777";

public static final String TEST_AUTH_TOKEN = "fis.auth.token";
public static final String TEST_AUTH_TOKEN_2 = "fis.auth.token2";

public static final String TEST_REFRESH_TOKEN = "1:test-refresh-token";

public static final String TEST_APP_ID_1 = "1:123456789:android:abcdef";
public static final String TEST_APP_ID_2 = "1:987654321:android:abcdef";

public static final long TEST_TOKEN_EXPIRATION_TIMESTAMP = 1000L;
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;
Expand Down
Loading