aasm 3.0.24 → 3.4.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/.gitignore +6 -0
- data/.travis.yml +29 -4
- data/CHANGELOG.md +56 -0
- data/Gemfile +10 -1
- data/LICENSE +1 -1
- data/README.md +151 -20
- data/aasm.gemspec +5 -6
- data/gemfiles/rails_3.2.gemfile +13 -0
- data/gemfiles/rails_4.0.gemfile +16 -0
- data/gemfiles/rails_4.1.gemfile +16 -0
- data/lib/aasm/aasm.rb +36 -32
- data/lib/aasm/base.rb +49 -31
- data/lib/aasm/event.rb +28 -17
- data/lib/aasm/instance_base.rb +9 -4
- data/lib/aasm/localizer.rb +1 -1
- data/lib/aasm/persistence/active_record_persistence.rb +65 -16
- data/lib/aasm/persistence/base.rb +10 -14
- data/lib/aasm/persistence/mongoid_persistence.rb +10 -8
- data/lib/aasm/persistence/sequel_persistence.rb +108 -0
- data/lib/aasm/persistence.rb +3 -0
- data/lib/aasm/state.rb +4 -3
- data/lib/aasm/state_machine.rb +18 -10
- data/lib/aasm/transition.rb +13 -6
- data/lib/aasm/version.rb +1 -1
- data/lib/aasm.rb +0 -3
- data/spec/database.rb +33 -0
- data/spec/models/double_definer.rb +21 -0
- data/spec/models/foo.rb +2 -1
- data/spec/models/guardian.rb +48 -0
- data/spec/models/mongoid/no_scope_mongoid.rb +1 -1
- data/spec/models/mongoid/simple_mongoid.rb +5 -4
- data/spec/models/mongoid/simple_new_dsl_mongoid.rb +1 -1
- data/spec/models/not_auto_loaded/process.rb +10 -8
- data/spec/models/persistence.rb +5 -13
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/api_spec.rb +12 -12
- data/spec/unit/callbacks_spec.rb +29 -45
- data/spec/unit/complex_example_spec.rb +24 -15
- data/spec/unit/event_naming_spec.rb +24 -0
- data/spec/unit/event_spec.rb +124 -76
- data/spec/unit/guard_spec.rb +60 -0
- data/spec/unit/initial_state_spec.rb +4 -5
- data/spec/unit/inspection_spec.rb +42 -53
- data/spec/unit/localizer_spec.rb +22 -18
- data/spec/unit/memory_leak_spec.rb +2 -2
- data/spec/unit/new_dsl_spec.rb +2 -2
- data/spec/unit/persistence/active_record_persistence_spec.rb +357 -89
- data/spec/unit/persistence/mongoid_persistance_spec.rb +102 -81
- data/spec/unit/persistence/sequel_persistence_spec.rb +103 -0
- data/spec/unit/reloading_spec.rb +15 -0
- data/spec/unit/simple_example_spec.rb +20 -21
- data/spec/unit/state_spec.rb +16 -16
- data/spec/unit/subclassing_spec.rb +8 -8
- data/spec/unit/transition_spec.rb +59 -44
- metadata +38 -96
- data/lib/aasm/deprecated/aasm.rb +0 -15
- data/spec/models/callback_old_dsl.rb +0 -41
- data/spec/schema.rb +0 -35
@@ -9,8 +9,8 @@ load_schema
|
|
9
9
|
|
10
10
|
shared_examples_for "aasm model" do
|
11
11
|
it "should include persistence mixins" do
|
12
|
-
klass.included_modules.
|
13
|
-
klass.included_modules.
|
12
|
+
expect(klass.included_modules).to be_include(AASM::Persistence::ActiveRecordPersistence)
|
13
|
+
expect(klass.included_modules).to be_include(AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -18,40 +18,266 @@ describe "instance methods" do
|
|
18
18
|
let(:gate) {Gate.new}
|
19
19
|
|
20
20
|
it "should respond to aasm persistence methods" do
|
21
|
-
gate.
|
22
|
-
gate.
|
23
|
-
gate.
|
21
|
+
expect(gate).to respond_to(:aasm_read_state)
|
22
|
+
expect(gate).to respond_to(:aasm_write_state)
|
23
|
+
expect(gate).to respond_to(:aasm_write_state_without_persistence)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "aasm_column_looks_like_enum" do
|
27
|
+
subject { lambda{ gate.send(:aasm_column_looks_like_enum) } }
|
28
|
+
|
29
|
+
let(:column_name) { "value" }
|
30
|
+
let(:columns_hash) { Hash[column_name, column] }
|
31
|
+
|
32
|
+
before :each do
|
33
|
+
gate.class.stub(:aasm_column).and_return(column_name.to_sym)
|
34
|
+
gate.class.stub(:columns_hash).and_return(columns_hash)
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when AASM column has integer type" do
|
38
|
+
let(:column) { double(Object, type: :integer) }
|
39
|
+
|
40
|
+
it "returns true" do
|
41
|
+
expect(subject.call).to be_true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when AASM column has string type" do
|
46
|
+
let(:column) { double(Object, type: :string) }
|
47
|
+
|
48
|
+
it "returns false" do
|
49
|
+
expect(subject.call).to be_false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "aasm_guess_enum_method" do
|
55
|
+
subject { lambda{ gate.send(:aasm_guess_enum_method) } }
|
56
|
+
|
57
|
+
before :each do
|
58
|
+
gate.class.stub(:aasm_column).and_return(:value)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "pluralizes AASM column name" do
|
62
|
+
expect(subject.call).to eq :values
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "aasm_enum" do
|
67
|
+
subject { lambda{ gate.send(:aasm_enum) } }
|
68
|
+
|
69
|
+
context "when AASM enum setting contains an explicit enum method name" do
|
70
|
+
let(:enum) { :test }
|
71
|
+
|
72
|
+
before :each do
|
73
|
+
AASM::StateMachine[Gate].config.stub(:enum).and_return(enum)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "returns whatever value was set in AASM config" do
|
77
|
+
expect(subject.call).to eq enum
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when AASM enum setting is simply set to true" do
|
82
|
+
before :each do
|
83
|
+
AASM::StateMachine[Gate].config.stub(:enum).and_return(true)
|
84
|
+
Gate.stub(:aasm_column).and_return(:value)
|
85
|
+
gate.stub(:aasm_guess_enum_method).and_return(:values)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "infers enum method name from pluralized column name" do
|
89
|
+
expect(subject.call).to eq :values
|
90
|
+
expect(gate).to have_received :aasm_guess_enum_method
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "when AASM enum setting is explicitly disabled" do
|
95
|
+
before :each do
|
96
|
+
AASM::StateMachine[Gate].config.stub(:enum).and_return(false)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "returns nil" do
|
100
|
+
expect(subject.call).to be_nil
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context "when AASM enum setting is not enabled" do
|
105
|
+
before :each do
|
106
|
+
AASM::StateMachine[Gate].config.stub(:enum).and_return(nil)
|
107
|
+
Gate.stub(:aasm_column).and_return(:value)
|
108
|
+
end
|
109
|
+
|
110
|
+
context "when AASM column looks like enum" do
|
111
|
+
before :each do
|
112
|
+
gate.stub(:aasm_column_looks_like_enum).and_return(true)
|
113
|
+
gate.stub(:aasm_guess_enum_method).and_return(:values)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "infers enum method name from pluralized column name" do
|
117
|
+
expect(subject.call).to eq :values
|
118
|
+
expect(gate).to have_received :aasm_guess_enum_method
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "when AASM column doesn't look like enum'" do
|
123
|
+
before :each do
|
124
|
+
gate.stub(:aasm_column_looks_like_enum)
|
125
|
+
.and_return(false)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "returns nil, as we're not using enum" do
|
129
|
+
expect(subject.call).to be_nil
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context "when AASM is configured to use enum" do
|
136
|
+
let(:state_sym) { :running }
|
137
|
+
let(:state_code) { 2 }
|
138
|
+
let(:enum_name) { :states }
|
139
|
+
let(:enum) { Hash[state_sym, state_code] }
|
140
|
+
|
141
|
+
before :each do
|
142
|
+
gate
|
143
|
+
.stub(:aasm_enum)
|
144
|
+
.and_return(enum_name)
|
145
|
+
gate.stub(:aasm_write_attribute)
|
146
|
+
gate.stub(:write_attribute)
|
147
|
+
|
148
|
+
gate
|
149
|
+
.class
|
150
|
+
.stub(enum_name)
|
151
|
+
.and_return(enum)
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "aasm_write_state" do
|
155
|
+
context "when AASM is configured to skip validations on save" do
|
156
|
+
before :each do
|
157
|
+
gate
|
158
|
+
.stub(:aasm_skipping_validations)
|
159
|
+
.and_return(true)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "passes state code instead of state symbol to update_all" do
|
163
|
+
# stub_chain does not allow us to give expectations on call
|
164
|
+
# parameters in the middle of the chain, so we need to use
|
165
|
+
# intermediate object instead.
|
166
|
+
obj = double(Object, update_all: 1)
|
167
|
+
gate
|
168
|
+
.class
|
169
|
+
.stub(:where)
|
170
|
+
.and_return(obj)
|
171
|
+
|
172
|
+
gate.aasm_write_state state_sym
|
173
|
+
|
174
|
+
expect(obj).to have_received(:update_all)
|
175
|
+
.with(Hash[gate.class.aasm_column, state_code])
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
context "when AASM is not skipping validations" do
|
180
|
+
it "delegates state update to the helper method" do
|
181
|
+
# Let's pretend that validation is passed
|
182
|
+
gate.stub(:save).and_return(true)
|
183
|
+
|
184
|
+
gate.aasm_write_state state_sym
|
185
|
+
|
186
|
+
expect(gate).to have_received(:aasm_write_attribute).with(state_sym)
|
187
|
+
expect(gate).to_not have_received :write_attribute
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe "aasm_write_state_without_persistence" do
|
193
|
+
it "delegates state update to the helper method" do
|
194
|
+
gate.aasm_write_state_without_persistence state_sym
|
195
|
+
|
196
|
+
expect(gate).to have_received(:aasm_write_attribute).with(state_sym)
|
197
|
+
expect(gate).to_not have_received :write_attribute
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe "aasm_raw_attribute_value" do
|
202
|
+
it "converts state symbol to state code" do
|
203
|
+
expect(gate.send(:aasm_raw_attribute_value, state_sym))
|
204
|
+
.to eq state_code
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
context "when AASM is configured to use string field" do
|
210
|
+
let(:state_sym) { :running }
|
211
|
+
|
212
|
+
before :each do
|
213
|
+
gate
|
214
|
+
.stub(:aasm_enum)
|
215
|
+
.and_return(nil)
|
216
|
+
end
|
217
|
+
|
218
|
+
describe "aasm_raw_attribute_value" do
|
219
|
+
it "converts state symbol to string" do
|
220
|
+
expect(gate.send(:aasm_raw_attribute_value, state_sym))
|
221
|
+
.to eq state_sym.to_s
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe "aasm_write_attribute helper method" do
|
227
|
+
let(:sym) { :sym }
|
228
|
+
let(:value) { 42 }
|
229
|
+
|
230
|
+
before :each do
|
231
|
+
gate.stub(:write_attribute)
|
232
|
+
gate.stub(:aasm_raw_attribute_value)
|
233
|
+
.and_return(value)
|
234
|
+
|
235
|
+
gate.send(:aasm_write_attribute, sym)
|
236
|
+
end
|
237
|
+
|
238
|
+
it "generates attribute value using a helper method" do
|
239
|
+
expect(gate).to have_received(:aasm_raw_attribute_value).with(sym)
|
240
|
+
end
|
241
|
+
|
242
|
+
it "writes attribute to the model" do
|
243
|
+
expect(gate).to have_received(:write_attribute).with(:aasm_state, value)
|
244
|
+
end
|
24
245
|
end
|
25
246
|
|
26
247
|
it "should return the initial state when new and the aasm field is nil" do
|
27
|
-
gate.
|
248
|
+
expect(gate.aasm.current_state).to eq(:opened)
|
28
249
|
end
|
29
250
|
|
30
251
|
it "should return the aasm column when new and the aasm field is not nil" do
|
31
252
|
gate.aasm_state = "closed"
|
32
|
-
gate.
|
253
|
+
expect(gate.aasm.current_state).to eq(:closed)
|
33
254
|
end
|
34
255
|
|
35
256
|
it "should return the aasm column when not new and the aasm_column is not nil" do
|
36
|
-
gate.
|
257
|
+
allow(gate).to receive(:new_record?).and_return(false)
|
37
258
|
gate.aasm_state = "state"
|
38
|
-
gate.
|
259
|
+
expect(gate.aasm.current_state).to eq(:state)
|
39
260
|
end
|
40
261
|
|
41
262
|
it "should allow a nil state" do
|
42
|
-
gate.
|
263
|
+
allow(gate).to receive(:new_record?).and_return(false)
|
43
264
|
gate.aasm_state = nil
|
44
|
-
gate.
|
265
|
+
expect(gate.aasm.current_state).to be_nil
|
45
266
|
end
|
46
267
|
|
47
268
|
it "should call aasm_ensure_initial_state on validation before create" do
|
48
|
-
gate.
|
269
|
+
expect(gate).to receive(:aasm_ensure_initial_state).and_return(true)
|
49
270
|
gate.valid?
|
50
271
|
end
|
51
272
|
|
273
|
+
it "should call aasm_ensure_initial_state before create, even if skipping validations" do
|
274
|
+
expect(gate).to receive(:aasm_ensure_initial_state).and_return(true)
|
275
|
+
gate.save(:validate => false)
|
276
|
+
end
|
277
|
+
|
52
278
|
it "should not call aasm_ensure_initial_state on validation before update" do
|
53
|
-
gate.
|
54
|
-
gate.
|
279
|
+
allow(gate).to receive(:new_record?).and_return(false)
|
280
|
+
expect(gate).not_to receive(:aasm_ensure_initial_state)
|
55
281
|
gate.valid?
|
56
282
|
end
|
57
283
|
|
@@ -59,59 +285,36 @@ end
|
|
59
285
|
|
60
286
|
describe 'subclasses' do
|
61
287
|
it "should have the same states as its parent class" do
|
62
|
-
|
288
|
+
expect(DerivateNewDsl.aasm.states).to eq(SimpleNewDsl.aasm.states)
|
63
289
|
end
|
64
290
|
|
65
291
|
it "should have the same events as its parent class" do
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
it "should have the same column as its parent class" do
|
70
|
-
Derivate.aasm_column.should == :status
|
292
|
+
expect(DerivateNewDsl.aasm.events).to eq(SimpleNewDsl.aasm.events)
|
71
293
|
end
|
72
294
|
|
73
295
|
it "should have the same column as its parent even for the new dsl" do
|
74
|
-
SimpleNewDsl.aasm_column.
|
75
|
-
DerivateNewDsl.aasm_column.
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe "named scopes with the old DSL" do
|
80
|
-
|
81
|
-
context "Does not already respond_to? the scope name" do
|
82
|
-
it "should add a scope" do
|
83
|
-
Simple.should respond_to(:unknown_scope)
|
84
|
-
SimpleNewDsl.unknown_scope.is_a?(ActiveRecord::Relation).should be_true
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
context "Already respond_to? the scope name" do
|
89
|
-
it "should not add a scope" do
|
90
|
-
Simple.should respond_to(:new)
|
91
|
-
Simple.new.class.should == Simple
|
92
|
-
end
|
296
|
+
expect(SimpleNewDsl.aasm_column).to eq(:status)
|
297
|
+
expect(DerivateNewDsl.aasm_column).to eq(:status)
|
93
298
|
end
|
94
|
-
|
95
299
|
end
|
96
300
|
|
97
301
|
describe "named scopes with the new DSL" do
|
98
|
-
|
99
302
|
context "Does not already respond_to? the scope name" do
|
100
303
|
it "should add a scope" do
|
101
|
-
SimpleNewDsl.
|
102
|
-
SimpleNewDsl.unknown_scope.is_a?(ActiveRecord::Relation).
|
304
|
+
expect(SimpleNewDsl).to respond_to(:unknown_scope)
|
305
|
+
expect(SimpleNewDsl.unknown_scope.is_a?(ActiveRecord::Relation)).to be_true
|
103
306
|
end
|
104
307
|
end
|
105
308
|
|
106
309
|
context "Already respond_to? the scope name" do
|
107
310
|
it "should not add a scope" do
|
108
|
-
SimpleNewDsl.
|
109
|
-
SimpleNewDsl.new.class.
|
311
|
+
expect(SimpleNewDsl).to respond_to(:new)
|
312
|
+
expect(SimpleNewDsl.new.class).to eq(SimpleNewDsl)
|
110
313
|
end
|
111
314
|
end
|
112
315
|
|
113
316
|
it "does not create scopes if requested" do
|
114
|
-
NoScope.
|
317
|
+
expect(NoScope).not_to respond_to(:ignored_scope)
|
115
318
|
end
|
116
319
|
|
117
320
|
end
|
@@ -119,8 +322,8 @@ end
|
|
119
322
|
describe 'initial states' do
|
120
323
|
|
121
324
|
it 'should support conditions' do
|
122
|
-
Thief.new(:skilled => true).
|
123
|
-
Thief.new(:skilled => false).
|
325
|
+
expect(Thief.new(:skilled => true).aasm.current_state).to eq(:rich)
|
326
|
+
expect(Thief.new(:skilled => false).aasm.current_state).to eq(:jailed)
|
124
327
|
end
|
125
328
|
end
|
126
329
|
|
@@ -128,54 +331,54 @@ describe 'transitions with persistence' do
|
|
128
331
|
|
129
332
|
it "should work for valid models" do
|
130
333
|
valid_object = Validator.create(:name => 'name')
|
131
|
-
valid_object.
|
334
|
+
expect(valid_object).to be_sleeping
|
132
335
|
valid_object.status = :running
|
133
|
-
valid_object.
|
336
|
+
expect(valid_object).to be_running
|
134
337
|
end
|
135
338
|
|
136
339
|
it 'should not store states for invalid models' do
|
137
340
|
validator = Validator.create(:name => 'name')
|
138
|
-
validator.
|
139
|
-
validator.
|
341
|
+
expect(validator).to be_valid
|
342
|
+
expect(validator).to be_sleeping
|
140
343
|
|
141
344
|
validator.name = nil
|
142
|
-
validator.
|
143
|
-
validator.run
|
144
|
-
validator.
|
345
|
+
expect(validator).not_to be_valid
|
346
|
+
expect(validator.run!).to be_false
|
347
|
+
expect(validator).to be_sleeping
|
145
348
|
|
146
349
|
validator.reload
|
147
|
-
validator.
|
148
|
-
validator.
|
350
|
+
expect(validator).not_to be_running
|
351
|
+
expect(validator).to be_sleeping
|
149
352
|
|
150
353
|
validator.name = 'another name'
|
151
|
-
validator.
|
152
|
-
validator.run
|
153
|
-
validator.
|
354
|
+
expect(validator).to be_valid
|
355
|
+
expect(validator.run!).to be_true
|
356
|
+
expect(validator).to be_running
|
154
357
|
|
155
358
|
validator.reload
|
156
|
-
validator.
|
157
|
-
validator.
|
359
|
+
expect(validator).to be_running
|
360
|
+
expect(validator).not_to be_sleeping
|
158
361
|
end
|
159
362
|
|
160
363
|
it 'should store states for invalid models if configured' do
|
161
364
|
persistor = InvalidPersistor.create(:name => 'name')
|
162
|
-
persistor.
|
163
|
-
persistor.
|
365
|
+
expect(persistor).to be_valid
|
366
|
+
expect(persistor).to be_sleeping
|
164
367
|
|
165
368
|
persistor.name = nil
|
166
|
-
persistor.
|
167
|
-
persistor.run
|
168
|
-
persistor.
|
369
|
+
expect(persistor).not_to be_valid
|
370
|
+
expect(persistor.run!).to be_true
|
371
|
+
expect(persistor).to be_running
|
169
372
|
|
170
373
|
persistor = InvalidPersistor.find(persistor.id)
|
171
374
|
persistor.valid?
|
172
|
-
persistor.
|
173
|
-
persistor.
|
174
|
-
persistor.
|
375
|
+
expect(persistor).to be_valid
|
376
|
+
expect(persistor).to be_running
|
377
|
+
expect(persistor).not_to be_sleeping
|
175
378
|
|
176
379
|
persistor.reload
|
177
|
-
persistor.
|
178
|
-
persistor.
|
380
|
+
expect(persistor).to be_running
|
381
|
+
expect(persistor).not_to be_sleeping
|
179
382
|
end
|
180
383
|
|
181
384
|
describe 'transactions' do
|
@@ -183,41 +386,106 @@ describe 'transitions with persistence' do
|
|
183
386
|
let(:transactor) { Transactor.create!(:name => 'transactor', :worker => worker) }
|
184
387
|
|
185
388
|
it 'should rollback all changes' do
|
186
|
-
transactor.
|
187
|
-
worker.status.
|
389
|
+
expect(transactor).to be_sleeping
|
390
|
+
expect(worker.status).to eq('sleeping')
|
188
391
|
|
189
|
-
|
190
|
-
transactor.
|
191
|
-
worker.reload.status.
|
392
|
+
expect {transactor.run!}.to raise_error(StandardError, 'failed on purpose')
|
393
|
+
expect(transactor).to be_running
|
394
|
+
expect(worker.reload.status).to eq('sleeping')
|
192
395
|
end
|
193
396
|
|
194
|
-
|
195
|
-
|
196
|
-
|
397
|
+
context "nested transactions" do
|
398
|
+
it "should rollback all changes in nested transaction" do
|
399
|
+
expect(transactor).to be_sleeping
|
400
|
+
expect(worker.status).to eq('sleeping')
|
197
401
|
|
198
|
-
|
199
|
-
|
402
|
+
Worker.transaction do
|
403
|
+
expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
|
404
|
+
end
|
405
|
+
|
406
|
+
expect(transactor).to be_running
|
407
|
+
expect(worker.reload.status).to eq('sleeping')
|
200
408
|
end
|
201
409
|
|
202
|
-
|
203
|
-
|
410
|
+
it "should only rollback changes in the main transaction not the nested one" do
|
411
|
+
# change configuration to not require new transaction
|
412
|
+
AASM::StateMachine[Transactor].config.requires_new_transaction = false
|
413
|
+
|
414
|
+
expect(transactor).to be_sleeping
|
415
|
+
expect(worker.status).to eq('sleeping')
|
416
|
+
|
417
|
+
Worker.transaction do
|
418
|
+
expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
|
419
|
+
end
|
420
|
+
|
421
|
+
expect(transactor).to be_running
|
422
|
+
expect(worker.reload.status).to eq('running')
|
423
|
+
end
|
204
424
|
end
|
205
425
|
|
206
426
|
describe "after_commit callback" do
|
207
427
|
it "should fire :after_commit if transaction was successful" do
|
208
428
|
validator = Validator.create(:name => 'name')
|
209
|
-
validator.
|
429
|
+
expect(validator).to be_sleeping
|
210
430
|
validator.run!
|
211
|
-
validator.
|
212
|
-
validator.name.
|
431
|
+
expect(validator).to be_running
|
432
|
+
expect(validator.name).not_to eq("name")
|
213
433
|
end
|
214
434
|
|
215
435
|
it "should not fire :after_commit if transaction failed" do
|
216
436
|
validator = Validator.create(:name => 'name')
|
217
|
-
|
218
|
-
validator.name.
|
437
|
+
expect { validator.fail! }.to raise_error(StandardError, 'failed on purpose')
|
438
|
+
expect(validator.name).to eq("name")
|
439
|
+
end
|
440
|
+
|
441
|
+
it "should not fire if not saving" do
|
442
|
+
validator = Validator.create(:name => 'name')
|
443
|
+
expect(validator).to be_sleeping
|
444
|
+
validator.run
|
445
|
+
expect(validator).to be_running
|
446
|
+
expect(validator.name).to eq("name")
|
219
447
|
end
|
220
448
|
|
221
449
|
end
|
450
|
+
|
451
|
+
context "when not persisting" do
|
452
|
+
it 'should not rollback all changes' do
|
453
|
+
expect(transactor).to be_sleeping
|
454
|
+
expect(worker.status).to eq('sleeping')
|
455
|
+
|
456
|
+
# Notice here we're calling "run" and not "run!" with a bang.
|
457
|
+
expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
|
458
|
+
expect(transactor).to be_running
|
459
|
+
expect(worker.reload.status).to eq('running')
|
460
|
+
end
|
461
|
+
|
462
|
+
it 'should not create a database transaction' do
|
463
|
+
expect(transactor.class).not_to receive(:transaction)
|
464
|
+
expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
|
465
|
+
end
|
466
|
+
end
|
222
467
|
end
|
223
468
|
end
|
469
|
+
|
470
|
+
describe "invalid states with persistence" do
|
471
|
+
|
472
|
+
it "should not store states" do
|
473
|
+
validator = Validator.create(:name => 'name')
|
474
|
+
validator.status = 'invalid_state'
|
475
|
+
expect(validator.save).to be_false
|
476
|
+
expect {validator.save!}.to raise_error(ActiveRecord::RecordInvalid)
|
477
|
+
|
478
|
+
validator.reload
|
479
|
+
expect(validator).to be_sleeping
|
480
|
+
end
|
481
|
+
|
482
|
+
it "should store invalid states if configured" do
|
483
|
+
persistor = InvalidPersistor.create(:name => 'name')
|
484
|
+
persistor.status = 'invalid_state'
|
485
|
+
expect(persistor.save).to be_true
|
486
|
+
|
487
|
+
persistor.reload
|
488
|
+
expect(persistor.status).to eq('invalid_state')
|
489
|
+
end
|
490
|
+
|
491
|
+
end
|