[Pkg-javascript-commits] [node-tap] 46/186: Unit test for t.spawn, and fix the bugs it found
Bastien Roucariès
rouca at moszumanska.debian.org
Fri Dec 1 16:40:42 UTC 2017
This is an automated email from the git hooks/post-receive script.
rouca pushed a commit to branch master
in repository node-tap.
commit e4a4f90b4ee47476d522e4e407a5a5b3e94be575
Author: isaacs <i at izs.me>
Date: Mon Oct 30 00:26:11 2017 -0700
Unit test for t.spawn, and fix the bugs it found
---
lib/base.js | 1 -
lib/spawn.js | 39 ++++----
lib/stack.js | 3 +-
scripts/generate-test-test.js | 1 +
test/test/mochalike--bail--buffer.tap | 2 +-
test/test/mochalike--bail.tap | 2 +-
test/test/mochalike--buffer.tap | 6 +-
test/test/mochalike.js | 3 +-
test/test/mochalike.tap | 6 +-
unit/spawn.js | 179 ++++++++++++++++++++++++++++++++++
10 files changed, 213 insertions(+), 29 deletions(-)
diff --git a/lib/base.js b/lib/base.js
index e0ca317..184eff2 100644
--- a/lib/base.js
+++ b/lib/base.js
@@ -191,7 +191,6 @@ class Base extends MiniPass {
omitVersion: this.omitVersion,
preserveWhitespace: this.preserveWhitespace
})
- assert(this.parser.preserveWhitespace)
this.parser.on('line', this.online.bind(this))
this.parser.once('bailout', this.onbail.bind(this))
this.parser.on('complete', this.oncomplete.bind(this))
diff --git a/lib/spawn.js b/lib/spawn.js
index f48c83e..49c5d6d 100644
--- a/lib/spawn.js
+++ b/lib/spawn.js
@@ -6,10 +6,7 @@ const util = require('util')
const ownOr = require('own-or')
const path = require('path')
const cleanYamlObject = require('./clean-yaml-object.js')
-
-
const cp = require('child_process')
-const spawn = cp.spawn
class Spawn extends Base {
constructor (options) {
@@ -32,6 +29,7 @@ class Spawn extends Base {
this.stdio = [ 0, 'pipe', 2 ]
this.stdio[1] = 'pipe'
+ options.stdio = this.stdio
const env = options.env || process.env
this.env = Object.assign({}, env)
@@ -60,7 +58,7 @@ class Spawn extends Base {
if (this.proc)
this.proc.kill('SIGKILL')
this.parser.abort('test unfinished')
- this.cb()
+ this.callCb()
}
main (cb) {
@@ -72,7 +70,7 @@ class Spawn extends Base {
stdio: this.stdio
}, this.options)
try {
- const proc = this.proc = spawn(this.command, this.args, options)
+ const proc = this.proc = cp.spawn(this.command, this.args, options)
proc.stdout.pipe(this.parser)
proc.on('close', this.onprocclose.bind(this))
proc.on('error', this.threw.bind(this))
@@ -81,6 +79,12 @@ class Spawn extends Base {
}
}
+ callCb () {
+ if (this.cb)
+ this.cb()
+ this.cb = null
+ }
+
threw (er, extra, proxy) {
extra = Base.prototype.threw.call(this, er, extra, proxy)
extra = cleanYamlObject(extra)
@@ -92,7 +96,7 @@ class Spawn extends Base {
this.proc.removeAllListeners('close')
this.proc.kill('SIGKILL')
}
- this.cb()
+ this.callCb()
}
onprocclose (code, signal) {
@@ -100,7 +104,6 @@ class Spawn extends Base {
this.options.exitCode = code
if (signal)
this.options.signal = signal
- this.results = this.results || {}
// spawn closing with no tests is treated as a skip.
if (this.results.plan && this.results.plan.skipAll && !code && !signal)
@@ -110,20 +113,22 @@ class Spawn extends Base {
this.results.ok = false
this.parser.ok = false
}
- return this.cb()
+ return this.callCb()
}
timeout (extra) {
- if (this.proc)
+ if (this.proc) {
this.proc.kill('SIGTERM')
- const t = setTimeout(() => {
- if (!this.options.signal && this.options.exitCode === undefined) {
- Base.prototype.timeout.call(this, extra)
- this.proc.kill('SIGKILL')
- }
- }, 1000)
- if (t.unref)
- t.unref()
+ const t = setTimeout(() => {
+ if (!this.options.signal && this.options.exitCode === undefined) {
+ Base.prototype.timeout.call(this, extra)
+ this.proc.kill('SIGKILL')
+ }
+ }, 1000)
+ /* istanbul ignore else */
+ if (t.unref)
+ t.unref()
+ }
}
}
diff --git a/lib/stack.js b/lib/stack.js
index fcd132f..5c8e511 100644
--- a/lib/stack.js
+++ b/lib/stack.js
@@ -3,6 +3,7 @@ const sourceMapSupport = require('source-map-support')
const StackUtils = require('stack-utils')
const path = require('path')
const tapDir = path.resolve(__dirname, '..')
+const osHomedir = require('os-homedir')
const resc = str =>
str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&')
@@ -15,7 +16,7 @@ const skip = (process.cwd() !== tapDir ||
+process.env.TAP_DEV_LONGSTACK !== 1
? [
/node_modules[\/\\]tap[\/\\]/,
- new RegExp(resc(path.resolve(process.env.HOME, '.node-spawn-wrap-')) + '.*'),
+ new RegExp(resc(path.resolve(osHomedir(), '.node-spawn-wrap-')) + '.*'),
new RegExp(resc(tapDir) + '\\b', 'i'),
new RegExp(resc(require.resolve('function-loop'))),
new RegExp(resc(path.dirname(require.resolve('bluebird/package.json'))))
diff --git a/scripts/generate-test-test.js b/scripts/generate-test-test.js
index 0a55d3c..dc47975 100644
--- a/scripts/generate-test-test.js
+++ b/scripts/generate-test-test.js
@@ -133,6 +133,7 @@ function yamlishToJson (output) {
if (inyaml) {
if (line.match(/^\s+\.\.\.$/) && line.length === startlen) {
const yload = yaml.safeLoad(y)
+ delete yload.stdio
const data = JSON.stringify(deStackify(yload))
ret += new Array(startlen - 2).join(' ') +
data + '\n' + line + '\n'
diff --git a/test/test/mochalike--bail--buffer.tap b/test/test/mochalike--bail--buffer.tap
index 3b62371..4657532 100644
--- a/test/test/mochalike--bail--buffer.tap
+++ b/test/test/mochalike--bail--buffer.tap
@@ -53,7 +53,7 @@ not ok 5 - failing indented things ___/# time=[0-9.]+(ms)?/~~~ {
not ok 1 - has no asserts, only throws ___/# time=[0-9.]+(ms)?/~~~ {
not ok 1 - false is not true on line 50
---
- {"actual":false,"at":{"column":7,"file":"test/test/mochalike.js","line":54},"expected":true,"generatedMessage":false,"operator":"==","source":"ok(false, 'false is not true on line 50')\n","test":"has no asserts, only throws","type":"AssertionError"}
+ {"actual":false,"at":{"column":7,"file":"test/test/mochalike.js","line":52},"expected":true,"generatedMessage":false,"operator":"==","source":"ok(false, 'false is not true on line 50')\n","test":"has no asserts, only throws","type":"AssertionError"}
...
Bail out! # false is not true on line 50
diff --git a/test/test/mochalike--bail.tap b/test/test/mochalike--bail.tap
index ff93287..66cab2b 100644
--- a/test/test/mochalike--bail.tap
+++ b/test/test/mochalike--bail.tap
@@ -53,7 +53,7 @@ ok 4 - reasonably indented things ___/# time=[0-9.]+(ms)?/~~~
# Subtest: has no asserts, only throws
not ok 1 - false is not true on line 50
---
- {"actual":false,"at":{"column":7,"file":"test/test/mochalike.js","line":54},"expected":true,"generatedMessage":false,"operator":"==","source":"ok(false, 'false is not true on line 50')\n","test":"has no asserts, only throws","type":"AssertionError"}
+ {"actual":false,"at":{"column":7,"file":"test/test/mochalike.js","line":52},"expected":true,"generatedMessage":false,"operator":"==","source":"ok(false, 'false is not true on line 50')\n","test":"has no asserts, only throws","type":"AssertionError"}
...
Bail out! # false is not true on line 50
diff --git a/test/test/mochalike--buffer.tap b/test/test/mochalike--buffer.tap
index fca2006..f6348e2 100644
--- a/test/test/mochalike--buffer.tap
+++ b/test/test/mochalike--buffer.tap
@@ -53,7 +53,7 @@ not ok 5 - failing indented things ___/# time=[0-9.]+(ms)?/~~~ {
not ok 1 - has no asserts, only throws ___/# time=[0-9.]+(ms)?/~~~ {
not ok 1 - false is not true on line 50
---
- {"actual":false,"at":{"column":7,"file":"test/test/mochalike.js","line":54},"expected":true,"generatedMessage":false,"operator":"==","source":"ok(false, 'false is not true on line 50')\n","test":"has no asserts, only throws","type":"AssertionError"}
+ {"actual":false,"at":{"column":7,"file":"test/test/mochalike.js","line":52},"expected":true,"generatedMessage":false,"operator":"==","source":"ok(false, 'false is not true on line 50')\n","test":"has no asserts, only throws","type":"AssertionError"}
...
1..1
@@ -69,7 +69,7 @@ not ok 5 - failing indented things ___/# time=[0-9.]+(ms)?/~~~ {
not ok 2 - second subset ___/# time=[0-9.]+(ms)?/~~~ {
not ok 1 - objectify the truthiness
---
- {"actual":false,"at":{"column":5,"file":"test/test/mochalike.js","line":60},"expected":true,"generatedMessage":false,"operator":"==","source":"ok(!{}, 'objectify the truthiness')\n","test":"second subset","type":"AssertionError"}
+ {"actual":false,"at":{"column":5,"file":"test/test/mochalike.js","line":58},"expected":true,"generatedMessage":false,"operator":"==","source":"ok(!{}, 'objectify the truthiness')\n","test":"second subset","type":"AssertionError"}
...
1..1
@@ -84,7 +84,7 @@ not ok 6 - a test passing an error to done() callback ___/# time=[0-9.]+(ms)?/~~
not ok 1 - is marked as failed ___/# time=[0-9.]+(ms)?/~~~ {
not ok 1 - error arg
---
- {"at":{"column":12,"file":"test/test/mochalike.js","line":67},"source":"done(new Error('error arg'))\n","test":"is marked as failed"}
+ {"at":{"column":12,"file":"test/test/mochalike.js","line":65},"source":"done(new Error('error arg'))\n","test":"is marked as failed"}
...
1..1
diff --git a/test/test/mochalike.js b/test/test/mochalike.js
index f93e755..940a4ef 100644
--- a/test/test/mochalike.js
+++ b/test/test/mochalike.js
@@ -1,6 +1,5 @@
-if (typeof describe !== 'function') {
+if (typeof describe !== 'function')
require('../../lib/mocha.js').global()
-}
/* global describe, it */
diff --git a/test/test/mochalike.tap b/test/test/mochalike.tap
index d464c9e..3a096d2 100644
--- a/test/test/mochalike.tap
+++ b/test/test/mochalike.tap
@@ -53,7 +53,7 @@ ok 4 - reasonably indented things ___/# time=[0-9.]+(ms)?/~~~
# Subtest: has no asserts, only throws
not ok 1 - false is not true on line 50
---
- {"actual":false,"at":{"column":7,"file":"test/test/mochalike.js","line":54},"expected":true,"generatedMessage":false,"operator":"==","source":"ok(false, 'false is not true on line 50')\n","test":"has no asserts, only throws","type":"AssertionError"}
+ {"actual":false,"at":{"column":7,"file":"test/test/mochalike.js","line":52},"expected":true,"generatedMessage":false,"operator":"==","source":"ok(false, 'false is not true on line 50')\n","test":"has no asserts, only throws","type":"AssertionError"}
...
1..1
@@ -69,7 +69,7 @@ ok 4 - reasonably indented things ___/# time=[0-9.]+(ms)?/~~~
# Subtest: second subset
not ok 1 - objectify the truthiness
---
- {"actual":false,"at":{"column":5,"file":"test/test/mochalike.js","line":60},"expected":true,"generatedMessage":false,"operator":"==","source":"ok(!{}, 'objectify the truthiness')\n","test":"second subset","type":"AssertionError"}
+ {"actual":false,"at":{"column":5,"file":"test/test/mochalike.js","line":58},"expected":true,"generatedMessage":false,"operator":"==","source":"ok(!{}, 'objectify the truthiness')\n","test":"second subset","type":"AssertionError"}
...
1..1
@@ -84,7 +84,7 @@ not ok 5 - failing indented things ___/# time=[0-9.]+(ms)?/~~~
# Subtest: is marked as failed
not ok 1 - error arg
---
- {"at":{"column":12,"file":"test/test/mochalike.js","line":67},"source":"done(new Error('error arg'))\n","test":"is marked as failed"}
+ {"at":{"column":12,"file":"test/test/mochalike.js","line":65},"source":"done(new Error('error arg'))\n","test":"is marked as failed"}
...
1..1
diff --git a/unit/spawn.js b/unit/spawn.js
new file mode 100644
index 0000000..38d513c
--- /dev/null
+++ b/unit/spawn.js
@@ -0,0 +1,179 @@
+const Spawn = require('../lib/spawn.js')
+const t = require('../')
+const Test = t.Test
+const Parser = require('tap-parser')
+const node = process.execPath
+const file = __filename
+
+const main = () => {
+ t.test('basic child process', t =>
+ t.spawn(node, [ file, 'ok' ]))
+
+ t.test('using a plan', t =>
+ t.spawn(node, [ file, 'plan-ok' ]))
+
+ t.test('hard quit', t =>
+ t.spawn(node, [ file, 'sigself' ],
+ { expectFail: true }))
+
+ t.test('failing process', t =>
+ t.spawn(node, [ file, 'not-ok' ],
+ { expectFail: true }))
+
+ t.test('timeout', t =>
+ t.spawn(node, [ file, 'timeout' ], {
+ expectFail: true,
+ timeout: 1
+ }))
+
+ t.test('timeout KILL', t => {
+ const s = new Spawn({
+ command: node,
+ args: [ file, 'catch-term' ],
+ timeout: 500,
+ buffered: true,
+ name: 'killa'
+ })
+ s.main(_ => {
+ t.equal(s.output, `
+not ok 1 - timeout!
+ ---
+ expired: killa
+ ...
+1..1
+# failed 1 test
+`)
+ t.end()
+ })
+ })
+
+ t.test('skip stuff', t => {
+ const tt = new Test({ buffered: true })
+ tt.spawn(node, [ file, 'skip' ], {
+ bail: true
+ }, 'skipper')
+ tt.spawn(node, [ file, 'skip-reason' ])
+ tt.test('check it', ttt => {
+ const output = tt.output
+ t.match(output, 'skipper # SKIP')
+ t.match(output,
+ 'spawn.js skip-reason # SKIP for no raisins')
+ t.end()
+ })
+ })
+
+ t.test('timeout before spawn is no-op', t => {
+ const s = new Spawn({
+ command: node,
+ args: [ file, 'timeout' ]
+ })
+ s.timeout()
+ t.end()
+ })
+
+ t.test('failure to spawn', t => {
+ const s = new Spawn({
+ command: 'something that does not exist',
+ args: [],
+ buffered: true,
+ stdio: [0, 1, 2]
+ })
+ s.main(_ => {
+ t.match(s.output,
+ 'not ok 1 - spawn something that does not exist ENOENT\n')
+ t.end()
+ })
+ })
+
+ t.test('failure to spawn even harder', t => {
+ const cp = require('child_process')
+ const spawn = cp.spawn
+ const poop = new Error('poop error')
+ cp.spawn = () => { throw poop }
+ t.teardown(_ => cp.spawn = spawn)
+ const s = new Spawn({
+ command: 'poop',
+ args: [],
+ buffered: true,
+ stdio: 'inherit'
+ })
+ s.main(_ => {
+ t.match(s.output, 'not ok 1 - poop error\n')
+ t.match(s.output, 'command: poop\n')
+ t.end()
+ })
+ })
+
+ t.throws(_ => new Spawn(),
+ new TypeError('no command provided'))
+
+ t.test('endAll called', t => {
+ t.test('call proc', t => {
+ const s = new Spawn({
+ command: node,
+ args: [ file, 'timeout' ],
+ buffered: true
+ })
+ s.main(_ => {
+ t.match(s.output, 'not ok 1 - test unfinished')
+ t.end()
+ })
+ setTimeout(_ => s.endAll())
+ })
+
+ t.test('pre-call', t => {
+ const cp = require('child_process')
+ const spawn = cp.spawn
+ const poop = new Error('poop error')
+ cp.spawn = () => { throw poop }
+ t.teardown(_ => cp.spawn = spawn)
+ const s = new Spawn({
+ command: node,
+ args: [ file, 'timeout' ],
+ buffered: true
+ })
+ s.endAll()
+ t.match(s.output, 'not ok 1 - test unfinished')
+ t.end()
+ })
+ t.end()
+ })
+}
+
+switch (process.argv[2]) {
+ case 'ok':
+ t.pass('this is fine')
+ break
+
+ case 'plan-ok':
+ t.plan(1)
+ t.pass('this is fine')
+ setTimeout(_ => _, 200)
+ break
+
+ case 'sigself':
+ setTimeout(_ =>
+ process.kill(process.pid, 'SIGQUIT'), 300)
+ break
+
+ case 'not-ok':
+ process.exit(1)
+ break
+
+ case 'skip':
+ t.plan(0)
+ break
+
+ case 'skip-reason':
+ t.plan(0, 'for no raisins')
+ break
+
+ case 'catch-term':
+ process.on('SIGTERM', _ => _)
+ case 'timeout':
+ setTimeout(_ => _, 5000)
+ break
+
+ default:
+ main()
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-tap.git
More information about the Pkg-javascript-commits
mailing list