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