From aa23ebf9f948ba42affc1aecee23aa08a47e8213 Mon Sep 17 00:00:00 2001 From: Hector Virgen Date: Tue, 5 Aug 2014 11:49:02 -0700 Subject: [PATCH] Health check for Connect. Usage: var connect = require('connect'); var healthCheck = require('tagged-health-check'); var app = connect(); // Default health check on `/health.json`: app.use(healthCheck()); // Custom health check path: app.use(healthCheck('/my/custom/health.json'); The health check responds with the following data: { "status": "OK", "arch": "x64", "pid": 1234, "uptime": 456, "memory": { "rss": 15208448, "heapTotal": 7195904, "heapUsed": 3183048 } } --- Gruntfile.js | 8 +-- README.md | 88 ++++++++++--------------------- lib/health_check.coffee | 19 +++++++ lib/index.js | 4 +- package.json | 19 ++++--- test/lib/health_check_test.coffee | 74 ++++++++++++++++++++++++++ test/lib/index_test.js | 10 ---- test/test_runner.js | 1 + 8 files changed, 138 insertions(+), 85 deletions(-) create mode 100644 lib/health_check.coffee create mode 100644 test/lib/health_check_test.coffee delete mode 100644 test/lib/index_test.js diff --git a/Gruntfile.js b/Gruntfile.js index 994763e..1b049f5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -2,7 +2,7 @@ var path = require('path'); module.exports = function(grunt) { var TEST_RUNNER = path.join(process.cwd(), 'test', 'test_runner'); - var ALL_TESTS = 'test/**/*_test.js'; + var ALL_TESTS = 'test/**/*_test.coffee'; // NPM tasks, alphabetical grunt.loadNpmTasks('grunt-contrib-clean'); @@ -20,7 +20,7 @@ module.exports = function(grunt) { // Documentation docco: { main: { - src: ['lib/**/*.js'], + src: ['lib/**/*.coffee', 'lib/**/*.js'], options: { output: 'docs/' } @@ -76,8 +76,8 @@ module.exports = function(grunt) { spawn: false }, files: [ - 'lib/**/*.js', - 'test/**/*.js' + 'lib/**/*.coffee', + 'test/**/*.coffee' ], tasks: ['mochaTest:test'] } diff --git a/README.md b/README.md index 406ba7b..d7b00b3 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,36 @@ -Tagged NPM Seed -=============== +Health check for Connect. +========================= -A blueprint for creating NPM packages. +Installation: +------------- -## Files and Directory Structure + $ npm install tagged-health-check -The following describes the various files in this repo and the directory structure. +Usage: +------ -**Note:** Files and directories prefixed by `*` are auto-generated and excluded from the -repository via `.gitignore`. +The health check can be registered as middleware in any Connect app: - . - ├── Gruntfile.js # grunt task configuration - ├── README.md # this file - ├── *docs # autogenerated documentation - │   └── *index.html # each JS file in `./lib` has a corresponding HTML file for documentation - ├── lib # all code for this library will be placed here - │   └── index.js # main entry point for your npm package - ├── *node_modules # all dependencies will be installed here by npm - ├── package.json # description of this package for npm, including dependency lists - └── test # unit test configuration, reports, and specs - ├── *coverage.html # code coverage report - ├── lib # specs go here, preferably with a 1:1 mapping to code in `./lib` - │   └── index_test.js # example spec for `./lib/index.js` - ├── mocha.opts # runtime options for mocha - └── test_runner.js # configures mocha environment (e.g. chai, sinon, etc.) + var connect = require('connect'); + var healthCheck = require('tagged-health-check'); + var app = connect(); -## What's Included? + // Default health check on `/health.json`: + app.use(healthCheck()); -### Grunt + // Custom health check path: + app.use(healthCheck('/my/custom/health.json'); -Grunt is a JavaScript task runner to automate common actions. The Tagged NPM Package Seed -supports the following built-in grunt tasks: +The health check responds with the following data: -**test** - -Runs all unit tests through mocha. - - $ grunt test - -**coverage** - -Runs all unit tests and generates a code coverage report in `./test/coverage.html` - - $ grunt coverage - -**watch** - -Automatically runs mocha tests each time a file changes in `./lib` or `./test`. - - $ grunt watch - -**docs** - -Generates documentation for all JS files within `./lib` using docco. Documentation is -written to `./docs`. - - $ grunt docs - -**clean** - -Deletes all auto-generated files, including `./docs` and `./test/coverage.html` - -### Mocha, Sinon, Chai, Blanket - -The ultimate TDD environment for node. Place your specs in `./test/lib`, and run `grunt test` -to run them. - -See `./test/lib/index_test.js` for examples. + { + "status": "OK", + "arch": "x64", + "pid": 1234, + "uptime": 456, + "memory": { + "rss": 15208448, + "heapTotal": 7195904, + "heapUsed": 3183048 + } + } diff --git a/lib/health_check.coffee b/lib/health_check.coffee new file mode 100644 index 0000000..1241450 --- /dev/null +++ b/lib/health_check.coffee @@ -0,0 +1,19 @@ +# Middleware for connect that responds with a health check +# if the request path matches the provided path +middleware = (path, req, res, next) -> + return next() if req.path != path + + res.send + status: 'OK' + arch: process.arch + pid: process.pid + uptime: process.uptime() + memory: process.memoryUsage() + +# Returns a middleware function +# bound with the provided path. +# If omitted, the path defaults to `/health.json`. +factory = (path = '/health.json') -> middleware.bind @, path + +# Expose the factory +module.exports = factory diff --git a/lib/index.js b/lib/index.js index b12f3f2..6a11d2c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,2 +1,2 @@ -// Whatever is exported here will be available to the consumers of your npm module. -module.exports = {}; +require('coffee-script'); +module.exports = require('./health_check'); diff --git a/package.json b/package.json index 4813d47..f7cdd4f 100644 --- a/package.json +++ b/package.json @@ -1,26 +1,26 @@ { - "name": "tagged-npm-seed", - "version": "0.0.0", - "description": "Tagged's seed project for NPM packages", + "name": "tagged-health", + "version": "0.0.1", + "description": "Health check middleware for connect", "main": "lib/index.js", "scripts": { "test": "grunt test" }, "repository": { "type": "git", - "url": "http://github.com/tagged/npm-seed.git" + "url": "http://github.com/tagged/connect-health-check.git" }, "keywords": [ - "api", "tagged", - "client" + "health", + "connect" ], "author": "Web Team Awesome", "license": "MIT", "bugs": { - "url": "https://github.com/tagged/npm-seed/issues" + "url": "https://github.com/tagged/connect-health-check/issues" }, - "homepage": "https://github.com/tagged/npm-seed", + "homepage": "https://github.com/tagged/connect-health-check", "devDependencies": { "blanket": "^1.1.6", "chai": "^1.9.1", @@ -31,5 +31,8 @@ "grunt-mocha-test": "^0.11.0", "mocha": "^1.20.1", "sinon": "^1.10.3" + }, + "dependencies": { + "coffee-script": "^1.7.1" } } diff --git a/test/lib/health_check_test.coffee b/test/lib/health_check_test.coffee new file mode 100644 index 0000000..2aedb38 --- /dev/null +++ b/test/lib/health_check_test.coffee @@ -0,0 +1,74 @@ +healthCheck = require "#{LIB_DIR}/health_check" + +describe 'healthCheck', -> + describe 'middleware', -> + beforeEach -> + @req = path: '/' + @res = send: sinon.spy() + @next = sinon.spy() + + it 'is a function', -> + healthCheck.should.be.a 'function' + + it 'returns a function', -> + healthCheck().should.be.a 'function' + + describe 'default route', -> + beforeEach -> + @middleware = healthCheck() # use default options + + it 'calls `next()` if `req.path` does not match default `/health.json`', -> + @middleware @req, @res, @next + @next.called.should.be.true + + it 'responds with health object if path matches default `/health.json`', -> + @req.path = '/health.json' + @middleware @req, @res, @next + @res.send.calledOnce.should.be.true + @res.send.lastCall.args[0].should.be.an 'object' + + describe 'configurable route', -> + beforeEach -> + @middleware = healthCheck '/test/health.json' # configurable route + + it 'responds with health object if path matches configured route', -> + @req.path = '/test/health.json' + @middleware @req, @res, @next + @res.send.calledOnce.should.be.true + @res.send.lastCall.args[0].should.be.an 'object' + + it 'calls next() if path does not match default `/health.json`', -> + @req.path = '/health.json' # should not match, because the default was overwritten + @middleware @req, @res, @next + @next.called.should.be.true + + describe 'health object', -> + beforeEach -> + @middleware = healthCheck() # use default options + @req.path = '/health.json' # ensure health object is returned + sinon.stub(process, 'uptime').returns('uptime_canary') + sinon.stub(process, 'memoryUsage').returns('memory_canary'); + + afterEach -> + process.uptime.restore() + process.memoryUsage.restore() + + it 'contains `status` property set to "OK"', -> + @middleware @req, @res, @next + @res.send.lastCall.args[0].should.have.property 'status', 'OK' + + it 'contains `arch` property set to `process.arch`', -> + @middleware @req, @res, @next + @res.send.lastCall.args[0].should.have.property 'arch', process.arch + + it 'contains `pid` property set to `process.pid`', -> + @middleware @req, @res, @next + @res.send.lastCall.args[0].should.have.property 'pid', process.pid + + it 'contains `uptime` property set to `process.uptime()`', -> + @middleware @req, @res, @next + @res.send.lastCall.args[0].should.have.property 'uptime', 'uptime_canary' + + it 'contains `memory` property set to `process.memoryUsage()`', -> + @middleware @req, @res, @next + @res.send.lastCall.args[0].should.have.property 'memory', 'memory_canary' diff --git a/test/lib/index_test.js b/test/lib/index_test.js deleted file mode 100644 index d72f2b4..0000000 --- a/test/lib/index_test.js +++ /dev/null @@ -1,10 +0,0 @@ -/*jshint expr: true*/ - -// Your npm package is accessible by requiring `LIB_DIR`. -var MyNpmPackage = require(LIB_DIR); - -describe('MyNpmPackage', function() { - it('exists', function() { - MyNpmPackage.should.exist; - }); -}); diff --git a/test/test_runner.js b/test/test_runner.js index ab67f00..0523bc4 100644 --- a/test/test_runner.js +++ b/test/test_runner.js @@ -1,3 +1,4 @@ +require('coffee-script'); var path = require('path'); // Use constant to help with resolving path to lib code within test files