From e13340c96734efb019a40faee51b8b8fc622d851 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Mon, 13 Nov 2017 12:34:47 -0800 Subject: [PATCH 01/24] Update dependencies --- functions/background/package.json | 10 +++++----- functions/datastore/package.json | 6 +++--- functions/errorreporting/package.json | 2 +- functions/gcs/package.json | 10 +++++----- functions/helloworld/package.json | 10 +++++----- functions/http/package.json | 6 +++--- functions/imagemagick/package.json | 8 ++++---- functions/log/package.json | 10 +++++----- functions/pubsub/package.json | 8 ++++---- functions/sendgrid/package.json | 12 ++++++------ functions/slack/package.json | 8 ++++---- functions/spanner/package.json | 8 ++++---- functions/uuid/package.json | 6 +++--- 13 files changed, 52 insertions(+), 52 deletions(-) diff --git a/functions/background/package.json b/functions/background/package.json index bba4020599..212f354255 100644 --- a/functions/background/package.json +++ b/functions/background/package.json @@ -17,14 +17,14 @@ "test": "ava -T 20s --verbose test/*.test.js" }, "dependencies": { - "request": "2.81.0", - "request-promise": "4.2.1" + "request": "2.83.0", + "request-promise": "4.2.2" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.21.0", + "@google-cloud/nodejs-repo-tools": "2.1.0", + "ava": "0.23.0", "proxyquire": "1.8.0", - "sinon": "3.2.0" + "sinon": "4.0.2" }, "cloud-repo-tools": { "requiresKeyFile": true, diff --git a/functions/datastore/package.json b/functions/datastore/package.json index 4914ac3ee0..6e2dd6c33c 100644 --- a/functions/datastore/package.json +++ b/functions/datastore/package.json @@ -20,10 +20,10 @@ "@google-cloud/datastore": "1.1.0" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.21.0", + "@google-cloud/nodejs-repo-tools": "2.1.0", + "ava": "0.23.0", "proxyquire": "1.8.0", - "sinon": "3.2.0" + "sinon": "4.0.2" }, "cloud-repo-tools": { "requiresKeyFile": true, diff --git a/functions/errorreporting/package.json b/functions/errorreporting/package.json index 9e20871d77..abfd6151bc 100644 --- a/functions/errorreporting/package.json +++ b/functions/errorreporting/package.json @@ -6,6 +6,6 @@ "author": "Google Inc.", "main": "./index.js", "dependencies": { - "@google-cloud/logging": "1.0.2" + "@google-cloud/logging": "1.1.1" } } diff --git a/functions/gcs/package.json b/functions/gcs/package.json index 9b137d6d6e..7eb33730c6 100644 --- a/functions/gcs/package.json +++ b/functions/gcs/package.json @@ -17,14 +17,14 @@ "test": "ava -T 20s --verbose test/*.test.js" }, "dependencies": { - "@google-cloud/storage": "1.2.1", - "request": "2.81.0" + "@google-cloud/storage": "1.4.0", + "request": "2.83.0" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.21.0", + "@google-cloud/nodejs-repo-tools": "2.1.0", + "ava": "0.23.0", "proxyquire": "1.8.0", - "sinon": "3.2.0" + "sinon": "4.0.2" }, "cloud-repo-tools": { "requiresKeyFile": true, diff --git a/functions/helloworld/package.json b/functions/helloworld/package.json index 4a896d4ba2..cdb63c6aca 100644 --- a/functions/helloworld/package.json +++ b/functions/helloworld/package.json @@ -17,15 +17,15 @@ "test": "ava -T 20s --verbose test/*.test.js" }, "dependencies": { - "@google-cloud/debug-agent": "2.1.3", - "pug": "2.0.0-rc.3", + "@google-cloud/debug-agent": "2.2.2", + "pug": "2.0.0-rc.4", "safe-buffer": "5.1.1" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.21.0", + "@google-cloud/nodejs-repo-tools": "2.1.0", + "ava": "0.23.0", "proxyquire": "1.8.0", - "sinon": "3.2.0" + "sinon": "4.0.2" }, "cloud-repo-tools": { "requiresKeyFile": true, diff --git a/functions/http/package.json b/functions/http/package.json index 634d2da900..e2f62fc186 100644 --- a/functions/http/package.json +++ b/functions/http/package.json @@ -17,10 +17,10 @@ "test": "ava -T 20s --verbose test/*.test.js" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.21.0", + "@google-cloud/nodejs-repo-tools": "2.1.0", + "ava": "0.23.0", "proxyquire": "1.8.0", - "sinon": "3.2.0" + "sinon": "4.0.2" }, "dependencies": { "safe-buffer": "5.1.1" diff --git a/functions/imagemagick/package.json b/functions/imagemagick/package.json index 9486fdc204..2f95f6e97a 100644 --- a/functions/imagemagick/package.json +++ b/functions/imagemagick/package.json @@ -17,14 +17,14 @@ "test": "ava -T 20s --verbose test/*.test.js" }, "dependencies": { - "@google-cloud/storage": "1.2.1", + "@google-cloud/storage": "1.4.0", "@google-cloud/vision": "0.12.0" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.21.0", + "@google-cloud/nodejs-repo-tools": "2.1.0", + "ava": "0.23.0", "proxyquire": "1.8.0", - "sinon": "3.2.0" + "sinon": "4.0.2" }, "cloud-repo-tools": { "requiresKeyFile": true, diff --git a/functions/log/package.json b/functions/log/package.json index 9686720437..24439c508d 100644 --- a/functions/log/package.json +++ b/functions/log/package.json @@ -17,14 +17,14 @@ "test": "ava -T 20s --verbose test/*.test.js" }, "dependencies": { - "@google-cloud/logging": "1.0.5", - "@google-cloud/monitoring": "0.2.3" + "@google-cloud/logging": "1.1.1", + "@google-cloud/monitoring": "0.4.1" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.21.0", + "@google-cloud/nodejs-repo-tools": "2.1.0", + "ava": "0.23.0", "proxyquire": "1.8.0", - "sinon": "3.2.0" + "sinon": "4.0.2" }, "cloud-repo-tools": { "requiresKeyFile": true, diff --git a/functions/pubsub/package.json b/functions/pubsub/package.json index 65adf0d032..1bdf0eb81a 100644 --- a/functions/pubsub/package.json +++ b/functions/pubsub/package.json @@ -17,14 +17,14 @@ "test": "ava -T 20s --verbose test/*.test.js" }, "dependencies": { - "@google-cloud/pubsub": "0.13.2", + "@google-cloud/pubsub": "0.14.5", "safe-buffer": "5.1.1" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.21.0", + "@google-cloud/nodejs-repo-tools": "2.1.0", + "ava": "0.23.0", "proxyquire": "1.8.0", - "sinon": "3.2.0" + "sinon": "4.0.2" }, "cloud-repo-tools": { "requiresKeyFile": true, diff --git a/functions/sendgrid/package.json b/functions/sendgrid/package.json index 9c8494921e..1c91441313 100644 --- a/functions/sendgrid/package.json +++ b/functions/sendgrid/package.json @@ -17,17 +17,17 @@ "test": "ava -T 20s --verbose test/*.test.js" }, "dependencies": { - "@google-cloud/bigquery": "0.9.6", - "@google-cloud/storage": "1.2.1", + "@google-cloud/bigquery": "0.10.0", + "@google-cloud/storage": "1.4.0", "safe-buffer": "5.1.1", - "sendgrid": "5.2.2", + "sendgrid": "5.2.3", "uuid": "3.1.0" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.21.0", + "@google-cloud/nodejs-repo-tools": "2.1.0", + "ava": "0.23.0", "proxyquire": "1.8.0", - "sinon": "3.2.0" + "sinon": "4.0.2" }, "cloud-repo-tools": { "requiresKeyFile": true, diff --git a/functions/slack/package.json b/functions/slack/package.json index cf92ff8555..ba2cd6f43c 100644 --- a/functions/slack/package.json +++ b/functions/slack/package.json @@ -17,13 +17,13 @@ "test": "ava -T 20s --verbose test/*.test.js" }, "dependencies": { - "googleapis": "20.1.0" + "googleapis": "22.2.0" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.21.0", + "@google-cloud/nodejs-repo-tools": "2.1.0", + "ava": "0.23.0", "proxyquire": "1.8.0", - "sinon": "3.2.0" + "sinon": "4.0.2" }, "cloud-repo-tools": { "requiresKeyFile": true, diff --git a/functions/spanner/package.json b/functions/spanner/package.json index 22aaf78bf2..6dc438f9d2 100644 --- a/functions/spanner/package.json +++ b/functions/spanner/package.json @@ -17,13 +17,13 @@ "test": "ava -T 20s --verbose test/*.test.js" }, "dependencies": { - "@google-cloud/spanner": "0.7.1" + "@google-cloud/spanner": "0.8.0" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.21.0", + "@google-cloud/nodejs-repo-tools": "2.1.0", + "ava": "0.23.0", "proxyquire": "1.8.0", - "sinon": "3.2.0" + "sinon": "4.0.2" }, "cloud-repo-tools": { "requiresKeyFile": true, diff --git a/functions/uuid/package.json b/functions/uuid/package.json index aa69fd79ba..cf5842b63b 100644 --- a/functions/uuid/package.json +++ b/functions/uuid/package.json @@ -20,9 +20,9 @@ "uuid": "3.1.0" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.21.0", - "sinon": "3.2.0" + "@google-cloud/nodejs-repo-tools": "2.1.0", + "ava": "0.23.0", + "sinon": "4.0.2" }, "cloud-repo-tools": { "requiresKeyFile": true, From d60d9f847c82d0dab000543ae157869225eaf15b Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Mon, 20 Nov 2017 13:28:27 -0800 Subject: [PATCH 02/24] Add functions tests for Kokoro --- .kokoro/functions-helloworld.sh | 59 +++++ functions/helloworld/index.js | 13 -- functions/helloworld/package.json | 11 +- functions/helloworld/test/index.test.js | 292 +++++++++++++----------- functions/helloworld/test/test.txt | 1 + 5 files changed, 223 insertions(+), 153 deletions(-) create mode 100644 .kokoro/functions-helloworld.sh create mode 100644 functions/helloworld/test/test.txt diff --git a/.kokoro/functions-helloworld.sh b/.kokoro/functions-helloworld.sh new file mode 100644 index 0000000000..46c181ad8f --- /dev/null +++ b/.kokoro/functions-helloworld.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +export GCLOUD_PROJECT=nodejs-docs-samples +STAGE_BUCKET=$GCLOUD_PROJECT +GCP_REGION=us-central1 +TOPIC=integration-test-functions +export FUNCTIONS_BASE_URL=https://${GCP_REGION}-${GCLOUD_PROJECT}.cloudfunctions.net + +# Configure gcloud +export GCLOUD_PROJECT=nodejs-getting-started-tests +export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/secrets-key.json +gcloud auth activate-service-account --key-file "$GOOGLE_APPLICATION_CREDENTIALS" +gcloud config set project nodejs-getting-started-tests + +function cleanup { + CODE=$? + + gcloud beta functions deploy helloworld -q + gcloud beta functions deploy helloGET -q + gcloud beta functions deploy helloBackground -q + gcloud beta functions deploy helloPubSub -q + gcloud beta functions deploy helloGCS -q + gcloud beta functions deploy helloError -q + gcloud beta functions deploy helloError2 -q + gcloud beta functions deploy helloError3 -q + gcloud beta functions deploy helloTemplate -q +} +trap cleanup EXIT + +set -e + +# Deploy all hello-world functions +# (If any step fails, the entire test run should fail) +gcloud beta functions deploy helloworld --trigger-http --stage-bucket $STAGE_BUCKET +gcloud beta functions deploy helloGET --trigger-http --stage-bucket $STAGE_BUCKET +gcloud beta functions deploy helloBackground --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC +gcloud beta functions deploy helloPubSub --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC +gcloud beta functions deploy helloGCS --stage-bucket $STAGE_BUCKET --trigger-bucket integration-test-functions +gcloud beta functions deploy helloError --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC +gcloud beta functions deploy helloError2 --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC +gcloud beta functions deploy helloError3 --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC +gcloud beta functions deploy helloTemplate --stage-bucket $STAGE_BUCKET --trigger-http + +# Run system tests +repo-tools test \ No newline at end of file diff --git a/functions/helloworld/index.js b/functions/helloworld/index.js index 0969f2394f..17b9f5a224 100644 --- a/functions/helloworld/index.js +++ b/functions/helloworld/index.js @@ -21,19 +21,6 @@ const Buffer = require('safe-buffer').Buffer; require('@google-cloud/debug-agent').start(); // [END functions_helloworld_debug] -// [START functions_helloworld] -/** - * Cloud Function. - * - * @param {object} event The Cloud Functions event. - * @param {function} callback The callback function. - */ -exports.helloWorld = function helloWorld (event, callback) { - console.log(`My Cloud Function: ${event.data.message}`); - callback(); -}; -// [END functions_helloworld] - // [START functions_helloworld_get] /** * HTTP Cloud Function. diff --git a/functions/helloworld/package.json b/functions/helloworld/package.json index cdb63c6aca..8deaa7f6a3 100644 --- a/functions/helloworld/package.json +++ b/functions/helloworld/package.json @@ -23,12 +23,19 @@ }, "devDependencies": { "@google-cloud/nodejs-repo-tools": "2.1.0", + "@google-cloud/pubsub": "^0.14.8", + "@google-cloud/storage": "^1.4.0", "ava": "0.23.0", "proxyquire": "1.8.0", - "sinon": "4.0.2" + "sinon": "4.0.2", + "supertest": "^3.0.0", + "uuid": "^3.1.0" }, "cloud-repo-tools": { "requiresKeyFile": true, - "requiresProjectId": true + "requiresProjectId": true, + "requiredEnvVars": [ + "FUNCTIONS_BASE_URL" + ] } } diff --git a/functions/helloworld/test/index.test.js b/functions/helloworld/test/index.test.js index 66d0bf96ff..46e6dbb44f 100644 --- a/functions/helloworld/test/index.test.js +++ b/functions/helloworld/test/index.test.js @@ -14,10 +14,24 @@ */ const Buffer = require('safe-buffer').Buffer; +const path = require('path'); const proxyquire = require(`proxyquire`).noCallThru(); const sinon = require(`sinon`); const test = require(`ava`); const tools = require(`@google-cloud/nodejs-repo-tools`); +const supertest = require(`supertest`); +const uuid = require(`uuid`); + +const pubsub = require(`@google-cloud/pubsub`)(); +const storage = require(`@google-cloud/storage`)(); + +const baseCmd = `gcloud beta functions`; +const topicName = `integration-test-functions`; + +const localFileName = `test.txt`; +const fileName = `test-${uuid.v4()}.txt`; + +const BASE_URL = process.env.FUNCTIONS_BASE_URL; const program = proxyquire(`../`, { '@google-cloud/debug-agent': { @@ -25,12 +39,16 @@ const program = proxyquire(`../`, { } }); +const bucketName = `integration-test-functions`; +const bucket = storage.bucket(bucketName); + +test.before(tools.checkCredentials); + test.beforeEach(tools.stubConsole); test.afterEach.always(tools.restoreConsole); -test.serial(`helloworld: should log a message`, (t) => { +test(`helloworld: should log a message`, (t) => { const expectedMsg = `My Cloud Function: hi`; - const callback = sinon.stub(); program.helloWorld({ data: { @@ -44,184 +62,182 @@ test.serial(`helloworld: should log a message`, (t) => { t.deepEqual(callback.firstCall.args, []); }); -test.cb.serial(`helloGET: should print hello world`, (t) => { - const expectedMsg = `Hello World!`; - - program.helloGET({}, { - send: (message) => { - t.is(message, expectedMsg); - t.end(); - } - }); +test.cb(`helloGET: should print hello world`, (t) => { + supertest(BASE_URL) + .get(`/helloGET`) + .expect(200) + .expect((response) => { + t.is(response.text, `Hello World!`); + }) + .end(t.end); }); -test.cb.serial(`helloHttp: should print a name`, (t) => { - const expectedMsg = `Hello John!`; +test.cb(`helloHttp: should print a name`, (t) => { + supertest(BASE_URL) + .post(`/helloHttp`) + .send({ name: 'John' }) + .expect(200) + .expect((response) => { + t.is(response.text, 'Hello John!'); + }) + .end(t.end); +}); - program.helloHttp({ - body: { - name: `John` - } - }, { - send: (message) => { - t.is(message, expectedMsg); - t.end(); - } - }); +test.cb(`helloHttp: should print hello world`, (t) => { + supertest(BASE_URL) + .get(`/helloHttp`) + .expect(200) + .expect((response) => { + t.is(response.text, `Hello World!`); + }) + .end(t.end); }); -test.cb.serial(`helloHttp: should print hello world`, (t) => { - const expectedMsg = `Hello World!`; +test(`helloBackground: should print a name`, async (t) => { + const data = JSON.stringify({name: 'John'}); + const output = await tools.runAsync(`${baseCmd} call helloBackground --data '${data}'`) - program.helloHttp({ - body: {} - }, { - send: (message) => { - t.is(message, expectedMsg); - t.end(); - } - }); + t.true(output.includes('Hello John!')); }); -test.serial(`helloBackground: should print a name`, (t) => { - const expectedMsg = `Hello John!`; - const callback = sinon.stub(); +test(`helloBackground: should print hello world`, async (t) => { + const output = await tools.runAsync(`${baseCmd} call helloBackground --data '{}'`) - program.helloBackground({ - data: { - name: `John` - } - }, callback); - - t.deepEqual(callback.callCount, 1); - t.deepEqual(callback.firstCall.args, [null, expectedMsg]); + t.true(output.includes('Hello World!')); }); -test.serial(`helloBackground: should print hello world`, (t) => { - const expectedMsg = `Hello World!`; - const callback = sinon.stub(); +test(`helloPubSub: should print a name`, async (t) => { + t.plan(0); + const startTime = new Date(Date.now()).toISOString(); + const name = uuid.v4(); - program.helloBackground({ data: {} }, callback); + // Publish to pub/sub topic + const topic = pubsub.topic(topicName); + const publisher = topic.publisher(); + await publisher.publish(Buffer.from(name)); - t.deepEqual(callback.callCount, 1); - t.deepEqual(callback.firstCall.args, [null, expectedMsg]); + // Check logs + await tools.tryTest(async (assert) => { + const logs = await tools.runAsync(`${baseCmd} logs read helloPubSub --start-time ${startTime}`); + assert(logs.includes('Hello, ${name}!')); + }); }); -test.serial(`helloPubSub: should print a name`, (t) => { - const expectedMsg = `Hello, Bob!`; - const callback = sinon.stub(); +test(`helloPubSub: should print hello world`, async (t) => { + t.plan(0); + const startTime = new Date(Date.now()).toISOString(); - program.helloPubSub({ - data: { - data: Buffer.from(`Bob`).toString(`base64`) - } - }, callback); + // Publish to pub/sub topic + const topic = pubsub.topic(topicName); + const publisher = topic.publisher(); + await publisher.publish(Buffer.from(''), { a: 'b' }); - t.deepEqual(console.log.callCount, 1); - t.deepEqual(console.log.firstCall.args, [expectedMsg]); - t.deepEqual(callback.callCount, 1); - t.deepEqual(callback.firstCall.args, []); + // Check logs + await tools.tryTest(async (assert) => { + const logs = await tools.runAsync(`${baseCmd} logs read helloPubSub --start-time ${startTime}`); + assert(logs.includes('Hello, World!')); + }); }); -test.serial(`helloPubSub: should print hello world`, (t) => { - const expectedMsg = `Hello, World!`; - const callback = sinon.stub(); +test.serial(`helloGCS: should print uploaded message`, async (t) => { + t.plan(0); + const startTime = new Date(Date.now()).toISOString(); - program.helloPubSub({ data: {} }, callback); + // Upload file + const filepath = path.join(__dirname, localFileName); + await bucket.upload(filepath, { + destination: fileName + }); - t.deepEqual(console.log.callCount, 1); - t.deepEqual(console.log.firstCall.args, [expectedMsg]); - t.deepEqual(callback.callCount, 1); - t.deepEqual(callback.firstCall.args, []); + // Check logs + await tools.tryTest(async (assert) => { + const logs = await tools.runAsync(`${baseCmd} logs read helloPubSub --start-time ${startTime}`); + assert(logs.includes('File ${fileName} uploaded')); + }); }); -test.serial(`helloGCS: should print uploaded message`, (t) => { - const expectedMsg = `File foo uploaded.`; - const callback = sinon.stub(); +test.serial(`helloGCS: should print metadata updated message`, async (t) => { + t.plan(0); + const startTime = new Date(Date.now()).toISOString(); - program.helloGCS({ - data: { - name: `foo`, - resourceState: `exists`, - metageneration: `1` - } - }, callback); + // Update file metadata + await bucket.setMetadata(fileName, { foo: `bar` }); - t.deepEqual(console.log.callCount, 1); - t.deepEqual(console.log.firstCall.args, [expectedMsg]); - t.deepEqual(callback.callCount, 1); - t.deepEqual(callback.firstCall.args, []); + // Check logs + await tools.tryTest(async (assert) => { + const logs = await tools.runAsync(`${baseCmd} logs read helloPubSub --start-time ${startTime}`); + assert(logs.includes('File ${fileName} metadata updated')); + }); }); -test.serial(`helloGCS: should print metadata updated message`, (t) => { - const expectedMsg = `File foo metadata updated.`; - const callback = sinon.stub(); +test.serial(`helloGCS: should print deleted message`, async (t) => { + t.plan(0); + const startTime = new Date(Date.now()).toISOString(); - program.helloGCS({ - data: { - name: `foo`, - resourceState: `exists`, - metageneration: `2` - } - }, callback); + // Delete file + bucket.delete(fileName); - t.deepEqual(console.log.callCount, 1); - t.deepEqual(console.log.firstCall.args, [expectedMsg]); - t.deepEqual(callback.callCount, 1); - t.deepEqual(callback.firstCall.args, []); + // Check logs + await tools.tryTest(async (assert) => { + const logs = await tools.runAsync(`${baseCmd} logs read helloPubSub --start-time ${startTime}`); + assert(logs.includes('File ${fileName} deleted')); + }); }); -test.serial(`helloGCS: should print deleted message`, (t) => { - const expectedMsg = `File foo deleted.`; - const callback = sinon.stub(); +test(`helloError: should throw an error`, async (t) => { + t.plan(0); + const startTime = new Date(Date.now()).toISOString(); - program.helloGCS({ - data: { - name: `foo`, - resourceState: `not_exists` - } - }, callback); + // Publish to pub/sub topic + const topic = pubsub.topic(topicName); + const publisher = topic.publisher(); + await publisher.publish(Buffer.from(''), { a: 'b' }); - t.deepEqual(console.log.callCount, 1); - t.deepEqual(console.log.firstCall.args, [expectedMsg]); - t.deepEqual(callback.callCount, 1); - t.deepEqual(callback.firstCall.args, []); + // Check logs + await tools.tryTest(async (assert) => { + const logs = await tools.runAsync(`${baseCmd} logs read helloError --start-time ${startTime}`); + assert(logs.includes('Error: I failed you')); + }); }); -test.serial(`helloError: should throw an error`, (t) => { - const expectedMsg = `I failed you`; +test(`helloError2: should throw a value`, async (t) => { + t.plan(0); + const startTime = new Date(Date.now()).toISOString(); - t.throws(() => { - program.helloError(); - }, Error, expectedMsg); -}); + // Publish to pub/sub topic + const topic = pubsub.topic(topicName); + const publisher = topic.publisher(); + await publisher.publish(Buffer.from(''), { a: 'b' }); -test.serial(`helloError2: should throw a value`, (t) => { - t.throws(() => { - program.helloError2(); + // Check logs + await tools.tryTest(async (assert) => { + const logs = await tools.runAsync(`${baseCmd} logs read helloError2 --start-time ${startTime}`); + assert(logs.includes(' 1\n')); }); }); -test.serial(`helloError3: callback shoud return an errback value`, (t) => { - const expectedMsg = `I failed you`; - const callback = sinon.stub(); +test(`helloError3: callback should return an errback value`, async (t) => { + t.plan(0); + const startTime = new Date(Date.now()).toISOString(); - program.helloError3({}, callback); + // Publish to pub/sub topic + const topic = pubsub.topic(topicName); + const publisher = topic.publisher(); + await publisher.publish(Buffer.from(''), { a: 'b' }); - t.deepEqual(callback.callCount, 1); - t.deepEqual(callback.firstCall.args, [expectedMsg]); + // Check logs + await tools.tryTest(async (assert) => { + const logs = await tools.runAsync(`${baseCmd} logs read helloError3 --start-time ${startTime}`); + assert(logs.includes(' I failed you\n')); + }); }); -test.serial(`helloTemplate: should render the html`, async (t) => { - const req = {}; - const res = {}; - res.send = sinon.stub().returnsThis(); - res.end = sinon.stub().returnsThis(); - - program.helloTemplate(req, res); - - t.is(res.send.callCount, 1); - t.is(res.send.getCall(0).args.length, 1); - t.is(res.send.getCall(0).args[0].includes('

Cloud Functions Template Sample

'), true); - t.is(res.end.callCount, 1); +test.cb(`helloTemplate: should render the html`, (t) => { + supertest(BASE_URL) + .get(`/helloTemplate`) + .expect(200) + .expect((response) => { + t.regex(response.text, /

Cloud Functions Template Sample<\/h1>/); + }) + .end(t.end); }); diff --git a/functions/helloworld/test/test.txt b/functions/helloworld/test/test.txt new file mode 100644 index 0000000000..16b14f5da9 --- /dev/null +++ b/functions/helloworld/test/test.txt @@ -0,0 +1 @@ +test file From cdf127e5179252476d1c2f591eed5806a21c17ef Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Mon, 20 Nov 2017 13:49:52 -0800 Subject: [PATCH 03/24] Start converting functions tests to Kokoro --- .kokoro/common.cfg | 13 +++++++++++++ .kokoro/functions-helloworld.cfg | 10 ++++++++++ .kokoro/functions-helloworld.sh | 0 .kokoro/trampoline.sh | 15 +++++++++++++++ 4 files changed, 38 insertions(+) create mode 100644 .kokoro/common.cfg create mode 100644 .kokoro/functions-helloworld.cfg mode change 100644 => 100755 .kokoro/functions-helloworld.sh create mode 100755 .kokoro/trampoline.sh diff --git a/.kokoro/common.cfg b/.kokoro/common.cfg new file mode 100644 index 0000000000..881f2f9de4 --- /dev/null +++ b/.kokoro/common.cfg @@ -0,0 +1,13 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Download trampoline resources. These will be in ${KOKORO_GFILE_DIR} +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" + +# All builds use the trampoline script to run in docker. +build_file: "nodejs-docs-samples/.kokoro/trampoline.sh" + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-docs-samples/nodejs" +} \ No newline at end of file diff --git a/.kokoro/functions-helloworld.cfg b/.kokoro/functions-helloworld.cfg new file mode 100644 index 0000000000..1ae3ec4590 --- /dev/null +++ b/.kokoro/functions-helloworld.cfg @@ -0,0 +1,10 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Download secrets from Cloud Storage. +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/nodejs-docs-samples" + +# Tell the trampoline which build file to use. +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/nodejs-docs-samples/.kokoro/functions-tests.sh" +} \ No newline at end of file diff --git a/.kokoro/functions-helloworld.sh b/.kokoro/functions-helloworld.sh old mode 100644 new mode 100755 diff --git a/.kokoro/trampoline.sh b/.kokoro/trampoline.sh new file mode 100755 index 0000000000..0ac4f9af0f --- /dev/null +++ b/.kokoro/trampoline.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py" From 9a266f88d25da745ee1a51e523ae3748a9613fa0 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Tue, 21 Nov 2017 16:13:47 -0800 Subject: [PATCH 04/24] Fix typo --- .kokoro/functions-helloworld.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.kokoro/functions-helloworld.cfg b/.kokoro/functions-helloworld.cfg index 1ae3ec4590..7d018ff1e2 100644 --- a/.kokoro/functions-helloworld.cfg +++ b/.kokoro/functions-helloworld.cfg @@ -6,5 +6,5 @@ gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/nodejs-docs-samples" # Tell the trampoline which build file to use. env_vars: { key: "TRAMPOLINE_BUILD_FILE" - value: "github/nodejs-docs-samples/.kokoro/functions-tests.sh" -} \ No newline at end of file + value: "github/nodejs-docs-samples/.kokoro/functions-helloworld.sh" +} From 5aa4a1599f0c0b631f007ac01e8396979726dc58 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Tue, 28 Nov 2017 13:10:49 -0800 Subject: [PATCH 05/24] Systemify datastore tests --- functions/datastore/index.js | 10 +- functions/datastore/package.json | 3 +- functions/datastore/test/index.test.js | 319 ++++++++++--------------- 3 files changed, 139 insertions(+), 193 deletions(-) diff --git a/functions/datastore/index.js b/functions/datastore/index.js index 6ff99ff14d..04be4cbf5e 100644 --- a/functions/datastore/index.js +++ b/functions/datastore/index.js @@ -69,7 +69,7 @@ exports.set = function set (req, res) { .then(() => res.status(200).send(`Entity ${key.path.join('/')} saved.`)) .catch((err) => { console.error(err); - res.status(500).send(err); + res.status(500).send(err.message); return Promise.reject(err); }); }; @@ -92,7 +92,7 @@ exports.get = function get (req, res) { return datastore.get(key) .then(([entity]) => { // The get operation will not fail for a non-existent entity, it just - // returns null. + // returns an empty dictionary. if (!entity) { throw new Error(`No entity found for key ${key.path.join('/')}.`); } @@ -101,7 +101,7 @@ exports.get = function get (req, res) { }) .catch((err) => { console.error(err); - res.status(500).send(err); + res.status(500).send(err.message); return Promise.reject(err); }); }; @@ -122,11 +122,13 @@ exports.del = function del (req, res) { const key = getKeyFromRequestData(req.body); // Deletes the entity + // The delete operation will not fail for a non-existent entity, it just + // doesn't delete anything return datastore.delete(key) .then(() => res.status(200).send(`Entity ${key.path.join('/')} deleted.`)) .catch((err) => { console.error(err); res.status(500).send(err); - return Promise.reject(err); + return Promise.reject(err.message); }); }; diff --git a/functions/datastore/package.json b/functions/datastore/package.json index 6e2dd6c33c..c672c405a6 100644 --- a/functions/datastore/package.json +++ b/functions/datastore/package.json @@ -17,7 +17,8 @@ "test": "ava -T 20s --verbose test/*.test.js" }, "dependencies": { - "@google-cloud/datastore": "1.1.0" + "@google-cloud/datastore": "1.1.0", + "supertest": "^3.0.0" }, "devDependencies": { "@google-cloud/nodejs-repo-tools": "2.1.0", diff --git a/functions/datastore/test/index.test.js b/functions/datastore/test/index.test.js index ecbfa01328..a167dbe6ce 100644 --- a/functions/datastore/test/index.test.js +++ b/functions/datastore/test/index.test.js @@ -15,230 +15,173 @@ 'use strict'; -const proxyquire = require(`proxyquire`).noCallThru(); -const sinon = require(`sinon`); const test = require(`ava`); -const tools = require(`@google-cloud/nodejs-repo-tools`); +const Datastore = require(`@google-cloud/datastore`); +const datastore = Datastore(); +const program = require(`../`); +const uuid = require(`uuid`); + +const supertest = require(`supertest`); +const request = supertest(process.env.BASE_URL); const NAME = `sampletask1`; -const KIND = `Task`; +const KIND = `Task-${uuid.v4()}`; const VALUE = { description: `Buy milk` }; -function getSample () { - const key = { - kind: KIND, - name: NAME, - path: [KIND, NAME] - }; - const entity = { - key: key, - data: VALUE - }; - const datastore = { - delete: sinon.stub().returns(Promise.resolve()), - get: sinon.stub().returns(Promise.resolve([entity])), - key: sinon.stub().returns(key), - save: sinon.stub().returns(Promise.resolve()) - }; - const DatastoreMock = sinon.stub().returns(datastore); - - return { - program: proxyquire(`../`, { - '@google-cloud/datastore': DatastoreMock - }), - mocks: { - Datastore: DatastoreMock, - datastore: datastore, - key: key, - entity: entity, - req: { - body: { - kind: KIND, - key: NAME, - value: VALUE - } - }, - res: { - status: sinon.stub().returnsThis(), - send: sinon.stub().returnsThis() - } - } - }; -} - -test.beforeEach(tools.stubConsole); -test.afterEach.always(tools.restoreConsole); - -test.serial(`set: Set fails without a value`, (t) => { - const expectedMsg = `Value not provided. Make sure you have a "value" property in your request`; - const sample = getSample(); +const errorMsg = msg => `${msg} not provided. Make sure you have a "${msg.toLowerCase()}" property in your request`; +test.serial(`set: Fails without a value`, (t) => { + const req = { + body: {} + }; t.throws(() => { - sample.mocks.req.body.value = undefined; - sample.program.set(sample.mocks.req, sample.mocks.res); - }, Error, expectedMsg); + program.set(req, null); + }, errorMsg(`Value`)); }); -test.serial(`set: Set fails without a key`, (t) => { - const expectedMsg = `Key not provided. Make sure you have a "key" property in your request`; - const sample = getSample(); - +test.serial(`set: Fails without a key`, (t) => { + const req = { + body: { + value: VALUE + } + }; t.throws(() => { - sample.mocks.req.body.key = undefined; - sample.program.set(sample.mocks.req, sample.mocks.res); - }, Error, expectedMsg); + program.set(req, null); + }, errorMsg(`Key`)); }); -test.serial(`set: Set fails without a kind`, (t) => { - const expectedMsg = `Kind not provided. Make sure you have a "kind" property in your request`; - const sample = getSample(); - +test.serial(`set: Fails without a kind`, (t) => { + const req = { + body: { + key: NAME, + value: VALUE + } + }; t.throws(() => { - sample.mocks.req.body.kind = undefined; - sample.program.set(sample.mocks.req, sample.mocks.res); - }, Error, expectedMsg); -}); - -test.serial(`set: Handles save error`, async (t) => { - const error = new Error(`error`); - const sample = getSample(); - - sample.mocks.datastore.save.returns(Promise.reject(error)); - - const err = await t.throws(sample.program.set(sample.mocks.req, sample.mocks.res)); - t.deepEqual(err, error); - t.deepEqual(console.error.callCount, 1); - t.deepEqual(console.error.firstCall.args, [error]); - t.deepEqual(sample.mocks.res.status.callCount, 1); - t.deepEqual(sample.mocks.res.status.firstCall.args, [500]); - t.deepEqual(sample.mocks.res.send.callCount, 1); - t.deepEqual(sample.mocks.res.send.firstCall.args, [error]); + program.set(req, null); + }, Error, errorMsg(`Kind`)); }); -test.serial(`set: Set saves an entity`, async (t) => { - const expectedMsg = `Entity ${KIND}/${NAME} saved.`; - const sample = getSample(); - - await sample.program.set(sample.mocks.req, sample.mocks.res); - t.deepEqual(sample.mocks.datastore.save.callCount, 1); - t.deepEqual(sample.mocks.datastore.save.firstCall.args, [sample.mocks.entity]); - t.deepEqual(sample.mocks.res.status.callCount, 1); - t.deepEqual(sample.mocks.res.status.firstCall.args, [200]); - t.deepEqual(sample.mocks.res.send.callCount, 1); - t.deepEqual(sample.mocks.res.send.firstCall.args, [expectedMsg]); +test.serial.cb(`set: Saves an entity`, (t) => { + request + .post(`/set`) + .send({ + kind: KIND, + key: NAME, + value: VALUE + }) + .expect(200) + .expect((response) => { + t.true(response.text.includes(`Entity ${KIND}/${NAME} saved`)); + }) + .end(t.end); }); -test.serial(`get: Get fails without a key`, (t) => { - const expectedMsg = `Key not provided. Make sure you have a "key" property in your request`; - const sample = getSample(); - +test.serial(`get: Fails without a key`, (t) => { + const req = { + body: {} + }; t.throws(() => { - sample.mocks.req.body.key = undefined; - sample.program.get(sample.mocks.req, sample.mocks.res); - }, Error, expectedMsg); + program.get(req, null); + }, Error, errorMsg(`Key`)); }); -test.serial(`get: Get fails without a kind`, (t) => { - const expectedMsg = `Kind not provided. Make sure you have a "kind" property in your request`; - const sample = getSample(); - +test.serial(`get: Fails without a kind`, (t) => { + const req = { + body: { + key: NAME + } + }; t.throws(() => { - sample.mocks.req.body.kind = undefined; - sample.program.get(sample.mocks.req, sample.mocks.res); - }, Error, expectedMsg); + program.get(req, null); + }, Error, errorMsg(`Kind`)); }); -test.serial(`get: Handles get error`, async (t) => { - const error = new Error(`error`); - const sample = getSample(); - - sample.mocks.datastore.get.returns(Promise.reject(error)); - - const err = await t.throws(sample.program.get(sample.mocks.req, sample.mocks.res)); - t.deepEqual(err, error); - t.deepEqual(console.error.callCount, 1); - t.deepEqual(console.error.firstCall.args, [error]); - t.deepEqual(sample.mocks.res.status.callCount, 1); - t.deepEqual(sample.mocks.res.status.firstCall.args, [500]); - t.deepEqual(sample.mocks.res.send.callCount, 1); - t.deepEqual(sample.mocks.res.send.firstCall.args, [error]); +test.serial.cb(`get: Fails when entity does not exist`, (t) => { + request + .post(`/get`) + .send({ + kind: KIND, + key: 'nonexistent' + }) + .expect(500) + .expect((response) => { + t.regex(response.text, /No entity found for key/); + }) + .end(() => { + setTimeout(t.end, 50); // Subsequent test is flaky without this timeout + }); }); -test.serial(`get: Fails when entity does not exist`, async (t) => { - const sample = getSample(); - const error = new Error(`No entity found for key ${sample.mocks.key.path.join('/')}.`); - - sample.mocks.datastore.get.returns(Promise.resolve([])); - - const err = await t.throws(sample.program.get(sample.mocks.req, sample.mocks.res)); - t.deepEqual(err, error); - t.deepEqual(console.error.callCount, 1); - t.deepEqual(console.error.firstCall.args, [error]); - t.deepEqual(sample.mocks.res.status.callCount, 1); - t.deepEqual(sample.mocks.res.status.firstCall.args, [500]); - t.deepEqual(sample.mocks.res.send.callCount, 1); - t.deepEqual(sample.mocks.res.send.firstCall.args, [error]); +test.serial.cb(`get: Finds an entity`, (t) => { + request + .post(`/get`) + .send({ + kind: KIND, + key: NAME + }) + .expect(200) + .expect((response) => { + t.deepEqual( + JSON.parse(response.text), + { description: 'Buy milk' } + ); + }) + .end(t.end); }); -test.serial(`get: Finds an entity`, async (t) => { - const sample = getSample(); - - await sample.program.get(sample.mocks.req, sample.mocks.res); - t.deepEqual(sample.mocks.datastore.get.callCount, 1); - t.deepEqual(sample.mocks.datastore.get.firstCall.args, [sample.mocks.key]); - t.deepEqual(sample.mocks.res.status.callCount, 1); - t.deepEqual(sample.mocks.res.status.firstCall.args, [200]); - t.deepEqual(sample.mocks.res.send.callCount, 1); - t.deepEqual(sample.mocks.res.send.firstCall.args, [sample.mocks.entity]); -}); - -test.serial(`del: Delete fails without a key`, (t) => { - const expectedMsg = `Key not provided. Make sure you have a "key" property in your request`; - const sample = getSample(); - +test.serial(`del: Fails without a key`, (t) => { + const req = { + body: {} + }; t.throws(() => { - sample.mocks.req.body.key = undefined; - sample.program.del(sample.mocks.req, sample.mocks.res); - }, Error, expectedMsg); + program.del(req, null); + }, Error, errorMsg(`Kind`)); }); -test.serial(`del: Delete fails without a kind`, (t) => { - const expectedMsg = `Kind not provided. Make sure you have a "kind" property in your request`; - const sample = getSample(); - +test.serial(`del: Fails without a kind`, (t) => { + const req = { + body: { + key: NAME + } + }; t.throws(() => { - sample.mocks.req.body.kind = undefined; - sample.program.del(sample.mocks.req, sample.mocks.res); - }, Error, expectedMsg); + program.del(req, null); + }, Error, errorMsg(`Kind`)); }); -test.serial(`del: Handles delete error`, async (t) => { - const error = new Error(`error`); - const sample = getSample(); - - sample.mocks.datastore.delete.returns(Promise.reject(error)); - - const err = await t.throws(sample.program.del(sample.mocks.req, sample.mocks.res)); - t.deepEqual(err, error); - t.deepEqual(console.error.callCount, 1); - t.deepEqual(console.error.firstCall.args, [error]); - t.deepEqual(sample.mocks.res.status.callCount, 1); - t.deepEqual(sample.mocks.res.status.firstCall.args, [500]); - t.deepEqual(sample.mocks.res.send.callCount, 1); - t.deepEqual(sample.mocks.res.send.firstCall.args, [error]); +test.serial.cb(`del: Doesn't fail when entity does not exist`, (t) => { + request + .post(`/del`) + .send({ + kind: KIND, + key: 'nonexistent' + }) + .expect(200) + .expect((response) => { + t.is(response.text, `Entity ${KIND}/nonexistent deleted.`); + }) + .end(t.end); }); test.serial(`del: Deletes an entity`, async (t) => { - const expectedMsg = `Entity ${KIND}/${NAME} deleted.`; - const sample = getSample(); - - await sample.program.del(sample.mocks.req, sample.mocks.res); - t.deepEqual(sample.mocks.datastore.delete.callCount, 1); - t.deepEqual(sample.mocks.datastore.delete.firstCall.args, [sample.mocks.key]); - t.deepEqual(sample.mocks.res.status.callCount, 1); - t.deepEqual(sample.mocks.res.status.firstCall.args, [200]); - t.deepEqual(sample.mocks.res.send.callCount, 1); - t.deepEqual(sample.mocks.res.send.firstCall.args, [expectedMsg]); + await new Promise(resolve => { + request + .post(`/del`) + .send({ + kind: KIND, + key: NAME + }) + .expect(200) + .expect((response) => { + t.is(response.text, `Entity ${KIND}/${NAME} deleted.`); + }) + .end(resolve); + }).then(async () => { + const key = datastore.key([KIND, NAME]); + const [entity] = await datastore.get(key); + t.falsy(entity); + }); }); From e12729c2a4c51116614e2bd588761dfa2a13c212 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Tue, 28 Nov 2017 13:11:15 -0800 Subject: [PATCH 06/24] Fix failing helloworld tests --- functions/helloworld/package.json | 16 ++++----- functions/helloworld/test/index.test.js | 46 +++++++------------------ 2 files changed, 20 insertions(+), 42 deletions(-) diff --git a/functions/helloworld/package.json b/functions/helloworld/package.json index 8deaa7f6a3..39deecac8b 100644 --- a/functions/helloworld/package.json +++ b/functions/helloworld/package.json @@ -12,22 +12,22 @@ "node": ">=4.3.2" }, "scripts": { - "lint": "samples lint", + "lint": "repo-tools lint", "pretest": "npm run lint", "test": "ava -T 20s --verbose test/*.test.js" }, "dependencies": { - "@google-cloud/debug-agent": "2.2.2", + "@google-cloud/debug-agent": "2.3.0", "pug": "2.0.0-rc.4", "safe-buffer": "5.1.1" }, "devDependencies": { - "@google-cloud/nodejs-repo-tools": "2.1.0", - "@google-cloud/pubsub": "^0.14.8", - "@google-cloud/storage": "^1.4.0", - "ava": "0.23.0", + "@google-cloud/nodejs-repo-tools": "2.1.3", + "@google-cloud/pubsub": "^0.15.0", + "@google-cloud/storage": "^1.5.0", + "ava": "0.24.0", "proxyquire": "1.8.0", - "sinon": "4.0.2", + "sinon": "4.1.2", "supertest": "^3.0.0", "uuid": "^3.1.0" }, @@ -35,7 +35,7 @@ "requiresKeyFile": true, "requiresProjectId": true, "requiredEnvVars": [ - "FUNCTIONS_BASE_URL" + "BASE_URL" ] } } diff --git a/functions/helloworld/test/index.test.js b/functions/helloworld/test/index.test.js index 46e6dbb44f..9e1a601575 100644 --- a/functions/helloworld/test/index.test.js +++ b/functions/helloworld/test/index.test.js @@ -15,8 +15,6 @@ const Buffer = require('safe-buffer').Buffer; const path = require('path'); -const proxyquire = require(`proxyquire`).noCallThru(); -const sinon = require(`sinon`); const test = require(`ava`); const tools = require(`@google-cloud/nodejs-repo-tools`); const supertest = require(`supertest`); @@ -31,37 +29,17 @@ const topicName = `integration-test-functions`; const localFileName = `test.txt`; const fileName = `test-${uuid.v4()}.txt`; -const BASE_URL = process.env.FUNCTIONS_BASE_URL; - -const program = proxyquire(`../`, { - '@google-cloud/debug-agent': { - start: sinon.stub() - } -}); +const BASE_URL = process.env.BASE_URL; const bucketName = `integration-test-functions`; const bucket = storage.bucket(bucketName); -test.before(tools.checkCredentials); - -test.beforeEach(tools.stubConsole); -test.afterEach.always(tools.restoreConsole); - -test(`helloworld: should log a message`, (t) => { - const expectedMsg = `My Cloud Function: hi`; - - program.helloWorld({ - data: { - message: `hi` - } - }, callback); - - t.deepEqual(console.log.callCount, 1); - t.deepEqual(console.log.firstCall.args, [expectedMsg]); - t.deepEqual(callback.callCount, 1); - t.deepEqual(callback.firstCall.args, []); +test.before(`Must specify BASE_URL`, t => { + t.truthy(BASE_URL); }); +test.before(tools.checkCredentials); + test.cb(`helloGET: should print hello world`, (t) => { supertest(BASE_URL) .get(`/helloGET`) @@ -95,13 +73,13 @@ test.cb(`helloHttp: should print hello world`, (t) => { test(`helloBackground: should print a name`, async (t) => { const data = JSON.stringify({name: 'John'}); - const output = await tools.runAsync(`${baseCmd} call helloBackground --data '${data}'`) + const output = await tools.runAsync(`${baseCmd} call helloBackground --data '${data}'`); t.true(output.includes('Hello John!')); }); test(`helloBackground: should print hello world`, async (t) => { - const output = await tools.runAsync(`${baseCmd} call helloBackground --data '{}'`) + const output = await tools.runAsync(`${baseCmd} call helloBackground --data '{}'`); t.true(output.includes('Hello World!')); }); @@ -119,7 +97,7 @@ test(`helloPubSub: should print a name`, async (t) => { // Check logs await tools.tryTest(async (assert) => { const logs = await tools.runAsync(`${baseCmd} logs read helloPubSub --start-time ${startTime}`); - assert(logs.includes('Hello, ${name}!')); + assert(logs.includes(`Hello, ${name}!`)); }); }); @@ -152,7 +130,7 @@ test.serial(`helloGCS: should print uploaded message`, async (t) => { // Check logs await tools.tryTest(async (assert) => { const logs = await tools.runAsync(`${baseCmd} logs read helloPubSub --start-time ${startTime}`); - assert(logs.includes('File ${fileName} uploaded')); + assert(logs.includes(`File ${fileName} uploaded`)); }); }); @@ -166,7 +144,7 @@ test.serial(`helloGCS: should print metadata updated message`, async (t) => { // Check logs await tools.tryTest(async (assert) => { const logs = await tools.runAsync(`${baseCmd} logs read helloPubSub --start-time ${startTime}`); - assert(logs.includes('File ${fileName} metadata updated')); + assert(logs.includes(`File ${fileName} metadata updated`)); }); }); @@ -175,12 +153,12 @@ test.serial(`helloGCS: should print deleted message`, async (t) => { const startTime = new Date(Date.now()).toISOString(); // Delete file - bucket.delete(fileName); + bucket.deleteFiles(); // Check logs await tools.tryTest(async (assert) => { const logs = await tools.runAsync(`${baseCmd} logs read helloPubSub --start-time ${startTime}`); - assert(logs.includes('File ${fileName} deleted')); + assert(logs.includes(`File ${fileName} deleted`)); }); }); From 4bf61fd0ea327107bfc6e66b5d1f7ea8071c4aaa Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Tue, 28 Nov 2017 13:39:58 -0800 Subject: [PATCH 07/24] Fix typos --- .kokoro/functions-helloworld.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.kokoro/functions-helloworld.sh b/.kokoro/functions-helloworld.sh index 46c181ad8f..1c0204e568 100755 --- a/.kokoro/functions-helloworld.sh +++ b/.kokoro/functions-helloworld.sh @@ -18,7 +18,7 @@ export GCLOUD_PROJECT=nodejs-docs-samples STAGE_BUCKET=$GCLOUD_PROJECT GCP_REGION=us-central1 TOPIC=integration-test-functions -export FUNCTIONS_BASE_URL=https://${GCP_REGION}-${GCLOUD_PROJECT}.cloudfunctions.net +export BASE_URL=https://${GCP_REGION}-${GCLOUD_PROJECT}.cloudfunctions.net # Configure gcloud export GCLOUD_PROJECT=nodejs-getting-started-tests @@ -29,15 +29,15 @@ gcloud config set project nodejs-getting-started-tests function cleanup { CODE=$? - gcloud beta functions deploy helloworld -q - gcloud beta functions deploy helloGET -q - gcloud beta functions deploy helloBackground -q - gcloud beta functions deploy helloPubSub -q - gcloud beta functions deploy helloGCS -q - gcloud beta functions deploy helloError -q - gcloud beta functions deploy helloError2 -q - gcloud beta functions deploy helloError3 -q - gcloud beta functions deploy helloTemplate -q + gcloud beta functions delete helloworld -q + gcloud beta functions delete helloGET -q + gcloud beta functions delete helloBackground -q + gcloud beta functions delete helloPubSub -q + gcloud beta functions delete helloGCS -q + gcloud beta functions delete helloError -q + gcloud beta functions delete helloError2 -q + gcloud beta functions delete helloError3 -q + gcloud beta functions delete helloTemplate -q } trap cleanup EXIT From 946845277cc695a80fcc611fb282cbbad46d817d Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Fri, 1 Dec 2017 15:47:29 -0800 Subject: [PATCH 08/24] Fix incorrect project ID --- .kokoro/functions-helloworld.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.kokoro/functions-helloworld.sh b/.kokoro/functions-helloworld.sh index 1c0204e568..ee5eb14863 100755 --- a/.kokoro/functions-helloworld.sh +++ b/.kokoro/functions-helloworld.sh @@ -14,17 +14,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -export GCLOUD_PROJECT=nodejs-docs-samples +export GCLOUD_PROJECT=nodejs-docs-samples-tests STAGE_BUCKET=$GCLOUD_PROJECT GCP_REGION=us-central1 TOPIC=integration-test-functions export BASE_URL=https://${GCP_REGION}-${GCLOUD_PROJECT}.cloudfunctions.net # Configure gcloud -export GCLOUD_PROJECT=nodejs-getting-started-tests export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/secrets-key.json gcloud auth activate-service-account --key-file "$GOOGLE_APPLICATION_CREDENTIALS" -gcloud config set project nodejs-getting-started-tests +gcloud config set project $GCLOUD_PROJECT function cleanup { CODE=$? From 49dd40be95dfe6e509d68aae3b76e40ac9c45326 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Sun, 3 Dec 2017 23:36:25 -0800 Subject: [PATCH 09/24] Add missing cd command + fix typo in function name --- .kokoro/functions-helloworld.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.kokoro/functions-helloworld.sh b/.kokoro/functions-helloworld.sh index ee5eb14863..78228c89b7 100755 --- a/.kokoro/functions-helloworld.sh +++ b/.kokoro/functions-helloworld.sh @@ -20,6 +20,8 @@ GCP_REGION=us-central1 TOPIC=integration-test-functions export BASE_URL=https://${GCP_REGION}-${GCLOUD_PROJECT}.cloudfunctions.net +cd github/nodejs-docs-samples/functions/helloworld + # Configure gcloud export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/secrets-key.json gcloud auth activate-service-account --key-file "$GOOGLE_APPLICATION_CREDENTIALS" @@ -28,7 +30,7 @@ gcloud config set project $GCLOUD_PROJECT function cleanup { CODE=$? - gcloud beta functions delete helloworld -q + gcloud beta functions delete helloHttp -q gcloud beta functions delete helloGET -q gcloud beta functions delete helloBackground -q gcloud beta functions delete helloPubSub -q @@ -44,7 +46,7 @@ set -e # Deploy all hello-world functions # (If any step fails, the entire test run should fail) -gcloud beta functions deploy helloworld --trigger-http --stage-bucket $STAGE_BUCKET +gcloud beta functions deploy helloHttp --trigger-http --stage-bucket $STAGE_BUCKET gcloud beta functions deploy helloGET --trigger-http --stage-bucket $STAGE_BUCKET gcloud beta functions deploy helloBackground --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC gcloud beta functions deploy helloPubSub --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC From 084f8b9ddfd1f3abb161adc88334d3351d0a041c Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Mon, 4 Dec 2017 10:35:46 -0800 Subject: [PATCH 10/24] Fix more typo --- .kokoro/functions-helloworld.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.kokoro/functions-helloworld.sh b/.kokoro/functions-helloworld.sh index 78228c89b7..3b68253ad0 100755 --- a/.kokoro/functions-helloworld.sh +++ b/.kokoro/functions-helloworld.sh @@ -57,4 +57,4 @@ gcloud beta functions deploy helloError3 --stage-bucket $STAGE_BUCKET --trigger- gcloud beta functions deploy helloTemplate --stage-bucket $STAGE_BUCKET --trigger-http # Run system tests -repo-tools test \ No newline at end of file +repo-tools test run \ No newline at end of file From 92ad5dd347e578e05195756bc65f05a1b4915ef0 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Mon, 4 Dec 2017 10:50:17 -0800 Subject: [PATCH 11/24] Add missing NPM command --- .kokoro/functions-helloworld.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.kokoro/functions-helloworld.sh b/.kokoro/functions-helloworld.sh index 3b68253ad0..4105de61be 100755 --- a/.kokoro/functions-helloworld.sh +++ b/.kokoro/functions-helloworld.sh @@ -22,6 +22,9 @@ export BASE_URL=https://${GCP_REGION}-${GCLOUD_PROJECT}.cloudfunctions.net cd github/nodejs-docs-samples/functions/helloworld +# Install dependencies +npm install + # Configure gcloud export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/secrets-key.json gcloud auth activate-service-account --key-file "$GOOGLE_APPLICATION_CREDENTIALS" From 2e4b0f40dbb5069991d166d52bcaae3a3613dd4b Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Tue, 5 Dec 2017 12:59:09 -0800 Subject: [PATCH 12/24] Disable CircleCI on Kokoro-backed tests --- circle.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/circle.yml b/circle.yml index 6f809b3a78..755054b54f 100644 --- a/circle.yml +++ b/circle.yml @@ -35,11 +35,9 @@ dependencies: - yarn install - yarn run lint - samples test install -l=functions/background - - samples test install -l=functions/datastore - samples test install -l=functions/errorreporting - samples test install -l=functions/gcs - samples test install -l=functions/helloworld - - samples test install -l=functions/http - samples test install -l=functions/imagemagick - samples test install -l=functions/log - samples test install -l=functions/ocr/app From d22510a79bba726ac7994d25584bfa768a477b46 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Tue, 19 Dec 2017 17:12:59 -0800 Subject: [PATCH 13/24] Add local-only 'system test' commands to package.json --- .kokoro/functions-helloworld.sh | 5 +++-- functions/datastore/package.json | 13 ++++++++++--- functions/helloworld/package.json | 10 ++++++++-- functions/helloworld/test/index.test.js | 6 +++--- functions/helloworld/test/updateFunctions.sh | 20 ++++++++++++++++++++ 5 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 functions/helloworld/test/updateFunctions.sh diff --git a/.kokoro/functions-helloworld.sh b/.kokoro/functions-helloworld.sh index 4105de61be..e786f1e7b5 100755 --- a/.kokoro/functions-helloworld.sh +++ b/.kokoro/functions-helloworld.sh @@ -18,6 +18,7 @@ export GCLOUD_PROJECT=nodejs-docs-samples-tests STAGE_BUCKET=$GCLOUD_PROJECT GCP_REGION=us-central1 TOPIC=integration-test-functions +BUCKET=$TOPIC export BASE_URL=https://${GCP_REGION}-${GCLOUD_PROJECT}.cloudfunctions.net cd github/nodejs-docs-samples/functions/helloworld @@ -59,5 +60,5 @@ gcloud beta functions deploy helloError2 --stage-bucket $STAGE_BUCKET --trigger- gcloud beta functions deploy helloError3 --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC gcloud beta functions deploy helloTemplate --stage-bucket $STAGE_BUCKET --trigger-http -# Run system tests -repo-tools test run \ No newline at end of file +# Run E2E tests +npm run e2e-test \ No newline at end of file diff --git a/functions/datastore/package.json b/functions/datastore/package.json index c672c405a6..c4a3ea3a53 100644 --- a/functions/datastore/package.json +++ b/functions/datastore/package.json @@ -12,9 +12,11 @@ "node": ">=4.3.2" }, "scripts": { - "lint": "samples lint", + "lint": "repo-tools lint", "pretest": "npm run lint", - "test": "ava -T 20s --verbose test/*.test.js" + "e2e-test": "export FUNCTIONS_CMD='gcloud beta functions' && sh test/updateFunctions.sh && BASE_URL=\"https://$GCF_REGION-$GCLOUD_PROJECT.cloudfunctions.net/\" ava -T 20s --verbose test/*.test.js", + "system-test": "export FUNCTIONS_CMD='functions' && sh test/updateFunctions.sh && BASE_URL=\"http://localhost:8010/$GCLOUD_PROJECT/$GCF_REGION\" ava -T 20s --verbose test/*.test.js", + "test": "npm run system-test" }, "dependencies": { "@google-cloud/datastore": "1.1.0", @@ -28,6 +30,11 @@ }, "cloud-repo-tools": { "requiresKeyFile": true, - "requiresProjectId": true + "requiresProjectId": true, + "requiredEnvVars": [ + "BASE_URL", + "GCF_REGION", + "FUNCTIONS_CMD" + ] } } diff --git a/functions/helloworld/package.json b/functions/helloworld/package.json index 39deecac8b..59dd26ae19 100644 --- a/functions/helloworld/package.json +++ b/functions/helloworld/package.json @@ -14,7 +14,9 @@ "scripts": { "lint": "repo-tools lint", "pretest": "npm run lint", - "test": "ava -T 20s --verbose test/*.test.js" + "e2e-test": "export FUNCTIONS_CMD='gcloud beta functions' && sh test/updateFunctions.sh && BASE_URL=\"https://$GCF_REGION-$GCLOUD_PROJECT.cloudfunctions.net/\" ava -T 20s --verbose test/*.test.js", + "system-test": "export FUNCTIONS_CMD='functions' && sh test/updateFunctions.sh && export BASE_URL=\"http://localhost:8010/$GCLOUD_PROJECT/$GCF_REGION\" && ava -T 20s --verbose test/*.test.js", + "test": "npm run system-test" }, "dependencies": { "@google-cloud/debug-agent": "2.3.0", @@ -35,7 +37,11 @@ "requiresKeyFile": true, "requiresProjectId": true, "requiredEnvVars": [ - "BASE_URL" + "BASE_URL", + "GCF_REGION", + "TOPIC", + "BUCKET", + "FUNCTIONS_CMD" ] } } diff --git a/functions/helloworld/test/index.test.js b/functions/helloworld/test/index.test.js index 9e1a601575..c6cb14603c 100644 --- a/functions/helloworld/test/index.test.js +++ b/functions/helloworld/test/index.test.js @@ -23,15 +23,15 @@ const uuid = require(`uuid`); const pubsub = require(`@google-cloud/pubsub`)(); const storage = require(`@google-cloud/storage`)(); -const baseCmd = `gcloud beta functions`; -const topicName = `integration-test-functions`; +const baseCmd = process.env.FUNCTIONS_CMD; +const topicName = process.env.TOPIC; const localFileName = `test.txt`; const fileName = `test-${uuid.v4()}.txt`; const BASE_URL = process.env.BASE_URL; -const bucketName = `integration-test-functions`; +const bucketName = process.env.BUCKET; const bucket = storage.bucket(bucketName); test.before(`Must specify BASE_URL`, t => { diff --git a/functions/helloworld/test/updateFunctions.sh b/functions/helloworld/test/updateFunctions.sh new file mode 100644 index 0000000000..6f47e627d5 --- /dev/null +++ b/functions/helloworld/test/updateFunctions.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Shell script to emulate/deploy all Cloud Functions in the file + +${FUNCTIONS_CMD} deploy helloGET --trigger-http +echo '-----------------------------' +${FUNCTIONS_CMD} deploy helloHttp --trigger-http +echo '-----------------------------' +${FUNCTIONS_CMD} deploy helloBackground --trigger-topic $TOPIC +echo '-----------------------------' +${FUNCTIONS_CMD} deploy helloPubSub --trigger-topic $TOPIC +echo '-----------------------------' +${FUNCTIONS_CMD} deploy helloGCS --trigger-bucket $BUCKET +echo '-----------------------------' +${FUNCTIONS_CMD} deploy helloError --trigger-topic $TOPIC +echo '-----------------------------' +${FUNCTIONS_CMD} deploy helloError2 --trigger-topic $TOPIC +echo '-----------------------------' +${FUNCTIONS_CMD} deploy helloError3 --trigger-topic $TOPIC +echo '-----------------------------' +${FUNCTIONS_CMD} deploy helloTemplate --trigger-http \ No newline at end of file From bddca3c79c69cbb6e18bf6a90e16d94f8095ec0d Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Tue, 19 Dec 2017 17:15:59 -0800 Subject: [PATCH 14/24] Remove old deploy commands --- .kokoro/functions-helloworld.sh | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/.kokoro/functions-helloworld.sh b/.kokoro/functions-helloworld.sh index e786f1e7b5..1a7b964a3b 100755 --- a/.kokoro/functions-helloworld.sh +++ b/.kokoro/functions-helloworld.sh @@ -48,17 +48,5 @@ trap cleanup EXIT set -e -# Deploy all hello-world functions -# (If any step fails, the entire test run should fail) -gcloud beta functions deploy helloHttp --trigger-http --stage-bucket $STAGE_BUCKET -gcloud beta functions deploy helloGET --trigger-http --stage-bucket $STAGE_BUCKET -gcloud beta functions deploy helloBackground --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC -gcloud beta functions deploy helloPubSub --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC -gcloud beta functions deploy helloGCS --stage-bucket $STAGE_BUCKET --trigger-bucket integration-test-functions -gcloud beta functions deploy helloError --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC -gcloud beta functions deploy helloError2 --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC -gcloud beta functions deploy helloError3 --stage-bucket $STAGE_BUCKET --trigger-topic $TOPIC -gcloud beta functions deploy helloTemplate --stage-bucket $STAGE_BUCKET --trigger-http - -# Run E2E tests +# Deploy + run the functions npm run e2e-test \ No newline at end of file From c00b9f7788e2363b610e5c6c347aa082b4c485e8 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Wed, 20 Dec 2017 11:09:10 -0800 Subject: [PATCH 15/24] Prefix env vars with FUNCTIONS_ --- .kokoro/functions-helloworld.sh | 4 ++-- functions/helloworld/test/index.test.js | 4 ++-- functions/helloworld/test/updateFunctions.sh | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.kokoro/functions-helloworld.sh b/.kokoro/functions-helloworld.sh index 1a7b964a3b..aac336cc7d 100755 --- a/.kokoro/functions-helloworld.sh +++ b/.kokoro/functions-helloworld.sh @@ -17,8 +17,8 @@ export GCLOUD_PROJECT=nodejs-docs-samples-tests STAGE_BUCKET=$GCLOUD_PROJECT GCP_REGION=us-central1 -TOPIC=integration-test-functions -BUCKET=$TOPIC +FUNCTIONS_TOPIC=integration-test-functions +FUNCTIONS_BUCKET=$FUNCTIONS_TOPIC export BASE_URL=https://${GCP_REGION}-${GCLOUD_PROJECT}.cloudfunctions.net cd github/nodejs-docs-samples/functions/helloworld diff --git a/functions/helloworld/test/index.test.js b/functions/helloworld/test/index.test.js index c6cb14603c..5033955c89 100644 --- a/functions/helloworld/test/index.test.js +++ b/functions/helloworld/test/index.test.js @@ -24,14 +24,14 @@ const pubsub = require(`@google-cloud/pubsub`)(); const storage = require(`@google-cloud/storage`)(); const baseCmd = process.env.FUNCTIONS_CMD; -const topicName = process.env.TOPIC; +const topicName = process.env.FUNCTIONS_TOPIC; const localFileName = `test.txt`; const fileName = `test-${uuid.v4()}.txt`; const BASE_URL = process.env.BASE_URL; -const bucketName = process.env.BUCKET; +const bucketName = process.env.FUNCTIONS_BUCKET; const bucket = storage.bucket(bucketName); test.before(`Must specify BASE_URL`, t => { diff --git a/functions/helloworld/test/updateFunctions.sh b/functions/helloworld/test/updateFunctions.sh index 6f47e627d5..cae716cd60 100644 --- a/functions/helloworld/test/updateFunctions.sh +++ b/functions/helloworld/test/updateFunctions.sh @@ -5,16 +5,16 @@ ${FUNCTIONS_CMD} deploy helloGET --trigger-http echo '-----------------------------' ${FUNCTIONS_CMD} deploy helloHttp --trigger-http echo '-----------------------------' -${FUNCTIONS_CMD} deploy helloBackground --trigger-topic $TOPIC +${FUNCTIONS_CMD} deploy helloBackground --trigger-topic $FUNCTIONS_TOPIC echo '-----------------------------' -${FUNCTIONS_CMD} deploy helloPubSub --trigger-topic $TOPIC +${FUNCTIONS_CMD} deploy helloPubSub --trigger-topic $FUNCTIONS_TOPIC echo '-----------------------------' -${FUNCTIONS_CMD} deploy helloGCS --trigger-bucket $BUCKET +${FUNCTIONS_CMD} deploy helloGCS --trigger-bucket $FUNCTIONS_BUCKET echo '-----------------------------' -${FUNCTIONS_CMD} deploy helloError --trigger-topic $TOPIC +${FUNCTIONS_CMD} deploy helloError --trigger-topic $FUNCTIONS_TOPIC echo '-----------------------------' -${FUNCTIONS_CMD} deploy helloError2 --trigger-topic $TOPIC +${FUNCTIONS_CMD} deploy helloError2 --trigger-topic $FUNCTIONS_TOPIC echo '-----------------------------' -${FUNCTIONS_CMD} deploy helloError3 --trigger-topic $TOPIC +${FUNCTIONS_CMD} deploy helloError3 --trigger-topic $FUNCTIONS_TOPIC echo '-----------------------------' ${FUNCTIONS_CMD} deploy helloTemplate --trigger-http \ No newline at end of file From c696bd598f2640ed9c07dee95cca0144ec9032a5 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Wed, 20 Dec 2017 11:31:39 -0800 Subject: [PATCH 16/24] Add BASE_URL variable to circle.yml --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 755054b54f..2c83f7249a 100644 --- a/circle.yml +++ b/circle.yml @@ -64,7 +64,7 @@ dependencies: # Run your tests test: override: - - samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/**/test/**/*.test.js' + - BASE_URL="http://localhost:8010/$GCLOUD_PROJECT/$GCF_REGION"; samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/**/test/**/*.test.js' post: - nyc report --reporter=lcov > coverage.lcov && codecov || true deployment: From 71e708b77f66162e7ccb8c1bad44c7bd93751728 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Tue, 2 Jan 2018 14:52:18 -0800 Subject: [PATCH 17/24] Add functions emulator to CircleCI --- circle.yml | 2 +- functions/datastore/package.json | 1 + functions/helloworld/package.json | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 2c83f7249a..7486fbe6c4 100644 --- a/circle.yml +++ b/circle.yml @@ -64,7 +64,7 @@ dependencies: # Run your tests test: override: - - BASE_URL="http://localhost:8010/$GCLOUD_PROJECT/$GCF_REGION"; samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/**/test/**/*.test.js' + - BASE_URL="http://localhost:8010/$GCLOUD_PROJECT/$GCF_REGION"; functions start && samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/**/test/**/*.test.js' post: - nyc report --reporter=lcov > coverage.lcov && codecov || true deployment: diff --git a/functions/datastore/package.json b/functions/datastore/package.json index c4a3ea3a53..8692856185 100644 --- a/functions/datastore/package.json +++ b/functions/datastore/package.json @@ -23,6 +23,7 @@ "supertest": "^3.0.0" }, "devDependencies": { + "@google-cloud/functions-emulator": "^1.0.0-alpha.29", "@google-cloud/nodejs-repo-tools": "2.1.0", "ava": "0.23.0", "proxyquire": "1.8.0", diff --git a/functions/helloworld/package.json b/functions/helloworld/package.json index 59dd26ae19..42ffb0c51c 100644 --- a/functions/helloworld/package.json +++ b/functions/helloworld/package.json @@ -24,6 +24,7 @@ "safe-buffer": "5.1.1" }, "devDependencies": { + "@google-cloud/functions-emulator": "^1.0.0-alpha.29", "@google-cloud/nodejs-repo-tools": "2.1.3", "@google-cloud/pubsub": "^0.15.0", "@google-cloud/storage": "^1.5.0", From edccd92a269d5b4e5528761db9619a7dfac0e30c Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Tue, 2 Jan 2018 16:35:34 -0800 Subject: [PATCH 18/24] Update circle.yml Node version to 6.12.3 --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 7486fbe6c4..3be1444927 100644 --- a/circle.yml +++ b/circle.yml @@ -18,7 +18,7 @@ machine: node: - version: 6.11.2 + version: 6.12.3 # Use for broader build-related configuration general: From 2b611f19befff7c9536b66b6245812d7b51c3d95 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Wed, 3 Jan 2018 10:16:38 -0800 Subject: [PATCH 19/24] Install the emulator explicitly --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 3be1444927..1f3d22ea56 100644 --- a/circle.yml +++ b/circle.yml @@ -31,7 +31,7 @@ dependencies: override: - echo $KEYFILE > /home/ubuntu/nodejs-docs-samples/key.json - gcloud auth activate-service-account --key-file /home/ubuntu/nodejs-docs-samples/key.json || true - - yarn global add ava nyc codecov semistandard @google-cloud/nodejs-repo-tools@1.4.17 + - yarn global add ava nyc codecov semistandard @google-cloud/nodejs-repo-tools@1.4.17 @google-cloud/functions-emulator@1.0.0-alpha.29 - yarn install - yarn run lint - samples test install -l=functions/background From 71ebb1a6f3a590f66be709ad8f4a56f256528d40 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Wed, 3 Jan 2018 13:11:45 -0800 Subject: [PATCH 20/24] Split up functions tests into individual steps --- circle.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 1f3d22ea56..337293b135 100644 --- a/circle.yml +++ b/circle.yml @@ -64,7 +64,18 @@ dependencies: # Run your tests test: override: - - BASE_URL="http://localhost:8010/$GCLOUD_PROJECT/$GCF_REGION"; functions start && samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/**/test/**/*.test.js' + - functions start && cd functions/datastore && npm run system-test + - functions start && cd functions/helloworld && npm run system-test + - samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/background/test/**/*.test.js' + - samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/gcs/test/**/*.test.js' + - samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/http/test/**/*.test.js' + - samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/imagemagick/test/**/*.test.js' + - samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/log/test/**/*.test.js' + - samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/pubsub/test/**/*.test.js' + - samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/sendgrid/test/**/*.test.js' + - samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/slack/test/**/*.test.js' + - samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/spanner/test/**/*.test.js' + - samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/uuid/test/**/*.test.js' post: - nyc report --reporter=lcov > coverage.lcov && codecov || true deployment: From d89a919b99ca26b32b1c762e22ea78519dcd8af2 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Thu, 4 Jan 2018 12:31:24 -0800 Subject: [PATCH 21/24] Remove broken debugging agent --- functions/helloworld/index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/functions/helloworld/index.js b/functions/helloworld/index.js index 17b9f5a224..11bbf171f9 100644 --- a/functions/helloworld/index.js +++ b/functions/helloworld/index.js @@ -17,10 +17,6 @@ const Buffer = require('safe-buffer').Buffer; -// [START functions_helloworld_debug] -require('@google-cloud/debug-agent').start(); -// [END functions_helloworld_debug] - // [START functions_helloworld_get] /** * HTTP Cloud Function. From eb7cdf77f834169bb2ca83861595ecb74c3b9d81 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Thu, 4 Jan 2018 12:33:17 -0800 Subject: [PATCH 22/24] Add missing update-functions file --- functions/datastore/test/updateFunctions.sh | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 functions/datastore/test/updateFunctions.sh diff --git a/functions/datastore/test/updateFunctions.sh b/functions/datastore/test/updateFunctions.sh new file mode 100644 index 0000000000..df89237334 --- /dev/null +++ b/functions/datastore/test/updateFunctions.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# Shell script to emulate/deploy all Cloud Functions in the file + +${FUNCTIONS_CMD} deploy set --trigger-http +echo '-----------------------------' +${FUNCTIONS_CMD} deploy get --trigger-http +echo '-----------------------------' +${FUNCTIONS_CMD} deploy del --trigger-http From 747386d1feff76817d5e73952aae3e6f2eba3d10 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Thu, 4 Jan 2018 12:51:41 -0800 Subject: [PATCH 23/24] Update dependencies --- functions/datastore/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/functions/datastore/package.json b/functions/datastore/package.json index 8692856185..1d455aea8f 100644 --- a/functions/datastore/package.json +++ b/functions/datastore/package.json @@ -19,15 +19,15 @@ "test": "npm run system-test" }, "dependencies": { - "@google-cloud/datastore": "1.1.0", + "@google-cloud/datastore": "1.3.3", "supertest": "^3.0.0" }, "devDependencies": { "@google-cloud/functions-emulator": "^1.0.0-alpha.29", - "@google-cloud/nodejs-repo-tools": "2.1.0", - "ava": "0.23.0", + "@google-cloud/nodejs-repo-tools": "2.1.3", + "ava": "0.24.0", "proxyquire": "1.8.0", - "sinon": "4.0.2" + "sinon": "4.1.3" }, "cloud-repo-tools": { "requiresKeyFile": true, From 4911f4540f859ba7e0b413d3c9edcb9d4e9216e7 Mon Sep 17 00:00:00 2001 From: Ace Nassri Date: Thu, 4 Jan 2018 13:31:21 -0800 Subject: [PATCH 24/24] Add missing dependency-installation commands --- circle.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/circle.yml b/circle.yml index 337293b135..780f05a5d5 100644 --- a/circle.yml +++ b/circle.yml @@ -37,6 +37,7 @@ dependencies: - samples test install -l=functions/background - samples test install -l=functions/errorreporting - samples test install -l=functions/gcs + - samples test install -l=functions/datastore - samples test install -l=functions/helloworld - samples test install -l=functions/imagemagick - samples test install -l=functions/log @@ -44,6 +45,7 @@ dependencies: - samples test install -l=functions/pubsub - samples test install -l=functions/sendgrid - samples test install -l=functions/slack + - samples test install -l=functions/spanner - samples test install -l=functions/uuid cache_directories: - ~/.cache/yarn @@ -59,6 +61,7 @@ dependencies: - functions/pubsub/node_modules - functions/sendgrid/node_modules - functions/slack/node_modules + - functions/spanner/node_modules - functions/uuid/node_modules # Run your tests