foreman_remote_execution 14.0.2 → 14.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/job_invocations_controller.rb +34 -17
  3. data/app/helpers/remote_execution_helper.rb +2 -2
  4. data/app/lib/actions/remote_execution/proxy_action.rb +10 -5
  5. data/app/lib/actions/remote_execution/run_host_job.rb +1 -1
  6. data/app/lib/actions/remote_execution/template_invocation_progress_logging.rb +2 -3
  7. data/app/views/api/v2/job_invocations/hosts.json.rabl +15 -0
  8. data/config/routes.rb +1 -0
  9. data/db/migrate/20240312133027_extend_template_invocation_events.rb +19 -0
  10. data/lib/foreman_remote_execution/version.rb +1 -1
  11. data/webpack/JobInvocationDetail/JobInvocationActions.js +1 -1
  12. data/webpack/JobInvocationDetail/JobInvocationConstants.js +84 -0
  13. data/webpack/JobInvocationDetail/JobInvocationDetail.scss +0 -1
  14. data/webpack/JobInvocationDetail/JobInvocationHostTable.js +210 -0
  15. data/webpack/JobInvocationDetail/JobInvocationSelectors.js +2 -2
  16. data/webpack/JobInvocationDetail/__tests__/MainInformation.test.js +5 -1
  17. data/webpack/JobInvocationDetail/__tests__/fixtures.js +9 -0
  18. data/webpack/JobInvocationDetail/index.js +56 -34
  19. data/webpack/__mocks__/foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState.js +1 -2
  20. data/webpack/react_app/components/RecentJobsCard/JobStatusIcon.js +38 -7
  21. data/webpack/react_app/components/RecentJobsCard/constants.js +4 -0
  22. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/HostStatus.test.js.snap +1 -1
  23. data/webpack/react_app/components/TargetingHosts/components/HostStatus.js +6 -6
  24. metadata +6 -94
  25. data/.babelrc.js +0 -3
  26. data/.eslintignore +0 -3
  27. data/.eslintrc +0 -13
  28. data/.github/workflows/js_ci.yml +0 -32
  29. data/.github/workflows/release.yml +0 -16
  30. data/.github/workflows/ruby_ci.yml +0 -19
  31. data/.gitignore +0 -19
  32. data/.packit.yaml +0 -45
  33. data/.prettierrc +0 -4
  34. data/.rubocop.yml +0 -105
  35. data/.rubocop_todo.yml +0 -516
  36. data/.tx/config +0 -10
  37. data/Gemfile +0 -5
  38. data/app/mailers/.gitkeep +0 -0
  39. data/app/views/dashboard/.gitkeep +0 -0
  40. data/foreman_remote_execution.gemspec +0 -33
  41. data/jsconfig.json +0 -8
  42. data/test/benchmark/run_hosts_job_benchmark.rb +0 -70
  43. data/test/benchmark/targeting_benchmark.rb +0 -31
  44. data/test/factories/foreman_remote_execution_factories.rb +0 -147
  45. data/test/functional/api/v2/foreign_input_sets_controller_test.rb +0 -58
  46. data/test/functional/api/v2/job_invocations_controller_test.rb +0 -446
  47. data/test/functional/api/v2/job_templates_controller_test.rb +0 -110
  48. data/test/functional/api/v2/registration_controller_test.rb +0 -73
  49. data/test/functional/api/v2/remote_execution_features_controller_test.rb +0 -34
  50. data/test/functional/api/v2/template_invocations_controller_test.rb +0 -33
  51. data/test/functional/cockpit_controller_test.rb +0 -16
  52. data/test/functional/job_invocations_controller_test.rb +0 -132
  53. data/test/functional/job_templates_controller_test.rb +0 -31
  54. data/test/functional/ui_job_wizard_controller_test.rb +0 -16
  55. data/test/graphql/mutations/job_invocations/create_test.rb +0 -58
  56. data/test/graphql/queries/job_invocation_query_test.rb +0 -31
  57. data/test/graphql/queries/job_invocations_query_test.rb +0 -35
  58. data/test/helpers/remote_execution_helper_test.rb +0 -46
  59. data/test/support/remote_execution_helper.rb +0 -5
  60. data/test/test_plugin_helper.rb +0 -9
  61. data/test/unit/actions/run_host_job_test.rb +0 -115
  62. data/test/unit/actions/run_hosts_job_test.rb +0 -214
  63. data/test/unit/api_params_test.rb +0 -25
  64. data/test/unit/concerns/foreman_tasks_cleaner_extensions_test.rb +0 -29
  65. data/test/unit/concerns/host_extensions_test.rb +0 -219
  66. data/test/unit/concerns/nic_extensions_test.rb +0 -9
  67. data/test/unit/execution_task_status_mapper_test.rb +0 -92
  68. data/test/unit/input_template_renderer_test.rb +0 -503
  69. data/test/unit/job_invocation_composer_test.rb +0 -974
  70. data/test/unit/job_invocation_report_template_test.rb +0 -60
  71. data/test/unit/job_invocation_test.rb +0 -232
  72. data/test/unit/job_template_effective_user_test.rb +0 -37
  73. data/test/unit/job_template_test.rb +0 -316
  74. data/test/unit/remote_execution_feature_test.rb +0 -86
  75. data/test/unit/remote_execution_provider_test.rb +0 -298
  76. data/test/unit/renderer_scope_input_test.rb +0 -49
  77. data/test/unit/targeting_test.rb +0 -206
  78. data/test/unit/template_invocation_input_value_test.rb +0 -38
