Skip to content

Commit 1877e98

Browse files
authored
Fix integration tests (#1179)
One notable change made here is that we generate and include ID tokens in requests to http/callable functions since we aren't allowed to run public functions on internal GCP project.
1 parent 9b6da2d commit 1877e98

File tree

8 files changed

+54
-32
lines changed

8 files changed

+54
-32
lines changed

integration_test/README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ Run the integration test as follows:
88
./run_tests.sh <project_id> [<project_id2>]
99
```
1010

11-
If just one project_id is provided, the both the node6 and node8 tests will be run on that project, in series. If two project_ids are provided, the node6 tests will be run on the first project and the node8 tests will be run on the second one, in parallel.
11+
Test runs cycles of testing, once for Node.js 14 and another for Node.js 16.
1212

13-
The tests run fully automatically, and will print the result on standard out. The integration test for HTTPS is that it properly kicks off other integration tests and returns a result. From there the other integration test suites will write their results back to the database, where you can check the detailed results if you'd like.
13+
Test uses locally installed firebase to invoke commands for deploying function. The test also requires that you have
14+
gcloud CLI installed and authenticated (`gcloud auth login`).
15+
16+
Integration test is triggered by invoking HTTP function integrationTest which in turns invokes each function trigger
17+
by issuing actions necessary to trigger it (e.g. write to storage bucket).
18+
19+
### Debugging
20+
21+
The status and result of each test is stored in RTDB of the project used for testing. You can also inspect Cloud Logging
22+
for more clues.

integration_test/firebase.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55
"firestore": {
66
"rules": "firestore.rules",
77
"indexes": "firestore.indexes.json"
8+
},
9+
"functions": {
10+
"predeploy": ["npm --prefix \"$RESOURCE_DIR\" run build"]
811
}
912
}

integration_test/functions/src/index.ts

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { PubSub } from '@google-cloud/pubsub';
2+
import { GoogleAuth } from 'google-auth-library';
23
import { Request, Response } from 'express';
34
import * as admin from 'firebase-admin';
45
import * as functions from 'firebase-functions';
@@ -22,17 +23,19 @@ const firebaseConfig = JSON.parse(process.env.FIREBASE_CONFIG);
2223
admin.initializeApp();
2324

2425
async function callHttpsTrigger(name: string, data: any) {
25-
const resp = await fetch(
26-
`https://${REGION}-${firebaseConfig.projectId}.cloudfunctions.net/${name}`,
27-
{
28-
method: 'POST',
29-
headers: {
30-
'Content-Type': 'application/json',
31-
},
32-
body: JSON.stringify({ data }),
33-
}
26+
const url = `https://${REGION}-${firebaseConfig.projectId}.cloudfunctions.net/${name}`;
27+
const client = await new GoogleAuth().getIdTokenClient(
28+
'32555940559.apps.googleusercontent.com'
3429
);
35-
if (!resp.ok) {
30+
const resp = await client.request({
31+
url,
32+
method: 'POST',
33+
headers: {
34+
'Content-Type': 'application/json',
35+
},
36+
body: JSON.stringify({ data }),
37+
});
38+
if (resp.status > 200) {
3639
throw Error(resp.statusText);
3740
}
3841
}
@@ -42,31 +45,36 @@ async function callV2HttpsTrigger(
4245
data: any,
4346
accessToken: string
4447
) {
45-
let resp = await fetch(
48+
const getFnResp = await fetch(
4649
`https://cloudfunctions.googleapis.com/v2beta/projects/${firebaseConfig.projectId}/locations/${REGION}/functions/${name}`,
4750
{
4851
headers: {
4952
Authorization: `Bearer ${accessToken}`,
5053
},
5154
}
5255
);
53-
if (!resp.ok) {
54-
throw new Error(resp.statusText);
56+
if (!getFnResp.ok) {
57+
throw new Error(getFnResp.statusText);
5558
}
56-
const fn = await resp.json();
59+
const fn = await getFnResp.json();
5760
const uri = fn.serviceConfig?.uri;
5861
if (!uri) {
5962
throw new Error(`Cannot call v2 https trigger ${name} - no uri found`);
6063
}
61-
resp = await fetch(uri, {
64+
65+
const client = await new GoogleAuth().getIdTokenClient(
66+
'32555940559.apps.googleusercontent.com'
67+
);
68+
const invokeFnREsp = await client.request({
69+
url: uri,
6270
method: 'POST',
6371
headers: {
6472
'Content-Type': 'application/json',
6573
},
6674
body: JSON.stringify({ data }),
6775
});
68-
if (!resp.ok) {
69-
throw new Error(resp.statusText);
76+
if (invokeFnREsp.status > 200) {
77+
throw Error(invokeFnREsp.statusText);
7078
}
7179
}
7280

@@ -170,6 +178,7 @@ export const integrationTests: any = functions
170178
.region(REGION)
171179
.runWith({
172180
timeoutSeconds: 540,
181+
invoker: 'private',
173182
})
174183
.https.onRequest(async (req: Request, resp: Response) => {
175184
const testId = admin

integration_test/functions/src/v1/https-tests.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ import * as functions from 'firebase-functions';
22
import { REGION } from '../region';
33
import { expectEq, TestSuite } from '../testing';
44

5-
export const callableTests: any = functions.region(REGION).https.onCall((d) => {
6-
return new TestSuite('https onCall')
7-
.it('should have the correct data', (data: any) =>
8-
expectEq(data?.foo, 'bar')
9-
)
10-
.run(d.testId, d);
11-
});
5+
export const callableTests: any = functions
6+
.runWith({ invoker: 'private' })
7+
.region(REGION)
8+
.https.onCall((d) => {
9+
return new TestSuite('https onCall')
10+
.it('should have the correct data', (data: any) =>
11+
expectEq(data?.foo, 'bar')
12+
)
13+
.run(d.testId, d);
14+
});

integration_test/functions/src/v2/https-tests.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { onCall } from 'firebase-functions/v2/https';
22
import { expectEq, TestSuite } from '../testing';
33

4-
export const callabletests = onCall((req) => {
4+
export const callabletests = onCall({ invoker: 'private' }, (req) => {
55
return new TestSuite('v2 https onCall')
66
.it('should have the correct data', (data: any) =>
77
expectEq(data?.foo, 'bar')

integration_test/functions/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"compilerOptions": {
33
"lib": ["es6", "dom"],
44
"module": "commonjs",
5-
"target": "es6",
5+
"target": "es2020",
66
"noImplicitAny": false,
77
"outDir": "lib",
88
"declaration": true,

integration_test/run_tests.sh

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ function delete_all_functions {
7474
}
7575

7676
function deploy {
77-
cd "${DIR}"
78-
./functions/node_modules/.bin/tsc -p functions/
7977
# Deploy functions, and security rules for database and Firestore. If the deploy fails, retry twice
8078
if [[ "${TOKEN}" == "" ]]; then
8179
for i in 1 2 3; do firebase deploy --project="${PROJECT_ID}" --only functions,database,firestore && break; done
@@ -97,7 +95,7 @@ function run_tests {
9795
TEST_URL="https://${FIREBASE_FUNCTIONS_TEST_REGION}-${PROJECT_ID}.${TEST_DOMAIN}/integrationTests"
9896
echo "${TEST_URL}"
9997

100-
curl --fail "${TEST_URL}"
98+
curl --fail -H "Authorization: Bearer $(gcloud auth print-identity-token)" "${TEST_URL}"
10199
}
102100

103101
function cleanup {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@
169169
"docgen:v2:toc": "ts-node docgen/toc.ts --input docgen/v2/markdown --output docgen/v2/markdown/toc --path /docs/functions/beta/reference",
170170
"docgen:v2:gen": "api-documenter-fire markdown -i docgen/v2 -o docgen/v2/markdown && npm run docgen:v2:toc",
171171
"docgen:v2": "npm run build && npm run docgen:v2:extract && npm run docgen:v2:gen",
172-
"build:pack": "rm -rf lib && npm install --production && tsc -p tsconfig.release.json && npm pack",
172+
"build:pack": "rm -rf lib && npm install && tsc -p tsconfig.release.json && npm pack",
173173
"build:release": "npm ci --production && npm install --no-save typescript firebase-admin && tsc -p tsconfig.release.json",
174174
"build": "tsc -p tsconfig.release.json",
175175
"build:watch": "npm run build -- -w",

0 commit comments

Comments
 (0)