bumbleworks 0.0.25 → 0.0.26

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,6 @@
1
1
  require "bumbleworks/tasks/base"
2
2
  require "bumbleworks/workitem_entity_storage"
3
+ require "bumbleworks/task/finder"
3
4
 
4
5
  module Bumbleworks
5
6
  class Task
@@ -8,6 +9,7 @@ module Bumbleworks
8
9
  class AlreadyClaimed < StandardError; end
9
10
  class MissingWorkitem < StandardError; end
10
11
  class NotCompletable < StandardError; end
12
+ class AvailabilityTimeout < StandardError; end
11
13
 
12
14
  extend Forwardable
13
15
  delegate [:sid, :fei, :fields, :params, :participant_name, :wfid, :wf_name] => :@workitem
@@ -29,24 +31,11 @@ module Bumbleworks
29
31
  end
30
32
  end
31
33
 
32
- def for_role(identifier)
33
- for_roles([identifier])
34
- end
35
-
36
- def for_roles(identifiers)
37
- return [] unless identifiers.is_a?(Array)
38
- workitems = identifiers.collect { |identifier|
39
- storage_participant.by_participant(identifier)
40
- }.flatten.uniq
41
- from_workitems(workitems)
42
- end
43
-
44
- def for_claimant(token)
45
- all.select { |t| t.claimant == token }
46
- end
47
-
48
- def all
49
- from_workitems(storage_participant.all)
34
+ def method_missing(method, *args)
35
+ if Finder.new.respond_to?(method)
36
+ return Finder.new.send(method, *args)
37
+ end
38
+ super
50
39
  end
51
40
 
52
41
  def find_by_id(sid)
@@ -60,12 +49,6 @@ module Bumbleworks
60
49
  def storage_participant
61
50
  Bumbleworks.dashboard.storage_participant
62
51
  end
63
-
64
- def from_workitems(workitems)
65
- workitems.map { |wi|
66
- new(wi) if wi.params['task']
67
- }.compact
68
- end
69
52
  end
70
53
 
71
54
  def initialize(workitem)
@@ -0,0 +1,75 @@
1
+ module Bumbleworks
2
+ class Task
3
+ class Finder
4
+ include Enumerable
5
+
6
+ def initialize(queries = [])
7
+ @queries = queries
8
+ end
9
+
10
+ def by_nickname(nickname)
11
+ @queries << proc { |wi| wi['fields']['params']['task'] == nickname }
12
+ self
13
+ end
14
+
15
+ def for_roles(identifiers)
16
+ identifiers ||= []
17
+ @queries << proc { |wi| identifiers.include?(wi['participant_name']) }
18
+ self
19
+ end
20
+
21
+ def for_role(identifier)
22
+ for_roles([identifier])
23
+ end
24
+
25
+ def for_claimant(token)
26
+ @queries << proc { |wi| wi['fields']['params']['claimant'] == token }
27
+ self
28
+ end
29
+
30
+ def for_entity(entity)
31
+ @queries << proc { |wi|
32
+ (wi['fields'][:entity_type] || wi['fields']['entity_type']) == entity.class.name &&
33
+ (wi['fields'][:entity_id] || wi['fields']['entity_id']) == entity.identifier
34
+ }
35
+ self
36
+ end
37
+
38
+ def all
39
+ workitems = Bumbleworks.dashboard.storage_participant.send(:do_select, {}) { |wi|
40
+ @queries.all? { |q| q.call(wi) }
41
+ }
42
+ from_workitems(workitems)
43
+ end
44
+
45
+ def each(&block)
46
+ all.each(&block)
47
+ end
48
+
49
+ def empty?
50
+ all.empty?
51
+ end
52
+
53
+ def next_available(options = {})
54
+ options[:timeout] ||= 5
55
+
56
+ start_time = Time.now
57
+ while first.nil?
58
+ if (Time.now - start_time) > options[:timeout]
59
+ raise Bumbleworks::Task::AvailabilityTimeout, "No tasks found matching criteria in time"
60
+ end
61
+ sleep 0.1
62
+ end
63
+ first
64
+ end
65
+
66
+ private
67
+
68
+ def from_workitems(workitems)
69
+ workitems.map { |wi|
70
+ Task.new(wi) if wi.params['task']
71
+ }.compact
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,3 +1,3 @@
1
1
  module Bumbleworks
