aasm 4.11.1 → 4.12.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +15 -16
- data/Appraisals +44 -0
- data/CHANGELOG.md +14 -0
- data/CONTRIBUTING.md +24 -0
- data/Gemfile +4 -21
- data/README.md +53 -32
- data/Rakefile +6 -1
- data/TESTING.md +25 -0
- data/aasm.gemspec +3 -0
- data/gemfiles/rails_3.2.gemfile +13 -0
- data/gemfiles/rails_4.0.gemfile +8 -9
- data/gemfiles/rails_4.2.gemfile +9 -9
- data/gemfiles/rails_4.2_mongoid_5.gemfile +5 -9
- data/gemfiles/rails_5.0.gemfile +7 -16
- data/lib/aasm/aasm.rb +9 -3
- data/lib/aasm/base.rb +3 -1
- data/lib/aasm/configuration.rb +4 -0
- data/lib/aasm/core/event.rb +17 -3
- data/lib/aasm/core/state.rb +7 -0
- data/lib/aasm/core/transition.rb +9 -0
- data/lib/aasm/persistence.rb +0 -3
- data/lib/aasm/persistence/active_record_persistence.rb +1 -1
- data/lib/aasm/persistence/mongoid_persistence.rb +48 -9
- data/lib/aasm/state_machine.rb +4 -2
- data/lib/aasm/state_machine_store.rb +5 -2
- data/lib/aasm/version.rb +1 -1
- data/lib/motion-aasm.rb +0 -1
- data/spec/generators/active_record_generator_spec.rb +42 -39
- data/spec/generators/mongoid_generator_spec.rb +4 -6
- data/spec/models/{invalid_persistor.rb → active_record/invalid_persistor.rb} +0 -2
- data/spec/models/{silent_persistor.rb → active_record/silent_persistor.rb} +0 -2
- data/spec/models/{transactor.rb → active_record/transactor.rb} +0 -2
- data/spec/models/{validator.rb → active_record/validator.rb} +0 -2
- data/spec/models/{worker.rb → active_record/worker.rb} +0 -0
- data/spec/models/callbacks/basic.rb +5 -2
- data/spec/models/guard_with_params.rb +1 -1
- data/spec/models/mongoid/invalid_persistor_mongoid.rb +39 -0
- data/spec/models/mongoid/silent_persistor_mongoid.rb +39 -0
- data/spec/models/mongoid/validator_mongoid.rb +100 -0
- data/spec/models/multiple_transitions_that_differ_only_by_guard.rb +31 -0
- data/spec/models/parametrised_event.rb +7 -0
- data/spec/models/simple_multiple_example.rb +12 -0
- data/spec/models/sub_class.rb +34 -0
- data/spec/spec_helper.rb +0 -33
- data/spec/spec_helpers/active_record.rb +7 -0
- data/spec/spec_helpers/dynamoid.rb +33 -0
- data/spec/spec_helpers/mongoid.rb +7 -0
- data/spec/spec_helpers/redis.rb +7 -0
- data/spec/spec_helpers/remove_warnings.rb +1 -0
- data/spec/spec_helpers/sequel.rb +7 -0
- data/spec/unit/api_spec.rb +76 -73
- data/spec/unit/callbacks_spec.rb +5 -0
- data/spec/unit/event_spec.rb +12 -0
- data/spec/unit/guard_with_params_spec.rb +4 -0
- data/spec/unit/localizer_spec.rb +55 -53
- data/spec/unit/multiple_transitions_that_differ_only_by_guard_spec.rb +14 -0
- data/spec/unit/override_warning_spec.rb +8 -0
- data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +452 -448
- data/spec/unit/persistence/active_record_persistence_spec.rb +523 -501
- data/spec/unit/persistence/dynamoid_persistence_multiple_spec.rb +4 -9
- data/spec/unit/persistence/dynamoid_persistence_spec.rb +4 -9
- data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +83 -9
- data/spec/unit/persistence/mongoid_persistence_spec.rb +85 -9
- data/spec/unit/persistence/redis_persistence_spec.rb +3 -7
- data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +4 -9
- data/spec/unit/persistence/sequel_persistence_spec.rb +4 -9
- data/spec/unit/simple_multiple_example_spec.rb +28 -0
- data/spec/unit/subclassing_multiple_spec.rb +37 -2
- data/spec/unit/subclassing_spec.rb +17 -2
- metadata +66 -28
- data/gemfiles/rails_3.2_stable.gemfile +0 -15
- data/gemfiles/rails_4.0_mongo_mapper.gemfile +0 -16
- data/gemfiles/rails_4.2_mongo_mapper.gemfile +0 -17
- data/lib/aasm/persistence/mongo_mapper_persistence.rb +0 -163
- data/spec/models/mongo_mapper/complex_mongo_mapper_example.rb +0 -37
- data/spec/models/mongo_mapper/no_scope_mongo_mapper.rb +0 -21
- data/spec/models/mongo_mapper/simple_mongo_mapper.rb +0 -23
- data/spec/models/mongo_mapper/simple_new_dsl_mongo_mapper.rb +0 -25
- data/spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb +0 -149
- data/spec/unit/persistence/mongo_mapper_persistence_spec.rb +0 -96
@@ -1,699 +1,721 @@
|
|
1
|
-
require 'active_record'
|
2
1
|
require 'spec_helper'
|
3
|
-
Dir[File.dirname(__FILE__) + "/../../models/active_record/*.rb"].sort.each do |f|
|
4
|
-
require File.expand_path(f)
|
5
|
-
end
|
6
|
-
|
7
|
-
load_schema
|
8
|
-
|
9
|
-
# if you want to see the statements while running the spec enable the following line
|
10
|
-
# require 'logger'
|
11
|
-
# ActiveRecord::Base.logger = Logger.new(STDERR)
|
12
2
|
|
13
|
-
|
14
|
-
let(:gate) {Gate.new}
|
3
|
+
if defined?(ActiveRecord)
|
15
4
|
|
16
|
-
|
17
|
-
|
18
|
-
expect(gate).to respond_to(:aasm_write_state)
|
19
|
-
expect(gate).to respond_to(:aasm_write_state_without_persistence)
|
5
|
+
Dir[File.dirname(__FILE__) + "/../../models/active_record/*.rb"].sort.each do |f|
|
6
|
+
require File.expand_path(f)
|
20
7
|
end
|
21
8
|
|
22
|
-
|
23
|
-
subject { lambda{ gate.send(:aasm_column_looks_like_enum) } }
|
9
|
+
load_schema
|
24
10
|
|
25
|
-
|
26
|
-
|
11
|
+
# if you want to see the statements while running the spec enable the following line
|
12
|
+
# require 'logger'
|
13
|
+
# ActiveRecord::Base.logger = Logger.new(STDERR)
|
27
14
|
|
28
|
-
|
29
|
-
|
30
|
-
allow(gate.class).to receive(:columns_hash).and_return(columns_hash)
|
31
|
-
end
|
32
|
-
|
33
|
-
context "when AASM column has integer type" do
|
34
|
-
let(:column) { double(Object, type: :integer) }
|
15
|
+
describe "instance methods" do
|
16
|
+
let(:gate) {Gate.new}
|
35
17
|
|
36
|
-
|
37
|
-
|
38
|
-
|
18
|
+
it "should respond to aasm persistence methods" do
|
19
|
+
expect(gate).to respond_to(:aasm_read_state)
|
20
|
+
expect(gate).to respond_to(:aasm_write_state)
|
21
|
+
expect(gate).to respond_to(:aasm_write_state_without_persistence)
|
39
22
|
end
|
40
23
|
|
41
|
-
|
42
|
-
|
24
|
+
describe "aasm_column_looks_like_enum" do
|
25
|
+
subject { lambda{ gate.send(:aasm_column_looks_like_enum) } }
|
43
26
|
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
27
|
+
let(:column_name) { "value" }
|
28
|
+
let(:columns_hash) { Hash[column_name, column] }
|
49
29
|
|
50
|
-
|
51
|
-
|
30
|
+
before :each do
|
31
|
+
allow(gate.class.aasm).to receive(:attribute_name).and_return(column_name.to_sym)
|
32
|
+
allow(gate.class).to receive(:columns_hash).and_return(columns_hash)
|
33
|
+
end
|
52
34
|
|
53
|
-
|
54
|
-
|
55
|
-
end
|
35
|
+
context "when AASM column has integer type" do
|
36
|
+
let(:column) { double(Object, type: :integer) }
|
56
37
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
38
|
+
it "returns true" do
|
39
|
+
expect(subject.call).to be_truthy
|
40
|
+
end
|
41
|
+
end
|
61
42
|
|
62
|
-
|
63
|
-
|
64
|
-
let(:with_enum) { WithEnum.new }
|
43
|
+
context "when AASM column has string type" do
|
44
|
+
let(:column) { double(Object, type: :string) }
|
65
45
|
|
66
|
-
|
67
|
-
|
46
|
+
it "returns false" do
|
47
|
+
expect(subject.call).to be_falsey
|
48
|
+
end
|
68
49
|
end
|
69
50
|
end
|
70
51
|
|
71
|
-
|
72
|
-
|
52
|
+
describe "aasm_guess_enum_method" do
|
53
|
+
subject { lambda{ gate.send(:aasm_guess_enum_method) } }
|
54
|
+
|
73
55
|
before :each do
|
74
|
-
allow(
|
56
|
+
allow(gate.class.aasm).to receive(:attribute_name).and_return(:value)
|
75
57
|
end
|
76
58
|
|
77
|
-
it "
|
78
|
-
expect(
|
59
|
+
it "pluralizes AASM column name" do
|
60
|
+
expect(subject.call).to eq :values
|
79
61
|
end
|
80
62
|
end
|
81
63
|
|
82
|
-
|
83
|
-
|
64
|
+
describe "aasm_enum" do
|
65
|
+
context "when AASM enum setting contains an explicit enum method name" do
|
66
|
+
let(:with_enum) { WithEnum.new }
|
84
67
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
context "when AASM enum setting is not enabled" do
|
91
|
-
before :each do
|
92
|
-
allow(Gate.aasm).to receive(:attribute_name).and_return(:value)
|
68
|
+
it "returns whatever value was set in AASM config" do
|
69
|
+
expect(with_enum.send(:aasm_enum)).to eq :test
|
70
|
+
end
|
93
71
|
end
|
94
72
|
|
95
|
-
context "when AASM
|
73
|
+
context "when AASM enum setting is simply set to true" do
|
74
|
+
let(:with_true_enum) { WithTrueEnum.new }
|
96
75
|
before :each do
|
97
|
-
allow(
|
76
|
+
allow(WithTrueEnum.aasm).to receive(:attribute_name).and_return(:value)
|
98
77
|
end
|
99
78
|
|
100
79
|
it "infers enum method name from pluralized column name" do
|
101
|
-
expect(
|
80
|
+
expect(with_true_enum.send(:aasm_enum)).to eq :values
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "when AASM enum setting is explicitly disabled" do
|
85
|
+
let(:with_false_enum) { WithFalseEnum.new }
|
86
|
+
|
87
|
+
it "returns nil" do
|
88
|
+
expect(with_false_enum.send(:aasm_enum)).to be_nil
|
102
89
|
end
|
103
90
|
end
|
104
91
|
|
105
|
-
context "when AASM
|
92
|
+
context "when AASM enum setting is not enabled" do
|
106
93
|
before :each do
|
107
|
-
allow(
|
108
|
-
.and_return(false)
|
94
|
+
allow(Gate.aasm).to receive(:attribute_name).and_return(:value)
|
109
95
|
end
|
110
96
|
|
111
|
-
|
112
|
-
|
97
|
+
context "when AASM column looks like enum" do
|
98
|
+
before :each do
|
99
|
+
allow(gate).to receive(:aasm_column_looks_like_enum).and_return(true)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "infers enum method name from pluralized column name" do
|
103
|
+
expect(gate.send(:aasm_enum)).to eq :values
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "when AASM column doesn't look like enum'" do
|
108
|
+
before :each do
|
109
|
+
allow(gate).to receive(:aasm_column_looks_like_enum)
|
110
|
+
.and_return(false)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "returns nil, as we're not using enum" do
|
114
|
+
expect(gate.send(:aasm_enum)).to be_nil
|
115
|
+
end
|
113
116
|
end
|
114
117
|
end
|
115
|
-
end
|
116
118
|
|
117
|
-
|
118
|
-
|
119
|
-
|
119
|
+
if ActiveRecord::VERSION::MAJOR >= 4 && ActiveRecord::VERSION::MINOR >= 1 # won't work with Rails <= 4.1
|
120
|
+
# Enum are introduced from Rails 4.1, therefore enum syntax will not work on Rails <= 4.1
|
121
|
+
context "when AASM enum setting is not enabled and aasm column not present" do
|
120
122
|
|
121
|
-
|
123
|
+
let(:with_enum_without_column) {WithEnumWithoutColumn.new}
|
122
124
|
|
123
|
-
|
124
|
-
|
125
|
+
it "should raise NoMethodError for transitions" do
|
126
|
+
expect{with_enum_without_column.send(:view)}.to raise_error(NoMethodError, "undefined method 'status' for WithEnumWithoutColumn")
|
127
|
+
end
|
125
128
|
end
|
129
|
+
|
126
130
|
end
|
127
131
|
|
128
132
|
end
|
129
133
|
|
130
|
-
|
134
|
+
context "when AASM is configured to use enum" do
|
135
|
+
let(:state_sym) { :running }
|
136
|
+
let(:state_code) { 2 }
|
137
|
+
let(:enum_name) { :states }
|
138
|
+
let(:enum) { Hash[state_sym, state_code] }
|
131
139
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
let(:enum) { Hash[state_sym, state_code] }
|
140
|
+
before :each do
|
141
|
+
allow(gate).to receive(:aasm_enum).and_return(enum_name)
|
142
|
+
allow(gate).to receive(:aasm_write_attribute)
|
143
|
+
allow(gate).to receive(:write_attribute)
|
137
144
|
|
138
|
-
|
139
|
-
|
140
|
-
allow(gate).to receive(:aasm_write_attribute)
|
141
|
-
allow(gate).to receive(:write_attribute)
|
145
|
+
allow(Gate).to receive(enum_name).and_return(enum)
|
146
|
+
end
|
142
147
|
|
143
|
-
|
144
|
-
|
148
|
+
describe "aasm_write_state" do
|
149
|
+
context "when AASM is configured to skip validations on save" do
|
150
|
+
before :each do
|
151
|
+
allow(gate).to receive(:aasm_skipping_validations).and_return(true)
|
152
|
+
end
|
145
153
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
154
|
+
it "passes state code instead of state symbol to update_all" do
|
155
|
+
# stub_chain does not allow us to give expectations on call
|
156
|
+
# parameters in the middle of the chain, so we need to use
|
157
|
+
# intermediate object instead.
|
158
|
+
obj = double(Object, update_all: 1)
|
159
|
+
allow(Gate).to receive_message_chain(:unscoped, :where).and_return(obj)
|
160
|
+
|
161
|
+
gate.aasm_write_state state_sym
|
162
|
+
|
163
|
+
expect(obj).to have_received(:update_all)
|
164
|
+
.with(Hash[gate.class.aasm.attribute_name, state_code])
|
165
|
+
end
|
166
|
+
|
167
|
+
it "searches model outside of default_scope when update_all" do
|
168
|
+
# stub_chain does not allow us to give expectations on call
|
169
|
+
# parameters in the middle of the chain, so we need to use
|
170
|
+
# intermediate object instead.
|
171
|
+
unscoped = double(Object, update_all: 1)
|
172
|
+
scoped = double(Object, update_all: 1)
|
173
|
+
|
174
|
+
allow(Gate).to receive(:unscoped).and_return(unscoped)
|
175
|
+
allow(Gate).to receive(:where).and_return(scoped)
|
176
|
+
allow(unscoped).to receive(:where).and_return(unscoped)
|
177
|
+
|
178
|
+
gate.aasm_write_state state_sym
|
179
|
+
|
180
|
+
expect(unscoped).to have_received(:update_all)
|
181
|
+
.with(Hash[gate.class.aasm.attribute_name, state_code])
|
182
|
+
expect(scoped).to_not have_received(:update_all)
|
183
|
+
.with(Hash[gate.class.aasm.attribute_name, state_code])
|
184
|
+
end
|
150
185
|
end
|
151
186
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
obj = double(Object, update_all: 1)
|
157
|
-
allow(Gate).to receive(:where).and_return(obj)
|
187
|
+
context "when AASM is not skipping validations" do
|
188
|
+
it "delegates state update to the helper method" do
|
189
|
+
# Let's pretend that validation is passed
|
190
|
+
allow(gate).to receive(:save).and_return(true)
|
158
191
|
|
159
|
-
|
192
|
+
gate.aasm_write_state state_sym
|
160
193
|
|
161
|
-
|
162
|
-
|
194
|
+
expect(gate).to have_received(:aasm_write_attribute).with(state_sym, :default)
|
195
|
+
expect(gate).to_not have_received :write_attribute
|
196
|
+
end
|
163
197
|
end
|
164
198
|
end
|
165
199
|
|
166
|
-
|
200
|
+
describe "aasm_write_state_without_persistence" do
|
167
201
|
it "delegates state update to the helper method" do
|
168
|
-
|
169
|
-
allow(gate).to receive(:save).and_return(true)
|
170
|
-
|
171
|
-
gate.aasm_write_state state_sym
|
202
|
+
gate.aasm_write_state_without_persistence state_sym
|
172
203
|
|
173
204
|
expect(gate).to have_received(:aasm_write_attribute).with(state_sym, :default)
|
174
205
|
expect(gate).to_not have_received :write_attribute
|
175
206
|
end
|
176
207
|
end
|
208
|
+
|
209
|
+
describe "aasm_raw_attribute_value" do
|
210
|
+
it "converts state symbol to state code" do
|
211
|
+
expect(gate.send(:aasm_raw_attribute_value, state_sym))
|
212
|
+
.to eq state_code
|
213
|
+
end
|
214
|
+
end
|
177
215
|
end
|
178
216
|
|
179
|
-
|
180
|
-
|
181
|
-
gate.aasm_write_state_without_persistence state_sym
|
217
|
+
context "when AASM is configured to use string field" do
|
218
|
+
let(:state_sym) { :running }
|
182
219
|
|
183
|
-
|
184
|
-
|
220
|
+
before :each do
|
221
|
+
allow(gate).to receive(:aasm_enum).and_return(nil)
|
185
222
|
end
|
186
|
-
end
|
187
223
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
224
|
+
describe "aasm_raw_attribute_value" do
|
225
|
+
it "converts state symbol to string" do
|
226
|
+
expect(gate.send(:aasm_raw_attribute_value, state_sym))
|
227
|
+
.to eq state_sym.to_s
|
228
|
+
end
|
192
229
|
end
|
193
230
|
end
|
194
|
-
end
|
195
231
|
|
196
|
-
|
197
|
-
|
232
|
+
describe "aasm_write_attribute helper method" do
|
233
|
+
let(:sym) { :sym }
|
234
|
+
let(:value) { 42 }
|
198
235
|
|
199
|
-
|
200
|
-
|
201
|
-
|
236
|
+
before :each do
|
237
|
+
allow(gate).to receive(:write_attribute)
|
238
|
+
allow(gate).to receive(:aasm_raw_attribute_value).and_return(value)
|
202
239
|
|
203
|
-
|
204
|
-
it "converts state symbol to string" do
|
205
|
-
expect(gate.send(:aasm_raw_attribute_value, state_sym))
|
206
|
-
.to eq state_sym.to_s
|
240
|
+
gate.send(:aasm_write_attribute, sym)
|
207
241
|
end
|
208
|
-
end
|
209
|
-
end
|
210
242
|
|
211
|
-
|
212
|
-
|
213
|
-
|
243
|
+
it "generates attribute value using a helper method" do
|
244
|
+
expect(gate).to have_received(:aasm_raw_attribute_value).with(sym, :default)
|
245
|
+
end
|
214
246
|
|
215
|
-
|
216
|
-
|
217
|
-
|
247
|
+
it "writes attribute to the model" do
|
248
|
+
expect(gate).to have_received(:write_attribute).with(:aasm_state, value)
|
249
|
+
end
|
250
|
+
end
|
218
251
|
|
219
|
-
|
252
|
+
it "should return the initial state when new and the aasm field is nil" do
|
253
|
+
expect(gate.aasm.current_state).to eq(:opened)
|
220
254
|
end
|
221
255
|
|
222
|
-
it "
|
223
|
-
|
256
|
+
it "should return the aasm column when new and the aasm field is not nil" do
|
257
|
+
gate.aasm_state = "closed"
|
258
|
+
expect(gate.aasm.current_state).to eq(:closed)
|
224
259
|
end
|
225
260
|
|
226
|
-
it "
|
227
|
-
|
261
|
+
it "should return the aasm column when not new and the aasm.attribute_name is not nil" do
|
262
|
+
allow(gate).to receive(:new_record?).and_return(false)
|
263
|
+
gate.aasm_state = "state"
|
264
|
+
expect(gate.aasm.current_state).to eq(:state)
|
228
265
|
end
|
229
|
-
end
|
230
266
|
|
231
|
-
|
232
|
-
|
233
|
-
|
267
|
+
it "should allow a nil state" do
|
268
|
+
allow(gate).to receive(:new_record?).and_return(false)
|
269
|
+
gate.aasm_state = nil
|
270
|
+
expect(gate.aasm.current_state).to be_nil
|
271
|
+
end
|
234
272
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
273
|
+
context 'on initialization' do
|
274
|
+
it "should initialize the aasm state" do
|
275
|
+
expect(Gate.new.aasm_state).to eql 'opened'
|
276
|
+
expect(Gate.new.aasm.current_state).to eql :opened
|
277
|
+
end
|
239
278
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
end
|
279
|
+
it "should not initialize the aasm state if it has not been loaded" do
|
280
|
+
# we have to create a gate in the database, for which we only want to
|
281
|
+
# load the id, and not the state
|
282
|
+
gate = Gate.create!
|
245
283
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
expect(gate.aasm.current_state).to be_nil
|
250
|
-
end
|
251
|
-
|
252
|
-
context 'on initialization' do
|
253
|
-
it "should initialize the aasm state" do
|
254
|
-
expect(Gate.new.aasm_state).to eql 'opened'
|
255
|
-
expect(Gate.new.aasm.current_state).to eql :opened
|
284
|
+
# then we just load the gate ids
|
285
|
+
Gate.select(:id).where(id: gate.id).first
|
286
|
+
end
|
256
287
|
end
|
257
288
|
|
258
|
-
|
259
|
-
# we have to create a gate in the database, for which we only want to
|
260
|
-
# load the id, and not the state
|
261
|
-
gate = Gate.create!
|
289
|
+
end
|
262
290
|
|
263
|
-
|
264
|
-
|
291
|
+
if ActiveRecord::VERSION::MAJOR < 4 && ActiveRecord::VERSION::MINOR < 2 # won't work with Rails >= 4.2
|
292
|
+
describe "direct state column access" do
|
293
|
+
it "accepts false states" do
|
294
|
+
f = FalseState.create!
|
295
|
+
expect(f.aasm_state).to eql false
|
296
|
+
expect {
|
297
|
+
f.aasm.events.map(&:name)
|
298
|
+
}.to_not raise_error
|
265
299
|
end
|
266
300
|
end
|
267
|
-
|
268
|
-
end
|
269
|
-
|
270
|
-
if ActiveRecord::VERSION::MAJOR < 4 && ActiveRecord::VERSION::MINOR < 2 # won't work with Rails >= 4.2
|
271
|
-
describe "direct state column access" do
|
272
|
-
it "accepts false states" do
|
273
|
-
f = FalseState.create!
|
274
|
-
expect(f.aasm_state).to eql false
|
275
|
-
expect {
|
276
|
-
f.aasm.events.map(&:name)
|
277
|
-
}.to_not raise_error
|
278
301
|
end
|
279
|
-
end
|
280
|
-
end
|
281
302
|
|
282
|
-
describe 'subclasses' do
|
283
|
-
|
284
|
-
|
285
|
-
|
303
|
+
describe 'subclasses' do
|
304
|
+
it "should have the same states as its parent class" do
|
305
|
+
expect(DerivateNewDsl.aasm.states).to eq(SimpleNewDsl.aasm.states)
|
306
|
+
end
|
286
307
|
|
287
|
-
|
288
|
-
|
289
|
-
|
308
|
+
it "should have the same events as its parent class" do
|
309
|
+
expect(DerivateNewDsl.aasm.events).to eq(SimpleNewDsl.aasm.events)
|
310
|
+
end
|
290
311
|
|
291
|
-
|
292
|
-
|
293
|
-
|
312
|
+
it "should have the same column as its parent even for the new dsl" do
|
313
|
+
expect(SimpleNewDsl.aasm.attribute_name).to eq(:status)
|
314
|
+
expect(DerivateNewDsl.aasm.attribute_name).to eq(:status)
|
315
|
+
end
|
294
316
|
end
|
295
|
-
end
|
296
317
|
|
297
|
-
describe "named scopes with the new DSL" do
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
318
|
+
describe "named scopes with the new DSL" do
|
319
|
+
context "Does not already respond_to? the scope name" do
|
320
|
+
it "should add a scope for each state" do
|
321
|
+
expect(SimpleNewDsl).to respond_to(:unknown_scope)
|
322
|
+
expect(SimpleNewDsl).to respond_to(:another_unknown_scope)
|
302
323
|
|
303
|
-
|
304
|
-
|
324
|
+
expect(SimpleNewDsl.unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
|
325
|
+
expect(SimpleNewDsl.another_unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
|
326
|
+
end
|
305
327
|
end
|
306
|
-
end
|
307
328
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
329
|
+
context "Already respond_to? the scope name" do
|
330
|
+
it "should not add a scope" do
|
331
|
+
expect(SimpleNewDsl).to respond_to(:new)
|
332
|
+
expect(SimpleNewDsl.new.class).to eq(SimpleNewDsl)
|
333
|
+
end
|
312
334
|
end
|
313
|
-
end
|
314
335
|
|
315
|
-
|
316
|
-
|
317
|
-
|
336
|
+
it "does not create scopes if requested" do
|
337
|
+
expect(NoScope).not_to respond_to(:pending)
|
338
|
+
end
|
318
339
|
|
319
|
-
|
320
|
-
|
321
|
-
|
340
|
+
context "result of scope" do
|
341
|
+
let!(:dsl1) { SimpleNewDsl.create!(status: :new) }
|
342
|
+
let!(:dsl2) { SimpleNewDsl.create!(status: :unknown_scope) }
|
322
343
|
|
323
|
-
|
324
|
-
|
344
|
+
after do
|
345
|
+
SimpleNewDsl.destroy_all
|
346
|
+
end
|
347
|
+
|
348
|
+
it "created scope works as where(name: :scope_name)" do
|
349
|
+
expect(SimpleNewDsl.unknown_scope).to contain_exactly(dsl2)
|
350
|
+
end
|
325
351
|
end
|
352
|
+
end # scopes
|
353
|
+
|
354
|
+
describe "direct assignment" do
|
355
|
+
it "is allowed by default" do
|
356
|
+
obj = NoScope.create
|
357
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
326
358
|
|
327
|
-
|
328
|
-
expect(
|
359
|
+
obj.aasm_state = :running
|
360
|
+
expect(obj.aasm_state.to_sym).to eql :running
|
329
361
|
end
|
330
|
-
end
|
331
|
-
end # scopes
|
332
362
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
expect(obj.aasm_state.to_sym).to eql :pending
|
363
|
+
it "is forbidden if configured" do
|
364
|
+
obj = NoDirectAssignment.create
|
365
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
337
366
|
|
338
|
-
|
339
|
-
|
340
|
-
|
367
|
+
expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
|
368
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
369
|
+
end
|
341
370
|
|
342
|
-
|
343
|
-
|
344
|
-
|
371
|
+
it 'can be turned off and on again' do
|
372
|
+
obj = NoDirectAssignment.create
|
373
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
345
374
|
|
346
|
-
|
347
|
-
|
348
|
-
end
|
375
|
+
expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
|
376
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
349
377
|
|
350
|
-
|
351
|
-
|
352
|
-
|
378
|
+
# allow it temporarily
|
379
|
+
NoDirectAssignment.aasm.state_machine.config.no_direct_assignment = false
|
380
|
+
obj.aasm_state = :pending
|
381
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
353
382
|
|
354
|
-
|
355
|
-
|
383
|
+
# and forbid it again
|
384
|
+
NoDirectAssignment.aasm.state_machine.config.no_direct_assignment = true
|
385
|
+
expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
|
386
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
387
|
+
end
|
388
|
+
end # direct assignment
|
356
389
|
|
357
|
-
|
358
|
-
NoDirectAssignment.aasm.state_machine.config.no_direct_assignment = false
|
359
|
-
obj.aasm_state = :pending
|
360
|
-
expect(obj.aasm_state.to_sym).to eql :pending
|
390
|
+
describe 'initial states' do
|
361
391
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
392
|
+
it 'should support conditions' do
|
393
|
+
expect(Thief.new(:skilled => true).aasm.current_state).to eq(:rich)
|
394
|
+
expect(Thief.new(:skilled => false).aasm.current_state).to eq(:jailed)
|
395
|
+
end
|
366
396
|
end
|
367
|
-
end # direct assignment
|
368
397
|
|
369
|
-
describe '
|
398
|
+
describe 'transitions with persistence' do
|
370
399
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
400
|
+
it "should work for valid models" do
|
401
|
+
valid_object = Validator.create(:name => 'name')
|
402
|
+
expect(valid_object).to be_sleeping
|
403
|
+
valid_object.status = :running
|
404
|
+
expect(valid_object).to be_running
|
405
|
+
end
|
376
406
|
|
377
|
-
|
407
|
+
it 'should not store states for invalid models' do
|
408
|
+
validator = Validator.create(:name => 'name')
|
409
|
+
expect(validator).to be_valid
|
410
|
+
expect(validator).to be_sleeping
|
378
411
|
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
expect(valid_object).to be_running
|
384
|
-
end
|
412
|
+
validator.name = nil
|
413
|
+
expect(validator).not_to be_valid
|
414
|
+
expect { validator.run! }.to raise_error(ActiveRecord::RecordInvalid)
|
415
|
+
expect(validator).to be_sleeping
|
385
416
|
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
expect(validator).to be_sleeping
|
417
|
+
validator.reload
|
418
|
+
expect(validator).not_to be_running
|
419
|
+
expect(validator).to be_sleeping
|
390
420
|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
421
|
+
validator.name = 'another name'
|
422
|
+
expect(validator).to be_valid
|
423
|
+
expect(validator.run!).to be_truthy
|
424
|
+
expect(validator).to be_running
|
395
425
|
|
396
|
-
|
397
|
-
|
398
|
-
|
426
|
+
validator.reload
|
427
|
+
expect(validator).to be_running
|
428
|
+
expect(validator).not_to be_sleeping
|
429
|
+
end
|
399
430
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
431
|
+
it 'should not store states for invalid models silently if configured' do
|
432
|
+
validator = SilentPersistor.create(:name => 'name')
|
433
|
+
expect(validator).to be_valid
|
434
|
+
expect(validator).to be_sleeping
|
404
435
|
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
436
|
+
validator.name = nil
|
437
|
+
expect(validator).not_to be_valid
|
438
|
+
expect(validator.run!).to be_falsey
|
439
|
+
expect(validator).to be_sleeping
|
409
440
|
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
expect(validator).to be_sleeping
|
441
|
+
validator.reload
|
442
|
+
expect(validator).not_to be_running
|
443
|
+
expect(validator).to be_sleeping
|
414
444
|
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
445
|
+
validator.name = 'another name'
|
446
|
+
expect(validator).to be_valid
|
447
|
+
expect(validator.run!).to be_truthy
|
448
|
+
expect(validator).to be_running
|
419
449
|
|
420
|
-
|
421
|
-
|
422
|
-
|
450
|
+
validator.reload
|
451
|
+
expect(validator).to be_running
|
452
|
+
expect(validator).not_to be_sleeping
|
453
|
+
end
|
423
454
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
455
|
+
it 'should store states for invalid models if configured' do
|
456
|
+
persistor = InvalidPersistor.create(:name => 'name')
|
457
|
+
expect(persistor).to be_valid
|
458
|
+
expect(persistor).to be_sleeping
|
428
459
|
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
460
|
+
persistor.name = nil
|
461
|
+
expect(persistor).not_to be_valid
|
462
|
+
expect(persistor.run!).to be_truthy
|
463
|
+
expect(persistor).to be_running
|
433
464
|
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
persistor.name = nil
|
440
|
-
expect(persistor).not_to be_valid
|
441
|
-
expect(persistor.run!).to be_truthy
|
442
|
-
expect(persistor).to be_running
|
443
|
-
|
444
|
-
persistor = InvalidPersistor.find(persistor.id)
|
445
|
-
persistor.valid?
|
446
|
-
expect(persistor).to be_valid
|
447
|
-
expect(persistor).to be_running
|
448
|
-
expect(persistor).not_to be_sleeping
|
449
|
-
|
450
|
-
persistor.reload
|
451
|
-
expect(persistor).to be_running
|
452
|
-
expect(persistor).not_to be_sleeping
|
453
|
-
end
|
465
|
+
persistor = InvalidPersistor.find(persistor.id)
|
466
|
+
persistor.valid?
|
467
|
+
expect(persistor).to be_valid
|
468
|
+
expect(persistor).to be_running
|
469
|
+
expect(persistor).not_to be_sleeping
|
454
470
|
|
455
|
-
|
456
|
-
|
471
|
+
persistor.reload
|
472
|
+
expect(persistor).to be_running
|
473
|
+
expect(persistor).not_to be_sleeping
|
474
|
+
end
|
457
475
|
|
458
|
-
|
476
|
+
describe 'pessimistic locking' do
|
477
|
+
let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
|
459
478
|
|
460
|
-
|
461
|
-
let(:transactor) { NoLockTransactor.create!(:name => 'no_lock_transactor', :worker => worker) }
|
479
|
+
subject { transactor.run! }
|
462
480
|
|
463
|
-
|
464
|
-
|
465
|
-
|
481
|
+
context 'no lock' do
|
482
|
+
let(:transactor) { NoLockTransactor.create!(:name => 'no_lock_transactor', :worker => worker) }
|
483
|
+
|
484
|
+
it 'should not invoke lock!' do
|
485
|
+
expect(transactor).to_not receive(:lock!)
|
486
|
+
subject
|
487
|
+
end
|
466
488
|
end
|
467
|
-
end
|
468
489
|
|
469
|
-
|
470
|
-
|
490
|
+
context 'a default lock' do
|
491
|
+
let(:transactor) { LockTransactor.create!(:name => 'lock_transactor', :worker => worker) }
|
471
492
|
|
472
|
-
|
473
|
-
|
474
|
-
|
493
|
+
it 'should invoke lock! with true' do
|
494
|
+
expect(transactor).to receive(:lock!).with(true).and_call_original
|
495
|
+
subject
|
496
|
+
end
|
475
497
|
end
|
476
|
-
end
|
477
498
|
|
478
|
-
|
479
|
-
|
499
|
+
context 'a FOR UPDATE NOWAIT lock' do
|
500
|
+
let(:transactor) { LockNoWaitTransactor.create!(:name => 'lock_no_wait_transactor', :worker => worker) }
|
480
501
|
|
481
|
-
|
482
|
-
|
483
|
-
|
502
|
+
it 'should invoke lock! with FOR UPDATE NOWAIT' do
|
503
|
+
expect(transactor).to receive(:lock!).with('FOR UPDATE NOWAIT').and_call_original
|
504
|
+
subject
|
505
|
+
end
|
484
506
|
end
|
485
507
|
end
|
486
|
-
end
|
487
508
|
|
488
|
-
|
489
|
-
|
490
|
-
|
509
|
+
describe 'transactions' do
|
510
|
+
let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
|
511
|
+
let(:transactor) { Transactor.create!(:name => 'transactor', :worker => worker) }
|
491
512
|
|
492
|
-
|
493
|
-
expect(transactor).to be_sleeping
|
494
|
-
expect(worker.status).to eq('sleeping')
|
495
|
-
|
496
|
-
expect {transactor.run!}.to raise_error(StandardError, 'failed on purpose')
|
497
|
-
expect(transactor).to be_running
|
498
|
-
expect(worker.reload.status).to eq('sleeping')
|
499
|
-
end
|
500
|
-
|
501
|
-
context "nested transactions" do
|
502
|
-
it "should rollback all changes in nested transaction" do
|
513
|
+
it 'should rollback all changes' do
|
503
514
|
expect(transactor).to be_sleeping
|
504
515
|
expect(worker.status).to eq('sleeping')
|
505
516
|
|
506
|
-
|
507
|
-
expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
|
508
|
-
end
|
509
|
-
|
517
|
+
expect {transactor.run!}.to raise_error(StandardError, 'failed on purpose')
|
510
518
|
expect(transactor).to be_running
|
511
519
|
expect(worker.reload.status).to eq('sleeping')
|
512
520
|
end
|
513
521
|
|
514
|
-
|
515
|
-
|
516
|
-
|
522
|
+
context "nested transactions" do
|
523
|
+
it "should rollback all changes in nested transaction" do
|
524
|
+
expect(transactor).to be_sleeping
|
525
|
+
expect(worker.status).to eq('sleeping')
|
517
526
|
|
518
|
-
|
519
|
-
|
527
|
+
Worker.transaction do
|
528
|
+
expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
|
529
|
+
end
|
520
530
|
|
521
|
-
|
522
|
-
expect
|
531
|
+
expect(transactor).to be_running
|
532
|
+
expect(worker.reload.status).to eq('sleeping')
|
523
533
|
end
|
524
534
|
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
end
|
535
|
+
it "should only rollback changes in the main transaction not the nested one" do
|
536
|
+
# change configuration to not require new transaction
|
537
|
+
AASM::StateMachineStore[Transactor][:default].config.requires_new_transaction = false
|
529
538
|
|
530
|
-
|
531
|
-
|
532
|
-
validator = Validator.create(:name => 'name')
|
533
|
-
expect(validator).to be_sleeping
|
539
|
+
expect(transactor).to be_sleeping
|
540
|
+
expect(worker.status).to eq('sleeping')
|
534
541
|
|
535
|
-
|
536
|
-
|
537
|
-
|
542
|
+
Worker.transaction do
|
543
|
+
expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
|
544
|
+
end
|
538
545
|
|
539
|
-
|
540
|
-
|
541
|
-
|
546
|
+
expect(transactor).to be_running
|
547
|
+
expect(worker.reload.status).to eq('running')
|
548
|
+
end
|
542
549
|
end
|
543
550
|
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
end
|
551
|
+
describe "after_commit callback" do
|
552
|
+
it "should fire :after_commit if transaction was successful" do
|
553
|
+
validator = Validator.create(:name => 'name')
|
554
|
+
expect(validator).to be_sleeping
|
549
555
|
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
expect { validator.run! }.to raise_error(ActiveRecord::RecordInvalid, 'Invalid record')
|
554
|
-
expect(validator).to be_sleeping
|
555
|
-
expect(validator.name).to eq("name")
|
556
|
-
end
|
556
|
+
validator.run!
|
557
|
+
expect(validator).to be_running
|
558
|
+
expect(validator.name).to eq("name changed")
|
557
559
|
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
expect(validator).to be_running
|
563
|
-
expect(validator.name).to eq("name")
|
564
|
-
end
|
565
|
-
end
|
566
|
-
|
567
|
-
describe 'before and after transaction callbacks' do
|
568
|
-
[:after, :before].each do |event_type|
|
569
|
-
describe "#{event_type}_transaction callback" do
|
570
|
-
it "should fire :#{event_type}_transaction if transaction was successful" do
|
571
|
-
validator = Validator.create(:name => 'name')
|
572
|
-
expect(validator).to be_sleeping
|
560
|
+
validator.sleep!("sleeper")
|
561
|
+
expect(validator).to be_sleeping
|
562
|
+
expect(validator.name).to eq("sleeper")
|
563
|
+
end
|
573
564
|
|
574
|
-
|
575
|
-
|
576
|
-
|
565
|
+
it "should not fire :after_commit if transaction failed" do
|
566
|
+
validator = Validator.create(:name => 'name')
|
567
|
+
expect { validator.fail! }.to raise_error(StandardError, 'failed on purpose')
|
568
|
+
expect(validator.name).to eq("name")
|
569
|
+
end
|
577
570
|
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
end.to change { validator.send("#{event_type}_transaction_performed_on_fail") }.from(nil).to(true)
|
586
|
-
expect(validator).to_not be_running
|
587
|
-
end
|
571
|
+
it "should not fire :after_commit if validation failed when saving object" do
|
572
|
+
validator = Validator.create(:name => 'name')
|
573
|
+
validator.invalid = true
|
574
|
+
expect { validator.run! }.to raise_error(ActiveRecord::RecordInvalid, 'Invalid record')
|
575
|
+
expect(validator).to be_sleeping
|
576
|
+
expect(validator.name).to eq("name")
|
577
|
+
end
|
588
578
|
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
end
|
579
|
+
it "should not fire if not saving" do
|
580
|
+
validator = Validator.create(:name => 'name')
|
581
|
+
expect(validator).to be_sleeping
|
582
|
+
validator.run
|
583
|
+
expect(validator).to be_running
|
584
|
+
expect(validator.name).to eq("name")
|
596
585
|
end
|
597
586
|
end
|
598
|
-
end
|
599
|
-
|
600
|
-
describe 'before and after all transactions callbacks' do
|
601
|
-
[:after, :before].each do |event_type|
|
602
|
-
describe "#{event_type}_all_transactions callback" do
|
603
|
-
it "should fire :#{event_type}_all_transactions if transaction was successful" do
|
604
|
-
validator = Validator.create(:name => 'name')
|
605
|
-
expect(validator).to be_sleeping
|
606
587
|
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
588
|
+
describe 'before and after transaction callbacks' do
|
589
|
+
[:after, :before].each do |event_type|
|
590
|
+
describe "#{event_type}_transaction callback" do
|
591
|
+
it "should fire :#{event_type}_transaction if transaction was successful" do
|
592
|
+
validator = Validator.create(:name => 'name')
|
593
|
+
expect(validator).to be_sleeping
|
594
|
+
|
595
|
+
expect { validator.run! }.to change { validator.send("#{event_type}_transaction_performed_on_run") }.from(nil).to(true)
|
596
|
+
expect(validator).to be_running
|
597
|
+
end
|
598
|
+
|
599
|
+
it "should fire :#{event_type}_transaction if transaction failed" do
|
600
|
+
validator = Validator.create(:name => 'name')
|
601
|
+
expect do
|
602
|
+
begin
|
603
|
+
validator.fail!
|
604
|
+
rescue => ignored
|
605
|
+
end
|
606
|
+
end.to change { validator.send("#{event_type}_transaction_performed_on_fail") }.from(nil).to(true)
|
607
|
+
expect(validator).to_not be_running
|
608
|
+
end
|
609
|
+
|
610
|
+
it "should not fire :#{event_type}_transaction if not saving" do
|
611
|
+
validator = Validator.create(:name => 'name')
|
612
|
+
expect(validator).to be_sleeping
|
613
|
+
expect { validator.run }.to_not change { validator.send("#{event_type}_transaction_performed_on_run") }
|
614
|
+
expect(validator).to be_running
|
615
|
+
expect(validator.name).to eq("name")
|
616
|
+
end
|
620
617
|
end
|
618
|
+
end
|
619
|
+
end
|
621
620
|
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
621
|
+
describe 'before and after all transactions callbacks' do
|
622
|
+
[:after, :before].each do |event_type|
|
623
|
+
describe "#{event_type}_all_transactions callback" do
|
624
|
+
it "should fire :#{event_type}_all_transactions if transaction was successful" do
|
625
|
+
validator = Validator.create(:name => 'name')
|
626
|
+
expect(validator).to be_sleeping
|
627
|
+
|
628
|
+
expect { validator.run! }.to change { validator.send("#{event_type}_all_transactions_performed") }.from(nil).to(true)
|
629
|
+
expect(validator).to be_running
|
630
|
+
end
|
631
|
+
|
632
|
+
it "should fire :#{event_type}_all_transactions if transaction failed" do
|
633
|
+
validator = Validator.create(:name => 'name')
|
634
|
+
expect do
|
635
|
+
begin
|
636
|
+
validator.fail!
|
637
|
+
rescue => ignored
|
638
|
+
end
|
639
|
+
end.to change { validator.send("#{event_type}_all_transactions_performed") }.from(nil).to(true)
|
640
|
+
expect(validator).to_not be_running
|
641
|
+
end
|
642
|
+
|
643
|
+
it "should not fire :#{event_type}_all_transactions if not saving" do
|
644
|
+
validator = Validator.create(:name => 'name')
|
645
|
+
expect(validator).to be_sleeping
|
646
|
+
expect { validator.run }.to_not change { validator.send("#{event_type}_all_transactions_performed") }
|
647
|
+
expect(validator).to be_running
|
648
|
+
expect(validator.name).to eq("name")
|
649
|
+
end
|
628
650
|
end
|
629
651
|
end
|
630
652
|
end
|
631
|
-
end
|
632
653
|
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
654
|
+
context "when not persisting" do
|
655
|
+
it 'should not rollback all changes' do
|
656
|
+
expect(transactor).to be_sleeping
|
657
|
+
expect(worker.status).to eq('sleeping')
|
637
658
|
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
659
|
+
# Notice here we're calling "run" and not "run!" with a bang.
|
660
|
+
expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
|
661
|
+
expect(transactor).to be_running
|
662
|
+
expect(worker.reload.status).to eq('running')
|
663
|
+
end
|
643
664
|
|
644
|
-
|
645
|
-
|
646
|
-
|
665
|
+
it 'should not create a database transaction' do
|
666
|
+
expect(transactor.class).not_to receive(:transaction)
|
667
|
+
expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
|
668
|
+
end
|
647
669
|
end
|
648
670
|
end
|
649
671
|
end
|
650
|
-
end
|
651
672
|
|
652
|
-
describe "invalid states with persistence" do
|
673
|
+
describe "invalid states with persistence" do
|
653
674
|
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
675
|
+
it "should not store states" do
|
676
|
+
validator = Validator.create(:name => 'name')
|
677
|
+
validator.status = 'invalid_state'
|
678
|
+
expect(validator.save).to be_falsey
|
679
|
+
expect {validator.save!}.to raise_error(ActiveRecord::RecordInvalid)
|
659
680
|
|
660
|
-
|
661
|
-
|
662
|
-
|
681
|
+
validator.reload
|
682
|
+
expect(validator).to be_sleeping
|
683
|
+
end
|
663
684
|
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
685
|
+
it "should store invalid states if configured" do
|
686
|
+
persistor = InvalidPersistor.create(:name => 'name')
|
687
|
+
persistor.status = 'invalid_state'
|
688
|
+
expect(persistor.save).to be_truthy
|
668
689
|
|
669
|
-
|
670
|
-
|
671
|
-
|
690
|
+
persistor.reload
|
691
|
+
expect(persistor.status).to eq('invalid_state')
|
692
|
+
end
|
672
693
|
|
673
|
-
end
|
694
|
+
end
|
674
695
|
|
675
|
-
describe 'basic example with two state machines' do
|
676
|
-
|
696
|
+
describe 'basic example with two state machines' do
|
697
|
+
let(:example) { BasicActiveRecordTwoStateMachinesExample.new }
|
677
698
|
|
678
|
-
|
679
|
-
|
680
|
-
|
699
|
+
it 'should initialise properly' do
|
700
|
+
expect(example.aasm(:search).current_state).to eql :initialised
|
701
|
+
expect(example.aasm(:sync).current_state).to eql :unsynced
|
702
|
+
end
|
681
703
|
end
|
682
|
-
end
|
683
704
|
|
684
|
-
describe 'testing the README examples' do
|
685
|
-
|
686
|
-
|
705
|
+
describe 'testing the README examples' do
|
706
|
+
it 'Usage' do
|
707
|
+
job = ReadmeJob.new
|
687
708
|
|
688
|
-
|
689
|
-
|
709
|
+
expect(job.sleeping?).to eql true
|
710
|
+
expect(job.may_run?).to eql true
|
690
711
|
|
691
|
-
|
712
|
+
job.run
|
692
713
|
|
693
|
-
|
694
|
-
|
695
|
-
|
714
|
+
expect(job.running?).to eql true
|
715
|
+
expect(job.sleeping?).to eql false
|
716
|
+
expect(job.may_run?).to eql false
|
696
717
|
|
697
|
-
|
718
|
+
expect { job.run }.to raise_error(AASM::InvalidTransition)
|
719
|
+
end
|
698
720
|
end
|
699
721
|
end
|