parallel.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /**
  2. * @author Toru Nagashima
  3. * @copyright 2016 Toru Nagashima. All rights reserved.
  4. * See LICENSE file in root directory for full license.
  5. */
  6. 'use strict'
  7. // ------------------------------------------------------------------------------
  8. // Requirements
  9. // ------------------------------------------------------------------------------
  10. const assert = require('assert').strict
  11. const nodeApi = require('../lib')
  12. const spawnWithKill = require('./lib/spawn-with-kill')
  13. const { delay, result, removeResult, runAll, runPar } = require('./lib/util')
  14. // ------------------------------------------------------------------------------
  15. // Test
  16. // ------------------------------------------------------------------------------
  17. describe('[parallel]', () => {
  18. before(() => process.chdir('test-workspace'))
  19. after(() => process.chdir('..'))
  20. beforeEach(() => delay(1000).then(removeResult))
  21. describe('should run tasks on parallel when was given --parallel option:', () => {
  22. it('Node API', async () => {
  23. const results = await nodeApi(['test-task:append a', 'test-task:append b'], { parallel: true })
  24. assert(results.length === 2)
  25. assert(results[0].name === 'test-task:append a')
  26. assert(results[0].code === 0)
  27. assert(results[1].name === 'test-task:append b')
  28. assert(results[1].code === 0)
  29. assert(
  30. result() === 'abab' ||
  31. result() === 'baba' ||
  32. result() === 'abba' ||
  33. result() === 'baab'
  34. )
  35. })
  36. it('npm-run-all command', async () => {
  37. await runAll(['--parallel', 'test-task:append a', 'test-task:append b'])
  38. assert(
  39. result() === 'abab' ||
  40. result() === 'baba' ||
  41. result() === 'abba' ||
  42. result() === 'baab'
  43. )
  44. })
  45. it('run-p command', async () => {
  46. await runPar(['test-task:append a', 'test-task:append b'])
  47. assert(
  48. result() === 'abab' ||
  49. result() === 'baba' ||
  50. result() === 'abba' ||
  51. result() === 'baab'
  52. )
  53. })
  54. })
  55. describe('should kill all tasks when was given --parallel option if a task exited with a non-zero code:', () => {
  56. it('Node API', async () => {
  57. try {
  58. await nodeApi(['test-task:append2 a', 'test-task:error'], { parallel: true })
  59. } catch (err) {
  60. assert(err.results.length === 2)
  61. assert(err.results[0].name === 'test-task:append2 a')
  62. assert(err.results[0].code === undefined)
  63. assert(err.results[1].name === 'test-task:error')
  64. assert(err.results[1].code === 1)
  65. assert(result() == null || result() === 'a')
  66. return
  67. }
  68. assert(false, 'should fail')
  69. })
  70. it('npm-run-all command', async () => {
  71. try {
  72. await runAll(['--parallel', 'test-task:append2 a', 'test-task:error'])
  73. } catch (_err) {
  74. assert(result() == null || result() === 'a')
  75. return
  76. }
  77. assert(false, 'should fail')
  78. })
  79. it('run-p command', async () => {
  80. try {
  81. await runPar(['test-task:append2 a', 'test-task:error'])
  82. } catch (_err) {
  83. assert(result() == null || result() === 'a')
  84. return
  85. }
  86. assert(false, 'should fail')
  87. })
  88. })
  89. describe('should remove intersected tasks from two or more patterns:', () => {
  90. it('Node API', async () => {
  91. await nodeApi(['test-task:*:a', '*:append:a'], { parallel: true })
  92. assert(result() === 'aa')
  93. })
  94. it('npm-run-all command', async () => {
  95. await runAll(['--parallel', 'test-task:*:a', '*:append:a'])
  96. assert(result() === 'aa')
  97. })
  98. it('run-p command', async () => {
  99. await runPar(['test-task:*:a', '*:append:a'])
  100. assert(result() === 'aa')
  101. })
  102. })
  103. describe('should not remove duplicate tasks from two or more the same pattern:', () => {
  104. it('Node API', async () => {
  105. await nodeApi(['test-task:*:a', 'test-task:*:a'], { parallel: true })
  106. assert(result() === 'aaaa')
  107. })
  108. it('npm-run-all command', async () => {
  109. await runAll(['--parallel', 'test-task:*:a', 'test-task:*:a'])
  110. assert(result() === 'aaaa')
  111. })
  112. it('run-p command', async () => {
  113. await runPar(['test-task:*:a', 'test-task:*:a'])
  114. assert(result() === 'aaaa')
  115. })
  116. })
  117. describe("should kill child processes when it's killed", () => {
  118. it('npm-run-all command', async () => {
  119. await spawnWithKill(
  120. 'node',
  121. ['../bin/npm-run-all/index.js', '--parallel', 'test-task:append2 a']
  122. )
  123. assert(result() == null || result() === 'a')
  124. })
  125. it('run-p command', async () => {
  126. await spawnWithKill(
  127. 'node',
  128. ['../bin/run-p/index.js', 'test-task:append2 a']
  129. )
  130. assert(result() == null || result() === 'a')
  131. })
  132. })
  133. describe('should continue on error when --continue-on-error option was specified:', () => {
  134. it('Node API', async () => {
  135. try {
  136. await nodeApi(['test-task:append a', 'test-task:error', 'test-task:append b'], { parallel: true, continueOnError: true })
  137. } catch (_err) {
  138. console.log(result()) // TODO: This is randomly failing
  139. assert(
  140. result() === 'abab' ||
  141. result() === 'baba' ||
  142. result() === 'abba' ||
  143. result() === 'baab'
  144. )
  145. return
  146. }
  147. assert(false, 'should fail.')
  148. })
  149. it('npm-run-all command (--continue-on-error)', async () => {
  150. try {
  151. await runAll(['--continue-on-error', '--parallel', 'test-task:append a', 'test-task:error', 'test-task:append b'])
  152. } catch (_err) {
  153. assert(
  154. result() === 'abab' ||
  155. result() === 'baba' ||
  156. result() === 'abba' ||
  157. result() === 'baab'
  158. )
  159. return
  160. }
  161. assert(false, 'should fail.')
  162. })
  163. it('npm-run-all command (-c)', async () => {
  164. try {
  165. await runAll(['-cp', 'test-task:append a', 'test-task:error', 'test-task:append b'])
  166. } catch (_err) {
  167. assert(
  168. result() === 'abab' ||
  169. result() === 'baba' ||
  170. result() === 'abba' ||
  171. result() === 'baab'
  172. )
  173. return
  174. }
  175. assert(false, 'should fail.')
  176. })
  177. it('run-p command (--continue-on-error)', async () => {
  178. try {
  179. await runPar(['--continue-on-error', 'test-task:append a', 'test-task:error', 'test-task:append b'])
  180. } catch (_err) {
  181. assert(
  182. result() === 'abab' ||
  183. result() === 'baba' ||
  184. result() === 'abba' ||
  185. result() === 'baab'
  186. )
  187. return
  188. }
  189. assert(false, 'should fail.')
  190. })
  191. it('run-p command (-c)', async () => {
  192. try {
  193. await runPar(['-c', 'test-task:append a', 'test-task:error', 'test-task:append b'])
  194. } catch (_err) {
  195. assert(
  196. result() === 'abab' ||
  197. result() === 'baba' ||
  198. result() === 'abba' ||
  199. result() === 'baab'
  200. )
  201. return
  202. }
  203. assert(false, 'should fail.')
  204. })
  205. })
  206. describe('should abort other tasks when a task finished, when --race option was specified:', () => {
  207. it('Node API', async () => {
  208. await nodeApi(['test-task:append1 a', 'test-task:append2 b'], { parallel: true, race: true })
  209. await delay(5000)
  210. assert(result() === 'a' || result() === 'ab' || result() === 'ba')
  211. })
  212. it('npm-run-all command (--race)', async () => {
  213. await runAll(['--race', '--parallel', 'test-task:append1 a', 'test-task:append2 b'])
  214. await delay(5000)
  215. assert(result() === 'a' || result() === 'ab' || result() === 'ba')
  216. })
  217. it('npm-run-all command (-r)', async () => {
  218. await runAll(['-rp', 'test-task:append1 a', 'test-task:append2 b'])
  219. await delay(5000)
  220. assert(result() === 'a' || result() === 'ab' || result() === 'ba')
  221. })
  222. it('run-p command (--race)', async () => {
  223. await runPar(['--race', 'test-task:append1 a', 'test-task:append2 b'])
  224. await delay(5000)
  225. assert(result() === 'a' || result() === 'ab' || result() === 'ba')
  226. })
  227. it('run-p command (-r)', async () => {
  228. await runPar(['-r', 'test-task:append1 a', 'test-task:append2 b'])
  229. await delay(5000)
  230. assert(result() === 'a' || result() === 'ab' || result() === 'ba')
  231. })
  232. it('run-p command (no -r)', async () => {
  233. await runPar(['test-task:append1 a', 'test-task:append2 b'])
  234. await delay(5000)
  235. assert(result() === 'abb' || result() === 'bab')
  236. })
  237. })
  238. describe('should run tasks in parallel-2 when was given --max-parallel 2 option:', () => {
  239. it('Node API', async () => {
  240. const results = await nodeApi(['test-task:append a', 'test-task:append b', 'test-task:append c'], { parallel: true, maxParallel: 2 })
  241. assert(results.length === 3)
  242. assert(results[0].name === 'test-task:append a')
  243. assert(results[0].code === 0)
  244. assert(results[1].name === 'test-task:append b')
  245. assert(results[1].code === 0)
  246. assert(results[2].name === 'test-task:append c')
  247. assert(results[2].code === 0)
  248. assert(
  249. result() === 'ababcc' ||
  250. result() === 'babacc' ||
  251. result() === 'abbacc' ||
  252. result() === 'baabcc'
  253. )
  254. })
  255. it('npm-run-all command', async () => {
  256. await runAll(['--parallel', 'test-task:append a', 'test-task:append b', 'test-task:append c', '--max-parallel', '2'])
  257. assert(
  258. result() === 'ababcc' ||
  259. result() === 'babacc' ||
  260. result() === 'abbacc' ||
  261. result() === 'baabcc'
  262. )
  263. })
  264. it('run-p command', async () => {
  265. await runPar(['test-task:append a', 'test-task:append b', 'test-task:append c', '--max-parallel', '2'])
  266. assert(
  267. result() === 'ababcc' ||
  268. result() === 'babacc' ||
  269. result() === 'abbacc' ||
  270. result() === 'baabcc'
  271. )
  272. })
  273. })
  274. })