2
- VERSION = "0.0.25"
2
+ VERSION = "0.0.26"
3
3
  end
@@ -5,8 +5,8 @@ module Bumbleworks
5
5
  def entity(options = {})
6
6
  @entity = nil if options[:reload] == true
7
7
  @entity ||= if has_entity_fields?
8
- klass = Bumbleworks::Support.constantize(workitem.fields['entity_type'])
9
- entity = klass.first_by_identifier(workitem.fields['entity_id'])
8
+ klass = Bumbleworks::Support.constantize(entity_type)
9
+ entity = klass.first_by_identifier(entity_id)
10
10
  end
11
11
  raise EntityNotFound unless @entity
12
12
  @entity
@@ -19,7 +19,17 @@ module Bumbleworks
19
19
  end
20
20
 
21
21
  def has_entity_fields?
22
- workitem.fields['entity_id'] && workitem.fields['entity_type']
22
+ entity_id && entity_type
23
+ end
24
+
25
+ private
26
+
27
+ def entity_id
28
+ workitem.fields[:entity_id] || workitem.fields['entity_id']
29
+ end
30
+
31
+ def entity_type
32
+ workitem.fields[:entity_type] || workitem.fields['entity_type']
23
33
  end
24
34
  end
25
35
  end
@@ -91,7 +91,7 @@ describe Bumbleworks::Task do
91
91
  it 'logs dispatch' do
92
92
  Bumbleworks.launch!('planting_a_noodle')
93
93
  Bumbleworks.dashboard.wait_for(:horse_feeder)
94
- task = described_class.for_role('horse_feeder').last
94
+ task = described_class.for_role('horse_feeder').first
95
95
  log_entry = Bumbleworks.logger.entries.last[:entry]
96
96
  log_entry[:action].should == :dispatch
97
97
  log_entry[:target_type].should == 'Task'
@@ -230,9 +230,22 @@ describe Bumbleworks::Task do
230
230
  end
231
231
 
232
232
  describe '.for_role' do
233
- it 'delegates to #for_roles with single-item array' do
234
- described_class.should_receive(:for_roles).with(['mister_mystery'])
235
- described_class.for_role('mister_mystery')
233
+ it 'returns all tasks for given role' do
234
+ Bumbleworks.define_process 'chalking' do
235
+ concurrence do
236
+ chalker :task => 'make_chalk_drawings'
237
+ hagrid :task => 'moan_endearingly'
238
+ chalker :task => 'chalk_it_good_baby'
239
+ end
240
+ end
241
+ Bumbleworks.launch!('chalking')
242
+ Bumbleworks.dashboard.wait_for(:chalker)
243
+
244
+ tasks = described_class.for_role('chalker')
245
+ tasks.map(&:nickname).should == [
246
+ 'make_chalk_drawings',
247
+ 'chalk_it_good_baby'
248
+ ]
236
249
  end
237
250
  end
238
251
 
@@ -325,6 +338,39 @@ describe Bumbleworks::Task do
325
338
  end
326
339
  end
327
340
 
