PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/test/functional/eft_6_concurrence.rb

http://github.com/jmettraux/ruote
Ruby | 658 lines | 438 code | 185 blank | 35 comment | 5 complexity | 1024007245b75b006bd41b512ab61f55 MD5 | raw file
  1. #
  2. # testing ruote
  3. #
  4. # Thu Jun 11 15:24:47 JST 2009
  5. #
  6. require File.expand_path('../base', __FILE__)
  7. class EftConcurrenceTest < Test::Unit::TestCase
  8. include FunctionalBase
  9. def test_basic
  10. pdef = Ruote.process_definition do
  11. concurrence do
  12. alpha
  13. alpha
  14. end
  15. end
  16. @dashboard.register_participant :alpha do
  17. tracer << "alpha\n"
  18. end
  19. assert_trace %w[ alpha alpha ], pdef
  20. end
  21. def test_empty
  22. pdef = Ruote.process_definition do
  23. concurrence do
  24. end
  25. echo 'done.'
  26. end
  27. assert_trace %w[ done. ], pdef
  28. end
  29. def test_accidental_empty
  30. @dashboard.register_participant :nada do
  31. tracer << "nada\n"
  32. end
  33. pdef = Ruote.process_definition do
  34. concurrence do
  35. nada :if => false
  36. end
  37. echo 'done.'
  38. end
  39. assert_trace %w[ done. ], pdef
  40. end
  41. def test_over_if
  42. pdef = Ruote.process_definition do
  43. concurrence :over_if => "${f:seen}", :merge_type => :isolate do
  44. alpha
  45. alpha
  46. alpha
  47. end
  48. bravo
  49. end
  50. stash[:count] = 0
  51. alpha = @dashboard.register :alpha, 'do_not_thread' => true do |wi|
  52. wi.fields['seen'] = 'indeed' if stash[:count] == 1
  53. tracer << "alpha\n"
  54. stash[:count] += 1
  55. nil
  56. end
  57. @dashboard.register_participant :bravo do |workitem|
  58. stash[:fields] = workitem.fields
  59. nil
  60. end
  61. assert_trace(%w[ alpha ] * 3, pdef)
  62. #assert_equal(
  63. # {'1'=>{"seen"=>"indeed"}, '0'=>{}, "params"=>{"ref"=>"bravo"}},
  64. # fields)
  65. params = @dashboard.context.stash[:fields].delete('params')
  66. assert_equal({ 'ref' => 'bravo' }, params)
  67. assert_match /seen/, @dashboard.context.stash[:fields].inspect
  68. end
  69. def test_over_if__remaining_cancel
  70. @dashboard.register 'alpha', Ruote::StorageParticipant
  71. pdef = Ruote.define do
  72. concurrence :over_if => '${seen}' do
  73. alpha
  74. alpha
  75. end
  76. end
  77. wfid = @dashboard.launch(pdef)
  78. @dashboard.wait_for('dispatched')
  79. wi = @dashboard.storage_participant.first
  80. wi.fields['seen'] = true
  81. @dashboard.storage_participant.proceed(wi)
  82. @dashboard.wait_for('dispatch_cancel')
  83. sleep 0.350
  84. assert_equal 0, @dashboard.storage_participant.size
  85. end
  86. def test_over_if__post
  87. @dashboard.register :alpha do |workitem|
  88. tracer << "alpha\n"
  89. workitem.fields['ok'] = 'yes'
  90. end
  91. @dashboard.register :bravo do |workitem|
  92. sleep 0.5
  93. tracer << "bravo\n"
  94. end
  95. @dashboard.register :zulu do |workitem|
  96. tracer << "zulu\n"
  97. end
  98. pdef = Ruote.define do
  99. set 'f:ok' => 'no'
  100. concurrence :over_if => '${f:ok} == yes' do
  101. #concurrence :over_if => '${f:ok} == yes', :merge_type => 'mix' do
  102. alpha
  103. bravo :if => 'false'
  104. end
  105. zulu :if => '${f:ok} == yes'
  106. end
  107. wfid = @dashboard.launch(pdef)
  108. r = @dashboard.wait_for(wfid)
  109. assert_equal 'terminated', r['action']
  110. assert_equal 'yes', r['workitem']['fields']['ok']
  111. assert_equal %w[ alpha zulu ], @tracer.to_a
  112. end
  113. def test_over_unless
  114. pdef = Ruote.process_definition do
  115. set 'f:ok' => 'true'
  116. concurrence :over_unless => '${f:ok}', :merge_type => :isolate do
  117. alpha
  118. alpha
  119. alpha
  120. end
  121. echo 'done.'
  122. end
  123. stash[:count] = 0
  124. alpha = @dashboard.register :alpha, 'do_not_thread' => true do |wi|
  125. if stash[:count] > 1
  126. wi.fields['ok'] = false
  127. else
  128. tracer << "a\n"
  129. stash[:count] += 1
  130. end
  131. end
  132. fields = nil
  133. @dashboard.register_participant :bravo do |workitem|
  134. fields = workitem.fields
  135. end
  136. assert_trace(%w[ a a done. ], pdef)
  137. end
  138. def test_remaining_forget_when_no_remains
  139. pdef = Ruote.process_definition do
  140. concurrence :remaining => :forget do
  141. echo 'a'
  142. echo 'b'
  143. end
  144. echo 'done.'
  145. end
  146. assert_trace %w[ a b done. ], %w[ b a done. ], pdef
  147. end
  148. # helper
  149. #
  150. def run_concurrence(concurrence_attributes)
  151. reverse_reply_order = concurrence_attributes.delete(:_reverse_reply_order)
  152. pdef = Ruote.define do
  153. concurrence(concurrence_attributes) do
  154. alpha
  155. alpha
  156. alpha
  157. end
  158. alpha
  159. end
  160. alpha = @dashboard.register_participant :alpha, Ruote::StorageParticipant
  161. wfid = @dashboard.launch(pdef)
  162. 3.times { wait_for('dispatched') }
  163. wis = @dashboard.storage_participant.to_a
  164. wis.reverse! if reverse_reply_order
  165. wis.each do |wi|
  166. wi.fields['seen'] = wi.fei.expid
  167. wi.fields[wi.fei.expid] = 'alpha'
  168. wi.fields['a'] = [ wi.fei.expid, 'x' ]
  169. wi.fields['h'] = { wi.fei.expid => 9 }
  170. alpha.proceed(wi)
  171. end
  172. wait_for(:alpha)
  173. wi = alpha.first
  174. ps = @dashboard.process(wi.fei.wfid)
  175. assert_equal %w[ 0 0_1 ], ps.expressions.collect { |e| e.fei.expid }.sort
  176. wi
  177. end
  178. #
  179. # merge tests
  180. def test_default_merge # first
  181. wi = run_concurrence({})
  182. assert_equal '0_0_0', wi.fields['seen']
  183. end
  184. def test_default_merge__reverse # first
  185. wi = run_concurrence(:_reverse_reply_order => true)
  186. assert_equal '0_0_2', wi.fields['seen']
  187. end
  188. def test_merge_last
  189. wi = run_concurrence(:merge => :last)
  190. assert_equal '0_0_2', wi.fields['seen']
  191. end
  192. def test_merge_last__reverse
  193. wi = run_concurrence(:merge => :last, :_reverse_reply_order => true)
  194. assert_equal '0_0_0', wi.fields['seen']
  195. end
  196. def test_merge_highest
  197. wi = run_concurrence(:merge => :highest)
  198. assert_equal '0_0_0', wi.fields['seen']
  199. end
  200. def test_merge_highest__reverse
  201. wi = run_concurrence(:merge => :highest, :_reverse_reply_order => true)
  202. assert_equal '0_0_0', wi.fields['seen']
  203. end
  204. def test_merge_lowest
  205. wi = run_concurrence(:merge => :lowest)
  206. assert_equal '0_0_2', wi.fields['seen']
  207. end
  208. def test_merge_lowest__reverse
  209. wi = run_concurrence(:merge => :lowest, :_reverse_reply_order => true)
  210. assert_equal '0_0_2', wi.fields['seen']
  211. end
  212. #
  213. # merge_type tests
  214. #def test_merge_type_override # already tested above
  215. #end
  216. def test_merge_type_mix
  217. wi = run_concurrence(:merge_type => :mix)
  218. assert_equal(
  219. %w[ 0_0_0 0_0_1 0_0_2 a dispatched_at h params seen ],
  220. wi.fields.keys.collect { |k| k.to_s }.sort)
  221. assert_equal('0_0_0', wi.fields['seen'])
  222. end
  223. def test_merge_type_isolate
  224. wi = run_concurrence(:merge_type => :isolate)
  225. assert_equal(
  226. %w[ 0 1 2 dispatched_at params ],
  227. wi.fields.keys.collect { |k| k.to_s }.sort)
  228. assert_equal({ 'ref' => 'alpha' }, wi.fields['params'])
  229. assert_equal(%w[ 0_0_0 a h seen ], wi.fields['0'].keys.sort)
  230. assert_equal(%w[ 0_0_1 a h seen ], wi.fields['1'].keys.sort)
  231. assert_equal(%w[ 0_0_2 a h seen ], wi.fields['2'].keys.sort)
  232. end
  233. def test_merge_type_stack
  234. wi = run_concurrence(:merge_type => :stack)
  235. assert_equal(
  236. %w[ dispatched_at params stack stack_attributes ],
  237. wi.fields.keys.collect { |k| k.to_s }.sort)
  238. assert_equal({ 'ref' => 'alpha' }, wi.fields['params'])
  239. assert_equal(%w[ 0_0_0 a h seen ], wi.fields['stack'][0].keys.sort)
  240. assert_equal(%w[ 0_0_1 a h seen ], wi.fields['stack'][1].keys.sort)
  241. assert_equal(%w[ 0_0_2 a h seen ], wi.fields['stack'][2].keys.sort)
  242. end
  243. def test_merge_type_union
  244. wi = run_concurrence(:merge_type => :union)
  245. assert_equal(
  246. %w[ 0_0_0 0_0_1 0_0_2 a dispatched_at h params seen ],
  247. wi.fields.keys.collect { |k| k.to_s }.sort)
  248. assert_equal('0_0_2', wi.fields['seen'])
  249. assert_equal(%w[ 0_0_0 x 0_0_1 0_0_2 ], wi.fields['a'])
  250. assert_equal(%w[ 0_0_0 0_0_1 0_0_2 ], wi.fields['h'].keys.sort)
  251. end
  252. def test_merge_type_concat
  253. wi = run_concurrence(:merge_type => :concat)
  254. assert_equal(
  255. %w[ 0_0_0 0_0_1 0_0_2 a dispatched_at h params seen ],
  256. wi.fields.keys.collect { |k| k.to_s }.sort)
  257. assert_equal('0_0_2', wi.fields['seen'])
  258. assert_equal(%w[ 0_0_0 x 0_0_1 x 0_0_2 x], wi.fields['a'])
  259. assert_equal(%w[ 0_0_0 0_0_1 0_0_2 ], wi.fields['h'].keys.sort)
  260. end
  261. # not deep enough though
  262. #
  263. def test_merge_type_deep
  264. wi = run_concurrence(:merge_type => :deep)
  265. assert_equal(
  266. %w[ 0_0_0 0_0_1 0_0_2 a dispatched_at h params seen ],
  267. wi.fields.keys.collect { |k| k.to_s }.sort)
  268. assert_equal('0_0_2', wi.fields['seen'])
  269. assert_equal(%w[ 0_0_0 x 0_0_1 x 0_0_2 x ], wi.fields['a'])
  270. assert_equal(%w[ 0_0_0 0_0_1 0_0_2 ], wi.fields['h'].keys.sort)
  271. end
  272. def test_merge_type_ignore
  273. wi = run_concurrence(:merge_type => :ignore)
  274. assert_equal(
  275. %w[ dispatched_at params ], wi.fields.keys.collect { |k| k.to_s }.sort)
  276. end
  277. #
  278. # count tests
  279. # helper
  280. #
  281. def run_test_count(remaining)
  282. pdef = Ruote.process_definition do
  283. concurrence :count => 1, :remaining => remaining do
  284. alpha
  285. bravo
  286. end
  287. end
  288. @dashboard.register_participant '.+', Ruote::StorageParticipant
  289. wfid = @dashboard.launch(pdef)
  290. wait_for(:alpha)
  291. @dashboard.storage_participant.proceed(@dashboard.storage_participant.first)
  292. wait_for(wfid)
  293. wfid
  294. end
  295. def test_count
  296. wfid = run_test_count('cancel')
  297. #puts
  298. #logger.log.each { |e| p e }
  299. #puts
  300. assert_equal 1, logger.log.select { |e| e['action'] == 'cancel' }.size
  301. sleep 0.350 # since now dispatch_cancel occurs asynchronously...
  302. assert_equal 0, @dashboard.storage_participant.size
  303. end
  304. def test_count_remaining_forget
  305. wfid = run_test_count('forget')
  306. #assert_equal 1, logger.log.select { |e| e['action'] == 'forget' }.size
  307. assert_equal 1, @dashboard.storage_participant.size
  308. assert_equal 'bravo', @dashboard.storage_participant.first.participant_name
  309. #@dashboard.context.storage.get_many('expressions').each { |e| p e['fei'] }
  310. #puts @dashboard.context.storage.dump('expressions')
  311. #p @dashboard.ps(wfid)
  312. assert_equal 2, @dashboard.context.storage.get_many('expressions').size
  313. assert_not_nil @dashboard.process(wfid)
  314. @dashboard.storage_participant.proceed(@dashboard.storage_participant.first)
  315. wait_for(wfid)
  316. @dashboard.context.storage.get_many('expressions').each { |e| p e['fei'] }
  317. assert_equal 0, @dashboard.context.storage.get_many('expressions').size
  318. end
  319. def test_count_negative
  320. pdef = Ruote.define do
  321. concurrence :mt => 'mix', :c => -1 do # all but 1
  322. set 'a' => 1
  323. set 'b' => 2
  324. set 'c' => 3
  325. end
  326. end
  327. wfid = @dashboard.launch(pdef)
  328. r = @dashboard.wait_for(wfid)
  329. assert_equal 1, r['workitem']['fields']['a']
  330. assert_equal 2, r['workitem']['fields']['b']
  331. assert_equal nil, r['workitem']['fields']['c']
  332. end
  333. def test_cancel
  334. pdef = Ruote.process_definition do
  335. concurrence do
  336. alpha
  337. alpha
  338. end
  339. end
  340. alpha = @dashboard.register_participant :alpha, Ruote::StorageParticipant
  341. wfid = @dashboard.launch(pdef)
  342. wait_for(:alpha)
  343. wait_for(:alpha)
  344. assert_equal 2, alpha.size
  345. @dashboard.cancel_process(wfid)
  346. wait_for(wfid)
  347. ps = @dashboard.process(wfid)
  348. assert_nil ps
  349. end
  350. #
  351. # 'wait_for' tests
  352. # 'wait_for => 1' is equivalent to 'count => 1'
  353. #
  354. def test_wait_for_int
  355. pdef = Ruote.define do
  356. concurrence :wait_for => 1 do
  357. sequence do
  358. stall
  359. echo 'alpha'
  360. end
  361. echo 'bravo'
  362. end
  363. echo 'over.'
  364. end
  365. wfid = @dashboard.launch(pdef)
  366. @dashboard.wait_for(wfid)
  367. assert_equal %w[ bravo over. ], @tracer.to_a
  368. end
  369. def test_wait_for_zero
  370. pdef = Ruote.define do
  371. concurrence :wait_for => 0, :remaining => :forget do
  372. sequence do
  373. wait '5s'
  374. echo 'alpha'
  375. end
  376. end
  377. echo 'over.'
  378. end
  379. wfid = @dashboard.launch(pdef)
  380. @dashboard.wait_for(wfid)
  381. assert_equal %w[ over. ], @tracer.to_a
  382. end
  383. def test_wait_for_tags
  384. pdef = Ruote.define do
  385. concurrence :wait_for => 'azuma, bashamichi', :merge_type => 'concat' do
  386. sequence :tag => 'azuma' do
  387. set 'seen' => [ 'azuma' ]
  388. end
  389. sequence :tag => 'bashamichi' do
  390. set 'seen' => [ 'bashamichi' ]
  391. end
  392. sequence :tag => 'katou' do
  393. set 'seen' => [ 'katou' ]
  394. end
  395. end
  396. end
  397. wfid = @dashboard.launch(pdef)
  398. r = @dashboard.wait_for(wfid)
  399. assert_equal %w[ azuma bashamichi ], r['workitem']['fields']['seen'].sort
  400. end
  401. def test_wait_for_tags_array
  402. pdef = Ruote.define do
  403. concurrence :wait_for => %w[ azuma bashamichi ], :mt => 'concat' do
  404. sequence :tag => 'azuma' do
  405. set 'seen' => [ 'azuma' ]
  406. end
  407. sequence :tag => 'bashamichi' do
  408. set 'seen' => [ 'bashamichi' ]
  409. end
  410. sequence :tag => 'katou' do
  411. set 'seen' => [ 'katou' ]
  412. wait '5s'
  413. end
  414. end
  415. end
  416. wfid = @dashboard.launch(pdef)
  417. r = @dashboard.wait_for(wfid)
  418. assert_equal %w[ azuma bashamichi ], r['workitem']['fields']['seen'].sort
  419. end
  420. def test_wait_for_one_tag
  421. @dashboard.register do
  422. administrator do |workitem|
  423. tracer << "administrator\n"
  424. sleep 0.7
  425. end
  426. evaluator Ruote::NullParticipant
  427. #evaluator Ruote::NoOpParticipant
  428. end
  429. pdef = Ruote.process_definition do
  430. concurrence :wait_for => 'first' do
  431. sequence :tag => 'first' do
  432. administrator
  433. end
  434. sequence :tag => 'second' do
  435. evaluator
  436. end
  437. end
  438. echo 'done.'
  439. end
  440. wfid = @dashboard.launch(pdef)
  441. r = @dashboard.wait_for(wfid)
  442. assert_equal 'terminated', r['action']
  443. assert_equal "administrator\ndone.", @tracer.to_s
  444. end
  445. def test_wait_for_unknown_tag
  446. pdef = Ruote.define do
  447. concurrence :wait_for => 'nada' do
  448. echo 'a'
  449. echo 'b'
  450. end
  451. echo 'c'
  452. end
  453. wfid = @dashboard.launch(pdef)
  454. r = @dashboard.wait_for(wfid)
  455. assert_equal 'ceased', r['action']
  456. assert_equal %w[ a b ], @tracer.to_a.sort
  457. end
  458. def test_remaining_wait
  459. pdef = Ruote.define do
  460. concurrence :count => 1, :rem => 'wait', :mt => 'mix' do
  461. set 'a' => true
  462. sequence do
  463. set 'b' => true
  464. stall
  465. end
  466. end
  467. end
  468. wfid = @dashboard.launch(pdef); r = @dashboard.wait_for(wfid)
  469. assert_equal(
  470. { 'a' => true, 'b' => true, '__result__' => true },
  471. r['workitem']['fields'])
  472. end
  473. end