seam-mongodb 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in seam-mongodb.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Darren Cauthon
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Seam::Mongodb
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'seam-mongodb'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install seam-mongodb
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,52 @@
1
+ require 'seam'
2
+ require "seam/mongodb/version"
3
+ require 'moped'
4
+
5
+ module Seam
6
+ module Mongodb
7
+
8
+ def self.collection
9
+ @collection
10
+ end
11
+
12
+ def self.set_collection collection
13
+ @collection = collection
14
+ overwrite_the_persistence_layer
15
+ end
16
+
17
+ def self.overwrite_the_persistence_layer
18
+ Seam::Persistence.class_eval do
19
+ def self.find_by_effort_id effort_id
20
+ document = Seam::Mongodb.collection.find( { id: effort_id } ).first
21
+ return nil unless document
22
+ Seam::Effort.parse document
23
+ end
24
+
25
+ def self.find_all_pending_executions_by_step step
26
+ Seam::Mongodb.collection
27
+ .find( { next_step: step, next_execute_at: { '$lte' => Time.now } } )
28
+ .map { |x| Seam::Effort.parse x }
29
+ end
30
+
31
+ def self.save effort
32
+ Seam::Mongodb.collection
33
+ .find( { id: effort.id } )
34
+ .update("$set" => effort.to_hash)
35
+ end
36
+
37
+ def self.create effort
38
+ Seam::Mongodb.collection.insert(effort.to_hash)
39
+ end
40
+
41
+ def self.all
42
+ Seam::Mongodb.collection.find.to_a
43
+ end
44
+
45
+ def self.destroy
46
+ Seam::Mongodb.collection.drop
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+
@@ -0,0 +1,5 @@
1
+ module Seam
2
+ module Mongodb
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'seam/mongodb/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "seam-mongodb"
8
+ spec.version = Seam::Mongodb::VERSION
9
+ spec.authors = ["Darren Cauthon"]
10
+ spec.email = ["darren@cauthon.com"]
11
+ spec.description = %q{MongoDB support for seam}
12
+ spec.summary = %q{MongoDB support for seam}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "json"
22
+ spec.add_runtime_dependency "activesupport", "~> 3.2"
23
+ spec.add_runtime_dependency "i18n"
24
+ spec.add_runtime_dependency "moped"
25
+ spec.add_runtime_dependency "json"
26
+ spec.add_runtime_dependency "seam"
27
+ spec.add_development_dependency "bundler", "~> 1.3"
28
+ spec.add_development_dependency "rake"
29
+ spec.add_development_dependency "subtle"
30
+ spec.add_development_dependency "contrast"
31
+ spec.add_development_dependency "mocha"
32
+ spec.add_development_dependency "contrast"
33
+ spec.add_development_dependency "timecop"
34
+
35
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Seam::Effort do
4
+ before do
5
+ Seam::Persistence.destroy
6
+ end
7
+
8
+ let(:flow) do
9
+ f = Seam::Flow.new
10
+ f.step1
11
+ f.step2
12
+ f
13
+ end
14
+
15
+ describe "updating an effort" do
16
+ it "should not create another document in the collection" do
17
+ first_effort = flow.start
18
+ Seam::Persistence.all.count.must_equal 1
19
+ first_effort.save
20
+ Seam::Persistence.all.count.must_equal 1
21
+
22
+ second_effort = flow.start
23
+ Seam::Persistence.all.count.must_equal 2
24
+ second_effort.save
25
+ Seam::Persistence.all.count.must_equal 2
26
+ end
27
+
28
+ it "should update the information" do
29
+ first_effort = flow.start
30
+ second_effort = flow.start
31
+
32
+ first_effort.next_step = 'i_changed_the_first_one'
33
+ first_effort.save
34
+ first_effort.to_hash.contrast_with! Seam::Effort.find(first_effort.id).to_hash, [:id, :created_at]
35
+ second_effort.to_hash.contrast_with! Seam::Effort.find(second_effort.id).to_hash, [:id, :created_at]
36
+
37
+ second_effort.next_step = 'i_changed_the_second_one'
38
+ second_effort.save
39
+ first_effort.to_hash.contrast_with! Seam::Effort.find(first_effort.id).to_hash, [:id, :created_at]
40
+ second_effort.to_hash.contrast_with! Seam::Effort.find(second_effort.id).to_hash, [:id, :created_at]
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,97 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "flow" do
4
+ before do
5
+ Seam::Persistence.destroy
6
+ end
7
+
8
+ after do
9
+ Timecop.return
10
+ end
11
+
12
+ describe "a useful example" do
13
+ let(:flow) do
14
+ f = Seam::Flow.new
15
+ f.wait_for_attempting_contact_stage limit: 2.weeks
16
+ f.determine_if_postcard_should_be_sent
17
+ f.send_postcard_if_necessary
18
+ f
19
+ end
20
+
21
+ describe "steps that must be taken" do
22
+ before do
23
+ flow
24
+ end
25
+
26
+ it "should not throw an error" do
27
+ flow.steps.count.must_equal 3
28
+ end
29
+
30
+ it "should set the name of the three steps" do
31
+ flow.steps[0].name.must_equal "wait_for_attempting_contact_stage"
32
+ flow.steps[1].name.must_equal "determine_if_postcard_should_be_sent"
33
+ flow.steps[2].name.must_equal "send_postcard_if_necessary"
34
+ end
35
+
36
+ it "should set the step types of the three steps" do
37
+ flow.steps[0].type.must_equal "do"
38
+ flow.steps[1].type.must_equal "do"
39
+ flow.steps[2].type.must_equal "do"
40
+ end
41
+
42
+ it "should set the arguments as well" do
43
+ flow.steps[0].arguments.must_equal [{ limit: 14.days.to_i }]
44
+ flow.steps[1].arguments.must_equal []
45
+ flow.steps[2].arguments.must_equal []
46
+ end
47
+ end
48
+ end
49
+
50
+ describe "a more useful example" do
51
+
52
+ describe "starting an effort" do
53
+ let(:flow) do
54
+ flow = Seam::Flow.new
55
+ flow.do_something
56
+ flow.do_something_else
57
+ flow
58
+ end
59
+
60
+ let(:now) { Time.parse('1/1/2011') }
61
+
62
+ before do
63
+ Timecop.freeze now
64
+
65
+ @expected_uuid = SecureRandom.uuid.to_s
66
+ SecureRandom.expects(:uuid).returns @expected_uuid
67
+
68
+ @effort = flow.start( { first_name: 'John' } )
69
+ end
70
+
71
+ it "should mark no steps as completed" do
72
+ @effort.completed_steps.count.must_equal 0
73
+ end
74
+
75
+ it "should stamp the effort with a uuid" do
76
+ @effort.id.must_equal @expected_uuid
77
+ end
78
+
79
+ it "should stamp the create date" do
80
+ @effort.created_at.must_equal now
81
+ end
82
+
83
+ it "should stamp the next execute date" do
84
+ @effort.next_execute_at.must_equal now
85
+ end
86
+
87
+ it "should stamp the next step name" do
88
+ @effort.next_step.must_equal "do_something"
89
+ end
90
+
91
+ it "should save an effort in the db" do
92
+ effort = Seam::Effort.find @effort.id
93
+ effort.to_hash.contrast_with! @effort.to_hash, [:id, :created_at]
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,584 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "worker" do
4
+
5
+ before do
6
+ Seam::Persistence.destroy
7
+ end
8
+
9
+ after do
10
+ Timecop.return
11
+ end
12
+
13
+ describe "move_to_next_step" do
14
+ it "should work" do
15
+ flow = Seam::Flow.new
16
+ flow.apple
17
+ flow.orange
18
+
19
+ effort = flow.start( { first_name: 'John' } )
20
+ effort = Seam::Effort.find(effort.id)
21
+
22
+ effort.next_step.must_equal "apple"
23
+
24
+ apple_worker = Seam::Worker.new
25
+ apple_worker.handles(:apple)
26
+ def apple_worker.process
27
+ move_to_next_step
28
+ end
29
+
30
+ apple_worker.execute effort
31
+
32
+ effort = Seam::Effort.find(effort.id)
33
+ effort.next_step.must_equal "orange"
34
+ end
35
+ end
36
+
37
+ describe "try_again_in" do
38
+
39
+ let(:effort) do
40
+ flow = Seam::Flow.new
41
+ flow.apple
42
+ flow.orange
43
+
44
+ e = flow.start( { first_name: 'John' } )
45
+ Seam::Effort.find(e.id)
46
+ end
47
+
48
+ before do
49
+ Timecop.freeze Time.parse('3/4/2013')
50
+ effort.next_step.must_equal "apple"
51
+
52
+ apple_worker = Seam::Worker.new
53
+ apple_worker.handles(:apple)
54
+ def apple_worker.process
55
+ try_again_in 1.day
56
+ end
57
+
58
+ apple_worker.execute effort
59
+ end
60
+
61
+ it "should not update the next step" do
62
+ fresh_effort = Seam::Effort.find(effort.id)
63
+ fresh_effort.next_step.must_equal "apple"
64
+ end
65
+
66
+ it "should not update the next execute date" do
67
+ fresh_effort = Seam::Effort.find(effort.id)
68
+ fresh_effort.next_execute_at.must_equal Time.parse('4/4/2013')
69
+ end
70
+ end
71
+
72
+ describe "more copmlex example" do
73
+
74
+ let(:effort1) do
75
+ flow = Seam::Flow.new
76
+ flow.grape
77
+ flow.mango
78
+
79
+ e = flow.start( { status: 'Good' } )
80
+ Seam::Effort.find(e.id)
81
+ end
82
+
83
+ let(:effort2) do
84
+ flow = Seam::Flow.new
85
+ flow.grape
86
+ flow.mango
87
+
88
+ e = flow.start( { status: 'Bad' } )
89
+ Seam::Effort.find(e.id)
90
+ end
91
+
92
+ before do
93
+ Timecop.freeze Time.parse('1/6/2013')
94
+
95
+ apple_worker = Seam::Worker.new
96
+ apple_worker.handles(:apple)
97
+ def apple_worker.process
98
+ if @current_effort.data[:status] == 'Good'
99
+ move_to_next_step
100
+ else
101
+ try_again_in 1.day
102
+ end
103
+ end
104
+
105
+ apple_worker.execute effort1
106
+ apple_worker.execute effort2
107
+ end
108
+
109
+ it "should move the first effort forward" do
110
+ fresh_effort = Seam::Effort.find(effort1.id)
111
+ fresh_effort.next_step.must_equal "mango"
112
+ end
113
+
114
+ it "should keep the second effort at the same step" do
115
+ fresh_effort = Seam::Effort.find(effort2.id)
116
+ fresh_effort.next_step.must_equal "grape"
117
+ fresh_effort.next_execute_at.must_equal Time.parse('2/6/2013')
118
+ end
119
+ end
120
+
121
+ describe "processing all pending steps for one effort" do
122
+ let(:effort1_creator) do
123
+ ->() do
124
+ flow = Seam::Flow.new
125
+ flow.banana
126
+ flow.mango
127
+
128
+ e = flow.start
129
+ Seam::Effort.find(e.id)
130
+ end
131
+ end
132
+
133
+ let(:effort2_creator) do
134
+ ->() do
135
+ flow = Seam::Flow.new
136
+ flow.apple
137
+ flow.orange
138
+
139
+ e = flow.start
140
+ Seam::Effort.find(e.id)
141
+ end
142
+ end
143
+
144
+ let(:apple_worker) do
145
+ apple_worker = Seam::Worker.new
146
+ apple_worker.handles(:apple)
147
+
148
+ apple_worker.class_eval do
149
+ attr_accessor :count
150
+ end
151
+
152
+ def apple_worker.process
153
+ self.count += 1
154
+ end
155
+
156
+ apple_worker.count = 0
157
+ apple_worker
158
+ end
159
+
160
+ before do
161
+ Timecop.freeze Time.parse('1/6/2013')
162
+
163
+ effort1_creator.call
164
+ effort1_creator.call
165
+ effort1_creator.call
166
+ effort2_creator.call
167
+ effort2_creator.call
168
+
169
+ apple_worker.execute_all
170
+ end
171
+
172
+ it "should call the apple worker for the record in question" do
173
+ apple_worker.count.must_equal 2
174
+ end
175
+ end
176
+
177
+ describe "a more realistic example" do
178
+
179
+ let(:flow) do
180
+ flow = Seam::Flow.new
181
+ flow.wait_for_attempting_contact_stage
182
+ flow.determine_if_postcard_should_be_sent
183
+ flow.send_postcard_if_necessary
184
+ flow
185
+ end
186
+
187
+ let(:effort_creator) do
188
+ ->() do
189
+ e = flow.start
190
+ Seam::Effort.find(e.id)
191
+ end
192
+ end
193
+
194
+ let(:wait_for_attempting_contact_stage_worker) do
195
+ worker = Seam::Worker.new
196
+ worker.handles(:wait_for_attempting_contact_stage)
197
+
198
+ def worker.process
199
+ @current_effort.data['hit 1'] ||= 0
200
+ @current_effort.data['hit 1'] += 1
201
+ move_to_next_step
202
+ end
203
+
204
+ worker
205
+ end
206
+
207
+ let(:determine_if_postcard_should_be_sent_worker) do
208
+ worker = Seam::Worker.new
209
+ worker.handles(:determine_if_postcard_should_be_sent)
210
+
211
+ def worker.process
212
+ @current_effort.data['hit 2'] ||= 0
213
+ @current_effort.data['hit 2'] += 1
214
+ move_to_next_step
215
+ end
216
+
217
+ worker
218
+ end
219
+
220
+ let(:send_postcard_if_necessary_worker) do
221
+ worker = Seam::Worker.new
222
+ worker.handles(:send_postcard_if_necessary)
223
+
224
+ def worker.process
225
+ @current_effort.data['hit 3'] ||= 0
226
+ @current_effort.data['hit 3'] += 1
227
+ move_to_next_step
228
+ end
229
+
230
+ worker
231
+ end
232
+
233
+ before do
234
+ Timecop.freeze Time.parse('1/6/2013')
235
+ end
236
+
237
+ it "should progress through the story" do
238
+
239
+ # SETUP
240
+ effort = effort_creator.call
241
+ effort.next_step.must_equal "wait_for_attempting_contact_stage"
242
+
243
+ # FIRST WAVE
244
+ send_postcard_if_necessary_worker.execute_all
245
+ determine_if_postcard_should_be_sent_worker.execute_all
246
+ wait_for_attempting_contact_stage_worker.execute_all
247
+
248
+ effort = Seam::Effort.find effort.id
249
+ effort.next_step.must_equal "determine_if_postcard_should_be_sent"
250
+
251
+ effort.complete?.must_equal false
252
+
253
+ # SECOND WAVE
254
+ send_postcard_if_necessary_worker.execute_all
255
+ determine_if_postcard_should_be_sent_worker.execute_all
256
+ wait_for_attempting_contact_stage_worker.execute_all
257
+
258
+ effort = Seam::Effort.find effort.id
259
+ effort.next_step.must_equal "send_postcard_if_necessary"
260
+
261
+ # THIRD WAVE
262
+ send_postcard_if_necessary_worker.execute_all
263
+ determine_if_postcard_should_be_sent_worker.execute_all
264
+ wait_for_attempting_contact_stage_worker.execute_all
265
+
266
+ effort = Seam::Effort.find effort.id
267
+ effort.next_step.must_equal nil
268
+
269
+ effort.data['hit 1'].must_equal 1
270
+ effort.data['hit 2'].must_equal 1
271
+ effort.data['hit 3'].must_equal 1
272
+
273
+ effort.complete?.must_equal true
274
+ #effort.completed_at.must_equal Time.now
275
+
276
+ # FUTURE WAVES
277
+ send_postcard_if_necessary_worker.execute_all
278
+ determine_if_postcard_should_be_sent_worker.execute_all
279
+ wait_for_attempting_contact_stage_worker.execute_all
280
+ send_postcard_if_necessary_worker.execute_all
281
+ determine_if_postcard_should_be_sent_worker.execute_all
282
+ wait_for_attempting_contact_stage_worker.execute_all
283
+ send_postcard_if_necessary_worker.execute_all
284
+ determine_if_postcard_should_be_sent_worker.execute_all
285
+ wait_for_attempting_contact_stage_worker.execute_all
286
+
287
+ effort = Seam::Effort.find effort.id
288
+ effort.next_step.must_equal nil
289
+
290
+ effort.data['hit 1'].must_equal 1
291
+ effort.data['hit 2'].must_equal 1
292
+ effort.data['hit 3'].must_equal 1
293
+
294
+ end
295
+ end
296
+
297
+ describe "a more realistic example with waiting" do
298
+
299
+ let(:flow) do
300
+ flow = Seam::Flow.new
301
+ flow.wait_for_attempting_contact_stage
302
+ flow.determine_if_postcard_should_be_sent
303
+ flow.send_postcard_if_necessary
304
+ flow
305
+ end
306
+
307
+ let(:effort_creator) do
308
+ ->() do
309
+ e = flow.start
310
+ Seam::Effort.find(e.id)
311
+ end
312
+ end
313
+
314
+ let(:wait_for_attempting_contact_stage_worker) do
315
+ worker = Seam::Worker.new
316
+ worker.handles(:wait_for_attempting_contact_stage)
317
+
318
+ def worker.process
319
+ @current_effort.data['hit 1'] ||= 0
320
+ @current_effort.data['hit 1'] += 1
321
+ if Time.now >= Time.parse('28/12/2013')
322
+ move_to_next_step
323
+ else
324
+ try_again_in 1.day
325
+ end
326
+ end
327
+
328
+ worker
329
+ end
330
+
331
+ let(:determine_if_postcard_should_be_sent_worker) do
332
+ worker = Seam::Worker.new
333
+ worker.handles(:determine_if_postcard_should_be_sent)
334
+
335
+ def worker.process
336
+ @current_effort.data['hit 2'] ||= 0
337
+ @current_effort.data['hit 2'] += 1
338
+ move_to_next_step
339
+ end
340
+
341
+ worker
342
+ end
343
+
344
+ let(:send_postcard_if_necessary_worker) do
345
+ worker = Seam::Worker.new
346
+ worker.handles(:send_postcard_if_necessary)
347
+
348
+ def worker.process
349
+ @current_effort.data['hit 3'] ||= 0
350
+ @current_effort.data['hit 3'] += 1
351
+ move_to_next_step
352
+ end
353
+
354
+ worker
355
+ end
356
+
357
+ before do
358
+ Timecop.freeze Time.parse('25/12/2013')
359
+ end
360
+
361
+ it "should progress through the story" do
362
+
363
+ # SETUP
364
+ effort = effort_creator.call
365
+ effort.next_step.must_equal "wait_for_attempting_contact_stage"
366
+
367
+ # FIRST DAY
368
+ send_postcard_if_necessary_worker.execute_all
369
+ determine_if_postcard_should_be_sent_worker.execute_all
370
+ wait_for_attempting_contact_stage_worker.execute_all
371
+
372
+ effort = Seam::Effort.find effort.id
373
+ effort.next_step.must_equal "wait_for_attempting_contact_stage"
374
+
375
+ send_postcard_if_necessary_worker.execute_all
376
+ determine_if_postcard_should_be_sent_worker.execute_all
377
+ wait_for_attempting_contact_stage_worker.execute_all
378
+ send_postcard_if_necessary_worker.execute_all
379
+ determine_if_postcard_should_be_sent_worker.execute_all
380
+ wait_for_attempting_contact_stage_worker.execute_all
381
+
382
+ effort = Seam::Effort.find effort.id
383
+ effort.next_step.must_equal "wait_for_attempting_contact_stage"
384
+
385
+ Timecop.freeze Time.parse('29/12/2013')
386
+
387
+ send_postcard_if_necessary_worker.execute_all
388
+ determine_if_postcard_should_be_sent_worker.execute_all
389
+ wait_for_attempting_contact_stage_worker.execute_all
390
+
391
+ effort = Seam::Effort.find effort.id
392
+ effort.next_step.must_equal "determine_if_postcard_should_be_sent"
393
+ effort.data['hit 1'].must_equal 2
394
+ end
395
+ end
396
+
397
+ describe "tracking history" do
398
+
399
+ let(:flow) do
400
+ flow = Seam::Flow.new
401
+ flow.wait_for_attempting_contact_stage
402
+ flow.determine_if_postcard_should_be_sent
403
+ flow.send_postcard_if_necessary
404
+ flow
405
+ end
406
+
407
+ let(:effort_creator) do
408
+ ->(values = {}) do
409
+ e = flow.start values
410
+ Seam::Effort.find(e.id)
411
+ end
412
+ end
413
+
414
+ let(:wait_for_attempting_contact_stage_worker) do
415
+ worker = Seam::Worker.new
416
+ worker.handles(:wait_for_attempting_contact_stage)
417
+
418
+ def worker.process
419
+ @current_effort.data['hit 1'] ||= 0
420
+ @current_effort.data['hit 1'] += 1
421
+ if Time.now >= Time.parse('28/12/2013')
422
+ move_to_next_step
423
+ else
424
+ try_again_in 1.day
425
+ end
426
+ end
427
+
428
+ worker
429
+ end
430
+
431
+ let(:determine_if_postcard_should_be_sent_worker) do
432
+ worker = Seam::Worker.new
433
+ worker.handles(:determine_if_postcard_should_be_sent)
434
+
435
+ def worker.process
436
+ @current_effort.data['hit 2'] ||= 0
437
+ @current_effort.data['hit 2'] += 1
438
+ move_to_next_step
439
+ end
440
+
441
+ worker
442
+ end
443
+
444
+ let(:send_postcard_if_necessary_worker) do
445
+ worker = Seam::Worker.new
446
+ worker.handles(:send_postcard_if_necessary)
447
+
448
+ def worker.process
449
+ @current_effort.data['hit 3'] ||= 0
450
+ @current_effort.data['hit 3'] += 1
451
+ move_to_next_step
452
+ end
453
+
454
+ worker
455
+ end
456
+
457
+ before do
458
+ Timecop.freeze Time.parse('26/12/2013')
459
+ end
460
+
461
+ it "should progress through the story" do
462
+
463
+ # SETUP
464
+ effort = effort_creator.call({ first_name: 'DARREN' })
465
+ effort.next_step.must_equal "wait_for_attempting_contact_stage"
466
+
467
+ # FIRST DAY
468
+ send_postcard_if_necessary_worker.execute_all
469
+ determine_if_postcard_should_be_sent_worker.execute_all
470
+ wait_for_attempting_contact_stage_worker.execute_all
471
+
472
+ effort = Seam::Effort.find effort.id
473
+ effort.next_step.must_equal "wait_for_attempting_contact_stage"
474
+
475
+ effort.history.count.must_equal 1
476
+ effort.history[0].contrast_with!( {
477
+ "started_at"=> Time.now,
478
+ "step"=>"wait_for_attempting_contact_stage",
479
+ "stopped_at" => Time.now,
480
+ "data_before" => { "first_name" => "DARREN" } ,
481
+ "data_after" => { "first_name" => "DARREN", "hit 1" => 1 }
482
+ } )
483
+
484
+ send_postcard_if_necessary_worker.execute_all
485
+ determine_if_postcard_should_be_sent_worker.execute_all
486
+ wait_for_attempting_contact_stage_worker.execute_all
487
+ send_postcard_if_necessary_worker.execute_all
488
+ determine_if_postcard_should_be_sent_worker.execute_all
489
+ wait_for_attempting_contact_stage_worker.execute_all
490
+
491
+ effort = Seam::Effort.find effort.id
492
+ effort.next_step.must_equal "wait_for_attempting_contact_stage"
493
+
494
+ effort.history.count.must_equal 1
495
+ effort.history[0].contrast_with!({"started_at"=> Time.now, "step"=>"wait_for_attempting_contact_stage", "stopped_at" => Time.now, "result" => "try_again_in", "try_again_on" => Time.now + 1.day } )
496
+
497
+ # THE NEXT DAY
498
+ Timecop.freeze Time.parse('27/12/2013')
499
+
500
+ send_postcard_if_necessary_worker.execute_all
501
+ determine_if_postcard_should_be_sent_worker.execute_all
502
+ wait_for_attempting_contact_stage_worker.execute_all
503
+
504
+ effort = Seam::Effort.find effort.id
505
+ effort.next_step.must_equal "wait_for_attempting_contact_stage"
506
+
507
+ effort.history.count.must_equal 2
508
+ effort.history[1].contrast_with!({"started_at"=> Time.now, "step"=>"wait_for_attempting_contact_stage", "stopped_at" => Time.now, "result" => "try_again_in" } )
509
+
510
+ # THE NEXT DAY
511
+ Timecop.freeze Time.parse('28/12/2013')
512
+
513
+ send_postcard_if_necessary_worker.execute_all
514
+ determine_if_postcard_should_be_sent_worker.execute_all
515
+ wait_for_attempting_contact_stage_worker.execute_all
516
+
517
+ effort = Seam::Effort.find effort.id
518
+ effort.next_step.must_equal "determine_if_postcard_should_be_sent"
519
+
520
+ effort.history.count.must_equal 3
521
+ effort.history[2].contrast_with!({"started_at"=> Time.now, "step"=>"wait_for_attempting_contact_stage", "stopped_at" => Time.now, "result" => "move_to_next_step" } )
522
+
523
+ # KEEP GOING
524
+ send_postcard_if_necessary_worker.execute_all
525
+ determine_if_postcard_should_be_sent_worker.execute_all
526
+ wait_for_attempting_contact_stage_worker.execute_all
527
+ effort = Seam::Effort.find effort.id
528
+ effort.next_step.must_equal "send_postcard_if_necessary"
529
+
530
+ effort.history.count.must_equal 4
531
+ effort.history[3].contrast_with!({"started_at"=> Time.now, "step"=>"determine_if_postcard_should_be_sent", "stopped_at" => Time.now, "result" => "move_to_next_step" } )
532
+
533
+ # KEEP GOING
534
+ send_postcard_if_necessary_worker.execute_all
535
+ determine_if_postcard_should_be_sent_worker.execute_all
536
+ wait_for_attempting_contact_stage_worker.execute_all
537
+ effort = Seam::Effort.find effort.id
538
+ effort.next_step.must_equal nil
539
+
540
+ effort.history.count.must_equal 5
541
+ effort.history[4].contrast_with!({"started_at"=> Time.now, "step"=>"send_postcard_if_necessary", "stopped_at" => Time.now, "result" => "move_to_next_step" } )
542
+ end
543
+ end
544
+
545
+ describe "eject" do
546
+
547
+ let(:effort) do
548
+ flow = Seam::Flow.new
549
+ flow.apple
550
+ flow.orange
551
+
552
+ e = flow.start( { first_name: 'John' } )
553
+ Seam::Effort.find(e.id)
554
+ end
555
+
556
+ before do
557
+ Timecop.freeze Time.parse('5/11/2013')
558
+ effort.next_step.must_equal "apple"
559
+
560
+ apple_worker = Seam::Worker.new
561
+ apple_worker.handles(:apple)
562
+ def apple_worker.process
563
+ eject
564
+ end
565
+
566
+ apple_worker.execute effort
567
+ end
568
+
569
+ it "should mark the step as completed" do
570
+ fresh_effort = Seam::Effort.find(effort.id)
571
+ fresh_effort.complete?.must_equal true
572
+ end
573
+
574
+ it "should mark the next step to nil" do
575
+ fresh_effort = Seam::Effort.find(effort.id)
576
+ fresh_effort.next_step.nil?.must_equal true
577
+ end
578
+
579
+ it "should mark the history" do
580
+ effort.history[0].contrast_with!({"step"=>"apple", "result" => "eject" } )
581
+ end
582
+
583
+ end
584
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/seam/mongodb')
2
+ require 'minitest/autorun'
3
+ require 'minitest/spec'
4
+ require 'minitest/pride'
5
+ require 'subtle'
6
+ require 'timecop'
7
+ require 'contrast'
8
+ require 'mocha/setup'
9
+
10
+ def test_moped_session
11
+ session = Moped::Session.new([ "127.0.0.1:27017" ])
12
+ session.use "seam_test"
13
+ end
14
+
15
+ Seam::Mongodb.set_collection test_moped_session['test_efforts']
metadata ADDED
@@ -0,0 +1,276 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seam-mongodb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Darren Cauthon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '3.2'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '3.2'
46
+ - !ruby/object:Gem::Dependency
47
+ name: i18n
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: moped
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: json
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: seam
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: bundler
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: '1.3'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: '1.3'
126
+ - !ruby/object:Gem::Dependency
127
+ name: rake
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: subtle
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: contrast
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ - !ruby/object:Gem::Dependency
175
+ name: mocha
176
+ requirement: !ruby/object:Gem::Requirement
177
+ none: false
178
+ requirements:
179
+ - - ! '>='
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ type: :development
183
+ prerelease: false
184
+ version_requirements: !ruby/object:Gem::Requirement
185
+ none: false
186
+ requirements:
187
+ - - ! '>='
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ - !ruby/object:Gem::Dependency
191
+ name: contrast
192
+ requirement: !ruby/object:Gem::Requirement
193
+ none: false
194
+ requirements:
195
+ - - ! '>='
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ type: :development
199
+ prerelease: false
200
+ version_requirements: !ruby/object:Gem::Requirement
201
+ none: false
202
+ requirements:
203
+ - - ! '>='
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
206
+ - !ruby/object:Gem::Dependency
207
+ name: timecop
208
+ requirement: !ruby/object:Gem::Requirement
209
+ none: false
210
+ requirements:
211
+ - - ! '>='
212
+ - !ruby/object:Gem::Version
213
+ version: '0'
214
+ type: :development
215
+ prerelease: false
216
+ version_requirements: !ruby/object:Gem::Requirement
217
+ none: false
218
+ requirements:
219
+ - - ! '>='
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
222
+ description: MongoDB support for seam
223
+ email:
224
+ - darren@cauthon.com
225
+ executables: []
226
+ extensions: []
227
+ extra_rdoc_files: []
228
+ files:
229
+ - .gitignore
230
+ - Gemfile
231
+ - LICENSE.txt
232
+ - README.md
233
+ - Rakefile
234
+ - lib/seam/mongodb.rb
235
+ - lib/seam/mongodb/version.rb
236
+ - seam-mongodb.gemspec
237
+ - spec/seam/effort_spec.rb
238
+ - spec/seam/flow_spec.rb
239
+ - spec/seam/worker_spec.rb
240
+ - spec/spec_helper.rb
241
+ homepage: ''
242
+ licenses:
243
+ - MIT
244
+ post_install_message:
245
+ rdoc_options: []
246
+ require_paths:
247
+ - lib
248
+ required_ruby_version: !ruby/object:Gem::Requirement
249
+ none: false
250
+ requirements:
251
+ - - ! '>='
252
+ - !ruby/object:Gem::Version
253
+ version: '0'
254
+ segments:
255
+ - 0
256
+ hash: 2083924864139500401
257
+ required_rubygems_version: !ruby/object:Gem::Requirement
258
+ none: false
259
+ requirements:
260
+ - - ! '>='
261
+ - !ruby/object:Gem::Version
262
+ version: '0'
263
+ segments:
264
+ - 0
265
+ hash: 2083924864139500401
266
+ requirements: []
267
+ rubyforge_project:
268
+ rubygems_version: 1.8.25
269
+ signing_key:
270
+ specification_version: 3
271
+ summary: MongoDB support for seam
272
+ test_files:
273
+ - spec/seam/effort_spec.rb
274
+ - spec/seam/flow_spec.rb
275
+ - spec/seam/worker_spec.rb
276
+ - spec/spec_helper.rb