11import { PubSub } from '@google-cloud/pubsub' ;
22import { Request , Response } from 'express' ;
3+ import fetch from 'node-fetch' ;
34import * as admin from 'firebase-admin' ;
45import * as functions from 'firebase-functions' ;
56import * as fs from 'fs' ;
6- import * as https from 'https' ;
77
8- export * from './pubsub-tests' ;
9- export * from './database-tests' ;
10- export * from './auth-tests' ;
11- export * from './firestore-tests' ;
12- export * from './https-tests' ;
13- export * from './remoteConfig-tests' ;
14- export * from './storage-tests' ;
15- export * from './testLab-tests' ;
16- const numTests = Object . keys ( exports ) . length ; // Assumption: every exported function is its own test.
8+ import * as v1 from './v1/index' ;
9+ const numTests = Object . keys ( v1 ) . filter ( ( k ) =>
10+ ( { } . hasOwnProperty . call ( v1 [ k ] , '__endpoint' ) )
11+ ) . length ;
12+ export { v1 } ;
1713
18- import * as utils from './test-utils' ;
19- import * as testLab from './testLab-utils' ;
14+ import * as testLab from './v1/testLab-utils' ;
2015
21- import 'firebase-functions' ; // temporary shim until process.env.FIREBASE_CONFIG available natively in GCF(BUG 63586213)
22- import { config } from 'firebase-functions' ;
2316const firebaseConfig = JSON . parse ( process . env . FIREBASE_CONFIG ) ;
24- admin . initializeApp ( ) ;
2517const REGION = functions . config ( ) . functions . test_region ;
18+ admin . initializeApp ( ) ;
2619
27- // TODO(klimt): Get rid of this once the JS client SDK supports callable triggers.
28- function callHttpsTrigger ( name : string , data : any , baseUrl ) {
29- return utils . makeRequest (
20+ function callHttpsTrigger ( name : string , data : any ) {
21+ return fetch (
22+ `https:// ${ REGION } - ${ firebaseConfig . projectId } .cloudfunctions.net/ ${ name } ` ,
3023 {
3124 method : 'POST' ,
32- host : REGION + '-' + firebaseConfig . projectId + '.' + baseUrl ,
33- path : '/' + name ,
3425 headers : {
3526 'Content-Type' : 'application/json' ,
3627 } ,
37- } ,
38- JSON . stringify ( { data } )
28+ body : JSON . stringify ( { data } ) ,
29+ }
3930 ) ;
4031}
4132
4233async function callScheduleTrigger ( functionName : string , region : string ) {
4334 const accessToken = await admin . credential
4435 . applicationDefault ( )
4536 . getAccessToken ( ) ;
46- return new Promise < string > ( ( resolve , reject ) => {
47- const request = https . request (
48- {
49- method : 'POST' ,
50- host : 'cloudscheduler.googleapis.com' ,
51- path : `/v1/projects/${ firebaseConfig . projectId } /locations/us-central1/jobs/firebase-schedule-${ functionName } -${ region } :run` ,
52- headers : {
53- 'Content-Type' : 'application/json' ,
54- Authorization : `Bearer ${ accessToken . access_token } ` ,
55- } ,
37+ const response = await fetch (
38+ `https://cloudscheduler.googleapis.com/v1/projects/${ firebaseConfig . projectId } /locations/us-central1/jobs/firebase-schedule-${ functionName } -${ region } :run` ,
39+ {
40+ method : 'POST' ,
41+ headers : {
42+ 'Content-Type' : 'application/json' ,
43+ Authorization : `Bearer ${ accessToken . access_token } ` ,
5644 } ,
57- ( response ) => {
58- if ( response . statusCode ! / 100 != 2 ) {
59- reject (
60- new Error ( 'Failed request with status ' + response . statusCode ! )
61- ) ;
62- return ;
63- }
64- let body = '' ;
65- response . on ( 'data' , ( chunk ) => {
66- body += chunk ;
67- } ) ;
68- response . on ( 'end' , ( ) => {
69- console . log ( `Successfully scheduled function ${ functionName } ` ) ;
70- resolve ( body ) ;
71- } ) ;
72- }
73- ) ;
74- request . on ( 'error' , ( err ) => {
75- console . error ( 'Failed to schedule cloud scheduler job with error' , err ) ;
76- reject ( err ) ;
77- } ) ;
78- request . write ( '{}' ) ;
79- request . end ( ) ;
80- } ) ;
45+ }
46+ ) ;
47+ if ( ! response . ok ) {
48+ throw new Error ( `Failed request with status ${ response . status } !` ) ;
49+ }
50+ const data = await response . text ( ) ;
51+ functions . logger . log ( `Successfully scheduled function ${ functionName } ` , data ) ;
52+ return ;
53+ }
54+
55+ async function updateRemoteConfig (
56+ testId : string ,
57+ accessToken : string
58+ ) : Promise < void > {
59+ await fetch (
60+ `https://firebaseremoteconfig.googleapis.com/v1/projects/${ firebaseConfig . projectId } /remoteConfig` ,
61+ {
62+ method : 'PUT' ,
63+ headers : {
64+ Authorization : `Bearer ${ accessToken } ` ,
65+ 'Content-Type' : 'application/json; UTF-8' ,
66+ 'Accept-Encoding' : 'gzip' ,
67+ 'If-Match' : '*' ,
68+ } ,
69+ body : JSON . stringify ( { version : { description : testId } } ) ,
70+ }
71+ ) ;
72+ }
73+
74+ function v1Tests ( testId : string , accessToken : string ) {
75+ return [
76+ // A database write to trigger the Firebase Realtime Database tests.
77+ admin
78+ . database ( )
79+ . ref ( `dbTests/${ testId } /start` )
80+ . set ( { '.sv' : 'timestamp' } ) ,
81+ // A Pub/Sub publish to trigger the Cloud Pub/Sub tests.
82+ new PubSub ( )
83+ . topic ( 'pubsubTests' )
84+ . publish ( Buffer . from ( JSON . stringify ( { testId } ) ) ) ,
85+ // A user creation to trigger the Firebase Auth user creation tests.
86+ admin
87+ . auth ( )
88+ . createUser ( {
89+ email : `${ testId } @fake.com` ,
90+ password : 'secret' ,
91+ displayName : `${ testId } ` ,
92+ } )
93+ . then ( ( userRecord ) => {
94+ // A user deletion to trigger the Firebase Auth user deletion tests.
95+ admin . auth ( ) . deleteUser ( userRecord . uid ) ;
96+ } ) ,
97+ // A firestore write to trigger the Cloud Firestore tests.
98+ admin
99+ . firestore ( )
100+ . collection ( 'tests' )
101+ . doc ( testId )
102+ . set ( { test : testId } ) ,
103+ // Invoke a callable HTTPS trigger.
104+ callHttpsTrigger ( 'v1-callableTests' , { foo : 'bar' , testId } ) ,
105+ // A Remote Config update to trigger the Remote Config tests.
106+ updateRemoteConfig ( testId , accessToken ) ,
107+ // A storage upload to trigger the Storage tests
108+ admin
109+ . storage ( )
110+ . bucket ( )
111+ . upload ( '/tmp/' + testId + '.txt' ) ,
112+ testLab . startTestRun ( firebaseConfig . projectId , testId ) ,
113+ // Invoke the schedule for our scheduled function to fire
114+ callScheduleTrigger ( 'v1-schedule' , 'us-central1' ) ,
115+ ] ;
81116}
82117
83118export const integrationTests : any = functions
@@ -86,12 +121,6 @@ export const integrationTests: any = functions
86121 timeoutSeconds : 540 ,
87122 } )
88123 . https . onRequest ( async ( req : Request , resp : Response ) => {
89- // We take the base url for our https call (cloudfunctions.net, txckloud.net, etc) from the request
90- // so that it changes with the environment that the tests are run in
91- const baseUrl = req . hostname
92- . split ( '.' )
93- . slice ( 1 )
94- . join ( '.' ) ;
95124 const testId = admin
96125 . database ( )
97126 . ref ( )
@@ -101,71 +130,15 @@ export const integrationTests: any = functions
101130 . ref ( `testRuns/${ testId } /timestamp` )
102131 . set ( Date . now ( ) ) ;
103132 const testIdRef = admin . database ( ) . ref ( `testRuns/${ testId } ` ) ;
104- console . log ( 'testId is: ' , testId ) ;
133+ functions . logger . info ( 'testId is: ' , testId ) ;
105134 fs . writeFile ( '/tmp/' + testId + '.txt' , 'test' , ( ) => { } ) ;
106135 try {
107- await Promise . all ( [
108- // A database write to trigger the Firebase Realtime Database tests.
109- admin
110- . database ( )
111- . ref ( `dbTests/${ testId } /start` )
112- . set ( { '.sv' : 'timestamp' } ) ,
113- // A Pub/Sub publish to trigger the Cloud Pub/Sub tests.
114- new PubSub ( )
115- . topic ( 'pubsubTests' )
116- . publish ( Buffer . from ( JSON . stringify ( { testId } ) ) ) ,
117- // A user creation to trigger the Firebase Auth user creation tests.
118- admin
119- . auth ( )
120- . createUser ( {
121- email : `${ testId } @fake.com` ,
122- password : 'secret' ,
123- displayName : `${ testId } ` ,
124- } )
125- . then ( ( userRecord ) => {
126- // A user deletion to trigger the Firebase Auth user deletion tests.
127- admin . auth ( ) . deleteUser ( userRecord . uid ) ;
128- } ) ,
129- // A firestore write to trigger the Cloud Firestore tests.
130- admin
131- . firestore ( )
132- . collection ( 'tests' )
133- . doc ( testId )
134- . set ( { test : testId } ) ,
135- // Invoke a callable HTTPS trigger.
136- callHttpsTrigger ( 'callableTests' , { foo : 'bar' , testId } , baseUrl ) ,
137- // A Remote Config update to trigger the Remote Config tests.
138- admin . credential
139- . applicationDefault ( )
140- . getAccessToken ( )
141- . then ( ( accessToken ) => {
142- const options = {
143- hostname : 'firebaseremoteconfig.googleapis.com' ,
144- path : `/v1/projects/${ firebaseConfig . projectId } /remoteConfig` ,
145- method : 'PUT' ,
146- headers : {
147- Authorization : 'Bearer ' + accessToken . access_token ,
148- 'Content-Type' : 'application/json; UTF-8' ,
149- 'Accept-Encoding' : 'gzip' ,
150- 'If-Match' : '*' ,
151- } ,
152- } ;
153- const request = https . request ( options , ( resp ) => { } ) ;
154- request . write ( JSON . stringify ( { version : { description : testId } } ) ) ;
155- request . end ( ) ;
156- } ) ,
157- // A storage upload to trigger the Storage tests
158- admin
159- . storage ( )
160- . bucket ( )
161- . upload ( '/tmp/' + testId + '.txt' ) ,
162- testLab . startTestRun ( firebaseConfig . projectId , testId ) ,
163- // Invoke the schedule for our scheduled function to fire
164- callScheduleTrigger ( 'schedule' , 'us-central1' ) ,
165- ] ) ;
166-
136+ const accessToken = await admin . credential
137+ . applicationDefault ( )
138+ . getAccessToken ( ) ;
139+ await Promise . all ( [ ...v1Tests ( testId , accessToken . access_token ) ] ) ;
167140 // On test completion, check that all tests pass and reply "PASS", or provide further details.
168- console . log ( 'Waiting for all tests to report they pass...' ) ;
141+ functions . logger . info ( 'Waiting for all tests to report they pass...' ) ;
169142 await new Promise < void > ( ( resolve , reject ) => {
170143 setTimeout ( ( ) => reject ( new Error ( 'Timeout' ) ) , 5 * 60 * 1000 ) ;
171144 let testsExecuted = 0 ;
@@ -179,7 +152,7 @@ export const integrationTests: any = functions
179152 ) ;
180153 return ;
181154 }
182- console . log (
155+ functions . logger . info (
183156 `${ snapshot . key } passed (${ testsExecuted } of ${ numTests } )`
184157 ) ;
185158 if ( testsExecuted < numTests ) {
@@ -190,10 +163,10 @@ export const integrationTests: any = functions
190163 resolve ( ) ;
191164 } ) ;
192165 } ) ;
193- console . log ( 'All tests pass!' ) ;
166+ functions . logger . info ( 'All tests pass!' ) ;
194167 resp . status ( 200 ) . send ( 'PASS \n' ) ;
195168 } catch ( err ) {
196- console . log ( `Some tests failed: ${ err } ` ) ;
169+ functions . logger . info ( `Some tests failed: ${ err } ` , err ) ;
197170 resp
198171 . status ( 500 )
199172 . send (
0 commit comments