From b70ce528a717a4e24e6aa4f7866976489f5e48fa Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Mon, 2 Nov 2015 16:09:56 -0800 Subject: [PATCH] Added integration tests to check that samples run. Closes #20. --- .travis.yml | 17 +++- appengine/redis/README.md | 2 +- appengine/redis/package.json | 27 ++--- package.json | 10 +- test/appengine/test.js | 189 +++++++++++++++++++++++++++++++++++ 5 files changed, 218 insertions(+), 27 deletions(-) create mode 100644 test/appengine/test.js diff --git a/.travis.yml b/.travis.yml index c716d9e2f3..5a5c7b7ba0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,20 @@ node_js: cache: directories: - $HOME/gcloud/ + - appengine/express/node_modules/ + - appengine/geddy/node_modules/ + - appengine/grunt/node_modules/ + - appengine/hapi/node_modules/ + - appengine/kraken/node_modules/ + - appengine/loopback/node_modules/ + - appengine/mailgun/node_modules/ + - appengine/redis/node_modules/ + - appengine/restify/node_modules/ + - appengine/sails/node_modules/ + +services: + - redis-server + env: - PATH=$PATH:$HOME/gcloud/google-cloud-sdk/bin GOOGLE_APPLICATION_CREDENTIALS=$TRAVIS_BUILD_DIR/nodejs-docs-samples.json TEST_BUCKET_NAME=cloud-samples-tests TEST_PROJECT_ID=cloud-samples-tests #Other environment variables on same line @@ -38,6 +52,3 @@ before_install: install: #Add app specific setup here #Use '-q' to disable interactive prompts - -script: - - jshint --exclude-path=.jshintignore . diff --git a/appengine/redis/README.md b/appengine/redis/README.md index 7227afb17d..2aafc2d29c 100644 --- a/appengine/redis/README.md +++ b/appengine/redis/README.md @@ -49,7 +49,7 @@ For convenience, you can use an npm script to run the deploy command. Modify you ```json "scripts": { - "start": "node ./bin/www", + "start": "node server.js", "deploy": "gcloud preview app deploy app.yaml --promote --project " } ``` diff --git a/appengine/redis/package.json b/appengine/redis/package.json index fcba628792..d521cd67cb 100644 --- a/appengine/redis/package.json +++ b/appengine/redis/package.json @@ -1,27 +1,16 @@ { "name": "appengine-redis", - "version": "1.0.0", - "description": "An example of using redis with Google App Engine.", - "main": "server.js", + "description": "An example of using Redis with Node.js on Google App Engine.", + "version": "0.0.1", + "private": true, + "license": "Apache Version 2.0", + "engines": { + "node": "~0.12.7" + }, "scripts": { + "start": "node server.js", "deploy": "gcloud preview app deploy app.yaml --promote --project node-redis-demo" }, - "repository": { - "type": "git", - "url": "http://github.com/JustinBeckwith/appengine-nodejs-samples" - }, - "keywords": [ - "nodejs", - "redis", - "appengine", - "google" - ], - "author": "Justin Beckwith", - "license": "Apache Version 2.0", - "bugs": { - "url": "https://github.com/JustinBeckwith/appengine-nodejs-samples/issues" - }, - "homepage": "https://github.com/JustinBeckwith/appengine-nodejs-samples", "dependencies": { "nconf": "^0.8.0", "redis": "^2.0.1" diff --git a/package.json b/package.json index 1b8c0f1b05..e31ad2e62f 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,9 @@ "description": "Samples used in the nodejs documentation on cloud.google.com", "main": "index.js", "scripts": { - "test": "mocha --recursive", - "jshint": "jshint --exclude-path=.jshintignore ." + "jshint": "jshint --exclude-path=.jshintignore .", + "mocha": "mocha --timeout 10000 --recursive", + "test": "npm run jshint && npm run mocha" }, "author": "jerjou@google.com", "license": "Apache 2", @@ -14,9 +15,10 @@ "googleapis": "~2.1.3" }, "devDependencies": { - "mocha": "~2.2.5", "jshint": "~2.8.0", - "lodash": "~3.10.1" + "lodash": "~3.10.1", + "mocha": "^2.2.5", + "request": "^2.65.0" }, "repository": { "type": "git", diff --git a/test/appengine/test.js b/test/appengine/test.js new file mode 100644 index 0000000000..74c3030e18 --- /dev/null +++ b/test/appengine/test.js @@ -0,0 +1,189 @@ +// 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 cwd = process.cwd(); + +function getPath(dir) { + return cwd + '/appengine/' + dir; +} + +var sampleTests = [ + { + dir: 'express', + cmd: 'node', + arg1: './bin/www', + msg: 'Hello World! Express.js on Google App Engine.' + }, + { + dir: 'geddy', + cmd: 'node', + arg1: 'node_modules/geddy/bin/cli.js', + msg: 'Hello, World! Geddy.js on Google App Engine.' + }, + { + dir: 'grunt', + cmd: 'node', + arg1: './src/bin/www', + msg: 'Hello World! Express.js + Grunt.js on Google App Engine.' + }, + { + dir: 'hapi', + cmd: 'node', + arg1: 'index.js', + msg: 'Hello World! Hapi.js on Google App Engine.' + }, + { + dir: 'kraken', + cmd: 'node', + arg1: 'server.js', + msg: 'Hello World! Kraken.js on Google App Engine.', + code: 304 + }, + { + dir: 'loopback', + cmd: 'node', + arg1: 'server/server.js', + msg: 'LoopBack.js on Google App Engine.', + code: 304 + }, + { + dir: 'mailgun', + cmd: 'node', + arg1: 'app.js', + msg: 'Express.js + Mailgun on Google App Engine.' + }, + { + dir: 'redis', + cmd: 'node', + arg1: 'server.js', + msg: '127.0.0.1' + }, + { + dir: 'restify', + cmd: 'node', + arg1: 'server.js', + msg: 'Hello World! Restify.js on Google App Engine.' + } +]; + +if (process.env.TRAVIS_NODE_VERSION !== 'stable') { + // For some reason the "npm install" step for the Sails sample doesn't work on + // Travis when using Node.js stable. It works locally, however. + sampleTests.push({ + dir: 'sails', + cmd: 'node', + arg1: 'app.js', + msg: 'Hello World! Sails.js on Google App Engine.', + timeout: 240000 + }); +} + +describe('appengine/', function () { + sampleTests.forEach(function (sample) { + it(sample.dir + ': dependencies should install', function (done) { + this.timeout(sample.timeout || 120000); + var calledDone = false; + + var proc = spawn('npm', ['install'], { + cwd: getPath(sample.dir) + }); + + proc.on('error', function (err) { + if (!calledDone) { + calledDone = true; + done(err); + } + }); + + if (!process.env.TRAVIS) { + proc.stderr.on('data', function (data) { + console.log('stderr: ' + data); + }); + } + + proc.on('exit', function (code) { + if (!calledDone) { + calledDone = true; + if (code !== 0) { + done(new Error(sample.dir + ': failed to install dependencies!')); + } else { + done(); + } + } + }); + }); + + it(sample.dir + ': should return 200 and Hello World', function (done) { + var timeoutId; + var intervalId; + var success = false; + var calledDone = false; + + var proc = spawn(sample.cmd, [sample.arg1], { + cwd: getPath(sample.dir) + }); + + proc.on('error', function (err) { + if (!calledDone) { + calledDone = true; + done(err); + } + }); + + if (!process.env.TRAVIS) { + proc.stderr.on('data', function (data) { + console.log('stderr: ' + data); + }); + } + + proc.on('exit', function (code, signal) { + if (!calledDone) { + calledDone = true; + if (code !== 0 && signal !== 'SIGKILL') { + done(new Error(sample.dir + ': failed to run!')); + } else { + if (!success) { + done(new Error(sample.dir + ': failed verification!')); + } else { + done(); + } + } + } + }); + + timeoutId = setTimeout(end, 5000); + intervalId = setInterval(testRequest, 1000); + + function end() { + clearTimeout(timeoutId); + clearInterval(intervalId); + proc.kill('SIGKILL'); + } + + function testRequest() { + request('http://localhost:8080', function (err, res, body) { + if (body && body.indexOf(sample.msg) !== -1 && + (res.statusCode === 200 || res.statusCode === sample.code)) { + success = true; + end(); + } + }); + } + }); + }); +});