rails_workflow 0.3.9 → 0.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 (161) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +2 -0
  3. data/app/concerns/rails_workflow/operation_status.rb +2 -0
  4. data/app/concerns/rails_workflow/operation_templates/assignments.rb +3 -1
  5. data/app/concerns/rails_workflow/operation_templates/dependencies.rb +18 -18
  6. data/app/concerns/rails_workflow/operations/assignments.rb +7 -5
  7. data/app/concerns/rails_workflow/operations/dependencies.rb +2 -0
  8. data/app/concerns/rails_workflow/status.rb +11 -15
  9. data/app/concerns/rails_workflow/user/assignment.rb +2 -0
  10. data/app/concerns/rails_workflow/uuid.rb +2 -0
  11. data/app/controllers/rails_workflow/application_controller.rb +2 -0
  12. data/app/controllers/rails_workflow/errors_controller.rb +2 -0
  13. data/app/controllers/rails_workflow/operation_templates_controller.rb +3 -1
  14. data/app/controllers/rails_workflow/operations_controller.rb +3 -1
  15. data/app/controllers/rails_workflow/process_templates_controller.rb +10 -8
  16. data/app/controllers/rails_workflow/processes_controller.rb +10 -8
  17. data/app/decorators/rails_workflow/context_decorator.rb +2 -0
  18. data/app/decorators/rails_workflow/decorator.rb +2 -0
  19. data/app/decorators/rails_workflow/operation_decorator.rb +2 -0
  20. data/app/decorators/rails_workflow/operation_helper_decorator.rb +2 -0
  21. data/app/decorators/rails_workflow/operation_template_decorator.rb +2 -0
  22. data/app/decorators/rails_workflow/paginating_decorator.rb +2 -0
  23. data/app/decorators/rails_workflow/process_decorator.rb +2 -0
  24. data/app/decorators/rails_workflow/process_template_decorator.rb +2 -0
  25. data/app/decorators/rails_workflow/status_decorator.rb +2 -0
  26. data/app/helpers/rails_workflow/application_helper.rb +2 -0
  27. data/app/jobs/rails_workflow/operation_execution_job.rb +11 -1
  28. data/app/models/rails_workflow/context.rb +3 -1
  29. data/app/models/rails_workflow/error.rb +23 -50
  30. data/app/models/rails_workflow/operation.rb +39 -3
  31. data/app/models/rails_workflow/operation_template.rb +2 -2
  32. data/app/models/rails_workflow/process.rb +34 -5
  33. data/app/models/rails_workflow/process_template.rb +12 -8
  34. data/app/models/rails_workflow/user_by_group_operation.rb +2 -0
  35. data/app/models/rails_workflow/user_by_role_operation.rb +2 -0
  36. data/app/models/rails_workflow/user_operation.rb +2 -0
  37. data/app/serializers/rails_workflow/operation_template_serializer.rb +2 -0
  38. data/app/serializers/rails_workflow/process_template_serializer.rb +2 -0
  39. data/app/services/rails_workflow/default_importer_preprocessor.rb +2 -0
  40. data/app/services/rails_workflow/process_importer.rb +2 -0
  41. data/app/views/rails_workflow/processes/index.html.slim +5 -5
  42. data/config/initializers/rails_workflow.rb +3 -3
  43. data/config/routes.rb +4 -2
  44. data/db/migrate/20150630174700_create_workflow_processes.rb +86 -84
  45. data/lib/generators/rails_workflow/install/install_generator.rb +2 -0
  46. data/lib/generators/rails_workflow/install/templates/create_workflow_processes.rb +86 -84
  47. data/lib/rails_workflow/config.rb +65 -24
  48. data/lib/rails_workflow/db/mysql.rb +3 -1
  49. data/lib/rails_workflow/db/pg.rb +3 -1
  50. data/lib/rails_workflow/dependency_resolver.rb +74 -0
  51. data/lib/rails_workflow/engine.rb +3 -1
  52. data/lib/rails_workflow/error_builder.rb +57 -0
  53. data/lib/rails_workflow/error_resolver.rb +72 -0
  54. data/lib/rails_workflow/operation_builder.rb +95 -0
  55. data/lib/rails_workflow/operation_runner.rb +113 -0
  56. data/lib/rails_workflow/process_builder.rb +57 -0
  57. data/lib/rails_workflow/process_manager.rb +66 -0
  58. data/lib/rails_workflow/process_runner.rb +72 -0
  59. data/lib/rails_workflow/version.rb +3 -1
  60. data/lib/rails_workflow.rb +2 -0
  61. data/lib/tasks/rails_workflow_tasks.rake +1 -0
  62. data/spec/concerns/status_spec.rb +25 -0
  63. data/spec/controllers/rails_workflow/operation_templates_controller_spec.rb +2 -0
  64. data/spec/controllers/rails_workflow/operations_controller_spec.rb +2 -0
  65. data/spec/controllers/rails_workflow/process_templates_controller_spec.rb +2 -0
  66. data/spec/controllers/rails_workflow/processes_controller_spec.rb +3 -1
  67. data/spec/dummy/Rakefile +2 -0
  68. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  69. data/spec/dummy/app/controllers/leads_controller.rb +2 -0
  70. data/spec/dummy/app/controllers/sales_contacts_controller.rb +2 -0
  71. data/spec/dummy/app/decorators/lead_decorator.rb +2 -0
  72. data/spec/dummy/app/decorators/sales_contact_decorator.rb +2 -0
  73. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  74. data/spec/dummy/app/helpers/leads_helper.rb +2 -0
  75. data/spec/dummy/app/helpers/sales_contacts_helper.rb +2 -0
  76. data/spec/dummy/app/models/bad_operation.rb +2 -0
  77. data/spec/dummy/app/models/bad_operation_template.rb +2 -0
  78. data/spec/dummy/app/models/lead.rb +2 -0
  79. data/spec/dummy/app/models/sales_contact.rb +2 -0
  80. data/spec/dummy/app/models/user.rb +2 -0
  81. data/spec/dummy/bin/bundle +2 -0
  82. data/spec/dummy/bin/rails +2 -0
  83. data/spec/dummy/bin/rake +2 -0
  84. data/spec/dummy/config/application.rb +2 -0
  85. data/spec/dummy/config/boot.rb +2 -0
  86. data/spec/dummy/config/database.yml.semaphore +2 -2
  87. data/spec/dummy/config/environment.rb +2 -0
  88. data/spec/dummy/config/environments/development.rb +2 -0
  89. data/spec/dummy/config/environments/production.rb +2 -0
  90. data/spec/dummy/config/environments/test.rb +2 -0
  91. data/spec/dummy/config/initializers/assets.rb +2 -0
  92. data/spec/dummy/config/initializers/backtrace_silencers.rb +1 -0
  93. data/spec/dummy/config/initializers/cookies_serializer.rb +2 -0
  94. data/spec/dummy/config/initializers/devise.rb +2 -0
  95. data/spec/dummy/config/initializers/filter_parameter_logging.rb +2 -0
  96. data/spec/dummy/config/initializers/inflections.rb +1 -0
  97. data/spec/dummy/config/initializers/mime_types.rb +1 -0
  98. data/spec/dummy/config/initializers/session_store.rb +2 -0
  99. data/spec/dummy/config/initializers/workflow.rb +2 -0
  100. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
  101. data/spec/dummy/config/routes.rb +2 -0
  102. data/spec/dummy/config.ru +2 -0
  103. data/spec/dummy/db/migrate/20150127171613_devise_create_users.rb +2 -0
  104. data/spec/dummy/db/migrate/20150130042852_create_sales_contacts.rb +2 -0
  105. data/spec/dummy/db/migrate/20150130043008_create_leads.rb +2 -0
  106. data/spec/dummy/log/development.log +110 -0
  107. data/spec/dummy/log/test.log +0 -0
  108. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/7O/7O5OddMZvWFGpj71BCdc0vA55rhj4YPoL0XjBV4_OYk.cache +1 -0
  109. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Cy/CyixQwp8QvorgpRadtYf6_zY35nZZp0JmrhkDN16XPM.cache +1 -0
  110. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/FW/FWR5Q7EP17cTcY35R1MscF6MX2HYiH5I2ZII89YLYxc.cache +1 -0
  111. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/HQ/HQuQO1k4kOyLSDXJEc8p-XR2agdkPF7mIFyh2noiNrU.cache +1 -0
  112. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/N4/N4e3G5QNTts2OVqkL0kxoP1xnAdDWnumpnH1m6WAsuY.cache +0 -0
  113. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Rs/RsIG_ias53xeb4WHWRodcMcDmVyz1QvLQNy4gV2iBSo.cache +1 -0
  114. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/WI/WI2XYMfwCaPWcjvvouKVltl9oKqKZL-BHePPLhC-rzw.cache +1 -0
  115. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Yc/YcbQRZWzddLfawePxNTEXcFFiS7asAyrujZzciT99l0.cache +1 -0
  116. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ai/aihcJWCIJGiHDpamul8bzy4jMsxnhewX6XWtkdsQ9dc.cache +1 -0
  117. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/fR/fRVQN4mU7z3MVJD9u1LMq8idpOH8o2tFh_YouMYGAM8.cache +1 -0
  118. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gU/gUFNMb7SgxFyz5ZZcGfp-VYRVIw711HUeiWonMzYrcU.cache +1 -0
  119. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/h8/h86FNb4MxO5dq40P8KcCgGwZ_uqd8nn_O2fMWGDApW8.cache +1 -0
  120. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/q7/q7cZDJXZFXTklMF8JAQSMr-MBxOKc7q1vZAPPR5RBf4.cache +2 -0
  121. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/s9/s98GbJDqEe4PG3moRH6h-ukIZmQz9Frq4LO_Z9vCBLM.cache +1 -0
  122. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xX/xXCd205lXu7u_BuyBL0kfZwkBGJLvocHDItBfU6tMm4.cache +2 -0
  123. data/spec/factories/context.rb +2 -0
  124. data/spec/factories/operation_templates.rb +2 -0
  125. data/spec/factories/operations.rb +3 -1
  126. data/spec/factories/process_templates.rb +2 -0
  127. data/spec/factories/processes.rb +3 -1
  128. data/spec/factories/user.rb +2 -0
  129. data/spec/factories/workflow_errors.rb +2 -0
  130. data/spec/features/operations_spec.rb +2 -0
  131. data/spec/features/process_template_spec.rb +2 -0
  132. data/spec/lib/error_builder_spec.rb +137 -0
  133. data/spec/lib/error_resolver_spec.rb +182 -0
  134. data/spec/lib/operation_builder_spec.rb +69 -0
  135. data/spec/lib/process_builder_spec.rb +19 -0
  136. data/spec/{core/rails_workflow → lib}/process_manager_spec.rb +17 -27
  137. data/spec/models/rails_workflow/context_spec.rb +6 -3
  138. data/spec/models/rails_workflow/error_spec.rb +20 -147
  139. data/spec/models/rails_workflow/operation_spec.rb +64 -97
  140. data/spec/models/rails_workflow/operation_template_spec.rb +24 -11
  141. data/spec/models/rails_workflow/process_spec.rb +5 -2
  142. data/spec/models/rails_workflow/process_template_spec.rb +2 -36
  143. data/spec/rails_helper.rb +2 -0
  144. data/spec/serializers/process_template_serializer_spec.rb +2 -0
  145. data/spec/services/process_importer_spec.rb +2 -0
  146. data/spec/spec_helper.rb +2 -0
  147. data/spec/support/controller_macros.rb +2 -0
  148. data/spec/support/pages/operations.rb +2 -0
  149. data/spec/support/rails_workflow/custom_operation.rb +2 -0
  150. data/spec/support/rails_workflow/custom_operation_template.rb +2 -0
  151. data/spec/{core → support}/rails_workflow/prepare_template.rb +3 -1
  152. data/spec/support/workflow_helper.rb +2 -0
  153. metadata +54 -28
  154. data/app/concerns/rails_workflow/operation_templates/default_builder.rb +0 -56
  155. data/app/concerns/rails_workflow/operations/default_runner.rb +0 -121
  156. data/app/concerns/rails_workflow/process_templates/default_builder.rb +0 -52
  157. data/app/concerns/rails_workflow/processes/default_runner.rb +0 -64
  158. data/app/concerns/rails_workflow/processes/dependency_resolver.rb +0 -54
  159. data/app/concerns/rails_workflow/reset_cache.rb +0 -13
  160. data/app/jobs/rails_workflow/operation_error_job.rb +0 -40
  161. data/app/managers/rails_workflow/process_manager.rb +0 -40
