Skip to content

Commit ee7d43f

Browse files
committed
Merge remote-tracking branch 'origin/master' into launch.next
2 parents a215d8e + f751f5c commit ee7d43f

File tree

23 files changed

+1429
-3039
lines changed

23 files changed

+1429
-3039
lines changed

.github/workflows/postmerge.yaml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright 2022 Google Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
name: Post-merge tests
15+
16+
on:
17+
workflow_dispatch:
18+
workflow_run:
19+
workflows: ['CI Tests']
20+
types: [completed]
21+
branches: [master]
22+
23+
concurrency:
24+
group: postmerge-${{ github.ref }}
25+
cancel-in-progress: true
26+
27+
env:
28+
CI: true
29+
30+
jobs:
31+
postmerge:
32+
runs-on: ubuntu-latest
33+
steps:
34+
- uses: actions/checkout@v3
35+
- uses: actions/setup-node@v3
36+
with:
37+
node-version: 16
38+
39+
- uses: google-github-actions/auth@v0
40+
with:
41+
credentials_json: '${{ secrets.CF3_INTEGRATION_TEST_GOOGLE_CREDENTIALS }}'
42+
create_credentials_file: true
43+
44+
- name: 'Set up Cloud SDK'
45+
uses: google-github-actions/setup-gcloud@v0
46+
47+
- name: 'Setup Firebase CLI'
48+
run: npm i -g firebase-tools
49+
50+
- name: 'Run integration test'
51+
run: npm run test:postmerge
52+
53+
- name: Print debug logs
54+
if: failure()
55+
run: find . -type f -name "*debug.log" | xargs cat

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: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
},
99
"functions": {
1010
"source": "functions",
11-
"codebase": "integration-tests"
11+
"codebase": "integration-tests",
12+
"predeploy": ["npm --prefix \"$RESOURCE_DIR\" run build"]
1213
}
1314
}

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

@@ -163,6 +171,7 @@ export const integrationTests: any = functions
163171
.region(REGION)
164172
.runWith({
165173
timeoutSeconds: 540,
174+
invoker: 'private',
166175
})
167176
.https.onRequest(async (req: Request, resp: Response) => {
168177
const testId = admin.database().ref().push().key;

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: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,14 @@
33
# Exit immediately if a command exits with a non-zero status.
44
set -e
55

6-
function usage {
7-
echo "Usage: ${0} <project_id> [<token>]"
8-
exit 1
9-
}
6+
PROJECT_ID="${GCLOUD_PROJECT}"
7+
TIMESTAMP=$(date +%s)
108

11-
# This script takes in one required argument specifying a project_id and an
12-
# optional arguement for a CI token that can be obtained by running
13-
# `firebase login:ci`
14-
# Example usage (from root dir) without token:
15-
# ./integration_test/run_tests.sh chenky-test-proj
16-
# Example usage (from root dir) with token:
17-
# ./integration_test/run_tests.sh chenky-test-proj $TOKEN
18-
if [[ "${1}" == "" ]]; then
19-
usage
9+
if [[ "${PROJECT_ID}" == "" ]]; then
10+
echo "process.env.GCLOUD_PROJECT cannot be empty"
11+
exit 1
2012
fi
2113

22-
PROJECT_ID="${1}"
23-
TIMESTAMP=$(date +%s)
24-
TOKEN="${2}"
25-
2614
# Directory where this script lives.
2715
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
2816

@@ -64,24 +52,14 @@ function delete_all_functions {
6452
cd "${DIR}"
6553
# Try to delete, if there are errors it is because the project is already empty,
6654
# in that case do nothing.
67-
if [[ "${TOKEN}" == "" ]]; then
68-
firebase functions:delete integration-tests --force --project=$PROJECT_ID || : &
69-
else
70-
firebase functions:delete integration-tests --force --project=$PROJECT_ID --token=$TOKEN || : &
71-
fi
55+
firebase functions:delete integrationTests v1 v2 --force --project=$PROJECT_ID || : &
7256
wait
7357
announce "Project emptied."
7458
}
7559

7660
function deploy {
77-
cd "${DIR}"
78-
./functions/node_modules/.bin/tsc -p functions/
7961
# Deploy functions, and security rules for database and Firestore. If the deploy fails, retry twice
80-
if [[ "${TOKEN}" == "" ]]; then
81-
for i in 1 2 3; do firebase deploy --project="${PROJECT_ID}" --only functions:integration-tests,database,firestore && break; done
82-
else
83-
for i in 1 2 3; do firebase deploy --project="${PROJECT_ID}" --token="${TOKEN}" --only functions:integration-tests,database,firestore && break; done
84-
fi
62+
for i in 1 2; do firebase deploy --project="${PROJECT_ID}" --only functions,database,firestore && break; done
8563
}
8664

8765
function run_tests {
@@ -97,7 +75,7 @@ function run_tests {
9775
TEST_URL="https://${FIREBASE_FUNCTIONS_TEST_REGION}-${PROJECT_ID}.${TEST_DOMAIN}/integrationTests"
9876
echo "${TEST_URL}"
9977

100-
curl --fail "${TEST_URL}"
78+
curl --fail -H "Authorization: Bearer $(gcloud auth print-identity-token)" "${TEST_URL}"
10179
}
10280

10381
function cleanup {

0 commit comments

Comments
 (0)