1 | import 'reflect-metadata';
|
2 | import kernel from '../inversify.config';
|
3 | import {expect} from 'chai';
|
4 | import * as sinon from 'sinon';
|
5 | import * as _ from 'lodash';
|
6 | import path = require('path');
|
7 | import {Spawn} from "../interfaces/spawn";
|
8 | import {SpawnOptions2} from "../custom-typings";
|
9 |
|
10 | const pathToScripts = path.resolve(__dirname, '../../ts/test/shell-scripts');
|
11 | const testScript = path.resolve(pathToScripts, 'kitchen-sink.sh');
|
12 | const testArgs = [
|
13 | 'arg1',
|
14 | 'arg2'
|
15 | ];
|
16 |
|
17 | function checkError(error,
|
18 | code: number = 0,
|
19 | signal: string = '',
|
20 | stdOut: string = '',
|
21 | stdErr: string = '') {
|
22 | expect(error).to.exist;
|
23 | expect(error.message).to.be.not.empty;
|
24 | checkResult(error.message, code, signal, stdOut, stdErr);
|
25 | }
|
26 |
|
27 | function checkResult(result,
|
28 | code: number = 0,
|
29 | signal: string = '',
|
30 | stdOut: string = '',
|
31 | stdErr: string = '') {
|
32 | const resultObj = JSON.parse(result);
|
33 | expect(resultObj.code).to.equal(code);
|
34 | expect(resultObj.signal).to.equal(signal);
|
35 | expect(resultObj.stderrText).to.equal(stdErr);
|
36 | expect(resultObj.stdoutText).to.equal(stdOut);
|
37 | }
|
38 |
|
39 | function getNewSpawnOptions(): SpawnOptions2 {
|
40 | return _.clone({
|
41 | preSpawnMessage: 'PreSpawn Message',
|
42 | postSpawnMessage: 'PostSpawn Message',
|
43 | suppressDiagnostics: true,
|
44 | suppressStdErr: true,
|
45 | suppressStdOut: true,
|
46 | cacheStdErr: true,
|
47 | cacheStdOut: true,
|
48 | suppressResult: true,
|
49 | suppressFinalError: true
|
50 | });
|
51 | }
|
52 |
|
53 | function getArgArray(): string[] {
|
54 | return [
|
55 | testScript,
|
56 | 'writeToStdOutErrExitWithErrCode',
|
57 | '0',
|
58 | 'writeToStdOut',
|
59 | 'writeToStdErr',
|
60 | ...testArgs
|
61 | ];
|
62 | }
|
63 |
|
64 | describe('Testing Spawn Creation/Force Error', () => {
|
65 | it('should be created by kernel', (done) => {
|
66 | const spawn = kernel.get<Spawn>('Spawn');
|
67 | expect(spawn).to.exist;
|
68 | done();
|
69 | });
|
70 | it('should have final callback with error', (done) => {
|
71 | const spawn = kernel.get<Spawn>('Spawn');
|
72 | spawn.forceError = true;
|
73 | spawn.spawnShellCommandAsync(null, null, null,
|
74 | (err) => {
|
75 | expect(err).to.exist;
|
76 | expect(err.message).to.equal('force error: spawnShellCommandAsync');
|
77 | done();
|
78 | });
|
79 | });
|
80 | });
|
81 |
|
82 | describe('Testing Spawn ', () => {
|
83 | let spawn: Spawn;
|
84 | let argArray: string[];
|
85 | let spawnOptions: SpawnOptions2;
|
86 | let sinonSandbox;
|
87 | let cbStdOutSpy;
|
88 | let cbStdErrSpy;
|
89 | let cbDiagnosticSpy;
|
90 |
|
91 | function cbStatusMock(err, result) {
|
92 | if (err) {
|
93 | cbStdErrSpy(err, result);
|
94 | } else {
|
95 | cbStdOutSpy(err, result);
|
96 | }
|
97 | }
|
98 |
|
99 | const o = {
|
100 | cbStdOutCall: () => {
|
101 | },
|
102 | cbStdErrCall: () => {
|
103 | },
|
104 | cbStatus: () => {
|
105 | },
|
106 | cbDiagnostic: () => {
|
107 | }
|
108 | };
|
109 | beforeEach(() => {
|
110 | spawn = kernel.get<Spawn>('Spawn');
|
111 | argArray = getArgArray();
|
112 | spawnOptions = getNewSpawnOptions();
|
113 | sinonSandbox = sinon.sandbox.create();
|
114 | cbDiagnosticSpy = sinonSandbox.spy(o, 'cbDiagnostic');
|
115 | cbStdOutSpy = sinonSandbox.spy(o, 'cbStdOutCall');
|
116 | cbStdErrSpy = sinonSandbox.spy(o, 'cbStdErrCall');
|
117 | });
|
118 | afterEach(() => {
|
119 | sinonSandbox.restore();
|
120 | });
|
121 | it('no result, exit with code 0', (done) => {
|
122 | argArray[1] = 'exitWithErrCode';
|
123 | spawn.spawnShellCommandAsync(
|
124 | argArray,
|
125 | spawnOptions,
|
126 | o.cbStatus,
|
127 | (err, result) => {
|
128 | expect(err).to.not.exist;
|
129 | expect(result).to.be.empty;
|
130 | expect(cbStdErrSpy.called).to.be.false;
|
131 | expect(cbStdOutSpy.called).to.be.false;
|
132 | expect(cbDiagnosticSpy.called).to.be.false;
|
133 | done();
|
134 | },
|
135 | o.cbDiagnostic
|
136 | );
|
137 | });
|
138 | it('no result, yes diagnostics, exit with code 0', (done) => {
|
139 | argArray[1] = 'exitWithErrCode';
|
140 | spawnOptions.suppressDiagnostics = false;
|
141 | spawn.spawnShellCommandAsync(
|
142 | argArray,
|
143 | spawnOptions,
|
144 | o.cbStatus,
|
145 | (err, result) => {
|
146 | expect(err).to.not.exist;
|
147 | expect(result).to.be.empty;
|
148 | expect(cbStdErrSpy.called).to.be.false;
|
149 | expect(cbStdOutSpy.called).to.be.false;
|
150 | expect(cbDiagnosticSpy.called).to.be.true;
|
151 | done();
|
152 | },
|
153 | o.cbDiagnostic
|
154 | );
|
155 | });
|
156 | it('yes result, exit with code 0', (done) => {
|
157 | argArray[1] = 'exitWithErrCode';
|
158 | spawnOptions.suppressResult = false;
|
159 | spawn.spawnShellCommandAsync(
|
160 | argArray,
|
161 | spawnOptions,
|
162 | o.cbStatus,
|
163 | (err, result) => {
|
164 | expect(err).to.not.exist;
|
165 | checkResult(result);
|
166 | expect(cbStdErrSpy.called).to.be.false;
|
167 | expect(cbStdOutSpy.called).to.be.false;
|
168 | expect(cbDiagnosticSpy.called).to.be.false;
|
169 | done();
|
170 | },
|
171 | o.cbDiagnostic
|
172 | );
|
173 | });
|
174 | it('no result, no finalError, exit with code 3', (done) => {
|
175 | argArray[1] = 'exitWithErrCode';
|
176 | argArray[2] = '3';
|
177 | spawn.spawnShellCommandAsync(
|
178 | argArray,
|
179 | spawnOptions,
|
180 | o.cbStatus,
|
181 | (err, result) => {
|
182 | expect(err).to.not.exist;
|
183 | expect(result).to.be.empty;
|
184 | expect(cbStdErrSpy.called).to.be.false;
|
185 | expect(cbStdOutSpy.called).to.be.false;
|
186 | expect(cbDiagnosticSpy.called).to.be.false;
|
187 | done();
|
188 | },
|
189 | o.cbDiagnostic
|
190 | );
|
191 | });
|
192 | it('no result, yes finalError, exit with code 3', (done) => {
|
193 | argArray[1] = 'exitWithErrCode';
|
194 | argArray[2] = '3';
|
195 | spawnOptions.suppressFinalError = false;
|
196 | spawn.spawnShellCommandAsync(
|
197 | argArray,
|
198 | spawnOptions,
|
199 | o.cbStatus,
|
200 | (err, result) => {
|
201 | checkError(err, 3);
|
202 | expect(result).to.be.empty;
|
203 | expect(cbStdErrSpy.called).to.be.false;
|
204 | expect(cbStdOutSpy.called).to.be.false;
|
205 | expect(cbDiagnosticSpy.called).to.be.false;
|
206 | done();
|
207 | },
|
208 | o.cbDiagnostic
|
209 | );
|
210 | });
|
211 | it('yes result, yes finalError, exit with code 3', (done) => {
|
212 | argArray[1] = 'exitWithErrCode';
|
213 | argArray[2] = '3';
|
214 | spawnOptions.suppressFinalError = false;
|
215 | spawnOptions.suppressResult = false;
|
216 | spawn.spawnShellCommandAsync(
|
217 | argArray,
|
218 | spawnOptions,
|
219 | o.cbStatus,
|
220 | (err, result) => {
|
221 | checkError(err, 3);
|
222 | checkResult(result, 3);
|
223 | expect(cbStdErrSpy.called).to.be.false;
|
224 | expect(cbStdOutSpy.called).to.be.false;
|
225 | expect(cbDiagnosticSpy.called).to.be.false;
|
226 | done();
|
227 | },
|
228 | o.cbDiagnostic
|
229 | );
|
230 | });
|
231 | it('yes result, no finalError, exit with code 3', (done) => {
|
232 | argArray[1] = 'exitWithErrCode';
|
233 | argArray[2] = '3';
|
234 | spawnOptions.suppressResult = false;
|
235 | spawn.spawnShellCommandAsync(
|
236 | argArray,
|
237 | spawnOptions,
|
238 | o.cbStatus,
|
239 | (err, result) => {
|
240 | expect(err).to.not.exist;
|
241 | checkResult(result, 3);
|
242 | expect(cbStdErrSpy.called).to.be.false;
|
243 | expect(cbStdOutSpy.called).to.be.false;
|
244 | expect(cbDiagnosticSpy.called).to.be.false;
|
245 | done();
|
246 | },
|
247 | o.cbDiagnostic
|
248 | );
|
249 | });
|
250 | it('yes result, no finalError, yes stdout, yes stderr, exit with code 0', (done) => {
|
251 | spawnOptions.suppressStdOut = false;
|
252 | spawnOptions.suppressStdErr = false;
|
253 | spawnOptions.suppressResult = false;
|
254 | spawn.spawnShellCommandAsync(
|
255 | argArray,
|
256 | spawnOptions,
|
257 | cbStatusMock,
|
258 | (err, result) => {
|
259 | expect(err).to.not.exist;
|
260 | const concatArgs = testArgs.join('');
|
261 | checkResult(result, 0, '', concatArgs, concatArgs);
|
262 | expect(cbStdErrSpy.called).to.be.true;
|
263 | expect(cbStdOutSpy.called).to.be.true;
|
264 | expect(cbDiagnosticSpy.called).to.be.false;
|
265 | done();
|
266 | },
|
267 | o.cbDiagnostic
|
268 | );
|
269 | });
|
270 | it('edge: yes suppressStdErr, no cacheStdErr', (done) => {
|
271 | spawnOptions.suppressResult = false;
|
272 | spawnOptions.cacheStdOut = false;
|
273 | spawnOptions.cacheStdErr = false;
|
274 | spawn.spawnShellCommandAsync(
|
275 | argArray,
|
276 | spawnOptions,
|
277 | cbStatusMock,
|
278 | (err, result) => {
|
279 | expect(err).to.not.exist;
|
280 | checkResult(result);
|
281 | expect(cbStdErrSpy.called).to.be.false;
|
282 | expect(cbStdOutSpy.called).to.be.false;
|
283 | expect(cbDiagnosticSpy.called).to.be.false;
|
284 | done();
|
285 | },
|
286 | o.cbDiagnostic
|
287 | );
|
288 | });
|
289 | it(`edge: fire 'error' event on child process`, (done) => {
|
290 | spawnOptions.suppressResult = false;
|
291 | spawnOptions.suppressFinalError = false;
|
292 | const cp = spawn.spawnShellCommandAsync(
|
293 | argArray,
|
294 | spawnOptions,
|
295 | o.cbStatus,
|
296 | (err, result) => {
|
297 | checkResult(result, 30, 'SIGUSR1');
|
298 | checkError(err, 30, 'SIGUSR1');
|
299 | expect(cbStdErrSpy.called).to.be.false;
|
300 | expect(cbStdOutSpy.called).to.be.false;
|
301 | expect(cbDiagnosticSpy.called).to.be.false;
|
302 | done();
|
303 | },
|
304 | o.cbDiagnostic
|
305 | );
|
306 | cp.emit('error', 30, 'SIGUSR1');
|
307 | });
|
308 | it(`edge: fire 'error' event on child process`, (done) => {
|
309 | argArray[0] = '/';
|
310 | spawnOptions.suppressResult = false;
|
311 | spawnOptions.suppressFinalError = false;
|
312 | spawn.spawnShellCommandAsync(
|
313 | argArray,
|
314 | spawnOptions,
|
315 | o.cbStatus,
|
316 | (err, result) => {
|
317 | expect(result).to.not.exist;
|
318 | expect(err['code']).to.equal('EACCES');
|
319 | expect(err['errno']).to.equal('EACCES');
|
320 | expect(err.message).to.equal('spawn EACCES');
|
321 | expect(cbStdErrSpy.called).to.be.false;
|
322 | expect(cbStdOutSpy.called).to.be.false;
|
323 | expect(cbDiagnosticSpy.called).to.be.false;
|
324 | done();
|
325 | },
|
326 | o.cbDiagnostic
|
327 | );
|
328 | });
|
329 | });
|