From 681471bb30160e9ed1d0ebe8561288a6303403cb Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Tue, 1 Dec 2015 15:36:16 -0800 Subject: [PATCH 1/2] Added tests. --- .gitignore | 5 + .jshintrc | 13 +- .travis.yml | 56 ++- 1-hello-world/app.js | 23 +- 1-hello-world/package.json | 9 +- 1-hello-world/test/1-hello-world.test.js | 57 +++ 2-structured-data/app.js | 15 +- 2-structured-data/config.js | 2 +- 2-structured-data/package.json | 9 +- .../test/2-structured-data.test.js | 72 +++ 3-binary-data/app.js | 16 +- 3-binary-data/config.js | 2 +- 3-binary-data/package.json | 9 +- 3-binary-data/test/3-binary-data.test.js | 72 +++ 4-auth/app.js | 16 +- 4-auth/config.js | 2 +- 4-auth/package.json | 9 +- 4-auth/test/4-auth.test.js | 72 +++ 5-logging/app.js | 16 +- 5-logging/config.js | 2 +- 5-logging/package.json | 9 +- 5-logging/test/5-logging.test.js | 72 +++ 6-pubsub/app.js | 16 +- 6-pubsub/config.js | 2 +- 6-pubsub/package.json | 11 +- 6-pubsub/test/6-pubsub.test.js | 72 +++ 6-pubsub/test/background.test.js | 423 ++++++++++++++++++ 7-gce/app.js | 16 +- 7-gce/config.js | 2 +- 7-gce/package.json | 11 +- 7-gce/test/7-gce.test.js | 72 +++ 7-gce/test/background.test.js | 423 ++++++++++++++++++ package.json | 60 +++ test/encrypted/nodejs-docs-samples.json.enc | Bin 0 -> 2320 bytes test/utils.js | 237 ++++++++++ 35 files changed, 1826 insertions(+), 77 deletions(-) create mode 100644 1-hello-world/test/1-hello-world.test.js create mode 100644 2-structured-data/test/2-structured-data.test.js create mode 100644 3-binary-data/test/3-binary-data.test.js create mode 100644 4-auth/test/4-auth.test.js create mode 100644 5-logging/test/5-logging.test.js create mode 100644 6-pubsub/test/6-pubsub.test.js create mode 100644 6-pubsub/test/background.test.js create mode 100644 7-gce/test/7-gce.test.js create mode 100644 7-gce/test/background.test.js create mode 100644 package.json create mode 100644 test/encrypted/nodejs-docs-samples.json.enc create mode 100644 test/utils.js diff --git a/.gitignore b/.gitignore index 37e0121c38..2b572d900c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ .DS_Store node_modules +**/node_modules/** *.log +coverage/ +test/encrypted/nodejs-docs-samples.json +*.iml +.idea/ diff --git a/.jshintrc b/.jshintrc index a8e226dd4b..d06dbfe00a 100644 --- a/.jshintrc +++ b/.jshintrc @@ -2,14 +2,21 @@ "camelcase" : true, "curly": true, "eqeqeq": true, - "globalstrict": true, "indent": 2, "newcap": true, "maxlen": 80, "node": true, "quotmark": "single", - "strict": true, + "strict": "global", "trailing": true, "undef": true, - "unused": true + "unused": true, + "globals": { + "after": false, + "afterEach": false, + "before": false, + "beforeEach": false, + "describe": false, + "it": false + } } diff --git a/.travis.yml b/.travis.yml index 2c1de29a3d..2da76b4a18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,60 @@ -sudo: false +# Copyright 2015, 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. + +sudo: required language: node_js node_js: - "stable" - "0.12" - "0.10" + +cache: + directories: + - $HOME/gcloud/ + - 1-hello-world/node_modules/ + - 2-structured-data/node_modules/ + - 3-binary-data/node_modules/ + - 4-auth/node_modules/ + - 5-logging/node_modules/ + - 6-pubsub/node_modules/ + - 7-gce/node_modules/ + - $TRAVIS_BUILD_DIR/node_modules/ + +services: + - docker + +env: + - PATH=$PATH:$HOME/gcloud/google-cloud-sdk/bin GOOGLE_APPLICATION_CREDENTIALS=$TRAVIS_BUILD_DIR/test/encrypted/nodejs-docs-samples.json TEST_BUCKET_NAME=nodejs-docs-samples TEST_PROJECT_ID=nodejs-docs-samples #Other environment variables on same line + +before_install: + - if [ ! -d $HOME/gcloud/google-cloud-sdk ]; then + mkdir -p $HOME/gcloud && + wget https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz --directory-prefix=$HOME/gcloud && + cd $HOME/gcloud && + tar xzf google-cloud-sdk.tar.gz && + printf '\ny\n\ny\ny\n' | ./google-cloud-sdk/install.sh && + source /home/travis/.bash_profile && + cd $TRAVIS_BUILD_DIR; + fi + - gcloud components update -q + - gcloud components update app -q + - openssl aes-256-cbc -K $encrypted_06352980ac5c_key -iv $encrypted_06352980ac5c_iv -in test/encrypted/nodejs-docs-samples.json.enc -out test/encrypted/nodejs-docs-samples.json -d + - if [ -a test/encrypted/nodejs-docs-samples.json ]; then + gcloud auth activate-service-account --key-file test/encrypted/nodejs-docs-samples.json; + fi + +after_success: +- npm run coveralls + +after_script: + - gsutil -m cp *.log gs://nodejs-docs-samples-travis-deployments diff --git a/1-hello-world/app.js b/1-hello-world/app.js index b6b8401613..8c71d06d13 100644 --- a/1-hello-world/app.js +++ b/1-hello-world/app.js @@ -25,13 +25,16 @@ app.get('/', function(req, res) { }); // [END hello_world] - -// [START server] -// Start the server -var server = app.listen(process.env.PORT || 8080, function () { - var host = server.address().address; - var port = server.address().port; - - console.log('App listening at http://%s:%s', host, port); -}); -// [END server] +if (module === require.main) { + // [START server] + // Start the server + var server = app.listen(process.env.PORT || 8080, function () { + var host = server.address().address; + var port = server.address().port; + + console.log('App listening at http://%s:%s', host, port); + }); + // [END server] +} + +module.exports = app; diff --git a/1-hello-world/package.json b/1-hello-world/package.json index 63a96ea9ea..433d7070f6 100644 --- a/1-hello-world/package.json +++ b/1-hello-world/package.json @@ -8,8 +8,9 @@ "start": "node app.js", "monitor": "nodemon app.js", "deploy": "gcloud preview app deploy app.yaml", - "lint": "jshint --exclude-path=.gitignore .", - "test": "npm run lint" + "lint": "jshint --exclude-path=../.gitignore .", + "mocha": "mocha test/*.test.js", + "test": "npm run lint && npm run mocha" }, "author": "Google Inc.", "contributors": [ @@ -31,7 +32,9 @@ "express": "^4.13.3" }, "devDependencies": { - "jshint": "^2.8.0" + "jshint": "^2.8.0", + "mocha": "^2.3.4", + "supertest": "^1.1.0" }, "engines": { "node": ">=0.12.7" diff --git a/1-hello-world/test/1-hello-world.test.js b/1-hello-world/test/1-hello-world.test.js new file mode 100644 index 0000000000..d00874a104 --- /dev/null +++ b/1-hello-world/test/1-hello-world.test.js @@ -0,0 +1,57 @@ +// Copyright 2015, 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. + +'use strict'; + +var assert = require('assert'); +var path = require('path'); +var request = require('supertest'); +var utils = require('../../test/utils'); + +var config = { + test: '1-hello-world', + path: path.resolve(path.join(__dirname, '../')), + cmd: 'node', + args: ['app.js'], + msg: 'Hello, world!' +}; + +describe(config.test, function () { + + it('should install dependencies', function (done) { + this.timeout(60 * 1000); // Allow 1 minute to test installation + utils.testInstallation(config, done); + }); + + it('should create an express app', function (done) { + request(require('../app')) + .get('/') + .expect(200) + .expect(function (response) { + assert.equal(response.text, config.msg); + }) + .end(done); + }); + + it('should run', function (done) { + this.timeout(15 * 1000); // Allow 15 seconds to test app + utils.testLocalApp(config, done); + }); + + if (process.env.TRAVIS && process.env.TRAVIS_NODE_VERSION === 'stable') { + it('should deploy', function (done) { + this.timeout(10 * 60 * 1000); // Allow 10 minutes to deploy app :( + utils.testDeployment(config, done); + }); + } +}); diff --git a/2-structured-data/app.js b/2-structured-data/app.js index 8784fbaec1..c7eee4d5ff 100644 --- a/2-structured-data/app.js +++ b/2-structured-data/app.js @@ -44,11 +44,14 @@ app.use(function(err, req, res, next) { res.status(500).send('Something broke!'); }); +if (module === require.main) { + // Start the server + var server = app.listen(config.port, function () { + var host = server.address().address; + var port = server.address().port; -// Start the server -var server = app.listen(config.port, function () { - var host = server.address().address; - var port = server.address().port; + console.log('App listening at http://%s:%s', host, port); + }); +} - console.log('App listening at http://%s:%s', host, port); -}); +module.exports = app; diff --git a/2-structured-data/config.js b/2-structured-data/config.js index e83d8290b4..076db7f053 100644 --- a/2-structured-data/config.js +++ b/2-structured-data/config.js @@ -25,7 +25,7 @@ module.exports = { // This is the id of your project in the Google Developers Console. gcloud: { - projectId: 'your-project-id' + projectId: process.env.TEST_PROJECT_ID || 'your-project-id' }, mysql: { diff --git a/2-structured-data/package.json b/2-structured-data/package.json index cdc8acad63..e1900630d5 100644 --- a/2-structured-data/package.json +++ b/2-structured-data/package.json @@ -8,8 +8,9 @@ "start": "node app.js", "monitor": "nodemon app.js", "deploy": "gcloud preview app deploy app.yaml", - "lint": "jshint --exclude-path=.gitignore .", - "test": "npm run lint", + "lint": "jshint --exclude-path=../.gitignore .", + "mocha": "mocha test/*.test.js", + "test": "npm run lint && npm run mocha", "init-cloudsql": "node books/model-cloudsql.js" }, "author": "Google Inc.", @@ -40,7 +41,9 @@ "prompt": "^0.2.14" }, "devDependencies": { - "jshint": "^2.8.0" + "jshint": "^2.8.0", + "mocha": "^2.3.4", + "supertest": "^1.1.0" }, "engines": { "node": ">=0.12.7" diff --git a/2-structured-data/test/2-structured-data.test.js b/2-structured-data/test/2-structured-data.test.js new file mode 100644 index 0000000000..2c4968a3eb --- /dev/null +++ b/2-structured-data/test/2-structured-data.test.js @@ -0,0 +1,72 @@ +// Copyright 2015, 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. + +'use strict'; + +var assert = require('assert'); +var path = require('path'); +var request = require('supertest'); +var utils = require('../../test/utils'); + +var config = { + test: '2-structured-data', + path: path.resolve(path.join(__dirname, '../')), + cmd: 'node', + args: ['app.js'], + msg: 'No books found.' +}; + +describe(config.test, function () { + + it('should install dependencies', function (done) { + this.timeout(60 * 1000); // Allow 1 minute to test installation + utils.testInstallation(config, done); + }); + + it('should redirect / to /books', function (done) { + request(require('../app')) + .get('/') + .expect(302) + .expect(function (response) { + assert.equal(response.text, 'Found. Redirecting to /books'); + }) + .end(done); + }); + + if (process.env.TEST_PROJECT_ID) { + it('should list books', function (done) { + request(require('../app')) + .get('/books') + .expect(200) + .expect(function (response) { + assert.ok(response.text.indexOf(config.msg) !== -1); + }) + .end(done); + }); + } + + it('should show add book form', function (done) { + request(require('../app')) + .get('/books/add') + .expect(200) + .expect(function (response) { + assert.ok(response.text.indexOf('Add book') !== -1); + }) + .end(done); + }); + + it('should run', function (done) { + this.timeout(15 * 1000); // Allow 15 seconds to test app + utils.testLocalApp(config, done); + }); +}); diff --git a/3-binary-data/app.js b/3-binary-data/app.js index 58140cad8a..cb3a158d69 100644 --- a/3-binary-data/app.js +++ b/3-binary-data/app.js @@ -48,10 +48,14 @@ app.use(function(err, req, res, next) { }); -// Start the server -var server = app.listen(config.port, function () { - var host = server.address().address; - var port = server.address().port; +if (module === require.main) { + // Start the server + var server = app.listen(config.port, function () { + var host = server.address().address; + var port = server.address().port; - console.log('App listening at http://%s:%s', host, port); -}); + console.log('App listening at http://%s:%s', host, port); + }); +} + +module.exports = app; diff --git a/3-binary-data/config.js b/3-binary-data/config.js index 68511726c7..28fbf4dbe4 100644 --- a/3-binary-data/config.js +++ b/3-binary-data/config.js @@ -25,7 +25,7 @@ module.exports = { // This is the id of your project in the Google Developers Console. gcloud: { - projectId: 'your-project-id' + projectId: process.env.TEST_PROJECT_ID || 'your-project-id' }, // Typically, you will create a bucket with the same name as your project ID. diff --git a/3-binary-data/package.json b/3-binary-data/package.json index 0897880f5e..eaf59583b6 100644 --- a/3-binary-data/package.json +++ b/3-binary-data/package.json @@ -8,8 +8,9 @@ "start": "node app.js", "monitor": "nodemon app.js", "deploy": "gcloud preview app deploy app.yaml", - "lint": "jshint --exclude-path=.gitignore .", - "test": "npm run lint", + "lint": "jshint --exclude-path=../.gitignore .", + "mocha": "mocha test/*.test.js", + "test": "npm run lint && npm run mocha", "init-cloudsql": "node books/model-cloudsql.js" }, "author": "Google Inc.", @@ -41,7 +42,9 @@ "prompt": "^0.2.14" }, "devDependencies": { - "jshint": "^2.8.0" + "jshint": "^2.8.0", + "mocha": "^2.3.4", + "supertest": "^1.1.0" }, "engines": { "node": ">=0.12.7" diff --git a/3-binary-data/test/3-binary-data.test.js b/3-binary-data/test/3-binary-data.test.js new file mode 100644 index 0000000000..d275e40a40 --- /dev/null +++ b/3-binary-data/test/3-binary-data.test.js @@ -0,0 +1,72 @@ +// Copyright 2015, 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. + +'use strict'; + +var assert = require('assert'); +var path = require('path'); +var request = require('supertest'); +var utils = require('../../test/utils'); + +var config = { + test: '3-binary-data', + path: path.resolve(path.join(__dirname, '../')), + cmd: 'node', + args: ['app.js'], + msg: 'No books found.' +}; + +describe(config.test, function () { + + it('should install dependencies', function (done) { + this.timeout(60 * 1000); // Allow 1 minute to test installation + utils.testInstallation(config, done); + }); + + it('should redirect / to /books', function (done) { + request(require('../app')) + .get('/') + .expect(302) + .expect(function (response) { + assert.equal(response.text, 'Found. Redirecting to /books'); + }) + .end(done); + }); + + if (process.env.TEST_PROJECT_ID) { + it('should list books', function (done) { + request(require('../app')) + .get('/books') + .expect(200) + .expect(function (response) { + assert.ok(response.text.indexOf(config.msg) !== -1); + }) + .end(done); + }); + } + + it('should show add book form', function (done) { + request(require('../app')) + .get('/books/add') + .expect(200) + .expect(function (response) { + assert.ok(response.text.indexOf('Add book') !== -1); + }) + .end(done); + }); + + it('should run', function (done) { + this.timeout(15 * 1000); // Allow 15 seconds to test app + utils.testLocalApp(config, done); + }); +}); diff --git a/4-auth/app.js b/4-auth/app.js index f614d655c7..e3435f4ec2 100644 --- a/4-auth/app.js +++ b/4-auth/app.js @@ -67,10 +67,14 @@ app.use(function(err, req, res, next) { }); -// Start the server -var server = app.listen(config.port, function () { - var host = server.address().address; - var port = server.address().port; +if (module === require.main) { + // Start the server + var server = app.listen(config.port, function () { + var host = server.address().address; + var port = server.address().port; - console.log('App listening at http://%s:%s', host, port); -}); + console.log('App listening at http://%s:%s', host, port); + }); +} + +module.exports = app; diff --git a/4-auth/config.js b/4-auth/config.js index 17914c05ff..0aedc90476 100644 --- a/4-auth/config.js +++ b/4-auth/config.js @@ -28,7 +28,7 @@ module.exports = { // This is the id of your project in the Google Developers Console. gcloud: { - projectId: 'your-project-id' + projectId: process.env.TEST_PROJECT_ID || 'your-project-id' }, // Typically, you will create a bucket with the same name as your project ID. diff --git a/4-auth/package.json b/4-auth/package.json index 5f69dfe2f3..50dc77822c 100644 --- a/4-auth/package.json +++ b/4-auth/package.json @@ -8,8 +8,9 @@ "start": "node app.js", "monitor": "nodemon app.js", "deploy": "gcloud preview app deploy app.yaml", - "lint": "jshint --exclude-path=.gitignore .", - "test": "npm run lint", + "lint": "jshint --exclude-path=../.gitignore .", + "mocha": "mocha test/*.test.js", + "test": "npm run lint && npm run mocha", "init-cloudsql": "node books/model-cloudsql.js" }, "author": "Google Inc.", @@ -44,7 +45,9 @@ "prompt": "^0.2.14" }, "devDependencies": { - "jshint": "^2.8.0" + "jshint": "^2.8.0", + "mocha": "^2.3.4", + "supertest": "^1.1.0" }, "engines": { "node": ">=0.12.7" diff --git a/4-auth/test/4-auth.test.js b/4-auth/test/4-auth.test.js new file mode 100644 index 0000000000..b2541fc6ef --- /dev/null +++ b/4-auth/test/4-auth.test.js @@ -0,0 +1,72 @@ +// Copyright 2015, 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. + +'use strict'; + +var assert = require('assert'); +var path = require('path'); +var request = require('supertest'); +var utils = require('../../test/utils'); + +var config = { + test: '4-auth', + path: path.resolve(path.join(__dirname, '../')), + cmd: 'node', + args: ['app.js'], + msg: 'No books found.' +}; + +describe(config.test, function () { + + it('should install dependencies', function (done) { + this.timeout(60 * 1000); // Allow 1 minute to test installation + utils.testInstallation(config, done); + }); + + it('should redirect / to /books', function (done) { + request(require('../app')) + .get('/') + .expect(302) + .expect(function (response) { + assert.equal(response.text, 'Found. Redirecting to /books'); + }) + .end(done); + }); + + if (process.env.TEST_PROJECT_ID) { + it('should list books', function (done) { + request(require('../app')) + .get('/books') + .expect(200) + .expect(function (response) { + assert.ok(response.text.indexOf(config.msg) !== -1); + }) + .end(done); + }); + } + + it('should show add book form', function (done) { + request(require('../app')) + .get('/books/add') + .expect(200) + .expect(function (response) { + assert.ok(response.text.indexOf('Add book') !== -1); + }) + .end(done); + }); + + it('should run', function (done) { + this.timeout(15 * 1000); // Allow 15 seconds to test app + utils.testLocalApp(config, done); + }); +}); diff --git a/5-logging/app.js b/5-logging/app.js index e5ac5c42bc..9139cef64b 100644 --- a/5-logging/app.js +++ b/5-logging/app.js @@ -78,10 +78,14 @@ app.use(function(err, req, res, next) { // [END errors] -// Start the server -var server = app.listen(config.port, function () { - var host = server.address().address; - var port = server.address().port; +if (module === require.main) { + // Start the server + var server = app.listen(config.port, function () { + var host = server.address().address; + var port = server.address().port; - console.log('App listening at http://%s:%s', host, port); -}); + console.log('App listening at http://%s:%s', host, port); + }); +} + +module.exports = app; diff --git a/5-logging/config.js b/5-logging/config.js index 17914c05ff..0aedc90476 100644 --- a/5-logging/config.js +++ b/5-logging/config.js @@ -28,7 +28,7 @@ module.exports = { // This is the id of your project in the Google Developers Console. gcloud: { - projectId: 'your-project-id' + projectId: process.env.TEST_PROJECT_ID || 'your-project-id' }, // Typically, you will create a bucket with the same name as your project ID. diff --git a/5-logging/package.json b/5-logging/package.json index 8e9aeeb12b..c198d21745 100644 --- a/5-logging/package.json +++ b/5-logging/package.json @@ -8,8 +8,9 @@ "start": "node app.js", "monitor": "nodemon app.js", "deploy": "gcloud preview app deploy app.yaml", - "lint": "jshint --exclude-path=.gitignore .", - "test": "npm run lint", + "lint": "jshint --exclude-path=../.gitignore .", + "mocha": "mocha test/*.test.js", + "test": "npm run lint && npm run mocha", "init-cloudsql": "node books/model-cloudsql.js" }, "author": "Google Inc.", @@ -46,7 +47,9 @@ "winston": "^1.1.1" }, "devDependencies": { - "jshint": "^2.8.0" + "jshint": "^2.8.0", + "mocha": "^2.3.4", + "supertest": "^1.1.0" }, "engines": { "node": ">=0.12.7" diff --git a/5-logging/test/5-logging.test.js b/5-logging/test/5-logging.test.js new file mode 100644 index 0000000000..eed8589e5d --- /dev/null +++ b/5-logging/test/5-logging.test.js @@ -0,0 +1,72 @@ +// Copyright 2015, 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. + +'use strict'; + +var assert = require('assert'); +var path = require('path'); +var request = require('supertest'); +var utils = require('../../test/utils'); + +var config = { + test: '5-logging', + path: path.resolve(path.join(__dirname, '../')), + cmd: 'node', + args: ['app.js'], + msg: 'No books found.' +}; + +describe(config.test, function () { + + it('should install dependencies', function (done) { + this.timeout(60 * 1000); // Allow 1 minute to test installation + utils.testInstallation(config, done); + }); + + it('should redirect / to /books', function (done) { + request(require('../app')) + .get('/') + .expect(302) + .expect(function (response) { + assert.equal(response.text, 'Found. Redirecting to /books'); + }) + .end(done); + }); + + if (process.env.TEST_PROJECT_ID) { + it('should list books', function (done) { + request(require('../app')) + .get('/books') + .expect(200) + .expect(function (response) { + assert.ok(response.text.indexOf(config.msg) !== -1); + }) + .end(done); + }); + } + + it('should show add book form', function (done) { + request(require('../app')) + .get('/books/add') + .expect(200) + .expect(function (response) { + assert.ok(response.text.indexOf('Add book') !== -1); + }) + .end(done); + }); + + it('should run', function (done) { + this.timeout(15 * 1000); // Allow 15 seconds to test app + utils.testLocalApp(config, done); + }); +}); diff --git a/6-pubsub/app.js b/6-pubsub/app.js index 7e798b6c25..dcd652d0c3 100644 --- a/6-pubsub/app.js +++ b/6-pubsub/app.js @@ -76,10 +76,14 @@ app.use(function(err, req, res, next) { }); -// Start the server -var server = app.listen(config.port, function () { - var host = server.address().address; - var port = server.address().port; +if (module === require.main) { + // Start the server + var server = app.listen(config.port, function () { + var host = server.address().address; + var port = server.address().port; - console.log('App listening at http://%s:%s', host, port); -}); + console.log('App listening at http://%s:%s', host, port); + }); +} + +module.exports = app; diff --git a/6-pubsub/config.js b/6-pubsub/config.js index a8dd97ca5e..3b7a3174be 100644 --- a/6-pubsub/config.js +++ b/6-pubsub/config.js @@ -28,7 +28,7 @@ module.exports = { // This is the id of your project in the Google Developers Console. gcloud: { - projectId: 'your-project-id' + projectId: process.env.TEST_PROJECT_ID || 'your-project-id' }, // Typically, you will create a bucket with the same name as your project ID. diff --git a/6-pubsub/package.json b/6-pubsub/package.json index d3837dd601..121807f6e7 100644 --- a/6-pubsub/package.json +++ b/6-pubsub/package.json @@ -8,8 +8,9 @@ "start": "node ${SCRIPT:-app.js}", "monitor": "nodemon ${SCRIPT:-app.js}", "deploy": "gcloud preview app deploy app.yaml worker.yaml", - "lint": "jshint --exclude-path=.gitignore .", - "test": "npm run lint", + "lint": "jshint --exclude-path=../.gitignore .", + "mocha": "mocha test/*.test.js", + "test": "npm run lint && npm run mocha", "init-cloudsql": "node books/model-cloudsql.js" }, "author": "Google Inc.", @@ -47,7 +48,11 @@ "winston": "^1.1.1" }, "devDependencies": { - "jshint": "^2.8.0" + "jshint": "^2.8.0", + "mocha": "^2.3.4", + "proxyquire": "^1.7.3", + "sinon": "^1.17.2", + "supertest": "^1.1.0" }, "engines": { "node": ">=0.12.7" diff --git a/6-pubsub/test/6-pubsub.test.js b/6-pubsub/test/6-pubsub.test.js new file mode 100644 index 0000000000..578f6e7cec --- /dev/null +++ b/6-pubsub/test/6-pubsub.test.js @@ -0,0 +1,72 @@ +// Copyright 2015, 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. + +'use strict'; + +var assert = require('assert'); +var path = require('path'); +var request = require('supertest'); +var utils = require('../../test/utils'); + +var config = { + test: '6-pubsub', + path: path.resolve(path.join(__dirname, '../')), + cmd: 'node', + args: ['app.js'], + msg: 'No books found.' +}; + +describe(config.test, function () { + + it('should install dependencies', function (done) { + this.timeout(60 * 1000); // Allow 1 minute to test installation + utils.testInstallation(config, done); + }); + + it('should redirect / to /books', function (done) { + request(require('../app')) + .get('/') + .expect(302) + .expect(function (response) { + assert.equal(response.text, 'Found. Redirecting to /books'); + }) + .end(done); + }); + + if (process.env.TEST_PROJECT_ID) { + it('should list books', function (done) { + request(require('../app')) + .get('/books') + .expect(200) + .expect(function (response) { + assert.ok(response.text.indexOf(config.msg) !== -1); + }) + .end(done); + }); + } + + it('should show add book form', function (done) { + request(require('../app')) + .get('/books/add') + .expect(200) + .expect(function (response) { + assert.ok(response.text.indexOf('Add book') !== -1); + }) + .end(done); + }); + + it('should run', function (done) { + this.timeout(15 * 1000); // Allow 15 seconds to test app + utils.testLocalApp(config, done); + }); +}); diff --git a/6-pubsub/test/background.test.js b/6-pubsub/test/background.test.js new file mode 100644 index 0000000000..ddfe75696c --- /dev/null +++ b/6-pubsub/test/background.test.js @@ -0,0 +1,423 @@ +// Copyright 2015, 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. + +'use strict'; + +var assert = require('assert'); +var sinon = require('sinon'); +var proxyquire = require('proxyquire').noPreserveCache(); +var background; +var mocks = {}; + +describe('background.js', function () { + + beforeEach(function () { + // Mock dependencies used by background.js + mocks.gcloudConfig = sinon.stub(); + mocks.config = { + gcloud: sinon.stub() + }; + Object.defineProperty(mocks.config, 'gcloud', { + get: mocks.gcloudConfig + }); + mocks.subscription = { + on: sinon.stub() + }; + mocks.topic = { + subscribe: sinon.stub().callsArgWith(2, null, mocks.subscription), + publish: sinon.stub().callsArg(1) + }; + mocks.pubsub = { + createTopic: sinon.stub().callsArgWith(1, null, mocks.topic), + topic: sinon.stub().returns(mocks.topic) + }; + mocks.gcloud = { + pubsub: sinon.stub().returns(mocks.pubsub) + }; + mocks.logging = { + info: sinon.stub(), + error: sinon.stub() + }; + // Load background.js with provided mocks + background = proxyquire('../lib/background', { + gcloud: mocks.gcloud, + '../config': mocks.config + })(null, mocks.logging); + + assert.ok( + mocks.gcloudConfig.calledOnce, + 'config.gcloud should have been accessed' + ); + assert.ok( + mocks.gcloud.pubsub.calledOnce, + 'gcloud.pubsub() should have been called once' + ); + }); + + describe('subscribe()', function () { + it('should subscribe and log message', function (done) { + // Setup + var testMessage = 'test message'; + + // Run target functionality + background.subscribe(function (err, message) { + // Assertions + assert.ok( + err === null, + 'err should be null' + ); + assert.equal(message, testMessage, 'should have message'); + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right args' + ); + assert.equal( + mocks.pubsub.topic.callCount, + 0, + 'pubsub.topic() should NOT have been called' + ); + assert.ok( + mocks.topic.subscribe.calledOnce, + 'topic.subscribe should have been called once' + ); + assert.equal( + mocks.topic.subscribe.firstCall.args[0], + 'shared-worker-subscription', + 'topic.subscribe() should have been called with the right arguments' + ); + assert.deepEqual( + mocks.topic.subscribe.firstCall.args[1], + { + autoAck: true, + reuseExisting: true + }, + 'topic.subscribe() should have been called with the right arguments' + ); + assert.ok( + mocks.subscription.on.calledOnce, + 'subscription.on should have been called once' + ); + assert.equal( + mocks.subscription.on.firstCall.args[0], + 'message', + 'subscription.on() should have been called with the right arguments' + ); + assert.ok( + typeof mocks.subscription.on.firstCall.args[1] === 'function', + 'subscription.on() should have been called with the right arguments' + ); + done(); + }); + + // Trigger a message + setTimeout(function () { + mocks.subscription.on.firstCall.args[1]({ + data: testMessage + }); + }, 10); + }); + it('should return topic error, if any', function (done) { + // Setup + var testErrorMsg = 'test error'; + mocks.pubsub.createTopic = sinon.stub().callsArgWith(1, testErrorMsg); + + // Run target functionality + background.subscribe(function (data) { + // Assertions + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right args' + ); + assert.equal( + mocks.pubsub.topic.callCount, + 0, + 'pubsub.topic() should NOT have been called' + ); + assert.equal(data, testErrorMsg); + assert.equal( + mocks.topic.subscribe.callCount, + 0, + 'topic.subscribe() should NOT have been called' + ); + assert.equal( + mocks.subscription.on.callCount, + 0, + 'subscription.on() should NOT have been called' + ); + done(); + }); + }); + it('should return subscription error, if any', function (done) { + // Setup + var testErrorMsg = 'test error'; + mocks.topic.subscribe = sinon.stub().callsArgWith(2, testErrorMsg); + + // Run target functionality + background.subscribe(function (data) { + // Assertions + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right args' + ); + assert.equal( + mocks.pubsub.topic.callCount, + 0, + 'pubsub.topic() should NOT have been called' + ); + assert.ok( + mocks.topic.subscribe.calledOnce, + 'topic.subscribe should have been called once' + ); + assert.equal( + mocks.topic.subscribe.firstCall.args[0], + 'shared-worker-subscription', + 'topic.subscribe() should have been called with the right arguments' + ); + assert.deepEqual( + mocks.topic.subscribe.firstCall.args[1], + { + autoAck: true, + reuseExisting: true + }, + 'topic.subscribe() should have been called with the right arguments' + ); + assert.equal(data, testErrorMsg); + assert.equal( + mocks.subscription.on.callCount, + 0, + 'subscription.on() should NOT have been called' + ); + assert.equal( + mocks.logging.info.callCount, + 0, + 'logging.info() should NOT have been called' + ); + done(); + }); + }); + }); + + describe('queueBook()', function () { + it('should queue a book and log message', function () { + // Setup + var testBookId = 1; + + // Run target functionality + background.queueBook(testBookId); + + // Assertions + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right arguments' + ); + assert.equal( + mocks.pubsub.topic.callCount, + 0, + 'pubsub.topic() should NOT have been called' + ); + assert.ok( + mocks.topic.publish, + 'topic.publish() should have been called once' + ); + assert.deepEqual( + mocks.topic.publish.firstCall.args[0], + { + data: { + action: 'processBook', + bookId: testBookId + } + }, + 'topic.publish() should have been called with the right arguments' + ); + assert.ok( + mocks.logging.info.calledOnce, + 'logging.info() should have been called' + ); + assert.equal( + mocks.logging.info.firstCall.args[0], + 'Book ' + testBookId + ' queued for background processing', + 'logging.info() should have been called with the right arguments' + ); + }); + it('should queue a book and log message even if topic exists', function () { + // Setup + var testBookId = 1; + mocks.pubsub.createTopic = sinon.stub().callsArgWith(1, { + code: 409 + }); + + // Run target functionality + background.queueBook(testBookId); + + // Assertions + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right arguments' + ); + assert.ok( + mocks.pubsub.topic.calledOnce, + 'pubsub.topic() should have been called once' + ); + assert.equal( + mocks.pubsub.topic.firstCall.args[0], + 'book-process-queue', + 'pubsub.topic() should have been called with the right arguments' + ); + assert.ok( + mocks.topic.publish, + 'topic.publish() should have been called once' + ); + assert.deepEqual( + mocks.topic.publish.firstCall.args[0], + { + data: { + action: 'processBook', + bookId: testBookId + } + }, + 'topic.publish() should have been called with the right arguments' + ); + assert.ok( + mocks.logging.info.calledOnce, + 'logging.info() should have been called' + ); + assert.equal( + mocks.logging.info.firstCall.args[0], + 'Book ' + testBookId + ' queued for background processing', + 'logging.info() should have been called with the right arguments' + ); + }); + it('should log error if cannot get topic', function () { + // Setup + var testBookId = 1; + var testErrorMsg = 'test error'; + mocks.pubsub.createTopic = sinon.stub().callsArgWith(1, testErrorMsg); + + // Run target functionality + background.queueBook(testBookId); + + // Assertions + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right arguments' + ); + assert.equal( + mocks.pubsub.topic.callCount, + 0, + 'pubsub.topic() should NOT have been called' + ); + assert.equal( + mocks.topic.publish.callCount, + 0, + 'topic.publish() should NOT have been called' + ); + assert.equal( + mocks.logging.info.callCount, + 0, + 'logging.info() should NOT have been called' + ); + assert.ok( + mocks.logging.error.calledOnce, + 'logging.error() should have been called' + ); + assert.deepEqual( + mocks.logging.error.firstCall.args, + ['Error occurred while getting pubsub topic', testErrorMsg], + 'logging.error() should have been called with the right arguments' + ); + }); + it('should log error if cannot publish message', function () { + // Setup + var testBookId = 1; + var testErrorMsg = 'test error'; + mocks.topic.publish = sinon.stub().callsArgWith(1, testErrorMsg); + + // Run target functionality + background.queueBook(testBookId); + + // Assertions + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right arguments' + ); + assert.equal( + mocks.pubsub.topic.callCount, + 0, + 'pubsub.topic() should NOT have been called' + ); + assert.ok( + mocks.topic.publish, + 'topic.publish() should have been called once' + ); + assert.deepEqual( + mocks.topic.publish.firstCall.args[0], + { + data: { + action: 'processBook', + bookId: testBookId + } + }, + 'topic.publish() should have been called with the right arguments' + ); + assert.equal( + mocks.logging.info.callCount, + 0, + 'logging.info() should NOT have been called' + ); + assert.ok( + mocks.logging.error.calledOnce, + 'logging.error() should have been called' + ); + assert.deepEqual( + mocks.logging.error.firstCall.args, + ['Error occurred while queuing background task', testErrorMsg], + 'logging.error() should have been called with the right arguments' + ); + }); + }); +}); diff --git a/7-gce/app.js b/7-gce/app.js index d59a90b043..44dbd6093f 100644 --- a/7-gce/app.js +++ b/7-gce/app.js @@ -84,10 +84,14 @@ app.use(function(err, req, res, next) { }); -// Start the server -var server = app.listen(config.port, function () { - var host = server.address().address; - var port = server.address().port; +if (module === require.main) { + // Start the server + var server = app.listen(config.port, function () { + var host = server.address().address; + var port = server.address().port; - console.log('App listening at http://%s:%s', host, port); -}); + console.log('App listening at http://%s:%s', host, port); + }); +} + +module.exports = app; diff --git a/7-gce/config.js b/7-gce/config.js index a8dd97ca5e..3b7a3174be 100644 --- a/7-gce/config.js +++ b/7-gce/config.js @@ -28,7 +28,7 @@ module.exports = { // This is the id of your project in the Google Developers Console. gcloud: { - projectId: 'your-project-id' + projectId: process.env.TEST_PROJECT_ID || 'your-project-id' }, // Typically, you will create a bucket with the same name as your project ID. diff --git a/7-gce/package.json b/7-gce/package.json index d3837dd601..121807f6e7 100644 --- a/7-gce/package.json +++ b/7-gce/package.json @@ -8,8 +8,9 @@ "start": "node ${SCRIPT:-app.js}", "monitor": "nodemon ${SCRIPT:-app.js}", "deploy": "gcloud preview app deploy app.yaml worker.yaml", - "lint": "jshint --exclude-path=.gitignore .", - "test": "npm run lint", + "lint": "jshint --exclude-path=../.gitignore .", + "mocha": "mocha test/*.test.js", + "test": "npm run lint && npm run mocha", "init-cloudsql": "node books/model-cloudsql.js" }, "author": "Google Inc.", @@ -47,7 +48,11 @@ "winston": "^1.1.1" }, "devDependencies": { - "jshint": "^2.8.0" + "jshint": "^2.8.0", + "mocha": "^2.3.4", + "proxyquire": "^1.7.3", + "sinon": "^1.17.2", + "supertest": "^1.1.0" }, "engines": { "node": ">=0.12.7" diff --git a/7-gce/test/7-gce.test.js b/7-gce/test/7-gce.test.js new file mode 100644 index 0000000000..46f4ef2c98 --- /dev/null +++ b/7-gce/test/7-gce.test.js @@ -0,0 +1,72 @@ +// Copyright 2015, 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. + +'use strict'; + +var assert = require('assert'); +var path = require('path'); +var request = require('supertest'); +var utils = require('../../test/utils'); + +var config = { + test: '7-gce', + path: path.resolve(path.join(__dirname, '../')), + cmd: 'node', + args: ['app.js'], + msg: 'No books found.' +}; + +describe(config.test, function () { + + it('should install dependencies', function (done) { + this.timeout(60 * 1000); // Allow 1 minute to test installation + utils.testInstallation(config, done); + }); + + it('should redirect / to /books', function (done) { + request(require('../app')) + .get('/') + .expect(302) + .expect(function (response) { + assert.equal(response.text, 'Found. Redirecting to /books'); + }) + .end(done); + }); + + if (process.env.TEST_PROJECT_ID) { + it('should list books', function (done) { + request(require('../app')) + .get('/books') + .expect(200) + .expect(function (response) { + assert.ok(response.text.indexOf(config.msg) !== -1); + }) + .end(done); + }); + } + + it('should show add book form', function (done) { + request(require('../app')) + .get('/books/add') + .expect(200) + .expect(function (response) { + assert.ok(response.text.indexOf('Add book') !== -1); + }) + .end(done); + }); + + it('should run', function (done) { + this.timeout(15 * 1000); // Allow 15 seconds to test app + utils.testLocalApp(config, done); + }); +}); diff --git a/7-gce/test/background.test.js b/7-gce/test/background.test.js new file mode 100644 index 0000000000..ddfe75696c --- /dev/null +++ b/7-gce/test/background.test.js @@ -0,0 +1,423 @@ +// Copyright 2015, 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. + +'use strict'; + +var assert = require('assert'); +var sinon = require('sinon'); +var proxyquire = require('proxyquire').noPreserveCache(); +var background; +var mocks = {}; + +describe('background.js', function () { + + beforeEach(function () { + // Mock dependencies used by background.js + mocks.gcloudConfig = sinon.stub(); + mocks.config = { + gcloud: sinon.stub() + }; + Object.defineProperty(mocks.config, 'gcloud', { + get: mocks.gcloudConfig + }); + mocks.subscription = { + on: sinon.stub() + }; + mocks.topic = { + subscribe: sinon.stub().callsArgWith(2, null, mocks.subscription), + publish: sinon.stub().callsArg(1) + }; + mocks.pubsub = { + createTopic: sinon.stub().callsArgWith(1, null, mocks.topic), + topic: sinon.stub().returns(mocks.topic) + }; + mocks.gcloud = { + pubsub: sinon.stub().returns(mocks.pubsub) + }; + mocks.logging = { + info: sinon.stub(), + error: sinon.stub() + }; + // Load background.js with provided mocks + background = proxyquire('../lib/background', { + gcloud: mocks.gcloud, + '../config': mocks.config + })(null, mocks.logging); + + assert.ok( + mocks.gcloudConfig.calledOnce, + 'config.gcloud should have been accessed' + ); + assert.ok( + mocks.gcloud.pubsub.calledOnce, + 'gcloud.pubsub() should have been called once' + ); + }); + + describe('subscribe()', function () { + it('should subscribe and log message', function (done) { + // Setup + var testMessage = 'test message'; + + // Run target functionality + background.subscribe(function (err, message) { + // Assertions + assert.ok( + err === null, + 'err should be null' + ); + assert.equal(message, testMessage, 'should have message'); + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right args' + ); + assert.equal( + mocks.pubsub.topic.callCount, + 0, + 'pubsub.topic() should NOT have been called' + ); + assert.ok( + mocks.topic.subscribe.calledOnce, + 'topic.subscribe should have been called once' + ); + assert.equal( + mocks.topic.subscribe.firstCall.args[0], + 'shared-worker-subscription', + 'topic.subscribe() should have been called with the right arguments' + ); + assert.deepEqual( + mocks.topic.subscribe.firstCall.args[1], + { + autoAck: true, + reuseExisting: true + }, + 'topic.subscribe() should have been called with the right arguments' + ); + assert.ok( + mocks.subscription.on.calledOnce, + 'subscription.on should have been called once' + ); + assert.equal( + mocks.subscription.on.firstCall.args[0], + 'message', + 'subscription.on() should have been called with the right arguments' + ); + assert.ok( + typeof mocks.subscription.on.firstCall.args[1] === 'function', + 'subscription.on() should have been called with the right arguments' + ); + done(); + }); + + // Trigger a message + setTimeout(function () { + mocks.subscription.on.firstCall.args[1]({ + data: testMessage + }); + }, 10); + }); + it('should return topic error, if any', function (done) { + // Setup + var testErrorMsg = 'test error'; + mocks.pubsub.createTopic = sinon.stub().callsArgWith(1, testErrorMsg); + + // Run target functionality + background.subscribe(function (data) { + // Assertions + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right args' + ); + assert.equal( + mocks.pubsub.topic.callCount, + 0, + 'pubsub.topic() should NOT have been called' + ); + assert.equal(data, testErrorMsg); + assert.equal( + mocks.topic.subscribe.callCount, + 0, + 'topic.subscribe() should NOT have been called' + ); + assert.equal( + mocks.subscription.on.callCount, + 0, + 'subscription.on() should NOT have been called' + ); + done(); + }); + }); + it('should return subscription error, if any', function (done) { + // Setup + var testErrorMsg = 'test error'; + mocks.topic.subscribe = sinon.stub().callsArgWith(2, testErrorMsg); + + // Run target functionality + background.subscribe(function (data) { + // Assertions + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right args' + ); + assert.equal( + mocks.pubsub.topic.callCount, + 0, + 'pubsub.topic() should NOT have been called' + ); + assert.ok( + mocks.topic.subscribe.calledOnce, + 'topic.subscribe should have been called once' + ); + assert.equal( + mocks.topic.subscribe.firstCall.args[0], + 'shared-worker-subscription', + 'topic.subscribe() should have been called with the right arguments' + ); + assert.deepEqual( + mocks.topic.subscribe.firstCall.args[1], + { + autoAck: true, + reuseExisting: true + }, + 'topic.subscribe() should have been called with the right arguments' + ); + assert.equal(data, testErrorMsg); + assert.equal( + mocks.subscription.on.callCount, + 0, + 'subscription.on() should NOT have been called' + ); + assert.equal( + mocks.logging.info.callCount, + 0, + 'logging.info() should NOT have been called' + ); + done(); + }); + }); + }); + + describe('queueBook()', function () { + it('should queue a book and log message', function () { + // Setup + var testBookId = 1; + + // Run target functionality + background.queueBook(testBookId); + + // Assertions + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right arguments' + ); + assert.equal( + mocks.pubsub.topic.callCount, + 0, + 'pubsub.topic() should NOT have been called' + ); + assert.ok( + mocks.topic.publish, + 'topic.publish() should have been called once' + ); + assert.deepEqual( + mocks.topic.publish.firstCall.args[0], + { + data: { + action: 'processBook', + bookId: testBookId + } + }, + 'topic.publish() should have been called with the right arguments' + ); + assert.ok( + mocks.logging.info.calledOnce, + 'logging.info() should have been called' + ); + assert.equal( + mocks.logging.info.firstCall.args[0], + 'Book ' + testBookId + ' queued for background processing', + 'logging.info() should have been called with the right arguments' + ); + }); + it('should queue a book and log message even if topic exists', function () { + // Setup + var testBookId = 1; + mocks.pubsub.createTopic = sinon.stub().callsArgWith(1, { + code: 409 + }); + + // Run target functionality + background.queueBook(testBookId); + + // Assertions + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right arguments' + ); + assert.ok( + mocks.pubsub.topic.calledOnce, + 'pubsub.topic() should have been called once' + ); + assert.equal( + mocks.pubsub.topic.firstCall.args[0], + 'book-process-queue', + 'pubsub.topic() should have been called with the right arguments' + ); + assert.ok( + mocks.topic.publish, + 'topic.publish() should have been called once' + ); + assert.deepEqual( + mocks.topic.publish.firstCall.args[0], + { + data: { + action: 'processBook', + bookId: testBookId + } + }, + 'topic.publish() should have been called with the right arguments' + ); + assert.ok( + mocks.logging.info.calledOnce, + 'logging.info() should have been called' + ); + assert.equal( + mocks.logging.info.firstCall.args[0], + 'Book ' + testBookId + ' queued for background processing', + 'logging.info() should have been called with the right arguments' + ); + }); + it('should log error if cannot get topic', function () { + // Setup + var testBookId = 1; + var testErrorMsg = 'test error'; + mocks.pubsub.createTopic = sinon.stub().callsArgWith(1, testErrorMsg); + + // Run target functionality + background.queueBook(testBookId); + + // Assertions + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right arguments' + ); + assert.equal( + mocks.pubsub.topic.callCount, + 0, + 'pubsub.topic() should NOT have been called' + ); + assert.equal( + mocks.topic.publish.callCount, + 0, + 'topic.publish() should NOT have been called' + ); + assert.equal( + mocks.logging.info.callCount, + 0, + 'logging.info() should NOT have been called' + ); + assert.ok( + mocks.logging.error.calledOnce, + 'logging.error() should have been called' + ); + assert.deepEqual( + mocks.logging.error.firstCall.args, + ['Error occurred while getting pubsub topic', testErrorMsg], + 'logging.error() should have been called with the right arguments' + ); + }); + it('should log error if cannot publish message', function () { + // Setup + var testBookId = 1; + var testErrorMsg = 'test error'; + mocks.topic.publish = sinon.stub().callsArgWith(1, testErrorMsg); + + // Run target functionality + background.queueBook(testBookId); + + // Assertions + assert.ok( + mocks.pubsub.createTopic, + 'pubsub.createTopic() should have been called once' + ); + assert.equal( + mocks.pubsub.createTopic.firstCall.args[0], + 'book-process-queue', + 'pubsub.createTopic() should have been called with the right arguments' + ); + assert.equal( + mocks.pubsub.topic.callCount, + 0, + 'pubsub.topic() should NOT have been called' + ); + assert.ok( + mocks.topic.publish, + 'topic.publish() should have been called once' + ); + assert.deepEqual( + mocks.topic.publish.firstCall.args[0], + { + data: { + action: 'processBook', + bookId: testBookId + } + }, + 'topic.publish() should have been called with the right arguments' + ); + assert.equal( + mocks.logging.info.callCount, + 0, + 'logging.info() should NOT have been called' + ); + assert.ok( + mocks.logging.error.calledOnce, + 'logging.error() should have been called' + ); + assert.deepEqual( + mocks.logging.error.firstCall.args, + ['Error occurred while queuing background task', testErrorMsg], + 'logging.error() should have been called with the right arguments' + ); + }); + }); +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000000..9b54e7abc9 --- /dev/null +++ b/package.json @@ -0,0 +1,60 @@ +{ + "name": "nodejs-getting-started", + "version": "1.0.0", + "description": "End to end sample for running Node.JS applications on Google Cloud Platform", + "repository": "https://github.com/GoogleCloudPlatform/nodejs-getting-started", + "private": true, + "scripts": { + "lint": "jshint --exclude-path=.gitignore .", + "mocha": "mocha 1-hello-world/test/* 2-structured-data/test/* 3-binary-data/test/* 4-auth/test/* 5-logging/test/* 6-pubsub/test/* 7-gce/test/*", + "cover": "istanbul cover --hook-run-in-context node_modules/mocha/bin/_mocha -- 1-hello-world/test/* 2-structured-data/test/* 3-binary-data/test/* 4-auth/test/* 5-logging/test/* 6-pubsub/test/* 7-gce/test/*", + "test": "npm run lint && npm run cover", + "coveralls": "cat ./coverage/lcov.info | node_modules/coveralls/bin/coveralls.js" + }, + "author": "Google Inc.", + "contributors": [ + { + "name": "Jon Wayne Parrott", + "email": "jonwayne@google.com" + }, + { + "name": "Jonathan Simon", + "email": "jbsimon@google.com" + }, + { + "name": "Jason Dobry", + "email": "jdobry@google.com" + } + ], + "license": "Apache Version 2.0", + "dependencies": { + "async": "^1.5.0", + "body-parser": "^1.14.1", + "cookie-session": "^2.0.0-alpha.1", + "express": "^4.13.3", + "express-winston": "^0.4.1", + "gcloud": "^0.24.0", + "googleapis": "^2.1.5", + "jade": "^1.11.0", + "kerberos": "^0.0.17", + "lodash": "^3.10.1", + "mongodb": "^2.0.46", + "multer": "^1.1.0", + "mysql": "^2.9.0", + "prompt": "^0.2.14", + "request": "^2.65.0", + "winston": "^1.1.1" + }, + "devDependencies": { + "coveralls": "^2.11.4", + "istanbul": "^0.4.1", + "jshint": "^2.8.0", + "mocha": "^2.3.4", + "proxyquire": "^1.7.3", + "sinon": "^1.17.2", + "supertest": "^1.1.0" + }, + "engines": { + "node": ">=0.12.7" + } +} diff --git a/test/encrypted/nodejs-docs-samples.json.enc b/test/encrypted/nodejs-docs-samples.json.enc new file mode 100644 index 0000000000000000000000000000000000000000..cadf165cf64c0bc94b488181d75e31c7ebdfe21c GIT binary patch literal 2320 zcmV+r3Geo)bx5NL91Gb(jLM{O9psIRgKqJ`R_B(MTe4m-XDJoUE0K#`)>r1Hp2tf$ zHZ6BEqGtQp{@)gt?fQ_nj;fq5oSCitaVUqel8#+5&nY!DBJ!j$$M~3{zbE<_-2n5y zVgfSGtCi?vAK$S2mlII%07R$N#FRMO9s=<*d0+VgeO?Irms1t*CWFV7%{l{PTErcL z8S!3}`^HE$Gq^bLo?1}`z8kvG;QV{Mw$Vc!z3wxrWqTre7oh!ra)+(n27;8zt0vN< zSu&*YO0Y+s{4$)HSeY^t_9Q~8H}|?B?&0z}kIII~Vya^RiasoJt;8 z{aBgK9FCw=pmlL~$Oub+tG||F%MSvwST!IJ zw8?IW-4x~$E$P#&`-ix)TySQ^0KW0|e}CXfUB6Esng6Bkd*XJJ ziI32MxrfYB-^PZw7I6g3*^q4{*_uW9;Ca^bINdtXorpc@TpPJwcx+et-F$2g+S+UP z1mKC68gMR2M;&0pXS3CGY`=faA`{rBW6icjI<7B89&hHWIvrz+PIyxxMa_wJB*@O- zpEYb@MkRafS2w+dV-dLF9iTM%otSs#*_eTiKn-Gb6Tyok6(KrA1_uH+@)NNl|w z&r@^kO6k!k8~ISOC^MVc9g;vO@f1nUw4O<|2UC5fd?x*TeL@_K&ZT>Uzo|_t=c^lEKybuEjqkP8A;9!QjbLdv%}UjSfzI0Q&{`5qMQ5eU53JI<)MN6htCM*$ z%lCo;Eo3pZYk9sM(N@T1d4s_~JPY$Cr;T;M1$#)!kim_?@JMjbA2tQ_p zz8E{e;{{wk<181vO~nk%PXsp6&A%-hNI}Rl%o)$xBS0T!(MT;Ur%$&SCJJxQa@3@ZJOMmrsmWe~P3Kyd%y2}s`1&tBIm9O*Y?PQI zHH9pll2QSdK)|0Yo%L`%>g=goR)EpxOtU+!9-Pd>L>7YVzeW zUN+z7or}KVE*p8eF(pLhdv82GvVQDV-fY7N1wU#Z$0>ZC=4W=l@XQoCX(zS13KfAW za18LF0_3tjM10@_a+ugEbm@L0Hw`Y5%ufRJpTo{r(TYS9T0@Xj6p&9><+7H10e>>p zs9D|oVWs{Ne*U2$Y9=ER5J4T5 z_U<^nTXKs;iQP$5jbQHrSi5Sfd`$!{QBOXX4Va`)3RIU`PjwZ=2A<^3a}FkDV5M5W zjHBXF%wEXof-hAk+kc=ed_H?7j-S%kwk(b5ADGrP=mw2NqPz9|mF{?fTt({`^ODDA zzd*t^2FdW+RcfVL1{z^LJR+FYt)_MMRu1zA6I|&O1fXwJFfOdavYLB=4>}xbXq(y= z#zK=1V|6eGXFPABErilax)1)l#qgc@6D)!N%GGrexH?pWFf=2id)E$UUmzD&K6cl2 zsn>+V)P{<}zM}t1zHOuVE&^C9NcF3!J4o8Qm(81gy%W3+jmxURVSPpIK}m5q&b&DP z`nJfTJc8Q4{KlLAm5oFLPYO)WckPK}m&}c!&Fe~bF&QJ7oO=Ml55<-qw8L$7KTba{ z-+v1g$0iAgCUg_tG2fshq$E%`1|oII0L&d3^4zPb^mLakAR>4yJ?t{P!-a`Y?3b#A z4>l5M{3ITeOUy-^1ozv%z4#kQri{Xh%pdSv#!;escsRy7-8Rs+&YRhDO@g5RT<+;Y zdHgH4bp(V`T5(Ee8Fz@EL{rZ2Xt6af2)BT6aUkzU;_)~KRERJ_|FY7wKQ&>?pIhJj zK`2))3GCb;4PizsN_JM!aRt;%DB9+D*Vr2x5N!%0;rIEEF_6PtYf(R4{KdMuv@X3M?c6wwelt|OT%}DQ!Py|U+1KBa?C={o)oWU*r>QJ5-y-MiCQ`Pb6IQLA{m`* z0)j-K^g1?(>yw5rqe(JeI*MA`IV)7@*N;p-S{`*psE^ICu!<~)U}8%_9Ti0(5U2+7 zFsq@<3{_cv0J_B~aX7|w2PVAT7vgH%mD+wd@Xyse8pm#u1#R6RHOwd9>S9p`L8Yq2 z!5r|pZ+A<=u0NJ*g$os^^CFq0Ov8iR8c-6A7iO*C}1baM22ClQJDi+T?C zj;GfdrMcZbTC-ZhN&f#>hYkj;!*XvF&AVGqrxM5l4BX9 literal 0 HcmV?d00001 diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 0000000000..e34ce4fa5c --- /dev/null +++ b/test/utils.js @@ -0,0 +1,237 @@ +// Copyright 2015, 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. + +'use strict'; + +var spawn = require('child_process').spawn; +var request = require('request'); +var fs = require('fs'); +var async = require('async'); +var projectId = process.env.TEST_PROJECT_ID || 'nodejs-docs-samples'; + +// Send a request to the given url and test that the response body has the +// expected value +function testRequest(url, config, cb) { + request(url, function (err, res, body) { + if (err) { + // Request error + return cb(err); + } else { + if (body && body.indexOf(config.msg) !== -1 && + (res.statusCode === 200 || res.statusCode === config.code)) { + // Success + return cb(null, true); + } else { + // Short-circuit app test + var message = config.test + ': failed verification!\n' + + 'Expected: ' + config.msg + '\n' + + 'Actual: ' + body; + + // Response body did not match expected + return cb(new Error(message)); + } + } + }); +} + +exports.testInstallation = function testInstallation(config, done) { + + // Keep track off whether "done" has been called yet + var calledDone = false; + + var proc = spawn('npm', ['install'], { + cwd: config.path + }); + + proc.on('error', finish); + + if (!process.env.TRAVIS) { + proc.stderr.on('data', function (data) { + console.log('stderr: ' + data); + }); + } + + proc.on('exit', function (code) { + if (code !== 0) { + finish(new Error(config.test + ': failed to install dependencies!')); + } else { + finish(); + } + }); + + // Exit helper so we don't call "cb" more than once + function finish(err) { + if (!calledDone) { + calledDone = true; + done(err); + } + } +}; + +exports.testLocalApp = function testLocalApp(config, done) { + var calledDone = false; + + var proc = spawn(config.cmd, config.args, { + cwd: config.path + }); + + proc.on('error', finish); + + if (!process.env.TRAVIS) { + proc.stderr.on('data', function (data) { + console.log('stderr: ' + data); + }); + } + + proc.on('exit', function (code, signal) { + if (code !== 0 && signal !== 'SIGKILL') { + return finish(new Error(config.test + ': failed to run!')); + } else { + return finish(); + } + }); + + // Give the server time to start up + setTimeout(function () { + // Test that the app is working + testRequest('http://localhost:8080', config, function (err) { + proc.kill('SIGKILL'); + setTimeout(function () { + return finish(err); + }, 1000); + }); + }, 3000); + + // Exit helper so we don't call "cb" more than once + function finish(err) { + if (!calledDone) { + calledDone = true; + done(err); + } + } +}; + +exports.testDeployment = function testDeployment(config, done) { + + // Keep track off whether "cb" has been called yet + var calledDone = false; + // Keep track off whether the logs have fully flushed + var logFinished = false; + + var _cwd = config.path; + var args = [ + 'preview', + 'app', + 'deploy', + 'app.yaml', + // Skip prompt + '-q', + '--project', + projectId, + // Deploy over existing version so we don't have to clean up + '--version', + config.test, + // Override any existing deployment + '--force', + config.promote ? '--promote' : '--no-promote', + // Build locally, much faster + '--docker-build', + config.dockerBuild ? config.dockerBuild : 'local', + '--verbosity', + 'debug' + ]; + + console.log(_cwd + ' $ gcloud ' + args.join(' ')); + + var logFile = (process.env.TRAVIS_BUILD_DIR || _cwd + '/..') + + '/' + + config.test + + '-' + + (process.env.TRAVIS_BUILD_ID || 0) + + '-' + + (process.env.TRAVIS_BUILD_NUMBER || 0) + + '-' + + (process.env.TRAVIS_JOB_ID || 0) + + '-' + + (process.env.TRAVIS_JOB_NUMBER || 0) + + '.log'; + + var logStream = fs.createWriteStream(logFile, { flags: 'a' }); + + // Don't use "npm run deploy" because we need extra flags + var proc = spawn('gcloud', args, { + cwd: _cwd + }); + + // Exit helper so we don't call "cb" more than once + function finish(err, result) { + if (!calledDone) { + calledDone = true; + var intervalId = setInterval(function () { + if (logFinished) { + clearInterval(intervalId); + done(err, result); + } + }, 1000); + } + } + + logStream.on('finish', function () { + if (!logFinished) { + logFinished = true; + } + }); + + proc.stdout.pipe(logStream, { end: false }); + proc.stderr.pipe(logStream, { end: false }); + + var numEnded = 0; + + function finishLogs() { + numEnded++; + if (numEnded === 2) { + logStream.end(); + console.log('Saved logs for ' + config.test + ' to ' + logFile); + } + } + + proc.stdout.on('end', finishLogs); + proc.stderr.on('end', finishLogs); + + // This is called if the process fails to start. "error" event may or may + // not be fired in addition to the "exit" event. + proc.on('error', finish); + + // Process has completed + proc.on('exit', function (code) { + if (code !== 0) { // Deployment failed + // Pass error as second argument so we don't short-circuit the + // parallel tasks + return finish(new Error(config.test + ': failed to deploy!')); + } else { // Deployment succeeded + // Test that sample app is running successfully + return async.waterfall([ + function (cb) { + // Give apps time to start + setTimeout(cb, 5000); + }, + function (cb) { + // Test versioned url of "default" module + var demoUrl = 'http://' + config.test + '-dot-' + projectId + + '.appspot.com'; + testRequest(demoUrl, config, cb); + } + ], finish); + } + }); +}; From 445bb3996702b5b686000ec00a9d31fe9fd84101 Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Tue, 2 Feb 2016 10:58:02 -0800 Subject: [PATCH 2/2] Upgraded dependencies. Added tests for creating and deleting books. --- .travis.yml | 17 +-- 1-hello-world/app.js | 2 +- 1-hello-world/app.yaml | 2 +- 1-hello-world/package.json | 6 +- 1-hello-world/test/1-hello-world.test.js | 10 +- 2-structured-data/app.js | 2 +- 2-structured-data/app.yaml | 2 +- 2-structured-data/books/api.js | 2 +- 2-structured-data/books/crud.js | 2 +- 2-structured-data/books/model-cloudsql.js | 2 +- 2-structured-data/books/model-datastore.js | 5 +- 2-structured-data/books/model-mongodb.js | 2 +- 2-structured-data/config.js | 4 +- 2-structured-data/package.json | 8 +- .../test/2-structured-data.test.js | 52 +++++-- 2-structured-data/views/base.jade | 2 +- 2-structured-data/views/books/form.jade | 2 +- 2-structured-data/views/books/list.jade | 2 +- 2-structured-data/views/books/view.jade | 2 +- 3-binary-data/app.js | 2 +- 3-binary-data/app.yaml | 2 +- 3-binary-data/books/api.js | 2 +- 3-binary-data/books/crud.js | 2 +- 3-binary-data/books/model-cloudsql.js | 2 +- 3-binary-data/books/model-datastore.js | 5 +- 3-binary-data/books/model-mongodb.js | 2 +- 3-binary-data/config.js | 4 +- 3-binary-data/lib/images.js | 2 +- 3-binary-data/package.json | 8 +- 3-binary-data/test/3-binary-data.test.js | 52 +++++-- 3-binary-data/views/base.jade | 2 +- 3-binary-data/views/books/form.jade | 2 +- 3-binary-data/views/books/list.jade | 2 +- 3-binary-data/views/books/view.jade | 2 +- 4-auth/app.js | 2 +- 4-auth/app.yaml | 2 +- 4-auth/books/api.js | 2 +- 4-auth/books/crud.js | 2 +- 4-auth/books/model-cloudsql.js | 2 +- 4-auth/books/model-datastore.js | 5 +- 4-auth/books/model-mongodb.js | 2 +- 4-auth/config.js | 4 +- 4-auth/lib/images.js | 2 +- 4-auth/lib/oauth2.js | 2 +- 4-auth/package.json | 8 +- 4-auth/test/4-auth.test.js | 51 +++++-- 4-auth/views/base.jade | 2 +- 4-auth/views/books/form.jade | 2 +- 4-auth/views/books/list.jade | 2 +- 4-auth/views/books/view.jade | 2 +- 5-logging/app.js | 2 +- 5-logging/app.yaml | 2 +- 5-logging/books/api.js | 2 +- 5-logging/books/crud.js | 2 +- 5-logging/books/model-cloudsql.js | 2 +- 5-logging/books/model-datastore.js | 5 +- 5-logging/books/model-mongodb.js | 2 +- 5-logging/config.js | 4 +- 5-logging/lib/images.js | 2 +- 5-logging/lib/logging.js | 2 +- 5-logging/lib/oauth2.js | 2 +- 5-logging/package.json | 8 +- 5-logging/test/5-logging.test.js | 52 +++++-- 5-logging/views/base.jade | 2 +- 5-logging/views/books/form.jade | 2 +- 5-logging/views/books/list.jade | 2 +- 5-logging/views/books/view.jade | 2 +- 6-pubsub/app.js | 2 +- 6-pubsub/app.yaml | 2 +- 6-pubsub/books/api.js | 2 +- 6-pubsub/books/crud.js | 2 +- 6-pubsub/books/model-cloudsql.js | 2 +- 6-pubsub/books/model-datastore.js | 8 +- 6-pubsub/books/model-mongodb.js | 2 +- 6-pubsub/config.js | 4 +- 6-pubsub/lib/background.js | 2 +- 6-pubsub/lib/images.js | 2 +- 6-pubsub/lib/logging.js | 2 +- 6-pubsub/lib/oauth2.js | 2 +- 6-pubsub/package.json | 14 +- 6-pubsub/test/6-pubsub.test.js | 52 +++++-- 6-pubsub/test/background.test.js | 2 +- 6-pubsub/views/base.jade | 2 +- 6-pubsub/views/books/form.jade | 2 +- 6-pubsub/views/books/list.jade | 2 +- 6-pubsub/views/books/view.jade | 2 +- 6-pubsub/worker.js | 4 +- 6-pubsub/worker.yaml | 2 +- 7-gce/app.js | 2 +- 7-gce/app.yaml | 2 +- 7-gce/books/api.js | 2 +- 7-gce/books/crud.js | 2 +- 7-gce/books/model-cloudsql.js | 2 +- 7-gce/books/model-datastore.js | 8 +- 7-gce/books/model-mongodb.js | 2 +- 7-gce/config.js | 4 +- 7-gce/gce/startup-script.sh | 2 +- 7-gce/lib/background.js | 2 +- 7-gce/lib/images.js | 2 +- 7-gce/lib/logging.js | 2 +- 7-gce/lib/oauth2.js | 2 +- 7-gce/package.json | 14 +- 7-gce/test/7-gce.test.js | 52 +++++-- 7-gce/test/background.test.js | 2 +- 7-gce/views/base.jade | 2 +- 7-gce/views/books/form.jade | 2 +- 7-gce/views/books/list.jade | 2 +- 7-gce/views/books/view.jade | 2 +- 7-gce/worker.js | 4 +- 7-gce/worker.yaml | 2 +- package.json | 40 +++--- test/utils.js | 128 +----------------- 112 files changed, 407 insertions(+), 395 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2da76b4a18..26cc89a6b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -# Copyright 2015, Google, Inc. +# Copyright 2015-2016, 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 @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -sudo: required +sudo: false language: node_js node_js: - "stable" @@ -28,13 +28,9 @@ cache: - 5-logging/node_modules/ - 6-pubsub/node_modules/ - 7-gce/node_modules/ - - $TRAVIS_BUILD_DIR/node_modules/ - -services: - - docker env: - - PATH=$PATH:$HOME/gcloud/google-cloud-sdk/bin GOOGLE_APPLICATION_CREDENTIALS=$TRAVIS_BUILD_DIR/test/encrypted/nodejs-docs-samples.json TEST_BUCKET_NAME=nodejs-docs-samples TEST_PROJECT_ID=nodejs-docs-samples #Other environment variables on same line + - PATH=$PATH:$HOME/gcloud/google-cloud-sdk/bin GOOGLE_APPLICATION_CREDENTIALS=$TRAVIS_BUILD_DIR/test/encrypted/nodejs-docs-samples.json TEST_BUCKET_NAME=nodejs-docs-samples GCLOUD_PROJECT=nodejs-docs-samples #Other environment variables on same line before_install: - if [ ! -d $HOME/gcloud/google-cloud-sdk ]; then @@ -43,11 +39,9 @@ before_install: cd $HOME/gcloud && tar xzf google-cloud-sdk.tar.gz && printf '\ny\n\ny\ny\n' | ./google-cloud-sdk/install.sh && - source /home/travis/.bash_profile && + source $HOME/.bashrc && cd $TRAVIS_BUILD_DIR; fi - - gcloud components update -q - - gcloud components update app -q - openssl aes-256-cbc -K $encrypted_06352980ac5c_key -iv $encrypted_06352980ac5c_iv -in test/encrypted/nodejs-docs-samples.json.enc -out test/encrypted/nodejs-docs-samples.json -d - if [ -a test/encrypted/nodejs-docs-samples.json ]; then gcloud auth activate-service-account --key-file test/encrypted/nodejs-docs-samples.json; @@ -55,6 +49,3 @@ before_install: after_success: - npm run coveralls - -after_script: - - gsutil -m cp *.log gs://nodejs-docs-samples-travis-deployments diff --git a/1-hello-world/app.js b/1-hello-world/app.js index 8c71d06d13..4d99aead3e 100644 --- a/1-hello-world/app.js +++ b/1-hello-world/app.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/1-hello-world/app.yaml b/1-hello-world/app.yaml index b4e5381ed7..f90ff8a1f2 100644 --- a/1-hello-world/app.yaml +++ b/1-hello-world/app.yaml @@ -1,4 +1,4 @@ -# Copyright 2015, Google, Inc. +# Copyright 2015-2016, 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 diff --git a/1-hello-world/package.json b/1-hello-world/package.json index 6e7bea8000..f43fbcf0e4 100644 --- a/1-hello-world/package.json +++ b/1-hello-world/package.json @@ -9,7 +9,7 @@ "monitor": "nodemon app.js", "deploy": "gcloud preview app deploy app.yaml", "lint": "jshint --exclude-path=../.gitignore .", - "mocha": "mocha test/*.test.js", + "mocha": "mocha test/*.test.js -t 30000", "test": "npm run lint && npm run mocha" }, "author": "Google Inc.", @@ -29,11 +29,11 @@ ], "license": "Apache Version 2.0", "dependencies": { - "express": "^4.13.3" + "express": "^4.13.4" }, "devDependencies": { "jshint": "^2.9.1", - "mocha": "^2.3.4", + "mocha": "^2.4.5", "supertest": "^1.1.0" }, "engines": { diff --git a/1-hello-world/test/1-hello-world.test.js b/1-hello-world/test/1-hello-world.test.js index d00874a104..ae6cce107f 100644 --- a/1-hello-world/test/1-hello-world.test.js +++ b/1-hello-world/test/1-hello-world.test.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -44,14 +44,6 @@ describe(config.test, function () { }); it('should run', function (done) { - this.timeout(15 * 1000); // Allow 15 seconds to test app utils.testLocalApp(config, done); }); - - if (process.env.TRAVIS && process.env.TRAVIS_NODE_VERSION === 'stable') { - it('should deploy', function (done) { - this.timeout(10 * 60 * 1000); // Allow 10 minutes to deploy app :( - utils.testDeployment(config, done); - }); - } }); diff --git a/2-structured-data/app.js b/2-structured-data/app.js index c7eee4d5ff..dc8394b456 100644 --- a/2-structured-data/app.js +++ b/2-structured-data/app.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/2-structured-data/app.yaml b/2-structured-data/app.yaml index 3e5c27cc72..13a38d297f 100644 --- a/2-structured-data/app.yaml +++ b/2-structured-data/app.yaml @@ -1,4 +1,4 @@ -# Copyright 2015, Google, Inc. +# Copyright 2015-2016, 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 diff --git a/2-structured-data/books/api.js b/2-structured-data/books/api.js index dafd1c18f1..0d195c2391 100644 --- a/2-structured-data/books/api.js +++ b/2-structured-data/books/api.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/2-structured-data/books/crud.js b/2-structured-data/books/crud.js index 7ef21a028f..644322343d 100644 --- a/2-structured-data/books/crud.js +++ b/2-structured-data/books/crud.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/2-structured-data/books/model-cloudsql.js b/2-structured-data/books/model-cloudsql.js index 987c2ebc96..f96cfa9724 100644 --- a/2-structured-data/books/model-cloudsql.js +++ b/2-structured-data/books/model-cloudsql.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/2-structured-data/books/model-datastore.js b/2-structured-data/books/model-datastore.js index 5a8c84d33c..5dc682cf5c 100644 --- a/2-structured-data/books/model-datastore.js +++ b/2-structured-data/books/model-datastore.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -124,7 +124,8 @@ module.exports = function(config) { ds.save( entity, function(err) { - cb(err, err ? null : fromDatastore(entity)); + data.id = entity.key.id; + cb(err, err ? null : data); } ); } diff --git a/2-structured-data/books/model-mongodb.js b/2-structured-data/books/model-mongodb.js index d2798f061b..a0978a7e5f 100644 --- a/2-structured-data/books/model-mongodb.js +++ b/2-structured-data/books/model-mongodb.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/2-structured-data/config.js b/2-structured-data/config.js index 076db7f053..7a511674f7 100644 --- a/2-structured-data/config.js +++ b/2-structured-data/config.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -25,7 +25,7 @@ module.exports = { // This is the id of your project in the Google Developers Console. gcloud: { - projectId: process.env.TEST_PROJECT_ID || 'your-project-id' + projectId: process.env.GCLOUD_PROJECT || 'your-project-id' }, mysql: { diff --git a/2-structured-data/package.json b/2-structured-data/package.json index 8667a9d5cb..7cd2ca8455 100644 --- a/2-structured-data/package.json +++ b/2-structured-data/package.json @@ -9,7 +9,7 @@ "monitor": "nodemon app.js", "deploy": "gcloud preview app deploy app.yaml", "lint": "jshint --exclude-path=../.gitignore .", - "mocha": "mocha test/*.test.js", + "mocha": "mocha test/*.test.js -t 30000", "test": "npm run lint && npm run mocha", "init-cloudsql": "node books/model-cloudsql.js" }, @@ -31,18 +31,18 @@ "license": "Apache Version 2.0", "dependencies": { "body-parser": "^1.14.2", - "express": "^4.13.3", + "express": "^4.13.4", "gcloud": "^0.27.0", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.0.0", + "lodash": "^4.2.1", "mongodb": "^2.1.4", "mysql": "^2.10.2", "prompt": "^0.2.14" }, "devDependencies": { "jshint": "^2.9.1", - "mocha": "^2.3.4", + "mocha": "^2.4.5", "supertest": "^1.1.0" }, "engines": { diff --git a/2-structured-data/test/2-structured-data.test.js b/2-structured-data/test/2-structured-data.test.js index 2c4968a3eb..eb510d06f6 100644 --- a/2-structured-data/test/2-structured-data.test.js +++ b/2-structured-data/test/2-structured-data.test.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -38,22 +38,47 @@ describe(config.test, function () { .get('/') .expect(302) .expect(function (response) { - assert.equal(response.text, 'Found. Redirecting to /books'); + assert.ok(response.text.indexOf('Redirecting to /books') !== -1); }) .end(done); }); - if (process.env.TEST_PROJECT_ID) { - it('should list books', function (done) { - request(require('../app')) - .get('/books') - .expect(200) - .expect(function (response) { - assert.ok(response.text.indexOf(config.msg) !== -1); - }) - .end(done); - }); - } + var id; + + it('should create a book', function (done) { + request(require('../app')) + .post('/api/books') + .send({ foo: 'bar', title: 'beep' }) + .expect(200) + .expect(function (response) { + id = response.body.id; + assert.ok(response.body.id); + assert.equal(response.body.foo, 'bar'); + assert.equal(response.body.title, 'beep'); + }) + .end(done); + }); + + it('should list books', function (done) { + request(require('../app')) + .get('/api/books') + .expect(200) + .expect(function (response) { + assert.ok(Array.isArray(response.body.items)); + assert.ok(response.body.items.length >= 1); + }) + .end(done); + }); + + it('should delete a book', function (done) { + request(require('../app')) + .delete('/api/books/' + id) + .expect(200) + .expect(function (response) { + assert.equal(response.text, 'OK'); + }) + .end(done); + }); it('should show add book form', function (done) { request(require('../app')) @@ -66,7 +91,6 @@ describe(config.test, function () { }); it('should run', function (done) { - this.timeout(15 * 1000); // Allow 15 seconds to test app utils.testLocalApp(config, done); }); }); diff --git a/2-structured-data/views/base.jade b/2-structured-data/views/base.jade index 3d6bbe3afa..7a93bf7156 100644 --- a/2-structured-data/views/base.jade +++ b/2-structured-data/views/base.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/2-structured-data/views/books/form.jade b/2-structured-data/views/books/form.jade index afac36b0a8..24fcc7c0bc 100644 --- a/2-structured-data/views/books/form.jade +++ b/2-structured-data/views/books/form.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/2-structured-data/views/books/list.jade b/2-structured-data/views/books/list.jade index ab2fce0fe0..3ecd5b5f05 100644 --- a/2-structured-data/views/books/list.jade +++ b/2-structured-data/views/books/list.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/2-structured-data/views/books/view.jade b/2-structured-data/views/books/view.jade index ad808d406f..760730fed6 100644 --- a/2-structured-data/views/books/view.jade +++ b/2-structured-data/views/books/view.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/3-binary-data/app.js b/3-binary-data/app.js index cb3a158d69..13a306adda 100644 --- a/3-binary-data/app.js +++ b/3-binary-data/app.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/3-binary-data/app.yaml b/3-binary-data/app.yaml index 3e5c27cc72..13a38d297f 100644 --- a/3-binary-data/app.yaml +++ b/3-binary-data/app.yaml @@ -1,4 +1,4 @@ -# Copyright 2015, Google, Inc. +# Copyright 2015-2016, 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 diff --git a/3-binary-data/books/api.js b/3-binary-data/books/api.js index dafd1c18f1..0d195c2391 100644 --- a/3-binary-data/books/api.js +++ b/3-binary-data/books/api.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/3-binary-data/books/crud.js b/3-binary-data/books/crud.js index e89bf659eb..e51c6e6e8b 100644 --- a/3-binary-data/books/crud.js +++ b/3-binary-data/books/crud.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/3-binary-data/books/model-cloudsql.js b/3-binary-data/books/model-cloudsql.js index a988be9adb..e0278ac8c6 100644 --- a/3-binary-data/books/model-cloudsql.js +++ b/3-binary-data/books/model-cloudsql.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/3-binary-data/books/model-datastore.js b/3-binary-data/books/model-datastore.js index a96b12fbc7..1979693049 100644 --- a/3-binary-data/books/model-datastore.js +++ b/3-binary-data/books/model-datastore.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -119,7 +119,8 @@ module.exports = function(config) { ds.save( entity, function(err) { - cb(err, err ? null : fromDatastore(entity)); + data.id = entity.key.id; + cb(err, err ? null : data); } ); } diff --git a/3-binary-data/books/model-mongodb.js b/3-binary-data/books/model-mongodb.js index b224cffc15..fd811e45db 100644 --- a/3-binary-data/books/model-mongodb.js +++ b/3-binary-data/books/model-mongodb.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/3-binary-data/config.js b/3-binary-data/config.js index 10fa8fe954..66b422da27 100644 --- a/3-binary-data/config.js +++ b/3-binary-data/config.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -25,7 +25,7 @@ module.exports = { // This is the id of your project in the Google Developers Console. gcloud: { - projectId: process.env.TEST_PROJECT_ID || 'your-project-id' + projectId: process.env.GCLOUD_PROJECT || 'your-project-id' }, // Typically, you will create a bucket with the same name as your project ID. diff --git a/3-binary-data/lib/images.js b/3-binary-data/lib/images.js index 00e4cafd95..4aa78eb828 100644 --- a/3-binary-data/lib/images.js +++ b/3-binary-data/lib/images.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/3-binary-data/package.json b/3-binary-data/package.json index d7fa97f54f..173132dff7 100644 --- a/3-binary-data/package.json +++ b/3-binary-data/package.json @@ -9,7 +9,7 @@ "monitor": "nodemon app.js", "deploy": "gcloud preview app deploy app.yaml", "lint": "jshint --exclude-path=../.gitignore .", - "mocha": "mocha test/*.test.js", + "mocha": "mocha test/*.test.js -t 30000", "test": "npm run lint && npm run mocha", "init-cloudsql": "node books/model-cloudsql.js" }, @@ -31,11 +31,11 @@ "license": "Apache Version 2.0", "dependencies": { "body-parser": "^1.14.2", - "express": "^4.13.3", + "express": "^4.13.4", "gcloud": "^0.27.0", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.0.0", + "lodash": "^4.2.1", "mongodb": "^2.1.4", "multer": "^1.1.0", "mysql": "^2.10.2", @@ -43,7 +43,7 @@ }, "devDependencies": { "jshint": "^2.9.1", - "mocha": "^2.3.4", + "mocha": "^2.4.5", "supertest": "^1.1.0" }, "engines": { diff --git a/3-binary-data/test/3-binary-data.test.js b/3-binary-data/test/3-binary-data.test.js index d275e40a40..9b22688a2d 100644 --- a/3-binary-data/test/3-binary-data.test.js +++ b/3-binary-data/test/3-binary-data.test.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -38,22 +38,47 @@ describe(config.test, function () { .get('/') .expect(302) .expect(function (response) { - assert.equal(response.text, 'Found. Redirecting to /books'); + assert.ok(response.text.indexOf('Redirecting to /books') !== -1); }) .end(done); }); - if (process.env.TEST_PROJECT_ID) { - it('should list books', function (done) { - request(require('../app')) - .get('/books') - .expect(200) - .expect(function (response) { - assert.ok(response.text.indexOf(config.msg) !== -1); - }) - .end(done); - }); - } + var id; + + it('should create a book', function (done) { + request(require('../app')) + .post('/api/books') + .send({ foo: 'bar', title: 'beep' }) + .expect(200) + .expect(function (response) { + id = response.body.id; + assert.ok(response.body.id); + assert.equal(response.body.foo, 'bar'); + assert.equal(response.body.title, 'beep'); + }) + .end(done); + }); + + it('should list books', function (done) { + request(require('../app')) + .get('/api/books') + .expect(200) + .expect(function (response) { + assert.ok(Array.isArray(response.body.items)); + assert.ok(response.body.items.length >= 1); + }) + .end(done); + }); + + it('should delete a book', function (done) { + request(require('../app')) + .delete('/api/books/' + id) + .expect(200) + .expect(function (response) { + assert.equal(response.text, 'OK'); + }) + .end(done); + }); it('should show add book form', function (done) { request(require('../app')) @@ -66,7 +91,6 @@ describe(config.test, function () { }); it('should run', function (done) { - this.timeout(15 * 1000); // Allow 15 seconds to test app utils.testLocalApp(config, done); }); }); diff --git a/3-binary-data/views/base.jade b/3-binary-data/views/base.jade index 3d6bbe3afa..7a93bf7156 100644 --- a/3-binary-data/views/base.jade +++ b/3-binary-data/views/base.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/3-binary-data/views/books/form.jade b/3-binary-data/views/books/form.jade index abf50cbfca..36a6308a9d 100644 --- a/3-binary-data/views/books/form.jade +++ b/3-binary-data/views/books/form.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/3-binary-data/views/books/list.jade b/3-binary-data/views/books/list.jade index 38977aa211..dd453386ba 100644 --- a/3-binary-data/views/books/list.jade +++ b/3-binary-data/views/books/list.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/3-binary-data/views/books/view.jade b/3-binary-data/views/books/view.jade index 7b0efe5696..55e7a4532c 100644 --- a/3-binary-data/views/books/view.jade +++ b/3-binary-data/views/books/view.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/4-auth/app.js b/4-auth/app.js index e3435f4ec2..4d4f5883dd 100644 --- a/4-auth/app.js +++ b/4-auth/app.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/4-auth/app.yaml b/4-auth/app.yaml index cf826b98f5..069f5f04c6 100644 --- a/4-auth/app.yaml +++ b/4-auth/app.yaml @@ -1,4 +1,4 @@ -# Copyright 2015, Google, Inc. +# Copyright 2015-2016, 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 diff --git a/4-auth/books/api.js b/4-auth/books/api.js index dafd1c18f1..0d195c2391 100644 --- a/4-auth/books/api.js +++ b/4-auth/books/api.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/4-auth/books/crud.js b/4-auth/books/crud.js index bbddf25590..9c93d99495 100644 --- a/4-auth/books/crud.js +++ b/4-auth/books/crud.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/4-auth/books/model-cloudsql.js b/4-auth/books/model-cloudsql.js index b64a9ebbc1..2df73df4a6 100644 --- a/4-auth/books/model-cloudsql.js +++ b/4-auth/books/model-cloudsql.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/4-auth/books/model-datastore.js b/4-auth/books/model-datastore.js index 07fda19768..2fac0d88de 100644 --- a/4-auth/books/model-datastore.js +++ b/4-auth/books/model-datastore.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -136,7 +136,8 @@ module.exports = function(config) { ds.save( entity, function(err) { - cb(err, err ? null : fromDatastore(entity)); + data.id = entity.key.id; + cb(err, err ? null : data); } ); } diff --git a/4-auth/books/model-mongodb.js b/4-auth/books/model-mongodb.js index bee809d9eb..216def4058 100644 --- a/4-auth/books/model-mongodb.js +++ b/4-auth/books/model-mongodb.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/4-auth/config.js b/4-auth/config.js index b9fd3a8a34..7f8611d575 100644 --- a/4-auth/config.js +++ b/4-auth/config.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -28,7 +28,7 @@ module.exports = { // This is the id of your project in the Google Developers Console. gcloud: { - projectId: process.env.TEST_PROJECT_ID || 'your-project-id' + projectId: process.env.GCLOUD_PROJECT || 'your-project-id' }, // Typically, you will create a bucket with the same name as your project ID. diff --git a/4-auth/lib/images.js b/4-auth/lib/images.js index 3dc199441b..f2d17de98e 100644 --- a/4-auth/lib/images.js +++ b/4-auth/lib/images.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/4-auth/lib/oauth2.js b/4-auth/lib/oauth2.js index b2b85066b7..b514ebc52b 100644 --- a/4-auth/lib/oauth2.js +++ b/4-auth/lib/oauth2.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/4-auth/package.json b/4-auth/package.json index c652f21a59..4e083b1759 100644 --- a/4-auth/package.json +++ b/4-auth/package.json @@ -9,7 +9,7 @@ "monitor": "nodemon app.js", "deploy": "gcloud preview app deploy app.yaml", "lint": "jshint --exclude-path=../.gitignore .", - "mocha": "mocha test/*.test.js", + "mocha": "mocha test/*.test.js -t 30000", "test": "npm run lint && npm run mocha", "init-cloudsql": "node books/model-cloudsql.js" }, @@ -33,12 +33,12 @@ "async": "^1.5.2", "body-parser": "^1.14.2", "cookie-session": "^2.0.0-alpha.1", - "express": "^4.13.3", + "express": "^4.13.4", "gcloud": "^0.27.0", "googleapis": "^2.1.7", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.0.0", + "lodash": "^4.2.1", "mongodb": "^2.1.4", "multer": "^1.1.0", "mysql": "^2.10.2", @@ -46,7 +46,7 @@ }, "devDependencies": { "jshint": "^2.9.1", - "mocha": "^2.3.4", + "mocha": "^2.4.5", "supertest": "^1.1.0" }, "engines": { diff --git a/4-auth/test/4-auth.test.js b/4-auth/test/4-auth.test.js index b2541fc6ef..e5be96076f 100644 --- a/4-auth/test/4-auth.test.js +++ b/4-auth/test/4-auth.test.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -38,22 +38,47 @@ describe(config.test, function () { .get('/') .expect(302) .expect(function (response) { - assert.equal(response.text, 'Found. Redirecting to /books'); + assert.ok(response.text.indexOf('Redirecting to /books') !== -1); }) .end(done); }); - if (process.env.TEST_PROJECT_ID) { - it('should list books', function (done) { - request(require('../app')) - .get('/books') - .expect(200) - .expect(function (response) { - assert.ok(response.text.indexOf(config.msg) !== -1); - }) - .end(done); - }); - } + var id; + + it('should create a book', function (done) { + request(require('../app')) + .post('/api/books') + .send({ foo: 'bar', title: 'beep' }) + .expect(200) + .expect(function (response) { + id = response.body.id; + assert.ok(response.body.id); + assert.equal(response.body.foo, 'bar'); + assert.equal(response.body.title, 'beep'); + }) + .end(done); + }); + + it('should list books', function (done) { + request(require('../app')) + .get('/api/books') + .expect(200) + .expect(function (response) { + assert.ok(Array.isArray(response.body.items)); + assert.ok(response.body.items.length >= 1); + }) + .end(done); + }); + + it('should delete a book', function (done) { + request(require('../app')) + .delete('/api/books/' + id) + .expect(200) + .expect(function (response) { + assert.equal(response.text, 'OK'); + }) + .end(done); + }); it('should show add book form', function (done) { request(require('../app')) diff --git a/4-auth/views/base.jade b/4-auth/views/base.jade index fdba4df175..4aada5913e 100644 --- a/4-auth/views/base.jade +++ b/4-auth/views/base.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/4-auth/views/books/form.jade b/4-auth/views/books/form.jade index dd8b680871..8368619eeb 100644 --- a/4-auth/views/books/form.jade +++ b/4-auth/views/books/form.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/4-auth/views/books/list.jade b/4-auth/views/books/list.jade index 38977aa211..dd453386ba 100644 --- a/4-auth/views/books/list.jade +++ b/4-auth/views/books/list.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/4-auth/views/books/view.jade b/4-auth/views/books/view.jade index 0921825cce..fb0123b05c 100644 --- a/4-auth/views/books/view.jade +++ b/4-auth/views/books/view.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/5-logging/app.js b/5-logging/app.js index 9139cef64b..e64eef0b32 100644 --- a/5-logging/app.js +++ b/5-logging/app.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/5-logging/app.yaml b/5-logging/app.yaml index cf826b98f5..069f5f04c6 100644 --- a/5-logging/app.yaml +++ b/5-logging/app.yaml @@ -1,4 +1,4 @@ -# Copyright 2015, Google, Inc. +# Copyright 2015-2016, 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 diff --git a/5-logging/books/api.js b/5-logging/books/api.js index dafd1c18f1..0d195c2391 100644 --- a/5-logging/books/api.js +++ b/5-logging/books/api.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/5-logging/books/crud.js b/5-logging/books/crud.js index 63514bf5d5..8fc7865b41 100644 --- a/5-logging/books/crud.js +++ b/5-logging/books/crud.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/5-logging/books/model-cloudsql.js b/5-logging/books/model-cloudsql.js index ad266e5020..f4bb94ae8b 100644 --- a/5-logging/books/model-cloudsql.js +++ b/5-logging/books/model-cloudsql.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/5-logging/books/model-datastore.js b/5-logging/books/model-datastore.js index 155a0db17e..98487b2331 100644 --- a/5-logging/books/model-datastore.js +++ b/5-logging/books/model-datastore.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -135,7 +135,8 @@ module.exports = function(config) { ds.save( entity, function(err) { - cb(err, err ? null : fromDatastore(entity)); + data.id = entity.key.id; + cb(err, err ? null : data); } ); } diff --git a/5-logging/books/model-mongodb.js b/5-logging/books/model-mongodb.js index ea6e6711ae..a0a8a98754 100644 --- a/5-logging/books/model-mongodb.js +++ b/5-logging/books/model-mongodb.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/5-logging/config.js b/5-logging/config.js index b9fd3a8a34..7f8611d575 100644 --- a/5-logging/config.js +++ b/5-logging/config.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -28,7 +28,7 @@ module.exports = { // This is the id of your project in the Google Developers Console. gcloud: { - projectId: process.env.TEST_PROJECT_ID || 'your-project-id' + projectId: process.env.GCLOUD_PROJECT || 'your-project-id' }, // Typically, you will create a bucket with the same name as your project ID. diff --git a/5-logging/lib/images.js b/5-logging/lib/images.js index 3dc199441b..f2d17de98e 100644 --- a/5-logging/lib/images.js +++ b/5-logging/lib/images.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/5-logging/lib/logging.js b/5-logging/lib/logging.js index e0bbc01dbd..1d45af6af1 100644 --- a/5-logging/lib/logging.js +++ b/5-logging/lib/logging.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/5-logging/lib/oauth2.js b/5-logging/lib/oauth2.js index 21a9291a39..dcbce38ebe 100644 --- a/5-logging/lib/oauth2.js +++ b/5-logging/lib/oauth2.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/5-logging/package.json b/5-logging/package.json index ef4bcad343..18e1585b13 100644 --- a/5-logging/package.json +++ b/5-logging/package.json @@ -9,7 +9,7 @@ "monitor": "nodemon app.js", "deploy": "gcloud preview app deploy app.yaml", "lint": "jshint --exclude-path=../.gitignore .", - "mocha": "mocha test/*.test.js", + "mocha": "mocha test/*.test.js -t 30000", "test": "npm run lint && npm run mocha", "init-cloudsql": "node books/model-cloudsql.js" }, @@ -33,13 +33,13 @@ "async": "^1.5.2", "body-parser": "^1.14.2", "cookie-session": "^2.0.0-alpha.1", - "express": "^4.13.3", + "express": "^4.13.4", "express-winston": "^1.2.0", "gcloud": "^0.27.0", "googleapis": "^2.1.7", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.0.0", + "lodash": "^4.2.1", "mongodb": "^2.1.4", "multer": "^1.1.0", "mysql": "^2.10.2", @@ -48,7 +48,7 @@ }, "devDependencies": { "jshint": "^2.9.1", - "mocha": "^2.3.4", + "mocha": "^2.4.5", "supertest": "^1.1.0" }, "engines": { diff --git a/5-logging/test/5-logging.test.js b/5-logging/test/5-logging.test.js index eed8589e5d..b9c5e0f53a 100644 --- a/5-logging/test/5-logging.test.js +++ b/5-logging/test/5-logging.test.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -38,22 +38,47 @@ describe(config.test, function () { .get('/') .expect(302) .expect(function (response) { - assert.equal(response.text, 'Found. Redirecting to /books'); + assert.ok(response.text.indexOf('Redirecting to /books') !== -1); }) .end(done); }); - if (process.env.TEST_PROJECT_ID) { - it('should list books', function (done) { - request(require('../app')) - .get('/books') - .expect(200) - .expect(function (response) { - assert.ok(response.text.indexOf(config.msg) !== -1); - }) - .end(done); - }); - } + var id; + + it('should create a book', function (done) { + request(require('../app')) + .post('/api/books') + .send({ foo: 'bar', title: 'beep' }) + .expect(200) + .expect(function (response) { + id = response.body.id; + assert.ok(response.body.id); + assert.equal(response.body.foo, 'bar'); + assert.equal(response.body.title, 'beep'); + }) + .end(done); + }); + + it('should list books', function (done) { + request(require('../app')) + .get('/api/books') + .expect(200) + .expect(function (response) { + assert.ok(Array.isArray(response.body.items)); + assert.ok(response.body.items.length >= 1); + }) + .end(done); + }); + + it('should delete a book', function (done) { + request(require('../app')) + .delete('/api/books/' + id) + .expect(200) + .expect(function (response) { + assert.equal(response.text, 'OK'); + }) + .end(done); + }); it('should show add book form', function (done) { request(require('../app')) @@ -66,7 +91,6 @@ describe(config.test, function () { }); it('should run', function (done) { - this.timeout(15 * 1000); // Allow 15 seconds to test app utils.testLocalApp(config, done); }); }); diff --git a/5-logging/views/base.jade b/5-logging/views/base.jade index bdb991feeb..ed8e70329c 100644 --- a/5-logging/views/base.jade +++ b/5-logging/views/base.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/5-logging/views/books/form.jade b/5-logging/views/books/form.jade index dd8b680871..8368619eeb 100644 --- a/5-logging/views/books/form.jade +++ b/5-logging/views/books/form.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/5-logging/views/books/list.jade b/5-logging/views/books/list.jade index 38977aa211..dd453386ba 100644 --- a/5-logging/views/books/list.jade +++ b/5-logging/views/books/list.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/5-logging/views/books/view.jade b/5-logging/views/books/view.jade index 0921825cce..fb0123b05c 100644 --- a/5-logging/views/books/view.jade +++ b/5-logging/views/books/view.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/6-pubsub/app.js b/6-pubsub/app.js index dcd652d0c3..6bab05f31c 100644 --- a/6-pubsub/app.js +++ b/6-pubsub/app.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/6-pubsub/app.yaml b/6-pubsub/app.yaml index cf826b98f5..069f5f04c6 100644 --- a/6-pubsub/app.yaml +++ b/6-pubsub/app.yaml @@ -1,4 +1,4 @@ -# Copyright 2015, Google, Inc. +# Copyright 2015-2016, 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 diff --git a/6-pubsub/books/api.js b/6-pubsub/books/api.js index dafd1c18f1..0d195c2391 100644 --- a/6-pubsub/books/api.js +++ b/6-pubsub/books/api.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/6-pubsub/books/crud.js b/6-pubsub/books/crud.js index 63514bf5d5..8fc7865b41 100644 --- a/6-pubsub/books/crud.js +++ b/6-pubsub/books/crud.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/6-pubsub/books/model-cloudsql.js b/6-pubsub/books/model-cloudsql.js index 3d7da3ccc3..a6a5af4a9a 100644 --- a/6-pubsub/books/model-cloudsql.js +++ b/6-pubsub/books/model-cloudsql.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/6-pubsub/books/model-datastore.js b/6-pubsub/books/model-datastore.js index b5ef29247a..491fbe91cc 100644 --- a/6-pubsub/books/model-datastore.js +++ b/6-pubsub/books/model-datastore.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -137,9 +137,9 @@ module.exports = function(config, background) { entity, function(err) { if(err) { return cb(err); } - var book = fromDatastore(entity); - background.queueBook(book.id); - cb(null, book); + data.id = entity.key.id; + background.queueBook(data.id); + cb(null, data); } ); } diff --git a/6-pubsub/books/model-mongodb.js b/6-pubsub/books/model-mongodb.js index 0e3d942b28..b2d646c768 100644 --- a/6-pubsub/books/model-mongodb.js +++ b/6-pubsub/books/model-mongodb.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/6-pubsub/config.js b/6-pubsub/config.js index b9fd3a8a34..7f8611d575 100644 --- a/6-pubsub/config.js +++ b/6-pubsub/config.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -28,7 +28,7 @@ module.exports = { // This is the id of your project in the Google Developers Console. gcloud: { - projectId: process.env.TEST_PROJECT_ID || 'your-project-id' + projectId: process.env.GCLOUD_PROJECT || 'your-project-id' }, // Typically, you will create a bucket with the same name as your project ID. diff --git a/6-pubsub/lib/background.js b/6-pubsub/lib/background.js index e0059867c7..c5ed4fd9a9 100644 --- a/6-pubsub/lib/background.js +++ b/6-pubsub/lib/background.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/6-pubsub/lib/images.js b/6-pubsub/lib/images.js index ddadce4a6c..e1bbde18b5 100644 --- a/6-pubsub/lib/images.js +++ b/6-pubsub/lib/images.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/6-pubsub/lib/logging.js b/6-pubsub/lib/logging.js index 123e11f293..133411900b 100644 --- a/6-pubsub/lib/logging.js +++ b/6-pubsub/lib/logging.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/6-pubsub/lib/oauth2.js b/6-pubsub/lib/oauth2.js index 21a9291a39..dcbce38ebe 100644 --- a/6-pubsub/lib/oauth2.js +++ b/6-pubsub/lib/oauth2.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/6-pubsub/package.json b/6-pubsub/package.json index cbdc1967f2..9def4a9e38 100644 --- a/6-pubsub/package.json +++ b/6-pubsub/package.json @@ -9,7 +9,7 @@ "monitor": "nodemon ${SCRIPT:-app.js}", "deploy": "gcloud preview app deploy app.yaml worker.yaml", "lint": "jshint --exclude-path=../.gitignore .", - "mocha": "mocha test/*.test.js", + "mocha": "mocha test/*.test.js -t 30000", "test": "npm run lint && npm run mocha", "init-cloudsql": "node books/model-cloudsql.js" }, @@ -33,25 +33,25 @@ "async": "^1.5.2", "body-parser": "^1.14.2", "cookie-session": "^2.0.0-alpha.1", - "express": "^4.13.3", + "express": "^4.13.4", "express-winston": "^1.2.0", "gcloud": "^0.27.0", "googleapis": "^2.1.7", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.0.0", + "lodash": "^4.2.1", "mongodb": "^2.1.4", "multer": "^1.1.0", "mysql": "^2.10.2", "prompt": "^0.2.14", - "request": "^2.67.0", + "request": "^2.69.0", "winston": "^2.1.1" }, "devDependencies": { "jshint": "^2.9.1", - "mocha": "^2.3.4", - "proxyquire": "^1.7.3", - "sinon": "^1.17.2", + "mocha": "^2.4.5", + "proxyquire": "^1.7.4", + "sinon": "^1.17.3", "supertest": "^1.1.0" }, "engines": { diff --git a/6-pubsub/test/6-pubsub.test.js b/6-pubsub/test/6-pubsub.test.js index 578f6e7cec..e1c39beb7e 100644 --- a/6-pubsub/test/6-pubsub.test.js +++ b/6-pubsub/test/6-pubsub.test.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -38,22 +38,47 @@ describe(config.test, function () { .get('/') .expect(302) .expect(function (response) { - assert.equal(response.text, 'Found. Redirecting to /books'); + assert.ok(response.text.indexOf('Redirecting to /books') !== -1); }) .end(done); }); - if (process.env.TEST_PROJECT_ID) { - it('should list books', function (done) { - request(require('../app')) - .get('/books') - .expect(200) - .expect(function (response) { - assert.ok(response.text.indexOf(config.msg) !== -1); - }) - .end(done); - }); - } + var id; + + it('should create a book', function (done) { + request(require('../app')) + .post('/api/books') + .send({ foo: 'bar', title: 'beep' }) + .expect(200) + .expect(function (response) { + id = response.body.id; + assert.ok(response.body.id); + assert.equal(response.body.foo, 'bar'); + assert.equal(response.body.title, 'beep'); + }) + .end(done); + }); + + it('should list books', function (done) { + request(require('../app')) + .get('/api/books') + .expect(200) + .expect(function (response) { + assert.ok(Array.isArray(response.body.items)); + assert.ok(response.body.items.length >= 1); + }) + .end(done); + }); + + it('should delete a book', function (done) { + request(require('../app')) + .delete('/api/books/' + id) + .expect(200) + .expect(function (response) { + assert.equal(response.text, 'OK'); + }) + .end(done); + }); it('should show add book form', function (done) { request(require('../app')) @@ -66,7 +91,6 @@ describe(config.test, function () { }); it('should run', function (done) { - this.timeout(15 * 1000); // Allow 15 seconds to test app utils.testLocalApp(config, done); }); }); diff --git a/6-pubsub/test/background.test.js b/6-pubsub/test/background.test.js index ddfe75696c..c80cf2f65b 100644 --- a/6-pubsub/test/background.test.js +++ b/6-pubsub/test/background.test.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/6-pubsub/views/base.jade b/6-pubsub/views/base.jade index bdb991feeb..ed8e70329c 100644 --- a/6-pubsub/views/base.jade +++ b/6-pubsub/views/base.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/6-pubsub/views/books/form.jade b/6-pubsub/views/books/form.jade index dd8b680871..8368619eeb 100644 --- a/6-pubsub/views/books/form.jade +++ b/6-pubsub/views/books/form.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/6-pubsub/views/books/list.jade b/6-pubsub/views/books/list.jade index 38977aa211..dd453386ba 100644 --- a/6-pubsub/views/books/list.jade +++ b/6-pubsub/views/books/list.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/6-pubsub/views/books/view.jade b/6-pubsub/views/books/view.jade index 0921825cce..fb0123b05c 100644 --- a/6-pubsub/views/books/view.jade +++ b/6-pubsub/views/books/view.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/6-pubsub/worker.js b/6-pubsub/worker.js index 87eb94958b..15c3c589a8 100644 --- a/6-pubsub/worker.js +++ b/6-pubsub/worker.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -122,7 +122,7 @@ function findBookInfo(book, cb) { var top = r.items[0]; book.title = top.volumeInfo.title; - book.author = top.volumeInfo.authors.join(', '); + book.author = (top.volumeInfo.authors || []).join(', '); book.publishedDate = top.volumeInfo.publishedDate; book.description = book.description || top.volumeInfo.description; diff --git a/6-pubsub/worker.yaml b/6-pubsub/worker.yaml index 46a6a05b69..a6bae0d26b 100644 --- a/6-pubsub/worker.yaml +++ b/6-pubsub/worker.yaml @@ -1,4 +1,4 @@ -# Copyright 2015, Google, Inc. +# Copyright 2015-2016, 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 diff --git a/7-gce/app.js b/7-gce/app.js index 44dbd6093f..5684f2d324 100644 --- a/7-gce/app.js +++ b/7-gce/app.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/7-gce/app.yaml b/7-gce/app.yaml index cf826b98f5..069f5f04c6 100644 --- a/7-gce/app.yaml +++ b/7-gce/app.yaml @@ -1,4 +1,4 @@ -# Copyright 2015, Google, Inc. +# Copyright 2015-2016, 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 diff --git a/7-gce/books/api.js b/7-gce/books/api.js index dafd1c18f1..0d195c2391 100644 --- a/7-gce/books/api.js +++ b/7-gce/books/api.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/7-gce/books/crud.js b/7-gce/books/crud.js index 63514bf5d5..8fc7865b41 100644 --- a/7-gce/books/crud.js +++ b/7-gce/books/crud.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/7-gce/books/model-cloudsql.js b/7-gce/books/model-cloudsql.js index a4116f28d5..62268a713f 100644 --- a/7-gce/books/model-cloudsql.js +++ b/7-gce/books/model-cloudsql.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/7-gce/books/model-datastore.js b/7-gce/books/model-datastore.js index 401a8b3fa0..1d31f05d46 100644 --- a/7-gce/books/model-datastore.js +++ b/7-gce/books/model-datastore.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -136,9 +136,9 @@ module.exports = function(config, background) { entity, function(err) { if(err) { return cb(err); } - var book = fromDatastore(entity); - background.queueBook(book.id); - cb(null, book); + data.id = entity.key.id; + background.queueBook(data.id); + cb(null, data); } ); } diff --git a/7-gce/books/model-mongodb.js b/7-gce/books/model-mongodb.js index cc08e35da8..3b1cc7eeed 100644 --- a/7-gce/books/model-mongodb.js +++ b/7-gce/books/model-mongodb.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/7-gce/config.js b/7-gce/config.js index b9fd3a8a34..7f8611d575 100644 --- a/7-gce/config.js +++ b/7-gce/config.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -28,7 +28,7 @@ module.exports = { // This is the id of your project in the Google Developers Console. gcloud: { - projectId: process.env.TEST_PROJECT_ID || 'your-project-id' + projectId: process.env.GCLOUD_PROJECT || 'your-project-id' }, // Typically, you will create a bucket with the same name as your project ID. diff --git a/7-gce/gce/startup-script.sh b/7-gce/gce/startup-script.sh index 5b6adff7f0..0d1e11d33b 100644 --- a/7-gce/gce/startup-script.sh +++ b/7-gce/gce/startup-script.sh @@ -1,6 +1,6 @@ #! /bin/bash -# Copyright 2015, Google, Inc. +# Copyright 2015-2016, 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 diff --git a/7-gce/lib/background.js b/7-gce/lib/background.js index 4eb609bdb5..c596f02535 100644 --- a/7-gce/lib/background.js +++ b/7-gce/lib/background.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/7-gce/lib/images.js b/7-gce/lib/images.js index c81e66dac5..e6cc36e0fe 100644 --- a/7-gce/lib/images.js +++ b/7-gce/lib/images.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/7-gce/lib/logging.js b/7-gce/lib/logging.js index 123e11f293..133411900b 100644 --- a/7-gce/lib/logging.js +++ b/7-gce/lib/logging.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/7-gce/lib/oauth2.js b/7-gce/lib/oauth2.js index 21a9291a39..dcbce38ebe 100644 --- a/7-gce/lib/oauth2.js +++ b/7-gce/lib/oauth2.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/7-gce/package.json b/7-gce/package.json index cbdc1967f2..9def4a9e38 100644 --- a/7-gce/package.json +++ b/7-gce/package.json @@ -9,7 +9,7 @@ "monitor": "nodemon ${SCRIPT:-app.js}", "deploy": "gcloud preview app deploy app.yaml worker.yaml", "lint": "jshint --exclude-path=../.gitignore .", - "mocha": "mocha test/*.test.js", + "mocha": "mocha test/*.test.js -t 30000", "test": "npm run lint && npm run mocha", "init-cloudsql": "node books/model-cloudsql.js" }, @@ -33,25 +33,25 @@ "async": "^1.5.2", "body-parser": "^1.14.2", "cookie-session": "^2.0.0-alpha.1", - "express": "^4.13.3", + "express": "^4.13.4", "express-winston": "^1.2.0", "gcloud": "^0.27.0", "googleapis": "^2.1.7", "jade": "^1.11.0", "kerberos": "^0.0.18", - "lodash": "^4.0.0", + "lodash": "^4.2.1", "mongodb": "^2.1.4", "multer": "^1.1.0", "mysql": "^2.10.2", "prompt": "^0.2.14", - "request": "^2.67.0", + "request": "^2.69.0", "winston": "^2.1.1" }, "devDependencies": { "jshint": "^2.9.1", - "mocha": "^2.3.4", - "proxyquire": "^1.7.3", - "sinon": "^1.17.2", + "mocha": "^2.4.5", + "proxyquire": "^1.7.4", + "sinon": "^1.17.3", "supertest": "^1.1.0" }, "engines": { diff --git a/7-gce/test/7-gce.test.js b/7-gce/test/7-gce.test.js index 46f4ef2c98..4015ef2f3c 100644 --- a/7-gce/test/7-gce.test.js +++ b/7-gce/test/7-gce.test.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -38,22 +38,47 @@ describe(config.test, function () { .get('/') .expect(302) .expect(function (response) { - assert.equal(response.text, 'Found. Redirecting to /books'); + assert.ok(response.text.indexOf('Redirecting to /books') !== -1); }) .end(done); }); - if (process.env.TEST_PROJECT_ID) { - it('should list books', function (done) { - request(require('../app')) - .get('/books') - .expect(200) - .expect(function (response) { - assert.ok(response.text.indexOf(config.msg) !== -1); - }) - .end(done); - }); - } + var id; + + it('should create a book', function (done) { + request(require('../app')) + .post('/api/books') + .send({ foo: 'bar', title: 'beep' }) + .expect(200) + .expect(function (response) { + id = response.body.id; + assert.ok(response.body.id); + assert.equal(response.body.foo, 'bar'); + assert.equal(response.body.title, 'beep'); + }) + .end(done); + }); + + it('should list books', function (done) { + request(require('../app')) + .get('/api/books') + .expect(200) + .expect(function (response) { + assert.ok(Array.isArray(response.body.items)); + assert.ok(response.body.items.length >= 1); + }) + .end(done); + }); + + it('should delete a book', function (done) { + request(require('../app')) + .delete('/api/books/' + id) + .expect(200) + .expect(function (response) { + assert.equal(response.text, 'OK'); + }) + .end(done); + }); it('should show add book form', function (done) { request(require('../app')) @@ -66,7 +91,6 @@ describe(config.test, function () { }); it('should run', function (done) { - this.timeout(15 * 1000); // Allow 15 seconds to test app utils.testLocalApp(config, done); }); }); diff --git a/7-gce/test/background.test.js b/7-gce/test/background.test.js index ddfe75696c..c80cf2f65b 100644 --- a/7-gce/test/background.test.js +++ b/7-gce/test/background.test.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 diff --git a/7-gce/views/base.jade b/7-gce/views/base.jade index bdb991feeb..ed8e70329c 100644 --- a/7-gce/views/base.jade +++ b/7-gce/views/base.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/7-gce/views/books/form.jade b/7-gce/views/books/form.jade index dd8b680871..8368619eeb 100644 --- a/7-gce/views/books/form.jade +++ b/7-gce/views/books/form.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/7-gce/views/books/list.jade b/7-gce/views/books/list.jade index 38977aa211..dd453386ba 100644 --- a/7-gce/views/books/list.jade +++ b/7-gce/views/books/list.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/7-gce/views/books/view.jade b/7-gce/views/books/view.jade index 0921825cce..fb0123b05c 100644 --- a/7-gce/views/books/view.jade +++ b/7-gce/views/books/view.jade @@ -1,4 +1,4 @@ -//- Copyright 2015, Google, Inc. +//- Copyright 2015-2016, 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 diff --git a/7-gce/worker.js b/7-gce/worker.js index 3083309bb6..c9dc32e95d 100644 --- a/7-gce/worker.js +++ b/7-gce/worker.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -115,7 +115,7 @@ function findBookInfo(book, cb) { var top = r.items[0]; book.title = top.volumeInfo.title; - book.author = top.volumeInfo.authors.join(', '); + book.author = (top.volumeInfo.authors || []).join(', '); book.publishedDate = top.volumeInfo.publishedDate; book.description = book.description || top.volumeInfo.description; diff --git a/7-gce/worker.yaml b/7-gce/worker.yaml index 46a6a05b69..a6bae0d26b 100644 --- a/7-gce/worker.yaml +++ b/7-gce/worker.yaml @@ -1,4 +1,4 @@ -# Copyright 2015, Google, Inc. +# Copyright 2015-2016, 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 diff --git a/package.json b/package.json index 9b54e7abc9..388604a2e5 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ "private": true, "scripts": { "lint": "jshint --exclude-path=.gitignore .", - "mocha": "mocha 1-hello-world/test/* 2-structured-data/test/* 3-binary-data/test/* 4-auth/test/* 5-logging/test/* 6-pubsub/test/* 7-gce/test/*", - "cover": "istanbul cover --hook-run-in-context node_modules/mocha/bin/_mocha -- 1-hello-world/test/* 2-structured-data/test/* 3-binary-data/test/* 4-auth/test/* 5-logging/test/* 6-pubsub/test/* 7-gce/test/*", + "mocha": "mocha 1-hello-world/test/* 2-structured-data/test/* 3-binary-data/test/* 4-auth/test/* 5-logging/test/* 6-pubsub/test/* 7-gce/test/* -t 30000", + "cover": "istanbul cover --hook-run-in-context node_modules/mocha/bin/_mocha -- 1-hello-world/test/* 2-structured-data/test/* 3-binary-data/test/* 4-auth/test/* 5-logging/test/* 6-pubsub/test/* 7-gce/test/* -t 30000", "test": "npm run lint && npm run cover", "coveralls": "cat ./coverage/lcov.info | node_modules/coveralls/bin/coveralls.js" }, @@ -28,30 +28,30 @@ ], "license": "Apache Version 2.0", "dependencies": { - "async": "^1.5.0", - "body-parser": "^1.14.1", + "async": "^1.5.2", + "body-parser": "^1.14.2", "cookie-session": "^2.0.0-alpha.1", - "express": "^4.13.3", - "express-winston": "^0.4.1", - "gcloud": "^0.24.0", - "googleapis": "^2.1.5", + "express": "^4.13.4", + "express-winston": "^1.2.0", + "gcloud": "^0.27.0", + "googleapis": "^2.1.7", "jade": "^1.11.0", - "kerberos": "^0.0.17", - "lodash": "^3.10.1", - "mongodb": "^2.0.46", + "kerberos": "^0.0.18", + "lodash": "^4.2.1", + "mongodb": "^2.1.4", "multer": "^1.1.0", - "mysql": "^2.9.0", + "mysql": "^2.10.2", "prompt": "^0.2.14", - "request": "^2.65.0", - "winston": "^1.1.1" + "request": "^2.69.0", + "winston": "^2.1.1" }, "devDependencies": { - "coveralls": "^2.11.4", - "istanbul": "^0.4.1", - "jshint": "^2.8.0", - "mocha": "^2.3.4", - "proxyquire": "^1.7.3", - "sinon": "^1.17.2", + "coveralls": "^2.11.6", + "istanbul": "^0.4.2", + "jshint": "^2.9.1", + "mocha": "^2.4.5", + "proxyquire": "^1.7.4", + "sinon": "^1.17.3", "supertest": "^1.1.0" }, "engines": { diff --git a/test/utils.js b/test/utils.js index e34ce4fa5c..080421fcd6 100644 --- a/test/utils.js +++ b/test/utils.js @@ -1,4 +1,4 @@ -// Copyright 2015, Google, Inc. +// Copyright 2015-2016, 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 @@ -15,9 +15,6 @@ var spawn = require('child_process').spawn; var request = require('request'); -var fs = require('fs'); -var async = require('async'); -var projectId = process.env.TEST_PROJECT_ID || 'nodejs-docs-samples'; // Send a request to the given url and test that the response body has the // expected value @@ -55,11 +52,9 @@ exports.testInstallation = function testInstallation(config, done) { proc.on('error', finish); - if (!process.env.TRAVIS) { - proc.stderr.on('data', function (data) { - console.log('stderr: ' + data); - }); - } + proc.stderr.on('data', function (data) { + console.log('stderr: ' + data); + }); proc.on('exit', function (code) { if (code !== 0) { @@ -120,118 +115,3 @@ exports.testLocalApp = function testLocalApp(config, done) { } } }; - -exports.testDeployment = function testDeployment(config, done) { - - // Keep track off whether "cb" has been called yet - var calledDone = false; - // Keep track off whether the logs have fully flushed - var logFinished = false; - - var _cwd = config.path; - var args = [ - 'preview', - 'app', - 'deploy', - 'app.yaml', - // Skip prompt - '-q', - '--project', - projectId, - // Deploy over existing version so we don't have to clean up - '--version', - config.test, - // Override any existing deployment - '--force', - config.promote ? '--promote' : '--no-promote', - // Build locally, much faster - '--docker-build', - config.dockerBuild ? config.dockerBuild : 'local', - '--verbosity', - 'debug' - ]; - - console.log(_cwd + ' $ gcloud ' + args.join(' ')); - - var logFile = (process.env.TRAVIS_BUILD_DIR || _cwd + '/..') + - '/' + - config.test + - '-' + - (process.env.TRAVIS_BUILD_ID || 0) + - '-' + - (process.env.TRAVIS_BUILD_NUMBER || 0) + - '-' + - (process.env.TRAVIS_JOB_ID || 0) + - '-' + - (process.env.TRAVIS_JOB_NUMBER || 0) + - '.log'; - - var logStream = fs.createWriteStream(logFile, { flags: 'a' }); - - // Don't use "npm run deploy" because we need extra flags - var proc = spawn('gcloud', args, { - cwd: _cwd - }); - - // Exit helper so we don't call "cb" more than once - function finish(err, result) { - if (!calledDone) { - calledDone = true; - var intervalId = setInterval(function () { - if (logFinished) { - clearInterval(intervalId); - done(err, result); - } - }, 1000); - } - } - - logStream.on('finish', function () { - if (!logFinished) { - logFinished = true; - } - }); - - proc.stdout.pipe(logStream, { end: false }); - proc.stderr.pipe(logStream, { end: false }); - - var numEnded = 0; - - function finishLogs() { - numEnded++; - if (numEnded === 2) { - logStream.end(); - console.log('Saved logs for ' + config.test + ' to ' + logFile); - } - } - - proc.stdout.on('end', finishLogs); - proc.stderr.on('end', finishLogs); - - // This is called if the process fails to start. "error" event may or may - // not be fired in addition to the "exit" event. - proc.on('error', finish); - - // Process has completed - proc.on('exit', function (code) { - if (code !== 0) { // Deployment failed - // Pass error as second argument so we don't short-circuit the - // parallel tasks - return finish(new Error(config.test + ': failed to deploy!')); - } else { // Deployment succeeded - // Test that sample app is running successfully - return async.waterfall([ - function (cb) { - // Give apps time to start - setTimeout(cb, 5000); - }, - function (cb) { - // Test versioned url of "default" module - var demoUrl = 'http://' + config.test + '-dot-' + projectId + - '.appspot.com'; - testRequest(demoUrl, config, cb); - } - ], finish); - } - }); -};