Binary file
@@ -0,0 +1 @@
1
+ "%����"m�J���S��E�j!�/�d�]�/[���
@@ -0,0 +1 @@
1
+ "%�Q)��MI-���{�h�⃯�\�WUD ���
@@ -0,0 +1 @@
1
+ "%]���:ǚ G�z#�X��oD^O��ެp8R
@@ -0,0 +1 @@
1
+ "%���NO|�Z�����?ʼ�P(v�o�J�9��1
@@ -0,0 +1 @@
1
+ "%���}�Tk�d \��@H��`�vB�'B���I
@@ -0,0 +1 @@
1
+ "%������S��h�˯Wu;&�V�#�Y��
@@ -0,0 +1 @@
1
+ "%>��.��l�;T��_2��IT���Ɣc�ḩ
@@ -0,0 +1 @@
1
+ "%�U7��r��� ����ڥ�2�)d*�d��/po�
@@ -0,0 +1 @@
1
+ "%��P�k7}�i�Ur�����Փa!�����@�a
@@ -0,0 +1 @@
1
+ "%���h��;����*���b(��n��Gn��L
@@ -0,0 +1 @@
1
+ "%K�@Ĝ(�2T�J��s�)iW�8���4�
@@ -0,0 +1,2 @@
1
+ "%~�n��Um�lr�+� Mp��
2
+ ���4v����
@@ -0,0 +1 @@
1
+ "%��}�������J�d���p�A,#G�� �j��
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  FactoryGirl.define do
2
4
  factory :context, class: 'RailsWorkflow::Context'
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  FactoryGirl.define do
2
4
  factory :operation_template, class: 'RailsWorkflow::OperationTemplate' do
3
5
  title 'Operation Template'
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  FactoryGirl.define do
2
4
  factory :operation, class: 'RailsWorkflow::Operation' do
3
5
  title 'Test Operation'
4
- status RailsWorkflow::Operation::NOT_STARTED
6
+ status RailsWorkflow::Status::NOT_STARTED
5
7
 
6
8
  factory :operation_with_context do
7
9
  context { create :context, data: { msg: 'Test' } }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  FactoryGirl.define do
2
4
  factory :process_template, class: 'RailsWorkflow::ProcessTemplate' do
3
5
  title 'Process Template'
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  FactoryGirl.define do
2
4
  factory :process, class: 'RailsWorkflow::Process' do
3
- status RailsWorkflow::Process::NOT_STARTED
5
+ status RailsWorkflow::Status::NOT_STARTED
4
6
  context { create :context, data: { msg: 'Test message' } }
5
7
  end
6
8
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  FactoryGirl.define do
2
4
  factory :user, class: User do
3
5
  email 'test@test.com'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  FactoryGirl.define do
2
4
  factory :workflow_error, class: 'RailsWorkflow::Error' do
3
5
  message 'MyString'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
  require_relative '../support/pages/operations.rb'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_helper'
2
4
 
3
5
  feature 'Process Template' do
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ module RailsWorkflow
6
+ RSpec.describe ErrorBuilder do
7
+ # TODO: add process builder failures tests
8
+ let(:process_template) { create :process_template }
9
+ let(:process) { create(:process, template: process_template) }
10
+ let(:operation) { create :operation, process: process }
11
+ let(:operation_runner) { OperationRunner.new(operation) }
12
+ let(:test_message) { 'Test message' }
13
+
14
+ let(:error) { operation.workflow_errors.first }
15
+ let(:error_parent) { operation }
16
+ let(:error_target) { operation }
17
+ let(:error_args) { nil }
18
+ let(:error_parent_type) { RailsWorkflow::Operation }
19
+ let(:error_method) { 'start_process' }
20
+
21
+ shared_context 'workflow failed' do
22
+ specify do
23
+ expect { failing_method_call }
24
+ .to change { RailsWorkflow::Error.count }.by(1)
25
+ end
26
+
27
+ context 'manager creates error' do
28
+ before { failing_method_call }
29
+ it_behaves_like 'has workflow error'
30
+ end
31
+ end
32
+
33
+ shared_examples 'has workflow error' do
34
+ it { expect(process.reload.status).to eq RailsWorkflow::Status::ERROR }
35
+
36
+ it { expect(error_parent.workflow_errors.count).to eq 1 }
37
+ it { expect(error_parent.status).to eq RailsWorkflow::Status::ERROR }
38
+
39
+ it { expect(error.message).to eq test_message }
40
+
41
+ # TODO: check with custom operation / process types
42
+ it { expect(error.parent).to be_a_kind_of(error_parent_type) }
43
+
44
+ it { expect(error.data[:target]).to eq error_target }
45
+ it { expect(error.data[:method]).to eq error_method }
46
+ it { expect(error.data[:args]).to eq error_args }
47
+ end
48
+
49
+ def raise_error(target, method_name)
50
+ allow(target).to receive(method_name).and_raise(test_message)
51
+ end
52
+
53
+ context 'when operation fails to start' do
54
+ let(:error_target) { 'operation_runner' }
55
+ before { raise_error operation, :can_start? }
56
+ let(:failing_method_call) { operation.start }
57
+ let(:error_method) { 'start' }
58
+
59
+ it_behaves_like 'workflow failed'
60
+ end
61
+
62
+ context 'when operation fails to start waiting' do
63
+ let(:error_target) { 'operation_runner' }
64
+ before { raise_error operation, :update_attribute }
65
+ let(:failing_method_call) { operation_runner.waiting }
66
+ let(:error_method) { 'waiting' }
67
+
68
+ it_behaves_like 'workflow failed'
69
+ end
70
+
71
+ # TODO: cover other errors in execute_in_transitions
72
+ context 'when operation execution fails' do
73
+ let(:error_method) { 'execute_in_transaction' }
74
+ let(:error_target) { 'operation_runner' }
75
+ before { raise_error(operation, :execute) }
76
+ let(:failing_method_call) { operation_runner.execute_in_transaction }
77
+
78
+ it_behaves_like 'workflow failed'
79
+ end
80
+
81
+ context 'when operation build fails' do
82
+ let(:operation_template) { create :operation_template }
83
+ let(:error) { process.workflow_errors.first }
84
+ let(:error_target) { 'operation_builder' }
85
+ let(:error_parent) { process }
86
+ let(:error_parent_type) { RailsWorkflow::Process }
87
+ let(:error_method) { 'create_operation' }
88
+ let(:error_args) { [process, operation_template, []] }
89
+ let(:operation_builder) do
90
+ OperationBuilder.new(process, operation_template)
91
+ end
92
+
93
+ before { raise_error operation_builder, :create_operation! }
94
+ let(:failing_method_call) do
95
+ operation_builder.create_operation
96
+ end
97
+
98
+ it_behaves_like 'workflow failed'
99
+ end
100
+
101
+ context 'when new operations build fails' do
102
+ let(:error) { process.workflow_errors.first }
103
+ let(:error_target) { 'dependency_resolver' }
104
+ let(:error_parent) { process }
105
+ let(:error_method) { 'build_new_operations' }
106
+ let(:error_parent_type) { RailsWorkflow::Process }
107
+ let(:error_args) { [operation] }
108
+ let(:dependency_resolver) { DependencyResolver.new(process) }
109
+
110
+ before { raise_error dependency_resolver, :matched_templates }
111
+ let(:failing_method_call) do
112
+ dependency_resolver.build_new_operations(operation)
113
+ end
114
+
115
+ it_behaves_like 'workflow failed'
116
+ end
117
+
118
+ context 'when process manager fails to start process' do
119
+ let(:process_manager) { RailsWorkflow::ProcessManager.new(process) }
120
+ let(:process_runner) { RailsWorkflow::ProcessRunner.new(process) }
121
+ let(:error) { process.workflow_errors.first }
122
+ let(:error_target) { 'process_manager' }
123
+ let(:error_parent) { process }
124
+ let(:error_parent_type) { RailsWorkflow::Process }
125
+
126
+ let(:failing_method_call) { process_manager.start_process }
127
+ before do
128
+ allow(RailsWorkflow::ProcessRunner).to receive(:new)
129
+ .and_return(process_runner)
130
+
131
+ raise_error process_runner, :start
132
+ end
133
+
134
+ it_behaves_like 'workflow failed'
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,182 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+ require_relative '../support/rails_workflow/prepare_template'
5
+
6
+ module RailsWorkflow
7
+ RSpec.describe ErrorResolver do
8
+ include PrepareTemplate
9
+
10
+ let(:template) { prepare_template }
11
+ let(:process_manager) do
12
+ ProcessManager.new(
13
+ template_id: template.id, context: { msg: 'Test' }
14
+ )
15
+ end
16
+
17
+ let(:process) { process_manager.create_process }
18
+ let(:process_runner) { RailsWorkflow::ProcessRunner.new(process) }
19
+
20
+ context 'operation fails' do
21
+ let(:operation) { process.operations.first }
22
+ let(:error) { operation.workflow_errors.first }
23
+ let(:error_resolver) { described_class.new(error) }
24
+
25
+ context 'to start' do
26
+ before do
27
+ with_failing_instance(Operation, :execute) do
28
+ process_runner.start
29
+ end
30
+ end
31
+
32
+ it 'set proper process status after retry' do
33
+ expect { error_resolver.retry }
34
+ .to change { process.reload.status }
35
+ .from(Status::ERROR).to(Status::DONE)
36
+ end
37
+
38
+ it 'set proper operation status after retry' do
39
+ expect { error_resolver.retry }
40
+ .to change { process.reload.operations.first.status }
41
+ .from(Status::ERROR).to(Status::DONE)
42
+ end
43
+ end
44
+
45
+ context 'to wait' do
46
+ before do
47
+ allow_any_instance_of(Operation)
48
+ .to receive(:can_start?).and_return(false)
49
+
50
+ with_failing_instance(Operation, :update_attribute) do
51
+ process_runner.start
52
+ end
53
+ end
54
+
55
+ it 'set proper process status' do
56
+ expect { error_resolver.retry }
57
+ .to change { process.reload.status }
58
+ .from(Status::ERROR).to(Status::IN_PROGRESS)
59
+ end
60
+
61
+ it 'set proper operation status' do
62
+ expect { error_resolver.retry }
63
+ .to change { process.reload.operations.first.status }
64
+ .from(Status::ERROR).to(Status::WAITING)
65
+ end
66
+ end
67
+
68
+ context 'execution fails' do
69
+ before do
70
+ with_failing_instance(Operation, :execute) do
71
+ process_runner.start
72
+ end
73
+ end
74
+
75
+ it 'set proper process status' do
76
+ expect { error_resolver.retry }
77
+ .to change { process.reload.status }
78
+ .from(Status::ERROR).to(Status::DONE)
79
+ end
80
+
81
+ it 'set proper operation status' do
82
+ expect { error_resolver.retry }
83
+ .to change { process.reload.operations.first.status }
84
+ .from(Status::ERROR).to(Status::DONE)
85
+ end
86
+ end
87
+ end
88
+
89
+ context 'operation building fails' do
90
+ let(:operation) { process.operations.first }
91
+ let(:error) { process.workflow_errors.first }
92
+ let(:error_resolver) { described_class.new(error) }
93
+
94
+ context 'when operation build fails' do
95
+ before do
96
+ with_failing(Operation, :create) do
97
+ process_runner.start
98
+ end
99
+ end
100
+
101
+ it 'set proper process status' do
102
+ expect { error_resolver.retry }
103
+ .to change { process.reload.status }
104
+ .from(Status::ERROR).to(Status::DONE)
105
+ end
106
+
107
+ it 'set proper operation status' do
108
+ expect { error_resolver.retry }
109
+ .to change { process.reload.operations&.first&.status }
110
+ .to(Status::DONE)
111
+ end
112
+ end
113
+ end
114
+
115
+ context 'process runner fails to start' do
116
+ let(:error) { Error.first }
117
+ let(:error_resolver) { described_class.new(error) }
118
+
119
+ context 'when operation build fails' do
120
+ before do
121
+ with_failing_instance(ProcessRunner, :start) do
122
+ process_manager.create_process
123
+ process_manager.start_process
124
+ end
125
+ end
126
+
127
+ it 'set proper process status' do
128
+ expect { error_resolver.retry }
129
+ .to change { Process.first.status }
130
+ .from(Status::ERROR).to(Status::DONE)
131
+ end
132
+
133
+ it 'creates and completes operations' do
134
+ expect { error_resolver.retry }
135
+ .to change { Process.first.operations.count }
136
+ .from(1).to(2)
137
+ end
138
+ end
139
+ end
140
+
141
+ context 'dependency resolver' do
142
+ let(:operation) { process.operations.first }
143
+ let(:error) { process.workflow_errors.first }
144
+ let(:error_resolver) { described_class.new(error) }
145
+
146
+ context 'when operation build fails' do
147
+ before do
148
+ with_failing_instance(DependencyResolver, :matched_templates) do
149
+ process_runner.start
150
+ end
151
+ end
152
+
153
+ it 'set proper process status' do
154
+ expect { error_resolver.retry }
155
+ .to change { Process.first.status }
156
+ .from(Status::ERROR).to(Status::DONE)
157
+ end
158
+
159
+ it 'set proper operation status' do
160
+ expect { error_resolver.retry }
161
+ .to change { Process.first.operations.count }
162
+ .from(1).to(2)
163
+ end
164
+ end
165
+ end
166
+
167
+ def with_failing_instance(target_class, method)
168
+ allow_any_instance_of(target_class)
169
+ .to receive(method) { raise 'Some error' }
170
+
171
+ yield
172
+
173
+ allow_any_instance_of(target_class).to receive(method).and_call_original
174
+ end
175
+
176
+ def with_failing(target, method)
177
+ allow(target).to receive(method) { raise 'Some error' }
178
+ yield
179
+ allow(target).to receive(method).and_call_original
180
+ end
181
+ end
182
+ end