foreman_remote_execution 14.0.2 → 14.1.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/app/controllers/api/v2/job_invocations_controller.rb +34 -17
- data/app/helpers/remote_execution_helper.rb +2 -2
- data/app/lib/actions/remote_execution/proxy_action.rb +10 -5
- data/app/lib/actions/remote_execution/run_host_job.rb +1 -1
- data/app/lib/actions/remote_execution/template_invocation_progress_logging.rb +2 -3
- data/app/views/api/v2/job_invocations/hosts.json.rabl +15 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20240312133027_extend_template_invocation_events.rb +19 -0
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/webpack/JobInvocationDetail/JobInvocationActions.js +1 -1
- data/webpack/JobInvocationDetail/JobInvocationConstants.js +84 -0
- data/webpack/JobInvocationDetail/JobInvocationDetail.scss +0 -1
- data/webpack/JobInvocationDetail/JobInvocationHostTable.js +210 -0
- data/webpack/JobInvocationDetail/JobInvocationSelectors.js +2 -2
- data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +5 -1
- data/webpack/JobInvocationDetail/__tests__/fixtures.js +9 -0
- data/webpack/JobInvocationDetail/index.js +56 -34
- data/webpack/__mocks__/foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState.js +1 -2
- data/webpack/react_app/components/RecentJobsCard/JobStatusIcon.js +38 -7
- data/webpack/react_app/components/RecentJobsCard/constants.js +4 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostStatus.test.js.snap +1 -1
- data/webpack/react_app/components/TargetingHosts/components/HostStatus.js +6 -6
- metadata +6 -94
- data/.babelrc.js +0 -3
- data/.eslintignore +0 -3
- data/.eslintrc +0 -13
- data/.github/workflows/js_ci.yml +0 -32
- data/.github/workflows/release.yml +0 -16
- data/.github/workflows/ruby_ci.yml +0 -19
- data/.gitignore +0 -19
- data/.packit.yaml +0 -45
- data/.prettierrc +0 -4
- data/.rubocop.yml +0 -105
- data/.rubocop_todo.yml +0 -516
- data/.tx/config +0 -10
- data/Gemfile +0 -5
- data/app/mailers/.gitkeep +0 -0
- data/app/views/dashboard/.gitkeep +0 -0
- data/foreman_remote_execution.gemspec +0 -33
- data/jsconfig.json +0 -8
- data/test/benchmark/run_hosts_job_benchmark.rb +0 -70
- data/test/benchmark/targeting_benchmark.rb +0 -31
- data/test/factories/foreman_remote_execution_factories.rb +0 -147
- data/test/functional/api/v2/foreign_input_sets_controller_test.rb +0 -58
- data/test/functional/api/v2/job_invocations_controller_test.rb +0 -446
- data/test/functional/api/v2/job_templates_controller_test.rb +0 -110
- data/test/functional/api/v2/registration_controller_test.rb +0 -73
- data/test/functional/api/v2/remote_execution_features_controller_test.rb +0 -34
- data/test/functional/api/v2/template_invocations_controller_test.rb +0 -33
- data/test/functional/cockpit_controller_test.rb +0 -16
- data/test/functional/job_invocations_controller_test.rb +0 -132
- data/test/functional/job_templates_controller_test.rb +0 -31
- data/test/functional/ui_job_wizard_controller_test.rb +0 -16
- data/test/graphql/mutations/job_invocations/create_test.rb +0 -58
- data/test/graphql/queries/job_invocation_query_test.rb +0 -31
- data/test/graphql/queries/job_invocations_query_test.rb +0 -35
- data/test/helpers/remote_execution_helper_test.rb +0 -46
- data/test/support/remote_execution_helper.rb +0 -5
- data/test/test_plugin_helper.rb +0 -9
- data/test/unit/actions/run_host_job_test.rb +0 -115
- data/test/unit/actions/run_hosts_job_test.rb +0 -214
- data/test/unit/api_params_test.rb +0 -25
- data/test/unit/concerns/foreman_tasks_cleaner_extensions_test.rb +0 -29
- data/test/unit/concerns/host_extensions_test.rb +0 -219
- data/test/unit/concerns/nic_extensions_test.rb +0 -9
- data/test/unit/execution_task_status_mapper_test.rb +0 -92
- data/test/unit/input_template_renderer_test.rb +0 -503
- data/test/unit/job_invocation_composer_test.rb +0 -974
- data/test/unit/job_invocation_report_template_test.rb +0 -60
- data/test/unit/job_invocation_test.rb +0 -232
- data/test/unit/job_template_effective_user_test.rb +0 -37
- data/test/unit/job_template_test.rb +0 -316
- data/test/unit/remote_execution_feature_test.rb +0 -86
- data/test/unit/remote_execution_provider_test.rb +0 -298
- data/test/unit/renderer_scope_input_test.rb +0 -49
- data/test/unit/targeting_test.rb +0 -206
- data/test/unit/template_invocation_input_value_test.rb +0 -38
@@ -1,974 +0,0 @@
|
|
1
|
-
require 'test_plugin_helper'
|
2
|
-
RemoteExecutionProvider.register(:Ansible, OpenStruct)
|
3
|
-
RemoteExecutionProvider.register(:Mcollective, OpenStruct)
|
4
|
-
|
5
|
-
class JobInvocationComposerTest < ActiveSupport::TestCase
|
6
|
-
before do
|
7
|
-
setup_user('create', 'template_invocations')
|
8
|
-
setup_user('view', 'job_templates', 'name ~ trying*')
|
9
|
-
setup_user('create', 'job_templates', 'name ~ trying*')
|
10
|
-
setup_user('view', 'job_invocations')
|
11
|
-
setup_user('create', 'job_invocations')
|
12
|
-
setup_user('view', 'bookmarks')
|
13
|
-
setup_user('create', 'bookmarks')
|
14
|
-
setup_user('edit', 'bookmarks')
|
15
|
-
setup_user('view', 'hosts')
|
16
|
-
setup_user('create', 'hosts')
|
17
|
-
end
|
18
|
-
|
19
|
-
class AnsibleInputs < RemoteExecutionProvider
|
20
|
-
class << self
|
21
|
-
def provider_input_namespace
|
22
|
-
:ansible
|
23
|
-
end
|
24
|
-
|
25
|
-
def provider_inputs
|
26
|
-
[
|
27
|
-
ForemanRemoteExecution::ProviderInput.new(name: 'tags', label: 'Tags', value: 'fooo', value_type: 'plain'),
|
28
|
-
ForemanRemoteExecution::ProviderInput.new(name: 'tags_flag', label: 'Tags Flag', value: '--tags', options: "--tags\n--skip-tags"),
|
29
|
-
]
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
RemoteExecutionProvider.register(:AnsibleInputs, AnsibleInputs)
|
34
|
-
|
35
|
-
let(:trying_job_template_1) { FactoryBot.create(:job_template, :job_category => 'trying_job_template_1', :name => 'trying1', :provider_type => 'SSH') }
|
36
|
-
let(:trying_job_template_2) { FactoryBot.create(:job_template, :job_category => 'trying_job_template_2', :name => 'trying2', :provider_type => 'Mcollective') }
|
37
|
-
let(:trying_job_template_3) { FactoryBot.create(:job_template, :job_category => 'trying_job_template_1', :name => 'trying3', :provider_type => 'SSH') }
|
38
|
-
let(:trying_job_template_5) { FactoryBot.create(:job_template, :job_category => 'trying_job_template_5', :name => 'trying5', :provider_type => 'SSH') }
|
39
|
-
let(:unauthorized_job_template_1) { FactoryBot.create(:job_template, :job_category => 'trying_job_template_1', :name => 'unauth1', :provider_type => 'SSH') }
|
40
|
-
let(:unauthorized_job_template_2) { FactoryBot.create(:job_template, :job_category => 'unauthorized_job_template_2', :name => 'unauth2', :provider_type => 'Ansible') }
|
41
|
-
|
42
|
-
let(:provider_inputs_job_template) { FactoryBot.create(:job_template, :job_category => 'trying_test_inputs', :name => 'trying provider inputs', :provider_type => 'AnsibleInputs') }
|
43
|
-
|
44
|
-
let(:input1) { FactoryBot.create(:template_input, :template => trying_job_template_1, :input_type => 'user') }
|
45
|
-
let(:input2) { FactoryBot.create(:template_input, :template => trying_job_template_3, :input_type => 'user') }
|
46
|
-
let(:input3) { FactoryBot.create(:template_input, :template => trying_job_template_1, :input_type => 'user', :required => true) }
|
47
|
-
let(:input4) { FactoryBot.create(:template_input, :template => provider_inputs_job_template, :input_type => 'user') }
|
48
|
-
let(:input5) { FactoryBot.create(:template_input, :template => trying_job_template_5, :input_type => 'user', :default => 'value') }
|
49
|
-
let(:unauthorized_input1) { FactoryBot.create(:template_input, :template => unauthorized_job_template_1, :input_type => 'user') }
|
50
|
-
|
51
|
-
let(:ansible_params) { { } }
|
52
|
-
let(:ssh_params) { { } }
|
53
|
-
let(:mcollective_params) { { } }
|
54
|
-
let(:providers_params) { { :providers => { :ansible => ansible_params, :ssh => ssh_params, :mcollective => mcollective_params } } }
|
55
|
-
|
56
|
-
context 'with general new invocation and empty params' do
|
57
|
-
let(:params) { {} }
|
58
|
-
let(:composer) { JobInvocationComposer.from_ui_params(params) }
|
59
|
-
|
60
|
-
describe '#available_templates' do
|
61
|
-
it 'obeys authorization' do
|
62
|
-
composer # lazy load composer before stubbing
|
63
|
-
JobTemplate.expects(:authorized).with(:view_job_templates).returns(JobTemplate.where({}))
|
64
|
-
composer.available_templates
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
context 'job templates exist' do
|
69
|
-
before do
|
70
|
-
trying_job_template_1
|
71
|
-
trying_job_template_2
|
72
|
-
trying_job_template_3
|
73
|
-
unauthorized_job_template_1
|
74
|
-
unauthorized_job_template_2
|
75
|
-
end
|
76
|
-
|
77
|
-
describe '#available_templates_for(job_category)' do
|
78
|
-
it 'find the templates only for a given job name' do
|
79
|
-
results = composer.available_templates_for(trying_job_template_1.job_category)
|
80
|
-
assert_includes results, trying_job_template_1
|
81
|
-
refute_includes results, trying_job_template_2
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'it respects view permissions' do
|
85
|
-
results = composer.available_templates_for(trying_job_template_1.job_category)
|
86
|
-
refute_includes results, unauthorized_job_template_1
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
describe '#available_job_categories' do
|
91
|
-
let(:job_categories) { composer.available_job_categories }
|
92
|
-
|
93
|
-
it 'find only job names that user is granted to view' do
|
94
|
-
assert_includes job_categories, trying_job_template_1.job_category
|
95
|
-
assert_includes job_categories, trying_job_template_2.job_category
|
96
|
-
refute_includes job_categories, unauthorized_job_template_2.job_category
|
97
|
-
end
|
98
|
-
|
99
|
-
it 'every job name is listed just once' do
|
100
|
-
assert_equal job_categories.uniq, job_categories
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
describe '#available_provider_types' do
|
105
|
-
let(:provider_types) { composer.available_provider_types }
|
106
|
-
|
107
|
-
it 'finds only providers which user is granted to view' do
|
108
|
-
composer.job_invocation.job_category = 'trying_job_template_1'
|
109
|
-
assert_includes provider_types, 'SSH'
|
110
|
-
refute_includes provider_types, 'Mcollective'
|
111
|
-
refute_includes provider_types, 'Ansible'
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'every provider type is listed just once' do
|
115
|
-
assert_equal provider_types.uniq, provider_types
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
describe '#available_template_inputs' do
|
120
|
-
before do
|
121
|
-
input1
|
122
|
-
input2
|
123
|
-
unauthorized_input1
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'returns only authorized inputs based on templates' do
|
127
|
-
assert_includes composer.available_template_inputs, input1
|
128
|
-
assert_includes composer.available_template_inputs, input2
|
129
|
-
refute_includes composer.available_template_inputs, unauthorized_input1
|
130
|
-
end
|
131
|
-
|
132
|
-
context 'params contains job template ids' do
|
133
|
-
let(:ssh_params) { { :job_template_id => trying_job_template_1.id.to_s } }
|
134
|
-
let(:ansible_params) { { :job_template_id => '' } }
|
135
|
-
let(:mcollective_params) { { :job_template_id => '' } }
|
136
|
-
let(:params) { { :job_invocation => providers_params }.with_indifferent_access }
|
137
|
-
|
138
|
-
it 'finds the inputs only specified job templates' do
|
139
|
-
assert_includes composer.available_template_inputs, input1
|
140
|
-
refute_includes composer.available_template_inputs, input2
|
141
|
-
refute_includes composer.available_template_inputs, unauthorized_input1
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
describe '#needs_provider_type_selection?' do
|
147
|
-
it 'returns true if there are more than one providers respecting authorization' do
|
148
|
-
composer.stubs(:available_provider_types => [ 'SSH', 'Ansible' ])
|
149
|
-
assert composer.needs_provider_type_selection?
|
150
|
-
end
|
151
|
-
|
152
|
-
it 'returns false if there is one provider' do
|
153
|
-
composer.stubs(:available_provider_types => [ 'SSH' ])
|
154
|
-
refute composer.needs_provider_type_selection?
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
describe '#displayed_provider_types' do
|
159
|
-
# nothing to test yet
|
160
|
-
end
|
161
|
-
|
162
|
-
describe '#templates_for_provider(provider_type)' do
|
163
|
-
it 'returns all templates for a given provider respecting template permissions' do
|
164
|
-
trying_job_template_4 = FactoryBot.create(:job_template, :job_category => 'trying_job_template_1', :name => 'trying4', :provider_type => 'Ansible')
|
165
|
-
result = composer.templates_for_provider('SSH')
|
166
|
-
assert_includes result, trying_job_template_1
|
167
|
-
assert_includes result, trying_job_template_3
|
168
|
-
refute_includes result, unauthorized_job_template_1
|
169
|
-
refute_includes result, trying_job_template_4
|
170
|
-
|
171
|
-
result = composer.templates_for_provider('Ansible')
|
172
|
-
refute_includes result, trying_job_template_1
|
173
|
-
refute_includes result, trying_job_template_3
|
174
|
-
refute_includes result, unauthorized_job_template_2
|
175
|
-
assert_includes result, trying_job_template_4
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
describe '#rerun_possible?' do
|
180
|
-
it 'is true when not rerunning' do
|
181
|
-
assert_predicate composer, :rerun_possible?
|
182
|
-
end
|
183
|
-
|
184
|
-
it 'is true when rerunning with pattern tempalte invocations' do
|
185
|
-
composer.expects(:reruns).returns(1)
|
186
|
-
composer.job_invocation.expects(:pattern_template_invocations).returns([1])
|
187
|
-
assert_predicate composer, :rerun_possible?
|
188
|
-
end
|
189
|
-
|
190
|
-
it 'is false when rerunning without pattern template invocations' do
|
191
|
-
composer.expects(:reruns).returns(1)
|
192
|
-
composer.job_invocation.expects(:pattern_template_invocations).returns([])
|
193
|
-
refute_predicate composer, :rerun_possible?
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
describe '#selected_job_templates' do
|
198
|
-
it 'returns no template if none was selected through params' do
|
199
|
-
assert_empty composer.selected_job_templates
|
200
|
-
end
|
201
|
-
|
202
|
-
context 'extra unavailable templates id were selected' do
|
203
|
-
let(:unauthorized) { FactoryBot.create(:job_template, :job_category => 'trying_job_template_1', :name => 'unauth3', :provider_type => 'Ansible') }
|
204
|
-
let(:mcollective_authorized) { FactoryBot.create(:job_template, :job_category => 'trying_job_template_1', :name => 'trying4', :provider_type => 'Mcollective') }
|
205
|
-
let(:ssh_params) { { :job_template_id => trying_job_template_1.id.to_s } }
|
206
|
-
let(:ansible_params) { { :job_template_id => unauthorized.id.to_s } }
|
207
|
-
let(:mcollective_params) { { :job_template_id => mcollective_authorized.id.to_s } }
|
208
|
-
let(:params) { { :job_invocation => providers_params }.with_indifferent_access }
|
209
|
-
|
210
|
-
it 'ignores unauthorized template' do
|
211
|
-
unauthorized # make sure unautorized exists
|
212
|
-
refute_includes composer.selected_job_templates, unauthorized
|
213
|
-
end
|
214
|
-
|
215
|
-
it 'contains only authorized template specified in params' do
|
216
|
-
mcollective_authorized # make sure mcollective_authorized exists
|
217
|
-
assert_includes composer.selected_job_templates, trying_job_template_1
|
218
|
-
assert_includes composer.selected_job_templates, mcollective_authorized
|
219
|
-
refute_includes composer.selected_job_templates, trying_job_template_3
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
describe '#preselected_template_for_provider(provider_type)' do
|
225
|
-
context 'none template was selected through params' do
|
226
|
-
it 'returns nil' do
|
227
|
-
assert_nil composer.preselected_template_for_provider('SSH')
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
context 'available template was selected for a specified provider through params' do
|
232
|
-
let(:ssh_params) { { :job_template_id => trying_job_template_1.id.to_s } }
|
233
|
-
let(:params) { { :job_invocation => providers_params }.with_indifferent_access }
|
234
|
-
|
235
|
-
it 'returns the selected template because it is available for provider' do
|
236
|
-
assert_equal trying_job_template_1, composer.preselected_template_for_provider('SSH')
|
237
|
-
end
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
describe '#pattern template_invocations' do
|
242
|
-
let(:ssh_params) do
|
243
|
-
{ :job_template_id => trying_job_template_1.id.to_s,
|
244
|
-
:job_templates => {
|
245
|
-
trying_job_template_1.id.to_s => {
|
246
|
-
:input_values => { input1.id.to_s => { :value => 'value1' }, unauthorized_input1.id.to_s => { :value => 'dropped' } },
|
247
|
-
},
|
248
|
-
}}
|
249
|
-
end
|
250
|
-
let(:params) { { :job_invocation => { :providers => { :ssh => ssh_params } } }.with_indifferent_access }
|
251
|
-
let(:invocations) { composer.pattern_template_invocations }
|
252
|
-
|
253
|
-
it 'builds pattern template invocations based on passed params and it filters out wrong inputs' do
|
254
|
-
assert_equal 1, invocations.size
|
255
|
-
assert_equal 1, invocations.first.input_values.size
|
256
|
-
assert_equal 'value1', invocations.first.input_values.first.value
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
describe '#effective_user' do
|
261
|
-
let(:ssh_params) do
|
262
|
-
{ :job_template_id => trying_job_template_1.id.to_s,
|
263
|
-
:job_templates => {
|
264
|
-
trying_job_template_1.id.to_s => {
|
265
|
-
:effective_user => invocation_effective_user,
|
266
|
-
},
|
267
|
-
}}
|
268
|
-
end
|
269
|
-
let(:params) { { :job_invocation => { :providers => { :ssh => ssh_params } } }.with_indifferent_access }
|
270
|
-
let(:template_invocation) do
|
271
|
-
trying_job_template_1.effective_user.update(:overridable => overridable, :value => 'template user')
|
272
|
-
composer.pattern_template_invocations.first
|
273
|
-
end
|
274
|
-
|
275
|
-
context 'when overridable and provided' do
|
276
|
-
let(:overridable) { true }
|
277
|
-
let(:invocation_effective_user) { 'invocation user' }
|
278
|
-
|
279
|
-
it 'takes the value from the template invocation' do
|
280
|
-
assert_equal 'invocation user', template_invocation.effective_user
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
context 'when overridable and not provided' do
|
285
|
-
let(:overridable) { true }
|
286
|
-
let(:invocation_effective_user) { '' }
|
287
|
-
|
288
|
-
it 'takes the value from the job template' do
|
289
|
-
assert_equal 'template user', template_invocation.effective_user
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
context 'when not overridable and provided' do
|
294
|
-
let(:overridable) { false }
|
295
|
-
let(:invocation_effective_user) { 'invocation user' }
|
296
|
-
|
297
|
-
it 'takes the value from the job template' do
|
298
|
-
assert_equal 'template user', template_invocation.effective_user
|
299
|
-
end
|
300
|
-
end
|
301
|
-
end
|
302
|
-
|
303
|
-
describe '#displayed_search_query' do
|
304
|
-
it 'is empty by default' do
|
305
|
-
assert_empty composer.displayed_search_query
|
306
|
-
end
|
307
|
-
|
308
|
-
let(:host) { FactoryBot.create(:host) }
|
309
|
-
let(:bookmark) { Bookmark.create!(:query => 'b', :name => 'bookmark', :public => true, :controller => 'hosts') }
|
310
|
-
|
311
|
-
context 'all targetings parameters are present' do
|
312
|
-
let(:params) { { :targeting => { :search_query => 'a', :bookmark_id => bookmark.id }, :host_ids => [ host.id ] }.with_indifferent_access }
|
313
|
-
|
314
|
-
it 'explicit search query has highest priority' do
|
315
|
-
assert_equal 'a', composer.displayed_search_query
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
context 'host ids and bookmark are present' do
|
320
|
-
let(:params) { { :targeting => { :bookmark_id => bookmark.id }, :host_ids => [ host.id ] }.with_indifferent_access }
|
321
|
-
|
322
|
-
it 'hosts will be used instead of a bookmark' do
|
323
|
-
assert_includes composer.displayed_search_query, host.name
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
context 'bookmark is present' do
|
328
|
-
let(:params) { { :targeting => { :bookmark_id => bookmark.id } }.with_indifferent_access }
|
329
|
-
|
330
|
-
it 'bookmark query is used if it is available for the user' do
|
331
|
-
bookmark.update_attribute :public, false
|
332
|
-
assert_equal bookmark.query, composer.displayed_search_query
|
333
|
-
end
|
334
|
-
|
335
|
-
it 'bookmark query is used if the bookmark is public' do
|
336
|
-
bookmark.owner = nil
|
337
|
-
bookmark.save(:validate => false) # skip validations so owner remains nil
|
338
|
-
assert_equal bookmark.query, composer.displayed_search_query
|
339
|
-
end
|
340
|
-
|
341
|
-
it 'empty search is returned if bookmark is not owned by the user and is not public' do
|
342
|
-
bookmark.public = false
|
343
|
-
bookmark.owner = nil
|
344
|
-
bookmark.save(:validate => false) # skip validations so owner remains nil
|
345
|
-
assert_empty composer.displayed_search_query
|
346
|
-
end
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
describe '#available_bookmarks' do
|
351
|
-
context 'there are hostgroups and hosts bookmark' do
|
352
|
-
let(:hostgroups) { Bookmark.create(:name => 'hostgroups', :query => 'name = x', :controller => 'hostgroups') }
|
353
|
-
let(:hosts) { Bookmark.create(:name => 'hosts', :query => 'name = x', :controller => 'hosts') }
|
354
|
-
let(:dashboard) { Bookmark.create(:name => 'dashboard', :query => 'name = x', :controller => 'dashboard') }
|
355
|
-
|
356
|
-
it 'finds only host related bookmarks' do
|
357
|
-
hosts
|
358
|
-
dashboard
|
359
|
-
hostgroups
|
360
|
-
assert_includes composer.available_bookmarks, hosts
|
361
|
-
assert_includes composer.available_bookmarks, dashboard
|
362
|
-
refute_includes composer.available_bookmarks, hostgroups
|
363
|
-
end
|
364
|
-
end
|
365
|
-
end
|
366
|
-
|
367
|
-
describe '#targeted_hosts_count' do
|
368
|
-
let(:host) { FactoryBot.create(:host) }
|
369
|
-
|
370
|
-
it 'obeys authorization' do
|
371
|
-
fake_scope = mock
|
372
|
-
composer.stubs(:displayed_search_query => "name = #{host.name}")
|
373
|
-
Host.expects(:execution_scope).returns(fake_scope)
|
374
|
-
fake_scope.expects(:authorized).with(:view_hosts, Host).returns(Host.where({}))
|
375
|
-
composer.targeted_hosts_count
|
376
|
-
end
|
377
|
-
|
378
|
-
it 'searches hosts based on displayed_search_query' do
|
379
|
-
composer.stubs(:displayed_search_query => "name = #{host.name}")
|
380
|
-
assert_equal 1, composer.targeted_hosts_count
|
381
|
-
end
|
382
|
-
|
383
|
-
it 'returns 0 for queries with syntax errors' do
|
384
|
-
composer.stubs(:displayed_search_query => 'name = ')
|
385
|
-
assert_equal 0, composer.targeted_hosts_count
|
386
|
-
end
|
387
|
-
|
388
|
-
it 'returns 0 when no query is present' do
|
389
|
-
composer.stubs(:displayed_search_query => '')
|
390
|
-
assert_equal 0, composer.targeted_hosts_count
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
describe '#input_value_for(input)' do
|
395
|
-
let(:value1) { composer.input_value_for(input1) }
|
396
|
-
it 'returns new empty input value if there is no invocation' do
|
397
|
-
assert value1.new_record?
|
398
|
-
assert_empty value1.value
|
399
|
-
end
|
400
|
-
|
401
|
-
context 'there are invocations without input values for a given input' do
|
402
|
-
let(:ssh_params) do
|
403
|
-
{ :job_template_id => trying_job_template_1.id.to_s,
|
404
|
-
:job_templates => {
|
405
|
-
trying_job_template_1.id.to_s => {
|
406
|
-
:input_values => { },
|
407
|
-
},
|
408
|
-
} }
|
409
|
-
end
|
410
|
-
let(:params) { { :job_invocation => { :providers => { :ssh => ssh_params } } }.with_indifferent_access }
|
411
|
-
|
412
|
-
it 'returns new empty input value' do
|
413
|
-
assert value1.new_record?
|
414
|
-
assert_empty value1.value
|
415
|
-
end
|
416
|
-
end
|
417
|
-
|
418
|
-
context 'there are invocations with input values for a given input' do
|
419
|
-
let(:ssh_params) do
|
420
|
-
{ :job_template_id => trying_job_template_1.id.to_s,
|
421
|
-
:job_templates => {
|
422
|
-
trying_job_template_1.id.to_s => {
|
423
|
-
:input_values => { input1.id.to_s => { :value => 'value1' } },
|
424
|
-
},
|
425
|
-
} }
|
426
|
-
end
|
427
|
-
let(:params) { { :job_invocation => { :providers => { :ssh => ssh_params } } }.with_indifferent_access }
|
428
|
-
|
429
|
-
it 'finds the value among template invocations' do
|
430
|
-
assert_equal 'value1', value1.value
|
431
|
-
end
|
432
|
-
end
|
433
|
-
end
|
434
|
-
|
435
|
-
describe '#valid?' do
|
436
|
-
let(:host) { FactoryBot.create(:host) }
|
437
|
-
let(:ssh_params) do
|
438
|
-
{ :job_template_id => trying_job_template_1.id.to_s,
|
439
|
-
:job_templates => {
|
440
|
-
trying_job_template_1.id.to_s => {
|
441
|
-
:input_values => { input1.id.to_s => { :value => 'value1' } },
|
442
|
-
},
|
443
|
-
} }
|
444
|
-
end
|
445
|
-
|
446
|
-
let(:params) do
|
447
|
-
{ :job_invocation => { :providers => { :ssh => ssh_params } }, :targeting => { :search_query => "name = #{host.name}" } }.with_indifferent_access
|
448
|
-
end
|
449
|
-
|
450
|
-
it 'validates all associated objects even if some of the is invalid' do
|
451
|
-
composer
|
452
|
-
composer.job_invocation.expects(:valid?).returns(false)
|
453
|
-
composer.targeting.expects(:valid?).returns(false)
|
454
|
-
composer.pattern_template_invocations.each { |invocation| invocation.expects(:valid?).returns(false) }
|
455
|
-
assert_not composer.valid?
|
456
|
-
end
|
457
|
-
end
|
458
|
-
|
459
|
-
describe 'concurrency control' do
|
460
|
-
|
461
|
-
describe 'with concurrency control set' do
|
462
|
-
let(:params) do
|
463
|
-
{ :job_invocation => { :providers => { :ssh => ssh_params }, :concurrency_level => '5' } }.with_indifferent_access
|
464
|
-
end
|
465
|
-
|
466
|
-
it 'accepts the concurrency options' do
|
467
|
-
assert_equal 5, composer.job_invocation.concurrency_level
|
468
|
-
end
|
469
|
-
end
|
470
|
-
|
471
|
-
it 'can be disabled' do
|
472
|
-
assert_nil composer.job_invocation.concurrency_level
|
473
|
-
end
|
474
|
-
end
|
475
|
-
|
476
|
-
describe 'triggering' do
|
477
|
-
let(:params) do
|
478
|
-
{ :job_invocation => { :providers => { :ssh => ssh_params } }, :triggering => { :mode => 'future', :end_time=> {"end_time(3i)": 1, "end_time(2i)": 2, "end_time(1i)": 3, "end_time(4i)": 4, "end_time(5i)": 5} }}.with_indifferent_access
|
479
|
-
end
|
480
|
-
|
481
|
-
it 'accepts the triggering params' do
|
482
|
-
assert_equal :future, composer.job_invocation.triggering.mode
|
483
|
-
end
|
484
|
-
|
485
|
-
it 'formats the triggering end time when its unordered' do
|
486
|
-
assert_equal Time.local(3,2,1,4,5), composer.job_invocation.triggering.end_time
|
487
|
-
end
|
488
|
-
end
|
489
|
-
|
490
|
-
describe '#save' do
|
491
|
-
it 'triggers save on job_invocation if it is valid' do
|
492
|
-
composer.stubs(:valid? => true)
|
493
|
-
composer.job_invocation.expects(:save)
|
494
|
-
composer.save
|
495
|
-
end
|
496
|
-
|
497
|
-
it 'does not trigger save on job_invocation if it is invalid' do
|
498
|
-
composer.stubs(:valid? => false)
|
499
|
-
composer.job_invocation.expects(:save).never
|
500
|
-
composer.save
|
501
|
-
end
|
502
|
-
end
|
503
|
-
|
504
|
-
describe '#job_category' do
|
505
|
-
it 'triggers job_category on job_invocation' do
|
506
|
-
composer
|
507
|
-
composer.job_invocation.expects(:job_category)
|
508
|
-
composer.job_category
|
509
|
-
end
|
510
|
-
end
|
511
|
-
|
512
|
-
describe '#password' do
|
513
|
-
let(:password) { 'changeme' }
|
514
|
-
let(:params) do
|
515
|
-
{ :job_invocation => { :password => password }}.with_indifferent_access
|
516
|
-
end
|
517
|
-
|
518
|
-
it 'sets the password properly' do
|
519
|
-
composer
|
520
|
-
assert_equal password, composer.job_invocation.password
|
521
|
-
end
|
522
|
-
end
|
523
|
-
|
524
|
-
describe '#key_passphrase' do
|
525
|
-
let(:key_passphrase) { 'changeme' }
|
526
|
-
let(:params) do
|
527
|
-
{ :job_invocation => { :key_passphrase => key_passphrase }}
|
528
|
-
end
|
529
|
-
|
530
|
-
it 'sets the key passphrase properly' do
|
531
|
-
composer
|
532
|
-
assert_equal key_passphrase, composer.job_invocation.key_passphrase
|
533
|
-
end
|
534
|
-
end
|
535
|
-
|
536
|
-
describe '#effective_user_password' do
|
537
|
-
let(:effective_user_password) { 'password' }
|
538
|
-
let(:params) do
|
539
|
-
{ :job_invocation => { :effective_user_password => effective_user_password }}
|
540
|
-
end
|
541
|
-
|
542
|
-
it 'sets the effective_user_password password properly' do
|
543
|
-
composer
|
544
|
-
assert_equal effective_user_password, composer.job_invocation.effective_user_password
|
545
|
-
end
|
546
|
-
end
|
547
|
-
|
548
|
-
describe '#targeting' do
|
549
|
-
it 'triggers targeting on job_invocation' do
|
550
|
-
composer
|
551
|
-
composer.job_invocation.expects(:targeting)
|
552
|
-
composer.targeting
|
553
|
-
end
|
554
|
-
end
|
555
|
-
|
556
|
-
describe '#compose_from_invocation(existing_invocation)' do
|
557
|
-
let(:host) { FactoryBot.create(:host) }
|
558
|
-
let(:ssh_params) do
|
559
|
-
{ :job_template_id => trying_job_template_1.id.to_s,
|
560
|
-
:job_templates => {
|
561
|
-
trying_job_template_1.id.to_s => {
|
562
|
-
:input_values => { input1.id.to_s => { :value => 'value1' } },
|
563
|
-
},
|
564
|
-
} }
|
565
|
-
end
|
566
|
-
let(:params) do
|
567
|
-
{
|
568
|
-
:job_invocation => {
|
569
|
-
:providers => { :ssh => ssh_params },
|
570
|
-
:concurrency_level => 5,
|
571
|
-
},
|
572
|
-
:targeting => {
|
573
|
-
:search_query => "name = #{host.name}",
|
574
|
-
:targeting_type => Targeting::STATIC_TYPE,
|
575
|
-
},
|
576
|
-
}.with_indifferent_access
|
577
|
-
end
|
578
|
-
let(:existing) { composer.job_invocation }
|
579
|
-
let(:new_composer) { JobInvocationComposer.from_job_invocation(composer.job_invocation) }
|
580
|
-
|
581
|
-
before do
|
582
|
-
composer.save
|
583
|
-
end
|
584
|
-
|
585
|
-
it 'sets the same job name' do
|
586
|
-
assert_equal existing.job_category, new_composer.job_category
|
587
|
-
end
|
588
|
-
|
589
|
-
it 'accepts additional host ids' do
|
590
|
-
new_composer = JobInvocationComposer.from_job_invocation(composer.job_invocation, { :host_ids => [host.id] })
|
591
|
-
assert_equal "name ^ (#{host.name})", new_composer.search_query
|
592
|
-
end
|
593
|
-
|
594
|
-
it 'builds new targeting object which keeps search query' do
|
595
|
-
refute_equal existing.targeting, new_composer.targeting
|
596
|
-
assert_equal existing.targeting.search_query, new_composer.search_query
|
597
|
-
end
|
598
|
-
|
599
|
-
it 'keeps job template ids' do
|
600
|
-
assert_equal existing.pattern_template_invocations.map(&:template_id), new_composer.job_template_ids
|
601
|
-
end
|
602
|
-
|
603
|
-
it 'keeps template invocations and their values' do
|
604
|
-
assert_equal existing.pattern_template_invocations.size, new_composer.pattern_template_invocations.size
|
605
|
-
end
|
606
|
-
|
607
|
-
it 'sets the same concurrency control options' do
|
608
|
-
assert_equal existing.concurrency_level, new_composer.job_invocation.concurrency_level
|
609
|
-
end
|
610
|
-
|
611
|
-
end
|
612
|
-
end
|
613
|
-
end
|
614
|
-
|
615
|
-
describe '.from_api_params' do
|
616
|
-
let(:composer) do
|
617
|
-
JobInvocationComposer.from_api_params(params)
|
618
|
-
end
|
619
|
-
let(:bookmark) { bookmarks(:one) }
|
620
|
-
|
621
|
-
context 'with targeting from bookmark' do
|
622
|
-
|
623
|
-
before do
|
624
|
-
[trying_job_template_1, trying_job_template_3] # mentioning templates we want to have initialized in the test
|
625
|
-
end
|
626
|
-
|
627
|
-
let(:params) do
|
628
|
-
{ :job_category => trying_job_template_1.job_category,
|
629
|
-
:job_template_id => trying_job_template_1.id,
|
630
|
-
:targeting_type => 'static_query',
|
631
|
-
:bookmark_id => bookmark.id }
|
632
|
-
end
|
633
|
-
|
634
|
-
it 'creates invocation with a bookmark' do
|
635
|
-
assert composer.save!
|
636
|
-
assert_equal bookmark, composer.job_invocation.targeting.bookmark
|
637
|
-
assert_equal composer.job_invocation.targeting.user, User.current
|
638
|
-
assert_not_empty composer.job_invocation.pattern_template_invocations
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
context 'with targeting from search query' do
|
643
|
-
let(:params) do
|
644
|
-
{ :job_category => trying_job_template_1.job_category,
|
645
|
-
:job_template_id => trying_job_template_1.id,
|
646
|
-
:targeting_type => 'static_query',
|
647
|
-
:search_query => 'some hosts' }
|
648
|
-
end
|
649
|
-
|
650
|
-
it 'creates invocation with a search query' do
|
651
|
-
assert composer.save!
|
652
|
-
assert_equal 'some hosts', composer.job_invocation.targeting.search_query
|
653
|
-
assert_not_empty composer.job_invocation.pattern_template_invocations
|
654
|
-
end
|
655
|
-
end
|
656
|
-
|
657
|
-
context 'with with inputs' do
|
658
|
-
let(:params) do
|
659
|
-
{ :job_category => trying_job_template_5.job_category,
|
660
|
-
:job_template_id => trying_job_template_5.id,
|
661
|
-
:targeting_type => 'static_query',
|
662
|
-
:search_query => 'some hosts',
|
663
|
-
:inputs => {input5.name => 'some_value'}}
|
664
|
-
end
|
665
|
-
|
666
|
-
it 'finds the inputs by name' do
|
667
|
-
assert composer.save!
|
668
|
-
values = composer.pattern_template_invocations.first.input_values
|
669
|
-
assert_equal 1, values.count
|
670
|
-
assert_equal 'some_value', values.first.value
|
671
|
-
end
|
672
|
-
|
673
|
-
it 'can be forced to be empty' do
|
674
|
-
params[:inputs] = {input5.name => ''}
|
675
|
-
assert composer.save!
|
676
|
-
values = composer.pattern_template_invocations.first.input_values
|
677
|
-
assert_equal 1, values.count
|
678
|
-
assert_equal '', values.first.value
|
679
|
-
end
|
680
|
-
end
|
681
|
-
|
682
|
-
context 'with inputs and default values' do
|
683
|
-
let(:params) do
|
684
|
-
{ :job_category => trying_job_template_5.job_category,
|
685
|
-
:job_template_id => trying_job_template_5.id,
|
686
|
-
:targeting_type => 'static_query',
|
687
|
-
:search_query => 'some hosts',
|
688
|
-
:inputs => {}}
|
689
|
-
end
|
690
|
-
|
691
|
-
it 'uses the default input values' do
|
692
|
-
input5 # Force the factory to be materialized
|
693
|
-
assert composer.save!
|
694
|
-
assert_equal 1, composer.pattern_template_invocations.first.input_values.collect.count
|
695
|
-
end
|
696
|
-
end
|
697
|
-
|
698
|
-
context 'with provider inputs' do
|
699
|
-
let(:params) do
|
700
|
-
{ :job_category => provider_inputs_job_template.job_category,
|
701
|
-
:job_template_id => provider_inputs_job_template.id,
|
702
|
-
:targeting_type => 'static_query',
|
703
|
-
:search_query => 'some hosts',
|
704
|
-
:inputs => { input4.name => 'some_value' },
|
705
|
-
:ansible => { 'tags' => 'bar', 'tags_flag' => '--skip-tags' } }
|
706
|
-
end
|
707
|
-
|
708
|
-
it 'detects provider inputs' do
|
709
|
-
assert composer.save!
|
710
|
-
scope = composer.job_invocation.pattern_template_invocations.first.provider_input_values
|
711
|
-
tags = scope.find_by :name => 'tags'
|
712
|
-
flags = scope.find_by :name => 'tags_flag'
|
713
|
-
assert_equal 'bar', tags.value
|
714
|
-
assert_equal '--skip-tags', flags.value
|
715
|
-
end
|
716
|
-
end
|
717
|
-
|
718
|
-
context 'with effective user' do
|
719
|
-
let(:params) do
|
720
|
-
{ :job_category => trying_job_template_1.job_category,
|
721
|
-
:job_template_id => trying_job_template_1.id,
|
722
|
-
:effective_user => 'invocation user',
|
723
|
-
:targeting_type => 'static_query',
|
724
|
-
:search_query => 'some hosts',
|
725
|
-
:inputs => {input1.name => 'some_value'}}
|
726
|
-
end
|
727
|
-
|
728
|
-
let(:template_invocation) { composer.job_invocation.pattern_template_invocations.first }
|
729
|
-
|
730
|
-
it 'sets the effective user based on the input' do
|
731
|
-
assert composer.save!
|
732
|
-
assert_equal 'invocation user', template_invocation.effective_user
|
733
|
-
end
|
734
|
-
end
|
735
|
-
|
736
|
-
context 'with concurrency_control' do
|
737
|
-
let(:level) { 5 }
|
738
|
-
let(:params) do
|
739
|
-
{ :job_category => trying_job_template_1.job_category,
|
740
|
-
:job_template_id => trying_job_template_1.id,
|
741
|
-
:concurrency_control => {
|
742
|
-
:concurrency_level => level,
|
743
|
-
},
|
744
|
-
:targeting_type => 'static_query',
|
745
|
-
:search_query => 'some hosts',
|
746
|
-
:inputs => { input1.name => 'some_value' } }
|
747
|
-
end
|
748
|
-
|
749
|
-
it 'sets the concurrency level based on the input' do
|
750
|
-
assert composer.save!
|
751
|
-
assert_equal level, composer.job_invocation.concurrency_level
|
752
|
-
end
|
753
|
-
end
|
754
|
-
|
755
|
-
context 'with rex feature defined' do
|
756
|
-
let(:feature) { FactoryBot.create(:remote_execution_feature) }
|
757
|
-
let(:params) do
|
758
|
-
{ :job_category => trying_job_template_1.job_category,
|
759
|
-
:job_template_id => trying_job_template_1.id,
|
760
|
-
:remote_execution_feature_id => feature.id,
|
761
|
-
:targeting_type => 'static_query',
|
762
|
-
:search_query => 'some hosts',
|
763
|
-
:inputs => { input1.name => 'some_value' } }
|
764
|
-
end
|
765
|
-
|
766
|
-
it 'sets the remote execution feature based on the input' do
|
767
|
-
assert composer.save!
|
768
|
-
assert_equal feature, composer.job_invocation.remote_execution_feature
|
769
|
-
end
|
770
|
-
|
771
|
-
it 'sets the remote execution_feature id based on `feature` param' do
|
772
|
-
params[:remote_execution_feature_id] = nil
|
773
|
-
params[:feature] = feature.label
|
774
|
-
params[:job_template_id] = trying_job_template_1.id
|
775
|
-
refute_equal feature.job_template, trying_job_template_1
|
776
|
-
|
777
|
-
assert composer.save!
|
778
|
-
assert_equal feature, composer.job_invocation.remote_execution_feature
|
779
|
-
end
|
780
|
-
end
|
781
|
-
|
782
|
-
context 'with invalid targeting' do
|
783
|
-
let(:params) do
|
784
|
-
{ :job_category => trying_job_template_1.job_category,
|
785
|
-
:job_template_id => trying_job_template_1.id,
|
786
|
-
:targeting_type => 'fake',
|
787
|
-
:search_query => 'some hosts',
|
788
|
-
:inputs => {input1.name => 'some_value'}}
|
789
|
-
end
|
790
|
-
|
791
|
-
it 'handles errors' do
|
792
|
-
assert_raises(ActiveRecord::RecordNotSaved) do
|
793
|
-
composer.save!
|
794
|
-
end
|
795
|
-
end
|
796
|
-
end
|
797
|
-
|
798
|
-
context 'with invalid bookmark and search query' do
|
799
|
-
let(:params) do
|
800
|
-
{ :job_category => trying_job_template_1.job_category,
|
801
|
-
:job_template_id => trying_job_template_1.id,
|
802
|
-
:targeting_type => 'static_query',
|
803
|
-
:search_query => 'some hosts',
|
804
|
-
:bookmark_id => bookmark.id,
|
805
|
-
:inputs => {input1.name => 'some_value'}}
|
806
|
-
end
|
807
|
-
|
808
|
-
it 'handles errors' do
|
809
|
-
assert_raises(Foreman::Exception) do
|
810
|
-
JobInvocationComposer.from_api_params(params)
|
811
|
-
end
|
812
|
-
end
|
813
|
-
end
|
814
|
-
|
815
|
-
context 'with invalid inputs' do
|
816
|
-
let(:params) do
|
817
|
-
{ :job_category => trying_job_template_1.job_category,
|
818
|
-
:job_template_id => trying_job_template_1.id,
|
819
|
-
:targeting_type => 'static_query',
|
820
|
-
:search_query => 'some hosts',
|
821
|
-
:inputs => {input3.name => nil}}
|
822
|
-
end
|
823
|
-
|
824
|
-
it 'handles errors' do
|
825
|
-
error = assert_raises(ActiveRecord::RecordNotSaved) do
|
826
|
-
composer.save!
|
827
|
-
end
|
828
|
-
assert_includes error.message, "Template #{trying_job_template_1.name}: Input #{input3.name.downcase}: Value can't be blank"
|
829
|
-
end
|
830
|
-
end
|
831
|
-
|
832
|
-
context 'with empty values for non-required inputs' do
|
833
|
-
let(:params) do
|
834
|
-
{ :job_category => trying_job_template_1.job_category,
|
835
|
-
:job_template_id => trying_job_template_1.id,
|
836
|
-
:targeting_type => 'static_query',
|
837
|
-
:search_query => 'some hosts',
|
838
|
-
:inputs => {input3.name => 'some value'}}
|
839
|
-
end
|
840
|
-
|
841
|
-
it 'accepts the params' do
|
842
|
-
composer.save!
|
843
|
-
assert_not composer.job_invocation.new_record?
|
844
|
-
end
|
845
|
-
end
|
846
|
-
|
847
|
-
context 'with missing required inputs' do
|
848
|
-
let(:params) do
|
849
|
-
{ :job_category => trying_job_template_1.job_category,
|
850
|
-
:job_template_id => trying_job_template_1.id,
|
851
|
-
:targeting_type => 'static_query',
|
852
|
-
:search_query => 'some hosts',
|
853
|
-
:inputs => {input1.name => 'some_value'}}
|
854
|
-
end
|
855
|
-
|
856
|
-
it 'handles errors' do
|
857
|
-
assert_predicate input3, :required
|
858
|
-
|
859
|
-
error = assert_raises(ActiveRecord::RecordNotSaved) do
|
860
|
-
composer.save!
|
861
|
-
end
|
862
|
-
|
863
|
-
assert_includes error.message, "Template #{trying_job_template_1.name}: Not all required inputs have values. Missing inputs: #{input3.name}"
|
864
|
-
end
|
865
|
-
end
|
866
|
-
end
|
867
|
-
|
868
|
-
describe '#from_job_invocation' do
|
869
|
-
let(:job_invocation) do
|
870
|
-
as_admin { FactoryBot.create(:job_invocation, :with_template, :with_task) }
|
871
|
-
end
|
872
|
-
|
873
|
-
before do
|
874
|
-
job_invocation.targeting.host_ids = job_invocation.template_invocations_host_ids
|
875
|
-
end
|
876
|
-
|
877
|
-
it 'marks targeting as resolved if static' do
|
878
|
-
created = JobInvocationComposer.from_job_invocation(job_invocation).job_invocation
|
879
|
-
assert created.targeting.resolved?
|
880
|
-
created.targeting.save
|
881
|
-
created.targeting.reload
|
882
|
-
assert_equal job_invocation.template_invocations_host_ids, created.targeting.targeting_hosts.pluck(:host_id)
|
883
|
-
end
|
884
|
-
|
885
|
-
it 'takes randomized_ordering from the original job invocation when rerunning failed' do
|
886
|
-
job_invocation.targeting.randomized_ordering = true
|
887
|
-
job_invocation.targeting.save!
|
888
|
-
host_ids = job_invocation.targeting.hosts.pluck(:id)
|
889
|
-
composer = JobInvocationComposer.from_job_invocation(job_invocation, :host_ids => host_ids)
|
890
|
-
assert composer.job_invocation.targeting.randomized_ordering
|
891
|
-
end
|
892
|
-
|
893
|
-
it 'works with invalid hosts' do
|
894
|
-
host = job_invocation.targeting.hosts.first
|
895
|
-
::Host::Managed.any_instance.stubs(:valid?).returns(false)
|
896
|
-
composer = JobInvocationComposer.from_job_invocation(job_invocation, {})
|
897
|
-
targeting = composer.compose.job_invocation.targeting
|
898
|
-
targeting.save!
|
899
|
-
targeting.reload
|
900
|
-
assert targeting.valid?
|
901
|
-
assert_equal targeting.hosts.pluck(:id), [host.id]
|
902
|
-
end
|
903
|
-
end
|
904
|
-
|
905
|
-
describe '.for_feature' do
|
906
|
-
let(:feature) { FactoryBot.create(:remote_execution_feature, job_template: trying_job_template_1) }
|
907
|
-
let(:host) { FactoryBot.create(:host) }
|
908
|
-
let(:bookmark) { Bookmark.create!(:query => 'b', :name => 'bookmark', :public => true, :controller => 'hosts') }
|
909
|
-
|
910
|
-
context 'specifying hosts' do
|
911
|
-
it 'takes a bookmarked search' do
|
912
|
-
composer = JobInvocationComposer.for_feature(feature.label, bookmark, {})
|
913
|
-
assert_equal bookmark.id, composer.params['targeting']['bookmark_id']
|
914
|
-
end
|
915
|
-
|
916
|
-
it 'takes an array of host ids' do
|
917
|
-
composer = JobInvocationComposer.for_feature(feature.label, [host.id], {})
|
918
|
-
assert_match(/#{host.name}/, composer.params['targeting']['search_query'])
|
919
|
-
end
|
920
|
-
|
921
|
-
it 'takes a single host object' do
|
922
|
-
composer = JobInvocationComposer.for_feature(feature.label, host, {})
|
923
|
-
assert_match(/#{host.name}/, composer.params['targeting']['search_query'])
|
924
|
-
end
|
925
|
-
|
926
|
-
it 'takes an array of host FQDNs' do
|
927
|
-
composer = JobInvocationComposer.for_feature(feature.label, [host.fqdn], {})
|
928
|
-
assert_match(/#{host.name}/, composer.params['targeting']['search_query'])
|
929
|
-
end
|
930
|
-
|
931
|
-
it 'takes a search query string' do
|
932
|
-
composer = JobInvocationComposer.for_feature(feature.label, 'host.example.com', {})
|
933
|
-
assert_equal 'host.example.com', composer.search_query
|
934
|
-
end
|
935
|
-
end
|
936
|
-
end
|
937
|
-
|
938
|
-
describe '#resolve_job_category and #resolve job_templates' do
|
939
|
-
let(:setting_template) { as_admin { FactoryBot.create(:job_template, :name => 'trying setting', :job_category => 'fluff') } }
|
940
|
-
let(:other_template) { as_admin { FactoryBot.create(:job_template, :name => 'trying something', :job_category => 'fluff') } }
|
941
|
-
let(:second_template) { as_admin { FactoryBot.create(:job_template, :name => 'second template', :job_category => 'fluff') } }
|
942
|
-
let(:params) { { :host_ids => nil, :targeting => { :targeting_type => "static_query", :bookmark_id => nil }, :job_template_id => setting_template.id } }
|
943
|
-
let(:composer) { JobInvocationComposer.from_api_params(params) }
|
944
|
-
|
945
|
-
context 'with template in setting present' do
|
946
|
-
before do
|
947
|
-
Setting[:remote_execution_form_job_template] = setting_template.name
|
948
|
-
end
|
949
|
-
|
950
|
-
it 'should resolve category to the setting value' do
|
951
|
-
assert_equal setting_template.job_category, composer.resolve_job_category('foo')
|
952
|
-
end
|
953
|
-
|
954
|
-
it 'should resolve template to the setting value' do
|
955
|
-
assert_equal setting_template, composer.resolve_job_template([other_template, setting_template])
|
956
|
-
end
|
957
|
-
|
958
|
-
it 'should respect provider templates when resolving templates' do
|
959
|
-
assert_equal other_template, composer.resolve_job_template([other_template])
|
960
|
-
end
|
961
|
-
end
|
962
|
-
|
963
|
-
context 'with template in setting absent' do
|
964
|
-
it 'should resolve category to the default value' do
|
965
|
-
category = 'foo'
|
966
|
-
assert_equal category, composer.resolve_job_category(category)
|
967
|
-
end
|
968
|
-
|
969
|
-
it 'should resolve template to the first in category' do
|
970
|
-
assert_equal other_template, composer.resolve_job_template([other_template, second_template])
|
971
|
-
end
|
972
|
-
end
|
973
|
-
end
|
974
|
-
end
|