foreman-tasks 9.1.0 → 9.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby_tests.yml +2 -0
- data/.rubocop.yml +6 -35
- data/.rubocop_todo.yml +216 -24
- data/Gemfile +2 -17
- data/app/controllers/foreman_tasks/tasks_controller.rb +8 -9
- data/app/models/foreman_tasks/remote_task.rb +3 -0
- data/app/models/foreman_tasks/task/dynflow_task.rb +4 -0
- data/foreman-tasks.gemspec +1 -1
- data/lib/foreman_tasks/tasks/export_tasks.rake +2 -2
- data/lib/foreman_tasks/version.rb +1 -1
- data/test/controllers/api/tasks_controller_test.rb +17 -17
- data/test/controllers/tasks_controller_test.rb +6 -6
- data/test/helpers/foreman_tasks/foreman_tasks_helper_test.rb +7 -7
- data/test/helpers/foreman_tasks/tasks_helper_test.rb +3 -3
- data/test/lib/actions/middleware/keep_current_request_id_test.rb +3 -3
- data/test/lib/concerns/polling_action_extensions_test.rb +4 -4
- data/test/tasks/generate_task_actions_test.rb +1 -1
- data/test/unit/actions/action_with_sub_plans_test.rb +4 -4
- data/test/unit/actions/bulk_action_test.rb +9 -9
- data/test/unit/actions/proxy_action_test.rb +20 -20
- data/test/unit/actions/recurring_action_test.rb +15 -15
- data/test/unit/actions/trigger_proxy_batch_test.rb +4 -4
- data/test/unit/cleaner_test.rb +24 -24
- data/test/unit/locking_test.rb +8 -8
- data/test/unit/proxy_selector_test.rb +9 -9
- data/test/unit/recurring_logic_test.rb +31 -32
- data/test/unit/remote_task_test.rb +4 -4
- data/test/unit/task_groups_test.rb +4 -4
- data/test/unit/task_test.rb +51 -51
- data/test/unit/triggering_test.rb +11 -11
- data/test/unit/troubleshooting_help_generator_test.rb +6 -6
- data/test/unit/ui_notifications_test.rb +20 -21
- metadata +4 -4
@@ -4,17 +4,17 @@ class RecurringLogicsTest < ActiveSupport::TestCase
|
|
4
4
|
describe 'generating times' do
|
5
5
|
it 'assembles cronline' do
|
6
6
|
hash = {}
|
7
|
-
|
7
|
+
assert_equal '* * * * *', ForemanTasks::RecurringLogic.assemble_cronline(hash)
|
8
8
|
hash.update :minutes => '*'
|
9
|
-
|
9
|
+
assert_equal '* * * * *', ForemanTasks::RecurringLogic.assemble_cronline(hash)
|
10
10
|
hash.update :hours => '0,12'
|
11
|
-
|
11
|
+
assert_equal '* 0,12 * * *', ForemanTasks::RecurringLogic.assemble_cronline(hash)
|
12
12
|
hash.update :days => '*/2'
|
13
|
-
|
13
|
+
assert_equal '* 0,12 */2 * *', ForemanTasks::RecurringLogic.assemble_cronline(hash)
|
14
14
|
hash.update :months => '12'
|
15
|
-
|
15
|
+
assert_equal '* 0,12 */2 12 *', ForemanTasks::RecurringLogic.assemble_cronline(hash)
|
16
16
|
hash.update :days_of_week => '1,2,3,4,5,6,7'
|
17
|
-
|
17
|
+
assert_equal '* 0,12 */2 12 1,2,3,4,5,6,7', ForemanTasks::RecurringLogic.assemble_cronline(hash)
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'generates correct times' do
|
@@ -25,17 +25,17 @@ class RecurringLogicsTest < ActiveSupport::TestCase
|
|
25
25
|
minute = 0
|
26
26
|
reference_time = Time.utc(year, month, day, hour, minute)
|
27
27
|
parser = ForemanTasks::RecurringLogic.new_from_cronline('* * * * *')
|
28
|
-
|
28
|
+
assert_equal Time.utc(year, month, day, hour, minute), parser.next_occurrence_time(reference_time)
|
29
29
|
parser = ForemanTasks::RecurringLogic.new_from_cronline('*/2 * * * *')
|
30
|
-
|
30
|
+
assert_equal Time.utc(year, month, day, hour, minute), parser.next_occurrence_time(reference_time)
|
31
31
|
parser = ForemanTasks::RecurringLogic.new_from_cronline('*/2 18,19 * * *')
|
32
|
-
|
32
|
+
assert_equal Time.utc(year, month, day, 18), parser.next_occurrence_time(reference_time)
|
33
33
|
parser = ForemanTasks::RecurringLogic.new_from_cronline('*/2 18,19 10 * *')
|
34
|
-
|
34
|
+
assert_equal Time.utc(year, month + 1, 10, 18, minute), parser.next_occurrence_time(reference_time)
|
35
35
|
parser = ForemanTasks::RecurringLogic.new_from_cronline('*/2 18,19 10 11,12 *')
|
36
|
-
|
36
|
+
assert_equal Time.utc(year, 11, 10, 18, 0), parser.next_occurrence_time(reference_time)
|
37
37
|
parser = ForemanTasks::RecurringLogic.new_from_cronline('* * * * 1')
|
38
|
-
|
38
|
+
assert_equal Time.utc(year, month + 1, 5), parser.next_occurrence_time(reference_time)
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'creates correct cronline hash' do
|
@@ -48,10 +48,10 @@ class RecurringLogicsTest < ActiveSupport::TestCase
|
|
48
48
|
expected_result_daily = { :minutes => minutes, :hours => hours }
|
49
49
|
expected_result_weekly = { :minutes => minutes, :hours => hours, :days_of_week => '1,4,6' }
|
50
50
|
expected_result_monthly = { :minutes => minutes, :hours => hours, :days => days }
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
assert_equal expected_result_hourly, ForemanTasks::RecurringLogic.cronline_hash(:hourly, time_hash, days, days_of_week)
|
52
|
+
assert_equal expected_result_daily, ForemanTasks::RecurringLogic.cronline_hash(:daily, time_hash, days, days_of_week)
|
53
|
+
assert_equal expected_result_weekly, ForemanTasks::RecurringLogic.cronline_hash(:weekly, time_hash, days, days_of_week)
|
54
|
+
assert_equal expected_result_monthly, ForemanTasks::RecurringLogic.cronline_hash(:monthly, time_hash, days, days_of_week)
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'validates cronline correctly' do
|
@@ -68,18 +68,18 @@ class RecurringLogicsTest < ActiveSupport::TestCase
|
|
68
68
|
it 'can have limited number of repeats' do
|
69
69
|
parser = ForemanTasks::RecurringLogic.new_from_cronline('* * * * *')
|
70
70
|
parser.state = 'active'
|
71
|
-
|
71
|
+
assert parser.can_continue?
|
72
72
|
parser.max_iteration = 5
|
73
73
|
parser.expects(:iteration).twice.returns(5)
|
74
|
-
|
74
|
+
assert_not parser.can_continue?
|
75
75
|
parser.max_iteration = nil
|
76
76
|
time = Time.utc(2015, 9, 29, 15, 0)
|
77
77
|
parser.end_time = time
|
78
|
-
|
78
|
+
assert_not parser.can_continue?(time)
|
79
79
|
parser.end_time = time + 120
|
80
|
-
|
80
|
+
assert parser.can_continue?(time)
|
81
81
|
parser.max_iteration = 5
|
82
|
-
|
82
|
+
assert_not parser.can_continue?(time)
|
83
83
|
end
|
84
84
|
|
85
85
|
it 'generates delay options' do
|
@@ -87,9 +87,8 @@ class RecurringLogicsTest < ActiveSupport::TestCase
|
|
87
87
|
parser.stubs(:id).returns(1)
|
88
88
|
reference_time = Time.utc(2015, 9, 29, 15)
|
89
89
|
expected_hash = { :start_at => reference_time, :start_before => nil, :recurring_logic_id => parser.id, :frozen => false }
|
90
|
-
|
91
|
-
|
92
|
-
.must_equal expected_hash.merge(:start_before => reference_time + 3600)
|
90
|
+
assert_equal expected_hash, parser.generate_delay_options(reference_time)
|
91
|
+
assert_equal expected_hash.merge(:start_before => reference_time + 3600), parser.generate_delay_options(reference_time, 'start_before' => reference_time + 3600)
|
93
92
|
end
|
94
93
|
|
95
94
|
it 'can start' do
|
@@ -119,19 +118,19 @@ class RecurringLogicsTest < ActiveSupport::TestCase
|
|
119
118
|
it 'has a task group associated to all tasks that were created as part of the recurring logic' do
|
120
119
|
recurring_logic = ForemanTasks::RecurringLogic.new_from_cronline('* * * * *')
|
121
120
|
recurring_logic.save
|
122
|
-
|
121
|
+
assert_kind_of ForemanTasks::TaskGroups::RecurringLogicTaskGroup, recurring_logic.task_group
|
123
122
|
task = FactoryBot.build(:dynflow_task, :user_create_task)
|
124
123
|
task.task_groups << Support::DummyTaskGroup.new
|
125
124
|
task.save!
|
126
125
|
recurring_logic.task_group.tasks << task
|
127
|
-
|
126
|
+
assert_includes recurring_logic.task_groups, *task.task_groups
|
128
127
|
end
|
129
128
|
|
130
129
|
it 'can be created from triggering' do
|
131
130
|
triggering = FactoryBot.build(:triggering, :recurring, :end_time_limited)
|
132
131
|
logic = ForemanTasks::RecurringLogic.new_from_triggering(triggering)
|
133
132
|
# Mysql coerces the times a bit
|
134
|
-
|
133
|
+
assert_in_delta triggering.end_time, logic.end_time, 1.second
|
135
134
|
end
|
136
135
|
|
137
136
|
it 'cannot trigger tasks when cancelled' do
|
@@ -181,24 +180,24 @@ class RecurringLogicsTest < ActiveSupport::TestCase
|
|
181
180
|
let(:logic) { FactoryBot.build(:recurring_logic) }
|
182
181
|
|
183
182
|
it 'is valid by default' do
|
184
|
-
|
183
|
+
assert_predicate logic, :valid?
|
185
184
|
end
|
186
185
|
|
187
186
|
it 'is invalid when end time in past' do
|
188
187
|
logic.end_time = (Time.zone.now - 120)
|
189
|
-
|
188
|
+
assert_not_predicate logic, :valid?
|
190
189
|
end
|
191
190
|
|
192
191
|
it 'is invalid when iteration limit < 1' do
|
193
192
|
logic.max_iteration = 0
|
194
|
-
|
193
|
+
assert_not_predicate logic, :valid?
|
195
194
|
end
|
196
195
|
|
197
196
|
it 'is valid when in active state' do
|
198
197
|
logic.end_time = (Time.zone.now - 120)
|
199
|
-
|
198
|
+
assert_not_predicate logic, :valid?
|
200
199
|
logic.state = 'active'
|
201
|
-
|
200
|
+
assert_predicate logic, :valid?
|
202
201
|
end
|
203
202
|
end
|
204
203
|
end
|
@@ -24,8 +24,8 @@ module ForemanTasks
|
|
24
24
|
RemoteTask.batch_trigger('a_operation', remote_tasks)
|
25
25
|
remote_tasks.each do |remote_task|
|
26
26
|
remote_task.reload
|
27
|
-
|
28
|
-
|
27
|
+
assert_equal 'triggered', remote_task.state
|
28
|
+
assert_equal (remote_task.id + 5).to_s, remote_task.remote_task_id
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -50,8 +50,8 @@ module ForemanTasks
|
|
50
50
|
RemoteTask.batch_trigger('a_operation', remote_tasks)
|
51
51
|
remote_tasks.each do |remote_task|
|
52
52
|
remote_task.reload
|
53
|
-
|
54
|
-
|
53
|
+
assert_equal 'triggered', remote_task.state
|
54
|
+
assert_equal (remote_task.id + 5).to_s, remote_task.remote_task_id
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
@@ -59,18 +59,18 @@ module ForemanTasks
|
|
59
59
|
|
60
60
|
it 'has the task group assigned' do
|
61
61
|
task = spawn_task.call ChildAction
|
62
|
-
|
62
|
+
assert_equal [1], task.task_groups.map(&:id)
|
63
63
|
end
|
64
64
|
|
65
65
|
it 'tasks inherit task groups correctly' do
|
66
66
|
children_count = 3
|
67
67
|
task = spawn_task.call ParentAction, children_count
|
68
68
|
# Parent task has task groups of its children
|
69
|
-
|
69
|
+
assert_equal [1, 2, 3, 4], task.task_groups.map(&:id).sort
|
70
70
|
# Children have the parent's and their own, they don't have their siblings' task groups
|
71
|
-
|
71
|
+
assert_equal children_count, task.sub_tasks.count
|
72
72
|
task.sub_tasks.each do |sub_task|
|
73
|
-
|
73
|
+
assert_equal [1, sub_task.input[:id]].sort, sub_task.task_groups.map(&:id).sort
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
data/test/unit/task_test.rb
CHANGED
@@ -32,8 +32,8 @@ class TasksTest < ActiveSupport::TestCase
|
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'cannot search by arbitrary key' do
|
35
|
-
|
36
|
-
|
35
|
+
assert_raises(ScopedSearch::QueryNotSupported) { ForemanTasks::Task.search_for('user.my_key ~ 5') }
|
36
|
+
assert_raises(ScopedSearch::QueryNotSupported) { ForemanTasks::Task.search_for('user. = 5') }
|
37
37
|
end
|
38
38
|
|
39
39
|
test 'can search the tasks by negated user' do
|
@@ -59,8 +59,8 @@ class TasksTest < ActiveSupport::TestCase
|
|
59
59
|
end
|
60
60
|
|
61
61
|
test 'cannot glob on user\'s id' do
|
62
|
-
|
63
|
-
|
62
|
+
assert_raises(ScopedSearch::QueryNotSupported) { ForemanTasks::Task.search_for("user.id ~ something") }
|
63
|
+
assert_raises(ScopedSearch::QueryNotSupported) { ForemanTasks::Task.search_for("user.id ~ 5") }
|
64
64
|
end
|
65
65
|
|
66
66
|
test 'can search the tasks by user with wildcards' do
|
@@ -105,28 +105,28 @@ class TasksTest < ActiveSupport::TestCase
|
|
105
105
|
|
106
106
|
it 'can search by seconds ' do
|
107
107
|
skip unless on_postgresql?
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
108
|
+
assert_empty scope.search_for('duration < 2')
|
109
|
+
assert_equal [@task_one, @task_two], scope.search_for('duration = 2')
|
110
|
+
assert_empty scope.search_for('duration < "2 seconds"')
|
111
|
+
assert_empty scope.search_for('duration > "2 seconds"')
|
112
|
+
assert_equal [@task_one, @task_two], scope.search_for('duration = "2 seconds"')
|
113
|
+
assert_equal [@task_one, @task_two], scope.search_for('duration <= "2 seconds"')
|
114
|
+
assert_equal [@task_one, @task_two], scope.search_for('duration >= "2 seconds"')
|
115
115
|
end
|
116
116
|
|
117
117
|
it 'can search by other time intervals' do
|
118
118
|
skip unless on_postgresql?
|
119
119
|
%w[minutes hours days months years].each do |interval|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
120
|
+
assert_equal [@task_one, @task_two], scope.search_for("duration < \"2 #{interval}\"")
|
121
|
+
assert_empty scope.search_for("duration > \"2 #{interval}\"")
|
122
|
+
assert_empty scope.search_for("duration = \"2 #{interval}\"")
|
123
|
+
assert_equal [@task_one, @task_two], scope.search_for("duration <= \"2 #{interval}\"")
|
124
|
+
assert_empty scope.search_for("duration >= \"2 #{interval}\"")
|
125
125
|
end
|
126
126
|
end
|
127
127
|
|
128
128
|
it 'raises an exception if duration is unknown' do
|
129
|
-
|
129
|
+
assert_raises(ScopedSearch::QueryNotSupported) { ForemanTasks::Task.search_for('duration = "25 potatoes"') }
|
130
130
|
end
|
131
131
|
end
|
132
132
|
|
@@ -144,7 +144,7 @@ class TasksTest < ActiveSupport::TestCase
|
|
144
144
|
describe 'users' do
|
145
145
|
test 'users can be deleted even if they have tasks assigned' do
|
146
146
|
user = FactoryBot.create(:user)
|
147
|
-
FactoryBot.create(:some_task, :
|
147
|
+
FactoryBot.create(:some_task, user: user)
|
148
148
|
user.destroy!
|
149
149
|
end
|
150
150
|
end
|
@@ -152,14 +152,14 @@ class TasksTest < ActiveSupport::TestCase
|
|
152
152
|
describe 'state_updated_at' do
|
153
153
|
it 'updates the state_updated_at when the state changes' do
|
154
154
|
task = FactoryBot.create(:some_task)
|
155
|
-
|
155
|
+
assert_operator task.state_updated_at, :>, Time.now.utc - 1.minute, "Newly created task has to have state_updated_at set"
|
156
156
|
task.update(state_updated_at: nil)
|
157
157
|
task.result = 'error'
|
158
158
|
task.save
|
159
|
-
|
159
|
+
assert_nil task.state_updated_at, "Other than state change should not affect 'state_updated_at'"
|
160
160
|
task.state = 'running'
|
161
161
|
task.save
|
162
|
-
|
162
|
+
assert_not_nil task.state_updated_at, "State change should set 'state_updated_at'"
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
@@ -171,7 +171,7 @@ class TasksTest < ActiveSupport::TestCase
|
|
171
171
|
permission = FactoryBot.build(:permission)
|
172
172
|
permission.resource_type = 'ForemanTasks::Task'
|
173
173
|
permission.save!
|
174
|
-
FactoryBot.create(:filter, :
|
174
|
+
FactoryBot.create(:filter, role: role, permissions: [permission])
|
175
175
|
|
176
176
|
User.current = user
|
177
177
|
task = FactoryBot.create(:dynflow_task)
|
@@ -184,21 +184,21 @@ class TasksTest < ActiveSupport::TestCase
|
|
184
184
|
describe 'consistency check' do
|
185
185
|
it 'ensures the tasks marked as running are really running in Dynflow' do
|
186
186
|
task = ForemanTasks.sync_task(Support::DummyDynflowAction)
|
187
|
-
task.update(:
|
188
|
-
task.update(:
|
187
|
+
task.update(state: 'running') # Updating state updates the timestamp
|
188
|
+
task.update(state_updated_at: Time.zone.now - 5.minutes)
|
189
189
|
|
190
190
|
ForemanTasks::Task::DynflowTask.consistency_check
|
191
191
|
task.reload
|
192
|
-
|
192
|
+
assert_equal 'stopped', task.state
|
193
193
|
end
|
194
194
|
end
|
195
195
|
|
196
196
|
describe 'active job task' do
|
197
197
|
it 'when scheduled to the future, the label and action is set properly' do
|
198
|
-
job = Support::DummyActiveJob.set(:
|
199
|
-
task = ForemanTasks::Task.find_by!(:
|
200
|
-
|
201
|
-
|
198
|
+
job = Support::DummyActiveJob.set(wait: 12.hours).perform_later
|
199
|
+
task = ForemanTasks::Task.find_by!(external_id: job.provider_job_id)
|
200
|
+
assert_equal "Dummy action", task.action
|
201
|
+
assert_equal "Support::DummyActiveJob", task.label
|
202
202
|
end
|
203
203
|
end
|
204
204
|
|
@@ -214,9 +214,9 @@ class TasksTest < ActiveSupport::TestCase
|
|
214
214
|
end
|
215
215
|
|
216
216
|
it 'handles the error while loading the task and does not propagate errors unless necessary' do
|
217
|
-
task.cancellable?
|
218
|
-
task.resumable?
|
219
|
-
task.main_action
|
217
|
+
assert_nothing_raised { task.cancellable? }
|
218
|
+
assert_nothing_raised { task.resumable? }
|
219
|
+
assert_nothing_raised { task.main_action }
|
220
220
|
assert_equal 'Support::DummyDynflowAction', task.get_humanized(:humanized_name)
|
221
221
|
assert_equal 0, task.progress
|
222
222
|
assert_raises(KeyError) { task.cancel }
|
@@ -226,19 +226,19 @@ class TasksTest < ActiveSupport::TestCase
|
|
226
226
|
describe 'subtask count querying' do
|
227
227
|
let(:result_base) do
|
228
228
|
{
|
229
|
-
:
|
230
|
-
:
|
231
|
-
:
|
232
|
-
:
|
233
|
-
:
|
234
|
-
:
|
229
|
+
error: 0,
|
230
|
+
warning: 0,
|
231
|
+
total: 0,
|
232
|
+
success: 0,
|
233
|
+
cancelled: 0,
|
234
|
+
pending: 0,
|
235
235
|
}
|
236
236
|
end
|
237
237
|
let(:task) { FactoryBot.create(:dynflow_task) }
|
238
238
|
|
239
239
|
describe 'without sub tasks' do
|
240
240
|
it 'calculates the progress report correctly' do
|
241
|
-
|
241
|
+
assert_equal result_base, task.sub_tasks_counts
|
242
242
|
end
|
243
243
|
end
|
244
244
|
|
@@ -248,22 +248,22 @@ class TasksTest < ActiveSupport::TestCase
|
|
248
248
|
before { task.sub_tasks = [success, failed] }
|
249
249
|
|
250
250
|
it 'calculate the progress report correctly' do
|
251
|
-
expected_result = result_base.merge(:
|
252
|
-
|
251
|
+
expected_result = result_base.merge(success: 1, error: 1, total: 2)
|
252
|
+
assert_equal expected_result, task.sub_tasks_counts
|
253
253
|
end
|
254
254
|
|
255
255
|
it 'calculates the progress report correctly when using batch planning' do
|
256
|
-
result_base = self.result_base.merge(:
|
257
|
-
fake_action = OpenStruct.new(:
|
256
|
+
result_base = self.result_base.merge(success: 1, error: 1, total: 25)
|
257
|
+
fake_action = OpenStruct.new(total_count: 25)
|
258
258
|
task.stubs(:main_action).returns(fake_action)
|
259
259
|
|
260
260
|
task.state = 'stopped'
|
261
|
-
expected_result = result_base.merge(:
|
262
|
-
|
261
|
+
expected_result = result_base.merge(cancelled: 23)
|
262
|
+
assert_equal expected_result, task.sub_tasks_counts
|
263
263
|
|
264
264
|
task.state = 'pending'
|
265
|
-
expected_result = result_base.merge(:
|
266
|
-
|
265
|
+
expected_result = result_base.merge(pending: 23)
|
266
|
+
assert_equal expected_result, task.sub_tasks_counts
|
267
267
|
end
|
268
268
|
end
|
269
269
|
end
|
@@ -284,11 +284,11 @@ class TasksTest < ActiveSupport::TestCase
|
|
284
284
|
let(:task) { FactoryBot.create(:some_task) }
|
285
285
|
|
286
286
|
it 'can indicate it is delayed' do
|
287
|
-
|
288
|
-
|
287
|
+
assert_not_predicate task, :delayed?
|
288
|
+
assert_equal 'Immediate', task.execution_type
|
289
289
|
task.start_at = Time.now.utc + 100
|
290
|
-
|
291
|
-
|
290
|
+
assert_predicate task, :delayed?
|
291
|
+
assert_equal 'Delayed', task.execution_type
|
292
292
|
end
|
293
293
|
end
|
294
294
|
|
@@ -3,34 +3,34 @@ require 'foreman_tasks_test_helper'
|
|
3
3
|
class TriggeringTest < ActiveSupport::TestCase
|
4
4
|
describe 'validation' do
|
5
5
|
it 'is valid when immediate' do
|
6
|
-
|
6
|
+
assert_predicate(FactoryBot.build(:triggering), :valid?)
|
7
7
|
end
|
8
8
|
|
9
9
|
it 'is validates future execution' do
|
10
10
|
triggering = FactoryBot.build(:triggering, :future)
|
11
|
-
|
11
|
+
assert_predicate(triggering, :valid?)
|
12
12
|
triggering.start_before = triggering.start_at - 120
|
13
|
-
|
13
|
+
assert_not_predicate(triggering, :valid?)
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'is invalid when recurring logic is invalid' do
|
17
17
|
triggering = FactoryBot.build(:triggering, :recurring)
|
18
|
-
|
18
|
+
assert_predicate(triggering, :valid?)
|
19
19
|
triggering.recurring_logic.stubs(:valid?).returns(false)
|
20
|
-
|
20
|
+
assert_not_predicate(triggering, :valid?)
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'is valid when recurring logic has purpose' do
|
24
24
|
logic = FactoryBot.build(:recurring_logic, :purpose => 'test', :state => 'active')
|
25
25
|
triggering = FactoryBot.build(:triggering, :recurring_logic => logic, :mode => :recurring, :input_type => :cronline, :cronline => '* * * * *')
|
26
|
-
|
26
|
+
assert_predicate(triggering, :valid?)
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'is invalid when recurring logic with given purpose exists' do
|
30
30
|
FactoryBot.create(:recurring_logic, :purpose => 'test', :state => 'active')
|
31
31
|
logic = FactoryBot.build(:recurring_logic, :purpose => 'test', :state => 'active')
|
32
32
|
triggering = FactoryBot.build(:triggering, :recurring_logic => logic, :mode => :recurring, :input_type => :cronline, :cronline => '* * * * *')
|
33
|
-
|
33
|
+
assert_not_predicate(triggering, :valid?)
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'is valid when recurring logic with given purpose exists and is not active or disabled' do
|
@@ -39,14 +39,14 @@ class TriggeringTest < ActiveSupport::TestCase
|
|
39
39
|
end
|
40
40
|
logic = FactoryBot.build(:recurring_logic, :purpose => 'test')
|
41
41
|
triggering = FactoryBot.build(:triggering, :recurring_logic => logic, :mode => :recurring, :input_type => :cronline, :cronline => '* * * * *')
|
42
|
-
|
42
|
+
assert_predicate(triggering, :valid?)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'cannot have mode set to arbitrary value' do
|
47
47
|
triggering = FactoryBot.build(:triggering)
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
assert_predicate(triggering, :valid?)
|
49
|
+
assert_raises(ArgumentError) { triggering.mode = 'bogus' }
|
50
|
+
assert_raises(ArgumentError) { triggering.mode = 27 }
|
51
51
|
end
|
52
52
|
end
|
@@ -28,8 +28,8 @@ module ForemanTasks
|
|
28
28
|
|
29
29
|
it 'generates html from the main action troubleshooting_info' do
|
30
30
|
generated_html = subject.generate_html
|
31
|
-
|
32
|
-
|
31
|
+
assert_includes generated_html, "A paused task represents a process that has not finished properly"
|
32
|
+
assert_includes generated_html, %(See <a href="#{expected_troubleshooting_url}">troubleshooting documentation</a> for more details on how to resolve the issue)
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'exposes link details' do
|
@@ -47,10 +47,10 @@ module ForemanTasks
|
|
47
47
|
|
48
48
|
it 'includes additional description in generated html' do
|
49
49
|
generated_html = subject.generate_html
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
assert_includes generated_html, 'A paused task represents a process that has not finished properly'
|
51
|
+
assert_match %r{See <a href=".*">troubleshooting documentation</a> for more details on how to resolve the issue}, generated_html
|
52
|
+
assert_includes generated_html, 'This task requires special handling'
|
53
|
+
assert_includes generated_html, 'Investigate <a href="/additional_troubleshooting_page">custom link</a> on more details for this custom error'
|
54
54
|
end
|
55
55
|
|
56
56
|
it 'includes additional links' do
|
@@ -22,33 +22,33 @@ module ForemanTasks
|
|
22
22
|
it 'notifies all admins about current amount of paused tasks when some paused task occurs' do
|
23
23
|
trigger_task
|
24
24
|
notification = user_notifications(admin_user).first
|
25
|
-
|
25
|
+
assert_equal "There is 1 paused task in the system that need attention", notification.message
|
26
26
|
links = notification.actions['links']
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
assert_includes(links, { 'href' => '/foreman_tasks/tasks?search=state%3Dpaused',
|
28
|
+
'title' => 'List of tasks' })
|
29
|
+
assert_includes(links, { 'name' => 'troubleshooting',
|
30
|
+
'title' => 'Troubleshooting Documentation',
|
31
|
+
'description' => 'See %{link} for more details on how to resolve the issue',
|
32
|
+
'href' => "https://theforeman.org/manuals/#{SETTINGS[:version].short}/tasks_troubleshooting.html#",
|
33
|
+
'external' => true })
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'aggregates the notification when multiple tasks get paused' do
|
37
37
|
trigger_task
|
38
38
|
recipient1 = NotificationRecipient.find_by(user_id: admin_user)
|
39
|
-
|
39
|
+
assert_match(/1 paused task/, recipient1.notification.message)
|
40
40
|
|
41
41
|
new_admin_user = FactoryBot.create(:user, :admin)
|
42
42
|
|
43
43
|
trigger_task
|
44
44
|
|
45
|
-
|
46
|
-
|
45
|
+
assert_nil NotificationRecipient.find_by(id: recipient1.id)
|
46
|
+
assert_nil Notification.find_by(id: recipient1.notification.id)
|
47
47
|
recipient2 = NotificationRecipient.find_by(user_id: admin_user)
|
48
|
-
|
48
|
+
assert_match(/2 paused tasks/, recipient2.notification.message)
|
49
49
|
|
50
50
|
new_recipient = NotificationRecipient.find_by(user_id: new_admin_user)
|
51
|
-
|
51
|
+
assert_equal recipient2.notification, new_recipient.notification
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -58,15 +58,14 @@ module ForemanTasks
|
|
58
58
|
notifications = user_notifications(task_owner)
|
59
59
|
assert_equal 1, notifications.size, 'Only notification for the main action should be triggered'
|
60
60
|
notification = notifications.first
|
61
|
-
|
61
|
+
assert_equal "The task 'Dummy pause action' got paused", notification.message
|
62
62
|
links = notification.actions['links']
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
'external' => true)
|
63
|
+
assert_includes(links, "href" => "/foreman_tasks/tasks/#{task.id}", "title" => "Task Details")
|
64
|
+
assert_includes(links, 'name' => 'troubleshooting',
|
65
|
+
'title' => 'Troubleshooting Documentation',
|
66
|
+
'description' => 'See %{link} for more details on how to resolve the issue',
|
67
|
+
'href' => "https://theforeman.org/manuals/#{SETTINGS[:version].short}/tasks_troubleshooting.html#Support::DummyPauseAction",
|
68
|
+
'external' => true)
|
70
69
|
end
|
71
70
|
end
|
72
71
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 9.
|
4
|
+
version: 9.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Nečas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dynflow
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: 1.9.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: 1.9.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: fugit
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|