@@ -1,60 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class JobReportTemplateTest < ActiveSupport::TestCase
4
- class FakeTask < OpenStruct
5
- class Jail < Safemode::Jail
6
- allow :action_continuous_output, :result, :ended_at
7
- end
8
- end
9
-
10
- context 'with valid job invocation report template' do
11
- let(:job_invocation_template) do
12
- file_path = File.read(File.expand_path(Rails.root + "app/views/unattended/report_templates/job_-_invocation_report.erb"))
13
- template = ReportTemplate.import_without_save("Job Invocation Report Template", file_path)
14
- template.save!
15
- template
16
- end
17
-
18
- describe 'template setting' do
19
- it 'in settings includes only report templates with job_id input' do
20
- FactoryBot.create(:report_template, name: 'Template 1')
21
- job_invocation_template
22
- templates = ForemanRemoteExecution.job_invocation_report_templates_select
23
-
24
- assert_include templates, 'Job Invocation Report Template'
25
- end
26
- end
27
-
28
- describe 'task reporting' do
29
- let(:fake_outputs) do
30
- [
31
- { 'output_type' => 'stderr', 'output' => "error" },
32
- { 'output_type' => 'stdout', 'output' => "output" },
33
- { 'output_type' => 'debug', 'output' => "debug" },
34
- ]
35
- end
36
- let(:fake_task) { FakeTask.new(result: 'success', action_continuous_output: fake_outputs, :ended_at => Time.new(2020, 12, 1, 0, 0, 0).utc) }
37
- let(:job_invocation) { FactoryBot.create(:job_invocation, :with_task) }
38
- let(:host) { job_invocation.template_invocations.first.host }
39
-
40
- it 'should render task outputs' do
41
- JobInvocation.any_instance.expects(:sub_task_for_host).returns(fake_task)
42
-
43
- input = job_invocation_template.template_inputs.first
44
- composer_params = { template_id: job_invocation_template.id, input_values: { input.id.to_s => { value: job_invocation.id.to_s } } }
45
- result = ReportComposer.new(composer_params).render
46
-
47
- # parsing the CSV result
48
- rows = CSV.parse(result.strip, headers: true)
49
- assert_equal 1, rows.count
50
- row = rows.first
51
- assert_equal host.name, row['Host']
52
- assert_equal 'success', row['Result']
53
- assert_equal 'error', row['stderr']
54
- assert_equal 'output', row['stdout']
55
- assert_equal 'debug', row['debug']
56
- assert_kind_of Time, Time.zone.parse(row['Finished']), 'Parsing of time column failed'
57
- end
58
- end
59
- end
60
- end
@@ -1,232 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class JobInvocationTest < ActiveSupport::TestCase
4
- let(:job_invocation) { FactoryBot.build(:job_invocation, :description => 'A text with "quotes"') }
5
- let(:template) { FactoryBot.create(:job_template, :with_input) }
6
-
7
- context 'search for job invocations' do
8
- before do
9
- job_invocation.save
10
- end
11
-
12
- it 'is able to perform search through job invocations' do
13
- found_jobs = JobInvocation.search_for(%{job_category = "#{job_invocation.job_category}"}).paginate(:page => 1).order('job_invocations.id DESC')
14
- assert_equal [job_invocation], found_jobs
15
- end
16
-
17
- it 'is able to auto complete description' do
18
- expected = 'description = "A text with \"quotes\""'
19
- assert_equal [expected], JobInvocation.complete_for('description = ')
20
- end
21
- end
22
-
23
- context 'able to be created' do
24
- it { assert job_invocation.save }
25
- end
26
-
27
- context 'requires targeting' do
28
- before { job_invocation.targeting = nil }
29
-
30
- it { refute_valid job_invocation }
31
- end
32
-
33
- context 'can delete a host' do
34
- let(:host) do
35
- FactoryBot.create(:host)
36
- end
37
-
38
- it 'can remove a host' do
39
- job_invocation.template_invocations.build(:host_id => host.id, :template_id => template.id)
40
- job_invocation.save!
41
- host.destroy
42
- job_invocation.reload
43
- assert_empty job_invocation.template_invocations
44
- end
45
- end
46
-
47
- context 'has template invocations with input values' do
48
- let(:job_invocation) { FactoryBot.create(:job_invocation, :with_template) }
49
-
50
- before do
51
- input = job_invocation.pattern_template_invocations.first.template.template_inputs.create!(:name => 'foo', :required => true, :input_type => 'user')
52
- input2 = job_invocation.pattern_template_invocations.first.template.template_inputs.create!(:name => 'bar', :required => true, :input_type => 'user')
53
- FactoryBot.create(:template_invocation_input_value,
54
- :template_invocation => job_invocation.pattern_template_invocations.first,
55
- :template_input => input2)
56
- @input_value = FactoryBot.create(:template_invocation_input_value,
57
- :template_invocation => job_invocation.pattern_template_invocations.first,
58
- :template_input => input)
59
- job_invocation.reload
60
- job_invocation.pattern_template_invocations.first.reload
61
- end
62
-
63
- it { assert_not job_invocation.reload.pattern_template_invocations.empty? }
64
- it { assert_not job_invocation.reload.pattern_template_invocations.first.input_values.empty? }
65
-
66
- it "can look up templates not belonging to user's organization" do
67
- organization = job_invocation.pattern_template_invocations.first.template.organizations.first
68
- Organization.current = organization
69
- job_invocation.pattern_template_invocations.first.template.organizations = []
70
- # The following line raises UndefinedMethod if the user can't look up the template
71
- job_invocation.pattern_template_invocations.first.template.name
72
-
73
- # Restore things to original state
74
- job_invocation.pattern_template_invocations.first.template.organizations = [organization]
75
- Organization.current = nil
76
- end
77
-
78
- it 'validates required inputs have values' do
79
- assert job_invocation.valid?
80
- @input_value.destroy
81
- assert_not job_invocation.reload.valid?
82
- end
83
-
84
- describe 'descriptions' do
85
- it 'generates description from input values' do
86
- job_invocation.description_format = '%{job_category} - %{foo}'
87
- job_invocation.generate_description
88
- assert_equal "#{job_invocation.job_category} - #{@input_value.value}", job_invocation.description
89
- end
90
-
91
- it 'handles missing keys correctly' do
92
- job_invocation.description_format = '%{job_category} - %{missing_key}'
93
- job_invocation.generate_description
94
- assert_equal "#{job_invocation.job_category} - ''", job_invocation.description
95
- end
96
-
97
- it 'truncates generated description to 255 characters' do
98
- column_limit = 255 # There is a 255 character limit on the database level
99
- expected_result = 'a' * column_limit
100
- job_invocation.description_format = '%{job_category}'
101
- job_invocation.job_category = 'a' * 1000
102
- job_invocation.generate_description
103
- assert_equal expected_result, job_invocation.description
104
- end
105
- end
106
- end
107
-
108
- context 'future execution' do
109
- it 'can report host count' do
110
- assert_equal 'N/A', job_invocation.total_hosts_count
111
- job_invocation.targeting.expects(:resolved_at).returns(Time.now.getlocal)
112
- assert_equal 0, job_invocation.total_hosts_count
113
- end
114
-
115
- # task does not exist
116
- specify { assert_equal HostStatus::ExecutionStatus::QUEUED, job_invocation.status }
117
- specify { assert_equal HostStatus::ExecutionStatus::STATUS_NAMES[HostStatus::ExecutionStatus::QUEUED], job_invocation.status_label }
118
- specify { assert_equal 0, job_invocation.progress }
119
- end
120
-
121
- context 'with task' do
122
- let(:task) { ForemanTasks::Task.new }
123
- let(:progress_report_without_sub_tasks) do
124
- {
125
- :error => 0,
126
- :warning => 0,
127
- :total => 0,
128
- :success => 0,
129
- :cancelled => 0,
130
- :failed => 0,
131
- :pending => 0,
132
- :progress => 0,
133
- :running => 0,
134
- }
135
- end
136
- before { job_invocation.task = task }
137
-
138
- context 'which is scheduled' do
139
- before { task.state = 'scheduled' }
140
-
141
- specify { assert_equal HostStatus::ExecutionStatus::QUEUED, job_invocation.status }
142
- specify { assert job_invocation.queued? }
143
- specify { assert_equal 0, job_invocation.progress }
144
- specify { assert_equal progress_report_without_sub_tasks, job_invocation.progress_report }
145
- end
146
-
147
- context 'with cancelled task' do
148
- before do
149
- task.state = 'stopped'
150
- task.result = 'error'
151
- end
152
-
153
- it 'calculates the progress correctly' do
154
- job_invocation.targeting.stubs(:resolved?).returns(true)
155
- task.expects(:sub_tasks_counts).never
156
- assert_equal progress_report_without_sub_tasks, job_invocation.progress_report
157
- end
158
- end
159
-
160
- context 'with succeeded task' do
161
- before do
162
- task.state = 'stopped'
163
- task.result = 'success'
164
- end
165
-
166
- specify { assert_equal HostStatus::ExecutionStatus::OK, job_invocation.status }
167
- specify { refute job_invocation.queued? }
168
-
169
- it 'calculates the progress correctly' do
170
- sub_tasks = [ForemanTasks::Task.new]
171
- job_invocation.targeting.expects(:resolved?).returns(true)
172
- job_invocation.targeting.expects(:hosts).returns([1])
173
- sub_tasks.expects(:where).with(:result => %w(success warning error)).returns(sub_tasks)
174
- job_invocation.stubs(:sub_tasks).returns(sub_tasks)
175
-
176
- assert_equal 100, job_invocation.progress
177
- end
178
- end
179
- end
180
-
181
- describe '#finished?' do
182
- let(:task) { ForemanTasks::Task.new }
183
- before { job_invocation.task = task }
184
-
185
- it 'returns false if task state is pending' do
186
- job_invocation.task.expects(:pending?).returns(true)
187
- assert_not job_invocation.finished?
188
- end
189
-
190
- it 'returns true if task is not pending' do
191
- job_invocation.task.expects(:pending?).returns(false)
192
- assert job_invocation.finished?
193
- end
194
- end
195
-
196
- describe '#failed_hosts' do
197
- let(:invocation) do
198
- invocation = FactoryBot.build(:job_invocation, :with_template, :with_task, :with_failed_task, :with_unplanned_host)
199
- invocation.template_invocations.each { |ti| invocation.targeting.hosts << ti.host }
200
- invocation.save!
201
- invocation
202
- end
203
-
204
- it 'returns only failed hosts when not #finished?' do
205
- invocation.stubs(:finished?).returns(false)
206
- assert_equal 1, invocation.failed_hosts.count
207
- end
208
-
209
- it 'returns failed hosts and hosts without task when #finished?' do
210
- invocation.stubs(:finished?).returns(true)
211
- assert_equal 2, invocation.failed_hosts.count
212
- end
213
-
214
- describe '#failed_template_invocations' do
215
- it 'finds only failed template invocations' do
216
- template_invocations = invocation.send(:failed_template_invocations)
217
- assert_equal 1, template_invocations.count
218
- template_invocation = template_invocations.first
219
- assert_equal 'error', template_invocation.run_host_job_task.result
220
- end
221
- end
222
-
223
- describe '#not_failed_template_invocations' do
224
- it 'finds only non-failed template invocations' do
225
- template_invocations = invocation.send(:not_failed_template_invocations)
226
- assert_equal 1, template_invocations.count
227
- template_invocation = template_invocations.first
228
- assert_equal 'success', template_invocation.run_host_job_task.result
229
- end
230
- end
231
- end
232
- end
@@ -1,37 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class JobTemplateEffectiveUserTest < ActiveSupport::TestCase
4
- let(:job_template) { FactoryBot.build(:job_template, :job_category => '') }
5
- let(:effective_user) { job_template.effective_user }
6
-
7
- describe 'by default' do
8
- it 'is overridable' do
9
- assert effective_user.overridable?
10
- end
11
-
12
- it 'does not use the current user' do
13
- assert_not effective_user.current_user?
14
- end
15
- end
16
-
17
- describe 'compute value' do
18
- it 'computes the value based on the current user when current_user set to true' do
19
- user = FactoryBot.create(:user)
20
- User.current = user
21
- effective_user.current_user = true
22
- assert_equal user.login, effective_user.compute_value
23
- end
24
-
25
- it 'returns the value when not current user is set to true' do
26
- effective_user.current_user = false
27
- effective_user.value = 'testuser'
28
- assert_equal 'testuser', effective_user.compute_value
29
- end
30
-
31
- it 'returns a default value when no value is specified for the user' do
32
- effective_user.value = ''
33
- Setting[:remote_execution_effective_user] = 'myuser'
34
- assert_equal 'myuser', effective_user.compute_value
35
- end
36
- end
37
- end
@@ -1,316 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class JobTemplateTest < ActiveSupport::TestCase
4
- context 'when creating a template' do
5
- let(:job_template) { FactoryBot.build(:job_template, :job_category => '') }
6
- let(:template_with_inputs) do
7
- FactoryBot.build(:job_template, :template => 'test').tap do |template|
8
- template.template_inputs << FactoryBot.build(:template_input, :name => 'command', :input_type => 'user')
9
- template.save!
10
- end
11
- end
12
-
13
- it 'has a unique name' do
14
- template1 = FactoryBot.create(:job_template)
15
- template2 = FactoryBot.build(:job_template, :name => template1.name)
16
- assert_not template2.valid?
17
- end
18
-
19
- it 'needs a job_category' do
20
- assert_not job_template.valid?
21
- end
22
-
23
- it 'does not need a job_category if it is a snippet' do
24
- job_template.snippet = true
25
- assert job_template.valid?
26
- end
27
-
28
- it 'validates the inputs are uniq in the template' do
29
- job_template.job_category = 'Miscellaneous'
30
- job_template.foreign_input_sets << FactoryBot.build(:foreign_input_set, :target_template => template_with_inputs)
31
- job_template.foreign_input_sets << FactoryBot.build(:foreign_input_set, :target_template => template_with_inputs)
32
- assert_not job_template.valid?
33
- assert_includes job_template.errors.full_messages.first, 'Duplicated inputs detected: ["command"]'
34
- end
35
- end
36
-
37
- context 'description format' do
38
- let(:template_with_description) { FactoryBot.build(:job_template, :with_description_format, :job_category => 'test job') }
39
- let(:template) { FactoryBot.build(:job_template, :with_input, :job_category => 'test job') }
40
- let(:minimal_template) { FactoryBot.build(:job_template) }
41
-
42
- it 'uses the description_format attribute if set' do
43
- assert_equal template_with_description.generate_description_format, template_with_description.description_format
44
- end
45
-
46
- it 'uses the job name as description_format if not set or blank and has no inputs' do
47
- assert_equal minimal_template.generate_description_format, '%{template_name}'
48
- minimal_template.description_format = ''
49
- assert_equal minimal_template.generate_description_format, '%{template_name}'
50
- end
51
-
52
- it 'generates the description_format if not set or blank and has inputs' do
53
- input_name = template.template_inputs.first.name
54
- expected_result = %(%{template_name} with inputs #{input_name}="%{#{input_name}}")
55
- assert_equal template.generate_description_format, expected_result
56
- template.description_format = ''
57
- assert_equal template.generate_description_format, expected_result
58
- end
59
- end
60
-
61
- context 'cloning' do
62
- let(:job_template) { FactoryBot.build(:job_template, :with_input) }
63
-
64
- describe '#dup' do
65
- it 'duplicates also template inputs' do
66
- duplicate = job_template.dup
67
- refute_equal duplicate, job_template
68
- refute_empty duplicate.template_inputs
69
- refute_equal duplicate.template_inputs.first, job_template.template_inputs.first
70
- assert_equal duplicate.template_inputs.first.name, job_template.template_inputs.first.name
71
- end
72
- end
73
- end
74
-
75
- context 'importing a new template' do
76
- let(:remote_execution_feature) do
77
- FactoryBot.create(:remote_execution_feature)
78
- end
79
-
80
- let(:template) do
81
- template = <<-END_TEMPLATE
82
- <%#
83
- kind: job_template
84
- name: Service Restart
85
- job_category: Service Restart
86
- provider_type: SSH
87
- feature: #{remote_execution_feature.label}
88
- template_inputs:
89
- - name: service_name
90
- input_type: user
91
- required: true
92
- - name: verbose
93
- input_type: user
94
- %>
95
-
96
- service <%= input("service_name") %> restart
97
-
98
- <%# test comment %>
99
- END_TEMPLATE
100
-
101
- JobTemplate.import_raw!(template, :default => true)
102
- end
103
-
104
- let(:template_with_input_sets) do
105
- template_with_input_sets = <<-END_TEMPLATE
106
- <%#
107
- kind: job_template
108
- name: Service Restart - Custom
109
- job_category: Service Restart
110
- provider_type: SSH
111
- foreign_input_sets:
112
- - template: #{template.name}
113
- exclude: verbose
114
- %>
115
-
116
- service <%= input("service_name") %> restart
117
- END_TEMPLATE
118
-
119
- JobTemplate.import_raw!(template_with_input_sets, :default => true)
120
- end
121
-
122
- it 'sets the name' do
123
- assert_equal template.name, 'Service Restart'
124
- end
125
-
126
- it 'has a template' do
127
- assert_equal template.template.squish, 'service <%= input("service_name") %> restart <%# test comment %>'
128
- end
129
-
130
- it 'imports inputs' do
131
- assert_equal template.template_inputs.first.name, 'service_name'
132
- end
133
-
134
- it 'imports input sets' do
135
- assert_equal template_with_input_sets.foreign_input_sets.first.target_template, template
136
- assert_equal template_with_input_sets.template_inputs_with_foreign.map(&:name), ['service_name']
137
- end
138
-
139
- it 'imports feature' do
140
- template # let is lazy
141
- remote_execution_feature.reload
142
- assert_equal remote_execution_feature.job_template, template
143
- end
144
-
145
- it 'sets additional options' do
146
- assert_equal template.default, true
147
- end
148
- end
149
-
150
- context 'importing an existing template' do
151
- let(:included) do
152
- template = <<-END_TEMPLATE
153
- <%#
154
- kind: job_template
155
- name: Banner
156
- job_category: Commands
157
- provider_type: SSH
158
- template_inputs:
159
- - name: banner_message
160
- input_type: user
161
- required: true
162
- %>
163
-
164
- echo input(:banner_message)
165
- END_TEMPLATE
166
-
167
- JobTemplate.import_raw!(template, :default => true)
168
- end
169
-
170
- let(:existing) do
171
- template = <<-END_TEMPLATE
172
- <%#
173
- kind: job_template
174
- name: Ping a Thing
175
- job_category: Commands
176
- provider_type: SSH
177
- template_inputs:
178
- - name: hostname
179
- input_type: user
180
- options: "www.google.com"
181
- required: true
182
- foreign_input_sets:
183
- - template: #{included.name}
184
- %>
185
-
186
- ping -c 5 <%= input("hostname") %>
187
- END_TEMPLATE
188
-
189
- JobTemplate.import_raw!(template, :default => true)
190
- end
191
-
192
- let(:updated) do
193
- <<-END_TEMPLATE
194
- <%#
195
- kind: job_template
196
- name: Ping a Thing
197
- job_category: Commands
198
- provider_type: SSH
199
- template_inputs:
200
- - name: hostname
201
- input_type: user
202
- options: 'www.redhat.com'
203
- required: true
204
- - name: count
205
- input_type: user
206
- required: true
207
- foreign_input_sets:
208
- - template: #{included.name}
209
- exclude: banner_message
210
- %>
211
-
212
- ping -c <%= input('count') %> <%= input('hostname') %>
213
- END_TEMPLATE
214
- end
215
-
216
- it 'will not overwrite by default' do
217
- existing
218
- assert_not JobTemplate.import_raw!(updated)
219
- end
220
-
221
- let(:synced_template) do
222
- existing
223
- JobTemplate.import_raw!(updated, :update => true)
224
- existing.reload
225
- end
226
-
227
- it 'syncs inputs' do
228
- hostname = synced_template.template_inputs.find { |input| input.name == 'hostname' }
229
- assert_equal hostname.options, 'www.redhat.com'
230
- end
231
-
232
- it 'syncs content' do
233
- assert_match(/ping -c <%= input\('count'\) %> <%= input\('hostname'\) %>/m, synced_template.template)
234
- end
235
-
236
- it 'syncs input sets' do
237
- assert_equal synced_template.foreign_input_sets.first.target_template, included
238
- assert_equal synced_template.template_inputs_with_foreign.map(&:name), ['hostname', 'count']
239
- end
240
- end
241
-
242
- context 'template export' do
243
- let(:exportable_template) do
244
- FactoryBot.create(:job_template, :with_input)
245
- end
246
-
247
- let(:erb) do
248
- exportable_template.to_erb
249
- end
250
-
251
- it 'exports name' do
252
- assert_match(/^name: #{exportable_template.name}$/, erb)
253
- end
254
-
255
- it 'includes template inputs' do
256
- assert_match(/^template_inputs:$/, erb)
257
- end
258
-
259
- it 'includes template contents' do
260
- assert_includes erb, exportable_template.template
261
- end
262
-
263
- it 'is importable' do
264
- erb
265
- old_name = exportable_template.name
266
- exportable_template.update(:name => "#{old_name}_renamed")
267
-
268
- imported = JobTemplate.import_raw!(erb)
269
- assert_equal imported.name, old_name
270
- assert_equal imported.template_inputs.first.to_export, exportable_template.template_inputs.first.to_export
271
- end
272
-
273
- it 'has taxonomies in metadata' do
274
- assert_equal 'Organization 1', exportable_template.to_export["organizations"].first
275
- assert_equal 'Location 1', exportable_template.to_export["locations"].first
276
- end
277
- end
278
-
279
- context 'there is existing template invocation of a job template' do
280
- let(:job_invocation) { FactoryBot.create(:job_invocation, :with_template) }
281
- let(:job_template) { job_invocation.pattern_template_invocations.first.template }
282
-
283
- describe 'job template deletion' do
284
- it 'succeeds' do
285
- refute_empty job_template.pattern_template_invocations
286
- assert job_template.destroy
287
- end
288
- end
289
- end
290
-
291
- context 'template locked' do
292
- it 'inputs cannot be changed' do
293
- job_template = FactoryBot.create(:job_template, :with_input, :locked => true)
294
- Foreman.expects(:in_rake?).returns(false).at_least_once
295
- assert_valid job_template
296
- job_template.template_inputs.first.name = 'something else'
297
- refute_valid job_template
298
- end
299
- end
300
-
301
- context 'rendering' do
302
- it 'renders nested template as a non-admin user' do
303
- inner = FactoryBot.create(:job_template)
304
- template_invocation = FactoryBot.create(:template_invocation)
305
- template_invocation.template.template = "<wrap><%= render_template('#{inner.name}') %></wrap>"
306
- template_invocation.template.save!
307
-
308
- setup_user('view', 'job_templates')
309
- renderer = InputTemplateRenderer.new template_invocation.template,
310
- template_invocation.host,
311
- template_invocation
312
- result = renderer.render
313
- assert_equal result, "<wrap>#{inner.template}</wrap>"
314
- end
315
- end
316
- end