foreman-tasks 5.0.0 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/foreman_tasks/api/tasks_controller.rb +4 -4
- data/app/controllers/foreman_tasks/tasks_controller.rb +5 -4
- data/app/graphql/types/recurring_logic.rb +1 -0
- data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +4 -1
- data/app/lib/actions/middleware/watch_delegated_proxy_sub_tasks.rb +2 -6
- data/app/lib/actions/trigger_proxy_batch.rb +79 -0
- data/app/models/foreman_tasks/recurring_logic.rb +8 -0
- data/app/models/foreman_tasks/task/dynflow_task.rb +8 -3
- data/app/models/foreman_tasks/task.rb +1 -0
- data/app/models/foreman_tasks/triggering.rb +12 -4
- data/app/views/foreman_tasks/api/tasks/show.json.rabl +1 -1
- data/app/views/foreman_tasks/layouts/react.html.erb +0 -1
- data/app/views/foreman_tasks/recurring_logics/index.html.erb +4 -2
- data/app/views/foreman_tasks/task_groups/recurring_logic_task_groups/_recurring_logic_task_group.html.erb +4 -0
- data/db/migrate/20210720115251_add_purpose_to_recurring_logic.rb +6 -0
- data/extra/foreman-tasks-cleanup.sh +127 -0
- data/extra/foreman-tasks-export.sh +117 -0
- data/lib/foreman_tasks/tasks/export_tasks.rake +92 -47
- data/lib/foreman_tasks/version.rb +1 -1
- data/test/controllers/api/tasks_controller_test.rb +29 -0
- data/test/controllers/tasks_controller_test.rb +19 -0
- data/test/unit/actions/trigger_proxy_batch_test.rb +59 -0
- data/test/unit/triggering_test.rb +22 -0
- data/webpack/ForemanTasks/Components/TaskActions/TaskActionHelpers.js +11 -4
- data/webpack/ForemanTasks/Components/TaskActions/TaskActionHelpers.test.js +27 -5
- data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +8 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +6 -1
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableHelpers.js +2 -1
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +22 -11
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableReducer.js +17 -16
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +3 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableHelpers.test.js +1 -1
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableReducer.test.js +3 -1
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +12 -2
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableReducer.test.js.snap +5 -0
- data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/__snapshots__/selectionHeaderCellFormatter.test.js.snap +1 -0
- data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/selectionHeaderCellFormatter.test.js +1 -1
- data/webpack/ForemanTasks/Components/TasksTable/formatters/selectionHeaderCellFormatter.js +1 -0
- data/webpack/ForemanTasks/Components/TasksTable/index.js +2 -0
- metadata +8 -5
- data/app/services/foreman_tasks/dashboard_table_filter.rb +0 -56
- data/test/unit/dashboard_table_filter_test.rb +0 -77
@@ -0,0 +1,117 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
PROGNAME="$0"
|
4
|
+
EXECUTE=0
|
5
|
+
RAKE_COMMAND="${RAKE_COMMAND:-"foreman-rake"}"
|
6
|
+
|
7
|
+
function die() {
|
8
|
+
local code="$1"
|
9
|
+
local message="$2"
|
10
|
+
echo "$message" >&2
|
11
|
+
exit $code
|
12
|
+
}
|
13
|
+
|
14
|
+
function build_rake() {
|
15
|
+
echo -n "$RAKE_COMMAND "
|
16
|
+
echo -n 'foreman_tasks:export_tasks '
|
17
|
+
for env in TASK_SEARCH TASK_FILE TASK_FORMAT TASK_DAYS; do
|
18
|
+
local value="${!env}"
|
19
|
+
[ -n "${value}" ] && echo -n "${env}=$(printf '%q' "$value") "
|
20
|
+
done
|
21
|
+
echo
|
22
|
+
}
|
23
|
+
|
24
|
+
function usage() {
|
25
|
+
cat << EOF
|
26
|
+
Usage: $PROGNAME [options]
|
27
|
+
|
28
|
+
An interface script for setting environment variables properly
|
29
|
+
for foreman-tasks:export_tasks rake task. By default only prints
|
30
|
+
the command to run, with -E|--execute flag performs the export.
|
31
|
+
|
32
|
+
Environment variables:
|
33
|
+
RAKE_COMMAND: can be used to redefine path to rake, by default foreman-rake
|
34
|
+
|
35
|
+
Script options:
|
36
|
+
EOF
|
37
|
+
cat <<EOF | column -s\& -t
|
38
|
+
-E|--execute & execute the created rake command
|
39
|
+
-h|--help & show this output
|
40
|
+
EOF
|
41
|
+
|
42
|
+
echo
|
43
|
+
echo Export options:
|
44
|
+
cat <<EOF | column -s\& -t
|
45
|
+
-d|--days DAYS & export only tasks started within the last DAYS days
|
46
|
+
-f|--format FORMAT & export tasks in FORMAT, one of html, html-dir, csv
|
47
|
+
-o|--output FILE & export tasks into FILE, a random file will be used if not provided
|
48
|
+
-s|--search QUERY & use QUERY in scoped search format to match tasks to export
|
49
|
+
EOF
|
50
|
+
}
|
51
|
+
|
52
|
+
SHORTOPTS="d:Ehs:o:f:"
|
53
|
+
LONGOPTS="days:,execute,help,search:,output:,format:"
|
54
|
+
|
55
|
+
ARGS=$(getopt -s bash \
|
56
|
+
--options $SHORTOPTS \
|
57
|
+
--longoptions $LONGOPTS \
|
58
|
+
--name $PROGNAME \
|
59
|
+
-- "$@" )
|
60
|
+
|
61
|
+
if [ $? -gt 0 ]; then
|
62
|
+
die 1 "getopt failed"
|
63
|
+
fi
|
64
|
+
|
65
|
+
eval set -- "$ARGS"
|
66
|
+
|
67
|
+
while true; do
|
68
|
+
case $1 in
|
69
|
+
-d|--days)
|
70
|
+
shift
|
71
|
+
TASK_DAYS="$1"
|
72
|
+
;;
|
73
|
+
-s|--search)
|
74
|
+
shift
|
75
|
+
TASK_SEARCH="$1"
|
76
|
+
;;
|
77
|
+
-o|--output)
|
78
|
+
shift
|
79
|
+
TASK_FILE="$1"
|
80
|
+
;;
|
81
|
+
-f|--format)
|
82
|
+
case "$2" in
|
83
|
+
"html" | "html-dir" | "csv")
|
84
|
+
shift
|
85
|
+
TASK_FORMAT="$1"
|
86
|
+
;;
|
87
|
+
*)
|
88
|
+
die 1 "Value for $1 must be one of html, csv. Given $2"
|
89
|
+
;;
|
90
|
+
esac
|
91
|
+
;;
|
92
|
+
-h|--help)
|
93
|
+
usage
|
94
|
+
exit 0
|
95
|
+
;;
|
96
|
+
-E|--execute)
|
97
|
+
EXECUTE=1
|
98
|
+
;;
|
99
|
+
\?)
|
100
|
+
die 1 "Invalid option: -$OPTARG"
|
101
|
+
;;
|
102
|
+
--)
|
103
|
+
;;
|
104
|
+
*)
|
105
|
+
[ -n "$1" ] || break
|
106
|
+
die 1 "Unaccepted parameter: $1"
|
107
|
+
shift
|
108
|
+
;;
|
109
|
+
esac
|
110
|
+
shift
|
111
|
+
done
|
112
|
+
|
113
|
+
if [ "$EXECUTE" -eq 1 ]; then
|
114
|
+
build_rake | sh
|
115
|
+
else
|
116
|
+
build_rake
|
117
|
+
fi
|
@@ -12,7 +12,7 @@ namespace :foreman_tasks do
|
|
12
12
|
|
13
13
|
* TASK_SEARCH : scoped search filter (example: 'label = "Actions::Foreman::Host::ImportFacts"')
|
14
14
|
* TASK_FILE : file to export to
|
15
|
-
* TASK_FORMAT : format to use for the export (either html or csv)
|
15
|
+
* TASK_FORMAT : format to use for the export (either html, html-dir or csv)
|
16
16
|
* TASK_DAYS : number of days to go back
|
17
17
|
|
18
18
|
If TASK_SEARCH is not defined, it defaults to all tasks in the past 7 days and
|
@@ -185,23 +185,27 @@ namespace :foreman_tasks do
|
|
185
185
|
end
|
186
186
|
|
187
187
|
class PageHelper
|
188
|
-
def self.pagify(template)
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
#{template}
|
202
|
-
<body>
|
203
|
-
</html>
|
188
|
+
def self.pagify(io, template = nil)
|
189
|
+
io.write <<~HTML
|
190
|
+
<html>
|
191
|
+
<head>
|
192
|
+
<title>Dynflow Console</title>
|
193
|
+
<script src="jquery.js"></script>
|
194
|
+
<link rel="stylesheet" type="text/css" href="bootstrap.css">
|
195
|
+
<link rel="stylesheet" type="text/css" href="application.css">
|
196
|
+
<script src="bootstrap.js"></script>
|
197
|
+
<script src="run_prettify.js"></script>
|
198
|
+
<script src="application.js"></script>
|
199
|
+
</head>
|
200
|
+
<body>
|
204
201
|
HTML
|
202
|
+
if block_given?
|
203
|
+
yield io
|
204
|
+
else
|
205
|
+
io.write template
|
206
|
+
end
|
207
|
+
ensure
|
208
|
+
io.write '</body></html>'
|
205
209
|
end
|
206
210
|
|
207
211
|
def self.copy_assets(tmp_dir)
|
@@ -216,13 +220,65 @@ namespace :foreman_tasks do
|
|
216
220
|
end
|
217
221
|
end
|
218
222
|
|
219
|
-
def self.
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
223
|
+
def self.generate_with_index(io)
|
224
|
+
io.write '<div><table class="table">'
|
225
|
+
yield io
|
226
|
+
ensure
|
227
|
+
io.write '</table></div>'
|
228
|
+
end
|
229
|
+
|
230
|
+
def self.generate_index_entry(io, task)
|
231
|
+
io << <<~HTML
|
232
|
+
<tr>
|
233
|
+
<td><a href=\"#{task.id}.html\">#{task.label}</a></td>
|
234
|
+
<td>#{task.started_at}</td>
|
235
|
+
<td>#{task.duration}</td>
|
236
|
+
<td>#{task.state}</td>
|
237
|
+
<td>#{task.result}</td>
|
238
|
+
</tr>
|
239
|
+
HTML
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def csv_export(export_filename, tasks)
|
244
|
+
CSV.open(export_filename, 'wb') do |csv|
|
245
|
+
csv << %w[id state type label result parent_task_id started_at ended_at duration]
|
246
|
+
tasks.find_each do |task|
|
247
|
+
csv << [task.id, task.state, task.type, task.label, task.result,
|
248
|
+
task.parent_task_id, task.started_at, task.ended_at, task.duration]
|
224
249
|
end
|
225
|
-
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def html_export(workdir, tasks)
|
254
|
+
PageHelper.copy_assets(workdir)
|
255
|
+
|
256
|
+
renderer = TaskRender.new
|
257
|
+
total = tasks.count(:all)
|
258
|
+
index = File.open(File.join(workdir, 'index.html'), 'w')
|
259
|
+
|
260
|
+
File.open(File.join(workdir, 'index.html'), 'w') do |index|
|
261
|
+
PageHelper.pagify(index) do |io|
|
262
|
+
PageHelper.generate_with_index(io) do |index|
|
263
|
+
tasks.find_each.each_with_index do |task, count|
|
264
|
+
File.open(File.join(workdir, "#{task.id}.html"), 'w') { |file| PageHelper.pagify(file, renderer.render_task(task)) }
|
265
|
+
PageHelper.generate_index_entry(index, task)
|
266
|
+
puts "#{count + 1}/#{total}"
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def generate_filename(format)
|
274
|
+
base = "/tmp/task-export-#{Time.now.to_i}"
|
275
|
+
case format
|
276
|
+
when 'html'
|
277
|
+
base + '.tar.gz'
|
278
|
+
when 'csv'
|
279
|
+
base + '.csv'
|
280
|
+
when 'html-dir'
|
281
|
+
base
|
226
282
|
end
|
227
283
|
end
|
228
284
|
|
@@ -239,36 +295,25 @@ namespace :foreman_tasks do
|
|
239
295
|
end
|
240
296
|
|
241
297
|
format = ENV['TASK_FORMAT'] || 'html'
|
242
|
-
export_filename = ENV['TASK_FILE'] ||
|
298
|
+
export_filename = ENV['TASK_FILE'] || generate_filename(format)
|
243
299
|
|
244
|
-
tasks = ForemanTasks::Task.search_for(filter)
|
300
|
+
tasks = ForemanTasks::Task.search_for(filter).order(:started_at => :desc).with_duration.distinct
|
245
301
|
|
246
302
|
puts _("Exporting all tasks matching filter #{filter}")
|
247
|
-
puts _("Gathering #{tasks.count} tasks.")
|
248
|
-
|
303
|
+
puts _("Gathering #{tasks.count(:all)} tasks.")
|
304
|
+
case format
|
305
|
+
when 'html'
|
249
306
|
Dir.mktmpdir('task-export') do |tmp_dir|
|
250
|
-
|
251
|
-
|
252
|
-
renderer = TaskRender.new
|
253
|
-
total = tasks.count
|
254
|
-
|
255
|
-
tasks.find_each.with_index do |task, count|
|
256
|
-
File.open(File.join(tmp_dir, "#{task.id}.html"), 'w') { |file| file.write(PageHelper.pagify(renderer.render_task(task))) }
|
257
|
-
puts "#{count + 1}/#{total}"
|
258
|
-
end
|
259
|
-
|
260
|
-
File.open(File.join(tmp_dir, 'index.html'), 'w') { |file| file.write(PageHelper.pagify(PageHelper.generate_index(tasks))) }
|
261
|
-
|
307
|
+
html_export(tmp_dir, tasks)
|
262
308
|
system("tar", "czf", export_filename, tmp_dir)
|
263
309
|
end
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
end
|
310
|
+
when 'html-dir'
|
311
|
+
FileUtils.mkdir_p(export_filename)
|
312
|
+
html_export(export_filename, tasks)
|
313
|
+
when 'csv'
|
314
|
+
csv_export(export_filename, tasks)
|
315
|
+
else
|
316
|
+
raise "Unkonwn export format '#{format}'"
|
272
317
|
end
|
273
318
|
|
274
319
|
puts "Created #{export_filename}"
|
@@ -68,6 +68,17 @@ module ForemanTasks
|
|
68
68
|
data = JSON.parse(response.body)
|
69
69
|
_(data[0]['results'][0]['id']).must_equal task.id
|
70
70
|
end
|
71
|
+
|
72
|
+
it 'can search for a specific resource' do
|
73
|
+
org = FactoryBot.create(:organization)
|
74
|
+
task = FactoryBot.create(:task_with_links, resource_id: org.id, resource_type: 'Organization')
|
75
|
+
|
76
|
+
post :bulk_search, params: { :searches => [{ :type => 'resource', :resource_id => org.id, :resource_type => 'Organization' }] }
|
77
|
+
|
78
|
+
assert_response :success
|
79
|
+
data = JSON.parse(response.body)
|
80
|
+
_(data[0]['results'][0]['id']).must_equal task.id
|
81
|
+
end
|
71
82
|
end
|
72
83
|
|
73
84
|
describe 'GET /api/tasks/show' do
|
@@ -91,6 +102,24 @@ module ForemanTasks
|
|
91
102
|
session: set_session_user(User.current)
|
92
103
|
assert_response :not_found
|
93
104
|
end
|
105
|
+
|
106
|
+
it 'shows duration column' do
|
107
|
+
task = ForemanTasks::Task.with_duration.find(FactoryBot.create(:dynflow_task).id)
|
108
|
+
get :show, params: { id: task.id }, session: set_session_user
|
109
|
+
assert_response :success
|
110
|
+
data = JSON.parse(response.body)
|
111
|
+
_(data['duration']).must_equal task.duration
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe 'GET /api/tasks/index' do
|
116
|
+
it 'shows duration column' do
|
117
|
+
task = ForemanTasks::Task.with_duration.find(FactoryBot.create(:dynflow_task).id)
|
118
|
+
get :index, session: set_session_user
|
119
|
+
assert_response :success
|
120
|
+
data = JSON.parse(response.body)
|
121
|
+
_(data['results'][0]['duration']).must_equal task.duration
|
122
|
+
end
|
94
123
|
end
|
95
124
|
|
96
125
|
describe 'GET /api/tasks/summary' do
|
@@ -91,6 +91,15 @@ module ForemanTasks
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
+
describe 'index' do
|
95
|
+
it 'shows duration column' do
|
96
|
+
task = ForemanTasks::Task.with_duration.find(FactoryBot.create(:some_task).id)
|
97
|
+
get(:index, params: {}, session: set_session_user)
|
98
|
+
assert_response :success
|
99
|
+
assert_include response.body.lines[1], task.duration
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
94
103
|
describe 'sub_tasks' do
|
95
104
|
it 'does not allow user without permissions to see task details' do
|
96
105
|
setup_user('view', 'foreman_tasks', 'owner.id = current_user')
|
@@ -109,6 +118,16 @@ module ForemanTasks
|
|
109
118
|
assert_equal 2, response.body.lines.size
|
110
119
|
assert_include response.body.lines[1], 'Child action'
|
111
120
|
end
|
121
|
+
|
122
|
+
it 'shows duration column' do
|
123
|
+
parent = ForemanTasks::Task.find(FactoryBot.create(:some_task).id)
|
124
|
+
child = ForemanTasks::Task.with_duration.find(FactoryBot.create(:some_task).id)
|
125
|
+
child.parent_task_id = parent.id
|
126
|
+
child.save!
|
127
|
+
get(:sub_tasks, params: { id: parent.id }, session: set_session_user)
|
128
|
+
assert_response :success
|
129
|
+
assert_include response.body.lines[1], child.duration
|
130
|
+
end
|
112
131
|
end
|
113
132
|
|
114
133
|
describe 'taxonomy scoping' do
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'foreman_tasks_test_helper'
|
2
|
+
|
3
|
+
module ForemanTasks
|
4
|
+
class TriggerProxyBatchTest < ActiveSupport::TestCase
|
5
|
+
describe Actions::TriggerProxyBatch do
|
6
|
+
include ::Dynflow::Testing
|
7
|
+
|
8
|
+
let(:batch_size) { 20 }
|
9
|
+
let(:total_count) { 100 }
|
10
|
+
let(:action) { create_and_plan_action(Actions::TriggerProxyBatch, total_count: total_count, batch_size: batch_size) }
|
11
|
+
let(:triggered) { run_action(action) }
|
12
|
+
|
13
|
+
describe 'triggering' do
|
14
|
+
it 'doesnt run anything on trigger' do
|
15
|
+
Actions::TriggerProxyBatch.any_instance.expects(:trigger_remote_tasks_batch).never
|
16
|
+
_(triggered.state).must_equal :suspended
|
17
|
+
_(triggered.output[:planned_count]).must_equal 0
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'triggers remote tasks on TriggerNextBatch' do
|
21
|
+
Actions::TriggerProxyBatch.any_instance.expects(:trigger_remote_tasks_batch).once
|
22
|
+
run_action(triggered, Actions::TriggerProxyBatch::TriggerNextBatch[1])
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'triggers remote tasks on TriggerNextBatch defined number of times' do
|
26
|
+
Actions::TriggerProxyBatch.any_instance.expects(:trigger_remote_tasks_batch).twice
|
27
|
+
run_action(triggered, Actions::TriggerProxyBatch::TriggerNextBatch[2])
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'triggers the last batch on resume' do
|
31
|
+
Actions::TriggerProxyBatch.any_instance.expects(:trigger_remote_tasks_batch).once
|
32
|
+
triggered.output[:planned_count] = ((total_count - 1) / batch_size) * batch_size
|
33
|
+
run_action(triggered)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#trigger_remote_tasks_batch' do
|
38
|
+
let(:proxy_operation_name) { 'ansible_runner' }
|
39
|
+
let(:grouped_remote_batch) { Array.new(batch_size).map { |i| mock("RemoteTask#{i}") } }
|
40
|
+
let(:remote_tasks) do
|
41
|
+
m = mock('RemoteTaskARScope')
|
42
|
+
m.stubs(pending: m, order: m)
|
43
|
+
m.stubs(group_by: { proxy_operation_name => grouped_remote_batch })
|
44
|
+
m
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'fetches batch_size of tasks and triggers them' do
|
48
|
+
remote_tasks.expects(:first).with(batch_size).returns(remote_tasks)
|
49
|
+
remote_tasks.expects(:size).returns(batch_size)
|
50
|
+
triggered.expects(:remote_tasks).returns(remote_tasks)
|
51
|
+
ForemanTasks::RemoteTask.expects(:batch_trigger).with(proxy_operation_name, grouped_remote_batch)
|
52
|
+
|
53
|
+
triggered.trigger_remote_tasks_batch
|
54
|
+
_(triggered.output[:planned_count]).must_equal(batch_size)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -19,6 +19,28 @@ class TriggeringTest < ActiveSupport::TestCase
|
|
19
19
|
triggering.recurring_logic.stubs(:valid?).returns(false)
|
20
20
|
_(triggering).wont_be :valid?
|
21
21
|
end
|
22
|
+
|
23
|
+
it 'is valid when recurring logic has purpose' do
|
24
|
+
logic = FactoryBot.build(:recurring_logic, :purpose => 'test', :state => 'active')
|
25
|
+
triggering = FactoryBot.build(:triggering, :recurring_logic => logic, :mode => :recurring, :input_type => :cronline, :cronline => '* * * * *')
|
26
|
+
_(triggering).must_be :valid?
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'is invalid when recurring logic with given purpose exists' do
|
30
|
+
FactoryBot.create(:recurring_logic, :purpose => 'test', :state => 'active')
|
31
|
+
logic = FactoryBot.build(:recurring_logic, :purpose => 'test', :state => 'active')
|
32
|
+
triggering = FactoryBot.build(:triggering, :recurring_logic => logic, :mode => :recurring, :input_type => :cronline, :cronline => '* * * * *')
|
33
|
+
_(triggering).wont_be :valid?
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'is valid when recurring logic with given purpose exists and is not active or disabled' do
|
37
|
+
['finished', 'cancelled', 'failed'].each do |item|
|
38
|
+
FactoryBot.create(:recurring_logic, :purpose => 'test', :state => item)
|
39
|
+
end
|
40
|
+
logic = FactoryBot.build(:recurring_logic, :purpose => 'test')
|
41
|
+
triggering = FactoryBot.build(:triggering, :recurring_logic => logic, :mode => :recurring, :input_type => :cronline, :cronline => '* * * * *')
|
42
|
+
_(triggering).must_be :valid?
|
43
|
+
end
|
22
44
|
end
|
23
45
|
|
24
46
|
it 'cannot have mode set to arbitrary value' do
|