341
+ context '.for_entity' do
342
+ it 'returns all tasks associated with given entity' do
343
+ fake_sandwich = OpenStruct.new(:identifier => 'rubies')
344
+ Bumbleworks.define_process 'existential_pb_and_j' do
345
+ concurrence do
346
+ sandwich :task => 'be_made'
347
+ sandwich :task => 'contemplate_being'
348
+ end
349
+ end
350
+ Bumbleworks.launch!('existential_pb_and_j', :entity => fake_sandwich)
351
+ Bumbleworks.dashboard.wait_for(:sandwich)
352
+ tasks = described_class.for_entity(fake_sandwich)
353
+ tasks.should have(2).items
354
+ end
355
+ end
356
+
357
+ context '.by_nickname' do
358
+ it 'returns all tasks with given nickname' do
359
+ Bumbleworks.define_process 'animal_disagreements' do
360
+ concurrence do
361
+ turtle :task => 'be_a_big_jerk'
362
+ goose :task => 'punch_turtle'
363
+ rabbit :task => 'punch_turtle'
364
+ end
365
+ end
366
+ Bumbleworks.launch!('animal_disagreements')
367
+ Bumbleworks.dashboard.wait_for(:rabbit)
368
+ tasks = described_class.by_nickname('punch_turtle')
369
+ tasks.should have(2).items
370
+ tasks.map(&:role).should =~ ['goose', 'rabbit']
371
+ end
372
+ end
373
+
328
374
  context 'claiming things' do
329
375
  before :each do
330
376
  Bumbleworks.define_process 'planting_a_noodle' do
@@ -337,7 +383,7 @@ describe Bumbleworks::Task do
337
383
  end
338
384
 
339
385
  describe '#claim' do
340
- it 'sets token on "claimant" param' do
386
+ it 'sets token on "claimant" param' do
341
387
  @task.params['claimant'].should == 'boss'
342
388
  end
343
389
 
@@ -515,4 +561,92 @@ describe Bumbleworks::Task do
515
561
  end
516
562
  end
517
563
  end
564
+
565
+ describe 'chained queries' do
566
+ it 'allows for AND-ed chained finders' do
567
+ Bumbleworks.define_process 'the_big_kachunko' do
568
+ concurrence do
569
+ red :task => 'be_really_mad'
570
+ blue :task => 'be_a_bit_sad'
571
+ yellow :task => 'be_scared'
572
+ green :task => 'be_envious'
573
+ green :task => 'be_proud'
574
+ pink :task => 'be_proud'
575
+ end
576
+ end
577
+ Bumbleworks.launch!('the_big_kachunko')
578
+ Bumbleworks.dashboard.wait_for(:pink)
579
+ described_class.by_nickname('be_really_mad').first.claim('crayon_box')
580
+ described_class.by_nickname('be_a_bit_sad').first.claim('crayon_box')
581
+ described_class.by_nickname('be_scared').first.claim('crayon_box')
582
+
583
+ tasks = described_class.
584
+ for_roles(['green', 'pink']).
585
+ by_nickname('be_proud')
586
+ tasks.should have(2).items
587
+ tasks.map(&:nickname).should =~ ['be_proud', 'be_proud']
588
+
589
+ tasks = described_class.
590
+ for_claimant('crayon_box').
591
+ for_roles(['red', 'yellow', 'green'])
592
+ tasks.should have(2).items
593
+ tasks.map(&:nickname).should =~ ['be_really_mad', 'be_scared']
594
+
595
+ tasks = described_class.
596
+ for_claimant('crayon_box').
597
+ by_nickname('be_a_bit_sad').
598
+ for_role('blue')
599
+ tasks.should have(1).item
600
+ tasks.first.nickname.should == 'be_a_bit_sad'
601
+ end
602
+ end
603
+
604
+ describe 'method missing' do
605
+ it 'calls method on new Finder object' do
606
+ described_class::Finder.any_instance.stub(:shabam!).with(:yay).and_return(:its_a_me)
607
+ described_class.shabam!(:yay).should == :its_a_me
608
+ end
609
+
610
+ it 'falls back to method missing if no finder method' do
611
+ expect {
612
+ described_class.kerplunk!(:oh_no)
613
+ }.to raise_error
614
+ end
615
+ end
616
+
617
+ describe '.next_available' do
618
+ it 'waits for one task to show up and returns it' do
619
+ Bumbleworks.define_process "lazy_bum_and_cool_guy" do
620
+ concurrence do
621
+ cool_guy :task => 'get_it_going_man'
622
+ sequence do
623
+ wait '2s'
624
+ bum :task => 'finally_get_a_round_tuit'
625
+ end
626
+ end
627
+ end
628
+ start_time = Time.now
629
+ Bumbleworks.launch!('lazy_bum_and_cool_guy')
630
+ task = described_class.for_role('bum').next_available
631
+ end_time = Time.now
632
+ task.nickname.should == 'finally_get_a_round_tuit'
633
+ (end_time - start_time).should >= 2
634
+ end
635
+
636
+ it 'times out if task does not appear in time' do
637
+ Bumbleworks.define_process "really_lazy_bum_and_cool_guy" do
638
+ concurrence do
639
+ cool_guy :task => 'good_golly_never_mind_you'
640
+ sequence do
641
+ wait '2s'
642
+ bum :task => 'whatever_these_socks_are_tasty'
643
+ end
644
+ end
645
+ end
646
+ Bumbleworks.launch!('really_lazy_bum_and_cool_guy')
647
+ expect {
648
+ described_class.for_role('bum').next_available(:timeout => 0.5)
649
+ }.to raise_error(Bumbleworks::Task::AvailabilityTimeout)
650
+ end
651
+ end
518
652
  end
