Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial commit

  • Loading branch information...
commit 519b49ffdf1c2e35ec6a65df2da47c51e3d438f6 0 parents
@coen-hyde authored
2  .gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+node_modules
39 grunt.js
@@ -0,0 +1,39 @@
+/*jshint node:true*/
+module.exports = function(grunt) {
+ 'use strict';
+
+ // Project configuration
+ grunt.initConfig({
+ lint: {
+ files: [
+ 'tasks/hang.js',
+ 'grunt.js'
+ ]
+ },
+
+ test: {
+ tasks: ['test/*_test.js']
+ },
+
+ jshint: {
+ options: {
+ node: true,
+ white: false,
+ smarttabs: true,
+ eqeqeq: true,
+ immed: true,
+ latedef: true,
+ newcap: true,
+ undef: true
+ }
+ },
+
+ clean: {
+ test: ['test/project/.grunthang']
+ }
+ });
+
+ // Default task
+ grunt.registerTask('default', 'lint test');
+
+};
40 index.js
@@ -0,0 +1,40 @@
+var path = require('path')
+ , fs = require('fs')
+ , EventEmitter = require('events').EventEmitter;
+
+module.exports = function(projectRoot) {
+ var buildFile = path.resolve(projectRoot)+'/.grunthang'
+ , building = false
+ , vent = new EventEmitter();
+
+ vent.on('build:start', function() {
+ building = true;
+ });
+
+ vent.on('build:end', function() {
+ building = false;
+ })
+
+ if (!fs.existsSync(buildFile)) {
+ fs.writeFileSync(buildFile, '-');
+ }
+
+ fs.watch(buildFile, function(event) {
+ // This is sync but this npm should only be used in development anyway.
+ contents = fs.readFileSync(buildFile, 'utf8');
+ if ('+' === contents) {
+ vent.emit('build:start');
+ }
+ else if ('-' === contents) {
+ vent.emit('build:end');
+ }
+ });
+
+ return function(req, res, next) {
+ if (!building) {
+ return next();
+ }
+
+ vent.once('build:end', next);
+ };
+};
31 package.json
@@ -0,0 +1,31 @@
+{
+ "name": "grunt-hang",
+ "description": "Hang express/connect requests while a grunt build process is in progress",
+ "main": "./index.js",
+ "author": {
+ "name": "Coen Hyde",
+ "url": "http://coenhyde.com/"
+ },
+ "version": "0.1.0",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/coen-hyde/grunt-hang.git"
+ },
+ "scripts": {
+ "test": "make test"
+ },
+ "dependencies": {
+ "grunt": "~0.3.17"
+ },
+ "devDependencies": {
+ "mocha": "~1.7.4",
+ "request": "~2.12.0",
+ "express": "~3.0.5",
+ "should": "~1.2.1",
+ "async": "~0.1.22",
+ "forever-monitor": "~1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+}
18 tasks/hang.js
@@ -0,0 +1,18 @@
+/*
+ * grunt-hang
+ *
+ * Copyright (c) 2013 Coen Hyde
+ * Licensed under the MIT license.
+ */
+
+module.exports = function(grunt) {
+ 'use strict';
+
+ grunt.registerTask('buildStart', 'Touch a file to indicate a build is in progress', function() {
+ grunt.file.write('.grunthang', '+');
+ });
+
+ grunt.registerTask('buildEnd', 'Delete the temp building file now that the build is complete', function() {
+ grunt.file.write('.grunthang', '-');
+ });
+};
105 test/hang_test.js
@@ -0,0 +1,105 @@
+var fs = require('fs')
+ , path = require('path');
+
+var request = require('request')
+ , forever = require('forever-monitor')
+ , async = require('async');
+
+/*
+ * Setup test server
+ */
+var testProjectDir = path.resolve(__dirname +'/project');
+var testServer = new (forever.Monitor)(testProjectDir + '/server.js', {
+ silent: false,
+ max: 1,
+ killTree: true,
+ uid: 'grunt-hang-test-server',
+ cwd: testProjectDir,
+ env: { NODE_ENV: 'test' }
+});
+
+var startTestServer = function(cb) {
+ testServer.on('stdout', function(output) {
+ if (output.toString().match(/Listening on port (\d*)/)) {
+ cb();
+ }
+ });
+
+ testServer.start();
+};
+
+/*
+ * Setup test grunt
+ */
+var testGrunt = new (forever.Monitor)('default', {
+ silent: false,
+ max: 1,
+ killTree: false,
+ uid: 'grunt-hang-test-grunt',
+ command: 'grunt',
+ cwd: testProjectDir,
+ env: { NODE_ENV: 'test' }
+});
+
+var startTestGrunt = function(cb) {
+ testGrunt.on('stdout', function(output) {
+ if (output.toString().match(/Running "hang" task/)) {
+ cb();
+ }
+ });
+
+ testGrunt.start();
+};
+
+exports.group = {
+ setUp: function(cb) {
+ startTestServer(cb);
+ },
+
+ tearDown: function(cb) {
+ testServer.on('exit', function() {
+ cb();
+ });
+
+ async.nextTick(function() {
+ testServer.stop();
+ });
+ },
+
+ test1: function(test) {
+ 'use strict';
+
+ test.expect(6);
+
+ async.series([
+ function(done) {
+ // make initial request to server to make sure it responds quickly without grunt running
+ var beforeStart = new Date().getTime();
+ request('http://127.0.0.1:8099/', function(err, res, body) {
+ test.equal(res.statusCode, 200);
+ test.equal(body, 'ok');
+
+ // Did the request take less than a second
+ var repsonseTime = new Date().getTime() - beforeStart
+ test.ok(repsonseTime < 1000, 'request to '+repsonseTime+'milliseconds to respond. Too slow.');
+ done();
+ });
+ },
+ function(done) {
+ startTestGrunt(done);
+ },
+ function(done) {
+ var beforeStart = new Date().getTime();
+ request('http://127.0.0.1:8099/', function(err, res, body) {
+ test.equal(res.statusCode, 200);
+ test.equal(body, 'ok');
+
+ // Did the request take less than 3 seconds
+ var repsonseTime = new Date().getTime() - beforeStart
+ test.ok(repsonseTime > 3000, 'request to '+repsonseTime+'milliseconds to respond. Too fast.');
+ done();
+ });
+ }
+ ], test.done);
+ }
+}
1  test/project/.grunthang
@@ -0,0 +1 @@
+-
22 test/project/grunt.js
@@ -0,0 +1,22 @@
+var grunt = require('grunt');
+
+module.exports = function (grunt) {
+ grunt.registerTask('hang', 'Hang the build process so we can test hanging middleware', function() {
+ var done = this.async();
+
+ setTimeout(done, 5000);
+ });
+
+ grunt.initConfig({
+ lint: {
+ files: [
+ 'tasks/hang.js',
+ 'grunt.js'
+ ]
+ },
+ });
+
+ grunt.loadTasks('../../tasks');
+
+ grunt.registerTask("default", 'buildStart hang buildEnd');
+}
14 test/project/server.js
@@ -0,0 +1,14 @@
+var express = require('express')
+ , gruntHang = require('../../');
+
+var app = express();
+
+app.use(gruntHang(__dirname));
+
+app.get('/', function(req, res) {
+ res.send(200, 'ok');
+});
+
+app.listen(8099, function() {
+ console.log('Listening on port 8099');
+});
Please sign in to comment.
Something went wrong with that request. Please try again.