Skip to content

Commit 2373cda

Browse files
author
Ace Nassri
authored
Add functions sample tests (GoogleCloudPlatform#553)
* Add sample HTTP system test * Add sample pub/sub system test * Fix style nits * Rename region tags to prevent conflicts * Add sample HTTP unit test * Add Pub/Sub unit test * Add storage unit test sample * Add storage system test sample * Add storage integration test sample * Add PubSub integration test sample * Swap integration + system tests to address Marek's comments * Fix region tags * Add HTTP integration test (duplicate of HTTP system test) * Add cloudbuild.yaml for autodeploy * Move cloudbuild.yaml to different file + switch to Yarn * Fix typo vis-a-vis docs * Add missing gcloud installation cmd * Try adding 'sudo' * Remove system tests from circleCI * Missed a spot * Add functions-stop command + fix package.json
1 parent 1873978 commit 2373cda

12 files changed

+554
-5
lines changed

circle.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ dependencies:
6767
# Run your tests
6868
test:
6969
override:
70-
- functions start && cd functions/datastore && npm run system-test
71-
- functions start && cd functions/helloworld && npm run system-test
70+
- functions start && cd functions/datastore && npm run system-test && functions stop
71+
- functions start && cd functions/helloworld && npm run test && functions stop
7272
- samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/background/test/**/*.test.js'
7373
- samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/gcs/test/**/*.test.js'
7474
- samples test run --cmd nyc -- --cache ava --verbose -T 30s 'functions/http/test/**/*.test.js'

functions/ci_cd/cloudbuild.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
steps:
2+
- name: 'gcr.io/cloud-builders/yarn'
3+
args: ['install']
4+
dir: 'functions/autodeploy'
5+
- name: 'gcr.io/cloud-builders/npm'
6+
args: ['test']
7+
dir: 'functions/autodeploy'
8+
- name: 'gcr.io/cloud-builders/gcloud'
9+
args: ['beta', 'functions', 'deploy', '[YOUR_FUNCTION_NAME]', '[YOUR_FUNCTION_TRIGGER]']
10+
dir: 'functions/autodeploy'

functions/helloworld/package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,15 @@
1515
"lint": "repo-tools lint",
1616
"pretest": "npm run lint",
1717
"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",
18-
"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",
19-
"test": "npm run system-test"
18+
"test": "export FUNCTIONS_CMD='functions' && sh test/updateFunctions.sh && export BASE_URL=\"http://localhost:8010/$GCLOUD_PROJECT/$GCF_REGION\" && ava -T 20s --verbose test/index.test.js test/*unit*test.js test/*integration*test.js",
19+
"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"
2020
},
2121
"dependencies": {
2222
"@google-cloud/debug-agent": "2.3.0",
2323
"pug": "2.0.0-rc.4",
2424
"safe-buffer": "5.1.1"
2525
},
2626
"devDependencies": {
27-
"@google-cloud/functions-emulator": "^1.0.0-alpha.29",
2827
"@google-cloud/nodejs-repo-tools": "2.1.3",
2928
"@google-cloud/pubsub": "^0.15.0",
3029
"@google-cloud/storage": "^1.5.0",
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright 2018, Google, Inc.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
// [START functions_http_integration_test]
17+
const test = require(`ava`);
18+
const Supertest = require(`supertest`);
19+
const supertest = Supertest(process.env.BASE_URL);
20+
21+
test.cb(`helloHttp: should print a name`, (t) => {
22+
supertest
23+
.post(`/helloHttp`)
24+
.send({ name: 'John' })
25+
.expect(200)
26+
.expect((response) => {
27+
t.is(response.text, 'Hello John!');
28+
})
29+
.end(t.end);
30+
});
31+
32+
test.cb(`helloHttp: should print hello world`, (t) => {
33+
supertest
34+
.get(`/helloHttp`)
35+
.expect(200)
36+
.expect((response) => {
37+
t.is(response.text, `Hello World!`);
38+
})
39+
.end(t.end);
40+
});
41+
// [END functions_http_integration_test]
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Copyright 2018, Google, Inc.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
// [START functions_pubsub_integration_test]
17+
const childProcess = require(`child_process`);
18+
const test = require(`ava`);
19+
const uuid = require(`uuid`);
20+
21+
test(`helloPubSub: should print a name`, async (t) => {
22+
t.plan(1);
23+
const startTime = new Date(Date.now()).toISOString();
24+
const name = uuid.v4();
25+
26+
// Mock Pub/Sub call, as the emulator doesn't listen to Pub/Sub topics
27+
const encodedName = Buffer.from(name).toString(`base64`);
28+
const data = JSON.stringify({ data: encodedName });
29+
childProcess.execSync(`functions call helloPubSub --data '${data}'`);
30+
31+
// Check the emulator's logs
32+
const logs = childProcess.execSync(`functions logs read helloPubSub --start-time ${startTime}`).toString();
33+
t.true(logs.includes(`Hello, ${name}!`));
34+
});
35+
36+
test(`helloPubSub: should print hello world`, async (t) => {
37+
t.plan(1);
38+
const startTime = new Date(Date.now()).toISOString();
39+
40+
// Mock Pub/Sub call, as the emulator doesn't listen to Pub/Sub topics
41+
childProcess.execSync(`functions call helloPubSub --data {}`);
42+
43+
// Check the emulator's logs
44+
const logs = childProcess.execSync(`functions logs read helloPubSub --start-time ${startTime}`).toString();
45+
t.true(logs.includes(`Hello, World!`));
46+
});
47+
// [END functions_pubsub_integration_test]
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* Copyright 2018, Google, Inc.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
// [START functions_storage_integration_test]
17+
const childProcess = require(`child_process`);
18+
const test = require(`ava`);
19+
const uuid = require(`uuid`);
20+
21+
test(`helloGCS: should print uploaded message`, async (t) => {
22+
t.plan(1);
23+
const startTime = new Date(Date.now()).toISOString();
24+
const filename = uuid.v4(); // Use a unique filename to avoid conflicts
25+
26+
// Mock GCS call, as the emulator doesn't listen to GCS buckets
27+
const data = JSON.stringify({
28+
name: filename,
29+
resourceState: 'exists',
30+
metageneration: '1'
31+
});
32+
33+
childProcess.execSync(`functions call helloGCS --data '${data}'`);
34+
35+
// Check the emulator's logs
36+
const logs = childProcess.execSync(`functions logs read helloGCS --start-time ${startTime}`).toString();
37+
t.true(logs.includes(`File ${filename} uploaded.`));
38+
});
39+
40+
test(`helloGCS: should print metadata updated message`, async (t) => {
41+
t.plan(1);
42+
const startTime = new Date(Date.now()).toISOString();
43+
const filename = uuid.v4(); // Use a unique filename to avoid conflicts
44+
45+
// Mock GCS call, as the emulator doesn't listen to GCS buckets
46+
const data = JSON.stringify({
47+
name: filename,
48+
resourceState: 'exists',
49+
metageneration: '2'
50+
});
51+
52+
childProcess.execSync(`functions call helloGCS --data '${data}'`);
53+
54+
// Check the emulator's logs
55+
const logs = childProcess.execSync(`functions logs read helloGCS --start-time ${startTime}`).toString();
56+
t.true(logs.includes(`File ${filename} metadata updated.`));
57+
});
58+
59+
test(`helloGCS: should print deleted message`, async (t) => {
60+
t.plan(1);
61+
const startTime = new Date(Date.now()).toISOString();
62+
const filename = uuid.v4(); // Use a unique filename to avoid conflicts
63+
64+
// Mock GCS call, as the emulator doesn't listen to GCS buckets
65+
const data = JSON.stringify({
66+
name: filename,
67+
resourceState: 'not_exists',
68+
metageneration: '3'
69+
});
70+
71+
childProcess.execSync(`functions call helloGCS --data '${data}'`);
72+
73+
// Check the emulator's logs
74+
const logs = childProcess.execSync(`functions logs read helloGCS --start-time ${startTime}`).toString();
75+
t.true(logs.includes(`File ${filename} deleted.`));
76+
});
77+
// [END functions_storage_integration_test]
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright 2018, Google, Inc.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
// [START functions_http_system_test]
17+
const test = require(`ava`);
18+
const Supertest = require(`supertest`);
19+
const supertest = Supertest(process.env.BASE_URL);
20+
21+
test.cb(`helloHttp: should print a name`, (t) => {
22+
supertest
23+
.post(`/helloHttp`)
24+
.send({ name: 'John' })
25+
.expect(200)
26+
.expect((response) => {
27+
t.is(response.text, 'Hello John!');
28+
})
29+
.end(t.end);
30+
});
31+
32+
test.cb(`helloHttp: should print hello world`, (t) => {
33+
supertest
34+
.get(`/helloHttp`)
35+
.expect(200)
36+
.expect((response) => {
37+
t.is(response.text, `Hello World!`);
38+
})
39+
.end(t.end);
40+
});
41+
// [END functions_http_system_test]
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* Copyright 2018, Google, Inc.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
// [START functions_pubsub_system_test]
17+
const childProcess = require(`child_process`);
18+
const test = require(`ava`);
19+
const uuid = require(`uuid`);
20+
const Pubsub = require(`@google-cloud/pubsub`);
21+
const pubsub = Pubsub();
22+
23+
const topicName = process.env.FUNCTIONS_TOPIC;
24+
const baseCmd = `gcloud beta functions`;
25+
26+
test(`helloPubSub: should print a name`, async (t) => {
27+
t.plan(1);
28+
const startTime = new Date(Date.now()).toISOString();
29+
const name = uuid.v4();
30+
31+
// Publish to pub/sub topic
32+
const topic = pubsub.topic(topicName);
33+
const publisher = topic.publisher();
34+
await publisher.publish(Buffer.from(name));
35+
36+
// Wait for logs to become consistent
37+
await new Promise(resolve => setTimeout(resolve, 15000));
38+
39+
// Check logs after a delay
40+
const logs = childProcess.execSync(`${baseCmd} logs read helloPubSub --start-time ${startTime}`).toString();
41+
t.true(logs.includes(`Hello, ${name}!`));
42+
});
43+
44+
test(`helloPubSub: should print hello world`, async (t) => {
45+
t.plan(1);
46+
const startTime = new Date(Date.now()).toISOString();
47+
48+
// Publish to pub/sub topic
49+
const topic = pubsub.topic(topicName);
50+
const publisher = topic.publisher();
51+
await publisher.publish(Buffer.from(''), { a: 'b' });
52+
53+
// Wait for logs to become consistent
54+
await new Promise(resolve => setTimeout(resolve, 15000));
55+
56+
// Check logs after a delay
57+
const logs = childProcess.execSync(`${baseCmd} logs read helloPubSub --start-time ${startTime}`).toString();
58+
t.true(logs.includes('Hello, World!'));
59+
});
60+
// [END functions_pubsub_system_test]
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* Copyright 2018, Google, Inc.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
// [START functions_storage_system_test]
17+
const Storage = require(`@google-cloud/storage`);
18+
const storage = Storage();
19+
const uuid = require(`uuid`);
20+
const test = require(`ava`);
21+
const path = require(`path`);
22+
const childProcess = require(`child_process`);
23+
const localFileName = `test.txt`;
24+
25+
// Use unique GCS filename to avoid conflicts between concurrent test runs
26+
const gcsFileName = `test-${uuid.v4()}.txt`;
27+
28+
const bucketName = process.env.BUCKET_NAME;
29+
const bucket = storage.bucket(bucketName);
30+
const baseCmd = `gcloud beta functions`;
31+
32+
test.serial(`helloGCS: should print uploaded message`, async (t) => {
33+
t.plan(1);
34+
const startTime = new Date(Date.now()).toISOString();
35+
36+
// Upload file
37+
const filepath = path.join(__dirname, localFileName);
38+
await bucket.upload(filepath, {
39+
destination: gcsFileName
40+
});
41+
42+
// Wait for consistency
43+
await new Promise(resolve => setTimeout(resolve, 15000));
44+
45+
// Check logs
46+
const logs = childProcess.execSync(`${baseCmd} logs read helloGCS --start-time ${startTime}`).toString();
47+
t.true(logs.includes(`File ${gcsFileName} uploaded`));
48+
});
49+
50+
test.serial(`helloGCS: should print metadata updated message`, async (t) => {
51+
t.plan(1);
52+
const startTime = new Date(Date.now()).toISOString();
53+
54+
// Update file metadata
55+
const file = bucket.file(gcsFileName);
56+
await file.setMetadata(gcsFileName, { foo: `bar` });
57+
58+
// Wait for consistency
59+
await new Promise(resolve => setTimeout(resolve, 15000));
60+
61+
// Check logs
62+
const logs = childProcess.execSync(`${baseCmd} logs read helloGCS --start-time ${startTime}`).toString();
63+
t.true(logs.includes(`File ${gcsFileName} metadata updated`));
64+
});
65+
66+
test.serial(`helloGCS: should print deleted message`, async (t) => {
67+
t.plan(1);
68+
const startTime = new Date(Date.now()).toISOString();
69+
70+
// Delete file
71+
bucket.deleteFiles();
72+
73+
// Wait for consistency
74+
await new Promise(resolve => setTimeout(resolve, 15000));
75+
76+
// Check logs
77+
const logs = childProcess.execSync(`${baseCmd} logs read helloGCS --start-time ${startTime}`).toString();
78+
t.true(logs.includes(`File ${gcsFileName} deleted`));
79+
});
80+
// [START functions_storage_system_test]

0 commit comments

Comments
 (0)