@@ -18,6 +18,11 @@ describe Bumbleworks::WorkitemEntityStorage do
18
18
  feh.should have_entity_fields
19
19
  end
20
20
 
21
+ it 'returns true if workitem fields include symbolized version of entity fields' do
22
+ feh = FakeEntityHolder.new(:entity_id => '1', :entity_type => 'SomeEntity')
23
+ feh.should have_entity_fields
24
+ end
25
+
21
26
  it 'returns false if workitem fields do not include entity fields' do
22
27
  feh = FakeEntityHolder.new
23
28
  feh.should_not have_entity_fields
@@ -62,6 +67,11 @@ describe Bumbleworks::WorkitemEntityStorage do
62
67
  feh.entity.identifier.should == '15'
63
68
  end
64
69
 
70
+ it 'works with symbolized _id and _type fields' do
71
+ feh = FakeEntityHolder.new(:entity_id => '15', :entity_type => 'LovelyEntity')
72
+ feh.entity.identifier.should == '15'
73
+ end
74
+
65
75
  it 'throw exception if entity fields not present' do
66
76
  feh = FakeEntityHolder.new
67
77
  expect {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bumbleworks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.25
4
+ version: 0.0.26
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -178,6 +178,7 @@ files:
178
178
  - lib/bumbleworks/storage_participant.rb
179
179
  - lib/bumbleworks/support.rb
180
180
  - lib/bumbleworks/task.rb
181
+ - lib/bumbleworks/task/finder.rb
181
182
  - lib/bumbleworks/tasks/base.rb
182
183
  - lib/bumbleworks/tree_builder.rb
183
184
  - lib/bumbleworks/version.rb
@@ -227,18 +228,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
227
228
  - - ! '>='
228
229
  - !ruby/object:Gem::Version
229
230
  version: '0'
230
- segments:
231
- - 0
232
- hash: -2155630126504321546
233
231
  required_rubygems_version: !ruby/object:Gem::Requirement
234
232
  none: false
235
233
  requirements:
236
234
  - - ! '>='
237
235
  - !ruby/object:Gem::Version
238
236
  version: '0'
239
- segments:
240
- - 0
241
- hash: -2155630126504321546
242
237
  requirements: []
243
238
  rubyforge_project:
244
239
  rubygems_version: 1.8.23
@@ -277,3 +272,4 @@ test_files:
277
272
  - spec/lib/bumbleworks_spec.rb
278
273
  - spec/spec_helper.rb
279
274
  - spec/support/path_helpers.rb
275
+ has_rdoc: