Skip to content

Commit

Permalink
feat: Add stopper to the public API
Browse files Browse the repository at this point in the history
Add the `stopper`  as a command to the public API allowing for enabling users to
programically terminate a running server.
  • Loading branch information
budde377 committed Feb 21, 2016
1 parent 66ae80b commit 3d4fa00
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 12 deletions.
16 changes: 16 additions & 0 deletions docs/dev/04-public-api.md
Expand Up @@ -118,6 +118,22 @@ runner.run({port: 9876}, function(exitCode) {
})
```

## karma.stopper

### **stopper.stop(options, [callback=process.exit])**

This function will signal a running server to stop. Equivalent of `karma stop`.

```javascript
var stopper = require('karma').stopper
runner.stop({port: 9876}, function(exitCode) {
if (exitCode === 0) {
console.log('Server stop as initiated')
}
process.exit(exitCode)
})
```

## Callback function notes

- If there is an error, the error code will be provided as the second parameter to the error callback.
2 changes: 2 additions & 0 deletions lib/index.js
Expand Up @@ -3,6 +3,7 @@
var constants = require('./constants')
var Server = require('./server')
var runner = require('./runner')
var stopper = require('./stopper')
var launcher = require('./launcher')

// TODO: remove in 1.0
Expand All @@ -21,6 +22,7 @@ module.exports = {
VERSION: constants.VERSION,
Server: Server,
runner: runner,
stopper: stopper,
launcher: launcher,
server: oldServer
}
15 changes: 12 additions & 3 deletions lib/stopper.js
Expand Up @@ -2,11 +2,14 @@ var http = require('http')

var cfg = require('./config')
var logger = require('./logger')
var helper = require('./helper')

exports.stop = function (config) {
exports.stop = function (config, done) {
logger.setupFromConfig(config)
done = helper.isFunction(done) ? done : process.exit
var log = logger.create('stopper')
config = cfg.parseConfig(config.configFile, config)

var options = {
hostname: config.hostname,
path: config.urlRoot + 'stop',
Expand All @@ -17,14 +20,20 @@ exports.stop = function (config) {
var request = http.request(options)

request.on('response', function (response) {
if (response.statusCode !== 200) {
log.error('Server returned status code: ' + response.statusCode)
done(1)
return
}

log.info('Server stopped.')
process.exit(response.statusCode === 200 ? 0 : 1)
done(0)
})

request.on('error', function (e) {
if (e.code === 'ECONNREFUSED') {
log.error('There is no server listening on port %d', options.port)
process.exit(1, e.code)
done(1, e.code)
} else {
throw e
}
Expand Down
31 changes: 22 additions & 9 deletions test/e2e/steps/core_steps.js
Expand Up @@ -5,6 +5,7 @@ module.exports = function coreSteps () {
var exec = ref.exec
var spawn = ref.spawn
var rimraf = require('rimraf')
var stopper = require('../../../lib/stopper')

this.World = require('../support/world').World
require('../support/after_hooks').call(this)
Expand Down Expand Up @@ -39,13 +40,22 @@ module.exports = function coreSteps () {
return callback()
})

this.When(/^I stop a server programmatically/, function (callback) {
var _this = this
setTimeout(function () {
stopper.stop(_this.configFile, function (exitCode) {
_this.stopperExitCode = exitCode
})
callback()
}, 1000)
})

this.When(/^I start a server in background/, function (callback) {
this.writeConfigFile(tmpDir, tmpConfigFile, (function (_this) {
return function (err, hash) {
if (err) {
return callback.fail(new Error(err))
}

var configFile = path.join(tmpDir, hash + '.' + tmpConfigFile)
var runtimePath = path.join(baseDir, 'bin', 'karma')
_this.child = spawn('' + runtimePath, ['start', '--log-level', 'debug', configFile])
Expand Down Expand Up @@ -173,7 +183,6 @@ module.exports = function coreSteps () {
var actualOutput = this.lastRun.stdout.toString()
var actualError = this.lastRun.error
var actualStderr = this.lastRun.stderr.toString()

if (actualOutput.match(new RegExp(expectedOutput))) {
return callback()
}
Expand All @@ -183,11 +192,15 @@ module.exports = function coreSteps () {
}
})

this.Then(/^The server is dead( with exit code ([0-9]+))?$/, function (withExitCode, code, callback) {
setTimeout((function (_this) {
if (_this.childExitCode === undefined) return callback(new Error('Server has not exited.'))
if (code === undefined || parseInt(code, 10) === _this.childExitCode) return callback()
callback(new Error('Exit-code mismatch'))
})(this), 1000)
})
this.Then(/^The (server|stopper) is dead( with exit code ([0-9]+))?$/,
function (stopperOrServer, withExitCode, code, callback) {
var server = stopperOrServer === 'server'
var _this = this
setTimeout(function () {
var actualExitCode = server ? _this.childExitCode : _this.stopperExitCode
if (actualExitCode === undefined) return callback(new Error('Server has not exited.'))
if (code === undefined || parseInt(code, 10) === actualExitCode) return callback()
callback(new Error('Exit-code mismatch'))
}, 1000)
})
}
18 changes: 18 additions & 0 deletions test/e2e/stop.feature
Expand Up @@ -42,3 +42,21 @@ Feature: Stop karma
"""
Server stopped.
"""


Scenario: A server can be stopped programically
Given a configuration with:
"""
files = ['basic/plus.js', 'basic/test.js'];
browsers = ['PhantomJS'];
plugins = [
'karma-jasmine',
'karma-phantomjs-launcher'
];
singleRun = false;
logLevel = 'error';
"""
When I start a server in background
And I stop a server programmatically
Then The server is dead with exit code 0
And The stopper is dead with exit code 0

0 comments on commit 3d4fa00

Please sign in to comment.