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.
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