state_manager 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +74 -0
- data/LICENSE.txt +20 -0
- data/README.md +241 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/lib/state_manager/adapters/active_record.rb +52 -0
- data/lib/state_manager/adapters/base.rb +49 -0
- data/lib/state_manager/adapters.rb +30 -0
- data/lib/state_manager/base.rb +169 -0
- data/lib/state_manager/core.rb +7 -0
- data/lib/state_manager/dsl.rb +77 -0
- data/lib/state_manager/helpers.rb +47 -0
- data/lib/state_manager/plugins/delayed_job.rb +54 -0
- data/lib/state_manager/plugins.rb +4 -0
- data/lib/state_manager/resource.rb +83 -0
- data/lib/state_manager/state.rb +146 -0
- data/lib/state_manager.rb +1 -0
- data/state_manager.gemspec +102 -0
- data/test/adapters/active_record_test.rb +112 -0
- data/test/basic_test.rb +132 -0
- data/test/definition_test.rb +132 -0
- data/test/helper.rb +29 -0
- data/test/helpers_test.rb +61 -0
- data/test/plugins/delayed_job_test.rb +131 -0
- data/test/transitions_test.rb +171 -0
- metadata +226 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class ActiveRecordTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
class PostStates < StateManager::Base
|
6
|
+
state :unsubmitted do
|
7
|
+
event :submit, :transitions_to => 'submitted.awaiting_review'
|
8
|
+
end
|
9
|
+
state :submitted do
|
10
|
+
state :awaiting_review do
|
11
|
+
event :review, :transitions_to => 'submitted.reviewing'
|
12
|
+
end
|
13
|
+
state :reviewing do
|
14
|
+
event :accept, :transitions_to => 'active'
|
15
|
+
event :clarify, :transitions_to => 'submitted.clarifying'
|
16
|
+
end
|
17
|
+
state :clarifying do
|
18
|
+
event :review, :transitions_to => 'submitted.reviewing'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
state :active
|
22
|
+
state :rejected
|
23
|
+
end
|
24
|
+
|
25
|
+
class Post < ActiveRecord::Base
|
26
|
+
extend StateManager::Resource
|
27
|
+
state_manager
|
28
|
+
end
|
29
|
+
|
30
|
+
def exec(sql)
|
31
|
+
ActiveRecord::Base.connection.execute sql
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup
|
35
|
+
ActiveRecord::Base.establish_connection(
|
36
|
+
:adapter => "sqlite3",
|
37
|
+
:database => ":memory:" #"tmp/test"
|
38
|
+
)
|
39
|
+
|
40
|
+
ActiveRecord::Schema.define do
|
41
|
+
create_table :posts do |t|
|
42
|
+
t.integer :id
|
43
|
+
t.string :title
|
44
|
+
t.string :body
|
45
|
+
t.string :state
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
exec "INSERT INTO posts VALUES(1, NULL, NULL, NULL)"
|
50
|
+
exec "INSERT INTO posts VALUES(2, NULL, NULL, 'unsubmitted')"
|
51
|
+
exec "INSERT INTO posts VALUES(3, NULL, NULL, 'submitted.reviewing')"
|
52
|
+
exec "INSERT INTO posts VALUES(4, NULL, NULL, 'submitted.bad_state')"
|
53
|
+
|
54
|
+
@resource = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def teardown
|
58
|
+
ActiveRecord::Base.connection.disconnect!
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_adapter_included
|
62
|
+
@resource = Post.find(1)
|
63
|
+
assert @resource.is_a?(StateManager::Adapters::ActiveRecord::ResourceMethods)
|
64
|
+
assert @resource.state_manager.is_a?(StateManager::Adapters::ActiveRecord::ManagerMethods)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_persist_initial_state
|
68
|
+
@resource = Post.find(1)
|
69
|
+
assert_state 'unsubmitted'
|
70
|
+
assert !@resource.changed?, "state should have been persisted"
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_initial_state_value
|
74
|
+
@resource = Post.find(3)
|
75
|
+
assert_state 'submitted.reviewing'
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_validate_nil_state
|
79
|
+
@resource = Post.find(1)
|
80
|
+
assert !@resource.state
|
81
|
+
@resource.save
|
82
|
+
assert_state 'unsubmitted'
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_validate_invalid_state
|
86
|
+
@resource = Post.find(4)
|
87
|
+
assert_equal 'submitted.bad_state', @resource.state
|
88
|
+
@resource.save
|
89
|
+
assert_state 'unsubmitted'
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_scopes
|
93
|
+
exec "INSERT INTO posts VALUES(5, NULL, NULL, 'submitted.reviewing')"
|
94
|
+
exec "INSERT INTO posts VALUES(6, NULL, NULL, 'submitted.reviewing')"
|
95
|
+
exec "INSERT INTO posts VALUES(7, NULL, NULL, 'submitted.reviewing')"
|
96
|
+
exec "INSERT INTO posts VALUES(8, NULL, NULL, 'submitted.reviewing')"
|
97
|
+
exec "INSERT INTO posts VALUES(9, NULL, NULL, 'submitted.clarifying')"
|
98
|
+
exec "INSERT INTO posts VALUES(10, NULL, NULL, 'submitted.clarifying')"
|
99
|
+
|
100
|
+
exec "INSERT INTO posts VALUES(11, NULL, NULL, 'active')"
|
101
|
+
exec "INSERT INTO posts VALUES(12, NULL, NULL, 'active')"
|
102
|
+
exec "INSERT INTO posts VALUES(13, NULL, NULL, 'active')"
|
103
|
+
exec "INSERT INTO posts VALUES(14, NULL, NULL, 'active')"
|
104
|
+
|
105
|
+
# +1 from setup
|
106
|
+
assert_equal 1, Post.unsubmitted.count
|
107
|
+
# +2 from setup
|
108
|
+
assert_equal 8, Post.submitted.count
|
109
|
+
assert_equal 4, Post.active.count
|
110
|
+
assert_equal 0, Post.rejected.count
|
111
|
+
end
|
112
|
+
end
|
data/test/basic_test.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class BasicTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
class PostStates < StateManager::Base
|
6
|
+
state :unsubmitted do
|
7
|
+
event :submit, :transitions_to => 'submitted.awaiting_review'
|
8
|
+
end
|
9
|
+
state :submitted do
|
10
|
+
state :awaiting_review do
|
11
|
+
event :review, :transitions_to => 'submitted.reviewing'
|
12
|
+
end
|
13
|
+
state :reviewing do
|
14
|
+
event :accept, :transitions_to => 'active'
|
15
|
+
event :clarify, :transitions_to => 'submitted.clarifying'
|
16
|
+
end
|
17
|
+
state :clarifying do
|
18
|
+
event :review, :transitions_to => 'submitted.reviewing'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
state :active
|
22
|
+
state :rejected
|
23
|
+
end
|
24
|
+
|
25
|
+
class Post
|
26
|
+
attr_accessor :state
|
27
|
+
extend StateManager::Resource
|
28
|
+
state_manager :state
|
29
|
+
end
|
30
|
+
|
31
|
+
class PostWithInitialState
|
32
|
+
attr_accessor :state
|
33
|
+
extend StateManager::Resource
|
34
|
+
state_manager :state, PostStates do
|
35
|
+
initial_state 'submitted.awaiting_review'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class PostWithCustomProperty
|
40
|
+
attr_accessor :workflow_state
|
41
|
+
extend StateManager::Resource
|
42
|
+
state_manager :workflow_state, PostStates
|
43
|
+
end
|
44
|
+
|
45
|
+
def setup
|
46
|
+
@resource = Post.new
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_state_manager_class_initialized
|
50
|
+
assert @resource.state_manager.is_a?(PostStates), "state manager should have been initialized"
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_initial_states
|
54
|
+
assert_state 'unsubmitted', "initial state should be set to the default"
|
55
|
+
|
56
|
+
@resource = PostWithInitialState.new
|
57
|
+
|
58
|
+
assert_state 'submitted.awaiting_review', "initial state should be set to specified initial state"
|
59
|
+
|
60
|
+
@resource = Post.new
|
61
|
+
@resource.state = 'active'
|
62
|
+
|
63
|
+
assert_state 'active', "initial state should be read from resource"
|
64
|
+
|
65
|
+
@resource = PostWithInitialState.new
|
66
|
+
@resource.state = ''
|
67
|
+
|
68
|
+
assert_state 'submitted.awaiting_review', "initial state should be set to specified initial state"
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_context
|
72
|
+
@resource.state_manager.context[:user] = 'brogrammer'
|
73
|
+
assert_equal 'brogrammer', @resource.state_manager.context[:user]
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_state_changes
|
77
|
+
@resource.state_manager.transition_to 'submitted.clarifying'
|
78
|
+
|
79
|
+
assert_state 'submitted.clarifying', 'state should have transitioned'
|
80
|
+
assert_equal @resource.state, 'submitted.clarifying', 'state should have been written'
|
81
|
+
|
82
|
+
@resource.state_manager.transition_to 'reviewing'
|
83
|
+
|
84
|
+
assert_state 'submitted.reviewing', 'state should transition with shorthand sibling name'
|
85
|
+
|
86
|
+
@resource.state_manager.transition_to 'rejected'
|
87
|
+
|
88
|
+
assert_state 'rejected', 'state should have transitioned'
|
89
|
+
|
90
|
+
assert_raise StateManager::StateNotFound do
|
91
|
+
@resource.state_manager.transition_to 'reviewing'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_events
|
96
|
+
@resource.state_manager.send_event! :submit
|
97
|
+
|
98
|
+
assert_equal @resource.state_manager.current_state.path, 'submitted.awaiting_review', 'state should have transitioned'
|
99
|
+
assert_equal @resource.state, 'submitted.awaiting_review', 'state should have been written'
|
100
|
+
|
101
|
+
assert_raise StateManager::InvalidEvent do
|
102
|
+
@resource.state_manager.send_event! :submit
|
103
|
+
end
|
104
|
+
assert_equal @resource.state, 'submitted.awaiting_review', 'state should not have changed'
|
105
|
+
|
106
|
+
@resource.state_manager.send_event! :review
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_alternate_property
|
110
|
+
@resource = PostWithCustomProperty.new
|
111
|
+
assert_state 'unsubmitted', @resource.workflow_state_manager
|
112
|
+
|
113
|
+
@resource.workflow_state_manager.send_event! :submit
|
114
|
+
|
115
|
+
assert_equal @resource.workflow_state_manager.current_state.path, 'submitted.awaiting_review', 'state should have transitioned'
|
116
|
+
assert_equal @resource.workflow_state, 'submitted.awaiting_review', 'state should have been written'
|
117
|
+
|
118
|
+
assert_raise StateManager::InvalidEvent do
|
119
|
+
@resource.workflow_state_manager.send_event! :submit
|
120
|
+
end
|
121
|
+
assert_equal @resource.workflow_state, 'submitted.awaiting_review', 'state should not have changed'
|
122
|
+
|
123
|
+
@resource.workflow_state_manager.send_event! :review
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_can_only_transition_to_leaf
|
127
|
+
assert_raise StateManager::InvalidTransition do
|
128
|
+
@resource.state_manager.transition_to('submitted')
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class DefinitionTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
class CommentStates < StateManager::Base
|
6
|
+
attr_accessor :accept_reason, :reject_reason
|
7
|
+
|
8
|
+
class Submitted < StateManager::State
|
9
|
+
|
10
|
+
state :awaiting_review do
|
11
|
+
event :review, :transitions_to => 'submitted.reviewing'
|
12
|
+
end
|
13
|
+
state :reviewing do
|
14
|
+
event :accept, :transitions_to => 'active'
|
15
|
+
event :clarify, :transitions_to => 'submitted.clarifying'
|
16
|
+
end
|
17
|
+
state :clarifying do
|
18
|
+
event :review, :transitions_to => 'submitted.reviewing'
|
19
|
+
end
|
20
|
+
|
21
|
+
class Reviewing
|
22
|
+
|
23
|
+
def accept(reason)
|
24
|
+
state_manager.accept_reason = reason
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
state :unsubmitted do
|
31
|
+
end
|
32
|
+
state :submitted do
|
33
|
+
end
|
34
|
+
state :active
|
35
|
+
state :rejected
|
36
|
+
|
37
|
+
event :reject
|
38
|
+
|
39
|
+
def accept(reason)
|
40
|
+
state_manager.accept_reason = 'bad value'
|
41
|
+
end
|
42
|
+
|
43
|
+
def reject(reason)
|
44
|
+
self.reject_reason = reason
|
45
|
+
transition_to :rejected
|
46
|
+
end
|
47
|
+
|
48
|
+
class Unsubmitted
|
49
|
+
|
50
|
+
event :submit, :transitions_to => 'submitted.awaiting_review'
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
class_attribute :_resource_class
|
55
|
+
def self.added_to_resource(klass, property, options)
|
56
|
+
self._resource_class = klass
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
class Comment
|
62
|
+
attr_accessor :state
|
63
|
+
extend StateManager::Resource
|
64
|
+
state_manager
|
65
|
+
end
|
66
|
+
|
67
|
+
class ItemStates < StateManager::Base
|
68
|
+
state :default
|
69
|
+
end
|
70
|
+
|
71
|
+
class Item
|
72
|
+
attr_accessor :state
|
73
|
+
extend StateManager::Resource
|
74
|
+
state_manager
|
75
|
+
end
|
76
|
+
|
77
|
+
class BaseStateManager < StateManager::Base
|
78
|
+
end
|
79
|
+
|
80
|
+
class ArticleListingStates < BaseStateManager
|
81
|
+
state :default
|
82
|
+
end
|
83
|
+
|
84
|
+
class ArticleListing
|
85
|
+
attr_accessor :state
|
86
|
+
extend StateManager::Resource
|
87
|
+
state_manager
|
88
|
+
end
|
89
|
+
|
90
|
+
def setup
|
91
|
+
@resource = Comment.new
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_event_in_separate_class_definition
|
95
|
+
@resource.submit!
|
96
|
+
assert_state 'submitted.awaiting_review'
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_states_in_separate_class_definition
|
100
|
+
@resource.submit!
|
101
|
+
|
102
|
+
assert_state 'submitted.awaiting_review'
|
103
|
+
|
104
|
+
@resource.review!
|
105
|
+
|
106
|
+
assert_state 'submitted.reviewing'
|
107
|
+
|
108
|
+
@resource.accept!('hipster')
|
109
|
+
|
110
|
+
assert_equal 'hipster', @resource.state_manager.accept_reason
|
111
|
+
assert_state 'active'
|
112
|
+
|
113
|
+
@resource.reject!('not a hipster')
|
114
|
+
|
115
|
+
assert_equal 'not a hipster', @resource.state_manager.reject_reason
|
116
|
+
|
117
|
+
assert_state 'rejected'
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_added_to_resource_callback
|
121
|
+
assert_equal Comment, @resource.state_manager.class._resource_class
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_resource_accessor
|
125
|
+
assert @resource.state_manager.class.method_defined?(:comment)
|
126
|
+
assert @resource.state_manager.class.specification.states.values.first.method_defined?(:comment)
|
127
|
+
assert !@resource.state_manager.class.method_defined?(:item), 'accessor for other resource should not be defined'
|
128
|
+
assert !@resource.state_manager.class.method_defined?(:article_listing), 'accessor for other resource should not be defined'
|
129
|
+
assert ArticleListing.new.state_manager.class.method_defined?(:article_listing)
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
|
12
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
13
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
14
|
+
require 'pry'
|
15
|
+
require 'delayed_job_active_record'
|
16
|
+
require 'state_manager'
|
17
|
+
|
18
|
+
class Test::Unit::TestCase
|
19
|
+
|
20
|
+
def assert_state(path, state_manager=nil, message=nil)
|
21
|
+
if state_manager.is_a? String
|
22
|
+
message = state_manager
|
23
|
+
state_manager = nil
|
24
|
+
end
|
25
|
+
state_manager ||= @resource.state_manager
|
26
|
+
assert_equal path, state_manager.current_state.path
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class HelpersTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
class ItemStates < StateManager::Base
|
6
|
+
state :default do
|
7
|
+
event :do_inner, :transitions_to => 'root.outer1.inner'
|
8
|
+
end
|
9
|
+
state :root do
|
10
|
+
state :outer1 do
|
11
|
+
event :next, :transitions_to => 'outer2.inner'
|
12
|
+
state :inner do
|
13
|
+
event :next, :transitions_to => 'inner2'
|
14
|
+
end
|
15
|
+
state :inner2
|
16
|
+
end
|
17
|
+
state :outer2 do
|
18
|
+
state :inner do
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Item
|
25
|
+
attr_accessor :state
|
26
|
+
extend StateManager::Resource
|
27
|
+
state_manager
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup
|
31
|
+
@resource = Item.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_helpers
|
35
|
+
assert @resource.default?
|
36
|
+
assert !@resource.root?
|
37
|
+
assert !@resource.root_outer1?
|
38
|
+
assert !@resource.root_outer1_inner?
|
39
|
+
assert @resource.can_do_inner?
|
40
|
+
assert !@resource.can_next?
|
41
|
+
|
42
|
+
@resource.do_inner!
|
43
|
+
|
44
|
+
assert @resource.root?
|
45
|
+
assert @resource.root_outer1?
|
46
|
+
assert @resource.root_outer1_inner?
|
47
|
+
assert !@resource.root_outer2_inner?
|
48
|
+
assert @resource.can_next?
|
49
|
+
|
50
|
+
@resource.next!
|
51
|
+
|
52
|
+
assert @resource.root_outer1_inner2?
|
53
|
+
assert @resource.can_next?
|
54
|
+
|
55
|
+
@resource.next!
|
56
|
+
|
57
|
+
assert @resource.root_outer2_inner?
|
58
|
+
assert !@resource.can_next?
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'timecop'
|
3
|
+
|
4
|
+
class DelayedJobTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
class ProjectStates < StateManager::Base
|
7
|
+
initial_state 'unsubmitted.initial'
|
8
|
+
state :unsubmitted do
|
9
|
+
event :submit, :transitions_to => 'submitted'
|
10
|
+
state :initial do
|
11
|
+
event :remind, :transitions_to => 'reminded', :delay => 2.hours
|
12
|
+
end
|
13
|
+
state :reminded
|
14
|
+
end
|
15
|
+
state :submitted do
|
16
|
+
event :accept, :transitions_to => 'accepted'
|
17
|
+
event :auto_accept, :transitions_to => 'accepted', :delay => 1.day
|
18
|
+
event :reject, :transitions_to => 'rejected'
|
19
|
+
end
|
20
|
+
state :accepted do
|
21
|
+
event :remind, :transitions_to => 'rejected'
|
22
|
+
end
|
23
|
+
state :rejected
|
24
|
+
end
|
25
|
+
|
26
|
+
def exec(sql)
|
27
|
+
ActiveRecord::Base.connection.execute sql
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup
|
31
|
+
ActiveRecord::Base.establish_connection(
|
32
|
+
:adapter => "sqlite3",
|
33
|
+
:database => ":memory:" #"tmp/test"
|
34
|
+
)
|
35
|
+
|
36
|
+
ActiveRecord::Schema.define do
|
37
|
+
create_table :projects do |t|
|
38
|
+
t.integer :id
|
39
|
+
t.string :title
|
40
|
+
t.string :state
|
41
|
+
end
|
42
|
+
|
43
|
+
create_table :delayed_jobs, :force => true do |table|
|
44
|
+
table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
|
45
|
+
table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
|
46
|
+
table.text :handler # YAML-encoded string of the object that will do work
|
47
|
+
table.text :last_error # reason for last failure (See Note below)
|
48
|
+
table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
|
49
|
+
table.datetime :locked_at # Set when a client is working on this object
|
50
|
+
table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
|
51
|
+
table.string :locked_by # Who is working on this object (if locked)
|
52
|
+
table.string :queue # The name of the queue this job is in
|
53
|
+
table.timestamps
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
exec "INSERT INTO projects VALUES(1, 'Project 1', NULL)"
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
class Project < ActiveRecord::Base
|
62
|
+
extend StateManager::Resource
|
63
|
+
state_manager
|
64
|
+
end
|
65
|
+
|
66
|
+
def teardown
|
67
|
+
ActiveRecord::Base.connection.disconnect!
|
68
|
+
Timecop.return
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# Convince delayed job that the duration has passed and perform any jobs that
|
73
|
+
# need doing
|
74
|
+
def time_warp(duration)
|
75
|
+
Timecop.travel(duration.from_now)
|
76
|
+
Delayed::Worker.new.work_off
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_delayed_event
|
80
|
+
@resource = Project.find(1)
|
81
|
+
|
82
|
+
assert_state 'unsubmitted.initial'
|
83
|
+
assert_equal 1, Delayed::Job.count
|
84
|
+
|
85
|
+
time_warp(4.hours)
|
86
|
+
|
87
|
+
assert_equal 0, Delayed::Job.count
|
88
|
+
@resource.reload
|
89
|
+
assert_state 'unsubmitted.reminded'
|
90
|
+
|
91
|
+
@resource.submit!
|
92
|
+
|
93
|
+
assert_state 'submitted'
|
94
|
+
|
95
|
+
time_warp(1.hour)
|
96
|
+
|
97
|
+
assert_state 'submitted', 'should not have transitioned yet'
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_expired_event
|
101
|
+
@resource = Project.find(1)
|
102
|
+
|
103
|
+
assert_state 'unsubmitted.initial'
|
104
|
+
assert_equal 1, Delayed::Job.count
|
105
|
+
|
106
|
+
@resource.submit!
|
107
|
+
|
108
|
+
assert_state 'submitted'
|
109
|
+
|
110
|
+
time_warp(4.hours)
|
111
|
+
|
112
|
+
assert_state 'submitted', 'should not have transitioned'
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_event_name_clashes
|
116
|
+
@resource = Project.find(1)
|
117
|
+
|
118
|
+
assert_state 'unsubmitted.initial'
|
119
|
+
assert_equal 1, Delayed::Job.count
|
120
|
+
|
121
|
+
@resource.submit!
|
122
|
+
@resource.accept!
|
123
|
+
|
124
|
+
assert_equal 2, Delayed::Job.count
|
125
|
+
|
126
|
+
time_warp(1.month)
|
127
|
+
|
128
|
+
assert_state 'accepted', 'remind event should not have been triggered'
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|