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,86 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class RemoteExecutionFeatureTest < ActiveSupport::TestCase
4
- should validate_presence_of(:name)
5
- should validate_presence_of(:label)
6
- should validate_uniqueness_of(:name)
7
- should validate_uniqueness_of(:label)
8
-
9
- let(:install_feature) do
10
- RemoteExecutionFeature.register(:katello_install_package, N_('Katello: Install package'),
11
- :description => 'Install package via Katello user interface',
12
- :provided_inputs => ['package'])
13
- end
14
-
15
- let(:package_template) do
16
- FactoryBot.create(:job_template).tap do |job_template|
17
- job_template.job_category = 'Package Action'
18
- job_template.name = 'Package Action - SSH Default'
19
- job_template.template_inputs.create(:name => 'package', :input_type => 'user')
20
- end
21
- end
22
-
23
- let(:host) { FactoryBot.create(:host) }
24
-
25
- before do
26
- User.current = users :admin
27
- install_feature.update!(:job_template_id => package_template.id)
28
- end
29
-
30
- describe 'composer' do
31
- it 'prepares composer for given feature based on the mapping' do
32
- composer = JobInvocationComposer.for_feature(:katello_install_package, host, :package => 'zsh')
33
- assert composer.valid?
34
- assert_equal 1, composer.pattern_template_invocations.size
35
- template_invocation = composer.pattern_template_invocations.first
36
- assert_equal package_template, template_invocation.template
37
- assert_equal 1, template_invocation.input_values.size
38
-
39
- input_value = template_invocation.input_values.first
40
- assert_equal 'zsh', input_value.value
41
- assert_equal 'package', input_value.template_input.name
42
-
43
- assert_equal "name ^ (#{host.name})", composer.targeting.search_query
44
- end
45
-
46
- it 'updates the feature when attributes change' do
47
- updated_feature = RemoteExecutionFeature.register(install_feature.label, N_('Katello: Install package'),
48
- :description => 'New description',
49
- :provided_inputs => ['package', 'force'])
50
- updated_feature.reload
51
- assert_equal install_feature.id, updated_feature.id
52
- assert_equal 'New description', updated_feature.description
53
- assert_equal ['package', 'force'], updated_feature.provided_input_names
54
- end
55
- end
56
-
57
- describe '.register' do
58
- it "creates a feature if it's missing" do
59
- feature = RemoteExecutionFeature.register('new_feature_that_does_not_exist', 'name')
60
- assert_predicate feature, :persisted?
61
- assert_equal 'new_feature_that_does_not_exist', feature.label
62
- assert_equal 'name', feature.name
63
- assert_not feature.host_action_button
64
- end
65
-
66
- it 'creates a feature with host action flag' do
67
- feature = RemoteExecutionFeature.register('new_feature_that_does_not_exist_button', 'name', :host_action_button => true)
68
- assert_predicate feature, :persisted?
69
- assert feature.host_action_button
70
- end
71
-
72
- it 'created feature with host action flag can be found using named scope' do
73
- feature = RemoteExecutionFeature.register('new_feature_that_does_not_exist_button', 'name', :host_action_button => true)
74
- assert_includes RemoteExecutionFeature.with_host_action_button, feature
75
- end
76
-
77
-
78
- it 'updates a feature if it exists' do
79
- existing = FactoryBot.create(:remote_execution_feature, :name => 'existing_feature_withou_action_button')
80
- feature = RemoteExecutionFeature.register(existing.label, existing.name, :host_action_button => true)
81
- assert_predicate feature, :persisted?
82
- existing.reload
83
- assert existing.host_action_button
84
- end
85
- end
86
- end
@@ -1,298 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class RemoteExecutionProviderTest < ActiveSupport::TestCase
4
- describe '.providers' do
5
- let(:providers) { RemoteExecutionProvider.providers }
6
- it { assert_kind_of HashWithIndifferentAccess, providers }
7
- it 'makes providers accessible using symbol' do
8
- assert_equal SSHExecutionProvider, providers[:SSH]
9
- assert_equal ScriptExecutionProvider, providers[:script]
10
- end
11
- it 'makes providers accessible using string' do
12
- assert_equal SSHExecutionProvider, providers['SSH']
13
- assert_equal ScriptExecutionProvider, providers['script']
14
- end
15
- end
16
-
17
- describe '.register_provider' do
18
- before { RemoteExecutionProvider.providers.delete(:new) }
19
- let(:new_provider) { RemoteExecutionProvider.providers[:new] }
20
- it { assert_nil new_provider }
21
-
22
- context 'registers a provider under key :new' do
23
- before { RemoteExecutionProvider.register(:new, String) }
24
- it { assert_equal String, new_provider }
25
- end
26
- end
27
-
28
- describe '.provider_for' do
29
- it 'accepts symbols' do
30
- assert_equal SSHExecutionProvider, RemoteExecutionProvider.provider_for(:SSH)
31
- end
32
-
33
- it 'accepts strings' do
34
- assert_equal SSHExecutionProvider, RemoteExecutionProvider.provider_for('SSH')
35
- end
36
-
37
- it 'returns a default one if unknown value is provided' do
38
- assert_equal ScriptExecutionProvider, RemoteExecutionProvider.provider_for('WinRM')
39
- end
40
- end
41
-
42
- describe '.provider_names' do
43
- let(:provider_names) { RemoteExecutionProvider.provider_names }
44
-
45
- it 'returns only strings' do
46
- provider_names.each do |name|
47
- assert_kind_of String, name
48
- end
49
- end
50
-
51
- context 'provider is registetered under :custom symbol' do
52
- before { RemoteExecutionProvider.register(:Custom, String) }
53
-
54
- it { assert_includes provider_names, 'SSH' }
55
- it { assert_includes provider_names, 'Custom' }
56
- end
57
- end
58
-
59
- describe '.proxy_feature' do
60
- # rubocop:disable Naming/ConstantName
61
- it 'handles provider subclasses properly' do
62
- old = ::RemoteExecutionProvider
63
-
64
- class P2 < old
65
- end
66
- ::RemoteExecutionProvider = P2
67
-
68
- class CustomProvider < ::RemoteExecutionProvider
69
- end
70
-
71
- ::RemoteExecutionProvider.register('custom', CustomProvider)
72
-
73
- feature = CustomProvider.proxy_feature
74
- assert_equal 'custom', feature
75
- ensure
76
- ::RemoteExecutionProvider = old
77
- end
78
- # rubocop:enable Naming/ConstantName
79
- end
80
-
81
- describe '.provider_proxy_features' do
82
- it 'returns correct values' do
83
- RemoteExecutionProvider.stubs(:providers).returns(
84
- :SSH => SSHExecutionProvider,
85
- :script => ScriptExecutionProvider
86
- )
87
-
88
- features = RemoteExecutionProvider.provider_proxy_features
89
- assert_includes features, 'SSH'
90
- assert_includes features, 'Script'
91
- RemoteExecutionProvider.unstub(:providers)
92
- end
93
-
94
- it 'can deal with non-arrays' do
95
- provider = OpenStruct.new(proxy_feature: 'Testing')
96
- RemoteExecutionProvider.stubs(:providers).returns(:testing => provider)
97
- features = RemoteExecutionProvider.provider_proxy_features
98
- assert_includes features, 'Testing'
99
- RemoteExecutionProvider.unstub(:providers)
100
- end
101
- end
102
-
103
- describe '.host_setting' do
104
- let(:host) { FactoryBot.create(:host) }
105
-
106
- it 'honors falsey values set as a host parameter' do
107
- key = 'remote_execution_connect_by_ip'
108
- Setting[key] = true
109
- host.parameters << HostParameter.new(name: key, value: false)
110
-
111
- refute RemoteExecutionProvider.host_setting(host, key)
112
- end
113
- end
114
-
115
- describe SSHExecutionProvider do
116
- before { User.current = FactoryBot.build(:user, :admin) }
117
- after { User.current = nil }
118
-
119
- let(:job_invocation) { FactoryBot.create(:job_invocation, :with_template) }
120
- let(:template_invocation) { job_invocation.pattern_template_invocations.first }
121
- let(:host) { FactoryBot.create(:host) }
122
- let(:proxy_options) { SSHExecutionProvider.proxy_command_options(template_invocation, host) }
123
- let(:secrets) { SSHExecutionProvider.secrets(host) }
124
-
125
- describe 'effective user' do
126
- it 'takes the effective user from value from the template invocation' do
127
- template_invocation.effective_user = 'my user'
128
- assert_equal 'my user', proxy_options[:effective_user]
129
- end
130
- end
131
-
132
- describe 'ssh user' do
133
- it 'uses the remote_execution_ssh_user on the host param' do
134
- host.host_parameters << FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_ssh_user', :value => 'my user')
135
- assert_equal 'my user', proxy_options[:ssh_user]
136
- end
137
- end
138
-
139
- describe 'effective user password' do
140
- it 'uses the remote_execution_effective_user_password on the host param' do
141
- host.params['remote_execution_effective_user_password'] = 'mypassword'
142
- host.host_parameters << FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_effective_user_password', :value => 'mypassword')
143
- assert_nil proxy_options[:effective_user_password]
144
- assert_equal 'mypassword', secrets[:effective_user_password]
145
- end
146
- end
147
-
148
- describe 'sudo' do
149
- it 'uses the remote_execution_effective_user_method on the host param' do
150
- host.params['remote_execution_effective_user_method'] = 'sudo'
151
- method_param = FactoryBot.create(:host_parameter, :host => host, :name => 'remote_execution_effective_user_method', :value => 'sudo')
152
- host.host_parameters << method_param
153
- assert_equal 'sudo', proxy_options[:effective_user_method]
154
- method_param.update!(:value => 'su')
155
- host.clear_host_parameters_cache!
156
- proxy_options = SSHExecutionProvider.proxy_command_options(template_invocation, host)
157
- assert_equal 'su', proxy_options[:effective_user_method]
158
- method_param.update!(:value => 'dzdo')
159
- host.clear_host_parameters_cache!
160
- proxy_options = SSHExecutionProvider.proxy_command_options(template_invocation, host)
161
- assert_equal 'dzdo', proxy_options[:effective_user_method]
162
- end
163
- end
164
-
165
- describe 'ssh port from settings' do
166
- before do
167
- Setting[:remote_execution_ssh_port] = '66'
168
- end
169
-
170
- it 'has ssh port changed in settings and check return type' do
171
- assert_kind_of Integer, proxy_options[:ssh_port]
172
- assert_equal 66, proxy_options[:ssh_port]
173
- end
174
- end
175
-
176
- describe 'ssh port from params' do
177
- it 'takes ssh port number from params and check return type' do
178
- host.params['remote_execution_ssh_port'] = '30'
179
- host.host_parameters << FactoryBot.build(:host_parameter, :name => 'remote_execution_ssh_port', :value => '30')
180
- host.clear_host_parameters_cache!
181
- assert_kind_of Integer, proxy_options[:ssh_port]
182
- assert_equal 30, proxy_options[:ssh_port]
183
- end
184
- end
185
-
186
- describe 'cleanup working directories setting' do
187
- before do
188
- Setting[:remote_execution_cleanup_working_dirs] = false
189
- end
190
-
191
- it 'updates the value via settings' do
192
- refute proxy_options[:cleanup_working_dirs]
193
- end
194
- end
195
-
196
- describe 'cleanup working directories from parameters' do
197
- it 'takes the value from host parameters' do
198
- host.params['remote_execution_cleanup_working_dirs'] = 'false'
199
- host.host_parameters << FactoryBot.build(:host_parameter, :name => 'remote_execution_cleanup_working_dirs', :value => 'false')
200
- host.clear_host_parameters_cache!
201
- refute proxy_options[:cleanup_working_dirs]
202
- end
203
- end
204
-
205
- describe '#find_ip_or_hostname' do
206
- let(:host) do
207
- FactoryBot.create(:host) do |host|
208
- host.interfaces = [FactoryBot.build(:nic_managed, flags.merge(:ip => nil, :name => 'somehost.somedomain.org', :primary => true)),
209
- FactoryBot.build(:nic_managed, flags.merge(:ip => '127.0.0.1'))]
210
- end.reload
211
- # Reassigning the interfaces triggers the on-deletion ssh key removal for the interface which is being replaced
212
- # This has an undesired side effect of caching the original interface as execution one which made the tests
213
- # give wrong results. Reloading the host wipes the cache
214
- end
215
-
216
- let(:flags) do
217
- { :primary => false, :provision => false, :execution => false }
218
- end
219
-
220
- it 'gets fqdn from flagged interfaces if not preferring ips' do
221
- # falling to primary interface
222
- assert_equal 'somehost.somedomain.org', SSHExecutionProvider.find_ip_or_hostname(host)
223
-
224
- # execution wins if present
225
- execution_interface = FactoryBot.build(:nic_managed,
226
- flags.merge(:execution => true, :name => 'special.somedomain.org'))
227
- host.interfaces << execution_interface
228
- host.primary_interface.update(:execution => false)
229
- host.interfaces.each(&:save)
230
- host.reload
231
- assert_equal execution_interface.fqdn, SSHExecutionProvider.find_ip_or_hostname(host)
232
- end
233
-
234
- it 'gets ip from flagged interfaces' do
235
- host.host_params['remote_execution_connect_by_ip'] = true
236
- # no ip address set on relevant interface - fallback to fqdn
237
- assert_equal 'somehost.somedomain.org', SSHExecutionProvider.find_ip_or_hostname(host)
238
-
239
- # provision interface with ip while primary without
240
- provision_interface = FactoryBot.build(:nic_managed,
241
- flags.merge(:provision => true, :ip => '10.0.0.1'))
242
- host.interfaces << provision_interface
243
- host.primary_interface.update(:provision => false)
244
- host.interfaces.each(&:save)
245
- host.reload
246
- assert_equal provision_interface.ip, SSHExecutionProvider.find_ip_or_hostname(host)
247
-
248
- # both primary and provision interface have IPs: the primary wins
249
- host.primary_interface.update(:ip => '10.0.0.2', :execution => false)
250
- host.reload
251
- assert_equal host.primary_interface.ip, SSHExecutionProvider.find_ip_or_hostname(host)
252
-
253
- # there is an execution interface with IP: it wins
254
- execution_interface = FactoryBot.build(:nic_managed,
255
- flags.merge(:execution => true, :ip => '10.0.0.3'))
256
- host.interfaces << execution_interface
257
- host.primary_interface.update(:execution => false)
258
- host.interfaces.each(&:save)
259
- host.reload
260
- assert_equal execution_interface.ip, SSHExecutionProvider.find_ip_or_hostname(host)
261
-
262
- # there is an execution interface with both IPv6 and IPv4: IPv4 is being preferred over IPv6 by default
263
- execution_interface = FactoryBot.build(:nic_managed,
264
- flags.merge(:execution => true, :ip => '10.0.0.4', :ip6 => 'fd00::4'))
265
- host.interfaces = [execution_interface]
266
- host.interfaces.each(&:save)
267
- host.reload
268
- assert_equal execution_interface.ip, SSHExecutionProvider.find_ip_or_hostname(host)
269
- end
270
-
271
- it 'gets ipv6 from flagged interfaces with IPv6 preference' do
272
- host.host_params['remote_execution_connect_by_ip_prefer_ipv6'] = true
273
- host.host_params['remote_execution_connect_by_ip'] = true
274
-
275
- # there is an execution interface with both IPv6 and IPv4: IPv6 is being preferred over IPv4 by host parameter configuration
276
- execution_interface = FactoryBot.build(:nic_managed,
277
- flags.merge(:execution => true, :ip => '10.0.0.4', :ip6 => 'fd00::4'))
278
- host.interfaces = [execution_interface]
279
- host.interfaces.each(&:save)
280
- host.reload
281
- assert_equal execution_interface.ip6, SSHExecutionProvider.find_ip_or_hostname(host)
282
- end
283
-
284
- it 'gets ipv6 from flagged interfaces with IPv4 preference but without IPv4 address' do
285
- host.host_params['remote_execution_connect_by_ip_prefer_ipv6'] = false
286
- host.host_params['remote_execution_connect_by_ip'] = true
287
-
288
- # there is an execution interface with both IPv6 and IPv4: IPv6 is being preferred over IPv4 by host parameter configuration
289
- execution_interface = FactoryBot.build(:nic_managed,
290
- flags.merge(:execution => true, :ip => nil, :ip6 => 'fd00::4'))
291
- host.interfaces = [execution_interface]
292
- host.interfaces.each(&:save)
293
- host.reload
294
- assert_equal execution_interface.ip6, SSHExecutionProvider.find_ip_or_hostname(host)
295
- end
296
- end
297
- end
298
- end
@@ -1,49 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class RendererScopeInputTest < ActiveSupport::TestCase
4
- let(:source) { Foreman::Renderer::Source::String.new(content: '') }
5
-
6
- describe 'caching helper in real mode' do
7
- let(:input) do
8
- input = ForemanRemoteExecution::Renderer::Scope::Input.new(source: source)
9
- input.stubs(:invocation => OpenStruct.new(:job_invocation_id => 1))
10
- input
11
- end
12
-
13
- it 'caches the value under given key' do
14
- i = 1
15
- result = input.cached('some_key') { i }
16
- assert_equal 1, result
17
-
18
- i += 1
19
- result = input.cached('some_key') { i }
20
- assert_equal 1, result
21
-
22
- i += 1
23
- result = input.cached('different_key') { i }
24
- assert_equal 3, result
25
- end
26
- end
27
-
28
- describe 'caching helper in preview mode' do
29
- let(:input) do
30
- input = ForemanRemoteExecution::Renderer::Scope::Input.new(source: source)
31
- input.stubs(:invocation => OpenStruct.new(:job_invocation_id => 1), :preview? => true)
32
- input
33
- end
34
-
35
- it 'does not cache the value' do
36
- i = 1
37
- result = input.cached('some_key') { i }
38
- assert_equal 1, result
39
-
40
- i += 1
41
- result = input.cached('some_key') { i }
42
- assert_equal 2, result
43
-
44
- i += 1
45
- result = input.cached('different_key') { i }
46
- assert_equal 3, result
47
- end
48
- end
49
- end
@@ -1,206 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class TargetingTest < ActiveSupport::TestCase
4
- let(:targeting) { FactoryBot.build(:targeting) }
5
- let(:bookmark) { bookmarks(:one) }
6
- let(:host) { FactoryBot.create(:host) }
7
-
8
- before do
9
- bookmark.query = 'name = bar'
10
- end
11
-
12
- describe '#resolved?' do
13
- context 'resolved_at is nil' do
14
- before { targeting.resolved_at = nil }
15
- it { assert_not targeting.resolved? }
16
- end
17
-
18
- context 'resolved_at is set' do
19
- before { targeting.resolved_at = Time.now.getlocal }
20
- it { assert targeting.resolved? }
21
- end
22
-
23
- end
24
-
25
- context 'able to be created with search term' do
26
- before { targeting.search_query = 'name = foo' }
27
- it { assert targeting.save }
28
- end
29
-
30
- context 'able to be created with a bookmark' do
31
- before do
32
- targeting.search_query = nil
33
- targeting.bookmark = bookmark
34
- end
35
- it { assert_valid targeting }
36
- end
37
-
38
- context 'cannot create without search term or bookmark' do
39
- before do
40
- targeting.targeting_type = Targeting::DYNAMIC_TYPE
41
- targeting.search_query = ''
42
- targeting.bookmark = nil
43
- end
44
- it { refute_valid targeting }
45
- end
46
-
47
- context 'can resolve hosts via query' do
48
- before do
49
- targeting.user = users(:admin)
50
- targeting.search_query = "name = #{host.name}"
51
- targeting.resolve_hosts!
52
- end
53
-
54
- it { assert_includes targeting.hosts, host }
55
- end
56
-
57
- context 'can delete a user' do
58
- before do
59
- targeting.user = users(:one)
60
- targeting.save!
61
- users(:one).destroy
62
- end
63
-
64
- it { assert_nil targeting.reload.user }
65
- it do
66
- assert_raises(Foreman::Exception) { targeting.resolve_hosts! }
67
- end
68
- end
69
-
70
- context 'can delete a host' do
71
- before do
72
- targeting.hosts << host
73
- targeting.save!
74
- host.destroy
75
- end
76
-
77
- it { assert_empty targeting.reload.hosts }
78
- end
79
-
80
- describe '#resolve_hosts!' do
81
- let(:second_host) { FactoryBot.create(:host) }
82
- let(:infra_host) { FactoryBot.create(:host, :with_infrastructure_facet) }
83
- let(:targeting) { FactoryBot.build(:targeting) }
84
-
85
- before do
86
- host
87
- second_host
88
- infra_host
89
- end
90
-
91
- context 'with infrastructure host permission' do
92
- before do
93
- setup_user('view', 'hosts')
94
- setup_user('execute_jobs_on', 'infrastructure_hosts')
95
- end
96
-
97
- it 'resolves all hosts' do
98
- hosts = [host, second_host, infra_host]
99
- targeting.search_query = "name ^ (#{hosts.map(&:name).join(',')})"
100
- targeting.user = User.current
101
- targeting.resolve_hosts!
102
-
103
- assert_includes targeting.hosts, host
104
- assert_includes targeting.hosts, second_host
105
- assert_includes targeting.hosts, infra_host
106
- end
107
- end
108
-
109
- context 'without infrastructure host permission' do
110
- before { setup_user('view', 'hosts') }
111
-
112
- it 'ignores infrastructure hosts' do
113
- hosts = [host, second_host, infra_host]
114
- targeting.search_query = "name ^ (#{hosts.map(&:name).join(',')})"
115
- targeting.user = User.current
116
- targeting.resolve_hosts!
117
-
118
- assert_includes targeting.hosts, host
119
- assert_includes targeting.hosts, second_host
120
- refute_includes targeting.hosts, infra_host
121
- end
122
- end
123
- end
124
-
125
- describe '#build_query_from_hosts(ids)' do
126
- let(:second_host) { FactoryBot.create(:host) }
127
- let(:infra_host) { FactoryBot.create(:host, :with_infrastructure_facet) }
128
-
129
- before do
130
- host
131
- second_host
132
- infra_host
133
- end
134
-
135
- context 'for two hosts' do
136
- let(:query) { Targeting.build_query_from_hosts([ host.id, second_host.id, infra_host.id ]) }
137
-
138
- it 'builds query using host names joining inside ^' do
139
- assert_includes query, host.name
140
- assert_includes query, second_host.name
141
- assert_includes query, infra_host.name
142
- assert_includes query, 'name ^'
143
-
144
- assert_includes Host.search_for(query), host
145
- assert_includes Host.search_for(query), second_host
146
- assert_includes Host.search_for(query), infra_host
147
- end
148
- end
149
-
150
- context 'for one host' do
151
- let(:query) { Targeting.build_query_from_hosts([ host.id ]) }
152
-
153
- it 'builds query using host name' do
154
- assert_equal "name ^ (#{host.name})", query
155
- assert_includes Host.search_for(query), host
156
- refute_includes Host.search_for(query), second_host
157
- refute_includes Host.search_for(query), infra_host
158
- end
159
- end
160
-
161
- context 'for no id' do
162
- let(:query) { Targeting.build_query_from_hosts([]) }
163
-
164
- it 'builds query to find all hosts' do
165
- assert_includes Host.search_for(query), host
166
- assert_includes Host.search_for(query), second_host
167
- assert_includes Host.search_for(query), infra_host
168
- end
169
- end
170
-
171
- context 'without infrastructure host permission' do
172
- before { User.current = nil }
173
-
174
- it 'ignores the infrastructure host' do
175
- query = Targeting.build_query_from_hosts([host.id, second_host.id, infra_host.id])
176
- assert_includes query, host.name
177
- assert_includes query, second_host.name
178
- refute_includes query, infra_host.name
179
- assert_includes query, 'name ^'
180
-
181
- assert_includes Host.search_for(query), host
182
- assert_includes Host.search_for(query), second_host
183
- refute_includes Host.search_for(query), infra_host
184
- end
185
- end
186
- end
187
-
188
- context 'randomized ordering' do
189
- let(:targeting) { FactoryBot.build(:targeting, :with_randomized_ordering) }
190
- let(:hosts) { (0..4).map { FactoryBot.create(:host) } }
191
-
192
- it 'loads the hosts in random order' do
193
- rng = Random.new(4) # Chosen by a fair dice roll
194
- Random.stubs(:new).returns(rng)
195
- hosts
196
- targeting.search_query = 'name ~ host*'
197
- targeting.user = users(:admin)
198
- targeting.resolve_hosts!
199
- randomized_host_ids = targeting.hosts.map(&:id)
200
- host_ids = hosts.map(&:id)
201
-
202
- assert_not_equal host_ids, randomized_host_ids
203
- assert_equal host_ids, randomized_host_ids.sort
204
- end
205
- end
206
- end
@@ -1,38 +0,0 @@
1
- require 'test_plugin_helper'
2
-
3
- class TemplateInvocationInputTest < ActiveSupport::TestCase
4
- let(:template) { FactoryBot.build(:job_template, :template => 'service restart <%= input("service_name") -%>') }
5
- let(:renderer) { InputTemplateRenderer.new(template) }
6
- let(:job_invocation) { FactoryBot.create(:job_invocation) }
7
- let(:template_invocation) { FactoryBot.build(:template_invocation, :template => template) }
8
- let(:result) { renderer.render }
9
-
10
- context 'with selectable options' do
11
- before do
12
- result # let is lazy
13
- template.template_inputs << FactoryBot.build(:template_input, :name => 'service_name', :input_type => 'user',
14
- :required => true, :options => "foreman\nhttpd")
15
- end
16
-
17
- it 'fails with an invalid option' do
18
- refute_valid FactoryBot.build(:template_invocation_input_value, :template_invocation => template_invocation,
19
- :template_input => template.template_inputs.first,
20
- :value => 'sendmail')
21
- end
22
-
23
- it 'succeeds with valid option' do
24
- assert_valid FactoryBot.build(:template_invocation_input_value, :template_invocation => template_invocation,
25
- :template_input => template.template_inputs.first,
26
- :value => 'foreman')
27
- end
28
- end
29
-
30
- it 'supports large inputs' do
31
- template.template_inputs << FactoryBot.build(:template_input, :name => 'service_name',
32
- :input_type => 'user', :required => true)
33
- assert_valid FactoryBot.create(:template_invocation_input_value,
34
- :template_invocation => template_invocation,
35
- :template_input => template.template_inputs.first,
36
- :value => 'foreman' * 1_000_000)
37
- end
38
- end