From af6ed7e926b6f4669298b4c5a62c977d64430028 Mon Sep 17 00:00:00 2001 From: Daniel Young Lee Date: Thu, 3 Feb 2022 11:54:57 -0800 Subject: [PATCH 1/9] Add integration test for firebase-functions binary. --- .mocharc.yaml | 4 +- package.json | 7 +- scripts/bin-test/mocha-setup.ts | 4 + scripts/bin-test/npm-link.sh | 10 + scripts/bin-test/run.sh | 17 ++ .../bin-test/sources/commonjs-grouped/g1.js | 9 + .../sources/commonjs-grouped/index.js | 20 ++ .../sources/commonjs-grouped/package.json | 3 + .../sources/commonjs-main/functions.js | 18 ++ .../sources/commonjs-main/package.json | 4 + scripts/bin-test/sources/commonjs/index.js | 18 ++ .../bin-test/sources/commonjs/package.json | 3 + .../bin-test}/sources/esm-ext/index.mjs | 4 +- .../bin-test}/sources/esm-ext/package.json | 0 .../bin-test}/sources/esm-main/functions.js | 4 +- .../bin-test}/sources/esm-main/package.json | 0 .../bin-test}/sources/esm/index.js | 4 +- .../bin-test}/sources/esm/package.json | 0 scripts/bin-test/test.ts | 233 ++++++++++++++++++ scripts/cloudbuild.yaml | 113 +++++++++ spec/runtime/loader.spec.ts | 33 +-- 21 files changed, 466 insertions(+), 42 deletions(-) create mode 100644 scripts/bin-test/mocha-setup.ts create mode 100755 scripts/bin-test/npm-link.sh create mode 100755 scripts/bin-test/run.sh create mode 100644 scripts/bin-test/sources/commonjs-grouped/g1.js create mode 100644 scripts/bin-test/sources/commonjs-grouped/index.js create mode 100644 scripts/bin-test/sources/commonjs-grouped/package.json create mode 100644 scripts/bin-test/sources/commonjs-main/functions.js create mode 100644 scripts/bin-test/sources/commonjs-main/package.json create mode 100644 scripts/bin-test/sources/commonjs/index.js create mode 100644 scripts/bin-test/sources/commonjs/package.json rename {spec/fixtures => scripts/bin-test}/sources/esm-ext/index.mjs (76%) rename {spec/fixtures => scripts/bin-test}/sources/esm-ext/package.json (100%) rename {spec/fixtures => scripts/bin-test}/sources/esm-main/functions.js (76%) rename {spec/fixtures => scripts/bin-test}/sources/esm-main/package.json (100%) rename {spec/fixtures => scripts/bin-test}/sources/esm/index.js (76%) rename {spec/fixtures => scripts/bin-test}/sources/esm/package.json (100%) create mode 100644 scripts/bin-test/test.ts create mode 100644 scripts/cloudbuild.yaml diff --git a/.mocharc.yaml b/.mocharc.yaml index 932144124..bd17af0dc 100644 --- a/.mocharc.yaml +++ b/.mocharc.yaml @@ -1,10 +1,8 @@ exit: true extension: - ts -file: - - mocha/setup.ts package: ./package.json reporter: spec require: - 'ts-node/register' -spec: spec/**/*.spec.ts + - 'source-map-support/register' \ No newline at end of file diff --git a/package.json b/package.json index 25f8d8d7f..888085883 100644 --- a/package.json +++ b/package.json @@ -149,7 +149,8 @@ "format:fix": "prettier --write '**/*.{json,md,ts,yml,yaml}'", "lint": "tslint --config tslint.json --project tsconfig.json ", "lint:fix": "tslint --config tslint.json --fix --project tsconfig.json", - "test": "mocha" + "test": "mocha --file ./mocha/setup.ts spec/**/*.spec.ts ", + "test:bin": "./scripts/bin-test/run.sh" }, "dependencies": { "@types/cors": "^2.8.5", @@ -180,10 +181,12 @@ "mock-require": "^3.0.3", "mz": "^2.7.0", "nock": "^10.0.6", + "node-fetch": "^2.6.7", + "portfinder": "^1.0.28", "prettier": "^1.18.2", "semver": "^7.3.5", "sinon": "^7.3.2", - "ts-node": "^8.3.0", + "ts-node": "^10.4.0", "tslint": "^5.18.0", "tslint-config-prettier": "^1.18.0", "tslint-no-unused-expression-chai": "^0.1.4", diff --git a/scripts/bin-test/mocha-setup.ts b/scripts/bin-test/mocha-setup.ts new file mode 100644 index 000000000..6dfdc7f9d --- /dev/null +++ b/scripts/bin-test/mocha-setup.ts @@ -0,0 +1,4 @@ +import * as chai from 'chai'; +import * as chaiAsPromised from 'chai-as-promised'; + +chai.use(chaiAsPromised); diff --git a/scripts/bin-test/npm-link.sh b/scripts/bin-test/npm-link.sh new file mode 100755 index 000000000..26e3276d2 --- /dev/null +++ b/scripts/bin-test/npm-link.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e + +if [ "$CI" = "true" ]; then + echo "Running sudo npm link..." + sudo npm link +else + echo "Running npm link..." + npm link +fi diff --git a/scripts/bin-test/run.sh b/scripts/bin-test/run.sh new file mode 100755 index 000000000..f1ff75142 --- /dev/null +++ b/scripts/bin-test/run.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -ex # Immediately exit on failure + +# Globally link the locally built Functions SDK for the testing framework. +npm run build +./scripts/bin-test/npm-link.sh + +# Link local SDK to all test sources. +for f in scripts/bin-test/sources/*; do + if [ -d "$f" ]; then + (cd "$f" && npm link firebase-functions) + fi +done + +mocha \ + --file ./scripts/bin-test/mocha-setup.ts \ + ./scripts/bin-test/test.ts diff --git a/scripts/bin-test/sources/commonjs-grouped/g1.js b/scripts/bin-test/sources/commonjs-grouped/g1.js new file mode 100644 index 000000000..57766af02 --- /dev/null +++ b/scripts/bin-test/sources/commonjs-grouped/g1.js @@ -0,0 +1,9 @@ +const functions = require("firebase-functions"); + +exports.groupedhttp = functions.https.onRequest((req, resp) => { + resp.status(200).send("PASS"); +}); + +exports.groupedcallable = functions.https.onCall(() => { + return "PASS"; +}); diff --git a/scripts/bin-test/sources/commonjs-grouped/index.js b/scripts/bin-test/sources/commonjs-grouped/index.js new file mode 100644 index 000000000..b00828de0 --- /dev/null +++ b/scripts/bin-test/sources/commonjs-grouped/index.js @@ -0,0 +1,20 @@ +const functions = require("firebase-functions"); +const functionsv2 = require("firebase-functions/v2"); + +exports.v1http = functions.https.onRequest((req, resp) => { + resp.status(200).send("PASS"); +}); + +exports.v1callable = functions.https.onCall(() => { + return "PASS"; +}); + +exports.v2http = functionsv2.https.onRequest((req, resp) => { + resp.status(200).send("PASS"); +}); + +exports.v2callable = functionsv2.https.onCall(() => { + return "PASS"; +}); + +exports.g1 = require("./g1"); diff --git a/scripts/bin-test/sources/commonjs-grouped/package.json b/scripts/bin-test/sources/commonjs-grouped/package.json new file mode 100644 index 000000000..1ec99f52f --- /dev/null +++ b/scripts/bin-test/sources/commonjs-grouped/package.json @@ -0,0 +1,3 @@ +{ + "name": "commonjs-grouped" +} diff --git a/scripts/bin-test/sources/commonjs-main/functions.js b/scripts/bin-test/sources/commonjs-main/functions.js new file mode 100644 index 000000000..9122f9223 --- /dev/null +++ b/scripts/bin-test/sources/commonjs-main/functions.js @@ -0,0 +1,18 @@ +const functions = require("firebase-functions"); +const functionsv2 = require("firebase-functions/v2"); + +exports.v1http = functions.https.onRequest((req, resp) => { + resp.status(200).send("PASS"); +}); + +exports.v1callable = functions.https.onCall(() => { + return "PASS"; +}); + +exports.v2http = functionsv2.https.onRequest((req, resp) => { + resp.status(200).send("PASS"); +}); + +exports.v2callable = functionsv2.https.onCall(() => { + return "PASS"; +}); diff --git a/scripts/bin-test/sources/commonjs-main/package.json b/scripts/bin-test/sources/commonjs-main/package.json new file mode 100644 index 000000000..a781259f8 --- /dev/null +++ b/scripts/bin-test/sources/commonjs-main/package.json @@ -0,0 +1,4 @@ +{ + "name": "commonjs-main", + "main": "functions.js" +} diff --git a/scripts/bin-test/sources/commonjs/index.js b/scripts/bin-test/sources/commonjs/index.js new file mode 100644 index 000000000..9122f9223 --- /dev/null +++ b/scripts/bin-test/sources/commonjs/index.js @@ -0,0 +1,18 @@ +const functions = require("firebase-functions"); +const functionsv2 = require("firebase-functions/v2"); + +exports.v1http = functions.https.onRequest((req, resp) => { + resp.status(200).send("PASS"); +}); + +exports.v1callable = functions.https.onCall(() => { + return "PASS"; +}); + +exports.v2http = functionsv2.https.onRequest((req, resp) => { + resp.status(200).send("PASS"); +}); + +exports.v2callable = functionsv2.https.onCall(() => { + return "PASS"; +}); diff --git a/scripts/bin-test/sources/commonjs/package.json b/scripts/bin-test/sources/commonjs/package.json new file mode 100644 index 000000000..30e1b1b27 --- /dev/null +++ b/scripts/bin-test/sources/commonjs/package.json @@ -0,0 +1,3 @@ +{ + "name": "commonjs" +} diff --git a/spec/fixtures/sources/esm-ext/index.mjs b/scripts/bin-test/sources/esm-ext/index.mjs similarity index 76% rename from spec/fixtures/sources/esm-ext/index.mjs rename to scripts/bin-test/sources/esm-ext/index.mjs index 28d538e3b..91e974d93 100644 --- a/spec/fixtures/sources/esm-ext/index.mjs +++ b/scripts/bin-test/sources/esm-ext/index.mjs @@ -1,5 +1,5 @@ -import * as functions from '../../../../lib/index.js'; -import * as functionsv2 from "../../../../lib/v2/index.js"; +import * as functions from "firebase-functions"; +import * as functionsv2 from "firebase-functions/v2"; export const v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); diff --git a/spec/fixtures/sources/esm-ext/package.json b/scripts/bin-test/sources/esm-ext/package.json similarity index 100% rename from spec/fixtures/sources/esm-ext/package.json rename to scripts/bin-test/sources/esm-ext/package.json diff --git a/spec/fixtures/sources/esm-main/functions.js b/scripts/bin-test/sources/esm-main/functions.js similarity index 76% rename from spec/fixtures/sources/esm-main/functions.js rename to scripts/bin-test/sources/esm-main/functions.js index d1f98b49a..b09186731 100644 --- a/spec/fixtures/sources/esm-main/functions.js +++ b/scripts/bin-test/sources/esm-main/functions.js @@ -1,5 +1,5 @@ -import * as functions from "../../../../lib/index.js"; -import * as functionsv2 from "../../../../lib/v2/index.js"; +import * as functions from "firebase-functions"; +import * as functionsv2 from "firebase-functions/v2"; export const v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); diff --git a/spec/fixtures/sources/esm-main/package.json b/scripts/bin-test/sources/esm-main/package.json similarity index 100% rename from spec/fixtures/sources/esm-main/package.json rename to scripts/bin-test/sources/esm-main/package.json diff --git a/spec/fixtures/sources/esm/index.js b/scripts/bin-test/sources/esm/index.js similarity index 76% rename from spec/fixtures/sources/esm/index.js rename to scripts/bin-test/sources/esm/index.js index d1f98b49a..b09186731 100644 --- a/spec/fixtures/sources/esm/index.js +++ b/scripts/bin-test/sources/esm/index.js @@ -1,5 +1,5 @@ -import * as functions from "../../../../lib/index.js"; -import * as functionsv2 from "../../../../lib/v2/index.js"; +import * as functions from "firebase-functions"; +import * as functionsv2 from "firebase-functions/v2"; export const v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); diff --git a/spec/fixtures/sources/esm/package.json b/scripts/bin-test/sources/esm/package.json similarity index 100% rename from spec/fixtures/sources/esm/package.json rename to scripts/bin-test/sources/esm/package.json diff --git a/scripts/bin-test/test.ts b/scripts/bin-test/test.ts new file mode 100644 index 000000000..103741b74 --- /dev/null +++ b/scripts/bin-test/test.ts @@ -0,0 +1,233 @@ +import * as path from 'path'; +import * as subprocess from 'child_process'; +import { promisify } from 'util'; + +import fetch from 'node-fetch'; +import * as portfinder from 'portfinder'; +import * as yaml from 'js-yaml'; +import * as semver from 'semver'; +import { expect } from 'chai'; + +const TIMEOUT_XL = 20_000; +const TIMEOUT_L = 10_000; +const TIMEOUT_M = 5_000; +const TIMEOUT_S = 1_000; + +const BASE_STACK = { + endpoints: { + v1http: { + platform: 'gcfv1', + entryPoint: 'v1http', + httpsTrigger: {}, + }, + v1callable: { + platform: 'gcfv1', + entryPoint: 'v1callable', + labels: {}, + callableTrigger: {}, + }, + v2http: { + platform: 'gcfv2', + entryPoint: 'v2http', + labels: {}, + httpsTrigger: {}, + }, + v2callable: { + platform: 'gcfv2', + entryPoint: 'v2callable', + labels: {}, + callableTrigger: {}, + }, + }, + requiredAPIs: [], + specVersion: 'v1alpha1', +}; + +type Testcase = { + name: string; + modulePath: string; + expected: Record; +}; + +async function retryUntil( + fn: () => Promise, + timeoutMs: number, + sleepMs: number = TIMEOUT_S +) { + const sleep = () => { + return new Promise((resolve) => { + setTimeout(() => resolve(), sleepMs); + }); + }; + const timedOut = new Promise((resolve, reject) => { + setTimeout(() => { + reject(new Error('retry timeout')); + }, timeoutMs); + }); + const retry = (async () => { + while (true) { + if (await fn()) break; + await sleep(); + } + })(); + await Promise.race([retry, timedOut]); +} + +async function startBin( + tc: Testcase, + debug?: boolean +): Promise<{ port: number; cleanup: () => Promise }> { + const getPort = promisify(portfinder.getPort) as () => Promise; + const port = await getPort(); + + const proc = subprocess.spawn('./node_modules/.bin/firebase-functions', [], { + cwd: path.resolve(tc.modulePath), + env: { + PATH: process.env.PATH, + GLCOUD_PROJECT: 'test-project', + STACK_CONTROL_API_PORT: port, + }, + }); + + if (!proc) { + throw new Error('Failed to start firebase functions'); + } + + await retryUntil(async () => { + try { + await fetch(`http://localhost:${port}/__/stack.yaml`); + } catch (e) { + if (e?.code === 'ECONNREFUSED') { + return false; + } + throw e; + } + return true; + }, TIMEOUT_M); + + if (debug) { + proc.stdout?.on('data', (data: unknown) => { + console.log(`[${tc.name} stdout] ` + data); + }); + + proc.stderr?.on('data', (data: unknown) => { + console.log(`[${tc.name} stderr] ` + data); + }); + } + + return { + port, + cleanup: async () => { + process.kill(proc.pid); + await retryUntil(async () => { + try { + process.kill(proc.pid, 0); + } catch { + // process.kill w/ signal 0 will throw an error if the pid no longer exists. + return true; + } + return false; + }, TIMEOUT_M); + }, + }; +} + +describe('stack.yaml', () => { + async function runTests(tc: Testcase) { + let port: number; + let cleanup: () => Promise; + + before(async () => { + const r = await startBin(tc); + port = r.port; + cleanup = r.cleanup; + }); + + after(async () => { + await cleanup(); + }); + + it('stack.yaml returns expected Manifest', async () => { + const res = await fetch(`http://localhost:${port}/__/stack.yaml`); + const text = await res.text(); + let parsed: any; + try { + parsed = yaml.load(text); + } catch (err) { + throw new Error('Failed to parse stack.yaml ' + err); + } + expect(parsed).to.be.deep.equal(tc.expected); + }); + } + + describe('commonjs', () => { + const testcases: Testcase[] = [ + { + name: 'basic', + modulePath: './scripts/bin-test/sources/commonjs', + expected: BASE_STACK, + }, + { + name: 'has main', + modulePath: './scripts/bin-test/sources/commonjs-main', + expected: BASE_STACK, + }, + { + name: 'grouped', + modulePath: './scripts/bin-test/sources/commonjs-grouped', + expected: { + ...BASE_STACK, + endpoints: { + ...BASE_STACK.endpoints, + 'g1-groupedhttp': { + platform: 'gcfv1', + entryPoint: 'g1.groupedhttp', + httpsTrigger: {}, + }, + 'g1-groupedcallable': { + platform: 'gcfv1', + entryPoint: 'g1.groupedcallable', + labels: {}, + callableTrigger: {}, + }, + }, + }, + }, + ]; + + for (const tc of testcases) { + describe(tc.name, async () => { + await runTests(tc); + }); + } + }).timeout(TIMEOUT_L); + + if (semver.gt(process.versions.node, '13.2.0')) { + describe('esm', () => { + const testcases: Testcase[] = [ + { + name: 'basic', + modulePath: './scripts/bin-test/sources/esm', + expected: BASE_STACK, + }, + { + name: 'with main', + + modulePath: './scripts/bin-test/sources/esm-main', + expected: BASE_STACK, + }, + { + name: 'with .m extension', + modulePath: './scripts/bin-test/sources/esm-ext', + expected: BASE_STACK, + }, + ]; + + for (const tc of testcases) { + describe(tc.name, async () => { + await runTests(tc); + }); + } + }).timeout(TIMEOUT_L); + } +}).timeout(TIMEOUT_XL); diff --git a/scripts/cloudbuild.yaml b/scripts/cloudbuild.yaml new file mode 100644 index 000000000..a0e07f79c --- /dev/null +++ b/scripts/cloudbuild.yaml @@ -0,0 +1,113 @@ +steps: + # Decrypt the SSH key. + - name: 'gcr.io/cloud-builders/gcloud' + args: + [ + 'kms', + 'decrypt', + '--ciphertext-file=publish/deploy_key.enc', + '--plaintext-file=/root/.ssh/id_rsa', + '--location=global', + '--keyring=${_KEY_RING}', + '--key=${_KEY_NAME}', + ] + + # Decrypt the Twitter credentials. + - name: 'gcr.io/cloud-builders/gcloud' + args: + [ + 'kms', + 'decrypt', + '--ciphertext-file=publish/twitter.json.enc', + '--plaintext-file=twitter.json', + '--location=global', + '--keyring=${_KEY_RING}', + '--key=${_KEY_NAME}', + ] + + # Decrypt the npm credentials. + - name: 'gcr.io/cloud-builders/gcloud' + args: + [ + 'kms', + 'decrypt', + '--ciphertext-file=publish/npmrc.enc', + '--plaintext-file=npmrc', + '--location=global', + '--keyring=${_KEY_RING}', + '--key=${_KEY_NAME}', + ] + + # Decrypt the hub (GitHub) credentials. + - name: 'gcr.io/cloud-builders/gcloud' + args: + [ + 'kms', + 'decrypt', + '--ciphertext-file=publish/hub.enc', + '--plaintext-file=hub', + '--location=global', + '--keyring=${_KEY_RING}', + '--key=${_KEY_NAME}', + ] + + # Set up git with key and domain. + - name: 'gcr.io/cloud-builders/git' + entrypoint: 'bash' + args: + - '-c' + - | + chmod 600 /root/.ssh/id_rsa + cat </root/.ssh/config + Hostname github.com + IdentityFile /root/.ssh/id_rsa + EOF + ssh-keyscan github.com >> /root/.ssh/known_hosts + + # Clone the repository. + - name: 'gcr.io/cloud-builders/git' + args: ['clone', 'git@github.com:${_REPOSITORY_ORG}/${_REPOSITORY_NAME}'] + + # Set up the Git configuration. + - name: 'gcr.io/cloud-builders/git' + dir: '${_REPOSITORY_NAME}' + args: ['config', '--global', 'user.email', 'firebase-oss-bot@google.com'] + - name: 'gcr.io/cloud-builders/git' + dir: '${_REPOSITORY_NAME}' + args: ['config', '--global', 'user.name', 'Google Open Source Bot'] + + # Set up the Twitter credentials. + - name: 'gcr.io/$PROJECT_ID/package-builder' + entrypoint: 'cp' + args: ['-v', 'twitter.json', '${_REPOSITORY_NAME}/scripts/twitter.json'] + + # Set up the npm credentials. + - name: 'gcr.io/$PROJECT_ID/package-builder' + entrypoint: 'bash' + args: ['-c', 'cp -v npmrc ~/.npmrc'] + + # Set up the hub credentials for package-builder. + - name: 'gcr.io/$PROJECT_ID/package-builder' + entrypoint: 'bash' + args: ['-c', 'mkdir -vp ~/.config && cp -v hub ~/.config/hub'] + + # Publish the package. + - name: 'gcr.io/$PROJECT_ID/package-builder' + args: ['bash', './publish.sh', '${_VERSION}'] + env: + - 'REPOSITORY_ORG=${_REPOSITORY_ORG}' + - 'REPOSITORY_NAME=${_REPOSITORY_NAME}' + - 'DRY_RUN=${_DRY_RUN}' + +options: + volumes: + - name: 'ssh' + path: /root/.ssh + +substitutions: + _VERSION: '' + _DRY_RUN: '' + _KEY_RING: 'npm-publish-keyring' + _KEY_NAME: 'publish' + _REPOSITORY_ORG: 'firebase' + _REPOSITORY_NAME: 'firebase-functions' diff --git a/spec/runtime/loader.spec.ts b/spec/runtime/loader.spec.ts index 1dab77c43..436d3ea62 100644 --- a/spec/runtime/loader.spec.ts +++ b/spec/runtime/loader.spec.ts @@ -1,5 +1,4 @@ import * as path from 'path'; -import * as semver from 'semver'; import { expect } from 'chai'; import * as loader from '../../src/runtime/loader'; @@ -251,13 +250,13 @@ describe('loadStack', () => { expected: ManifestStack; }; function runTests(tc: Testcase) { - it('loads backend given relative path', async () => { + it('loads stack given relative path', async () => { await expect(loader.loadStack(tc.modulePath)).to.eventually.deep.equal( tc.expected ); }); - it('loads backend given absolute path', async () => { + it('loads stack given absolute path', async () => { await expect( loader.loadStack(path.join(process.cwd(), tc.modulePath)) ).to.eventually.deep.equal(tc.expected); @@ -317,32 +316,4 @@ describe('loadStack', () => { }); } }); - - if (semver.gt(process.versions.node, '13.2.0')) { - describe('esm', () => { - const testcases: Testcase[] = [ - { - name: 'basic', - modulePath: './spec/fixtures/sources/esm', - expected, - }, - { - name: 'with main', - modulePath: './spec/fixtures/sources/esm-main', - expected, - }, - { - name: 'with .m extension', - modulePath: './spec/fixtures/sources/esm-ext', - expected, - }, - ]; - - for (const tc of testcases) { - describe(tc.name, () => { - runTests(tc); - }); - } - }); - } }); From e58acbdffe49d421c3bd2720e9768e03e86e15d6 Mon Sep 17 00:00:00 2001 From: Daniel Young Lee Date: Thu, 3 Feb 2022 11:56:15 -0800 Subject: [PATCH 2/9] Minor fixes. --- .mocharc.yaml | 2 +- scripts/cloudbuild.yaml | 113 ---------------------------------------- 2 files changed, 1 insertion(+), 114 deletions(-) delete mode 100644 scripts/cloudbuild.yaml diff --git a/.mocharc.yaml b/.mocharc.yaml index bd17af0dc..2bb78edfc 100644 --- a/.mocharc.yaml +++ b/.mocharc.yaml @@ -5,4 +5,4 @@ package: ./package.json reporter: spec require: - 'ts-node/register' - - 'source-map-support/register' \ No newline at end of file + - 'source-map-support/register' diff --git a/scripts/cloudbuild.yaml b/scripts/cloudbuild.yaml deleted file mode 100644 index a0e07f79c..000000000 --- a/scripts/cloudbuild.yaml +++ /dev/null @@ -1,113 +0,0 @@ -steps: - # Decrypt the SSH key. - - name: 'gcr.io/cloud-builders/gcloud' - args: - [ - 'kms', - 'decrypt', - '--ciphertext-file=publish/deploy_key.enc', - '--plaintext-file=/root/.ssh/id_rsa', - '--location=global', - '--keyring=${_KEY_RING}', - '--key=${_KEY_NAME}', - ] - - # Decrypt the Twitter credentials. - - name: 'gcr.io/cloud-builders/gcloud' - args: - [ - 'kms', - 'decrypt', - '--ciphertext-file=publish/twitter.json.enc', - '--plaintext-file=twitter.json', - '--location=global', - '--keyring=${_KEY_RING}', - '--key=${_KEY_NAME}', - ] - - # Decrypt the npm credentials. - - name: 'gcr.io/cloud-builders/gcloud' - args: - [ - 'kms', - 'decrypt', - '--ciphertext-file=publish/npmrc.enc', - '--plaintext-file=npmrc', - '--location=global', - '--keyring=${_KEY_RING}', - '--key=${_KEY_NAME}', - ] - - # Decrypt the hub (GitHub) credentials. - - name: 'gcr.io/cloud-builders/gcloud' - args: - [ - 'kms', - 'decrypt', - '--ciphertext-file=publish/hub.enc', - '--plaintext-file=hub', - '--location=global', - '--keyring=${_KEY_RING}', - '--key=${_KEY_NAME}', - ] - - # Set up git with key and domain. - - name: 'gcr.io/cloud-builders/git' - entrypoint: 'bash' - args: - - '-c' - - | - chmod 600 /root/.ssh/id_rsa - cat </root/.ssh/config - Hostname github.com - IdentityFile /root/.ssh/id_rsa - EOF - ssh-keyscan github.com >> /root/.ssh/known_hosts - - # Clone the repository. - - name: 'gcr.io/cloud-builders/git' - args: ['clone', 'git@github.com:${_REPOSITORY_ORG}/${_REPOSITORY_NAME}'] - - # Set up the Git configuration. - - name: 'gcr.io/cloud-builders/git' - dir: '${_REPOSITORY_NAME}' - args: ['config', '--global', 'user.email', 'firebase-oss-bot@google.com'] - - name: 'gcr.io/cloud-builders/git' - dir: '${_REPOSITORY_NAME}' - args: ['config', '--global', 'user.name', 'Google Open Source Bot'] - - # Set up the Twitter credentials. - - name: 'gcr.io/$PROJECT_ID/package-builder' - entrypoint: 'cp' - args: ['-v', 'twitter.json', '${_REPOSITORY_NAME}/scripts/twitter.json'] - - # Set up the npm credentials. - - name: 'gcr.io/$PROJECT_ID/package-builder' - entrypoint: 'bash' - args: ['-c', 'cp -v npmrc ~/.npmrc'] - - # Set up the hub credentials for package-builder. - - name: 'gcr.io/$PROJECT_ID/package-builder' - entrypoint: 'bash' - args: ['-c', 'mkdir -vp ~/.config && cp -v hub ~/.config/hub'] - - # Publish the package. - - name: 'gcr.io/$PROJECT_ID/package-builder' - args: ['bash', './publish.sh', '${_VERSION}'] - env: - - 'REPOSITORY_ORG=${_REPOSITORY_ORG}' - - 'REPOSITORY_NAME=${_REPOSITORY_NAME}' - - 'DRY_RUN=${_DRY_RUN}' - -options: - volumes: - - name: 'ssh' - path: /root/.ssh - -substitutions: - _VERSION: '' - _DRY_RUN: '' - _KEY_RING: 'npm-publish-keyring' - _KEY_NAME: 'publish' - _REPOSITORY_ORG: 'firebase' - _REPOSITORY_NAME: 'firebase-functions' From 6f6a298e464cb5dce02e1d24aadbf30373df8216 Mon Sep 17 00:00:00 2001 From: Daniel Young Lee Date: Thu, 3 Feb 2022 11:58:27 -0800 Subject: [PATCH 3/9] Run the new integration test on PR and in release script. --- .github/workflows/test.yaml | 3 ++- scripts/publish.sh | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 4160a1eb3..25463f960 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -31,4 +31,5 @@ jobs: - run: npm install - run: npm run lint - run: npm run format - - run: npm run build && npm run test + - run: npm run test + - run: npm run test:bin diff --git a/scripts/publish.sh b/scripts/publish.sh index ea5acde68..a7574a15a 100644 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -80,6 +80,7 @@ echo "Ran npm ci." echo "Running tests..." npm test +npm run test:bin echo "Ran tests." echo "Running publish build..." From c1683e8d5ae9d45e71a1e8c433f2aac31025d7a2 Mon Sep 17 00:00:00 2001 From: Daniel Young Lee Date: Thu, 3 Feb 2022 13:00:26 -0800 Subject: [PATCH 4/9] Make cleanup call robust. --- scripts/bin-test/test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bin-test/test.ts b/scripts/bin-test/test.ts index 103741b74..1c6f1a24e 100644 --- a/scripts/bin-test/test.ts +++ b/scripts/bin-test/test.ts @@ -144,7 +144,7 @@ describe('stack.yaml', () => { }); after(async () => { - await cleanup(); + await cleanup?.(); }); it('stack.yaml returns expected Manifest', async () => { From ef716d2f0c5ef5da3cea3520108ccc79d5c37503 Mon Sep 17 00:00:00 2001 From: Daniel Young Lee Date: Thu, 3 Feb 2022 13:02:17 -0800 Subject: [PATCH 5/9] Breakout integration test as its own workflow. --- .github/workflows/test-integration.yaml | 32 +++++++++++++++++++++++++ .github/workflows/test.yaml | 1 - 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/test-integration.yaml diff --git a/.github/workflows/test-integration.yaml b/.github/workflows/test-integration.yaml new file mode 100644 index 000000000..2de0483a0 --- /dev/null +++ b/.github/workflows/test-integration.yaml @@ -0,0 +1,32 @@ +name: CI Tests - Integration + +on: + - pull_request + - push + +env: + CI: true + +jobs: + unit: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: + - 10.x + - 12.x + - 14.x + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Cache npm + uses: actions/cache@v1 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }} + + - run: npm install + - run: npm run test:bin diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 25463f960..c56d65e12 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -32,4 +32,3 @@ jobs: - run: npm run lint - run: npm run format - run: npm run test - - run: npm run test:bin From 1f161781bca38d99a36f6e9868383a0b01ce8ca8 Mon Sep 17 00:00:00 2001 From: Daniel Young Lee Date: Thu, 3 Feb 2022 13:03:42 -0800 Subject: [PATCH 6/9] Correctly breakout integration tests. --- .github/workflows/test-integration.yaml | 32 ------------------------- .github/workflows/test.yaml | 22 +++++++++++++++++ 2 files changed, 22 insertions(+), 32 deletions(-) delete mode 100644 .github/workflows/test-integration.yaml diff --git a/.github/workflows/test-integration.yaml b/.github/workflows/test-integration.yaml deleted file mode 100644 index 2de0483a0..000000000 --- a/.github/workflows/test-integration.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: CI Tests - Integration - -on: - - pull_request - - push - -env: - CI: true - -jobs: - unit: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: - - 10.x - - 12.x - - 14.x - steps: - - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - - name: Cache npm - uses: actions/cache@v1 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }} - - - run: npm install - - run: npm run test:bin diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c56d65e12..e6d79e47a 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -32,3 +32,25 @@ jobs: - run: npm run lint - run: npm run format - run: npm run test + integration: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: + - 10.x + - 12.x + - 14.x + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Cache npm + uses: actions/cache@v1 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }} + + - run: npm install + - run: npm run test:bin From cd20c24b60db3dbca7602b9d60b7cfc5dd484a01 Mon Sep 17 00:00:00 2001 From: Daniel Young Lee Date: Thu, 3 Feb 2022 13:06:03 -0800 Subject: [PATCH 7/9] Temporarily add debug message to help debug ci test issues. --- scripts/bin-test/run.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/bin-test/run.sh b/scripts/bin-test/run.sh index f1ff75142..7045b9188 100755 --- a/scripts/bin-test/run.sh +++ b/scripts/bin-test/run.sh @@ -12,6 +12,9 @@ for f in scripts/bin-test/sources/*; do fi done +## DEBUG +ls -la scripts/bin-test/sources/commonjs/node_modules + mocha \ --file ./scripts/bin-test/mocha-setup.ts \ ./scripts/bin-test/test.ts From 31d3506f0c2a803b5be9358c462fc640d959d60d Mon Sep 17 00:00:00 2001 From: Daniel Young Lee Date: Thu, 3 Feb 2022 13:09:37 -0800 Subject: [PATCH 8/9] Try not using sudo npm link. --- scripts/bin-test/run.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/bin-test/run.sh b/scripts/bin-test/run.sh index 7045b9188..f92ad2cda 100755 --- a/scripts/bin-test/run.sh +++ b/scripts/bin-test/run.sh @@ -3,7 +3,8 @@ set -ex # Immediately exit on failure # Globally link the locally built Functions SDK for the testing framework. npm run build -./scripts/bin-test/npm-link.sh +#./scripts/bin-test/npm-link.sh +npm link # Link local SDK to all test sources. for f in scripts/bin-test/sources/*; do From 3767b61357f66f2a7b555044d9327e7143429d88 Mon Sep 17 00:00:00 2001 From: Daniel Young Lee Date: Thu, 3 Feb 2022 13:13:46 -0800 Subject: [PATCH 9/9] Fix integration test in CI env. --- .github/workflows/test.yaml | 3 ++- scripts/bin-test/npm-link.sh | 10 ---------- scripts/bin-test/run.sh | 3 +-- 3 files changed, 3 insertions(+), 13 deletions(-) delete mode 100755 scripts/bin-test/npm-link.sh diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index e6d79e47a..75cee99b0 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -16,6 +16,7 @@ jobs: - 10.x - 12.x - 14.x + - 16.x steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 @@ -37,9 +38,9 @@ jobs: strategy: matrix: node-version: - - 10.x - 12.x - 14.x + - 16.x steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 diff --git a/scripts/bin-test/npm-link.sh b/scripts/bin-test/npm-link.sh deleted file mode 100755 index 26e3276d2..000000000 --- a/scripts/bin-test/npm-link.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -if [ "$CI" = "true" ]; then - echo "Running sudo npm link..." - sudo npm link -else - echo "Running npm link..." - npm link -fi diff --git a/scripts/bin-test/run.sh b/scripts/bin-test/run.sh index f92ad2cda..c3e3da673 100755 --- a/scripts/bin-test/run.sh +++ b/scripts/bin-test/run.sh @@ -1,9 +1,8 @@ #!/bin/bash set -ex # Immediately exit on failure -# Globally link the locally built Functions SDK for the testing framework. +# Link the Functions SDK for the testing environment. npm run build -#./scripts/bin-test/npm-link.sh npm link # Link local SDK to all test sources.