aasm 5.0.8
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 +7 -0
- data/.document +6 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.gitignore +20 -0
- data/.travis.yml +100 -0
- data/API +34 -0
- data/Appraisals +71 -0
- data/CHANGELOG.md +431 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/CONTRIBUTING.md +24 -0
- data/Dockerfile +44 -0
- data/Gemfile +6 -0
- data/Gemfile.lock_old +151 -0
- data/HOWTO +12 -0
- data/LICENSE +20 -0
- data/PLANNED_CHANGES.md +11 -0
- data/README.md +1439 -0
- data/README_FROM_VERSION_3_TO_4.md +240 -0
- data/Rakefile +31 -0
- data/TESTING.md +25 -0
- data/aasm.gemspec +37 -0
- data/callbacks.txt +51 -0
- data/docker-compose.yml +40 -0
- data/gemfiles/norails.gemfile +10 -0
- data/gemfiles/rails_3.2.gemfile +14 -0
- data/gemfiles/rails_4.2.gemfile +16 -0
- data/gemfiles/rails_4.2_mongoid_5.gemfile +11 -0
- data/gemfiles/rails_4.2_nobrainer.gemfile +9 -0
- data/gemfiles/rails_5.0.gemfile +13 -0
- data/gemfiles/rails_5.0_nobrainer.gemfile +9 -0
- data/gemfiles/rails_5.1.gemfile +13 -0
- data/gemfiles/rails_5.2.gemfile +13 -0
- data/lib/aasm.rb +23 -0
- data/lib/aasm/aasm.rb +208 -0
- data/lib/aasm/base.rb +271 -0
- data/lib/aasm/configuration.rb +45 -0
- data/lib/aasm/core/event.rb +172 -0
- data/lib/aasm/core/invoker.rb +129 -0
- data/lib/aasm/core/invokers/base_invoker.rb +75 -0
- data/lib/aasm/core/invokers/class_invoker.rb +52 -0
- data/lib/aasm/core/invokers/literal_invoker.rb +47 -0
- data/lib/aasm/core/invokers/proc_invoker.rb +59 -0
- data/lib/aasm/core/state.rb +90 -0
- data/lib/aasm/core/transition.rb +83 -0
- data/lib/aasm/dsl_helper.rb +30 -0
- data/lib/aasm/errors.rb +21 -0
- data/lib/aasm/instance_base.rb +133 -0
- data/lib/aasm/localizer.rb +54 -0
- data/lib/aasm/minitest.rb +5 -0
- data/lib/aasm/minitest/allow_event.rb +13 -0
- data/lib/aasm/minitest/allow_transition_to.rb +13 -0
- data/lib/aasm/minitest/have_state.rb +13 -0
- data/lib/aasm/minitest/transition_from.rb +21 -0
- data/lib/aasm/minitest_spec.rb +15 -0
- data/lib/aasm/persistence.rb +54 -0
- data/lib/aasm/persistence/active_record_persistence.rb +165 -0
- data/lib/aasm/persistence/base.rb +78 -0
- data/lib/aasm/persistence/core_data_query_persistence.rb +94 -0
- data/lib/aasm/persistence/dynamoid_persistence.rb +92 -0
- data/lib/aasm/persistence/mongoid_persistence.rb +126 -0
- data/lib/aasm/persistence/no_brainer_persistence.rb +105 -0
- data/lib/aasm/persistence/orm.rb +150 -0
- data/lib/aasm/persistence/plain_persistence.rb +26 -0
- data/lib/aasm/persistence/redis_persistence.rb +112 -0
- data/lib/aasm/persistence/sequel_persistence.rb +83 -0
- data/lib/aasm/rspec.rb +5 -0
- data/lib/aasm/rspec/allow_event.rb +26 -0
- data/lib/aasm/rspec/allow_transition_to.rb +26 -0
- data/lib/aasm/rspec/have_state.rb +22 -0
- data/lib/aasm/rspec/transition_from.rb +36 -0
- data/lib/aasm/state_machine.rb +53 -0
- data/lib/aasm/state_machine_store.rb +76 -0
- data/lib/aasm/version.rb +3 -0
- data/lib/generators/aasm/aasm_generator.rb +16 -0
- data/lib/generators/aasm/orm_helpers.rb +41 -0
- data/lib/generators/active_record/aasm_generator.rb +40 -0
- data/lib/generators/active_record/templates/migration.rb +8 -0
- data/lib/generators/active_record/templates/migration_existing.rb +5 -0
- data/lib/generators/mongoid/aasm_generator.rb +28 -0
- data/lib/generators/nobrainer/aasm_generator.rb +28 -0
- data/lib/motion-aasm.rb +37 -0
- data/spec/database.rb +59 -0
- data/spec/database.yml +3 -0
- data/spec/en.yml +12 -0
- data/spec/en_deprecated_style.yml +10 -0
- data/spec/generators/active_record_generator_spec.rb +53 -0
- data/spec/generators/mongoid_generator_spec.rb +31 -0
- data/spec/generators/no_brainer_generator_spec.rb +29 -0
- data/spec/models/active_record/basic_active_record_two_state_machines_example.rb +25 -0
- data/spec/models/active_record/complex_active_record_example.rb +37 -0
- data/spec/models/active_record/derivate_new_dsl.rb +7 -0
- data/spec/models/active_record/false_state.rb +35 -0
- data/spec/models/active_record/gate.rb +39 -0
- data/spec/models/active_record/instance_level_skip_validation_example.rb +19 -0
- data/spec/models/active_record/invalid_persistor.rb +29 -0
- data/spec/models/active_record/localizer_test_model.rb +34 -0
- data/spec/models/active_record/no_direct_assignment.rb +21 -0
- data/spec/models/active_record/no_scope.rb +21 -0
- data/spec/models/active_record/persisted_state.rb +12 -0
- data/spec/models/active_record/person.rb +23 -0
- data/spec/models/active_record/provided_and_persisted_state.rb +24 -0
- data/spec/models/active_record/reader.rb +7 -0
- data/spec/models/active_record/readme_job.rb +21 -0
- data/spec/models/active_record/silent_persistor.rb +29 -0
- data/spec/models/active_record/simple_new_dsl.rb +32 -0
- data/spec/models/active_record/thief.rb +29 -0
- data/spec/models/active_record/transactor.rb +124 -0
- data/spec/models/active_record/transient.rb +6 -0
- data/spec/models/active_record/validator.rb +118 -0
- data/spec/models/active_record/with_enum.rb +39 -0
- data/spec/models/active_record/with_enum_without_column.rb +38 -0
- data/spec/models/active_record/with_false_enum.rb +31 -0
- data/spec/models/active_record/with_true_enum.rb +39 -0
- data/spec/models/active_record/work.rb +3 -0
- data/spec/models/active_record/worker.rb +2 -0
- data/spec/models/active_record/writer.rb +6 -0
- data/spec/models/basic_two_state_machines_example.rb +25 -0
- data/spec/models/callbacks/basic.rb +98 -0
- data/spec/models/callbacks/basic_multiple.rb +75 -0
- data/spec/models/callbacks/guard_within_block.rb +67 -0
- data/spec/models/callbacks/guard_within_block_multiple.rb +66 -0
- data/spec/models/callbacks/multiple_transitions_transition_guard.rb +66 -0
- data/spec/models/callbacks/multiple_transitions_transition_guard_multiple.rb +65 -0
- data/spec/models/callbacks/private_method.rb +44 -0
- data/spec/models/callbacks/private_method_multiple.rb +44 -0
- data/spec/models/callbacks/with_args.rb +62 -0
- data/spec/models/callbacks/with_args_multiple.rb +61 -0
- data/spec/models/callbacks/with_state_arg.rb +34 -0
- data/spec/models/callbacks/with_state_arg_multiple.rb +29 -0
- data/spec/models/complex_example.rb +222 -0
- data/spec/models/conversation.rb +93 -0
- data/spec/models/default_state.rb +12 -0
- data/spec/models/double_definer.rb +21 -0
- data/spec/models/dynamoid/complex_dynamoid_example.rb +37 -0
- data/spec/models/dynamoid/dynamoid_multiple.rb +18 -0
- data/spec/models/dynamoid/dynamoid_simple.rb +18 -0
- data/spec/models/foo.rb +106 -0
- data/spec/models/foo_callback_multiple.rb +45 -0
- data/spec/models/guard_arguments_check.rb +17 -0
- data/spec/models/guard_with_params.rb +24 -0
- data/spec/models/guard_with_params_multiple.rb +18 -0
- data/spec/models/guardian.rb +58 -0
- data/spec/models/guardian_multiple.rb +48 -0
- data/spec/models/guardian_without_from_specified.rb +18 -0
- data/spec/models/initial_state_proc.rb +31 -0
- data/spec/models/mongoid/complex_mongoid_example.rb +37 -0
- data/spec/models/mongoid/invalid_persistor_mongoid.rb +39 -0
- data/spec/models/mongoid/mongoid_relationships.rb +26 -0
- data/spec/models/mongoid/no_scope_mongoid.rb +21 -0
- data/spec/models/mongoid/silent_persistor_mongoid.rb +39 -0
- data/spec/models/mongoid/simple_mongoid.rb +23 -0
- data/spec/models/mongoid/simple_new_dsl_mongoid.rb +25 -0
- data/spec/models/mongoid/validator_mongoid.rb +100 -0
- data/spec/models/multi_transitioner.rb +34 -0
- data/spec/models/multiple_transitions_that_differ_only_by_guard.rb +31 -0
- data/spec/models/namespaced_multiple_example.rb +42 -0
- data/spec/models/no_initial_state.rb +25 -0
- data/spec/models/nobrainer/complex_no_brainer_example.rb +36 -0
- data/spec/models/nobrainer/invalid_persistor_no_brainer.rb +39 -0
- data/spec/models/nobrainer/no_scope_no_brainer.rb +21 -0
- data/spec/models/nobrainer/nobrainer_relationships.rb +25 -0
- data/spec/models/nobrainer/silent_persistor_no_brainer.rb +39 -0
- data/spec/models/nobrainer/simple_new_dsl_nobrainer.rb +25 -0
- data/spec/models/nobrainer/simple_no_brainer.rb +23 -0
- data/spec/models/nobrainer/validator_no_brainer.rb +98 -0
- data/spec/models/not_auto_loaded/process.rb +21 -0
- data/spec/models/parametrised_event.rb +42 -0
- data/spec/models/parametrised_event_multiple.rb +29 -0
- data/spec/models/process_with_new_dsl.rb +31 -0
- data/spec/models/provided_state.rb +24 -0
- data/spec/models/redis/complex_redis_example.rb +40 -0
- data/spec/models/redis/redis_multiple.rb +20 -0
- data/spec/models/redis/redis_simple.rb +20 -0
- data/spec/models/sequel/complex_sequel_example.rb +46 -0
- data/spec/models/sequel/invalid_persistor.rb +52 -0
- data/spec/models/sequel/sequel_multiple.rb +25 -0
- data/spec/models/sequel/sequel_simple.rb +26 -0
- data/spec/models/sequel/silent_persistor.rb +50 -0
- data/spec/models/sequel/transactor.rb +112 -0
- data/spec/models/sequel/validator.rb +93 -0
- data/spec/models/sequel/worker.rb +12 -0
- data/spec/models/silencer.rb +27 -0
- data/spec/models/simple_custom_example.rb +53 -0
- data/spec/models/simple_example.rb +23 -0
- data/spec/models/simple_example_with_guard_args.rb +17 -0
- data/spec/models/simple_multiple_example.rb +42 -0
- data/spec/models/state_machine_with_failed_event.rb +20 -0
- data/spec/models/states_on_one_line_example.rb +8 -0
- data/spec/models/sub_class.rb +41 -0
- data/spec/models/sub_class_with_more_states.rb +18 -0
- data/spec/models/sub_classing.rb +3 -0
- data/spec/models/super_class.rb +46 -0
- data/spec/models/this_name_better_not_be_in_use.rb +11 -0
- data/spec/models/valid_state_name.rb +23 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/spec_helpers/active_record.rb +8 -0
- data/spec/spec_helpers/dynamoid.rb +35 -0
- data/spec/spec_helpers/mongoid.rb +26 -0
- data/spec/spec_helpers/nobrainer.rb +15 -0
- data/spec/spec_helpers/redis.rb +18 -0
- data/spec/spec_helpers/remove_warnings.rb +1 -0
- data/spec/spec_helpers/sequel.rb +7 -0
- data/spec/unit/abstract_class_spec.rb +27 -0
- data/spec/unit/api_spec.rb +100 -0
- data/spec/unit/basic_two_state_machines_example_spec.rb +10 -0
- data/spec/unit/callback_multiple_spec.rb +304 -0
- data/spec/unit/callbacks_spec.rb +521 -0
- data/spec/unit/complex_example_spec.rb +93 -0
- data/spec/unit/complex_multiple_example_spec.rb +115 -0
- data/spec/unit/edge_cases_spec.rb +16 -0
- data/spec/unit/event_multiple_spec.rb +73 -0
- data/spec/unit/event_naming_spec.rb +16 -0
- data/spec/unit/event_spec.rb +394 -0
- data/spec/unit/exception_spec.rb +11 -0
- data/spec/unit/guard_arguments_check_spec.rb +9 -0
- data/spec/unit/guard_multiple_spec.rb +60 -0
- data/spec/unit/guard_spec.rb +89 -0
- data/spec/unit/guard_with_params_multiple_spec.rb +10 -0
- data/spec/unit/guard_with_params_spec.rb +14 -0
- data/spec/unit/guard_without_from_specified_spec.rb +10 -0
- data/spec/unit/initial_state_multiple_spec.rb +15 -0
- data/spec/unit/initial_state_spec.rb +12 -0
- data/spec/unit/inspection_multiple_spec.rb +201 -0
- data/spec/unit/inspection_spec.rb +149 -0
- data/spec/unit/invoker_spec.rb +189 -0
- data/spec/unit/invokers/base_invoker_spec.rb +72 -0
- data/spec/unit/invokers/class_invoker_spec.rb +95 -0
- data/spec/unit/invokers/literal_invoker_spec.rb +86 -0
- data/spec/unit/invokers/proc_invoker_spec.rb +86 -0
- data/spec/unit/localizer_spec.rb +78 -0
- data/spec/unit/memory_leak_spec.rb +38 -0
- data/spec/unit/multiple_transitions_that_differ_only_by_guard_spec.rb +14 -0
- data/spec/unit/namespaced_multiple_example_spec.rb +75 -0
- data/spec/unit/new_dsl_spec.rb +12 -0
- data/spec/unit/override_warning_spec.rb +94 -0
- data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +618 -0
- data/spec/unit/persistence/active_record_persistence_spec.rb +773 -0
- data/spec/unit/persistence/dynamoid_persistence_multiple_spec.rb +135 -0
- data/spec/unit/persistence/dynamoid_persistence_spec.rb +84 -0
- data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +200 -0
- data/spec/unit/persistence/mongoid_persistence_spec.rb +165 -0
- data/spec/unit/persistence/no_brainer_persistence_multiple_spec.rb +198 -0
- data/spec/unit/persistence/no_brainer_persistence_spec.rb +158 -0
- data/spec/unit/persistence/redis_persistence_multiple_spec.rb +88 -0
- data/spec/unit/persistence/redis_persistence_spec.rb +53 -0
- data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +148 -0
- data/spec/unit/persistence/sequel_persistence_spec.rb +368 -0
- data/spec/unit/readme_spec.rb +41 -0
- data/spec/unit/reloading_spec.rb +15 -0
- data/spec/unit/rspec_matcher_spec.rb +88 -0
- data/spec/unit/simple_custom_example_spec.rb +39 -0
- data/spec/unit/simple_example_spec.rb +57 -0
- data/spec/unit/simple_multiple_example_spec.rb +91 -0
- data/spec/unit/state_spec.rb +89 -0
- data/spec/unit/states_on_one_line_example_spec.rb +16 -0
- data/spec/unit/subclassing_multiple_spec.rb +74 -0
- data/spec/unit/subclassing_spec.rb +46 -0
- data/spec/unit/transition_spec.rb +436 -0
- data/test/minitest_helper.rb +57 -0
- data/test/unit/minitest_matcher_test.rb +80 -0
- metadata +609 -0
@@ -0,0 +1,773 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
if defined?(ActiveRecord)
|
4
|
+
|
5
|
+
Dir[File.dirname(__FILE__) + "/../../models/active_record/*.rb"].sort.each do |f|
|
6
|
+
require File.expand_path(f)
|
7
|
+
end
|
8
|
+
|
9
|
+
load_schema
|
10
|
+
|
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)
|
14
|
+
|
15
|
+
describe "instance methods" do
|
16
|
+
let(:gate) {Gate.new}
|
17
|
+
|
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)
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "aasm_column_looks_like_enum" do
|
25
|
+
subject { lambda{ gate.send(:aasm_column_looks_like_enum) } }
|
26
|
+
|
27
|
+
let(:column_name) { "value" }
|
28
|
+
let(:columns_hash) { Hash[column_name, column] }
|
29
|
+
|
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
|
34
|
+
|
35
|
+
context "when AASM column has integer type" do
|
36
|
+
let(:column) { double(Object, type: :integer) }
|
37
|
+
|
38
|
+
it "returns true" do
|
39
|
+
expect(subject.call).to be_truthy
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when AASM column has string type" do
|
44
|
+
let(:column) { double(Object, type: :string) }
|
45
|
+
|
46
|
+
it "returns false" do
|
47
|
+
expect(subject.call).to be_falsey
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "aasm_guess_enum_method" do
|
53
|
+
subject { lambda{ gate.send(:aasm_guess_enum_method) } }
|
54
|
+
|
55
|
+
before :each do
|
56
|
+
allow(gate.class.aasm).to receive(:attribute_name).and_return(:value)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "pluralizes AASM column name" do
|
60
|
+
expect(subject.call).to eq :values
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "aasm_enum" do
|
65
|
+
context "when AASM enum setting contains an explicit enum method name" do
|
66
|
+
let(:with_enum) { WithEnum.new }
|
67
|
+
|
68
|
+
it "returns whatever value was set in AASM config" do
|
69
|
+
expect(with_enum.send(:aasm_enum)).to eq :test
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when AASM enum setting is simply set to true" do
|
74
|
+
let(:with_true_enum) { WithTrueEnum.new }
|
75
|
+
before :each do
|
76
|
+
allow(WithTrueEnum.aasm).to receive(:attribute_name).and_return(:value)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "infers enum method name from pluralized column name" do
|
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
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when AASM enum setting is not enabled" do
|
93
|
+
before :each do
|
94
|
+
allow(Gate.aasm).to receive(:attribute_name).and_return(:value)
|
95
|
+
end
|
96
|
+
|
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
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
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
|
122
|
+
|
123
|
+
let(:with_enum_without_column) {WithEnumWithoutColumn.new}
|
124
|
+
|
125
|
+
it "should raise NoMethodError for transitions" do
|
126
|
+
expect{with_enum_without_column.send(:view)}.to raise_error(NoMethodError, /undefined method .status./)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
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] }
|
139
|
+
|
140
|
+
before :each do
|
141
|
+
allow(gate).to receive(:aasm_enum).and_return(enum_name)
|
142
|
+
allow(gate).to receive(:aasm_write_state_attribute)
|
143
|
+
allow(gate).to receive(:write_attribute)
|
144
|
+
|
145
|
+
allow(Gate).to receive(enum_name).and_return(enum)
|
146
|
+
end
|
147
|
+
|
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
|
153
|
+
|
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
|
185
|
+
end
|
186
|
+
|
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)
|
191
|
+
|
192
|
+
gate.aasm_write_state state_sym
|
193
|
+
|
194
|
+
expect(gate).to have_received(:aasm_write_state_attribute).with(state_sym, :default)
|
195
|
+
expect(gate).to_not have_received :write_attribute
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "aasm_write_state_without_persistence" do
|
201
|
+
it "delegates state update to the helper method" do
|
202
|
+
gate.aasm_write_state_without_persistence state_sym
|
203
|
+
|
204
|
+
expect(gate).to have_received(:aasm_write_state_attribute).with(state_sym, :default)
|
205
|
+
expect(gate).to_not have_received :write_attribute
|
206
|
+
end
|
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
|
215
|
+
end
|
216
|
+
|
217
|
+
context "when AASM is configured to use string field" do
|
218
|
+
let(:state_sym) { :running }
|
219
|
+
|
220
|
+
before :each do
|
221
|
+
allow(gate).to receive(:aasm_enum).and_return(nil)
|
222
|
+
end
|
223
|
+
|
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
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "aasm_write_attribute helper method" do
|
233
|
+
let(:sym) { :sym }
|
234
|
+
let(:value) { 42 }
|
235
|
+
|
236
|
+
before :each do
|
237
|
+
allow(gate).to receive(:write_attribute)
|
238
|
+
allow(gate).to receive(:aasm_raw_attribute_value).and_return(value)
|
239
|
+
|
240
|
+
gate.send(:aasm_write_state_attribute, sym)
|
241
|
+
end
|
242
|
+
|
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
|
246
|
+
|
247
|
+
it "writes attribute to the model" do
|
248
|
+
expect(gate).to have_received(:write_attribute).with(:aasm_state, value)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
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)
|
254
|
+
end
|
255
|
+
|
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)
|
259
|
+
end
|
260
|
+
|
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)
|
265
|
+
end
|
266
|
+
|
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
|
272
|
+
|
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
|
278
|
+
|
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!
|
283
|
+
|
284
|
+
# then we just load the gate ids
|
285
|
+
Gate.select(:id).where(id: gate.id).first
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
|
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
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
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
|
307
|
+
|
308
|
+
it "should have the same events as its parent class" do
|
309
|
+
expect(DerivateNewDsl.aasm.events).to eq(SimpleNewDsl.aasm.events)
|
310
|
+
end
|
311
|
+
|
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
|
316
|
+
end
|
317
|
+
|
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)
|
323
|
+
|
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
|
327
|
+
end
|
328
|
+
|
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
|
334
|
+
end
|
335
|
+
|
336
|
+
# Scopes on abstract classes didn't work until Rails 5.
|
337
|
+
#
|
338
|
+
# Reference:
|
339
|
+
# https://github.com/rails/rails/issues/10658
|
340
|
+
if ActiveRecord::VERSION::MAJOR >= 5
|
341
|
+
context "For a descendant of an abstract model" do
|
342
|
+
it "should add the scope without the table_name" do
|
343
|
+
expect(ImplementedAbstractClassDsl).to respond_to(:unknown_scope)
|
344
|
+
expect(ImplementedAbstractClassDsl).to respond_to(:another_unknown_scope)
|
345
|
+
|
346
|
+
expect(ImplementedAbstractClassDsl.unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
|
347
|
+
expect(ImplementedAbstractClassDsl.another_unknown_scope.is_a?(ActiveRecord::Relation)).to be_truthy
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
it "does not create scopes if requested" do
|
353
|
+
expect(NoScope).not_to respond_to(:pending)
|
354
|
+
end
|
355
|
+
|
356
|
+
context "result of scope" do
|
357
|
+
let!(:dsl1) { SimpleNewDsl.create!(status: :new) }
|
358
|
+
let!(:dsl2) { SimpleNewDsl.create!(status: :unknown_scope) }
|
359
|
+
|
360
|
+
after do
|
361
|
+
SimpleNewDsl.destroy_all
|
362
|
+
end
|
363
|
+
|
364
|
+
it "created scope works as where(name: :scope_name)" do
|
365
|
+
expect(SimpleNewDsl.unknown_scope).to contain_exactly(dsl2)
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end # scopes
|
369
|
+
|
370
|
+
describe "direct assignment" do
|
371
|
+
it "is allowed by default" do
|
372
|
+
obj = NoScope.create
|
373
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
374
|
+
|
375
|
+
obj.aasm_state = :running
|
376
|
+
expect(obj.aasm_state.to_sym).to eql :running
|
377
|
+
end
|
378
|
+
|
379
|
+
it "is forbidden if configured" do
|
380
|
+
obj = NoDirectAssignment.create
|
381
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
382
|
+
|
383
|
+
expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
|
384
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
385
|
+
end
|
386
|
+
|
387
|
+
it 'can be turned off and on again' do
|
388
|
+
obj = NoDirectAssignment.create
|
389
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
390
|
+
|
391
|
+
expect {obj.aasm_state = :running}.to raise_error(AASM::NoDirectAssignmentError)
|
392
|
+
expect(obj.aasm_state.to_sym).to eql :pending
|
393
|
+
|
394
|
+
# allow it temporarily
|
395
|
+
NoDirectAssignment.aasm.state_machine.config.no_direct_assignment = false
|
396
|
+
obj.aasm_state = :running
|
397
|
+
expect(obj.aasm_state.to_sym).to eql :running
|
398
|
+
|
399
|
+
# and forbid it again
|
400
|
+
NoDirectAssignment.aasm.state_machine.config.no_direct_assignment = true
|
401
|
+
expect {obj.aasm_state = :pending}.to raise_error(AASM::NoDirectAssignmentError)
|
402
|
+
expect(obj.aasm_state.to_sym).to eql :running
|
403
|
+
end
|
404
|
+
end # direct assignment
|
405
|
+
|
406
|
+
describe 'initial states' do
|
407
|
+
|
408
|
+
it 'should support conditions' do
|
409
|
+
expect(Thief.new(:skilled => true).aasm.current_state).to eq(:rich)
|
410
|
+
expect(Thief.new(:skilled => false).aasm.current_state).to eq(:jailed)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
describe 'transitions with persistence' do
|
415
|
+
|
416
|
+
it "should work for valid models" do
|
417
|
+
valid_object = Validator.create(:name => 'name')
|
418
|
+
expect(valid_object).to be_sleeping
|
419
|
+
valid_object.status = :running
|
420
|
+
expect(valid_object).to be_running
|
421
|
+
end
|
422
|
+
|
423
|
+
it 'should not store states for invalid models' do
|
424
|
+
validator = Validator.create(:name => 'name')
|
425
|
+
expect(validator).to be_valid
|
426
|
+
expect(validator).to be_sleeping
|
427
|
+
|
428
|
+
validator.name = nil
|
429
|
+
expect(validator).not_to be_valid
|
430
|
+
expect { validator.run! }.to raise_error(ActiveRecord::RecordInvalid)
|
431
|
+
expect(validator).to be_sleeping
|
432
|
+
|
433
|
+
validator.reload
|
434
|
+
expect(validator).not_to be_running
|
435
|
+
expect(validator).to be_sleeping
|
436
|
+
|
437
|
+
validator.name = 'another name'
|
438
|
+
expect(validator).to be_valid
|
439
|
+
expect(validator.run!).to be_truthy
|
440
|
+
expect(validator).to be_running
|
441
|
+
|
442
|
+
validator.reload
|
443
|
+
expect(validator).to be_running
|
444
|
+
expect(validator).not_to be_sleeping
|
445
|
+
end
|
446
|
+
|
447
|
+
it 'should not store states for invalid models silently if configured' do
|
448
|
+
validator = SilentPersistor.create(:name => 'name')
|
449
|
+
expect(validator).to be_valid
|
450
|
+
expect(validator).to be_sleeping
|
451
|
+
|
452
|
+
validator.name = nil
|
453
|
+
expect(validator).not_to be_valid
|
454
|
+
expect(validator.run!).to be_falsey
|
455
|
+
expect(validator).to be_sleeping
|
456
|
+
|
457
|
+
validator.reload
|
458
|
+
expect(validator).not_to be_running
|
459
|
+
expect(validator).to be_sleeping
|
460
|
+
|
461
|
+
validator.name = 'another name'
|
462
|
+
expect(validator).to be_valid
|
463
|
+
expect(validator.run!).to be_truthy
|
464
|
+
expect(validator).to be_running
|
465
|
+
|
466
|
+
validator.reload
|
467
|
+
expect(validator).to be_running
|
468
|
+
expect(validator).not_to be_sleeping
|
469
|
+
end
|
470
|
+
|
471
|
+
it 'should store states for invalid models if configured' do
|
472
|
+
persistor = InvalidPersistor.create(:name => 'name')
|
473
|
+
expect(persistor).to be_valid
|
474
|
+
expect(persistor).to be_sleeping
|
475
|
+
|
476
|
+
persistor.name = nil
|
477
|
+
expect(persistor).not_to be_valid
|
478
|
+
expect(persistor.run!).to be_truthy
|
479
|
+
expect(persistor).to be_running
|
480
|
+
|
481
|
+
persistor = InvalidPersistor.find(persistor.id)
|
482
|
+
persistor.valid?
|
483
|
+
expect(persistor).to be_valid
|
484
|
+
expect(persistor).to be_running
|
485
|
+
expect(persistor).not_to be_sleeping
|
486
|
+
|
487
|
+
persistor.reload
|
488
|
+
expect(persistor).to be_running
|
489
|
+
expect(persistor).not_to be_sleeping
|
490
|
+
end
|
491
|
+
|
492
|
+
describe 'pessimistic locking' do
|
493
|
+
let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
|
494
|
+
|
495
|
+
subject { transactor.run! }
|
496
|
+
|
497
|
+
context 'no lock' do
|
498
|
+
let(:transactor) { NoLockTransactor.create!(:name => 'no_lock_transactor', :worker => worker) }
|
499
|
+
|
500
|
+
it 'should not invoke lock!' do
|
501
|
+
expect(transactor).to_not receive(:lock!)
|
502
|
+
subject
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
context 'a default lock' do
|
507
|
+
let(:transactor) { LockTransactor.create!(:name => 'lock_transactor', :worker => worker) }
|
508
|
+
|
509
|
+
it 'should invoke lock! with true' do
|
510
|
+
expect(transactor).to receive(:lock!).with(true).and_call_original
|
511
|
+
subject
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
context 'a FOR UPDATE NOWAIT lock' do
|
516
|
+
let(:transactor) { LockNoWaitTransactor.create!(:name => 'lock_no_wait_transactor', :worker => worker) }
|
517
|
+
|
518
|
+
it 'should invoke lock! with FOR UPDATE NOWAIT' do
|
519
|
+
expect(transactor).to receive(:lock!).with('FOR UPDATE NOWAIT').and_call_original
|
520
|
+
subject
|
521
|
+
end
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
describe 'without transactions' do
|
526
|
+
let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
|
527
|
+
let(:no_transactor) { NoTransactor.create!(:name => 'transactor', :worker => worker) }
|
528
|
+
|
529
|
+
it 'should not rollback all changes' do
|
530
|
+
expect(no_transactor).to be_sleeping
|
531
|
+
expect(worker.status).to eq('sleeping')
|
532
|
+
|
533
|
+
expect {no_transactor.run!}.to raise_error(StandardError, 'failed on purpose')
|
534
|
+
expect(no_transactor).to be_running
|
535
|
+
expect(worker.reload.status).to eq('running')
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
describe 'transactions' do
|
540
|
+
let(:worker) { Worker.create!(:name => 'worker', :status => 'sleeping') }
|
541
|
+
let(:transactor) { Transactor.create!(:name => 'transactor', :worker => worker) }
|
542
|
+
|
543
|
+
it 'should rollback all changes' do
|
544
|
+
expect(transactor).to be_sleeping
|
545
|
+
expect(worker.status).to eq('sleeping')
|
546
|
+
|
547
|
+
expect {transactor.run!}.to raise_error(StandardError, 'failed on purpose')
|
548
|
+
expect(transactor).to be_running
|
549
|
+
expect(worker.reload.status).to eq('sleeping')
|
550
|
+
end
|
551
|
+
|
552
|
+
context "nested transactions" do
|
553
|
+
it "should rollback all changes in nested transaction" do
|
554
|
+
expect(transactor).to be_sleeping
|
555
|
+
expect(worker.status).to eq('sleeping')
|
556
|
+
|
557
|
+
Worker.transaction do
|
558
|
+
expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
|
559
|
+
end
|
560
|
+
|
561
|
+
expect(transactor).to be_running
|
562
|
+
expect(worker.reload.status).to eq('sleeping')
|
563
|
+
end
|
564
|
+
|
565
|
+
it "should only rollback changes in the main transaction not the nested one" do
|
566
|
+
# change configuration to not require new transaction
|
567
|
+
AASM::StateMachineStore[Transactor][:default].config.requires_new_transaction = false
|
568
|
+
|
569
|
+
expect(transactor).to be_sleeping
|
570
|
+
expect(worker.status).to eq('sleeping')
|
571
|
+
|
572
|
+
Worker.transaction do
|
573
|
+
expect { transactor.run! }.to raise_error(StandardError, 'failed on purpose')
|
574
|
+
end
|
575
|
+
|
576
|
+
expect(transactor).to be_running
|
577
|
+
expect(worker.reload.status).to eq('running')
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
describe "after_commit callback" do
|
582
|
+
it "should fire :after_commit if transaction was successful" do
|
583
|
+
validator = Validator.create(:name => 'name')
|
584
|
+
expect(validator).to be_sleeping
|
585
|
+
|
586
|
+
validator.run!
|
587
|
+
expect(validator).to be_running
|
588
|
+
expect(validator.name).to eq("name changed")
|
589
|
+
|
590
|
+
validator.sleep!("sleeper")
|
591
|
+
expect(validator).to be_sleeping
|
592
|
+
expect(validator.name).to eq("sleeper")
|
593
|
+
end
|
594
|
+
|
595
|
+
it "should not fire :after_commit if transaction failed" do
|
596
|
+
validator = Validator.create(:name => 'name')
|
597
|
+
expect { validator.fail! }.to raise_error(StandardError, 'failed on purpose')
|
598
|
+
expect(validator.name).to eq("name")
|
599
|
+
end
|
600
|
+
|
601
|
+
it "should not fire :after_commit if validation failed when saving object" do
|
602
|
+
validator = Validator.create(:name => 'name')
|
603
|
+
validator.invalid = true
|
604
|
+
expect { validator.run! }.to raise_error(ActiveRecord::RecordInvalid, 'Invalid record')
|
605
|
+
expect(validator).to be_sleeping
|
606
|
+
expect(validator.name).to eq("name")
|
607
|
+
end
|
608
|
+
|
609
|
+
it "should not fire if not saving" do
|
610
|
+
validator = Validator.create(:name => 'name')
|
611
|
+
expect(validator).to be_sleeping
|
612
|
+
validator.run
|
613
|
+
expect(validator).to be_running
|
614
|
+
expect(validator.name).to eq("name")
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
describe 'before and after transaction callbacks' do
|
619
|
+
[:after, :before].each do |event_type|
|
620
|
+
describe "#{event_type}_transaction callback" do
|
621
|
+
it "should fire :#{event_type}_transaction if transaction was successful" do
|
622
|
+
validator = Validator.create(:name => 'name')
|
623
|
+
expect(validator).to be_sleeping
|
624
|
+
|
625
|
+
expect { validator.run! }.to change { validator.send("#{event_type}_transaction_performed_on_run") }.from(nil).to(true)
|
626
|
+
expect(validator).to be_running
|
627
|
+
end
|
628
|
+
|
629
|
+
it "should fire :#{event_type}_transaction if transaction failed" do
|
630
|
+
validator = Validator.create(:name => 'name')
|
631
|
+
expect do
|
632
|
+
begin
|
633
|
+
validator.fail!
|
634
|
+
rescue => ignored
|
635
|
+
end
|
636
|
+
end.to change { validator.send("#{event_type}_transaction_performed_on_fail") }.from(nil).to(true)
|
637
|
+
expect(validator).to_not be_running
|
638
|
+
end
|
639
|
+
|
640
|
+
it "should not fire :#{event_type}_transaction if not saving" do
|
641
|
+
validator = Validator.create(:name => 'name')
|
642
|
+
expect(validator).to be_sleeping
|
643
|
+
expect { validator.run }.to_not change { validator.send("#{event_type}_transaction_performed_on_run") }
|
644
|
+
expect(validator).to be_running
|
645
|
+
expect(validator.name).to eq("name")
|
646
|
+
end
|
647
|
+
end
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
describe 'before and after all transactions callbacks' do
|
652
|
+
[:after, :before].each do |event_type|
|
653
|
+
describe "#{event_type}_all_transactions callback" do
|
654
|
+
it "should fire :#{event_type}_all_transactions if transaction was successful" do
|
655
|
+
validator = Validator.create(:name => 'name')
|
656
|
+
expect(validator).to be_sleeping
|
657
|
+
|
658
|
+
expect { validator.run! }.to change { validator.send("#{event_type}_all_transactions_performed") }.from(nil).to(true)
|
659
|
+
expect(validator).to be_running
|
660
|
+
end
|
661
|
+
|
662
|
+
it "should fire :#{event_type}_all_transactions if transaction failed" do
|
663
|
+
validator = Validator.create(:name => 'name')
|
664
|
+
expect do
|
665
|
+
begin
|
666
|
+
validator.fail!
|
667
|
+
rescue => ignored
|
668
|
+
end
|
669
|
+
end.to change { validator.send("#{event_type}_all_transactions_performed") }.from(nil).to(true)
|
670
|
+
expect(validator).to_not be_running
|
671
|
+
end
|
672
|
+
|
673
|
+
it "should not fire :#{event_type}_all_transactions if not saving" do
|
674
|
+
validator = Validator.create(:name => 'name')
|
675
|
+
expect(validator).to be_sleeping
|
676
|
+
expect { validator.run }.to_not change { validator.send("#{event_type}_all_transactions_performed") }
|
677
|
+
expect(validator).to be_running
|
678
|
+
expect(validator.name).to eq("name")
|
679
|
+
end
|
680
|
+
end
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
context "when not persisting" do
|
685
|
+
it 'should not rollback all changes' do
|
686
|
+
expect(transactor).to be_sleeping
|
687
|
+
expect(worker.status).to eq('sleeping')
|
688
|
+
|
689
|
+
# Notice here we're calling "run" and not "run!" with a bang.
|
690
|
+
expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
|
691
|
+
expect(transactor).to be_running
|
692
|
+
expect(worker.reload.status).to eq('running')
|
693
|
+
end
|
694
|
+
|
695
|
+
it 'should not create a database transaction' do
|
696
|
+
expect(transactor.class).not_to receive(:transaction)
|
697
|
+
expect {transactor.run}.to raise_error(StandardError, 'failed on purpose')
|
698
|
+
end
|
699
|
+
end
|
700
|
+
end
|
701
|
+
end
|
702
|
+
|
703
|
+
describe "invalid states with persistence" do
|
704
|
+
|
705
|
+
it "should not store states" do
|
706
|
+
validator = Validator.create(:name => 'name')
|
707
|
+
validator.status = 'invalid_state'
|
708
|
+
expect(validator.save).to be_falsey
|
709
|
+
expect {validator.save!}.to raise_error(ActiveRecord::RecordInvalid)
|
710
|
+
|
711
|
+
validator.reload
|
712
|
+
expect(validator).to be_sleeping
|
713
|
+
end
|
714
|
+
|
715
|
+
it "should store invalid states if configured" do
|
716
|
+
persistor = InvalidPersistor.create(:name => 'name')
|
717
|
+
persistor.status = 'invalid_state'
|
718
|
+
expect(persistor.save).to be_truthy
|
719
|
+
|
720
|
+
persistor.reload
|
721
|
+
expect(persistor.status).to eq('invalid_state')
|
722
|
+
end
|
723
|
+
|
724
|
+
end
|
725
|
+
|
726
|
+
describe 'basic example with two state machines' do
|
727
|
+
let(:example) { BasicActiveRecordTwoStateMachinesExample.new }
|
728
|
+
|
729
|
+
it 'should initialise properly' do
|
730
|
+
expect(example.aasm(:search).current_state).to eql :initialised
|
731
|
+
expect(example.aasm(:sync).current_state).to eql :unsynced
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
735
|
+
describe 'testing the README examples' do
|
736
|
+
it 'Usage' do
|
737
|
+
job = ReadmeJob.new
|
738
|
+
|
739
|
+
expect(job.sleeping?).to eql true
|
740
|
+
expect(job.may_run?).to eql true
|
741
|
+
|
742
|
+
job.run
|
743
|
+
|
744
|
+
expect(job.running?).to eql true
|
745
|
+
expect(job.sleeping?).to eql false
|
746
|
+
expect(job.may_run?).to eql false
|
747
|
+
|
748
|
+
expect { job.run }.to raise_error(AASM::InvalidTransition)
|
749
|
+
end
|
750
|
+
end
|
751
|
+
|
752
|
+
describe 'testing the instance_level skip validation with _without_validation method' do
|
753
|
+
let(:example) do
|
754
|
+
obj = InstanceLevelSkipValidationExample.new(state: 'new')
|
755
|
+
obj.save(validate: false)
|
756
|
+
obj
|
757
|
+
end
|
758
|
+
|
759
|
+
it 'should be able to change the state with invalid record' do
|
760
|
+
expect(example.valid?).to be_falsey
|
761
|
+
expect(example.complete!).to be_falsey
|
762
|
+
expect(example.complete_without_validation!).to be_truthy
|
763
|
+
expect(example.state).to eq('complete')
|
764
|
+
end
|
765
|
+
|
766
|
+
it 'shouldn\'t affect the behaviour of existing method after calling _without_validation! method' do
|
767
|
+
expect(example.set_draft!).to be_falsey
|
768
|
+
expect(example.set_draft_without_validation!).to be_truthy
|
769
|
+
expect(example.state).to eq('draft')
|
770
|
+
expect(example.complete!).to be_falsey
|
771
|
+
end
|
772
|
+
end
|
773
|
+
end
|