Skip to content

Commit

Permalink
feat(runner): Buffer stdout and stderr for output when errors occur
Browse files Browse the repository at this point in the history
When it is determined that an error occured during the run of a launch
it's useful to have output from the process.
We just need to know what was going on in order to debug (if necessary)

Related to #2663 Complete browser log output when process isn't started
  • Loading branch information
LoveIsGrief committed Apr 18, 2017
1 parent 03958ce commit 460d423
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
25 changes: 24 additions & 1 deletion lib/launchers/process.js
Expand Up @@ -6,6 +6,11 @@ var ProcessLauncher = function (spawn, tempDir, timer, processKillTimeout) {
var self = this
var onExitCallback
var killTimeout = processKillTimeout || 2000
// Will hold output from the spawned child process
var streamedOutputs = {
stdout: '',
stderr: ''
}

this._tempDir = tempDir.getPath('/karma-' + this.id.toString())

Expand Down Expand Up @@ -46,6 +51,14 @@ var ProcessLauncher = function (spawn, tempDir, timer, processKillTimeout) {
return path.normalize(cmd)
}

this._onStdout = function (data) {
streamedOutputs.stdout += data
}

this._onStderr = function (data) {
streamedOutputs.stderr += data
}

this._execCommand = function (cmd, args) {
if (!cmd) {
log.error('No binary for %s browser on your platform.\n ' +
Expand All @@ -61,9 +74,12 @@ var ProcessLauncher = function (spawn, tempDir, timer, processKillTimeout) {

log.debug(cmd + ' ' + args.join(' '))
self._process = spawn(cmd, args)

var errorOutput = ''

self._process.stdout.on('data', self._onStdout)

self._process.stderr.on('data', self._onStderr)

self._process.on('exit', function (code) {
self._onProcessExit(code, errorOutput)
})
Expand Down Expand Up @@ -98,7 +114,14 @@ var ProcessLauncher = function (spawn, tempDir, timer, processKillTimeout) {
error = 'crashed'
}

if (error) {
log.error('%s stdout: %s', self.name, streamedOutputs.stdout)
log.error('%s stderr: %s', self.name, streamedOutputs.stderr)
}

self._process = null
streamedOutputs.stdout = ''
streamedOutputs.stderr = ''
if (self._killTimer) {
timer.clearTimeout(self._killTimer)
self._killTimer = null
Expand Down
15 changes: 15 additions & 0 deletions test/unit/launchers/process.spec.js
Expand Up @@ -22,6 +22,7 @@ describe('launchers/process.js', () => {

mockSpawn = sinon.spy(function (cmd, args) {
var process = new EventEmitter()
process.stdout = new EventEmitter()
process.stderr = new EventEmitter()
process.kill = sinon.spy()
process.exitCode = null
Expand Down Expand Up @@ -137,16 +138,30 @@ describe('launchers/process.js', () => {

// when the browser fails to get captured in default timeout, it should restart
it('start -> timeout -> restart', (done) => {
var stdOutSpy = sinon.spy(launcher, '_onStdout')
var stdErrSpy = sinon.spy(launcher, '_onStderr')

// start
launcher.start('http://localhost/')

// expect starting the process
expect(mockSpawn).to.have.been.calledWith(BROWSER_PATH, ['http://localhost/?id=fake-id'])
var browserProcess = mockSpawn._processes.shift()

var expectedStdoutString = 'starting...'
var expectedStderrString = 'Oops...there was a problem'
browserProcess.stdout.emit('data', expectedStdoutString)
browserProcess.stderr.emit('data', expectedStderrString)

// timeout
mockTimer.wind(101)

// We must've caught some output
expect(stdOutSpy).to.have.been.called
expect(stdErrSpy).to.have.been.called

stdOutSpy.calledWith(expectedStdoutString)

// expect killing browser
expect(browserProcess.kill).to.have.been.called
browserProcess.emit('exit', 0)
Expand Down

0 comments on commit 460d423

Please sign in to comment.