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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/.travis.yml +29 -4
  4. data/CHANGELOG.md +56 -0
  5. data/Gemfile +10 -1
  6. data/LICENSE +1 -1
  7. data/README.md +151 -20
  8. data/aasm.gemspec +5 -6
  9. data/gemfiles/rails_3.2.gemfile +13 -0
  10. data/gemfiles/rails_4.0.gemfile +16 -0
  11. data/gemfiles/rails_4.1.gemfile +16 -0
  12. data/lib/aasm/aasm.rb +36 -32
  13. data/lib/aasm/base.rb +49 -31
  14. data/lib/aasm/event.rb +28 -17
  15. data/lib/aasm/instance_base.rb +9 -4
  16. data/lib/aasm/localizer.rb +1 -1
  17. data/lib/aasm/persistence/active_record_persistence.rb +65 -16
  18. data/lib/aasm/persistence/base.rb +10 -14
  19. data/lib/aasm/persistence/mongoid_persistence.rb +10 -8
  20. data/lib/aasm/persistence/sequel_persistence.rb +108 -0
  21. data/lib/aasm/persistence.rb +3 -0
  22. data/lib/aasm/state.rb +4 -3
  23. data/lib/aasm/state_machine.rb +18 -10
  24. data/lib/aasm/transition.rb +13 -6
  25. data/lib/aasm/version.rb +1 -1
  26. data/lib/aasm.rb +0 -3
  27. data/spec/database.rb +33 -0
  28. data/spec/models/double_definer.rb +21 -0
  29. data/spec/models/foo.rb +2 -1
  30. data/spec/models/guardian.rb +48 -0
  31. data/spec/models/mongoid/no_scope_mongoid.rb +1 -1
  32. data/spec/models/mongoid/simple_mongoid.rb +5 -4
  33. data/spec/models/mongoid/simple_new_dsl_mongoid.rb +1 -1
  34. data/spec/models/not_auto_loaded/process.rb +10 -8
  35. data/spec/models/persistence.rb +5 -13
  36. data/spec/spec_helper.rb +1 -1
  37. data/spec/unit/api_spec.rb +12 -12
  38. data/spec/unit/callbacks_spec.rb +29 -45
  39. data/spec/unit/complex_example_spec.rb +24 -15
  40. data/spec/unit/event_naming_spec.rb +24 -0
  41. data/spec/unit/event_spec.rb +124 -76
  42. data/spec/unit/guard_spec.rb +60 -0
  43. data/spec/unit/initial_state_spec.rb +4 -5
  44. data/spec/unit/inspection_spec.rb +42 -53
  45. data/spec/unit/localizer_spec.rb +22 -18
  46. data/spec/unit/memory_leak_spec.rb +2 -2
  47. data/spec/unit/new_dsl_spec.rb +2 -2
  48. data/spec/unit/persistence/active_record_persistence_spec.rb +357 -89
  49. data/spec/unit/persistence/mongoid_persistance_spec.rb +102 -81
  50. data/spec/unit/persistence/sequel_persistence_spec.rb +103 -0
  51. data/spec/unit/reloading_spec.rb +15 -0
  52. data/spec/unit/simple_example_spec.rb +20 -21
  53. data/spec/unit/state_spec.rb +16 -16
  54. data/spec/unit/subclassing_spec.rb +8 -8
  55. data/spec/unit/transition_spec.rb +59 -44
  56. metadata +38 -96
  57. data/lib/aasm/deprecated/aasm.rb +0 -15
  58. data/spec/models/callback_old_dsl.rb +0 -41
  59. 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.should be_include(AASM::Persistence::ActiveRecordPersistence)
13
- klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
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.should respond_to(:aasm_read_state)
22
- gate.should respond_to(:aasm_write_state)
23
- gate.should respond_to(:aasm_write_state_without_persistence)
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.aasm_current_state.should == :opened
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.aasm_current_state.should == :closed
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.stub(:new_record?).and_return(false)
257
+ allow(gate).to receive(:new_record?).and_return(false)
37
258
  gate.aasm_state = "state"
38
- gate.aasm_current_state.should == :state
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.stub(:new_record?).and_return(false)
263
+ allow(gate).to receive(:new_record?).and_return(false)
43
264
  gate.aasm_state = nil
44
- gate.aasm_current_state.should be_nil
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.should_receive(:aasm_ensure_initial_state).and_return(true)
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.stub(:new_record?).and_return(false)
54
- gate.should_not_receive(:aasm_ensure_initial_state)
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
- Derivate.aasm_states.should == Simple.aasm_states
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
- Derivate.aasm_events.should == Simple.aasm_events
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.should == :status
75
- DerivateNewDsl.aasm_column.should == :status
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.should respond_to(:unknown_scope)
102
- SimpleNewDsl.unknown_scope.is_a?(ActiveRecord::Relation).should be_true
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.should respond_to(:new)
109
- SimpleNewDsl.new.class.should == SimpleNewDsl
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.should_not respond_to(:ignored_scope)
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).aasm_current_state.should == :rich
123
- Thief.new(:skilled => false).aasm_current_state.should == :jailed
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.should be_sleeping
334
+ expect(valid_object).to be_sleeping
132
335
  valid_object.status = :running
133
- valid_object.should be_running
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.should be_valid
139
- validator.should be_sleeping
341
+ expect(validator).to be_valid
342
+ expect(validator).to be_sleeping
140
343
 
141
344
  validator.name = nil
142
- validator.should_not be_valid
143
- validator.run!.should be_false
144
- validator.should be_sleeping
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.should_not be_running
148
- validator.should be_sleeping
350
+ expect(validator).not_to be_running
351
+ expect(validator).to be_sleeping
149
352
 
150
353
  validator.name = 'another name'
151
- validator.should be_valid
152
- validator.run!.should be_true
153
- validator.should be_running
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.should be_running
157
- validator.should_not be_sleeping
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.should be_valid
163
- persistor.should be_sleeping
365
+ expect(persistor).to be_valid
366
+ expect(persistor).to be_sleeping
164
367
 
165
368
  persistor.name = nil
166
- persistor.should_not be_valid
167
- persistor.run!.should be_true
168
- persistor.should be_running
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.should be_valid
173
- persistor.should be_running
174
- persistor.should_not be_sleeping
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.should be_running
178
- persistor.should_not be_sleeping
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.should be_sleeping
187
- worker.status.should == 'sleeping'
389
+ expect(transactor).to be_sleeping
390
+ expect(worker.status).to eq('sleeping')
188
391
 
189
- lambda {transactor.run!}.should raise_error(StandardError, 'failed on purpose')
190
- transactor.should be_running
191
- worker.reload.status.should == 'sleeping'
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
- it "should rollback all changes in nested transaction" do
195
- transactor.should be_sleeping
196
- worker.status.should == 'sleeping'
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
- Worker.transaction do
199
- lambda { transactor.run! }.should raise_error(StandardError, 'failed on purpose')
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
- transactor.should be_running
203
- worker.reload.status.should == 'sleeping'
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.should be_sleeping
429
+ expect(validator).to be_sleeping
210
430
  validator.run!
211
- validator.should be_running
212
- validator.name.should_not == "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
- lambda { validator.fail! }.should raise_error(StandardError, 'failed on purpose')
218
- validator.name.should == "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