rails_workflow 0.3.9 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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