Skip to content

Commit 0749d2c

Browse files
committed
add to spawn
1 parent 57b90fc commit 0749d2c

6 files changed

Lines changed: 180 additions & 124 deletions

File tree

lib/commandExecutorBuilder.js

Lines changed: 9 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,12 @@
1-
const {exec} = require('child_process')
2-
const {returnStringType} = require('./helpers')
3-
const {executionWatcher} = require('./utils')
4-
5-
function buildCommandExecutor(failedByAssert, runOpts) {
6-
7-
const {
8-
addSpecificOptionsBeforeRun,
9-
currentExecutionVariable,
10-
longestProcessTime,
11-
debugProcess,
12-
reformatCommand,
13-
stackAnalize
14-
} = runOpts
15-
16-
const executeCommandAsync = (cmd, index) => new Promise((resolve) => {
17-
let watcher = null
18-
let additionalOpts = null
19-
let originalCmd = cmd
20-
let specificCallBack = null
21-
let killTooLongExecution = null
22-
let executionStack = ''
23-
24-
/**
25-
* @now this variable will be used for process kill if time more than @longestProcessTime
26-
*/
27-
const now = +Date.now()
28-
29-
/**
30-
* @param {undefined|function} addSpecificOptions if function cmd will go to this function as argument
31-
*/
32-
if(addSpecificOptionsBeforeRun) {
33-
const cmdObj = addSpecificOptionsBeforeRun(cmd)
34-
cmd = cmdObj.cmd
35-
specificCallBack = cmdObj.cmdExecutableCB
36-
additionalOpts = cmd.replace(originalCmd, '')
37-
}
38-
39-
if(currentExecutionVariable) {
40-
if(cmd.includes(currentExecutionVariable)) {
41-
cmd = cmd.replace(new RegExp(`${currentExecutionVariable}=\\d+`, 'ig'), `${currentExecutionVariable}=${index}`)
42-
} else {
43-
cmd = `${currentExecutionVariable}=${index} ${cmd}`
44-
}
45-
}
46-
47-
if(debugProcess) {console.log(cmd)}
48-
49-
const proc = exec(cmd)
50-
51-
52-
53-
watcher = setInterval(() => executionWatcher(debugProcess, now, longestProcessTime, watcher, proc, resolve, cmd), 5000)
54-
55-
56-
57-
proc.on('exit', () => {clearInterval(watcher)})
58-
59-
proc.stdout.on('data', (data) => {
60-
(debugProcess) && console.log(data.toString('utf8')); executionStack += data.toString()
61-
})
62-
proc.stderr.on('data', (data) => console.log(data.toString('utf8')))
63-
proc.on('error', (e) => {console.error(e)})
64-
65-
proc.on('close', async (code) => {
66-
67-
let commandToRerun = null
68-
69-
if(debugProcess) {console.log(executionStack, code)}
70-
71-
// if process code 0 - exit as a success result
72-
if(code === 0) {
73-
resolve(commandToRerun); return
74-
}
75-
// stackAnalize - check that stack contains or not contains some specific data
76-
if(code !== 0 && stackAnalize && stackAnalize(executionStack)) {
77-
commandToRerun = cmd
78-
} else if(code !== 0 && reformatCommand) {
79-
commandToRerun = cmd
80-
} else {
81-
failedByAssert.push(cmd)
82-
}
83-
84-
// if code === 0 do nothing, success
85-
if(specificCallBack) {
86-
if(specificCallBack.then || returnStringType(specificCallBack) === '[object AsyncFunction]') {
87-
await specificCallBack()
88-
} else {
89-
specificCallBack()
90-
}
91-
}
92-
93-
if(reformatCommand && commandToRerun) {
94-
commandToRerun = reformatCommand(commandToRerun, executionStack)
95-
}
96-
// addSpecificOptionsBeforeRun was defined - we should remove useless opts what will be added in next iteration
97-
if(additionalOpts) {
98-
commandToRerun = commandToRerun.replace(additionalOpts, '')
99-
}
100-
101-
resolve(commandToRerun)
102-
})
103-
})
104-
return executeCommandAsync
1+
const {buildExecRunner} = require('./execProc')
2+
const {buildSpawnRunner} = require('./spawnProc')
3+
4+
function buildCommandExecutor(failedByAssert, {spawn = false, ...runOpts}) {
5+
if(spawn) {
6+
return buildSpawnRunner(failedByAssert, runOpts)
7+
} else {
8+
return buildExecRunner(failedByAssert, runOpts)
9+
}
10510
}
10611

10712
module.exports = {

lib/execProc.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,7 @@ function buildExecRunner(failedByAssert, runOpts) {
2424
*/
2525
const now = +Date.now()
2626

27-
const killTooLongExecution = (proc) => {
28-
if(Date.now() - now >= longestProcessTime) {
29-
proc.kill()
30-
}
31-
}
27+
3228
/**
3329
* @param {undefined|function} addSpecificOptions if function cmd will go to this function as argument
3430
*/
@@ -51,8 +47,13 @@ function buildExecRunner(failedByAssert, runOpts) {
5147

5248
const proc = exec(cmd)
5349

50+
const killTooLongExecution = (proc) => {
51+
if(now - Date.now() < longestProcessTime) {
52+
proc.kill()
53+
}
54+
}
5455

55-
watcher = setInterval(killTooLongExecution, 5000)
56+
watcher = setInterval(() => killTooLongExecution(proc), 5000)
5657

5758
proc.on('exit', () => {clearInterval(watcher)})
5859

@@ -63,7 +64,6 @@ function buildExecRunner(failedByAssert, runOpts) {
6364
proc.on('error', (e) => {console.error(e)})
6465

6566
proc.on('close', async (code) => {
66-
6767
let commandToRerun = null
6868

6969
if(debugProcess) {console.log(executionStack, code)}

lib/spawnProc.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
const {exec} = require('child_process')
1+
const {spawn} = require('child_process')
22
const {returnStringType} = require('./helpers')
33

4-
function buildExecRunner(failedByAssert, runOpts) {
4+
function buildSpawnRunner(failedByAssert, runOpts) {
55

66
const {
77
addSpecificOptionsBeforeRun,
@@ -11,10 +11,9 @@ function buildExecRunner(failedByAssert, runOpts) {
1111
stackAnalize
1212
} = runOpts
1313

14-
1514
const executeCommandAsync = (cmd) => new Promise((resolve) => {
1615
let watcher = null
17-
let additionalOpts = null
16+
let originalComman = null
1817
let originalCmd = cmd
1918
let specificCallBack = null
2019
let executionStack = ''
@@ -33,30 +32,29 @@ function buildExecRunner(failedByAssert, runOpts) {
3332
* @param {undefined|function} addSpecificOptions if function cmd will go to this function as argument
3433
*/
3534
if(addSpecificOptionsBeforeRun) {
36-
3735
const cmdObj = addSpecificOptionsBeforeRun(cmd)
36+
originalComman = {...cmd}
3837
cmd = cmdObj.cmd
3938

4039
specificCallBack = cmdObj.cmdExecutableCB
41-
additionalOpts = cmd.replace(originalCmd, '')
4240
}
4341

4442
if(debugProcess) {console.log(cmd)}
4543

4644
const proc = spawn(cmd.command, cmd.args, cmd.options)
4745

48-
watcher = setInterval(killTooLongExecution, 5000)
46+
watcher = setInterval(() => killTooLongExecution(proc), 5000)
4947

5048
proc.on('exit', () => {clearInterval(watcher)})
5149

5250
proc.stdout.on('data', (data) => {
5351
(debugProcess) && console.log(data.toString('utf8')); executionStack += data.toString()
5452
})
5553
proc.stderr.on('data', (data) => console.log(data.toString('utf8')))
54+
5655
proc.on('error', (e) => {console.error(e)})
5756

5857
proc.on('close', async (code) => {
59-
6058
let commandToRerun = null
6159

6260
if(debugProcess) {console.log(executionStack, code)}
@@ -87,9 +85,9 @@ function buildExecRunner(failedByAssert, runOpts) {
8785
commandToRerun = reformatCommand(commandToRerun, executionStack)
8886
}
8987
// addSpecificOptionsBeforeRun was defined - we should remove useless opts what will be added in next iteration
90-
if(additionalOpts) {
91-
commandToRerun = commandToRerun.replace(additionalOpts, '')
92-
}
88+
// if(additionalOpts) {
89+
// commandToRerun = commandToRerun.replace(additionalOpts, '')
90+
// }
9391

9492
resolve(commandToRerun)
9593
})
@@ -98,5 +96,5 @@ function buildExecRunner(failedByAssert, runOpts) {
9896
}
9997

10098
module.exports = {
101-
buildExecRunner
99+
buildSpawnRunner
102100
}

lol.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const {spawn} = require('child_process')
2+
3+
const cmd = ['node', ['-e', "console.log(\'test\')"]]
4+
5+
const proc = spawn(...cmd)
6+
7+
proc.stdout.on('data', (data) => {
8+
console.log(data.toString('utf8'))
9+
})

unit_specs/exec/commandExecutorBuilder.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ describe('buildCommandExecutor', () => {
9797

9898
const executeCommandAsync = buildCommandExecutor(failedByAssert, {stackAnalize, longestProcessTime: 1})
9999
await executeCommandAsync(cmd)
100-
expect(holder).to.eq(null)
100+
expect(holder).not.to.eq(null)
101101
}
102102
{
103103
const failedByAssert = []
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
const {expect} = require('chai')
2+
3+
const {buildCommandExecutor} = require('../../lib/commandExecutorBuilder')
4+
5+
describe('buildCommandExecutor spawn', () => {
6+
7+
it('addSpecificOptionsBeforeRun', async () => {
8+
{
9+
const cmd = {command: 'node', args: ['-e', "console.log(\'test\')"]}
10+
const failedByAssert = []
11+
let holder = null
12+
13+
const addSpecificOptionsBeforeRun = (cmd) => {
14+
cmd.args.push('&&', 'echo', '"FOO"')
15+
holder = {}
16+
holder.cmd = {...cmd}
17+
const cmdExecutableCB = () => {holder.exec = true}
18+
return {cmd, cmdExecutableCB}
19+
}
20+
21+
const executeCommandAsync = buildCommandExecutor(failedByAssert, {spawn: true, addSpecificOptionsBeforeRun})
22+
await executeCommandAsync(cmd)
23+
expect(holder.cmd.args).to.contains('&&')
24+
expect(holder.cmd.args).to.contains('echo')
25+
expect(holder.cmd.args).to.contains('"FOO"')
26+
expect(holder.exec).to.eq(undefined)
27+
}
28+
{
29+
const cmd = {command: 'node', args: ['-e', "console.log(\'test\'); process.exit(100)"]}
30+
const failedByAssert = []
31+
let holder = null
32+
33+
const addSpecificOptionsBeforeRun = (cmd) => {
34+
cmd.args.push('&&', 'echo', '"FOO"')
35+
holder = {}
36+
holder.cmd = {...cmd}
37+
const cmdExecutableCB = () => {holder.exec = true}
38+
return {cmd, cmdExecutableCB}
39+
}
40+
41+
const executeCommandAsync = buildCommandExecutor(failedByAssert, {spawn: true, addSpecificOptionsBeforeRun})
42+
await executeCommandAsync(cmd)
43+
expect(holder.cmd.args).to.contains('&&')
44+
expect(holder.cmd.args).to.contains('echo')
45+
expect(holder.cmd.args).to.contains('"FOO"')
46+
expect(holder.exec).to.eq(true)
47+
}
48+
})
49+
50+
it('reformatCommand', async () => {
51+
const failedByAssert = []
52+
let holder = null
53+
54+
const cmd = {command: 'node', args: ['-e', "console.log(\'test\'); process.exit(1)"]}
55+
56+
const reformatCommand = (cmd, stack) => {
57+
holder = {}
58+
holder.cmd = cmd
59+
holder.stack = stack
60+
}
61+
62+
const executeCommandAsync = buildCommandExecutor(failedByAssert, {spawn: true, reformatCommand})
63+
await executeCommandAsync(cmd)
64+
expect(holder.cmd).to.eq(cmd)
65+
expect(holder.stack).to.eql('test\n')
66+
})
67+
68+
it('stackAnalize', async () => {
69+
const failedByAssert = []
70+
let holder = null
71+
72+
const cmd = {command: 'node', args: ['-e', "console.log('test'); process.exit(1)"]}
73+
74+
const reformatCommand = (cmd, stack) => {
75+
if(!holder) holder = {}
76+
holder.cmd = cmd
77+
holder.stack = stack
78+
}
79+
80+
const stackAnalize = (stack) => {
81+
holder = {}
82+
holder.fromStackAnalize = stack
83+
return false
84+
}
85+
const executeCommandAsync = buildCommandExecutor(failedByAssert, {
86+
spawn: true,
87+
reformatCommand,
88+
stackAnalize
89+
})
90+
await executeCommandAsync(cmd)
91+
expect(holder.fromStackAnalize).to.eq('test\n')
92+
expect(holder.cmd).to.eq(cmd)
93+
expect(holder.stack).to.eq('test\n')
94+
})
95+
96+
it('longestProcessTime', async () => {
97+
{
98+
const failedByAssert = []
99+
let holder = null
100+
const stackAnalize = (stack) => {
101+
holder = {}
102+
holder.fromStackAnalize = stack
103+
return false
104+
}
105+
const cmd = {
106+
command: 'node', args: ['-e', `(async function() {await new Promise((res) => setTimeout(() => {
107+
res(process.exit(1))
108+
}, 25000))})()`
109+
]
110+
}
111+
112+
const executeCommandAsync = buildCommandExecutor(failedByAssert, {
113+
spawn: true,
114+
stackAnalize,
115+
longestProcessTime: 1
116+
})
117+
await executeCommandAsync(cmd)
118+
expect(holder).to.eql({fromStackAnalize: ''})
119+
}
120+
{
121+
const failedByAssert = []
122+
let holder = null
123+
const stackAnalize = (stack) => {
124+
holder = {}
125+
holder.fromStackAnalize = stack
126+
return false
127+
}
128+
const cmd = {
129+
command: 'node', args: ['-e', `(async function() {await new Promise((res) => setTimeout(() => {
130+
res(process.exit(1))
131+
}, 25000))})()`
132+
]
133+
}
134+
135+
const executeCommandAsync = buildCommandExecutor(failedByAssert, {
136+
spawn: true,
137+
stackAnalize,
138+
longestProcessTime: 10000
139+
})
140+
await executeCommandAsync(cmd)
141+
expect(holder).to.not.eq(null)
142+
}
143+
})
144+
})

0 commit comments

Comments
 (0)