From 808659f66ff4ec7158ffb212021292276c3efc0e Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Thu, 12 Jul 2018 18:29:08 -0700 Subject: [PATCH 01/15] Enable firestore sdk to talk to emulator --- packages/firestore/src/api/credentials.ts | 13 +++++++++-- packages/testing/index.ts | 1 + packages/testing/src/api/index.ts | 27 +++++++++++++++++++++++ packages/testing/test/database.test.ts | 26 ++++++++++++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/packages/firestore/src/api/credentials.ts b/packages/firestore/src/api/credentials.ts index a808ad5a273..02d342050fd 100644 --- a/packages/firestore/src/api/credentials.ts +++ b/packages/firestore/src/api/credentials.ts @@ -18,7 +18,7 @@ import { User } from '../auth/user'; import { assert, fail } from '../util/assert'; import { Code, FirestoreError } from '../util/error'; import { FirebaseApp } from '@firebase/app-types'; -import { _FirebaseApp } from '@firebase/app-types/private'; +import { _FirebaseApp, FirebaseAuthTokenData } from '@firebase/app-types/private'; // TODO(mikelehen): This should be split into multiple files and probably // moved to an auth/ folder to match other platforms. @@ -145,6 +145,8 @@ export class FirebaseCredentialsProvider implements CredentialsProvider { private forceRefresh = false; + private tokenOverride: string = null; + constructor(private readonly app: FirebaseApp) { // We listen for token changes but all we really care about is knowing when // the uid may have changed. @@ -160,6 +162,7 @@ export class FirebaseCredentialsProvider implements CredentialsProvider { }; this.userCounter = 0; + this.tokenOverride = app.options.tokenOverride; // Will fire at least once where we set this.currentUser (this.app as _FirebaseApp).INTERNAL.addAuthTokenListener( @@ -179,7 +182,13 @@ export class FirebaseCredentialsProvider implements CredentialsProvider { const initialUserCounter = this.userCounter; const forceRefresh = this.forceRefresh; this.forceRefresh = false; - return (this.app as _FirebaseApp).INTERNAL.getToken(forceRefresh).then( + var token: Promise; + if (this.tokenOverride != null) { + token = Promise.resolve({ accessToken: this.tokenOverride }); + } else { + token = (this.app as _FirebaseApp).INTERNAL.getToken(forceRefresh); + } + return token.then( tokenData => { // Cancel the request since the user changed while the request was // outstanding so the response is likely for a previous user (which diff --git a/packages/testing/index.ts b/packages/testing/index.ts index 771308161a0..f6f624b4888 100644 --- a/packages/testing/index.ts +++ b/packages/testing/index.ts @@ -26,5 +26,6 @@ export { assertSucceeds, initializeAdminApp, initializeTestApp, + initializeFirestoreTestApp, loadDatabaseRules } from './src/api'; diff --git a/packages/testing/src/api/index.ts b/packages/testing/src/api/index.ts index 9239ba34bfc..d7372c98fbc 100644 --- a/packages/testing/src/api/index.ts +++ b/packages/testing/src/api/index.ts @@ -14,9 +14,12 @@ * limitations under the License. */ +import { firebase } from '@firebase/app'; import * as admin from 'firebase-admin'; import request from 'request-promise'; import * as fs from 'fs'; +import { FirebaseApp } from '@firebase/app-types'; +import * as util from '@firebase/util'; const DBURL = 'http://localhost:9000'; @@ -64,6 +67,30 @@ export function initializeTestApp(options: any): admin.app.App { ); } +export function initializeFirestoreTestApp(options: any): FirebaseApp { + if (!('projectId' in options)) { + throw new Error('projectId not specified'); + } + if (typeof options.auth != 'object') { + throw new Error('auth must be an object'); + } + var header = { + alg: "RS256", + kid: "fakekid" + }; + var fakeToken = [ + util.base64.encodeString(JSON.stringify(header),/*webSafe=*/true), + util.base64.encodeString(JSON.stringify(options.auth),/*webSafe=*/true), + "fakesignature" + ].join("."); + return firebase.initializeApp({ + projectId: options.projectId, + tokenOverride: fakeToken + }, + 'app-' + new Date().getTime() + "-" + Math.random() + ); +} + export type LoadDatabaseRulesOptions = { databaseName: String; rules: String; diff --git a/packages/testing/test/database.test.ts b/packages/testing/test/database.test.ts index 9e7f6bb9f76..0d5bea33e4f 100644 --- a/packages/testing/test/database.test.ts +++ b/packages/testing/test/database.test.ts @@ -84,6 +84,32 @@ describe('Testing Module Tests', function() { ); }); + it('initializeFirestoreTestApp() throws if no projectId', function() { + expect(firebase.initializeFirestoreTestApp.bind(null, { auth: {} })).to.throw( + /projectId not specified/ + ); + expect( + firebase.initializeFirestoreTestApp.bind(null, { projectId: 'foo', auth: {} }) + ).to.not.throw(); + }); + + it('initializeFirestoreTestApp() throws if auth is not an object', function() { + expect(firebase.initializeFirestoreTestApp.bind(null, { projectId: 'a', auth: 'b' })).to.throw( + /auth must be an object/ + ); + expect( + firebase.initializeFirestoreTestApp.bind(null, { projectId: 'a', auth: {} }) + ).to.not.throw(); + }); + + it('initializeFirestoreTestApp() uses specified auth.', function() { + let app = firebase.initializeFirestoreTestApp({ projectId: 'foo', auth: {} }); + expect(app.options).to.have.any.keys('tokenOverride'); + + app = firebase.initializeFirestoreTestApp({ projectId: 'foo', auth: { uid: 'alice' }}); + expect(app.options).to.have.any.keys('tokenOverride'); + }); + it('loadDatabaseRules() throws if no databaseName or rulesPath', async function() { expect(firebase.loadDatabaseRules.bind(null, {})).to.throw( /databaseName not specified/ From b7d185b4f01922346b8ba166f7e7c5c99fedf046 Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Thu, 12 Jul 2018 18:29:27 -0700 Subject: [PATCH 02/15] [AUTOMATED]: Prettier Code Styling --- packages/firestore/src/api/credentials.ts | 41 ++++++++++++----------- packages/testing/src/api/index.ts | 17 +++++----- packages/testing/test/database.test.ts | 35 +++++++++++++------ 3 files changed, 55 insertions(+), 38 deletions(-) diff --git a/packages/firestore/src/api/credentials.ts b/packages/firestore/src/api/credentials.ts index 02d342050fd..9c9be6f627b 100644 --- a/packages/firestore/src/api/credentials.ts +++ b/packages/firestore/src/api/credentials.ts @@ -18,7 +18,10 @@ import { User } from '../auth/user'; import { assert, fail } from '../util/assert'; import { Code, FirestoreError } from '../util/error'; import { FirebaseApp } from '@firebase/app-types'; -import { _FirebaseApp, FirebaseAuthTokenData } from '@firebase/app-types/private'; +import { + _FirebaseApp, + FirebaseAuthTokenData +} from '@firebase/app-types/private'; // TODO(mikelehen): This should be split into multiple files and probably // moved to an auth/ folder to match other platforms. @@ -188,29 +191,27 @@ export class FirebaseCredentialsProvider implements CredentialsProvider { } else { token = (this.app as _FirebaseApp).INTERNAL.getToken(forceRefresh); } - return token.then( - tokenData => { - // Cancel the request since the user changed while the request was - // outstanding so the response is likely for a previous user (which - // user, we can't be sure). - if (this.userCounter !== initialUserCounter) { - throw new FirestoreError( - Code.ABORTED, - 'getToken aborted due to uid change.' + return token.then(tokenData => { + // Cancel the request since the user changed while the request was + // outstanding so the response is likely for a previous user (which + // user, we can't be sure). + if (this.userCounter !== initialUserCounter) { + throw new FirestoreError( + Code.ABORTED, + 'getToken aborted due to uid change.' + ); + } else { + if (tokenData) { + assert( + typeof tokenData.accessToken === 'string', + 'Invalid tokenData returned from getToken():' + tokenData ); + return new OAuthToken(tokenData.accessToken, this.currentUser); } else { - if (tokenData) { - assert( - typeof tokenData.accessToken === 'string', - 'Invalid tokenData returned from getToken():' + tokenData - ); - return new OAuthToken(tokenData.accessToken, this.currentUser); - } else { - return null; - } + return null; } } - ); + }); } invalidateToken(): void { diff --git a/packages/testing/src/api/index.ts b/packages/testing/src/api/index.ts index d7372c98fbc..ed9caaf91c5 100644 --- a/packages/testing/src/api/index.ts +++ b/packages/testing/src/api/index.ts @@ -75,19 +75,20 @@ export function initializeFirestoreTestApp(options: any): FirebaseApp { throw new Error('auth must be an object'); } var header = { - alg: "RS256", - kid: "fakekid" + alg: 'RS256', + kid: 'fakekid' }; var fakeToken = [ - util.base64.encodeString(JSON.stringify(header),/*webSafe=*/true), - util.base64.encodeString(JSON.stringify(options.auth),/*webSafe=*/true), - "fakesignature" - ].join("."); - return firebase.initializeApp({ + util.base64.encodeString(JSON.stringify(header), /*webSafe=*/ true), + util.base64.encodeString(JSON.stringify(options.auth), /*webSafe=*/ true), + 'fakesignature' + ].join('.'); + return firebase.initializeApp( + { projectId: options.projectId, tokenOverride: fakeToken }, - 'app-' + new Date().getTime() + "-" + Math.random() + 'app-' + new Date().getTime() + '-' + Math.random() ); } diff --git a/packages/testing/test/database.test.ts b/packages/testing/test/database.test.ts index 0d5bea33e4f..a93a82f107a 100644 --- a/packages/testing/test/database.test.ts +++ b/packages/testing/test/database.test.ts @@ -85,28 +85,43 @@ describe('Testing Module Tests', function() { }); it('initializeFirestoreTestApp() throws if no projectId', function() { - expect(firebase.initializeFirestoreTestApp.bind(null, { auth: {} })).to.throw( - /projectId not specified/ - ); expect( - firebase.initializeFirestoreTestApp.bind(null, { projectId: 'foo', auth: {} }) + firebase.initializeFirestoreTestApp.bind(null, { auth: {} }) + ).to.throw(/projectId not specified/); + expect( + firebase.initializeFirestoreTestApp.bind(null, { + projectId: 'foo', + auth: {} + }) ).to.not.throw(); }); it('initializeFirestoreTestApp() throws if auth is not an object', function() { - expect(firebase.initializeFirestoreTestApp.bind(null, { projectId: 'a', auth: 'b' })).to.throw( - /auth must be an object/ - ); expect( - firebase.initializeFirestoreTestApp.bind(null, { projectId: 'a', auth: {} }) + firebase.initializeFirestoreTestApp.bind(null, { + projectId: 'a', + auth: 'b' + }) + ).to.throw(/auth must be an object/); + expect( + firebase.initializeFirestoreTestApp.bind(null, { + projectId: 'a', + auth: {} + }) ).to.not.throw(); }); it('initializeFirestoreTestApp() uses specified auth.', function() { - let app = firebase.initializeFirestoreTestApp({ projectId: 'foo', auth: {} }); + let app = firebase.initializeFirestoreTestApp({ + projectId: 'foo', + auth: {} + }); expect(app.options).to.have.any.keys('tokenOverride'); - app = firebase.initializeFirestoreTestApp({ projectId: 'foo', auth: { uid: 'alice' }}); + app = firebase.initializeFirestoreTestApp({ + projectId: 'foo', + auth: { uid: 'alice' } + }); expect(app.options).to.have.any.keys('tokenOverride'); }); From 0c7999cb82be011e5c54d0ee48f35e62304df12e Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Fri, 13 Jul 2018 11:06:04 -0700 Subject: [PATCH 03/15] Revert firestore sdk changes --- packages/firestore/src/api/credentials.ts | 11 +---------- packages/testing/src/api/index.ts | 10 ++++++---- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/packages/firestore/src/api/credentials.ts b/packages/firestore/src/api/credentials.ts index 9c9be6f627b..c336d3455d0 100644 --- a/packages/firestore/src/api/credentials.ts +++ b/packages/firestore/src/api/credentials.ts @@ -148,8 +148,6 @@ export class FirebaseCredentialsProvider implements CredentialsProvider { private forceRefresh = false; - private tokenOverride: string = null; - constructor(private readonly app: FirebaseApp) { // We listen for token changes but all we really care about is knowing when // the uid may have changed. @@ -165,7 +163,6 @@ export class FirebaseCredentialsProvider implements CredentialsProvider { }; this.userCounter = 0; - this.tokenOverride = app.options.tokenOverride; // Will fire at least once where we set this.currentUser (this.app as _FirebaseApp).INTERNAL.addAuthTokenListener( @@ -185,13 +182,7 @@ export class FirebaseCredentialsProvider implements CredentialsProvider { const initialUserCounter = this.userCounter; const forceRefresh = this.forceRefresh; this.forceRefresh = false; - var token: Promise; - if (this.tokenOverride != null) { - token = Promise.resolve({ accessToken: this.tokenOverride }); - } else { - token = (this.app as _FirebaseApp).INTERNAL.getToken(forceRefresh); - } - return token.then(tokenData => { + return (this.app as _FirebaseApp).INTERNAL.getToken(forceRefresh).then(tokenData => { // Cancel the request since the user changed while the request was // outstanding so the response is likely for a previous user (which // user, we can't be sure). diff --git a/packages/testing/src/api/index.ts b/packages/testing/src/api/index.ts index ed9caaf91c5..0bd83b505e4 100644 --- a/packages/testing/src/api/index.ts +++ b/packages/testing/src/api/index.ts @@ -19,7 +19,7 @@ import * as admin from 'firebase-admin'; import request from 'request-promise'; import * as fs from 'fs'; import { FirebaseApp } from '@firebase/app-types'; -import * as util from '@firebase/util'; +import { base64 } from '@firebase/util'; const DBURL = 'http://localhost:9000'; @@ -79,17 +79,19 @@ export function initializeFirestoreTestApp(options: any): FirebaseApp { kid: 'fakekid' }; var fakeToken = [ - util.base64.encodeString(JSON.stringify(header), /*webSafe=*/ true), - util.base64.encodeString(JSON.stringify(options.auth), /*webSafe=*/ true), + base64.encodeString(JSON.stringify(header), /*webSafe=*/ true), + base64.encodeString(JSON.stringify(options.auth), /*webSafe=*/ true), 'fakesignature' ].join('.'); - return firebase.initializeApp( + let app = firebase.initializeApp( { projectId: options.projectId, tokenOverride: fakeToken }, 'app-' + new Date().getTime() + '-' + Math.random() ); + (app as any).INTERNAL.getToken = () => Promise.resolve({ accessToken: fakeToken }); + return app; } export type LoadDatabaseRulesOptions = { From 254bf5433a80bb72ee7c467a7f390f570c305b7f Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Fri, 13 Jul 2018 11:06:23 -0700 Subject: [PATCH 04/15] [AUTOMATED]: Prettier Code Styling --- packages/firestore/src/api/credentials.ts | 36 ++++++++++++----------- packages/testing/src/api/index.ts | 3 +- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/packages/firestore/src/api/credentials.ts b/packages/firestore/src/api/credentials.ts index c336d3455d0..75884aa8138 100644 --- a/packages/firestore/src/api/credentials.ts +++ b/packages/firestore/src/api/credentials.ts @@ -182,27 +182,29 @@ export class FirebaseCredentialsProvider implements CredentialsProvider { const initialUserCounter = this.userCounter; const forceRefresh = this.forceRefresh; this.forceRefresh = false; - return (this.app as _FirebaseApp).INTERNAL.getToken(forceRefresh).then(tokenData => { - // Cancel the request since the user changed while the request was - // outstanding so the response is likely for a previous user (which - // user, we can't be sure). - if (this.userCounter !== initialUserCounter) { - throw new FirestoreError( - Code.ABORTED, - 'getToken aborted due to uid change.' - ); - } else { - if (tokenData) { - assert( - typeof tokenData.accessToken === 'string', - 'Invalid tokenData returned from getToken():' + tokenData + return (this.app as _FirebaseApp).INTERNAL.getToken(forceRefresh).then( + tokenData => { + // Cancel the request since the user changed while the request was + // outstanding so the response is likely for a previous user (which + // user, we can't be sure). + if (this.userCounter !== initialUserCounter) { + throw new FirestoreError( + Code.ABORTED, + 'getToken aborted due to uid change.' ); - return new OAuthToken(tokenData.accessToken, this.currentUser); } else { - return null; + if (tokenData) { + assert( + typeof tokenData.accessToken === 'string', + 'Invalid tokenData returned from getToken():' + tokenData + ); + return new OAuthToken(tokenData.accessToken, this.currentUser); + } else { + return null; + } } } - }); + ); } invalidateToken(): void { diff --git a/packages/testing/src/api/index.ts b/packages/testing/src/api/index.ts index 0bd83b505e4..2f85276b720 100644 --- a/packages/testing/src/api/index.ts +++ b/packages/testing/src/api/index.ts @@ -90,7 +90,8 @@ export function initializeFirestoreTestApp(options: any): FirebaseApp { }, 'app-' + new Date().getTime() + '-' + Math.random() ); - (app as any).INTERNAL.getToken = () => Promise.resolve({ accessToken: fakeToken }); + (app as any).INTERNAL.getToken = () => + Promise.resolve({ accessToken: fakeToken }); return app; } From e7a155e6051837fb95140dfcc75e496a55b07a7e Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Fri, 13 Jul 2018 11:08:38 -0700 Subject: [PATCH 05/15] Revert credentials.ts --- packages/firestore/src/api/credentials.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/firestore/src/api/credentials.ts b/packages/firestore/src/api/credentials.ts index 75884aa8138..a808ad5a273 100644 --- a/packages/firestore/src/api/credentials.ts +++ b/packages/firestore/src/api/credentials.ts @@ -18,10 +18,7 @@ import { User } from '../auth/user'; import { assert, fail } from '../util/assert'; import { Code, FirestoreError } from '../util/error'; import { FirebaseApp } from '@firebase/app-types'; -import { - _FirebaseApp, - FirebaseAuthTokenData -} from '@firebase/app-types/private'; +import { _FirebaseApp } from '@firebase/app-types/private'; // TODO(mikelehen): This should be split into multiple files and probably // moved to an auth/ folder to match other platforms. From 3b03a9c346f0af1aad51b8e60742f255f57d7b2c Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Fri, 13 Jul 2018 12:01:59 -0700 Subject: [PATCH 06/15] Cleanup --- packages/testing/src/api/index.ts | 37 +++++++------- packages/testing/test/database.test.ts | 69 ++++++++++---------------- 2 files changed, 46 insertions(+), 60 deletions(-) diff --git a/packages/testing/src/api/index.ts b/packages/testing/src/api/index.ts index 2f85276b720..cdea863a24e 100644 --- a/packages/testing/src/api/index.ts +++ b/packages/testing/src/api/index.ts @@ -39,6 +39,10 @@ export function apps(): (admin.app.App | null)[] { return admin.apps; } +export function firestoreApps(): (FirebaseApp | null)[] { + return firebase.apps; +} + export function initializeAdminApp(options: any): admin.app.App { if (!('databaseName' in options)) { throw new Error('databaseName not specified'); @@ -52,10 +56,11 @@ export function initializeAdminApp(options: any): admin.app.App { ); } -export function initializeTestApp(options: any): admin.app.App { - if (!('databaseName' in options)) { - throw new Error('databaseName not specified'); - } +export type TestAppOptions = { + databaseName: string; + auth: Object; +}; +export function initializeTestApp(options: TestAppOptions): admin.app.App { // if options.auth is not present, we will construct an app with auth == null return admin.initializeApp( { @@ -67,29 +72,25 @@ export function initializeTestApp(options: any): admin.app.App { ); } -export function initializeFirestoreTestApp(options: any): FirebaseApp { - if (!('projectId' in options)) { - throw new Error('projectId not specified'); - } - if (typeof options.auth != 'object') { - throw new Error('auth must be an object'); - } - var header = { +export type FirestoreTestAppOptions = { + projectId: string; + auth: Object; +}; +export function initializeFirestoreTestApp(options: FirestoreTestAppOptions): FirebaseApp { + const header = { alg: 'RS256', kid: 'fakekid' }; - var fakeToken = [ + const fakeToken = [ base64.encodeString(JSON.stringify(header), /*webSafe=*/ true), base64.encodeString(JSON.stringify(options.auth), /*webSafe=*/ true), 'fakesignature' ].join('.'); - let app = firebase.initializeApp( - { - projectId: options.projectId, - tokenOverride: fakeToken - }, + const app = firebase.initializeApp( + { projectId: options.projectId }, 'app-' + new Date().getTime() + '-' + Math.random() ); + // hijacking INTERNAL.getToken to bypass FirebaseAuth and allows specifying of auth headers (app as any).INTERNAL.getToken = () => Promise.resolve({ accessToken: fakeToken }); return app; diff --git a/packages/testing/test/database.test.ts b/packages/testing/test/database.test.ts index a93a82f107a..468712af35f 100644 --- a/packages/testing/test/database.test.ts +++ b/packages/testing/test/database.test.ts @@ -16,6 +16,7 @@ import { expect } from 'chai'; import * as firebase from '../src/api'; +import { base64 } from '@firebase/util'; describe('Testing Module Tests', function() { it('assertSucceeds() iff success', async function() { @@ -60,17 +61,8 @@ describe('Testing Module Tests', function() { expect(app.options).to.not.have.any.keys('databaseAuthVariableOverride'); }); - it('initializeTestApp() throws if no databaseName', function() { - expect(firebase.initializeTestApp.bind(null, {})).to.throw( - /databaseName not specified/ - ); - expect( - firebase.initializeTestApp.bind(null, { databaseName: 'foo' }) - ).to.not.throw(); - }); - it('initializeTestApp() uses specified auth.', function() { - let app = firebase.initializeTestApp({ databaseName: 'foo' }); + let app = firebase.initializeTestApp({ databaseName: 'foo', auth: {} }); expect(app.options).to.have.any.keys('databaseAuthVariableOverride'); app = firebase.initializeTestApp({ @@ -84,45 +76,24 @@ describe('Testing Module Tests', function() { ); }); - it('initializeFirestoreTestApp() throws if no projectId', function() { - expect( - firebase.initializeFirestoreTestApp.bind(null, { auth: {} }) - ).to.throw(/projectId not specified/); - expect( - firebase.initializeFirestoreTestApp.bind(null, { - projectId: 'foo', - auth: {} - }) - ).to.not.throw(); - }); - - it('initializeFirestoreTestApp() throws if auth is not an object', function() { - expect( - firebase.initializeFirestoreTestApp.bind(null, { - projectId: 'a', - auth: 'b' - }) - ).to.throw(/auth must be an object/); - expect( - firebase.initializeFirestoreTestApp.bind(null, { - projectId: 'a', - auth: {} - }) - ).to.not.throw(); - }); - - it('initializeFirestoreTestApp() uses specified auth.', function() { + it('initializeFirestoreTestApp() uses specified auth.', async function() { let app = firebase.initializeFirestoreTestApp({ projectId: 'foo', auth: {} }); - expect(app.options).to.have.any.keys('tokenOverride'); + let token = await (app as any).INTERNAL.getToken(); + expect(token).to.have.any.keys('accessToken'); + let claims = base64.decodeString(token.accessToken.split('.')[3],/*webSafe=*/true); + expect(claims).to.equal('{}'); app = firebase.initializeFirestoreTestApp({ projectId: 'foo', auth: { uid: 'alice' } }); - expect(app.options).to.have.any.keys('tokenOverride'); + token = await (app as any).INTERNAL.getToken() + expect(token).to.have.any.keys('accessToken'); + claims = base64.decodeString(token.accessToken.split('.')[3],/*webSafe=*/true); + expect(claims).to.equal('{"uid":"alice"}'); }); it('loadDatabaseRules() throws if no databaseName or rulesPath', async function() { @@ -149,13 +120,27 @@ describe('Testing Module Tests', function() { ).to.throw(/Could not find file/); }); - it('apps() returns all created apps', async function() { + it('apps() returns all apps created except by initializeFirestoreTestApp', async function() { const numApps = firebase.apps().length; await firebase.initializeAdminApp({ databaseName: 'foo' }); expect(firebase.apps().length).to.equal(numApps + 1); await firebase.initializeAdminApp({ databaseName: 'foo' }); expect(firebase.apps().length).to.equal(numApps + 2); - await firebase.initializeTestApp({ databaseName: 'foo' }); + await firebase.initializeTestApp({ databaseName: 'foo', auth: {} }); + expect(firebase.apps().length).to.equal(numApps + 3); + await firebase.initializeFirestoreTestApp({ projectId: 'foo', auth: {} }); expect(firebase.apps().length).to.equal(numApps + 3); }); + + it('firestoreApps() returns only apps created with initializeFirestoreTestApp', async function() { + const numApps = firebase.firestoreApps().length; + await firebase.initializeAdminApp({ databaseName: 'foo' }); + expect(firebase.firestoreApps().length).to.equal(numApps + 0); + await firebase.initializeAdminApp({ databaseName: 'foo' }); + expect(firebase.firestoreApps().length).to.equal(numApps + 0); + await firebase.initializeTestApp({ databaseName: 'foo', auth: {} }); + expect(firebase.firestoreApps().length).to.equal(numApps + 0); + await firebase.initializeFirestoreTestApp({ projectId: 'foo', auth: {} }); + expect(firebase.firestoreApps().length).to.equal(numApps + 1); + }); }); From d8865f7ab4016a551a44bafc580d091d919c1a75 Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Fri, 13 Jul 2018 12:02:18 -0700 Subject: [PATCH 07/15] [AUTOMATED]: Prettier Code Styling --- packages/testing/src/api/index.ts | 4 +++- packages/testing/test/database.test.ts | 12 +++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/testing/src/api/index.ts b/packages/testing/src/api/index.ts index cdea863a24e..8c2417f3993 100644 --- a/packages/testing/src/api/index.ts +++ b/packages/testing/src/api/index.ts @@ -76,7 +76,9 @@ export type FirestoreTestAppOptions = { projectId: string; auth: Object; }; -export function initializeFirestoreTestApp(options: FirestoreTestAppOptions): FirebaseApp { +export function initializeFirestoreTestApp( + options: FirestoreTestAppOptions +): FirebaseApp { const header = { alg: 'RS256', kid: 'fakekid' diff --git a/packages/testing/test/database.test.ts b/packages/testing/test/database.test.ts index 468712af35f..1eb77c5ce03 100644 --- a/packages/testing/test/database.test.ts +++ b/packages/testing/test/database.test.ts @@ -83,16 +83,22 @@ describe('Testing Module Tests', function() { }); let token = await (app as any).INTERNAL.getToken(); expect(token).to.have.any.keys('accessToken'); - let claims = base64.decodeString(token.accessToken.split('.')[3],/*webSafe=*/true); + let claims = base64.decodeString( + token.accessToken.split('.')[3], + /*webSafe=*/ true + ); expect(claims).to.equal('{}'); app = firebase.initializeFirestoreTestApp({ projectId: 'foo', auth: { uid: 'alice' } }); - token = await (app as any).INTERNAL.getToken() + token = await (app as any).INTERNAL.getToken(); expect(token).to.have.any.keys('accessToken'); - claims = base64.decodeString(token.accessToken.split('.')[3],/*webSafe=*/true); + claims = base64.decodeString( + token.accessToken.split('.')[3], + /*webSafe=*/ true + ); expect(claims).to.equal('{"uid":"alice"}'); }); From 92977e833f914fbeec0330c8ae0dd4ed28466ee7 Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Fri, 13 Jul 2018 12:26:52 -0700 Subject: [PATCH 08/15] Set webSafe=false --- packages/testing/src/api/index.ts | 4 ++-- packages/testing/test/database.test.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/testing/src/api/index.ts b/packages/testing/src/api/index.ts index 8c2417f3993..0a5a7dc05b0 100644 --- a/packages/testing/src/api/index.ts +++ b/packages/testing/src/api/index.ts @@ -84,8 +84,8 @@ export function initializeFirestoreTestApp( kid: 'fakekid' }; const fakeToken = [ - base64.encodeString(JSON.stringify(header), /*webSafe=*/ true), - base64.encodeString(JSON.stringify(options.auth), /*webSafe=*/ true), + base64.encodeString(JSON.stringify(header), /*webSafe=*/ false), + base64.encodeString(JSON.stringify(options.auth), /*webSafe=*/ false), 'fakesignature' ].join('.'); const app = firebase.initializeApp( diff --git a/packages/testing/test/database.test.ts b/packages/testing/test/database.test.ts index 1eb77c5ce03..e1c2b529eea 100644 --- a/packages/testing/test/database.test.ts +++ b/packages/testing/test/database.test.ts @@ -84,8 +84,8 @@ describe('Testing Module Tests', function() { let token = await (app as any).INTERNAL.getToken(); expect(token).to.have.any.keys('accessToken'); let claims = base64.decodeString( - token.accessToken.split('.')[3], - /*webSafe=*/ true + token.accessToken.split('.')[1], + /*webSafe=*/ false ); expect(claims).to.equal('{}'); @@ -96,8 +96,8 @@ describe('Testing Module Tests', function() { token = await (app as any).INTERNAL.getToken(); expect(token).to.have.any.keys('accessToken'); claims = base64.decodeString( - token.accessToken.split('.')[3], - /*webSafe=*/ true + token.accessToken.split('.')[1], + /*webSafe=*/ false ); expect(claims).to.equal('{"uid":"alice"}'); }); From 3a2ff76d3bd8cc1f772c3fb62c70eceb86d30b70 Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Fri, 13 Jul 2018 15:26:46 -0700 Subject: [PATCH 09/15] Combine initializeTestApp and initializeFirestoreTestApp --- packages/testing/src/api/index.ts | 60 +++++++++++------------- packages/testing/test/database.test.ts | 64 +++++++++++++------------- 2 files changed, 59 insertions(+), 65 deletions(-) diff --git a/packages/testing/src/api/index.ts b/packages/testing/src/api/index.ts index 0a5a7dc05b0..abcbd484f65 100644 --- a/packages/testing/src/api/index.ts +++ b/packages/testing/src/api/index.ts @@ -18,7 +18,7 @@ import { firebase } from '@firebase/app'; import * as admin from 'firebase-admin'; import request from 'request-promise'; import * as fs from 'fs'; -import { FirebaseApp } from '@firebase/app-types'; +import { FirebaseApp, FirebaseOptions } from '@firebase/app-types'; import { base64 } from '@firebase/util'; const DBURL = 'http://localhost:9000'; @@ -35,50 +35,48 @@ class FakeCredentials { } } -export function apps(): (admin.app.App | null)[] { +export function adminApps(): (admin.app.App | null)[] { return admin.apps; } -export function firestoreApps(): (FirebaseApp | null)[] { +export function apps(): (FirebaseApp | null)[] { return firebase.apps; } -export function initializeAdminApp(options: any): admin.app.App { - if (!('databaseName' in options)) { - throw new Error('databaseName not specified'); - } +type AdminAppOptions = { + databaseName: string; +} + +export function initializeAdminApp(options: AdminAppOptions): admin.app.App { + const appName = 'app-' + new Date().getTime() + '-' + Math.random(); return admin.initializeApp( { credential: new FakeCredentials(), databaseURL: DBURL + '?ns=' + options.databaseName }, - 'app-' + (new Date().getTime() + Math.random()) + appName ); } -export type TestAppOptions = { +export type DatabaseAppOptions = { databaseName: string; - auth: Object; -}; -export function initializeTestApp(options: TestAppOptions): admin.app.App { - // if options.auth is not present, we will construct an app with auth == null - return admin.initializeApp( - { - credential: new FakeCredentials(), - databaseURL: DBURL + '?ns=' + options.databaseName, - databaseAuthVariableOverride: options.auth || null - }, - 'app-' + (new Date().getTime() + Math.random()) - ); + auth: object; } - -export type FirestoreTestAppOptions = { +export type FirestoreAppOptions = { projectId: string; - auth: Object; -}; -export function initializeFirestoreTestApp( - options: FirestoreTestAppOptions -): FirebaseApp { + auth: object; +} +export function initializeTestApp(options: DatabaseAppOptions | FirestoreAppOptions): FirebaseApp { + let appOptions: FirebaseOptions; + if ('databaseName' in options) { + appOptions = { + databaseURL: DBURL + '?ns=' + options.databaseName + }; + } else if ('projectId' in options) { + appOptions = { + projectId: options.projectId + }; + } const header = { alg: 'RS256', kid: 'fakekid' @@ -88,10 +86,8 @@ export function initializeFirestoreTestApp( base64.encodeString(JSON.stringify(options.auth), /*webSafe=*/ false), 'fakesignature' ].join('.'); - const app = firebase.initializeApp( - { projectId: options.projectId }, - 'app-' + new Date().getTime() + '-' + Math.random() - ); + const appName = 'app-' + new Date().getTime() + '-' + Math.random(); + const app = firebase.initializeApp(appOptions, appName); // hijacking INTERNAL.getToken to bypass FirebaseAuth and allows specifying of auth headers (app as any).INTERNAL.getToken = () => Promise.resolve({ accessToken: fakeToken }); diff --git a/packages/testing/test/database.test.ts b/packages/testing/test/database.test.ts index e1c2b529eea..9f5495bf249 100644 --- a/packages/testing/test/database.test.ts +++ b/packages/testing/test/database.test.ts @@ -47,37 +47,39 @@ describe('Testing Module Tests', function() { }); }); - it('initializeAdminApp() throws if no databaseName', function() { - expect(firebase.initializeAdminApp.bind(null, {})).to.throw( - /databaseName not specified/ - ); - expect( - firebase.initializeAdminApp.bind(null, { databaseName: 'foo' }) - ).to.not.throw(); - }); - it('initializeAdminApp() provides admin', function() { const app = firebase.initializeAdminApp({ databaseName: 'foo' }); expect(app.options).to.not.have.any.keys('databaseAuthVariableOverride'); }); - it('initializeTestApp() uses specified auth.', function() { - let app = firebase.initializeTestApp({ databaseName: 'foo', auth: {} }); - expect(app.options).to.have.any.keys('databaseAuthVariableOverride'); + it('initializeTestApp() with DatabaseAppOptions uses specified auth.', async function() { + let app = firebase.initializeTestApp({ + projectId: 'foo', + auth: {} + }); + let token = await (app as any).INTERNAL.getToken(); + expect(token).to.have.any.keys('accessToken'); + let claims = base64.decodeString( + token.accessToken.split('.')[1], + /*webSafe=*/ false + ); + expect(claims).to.equal('{}'); app = firebase.initializeTestApp({ - databaseName: 'foo', + projectId: 'foo', auth: { uid: 'alice' } }); - expect(app.options).to.have.any.keys('databaseAuthVariableOverride'); - expect(app.options.databaseAuthVariableOverride).to.have.all.keys('uid'); - expect(app.options.databaseAuthVariableOverride['uid']).to.be.equal( - 'alice' + token = await (app as any).INTERNAL.getToken(); + expect(token).to.have.any.keys('accessToken'); + claims = base64.decodeString( + token.accessToken.split('.')[1], + /*webSafe=*/ false ); + expect(claims).to.equal('{"uid":"alice"}'); }); - it('initializeFirestoreTestApp() uses specified auth.', async function() { - let app = firebase.initializeFirestoreTestApp({ + it('initializeTestApp() with FirestoreAppOptions uses specified auth.', async function() { + let app = firebase.initializeTestApp({ projectId: 'foo', auth: {} }); @@ -89,7 +91,7 @@ describe('Testing Module Tests', function() { ); expect(claims).to.equal('{}'); - app = firebase.initializeFirestoreTestApp({ + app = firebase.initializeTestApp({ projectId: 'foo', auth: { uid: 'alice' } }); @@ -126,27 +128,23 @@ describe('Testing Module Tests', function() { ).to.throw(/Could not find file/); }); - it('apps() returns all apps created except by initializeFirestoreTestApp', async function() { + it('adminApps() returns only apps created with initializeAdminApp', async function() { const numApps = firebase.apps().length; await firebase.initializeAdminApp({ databaseName: 'foo' }); - expect(firebase.apps().length).to.equal(numApps + 1); + expect(firebase.adminApps().length).to.equal(numApps + 1); await firebase.initializeAdminApp({ databaseName: 'foo' }); - expect(firebase.apps().length).to.equal(numApps + 2); + expect(firebase.adminApps().length).to.equal(numApps + 2); await firebase.initializeTestApp({ databaseName: 'foo', auth: {} }); - expect(firebase.apps().length).to.equal(numApps + 3); - await firebase.initializeFirestoreTestApp({ projectId: 'foo', auth: {} }); - expect(firebase.apps().length).to.equal(numApps + 3); + expect(firebase.adminApps().length).to.equal(numApps + 2); }); - it('firestoreApps() returns only apps created with initializeFirestoreTestApp', async function() { - const numApps = firebase.firestoreApps().length; + it('apps() returns only apps created with initializeTestApp', async function() { + const numApps = firebase.apps().length; await firebase.initializeAdminApp({ databaseName: 'foo' }); - expect(firebase.firestoreApps().length).to.equal(numApps + 0); + expect(firebase.apps().length).to.equal(numApps + 0); await firebase.initializeAdminApp({ databaseName: 'foo' }); - expect(firebase.firestoreApps().length).to.equal(numApps + 0); + expect(firebase.apps().length).to.equal(numApps + 0); await firebase.initializeTestApp({ databaseName: 'foo', auth: {} }); - expect(firebase.firestoreApps().length).to.equal(numApps + 0); - await firebase.initializeFirestoreTestApp({ projectId: 'foo', auth: {} }); - expect(firebase.firestoreApps().length).to.equal(numApps + 1); + expect(firebase.apps().length).to.equal(numApps + 1); }); }); From 8452e3f9ba5825f72dab547642fc0debf50d7fcb Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Fri, 13 Jul 2018 15:28:04 -0700 Subject: [PATCH 10/15] [AUTOMATED]: Prettier Code Styling --- packages/testing/src/api/index.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/testing/src/api/index.ts b/packages/testing/src/api/index.ts index abcbd484f65..1ba60b9a16a 100644 --- a/packages/testing/src/api/index.ts +++ b/packages/testing/src/api/index.ts @@ -45,7 +45,7 @@ export function apps(): (FirebaseApp | null)[] { type AdminAppOptions = { databaseName: string; -} +}; export function initializeAdminApp(options: AdminAppOptions): admin.app.App { const appName = 'app-' + new Date().getTime() + '-' + Math.random(); @@ -61,12 +61,14 @@ export function initializeAdminApp(options: AdminAppOptions): admin.app.App { export type DatabaseAppOptions = { databaseName: string; auth: object; -} +}; export type FirestoreAppOptions = { projectId: string; auth: object; -} -export function initializeTestApp(options: DatabaseAppOptions | FirestoreAppOptions): FirebaseApp { +}; +export function initializeTestApp( + options: DatabaseAppOptions | FirestoreAppOptions +): FirebaseApp { let appOptions: FirebaseOptions; if ('databaseName' in options) { appOptions = { From b2259f5ff91e5fe8f7d95f91b0364f8c4c1dbb00 Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Fri, 13 Jul 2018 16:19:46 -0700 Subject: [PATCH 11/15] Cleanup --- packages/testing/index.ts | 1 - packages/testing/src/api/index.ts | 17 +++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/testing/index.ts b/packages/testing/index.ts index f6f624b4888..771308161a0 100644 --- a/packages/testing/index.ts +++ b/packages/testing/index.ts @@ -26,6 +26,5 @@ export { assertSucceeds, initializeAdminApp, initializeTestApp, - initializeFirestoreTestApp, loadDatabaseRules } from './src/api'; diff --git a/packages/testing/src/api/index.ts b/packages/testing/src/api/index.ts index 1ba60b9a16a..89334578a75 100644 --- a/packages/testing/src/api/index.ts +++ b/packages/testing/src/api/index.ts @@ -58,17 +58,12 @@ export function initializeAdminApp(options: AdminAppOptions): admin.app.App { ); } -export type DatabaseAppOptions = { - databaseName: string; - auth: object; -}; -export type FirestoreAppOptions = { - projectId: string; +export type AppOptions = { + databaseName?: string; + projectId?: string; auth: object; -}; -export function initializeTestApp( - options: DatabaseAppOptions | FirestoreAppOptions -): FirebaseApp { +} +export function initializeTestApp(options: AppOptions): FirebaseApp { let appOptions: FirebaseOptions; if ('databaseName' in options) { appOptions = { @@ -78,6 +73,8 @@ export function initializeTestApp( appOptions = { projectId: options.projectId }; + } else { + throw new Error("neither databaseName or projectId were specified"); } const header = { alg: 'RS256', From bf748c3eab004084d8bdf09dafdedf6354069de8 Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Fri, 13 Jul 2018 16:20:04 -0700 Subject: [PATCH 12/15] [AUTOMATED]: Prettier Code Styling --- packages/testing/src/api/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/testing/src/api/index.ts b/packages/testing/src/api/index.ts index 89334578a75..8991fc92139 100644 --- a/packages/testing/src/api/index.ts +++ b/packages/testing/src/api/index.ts @@ -62,7 +62,7 @@ export type AppOptions = { databaseName?: string; projectId?: string; auth: object; -} +}; export function initializeTestApp(options: AppOptions): FirebaseApp { let appOptions: FirebaseOptions; if ('databaseName' in options) { @@ -74,7 +74,7 @@ export function initializeTestApp(options: AppOptions): FirebaseApp { projectId: options.projectId }; } else { - throw new Error("neither databaseName or projectId were specified"); + throw new Error('neither databaseName or projectId were specified'); } const header = { alg: 'RS256', From 5497fba0dbd08fb9f97c09b54dbcd63423a9cd2d Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Mon, 16 Jul 2018 11:37:23 -0700 Subject: [PATCH 13/15] Update major version since this is a breaking change that will cause the testing sdk to no longer work with old versions of the RTDB emulator --- packages/testing/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/testing/package.json b/packages/testing/package.json index 3244a9b8892..97ed1286b2b 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -1,6 +1,6 @@ { "name": "@firebase/testing", - "version": "0.1.0", + "version": "1.0.0", "private": true, "description": "", "author": "Firebase (https://firebase.google.com/)", From 585366f90d1ce15692bd01937d55b786ae60e999 Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Mon, 16 Jul 2018 11:51:31 -0700 Subject: [PATCH 14/15] Completely remove admin sdk --- packages/testing/index.ts | 1 - packages/testing/package.json | 1 - packages/testing/src/api/index.ts | 20 -------------------- packages/testing/test/database.test.ts | 23 +++-------------------- 4 files changed, 3 insertions(+), 42 deletions(-) diff --git a/packages/testing/index.ts b/packages/testing/index.ts index 771308161a0..c3a1aa3ba0f 100644 --- a/packages/testing/index.ts +++ b/packages/testing/index.ts @@ -24,7 +24,6 @@ export { apps, assertFails, assertSucceeds, - initializeAdminApp, initializeTestApp, loadDatabaseRules } from './src/api'; diff --git a/packages/testing/package.json b/packages/testing/package.json index 97ed1286b2b..851ed5aa6ef 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -16,7 +16,6 @@ }, "license": "Apache-2.0", "dependencies": { - "firebase-admin": "5.12.0", "request-promise": "4.2.2" }, "devDependencies": { diff --git a/packages/testing/src/api/index.ts b/packages/testing/src/api/index.ts index 8991fc92139..31bc5049d0b 100644 --- a/packages/testing/src/api/index.ts +++ b/packages/testing/src/api/index.ts @@ -15,7 +15,6 @@ */ import { firebase } from '@firebase/app'; -import * as admin from 'firebase-admin'; import request from 'request-promise'; import * as fs from 'fs'; import { FirebaseApp, FirebaseOptions } from '@firebase/app-types'; @@ -35,29 +34,10 @@ class FakeCredentials { } } -export function adminApps(): (admin.app.App | null)[] { - return admin.apps; -} - export function apps(): (FirebaseApp | null)[] { return firebase.apps; } -type AdminAppOptions = { - databaseName: string; -}; - -export function initializeAdminApp(options: AdminAppOptions): admin.app.App { - const appName = 'app-' + new Date().getTime() + '-' + Math.random(); - return admin.initializeApp( - { - credential: new FakeCredentials(), - databaseURL: DBURL + '?ns=' + options.databaseName - }, - appName - ); -} - export type AppOptions = { databaseName?: string; projectId?: string; diff --git a/packages/testing/test/database.test.ts b/packages/testing/test/database.test.ts index 9f5495bf249..a89aa185963 100644 --- a/packages/testing/test/database.test.ts +++ b/packages/testing/test/database.test.ts @@ -47,11 +47,6 @@ describe('Testing Module Tests', function() { }); }); - it('initializeAdminApp() provides admin', function() { - const app = firebase.initializeAdminApp({ databaseName: 'foo' }); - expect(app.options).to.not.have.any.keys('databaseAuthVariableOverride'); - }); - it('initializeTestApp() with DatabaseAppOptions uses specified auth.', async function() { let app = firebase.initializeTestApp({ projectId: 'foo', @@ -128,23 +123,11 @@ describe('Testing Module Tests', function() { ).to.throw(/Could not find file/); }); - it('adminApps() returns only apps created with initializeAdminApp', async function() { - const numApps = firebase.apps().length; - await firebase.initializeAdminApp({ databaseName: 'foo' }); - expect(firebase.adminApps().length).to.equal(numApps + 1); - await firebase.initializeAdminApp({ databaseName: 'foo' }); - expect(firebase.adminApps().length).to.equal(numApps + 2); - await firebase.initializeTestApp({ databaseName: 'foo', auth: {} }); - expect(firebase.adminApps().length).to.equal(numApps + 2); - }); - - it('apps() returns only apps created with initializeTestApp', async function() { + it('apps() returns apps created with initializeTestApp', async function() { const numApps = firebase.apps().length; - await firebase.initializeAdminApp({ databaseName: 'foo' }); - expect(firebase.apps().length).to.equal(numApps + 0); - await firebase.initializeAdminApp({ databaseName: 'foo' }); - expect(firebase.apps().length).to.equal(numApps + 0); await firebase.initializeTestApp({ databaseName: 'foo', auth: {} }); expect(firebase.apps().length).to.equal(numApps + 1); + await firebase.initializeTestApp({ databaseName: 'bar', auth: {} }); + expect(firebase.apps().length).to.equal(numApps + 2); }); }); From 85ca2e266fffad8c9bbeadc236dbb3fc53402839 Mon Sep 17 00:00:00 2001 From: Tony Meng Date: Mon, 16 Jul 2018 12:09:51 -0700 Subject: [PATCH 15/15] Change version back to 0.1.0 --- packages/testing/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/testing/package.json b/packages/testing/package.json index 851ed5aa6ef..8a7c5add0a1 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -1,6 +1,6 @@ { "name": "@firebase/testing", - "version": "1.0.0", + "version": "0.1.0", "private": true, "description": "", "author": "Firebase (https://firebase.google.com/)",