foreman_remote_execution 7.0.0 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby_ci.yml +4 -2
  3. data/app/controllers/foreman_remote_execution/concerns/api/v2/registration_commands_controller_extensions.rb +1 -0
  4. data/app/controllers/foreman_remote_execution/concerns/api/v2/registration_controller_extensions.rb +8 -0
  5. data/app/controllers/ui_job_wizard_controller.rb +15 -0
  6. data/app/helpers/remote_execution_helper.rb +1 -1
  7. data/app/models/concerns/foreman_remote_execution/foreman_tasks_task_extensions.rb +6 -0
  8. data/app/models/host_status/execution_status.rb +2 -1
  9. data/app/models/job_invocation.rb +1 -1
  10. data/app/models/job_invocation_composer.rb +6 -3
  11. data/app/models/job_template.rb +2 -0
  12. data/app/models/remote_execution_provider.rb +4 -0
  13. data/app/models/template_invocation.rb +2 -0
  14. data/app/services/remote_execution_proxy_selector.rb +1 -1
  15. data/app/views/overrides/subnets/_rex_tab_pane.html.erb +1 -1
  16. data/app/views/templates/script/package_action.erb +8 -3
  17. data/config/routes.rb +3 -1
  18. data/lib/foreman_remote_execution/engine.rb +6 -5
  19. data/lib/foreman_remote_execution/version.rb +1 -1
  20. data/test/functional/api/v2/job_invocations_controller_test.rb +8 -0
  21. data/test/helpers/remote_execution_helper_test.rb +4 -0
  22. data/test/unit/api_params_test.rb +33 -0
  23. data/test/unit/job_invocation_report_template_test.rb +1 -1
  24. data/test/unit/job_invocation_test.rb +1 -2
  25. data/test/unit/remote_execution_provider_test.rb +26 -0
  26. data/webpack/JobWizard/JobWizard.js +154 -20
  27. data/webpack/JobWizard/JobWizard.scss +43 -1
  28. data/webpack/JobWizard/JobWizardConstants.js +11 -1
  29. data/webpack/JobWizard/JobWizardPageRerun.js +112 -0
  30. data/webpack/JobWizard/__tests__/JobWizardPageRerun.test.js +79 -0
  31. data/webpack/JobWizard/__tests__/fixtures.js +73 -0
  32. data/webpack/JobWizard/__tests__/integration.test.js +17 -3
  33. data/webpack/JobWizard/autofill.js +8 -1
  34. data/webpack/JobWizard/steps/AdvancedFields/AdvancedFields.js +9 -0
  35. data/webpack/JobWizard/steps/AdvancedFields/Fields.js +21 -0
  36. data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +41 -17
  37. data/webpack/JobWizard/steps/CategoryAndTemplate/index.js +3 -3
  38. data/webpack/JobWizard/steps/ReviewDetails/index.js +2 -3
  39. data/webpack/JobWizard/steps/Schedule/PurposeField.js +1 -3
  40. data/webpack/JobWizard/steps/Schedule/QueryType.js +33 -40
  41. data/webpack/JobWizard/steps/Schedule/RepeatHour.js +55 -16
  42. data/webpack/JobWizard/steps/Schedule/RepeatOn.js +19 -56
  43. data/webpack/JobWizard/steps/Schedule/RepeatWeek.js +1 -1
  44. data/webpack/JobWizard/steps/Schedule/ScheduleFuture.js +126 -0
  45. data/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js +287 -0
  46. data/webpack/JobWizard/steps/Schedule/ScheduleType.js +88 -20
  47. data/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js +206 -186
  48. data/webpack/JobWizard/steps/form/DateTimePicker.js +23 -6
  49. data/webpack/JobWizard/steps/form/Formatter.js +7 -8
  50. data/webpack/JobWizard/submit.js +10 -3
  51. data/webpack/Routes/routes.js +8 -2
  52. data/webpack/__mocks__/foremanReact/common/hooks/API/APIHooks.js +1 -0
  53. data/webpack/react_app/components/FeaturesDropdown/index.js +1 -1
  54. data/webpack/react_app/components/RegistrationExtension/RexPull.js +73 -0
  55. data/webpack/react_app/extend/Fills.js +8 -1
  56. metadata +11 -6
  57. data/webpack/JobWizard/steps/Schedule/StartEndDates.js +0 -106
  58. data/webpack/JobWizard/steps/Schedule/__tests__/StartEndDates.test.js +0 -32
  59. data/webpack/JobWizard/steps/Schedule/index.js +0 -178
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e9183b3b81c3033d696f4aedf861cb5eed143fb9eacccb144a23d859e3ccae69
4
- data.tar.gz: 4c7c6c09c84f3d4cbef2aaa8330b7bf048d42570e9319ad227c30abc5613770c
3
+ metadata.gz: aa3c6d67549990da3bbd1d7cbf55408bd4a1dc4d7fc5cbcec8db99eded747964
4
+ data.tar.gz: ca4e519773be6b0493341fd25ba55e8d4345367c88e0b068183ebe66d020e22e
5
5
  SHA512:
6
- metadata.gz: b35e41908b57f97f80272070d84b8d2ceeb7e061e22ad673d07c694a643d057399e207af9c8f36d14d535a7ddb3eddefa013e04b3d63689796e66e6d9aeae88b
7
- data.tar.gz: 5c0b0d79edaab4c28721ad26df27ad8ac14878e09349929d28175c2cc1714ebb1f81ceb9f4824215d781dc1b4b0662962a9043f4f56963fea4d0aaa3e2483f8d
6
+ metadata.gz: bbeb56766cc65ed9fcd587f260fb29fca965b961b0787230f0510166702351cb5ff0c78387b3f818b9741f281519f33931bc8d0aa36a923d92e0d50f620d113e
7
+ data.tar.gz: 3238dc8bc7cdbaa361a6c077e5d611839cb549424ad98daea9e68ac81a932dd6c8de2f233b31f019cc7a1d037b6fea4a656ca3d7e789eb9a794170fb26ac1f68
@@ -16,8 +16,10 @@ jobs:
16
16
  - name: Setup Ruby
17
17
  uses: ruby/setup-ruby@v1
18
18
  with:
19
- ruby-version: 2.5
19
+ ruby-version: 2.7
20
20
  bundler-cache: true
21
+ cache-version: 1
22
+ rubygems: 3.0.0
21
23
  - name: Run rubocop
22
24
  if: github.event_name != 'push'
23
25
  run: bundle exec rubocop --format github
@@ -36,7 +38,7 @@ jobs:
36
38
  fail-fast: false
37
39
  matrix:
38
40
  foreman-core-branch: [develop]
39
- ruby-version: [2.5, 2.7]
41
+ ruby-version: [2.7]
40
42
  node-version: [12]
41
43
  steps:
42
44
  - run: sudo apt-get update
@@ -9,6 +9,7 @@ module ForemanRemoteExecution
9
9
  update_api(:create) do
10
10
  param :registration_command, Hash do
11
11
  param :remote_execution_interface, String, desc: N_("Identifier of the Host interface for Remote execution")
12
+ param :setup_remote_execution_pull, :bool, desc: N_("Set 'host_registration_remote_execution_pull' parameter for the host. If it is set to true, pull provider client will be deployed on the host")
12
13
  end
13
14
  end
14
15
  end
@@ -6,6 +6,7 @@ module ForemanRemoteExecution
6
6
 
7
7
  update_api(:global, :host) do
8
8
  param :remote_execution_interface, String, desc: N_("Identifier of the Host interface for Remote execution")
9
+ param :setup_remote_execution_pull, :bool, desc: N_("Set 'host_registration_remote_execution_pull' parameter for the host. If it is set to true, pull provider client will be deployed on the host")
9
10
  end
10
11
  end
11
12
 
@@ -13,10 +14,17 @@ module ForemanRemoteExecution
13
14
 
14
15
  def host_setup_extension
15
16
  remote_execution_interface
17
+ remote_execution_pull
16
18
  reset_host_known_keys! unless @host.new_record?
17
19
  super
18
20
  end
19
21
 
22
+ def remote_execution_pull
23
+ HostParameter.where(host: @host, name: 'host_registration_remote_execution_pull').destroy_all
24
+
25
+ setup_host_param('host_registration_remote_execution_pull', ActiveRecord::Type::Boolean.new.deserialize(params['setup_remote_execution_pull']))
26
+ end
27
+
20
28
  def remote_execution_interface
21
29
  return unless params['remote_execution_interface'].present?
22
30
 
@@ -57,4 +57,19 @@ class UiJobWizardController < ApplicationController
57
57
  render :json => { :results =>
58
58
  resource_list.sort_by { |r| r[:name] }.take(100), :subtotal => resource_list.count}
59
59
  end
60
+
61
+ def job_invocation
62
+ job = JobInvocation.authorized.find(params[:id])
63
+ composer = JobInvocationComposer.from_job_invocation(job, params).params
64
+ job_template_inputs = JobTemplate.authorized.find(composer[:template_invocations][0][:template_id]).template_inputs_with_foreign
65
+ inputs = Hash[job_template_inputs.map { |input| ["inputs[#{input[:name]}]", (composer[:template_invocations][0][:input_values].find { |value| value[:template_input_id] == input[:id] })[:value]] }]
66
+ job_organization = Taxonomy.find_by(id: job.task.input[:current_organization_id])
67
+ job_location = Taxonomy.find_by(id: job.task.input[:current_location_id])
68
+ render :json => {
69
+ :job => composer,
70
+ :job_organization => job_organization,
71
+ :job_location => job_location,
72
+ :inputs => inputs,
73
+ }
74
+ end
60
75
  end
@@ -246,7 +246,7 @@ module RemoteExecutionHelper
246
246
  def job_report_template
247
247
  template = ReportTemplate.where(name: Setting['remote_execution_job_invocation_report_template']).first
248
248
 
249
- template if template.template_inputs.where(name: 'job_id').exists?
249
+ template if template && template.template_inputs.where(name: 'job_id').exists?
250
250
  end
251
251
 
252
252
  def job_report_template_parameters(job_invocation, template)
@@ -4,6 +4,12 @@ module ForemanRemoteExecution
4
4
 
5
5
  included do
6
6
  has_many :job_invocations, :dependent => :destroy, :foreign_key => 'task_id'
7
+ has_one :template_invocation, :inverse_of => :run_host_job_task, :foreign_key => 'run_host_job_task_id', :dependent => :nullify
8
+ has_one :template, :through => :template_invocation
9
+ has_many :remote_execution_features, :through => :template
10
+
11
+ scoped_search :relation => :remote_execution_features, :on => :name, :rename => 'remote_execution_feature.name'
12
+ scoped_search :relation => :remote_execution_features, :on => :label, :rename => 'remote_execution_feature.label'
7
13
  end
8
14
  end
9
15
  end
@@ -50,7 +50,8 @@ class HostStatus::ExecutionStatus < HostStatus::Status
50
50
  end
51
51
 
52
52
  def status_link
53
- job_invocation = last_stopped_task.parent_task.job_invocations.first
53
+ job_invocation = last_stopped_task&.parent_task&.job_invocations&.first
54
+ return unless job_invocation
54
55
  return nil unless User.current.can?(:view_job_invocations, job_invocation)
55
56
 
56
57
  Rails.application.routes.url_helpers.job_invocation_path(job_invocation)
@@ -25,7 +25,7 @@ class JobInvocation < ApplicationRecord
25
25
  validates :job_category, :presence => true
26
26
  validates_associated :targeting, :all_template_invocations
27
27
 
28
- scoped_search :on => :id, :complete_value => true
28
+ scoped_search :on => :id, :complete_value => true, :validator => ScopedSearch::Validators::INTEGER
29
29
  scoped_search :on => :job_category, :complete_value => true
30
30
  scoped_search :on => :description, :complete_value => true
31
31
 
@@ -219,7 +219,7 @@ class JobInvocationComposer
219
219
  def format_datetime(datetime)
220
220
  return datetime if datetime.blank?
221
221
 
222
- Time.parse(datetime).in_time_zone.strftime('%Y-%m-%d %H:%M')
222
+ Time.zone.parse(datetime).strftime('%Y-%m-%d %H:%M')
223
223
  end
224
224
  end
225
225
 
@@ -441,8 +441,11 @@ class JobInvocationComposer
441
441
  end
442
442
 
443
443
  def valid?
444
- targeting.valid? & job_invocation.valid? & !pattern_template_invocations.map(&:valid?).include?(false) &
445
- triggering.valid?
444
+ unless triggering.valid?
445
+ job_invocation.errors.add(:triggering, 'is invalid')
446
+ return false
447
+ end
448
+ targeting.valid? & job_invocation.valid? & !pattern_template_invocations.map(&:valid?).include?(false)
446
449
  end
447
450
 
448
451
  def save
@@ -32,6 +32,8 @@ class JobTemplate < ::Template
32
32
  scoped_search :on => :snippet, :complete_value => {:true => true, :false => false}
33
33
  scoped_search :on => :provider_type, :complete_value => true
34
34
  scoped_search :on => :template
35
+ scoped_search :relation => :remote_execution_features, :on => :name, :rename => 'feature.name'
36
+ scoped_search :relation => :remote_execution_features, :on => :label, :rename => 'feature.label'
35
37
 
36
38
  # with proc support, default_scope can no longer be chained
37
39
  # include all default scoping here
@@ -28,6 +28,10 @@ class RemoteExecutionProvider
28
28
  providers.keys.map(&:to_s)
29
29
  end
30
30
 
31
+ def provider_proxy_features
32
+ providers.values.map(&:proxy_feature).flatten.uniq.compact
33
+ end
34
+
31
35
  def proxy_command_options(template_invocation, host)
32
36
  {:proxy_operation_name => proxy_operation_name}.merge(proxy_command_provider_inputs(template_invocation))
33
37
  end
@@ -16,6 +16,7 @@ class TemplateInvocation < ApplicationRecord
16
16
  belongs_to :host, :class_name => 'Host::Managed', :foreign_key => :host_id
17
17
  has_one :host_group, :through => :host, :source => :hostgroup
18
18
  belongs_to :run_host_job_task, :class_name => 'ForemanTasks::Task'
19
+ has_many :remote_execution_features, :through => :template
19
20
 
20
21
  validates_associated :input_values
21
22
  validate :provides_required_input_values
@@ -25,6 +26,7 @@ class TemplateInvocation < ApplicationRecord
25
26
  scoped_search :relation => :host_group, :on => :name, :rename => 'host_group.name', :complete_value => true
26
27
  scoped_search :relation => :template, :on => :job_category, :complete_value => true
27
28
  scoped_search :relation => :template, :on => :name, :complete_value => true
29
+ scoped_search :relation => :remote_execution_features, :on => :name, :rename => 'feature'
28
30
 
29
31
  class TaskResultMap
30
32
  MAP = {
@@ -7,7 +7,7 @@ class RemoteExecutionProxySelector < ::ForemanTasks::ProxySelector
7
7
  return proxies if capability.nil?
8
8
 
9
9
  proxies.reduce({}) do |acc, (strategy, possible_proxies)|
10
- acc.merge(strategy => possible_proxies.select { |proxy| proxy.has_capability?(capability) })
10
+ acc.merge(strategy => possible_proxies.select { |proxy| proxy.has_capability?(provider, capability) })
11
11
  end
12
12
  end
13
13
  end
@@ -1,5 +1,5 @@
1
1
  <div class="tab-pane" id="rex_proxies">
2
2
  <%= fields_for :subnet do |f| %>
3
- <%= multiple_selects f, :remote_execution_proxies, SmartProxy.authorized.with_features(*RemoteExecutionProvider.provider_names).distinct, @subnet.remote_execution_proxy_ids, {:label => _("Proxies"), :help_inline => _("Select as many remote execution proxies as applicable for this subnet. When multiple proxies with the same provider are added, actions will be load balanced among them.")} %>
3
+ <%= multiple_selects f, :remote_execution_proxies, SmartProxy.authorized.with_features(*RemoteExecutionProvider.provider_proxy_features).distinct, @subnet.remote_execution_proxy_ids, {:label => _("Proxies"), :help_inline => _("Select as many remote execution proxies as applicable for this subnet. When multiple proxies with the same provider are added, actions will be load balanced among them.")} %>
4
4
  <% end %>
5
5
  </div>
@@ -16,6 +16,11 @@ template_inputs:
16
16
  input_type: user
17
17
  required: true
18
18
  options: "install\nupdate\nremove\ngroup install\ngroup remove"
19
+ - name: options
20
+ description: Additional options for the package manager
21
+ input_type: user
22
+ required: false
23
+ advanced: true
19
24
  - name: package
20
25
  description: The name of the package, if any
21
26
  input_type: user
@@ -87,7 +92,7 @@ handle_zypp_res_codes () {
87
92
 
88
93
  # Action
89
94
  <% if package_manager == 'yum' -%>
90
- yum -y <%= action %> <%= input("package") %>
95
+ yum -y <%= input("options") %> <%= action %> <%= input("package") %>
91
96
  <% elsif package_manager == 'apt' -%>
92
97
  <%-
93
98
  action = 'install' if action == 'group install'
@@ -103,7 +108,7 @@ handle_zypp_res_codes () {
103
108
  [ -x "$(command -v subscription-manager)" ] && subscription-manager refresh
104
109
  export DEBIAN_FRONTEND=noninteractive
105
110
  apt-get -y update
106
- apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -y <%= action %> <%= input("package") %>
111
+ apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -y <%= input("options") %> <%= action %> <%= input("package") %>
107
112
  <% elsif package_manager == 'zypper' -%>
108
113
  <%-
109
114
  if action == "group install"
@@ -113,7 +118,7 @@ handle_zypp_res_codes () {
113
118
  end
114
119
  -%>
115
120
  zypper refresh
116
- zypper -n <%= action %> <%= input("package") %>
121
+ zypper -n <%= action %> <%= input("options") %> <%= input("package") %>
117
122
  handle_zypp_res_codes $?
118
123
  <% end -%>
119
124
  RETVAL=$?
data/config/routes.rb CHANGED
@@ -46,8 +46,10 @@ Rails.application.routes.draw do
46
46
  get 'ui_job_wizard/categories', to: 'ui_job_wizard#categories'
47
47
  get 'ui_job_wizard/template/:id', to: 'ui_job_wizard#template'
48
48
  get 'ui_job_wizard/resources', to: 'ui_job_wizard#resources'
49
+ get 'ui_job_wizard/job_invocation', to: 'ui_job_wizard#job_invocation'
49
50
 
50
- match '/experimental/job_wizard', to: 'react#index', :via => [:get]
51
+ match '/experimental/job_wizard/new', to: 'react#index', :via => [:get]
52
+ match '/experimental/job_wizard/:id/rerun', to: 'react#index', :via => [:get]
51
53
 
52
54
  namespace :api, :defaults => {:format => 'json'} do
53
55
  scope '(:apiv)', :module => :v2, :defaults => {:apiv => 'v2'}, :apiv => /v1|v2/, :constraints => ApiConstraints.new(:version => 2, :default => true) do
@@ -47,7 +47,7 @@ module ForemanRemoteExecution
47
47
 
48
48
  initializer 'foreman_remote_execution.register_plugin', before: :finisher_hook do |_app|
49
49
  Foreman::Plugin.register :foreman_remote_execution do
50
- requires_foreman '>= 3.3'
50
+ requires_foreman '>= 3.4'
51
51
  register_global_js_file 'global'
52
52
 
53
53
  apipie_documented_controllers ["#{ForemanRemoteExecution::Engine.root}/app/controllers/api/v2/*.rb"]
@@ -152,7 +152,7 @@ module ForemanRemoteExecution
152
152
  setting 'remote_execution_job_invocation_report_template',
153
153
  type: :string,
154
154
  description: N_('Select a report template used for generating a report for a particular remote execution job'),
155
- default: 'Job invocation - report template',
155
+ default: 'Job - Invocation Report',
156
156
  full_name: N_('Job Invocation Report Template'),
157
157
  collection: proc { ForemanRemoteExecution.job_invocation_report_templates_select }
158
158
  end
@@ -164,7 +164,7 @@ module ForemanRemoteExecution
164
164
  :'api/v2/job_templates' => [:index, :show, :revision, :export],
165
165
  :'api/v2/template_inputs' => [:index, :show],
166
166
  :'api/v2/foreign_input_sets' => [:index, :show],
167
- :ui_job_wizard => [:categories, :template, :resources]}, :resource_type => 'JobTemplate'
167
+ :ui_job_wizard => [:categories, :template, :resources, :job_invocation]}, :resource_type => 'JobTemplate'
168
168
  permission :create_job_templates, { :job_templates => [:new, :create, :clone_template, :import],
169
169
  :'api/v2/job_templates' => [:create, :clone, :import] }, :resource_type => 'JobTemplate'
170
170
  permission :edit_job_templates, { :job_templates => [:edit, :update],
@@ -181,7 +181,7 @@ module ForemanRemoteExecution
181
181
  permission :view_job_invocations, { :job_invocations => [:index, :chart, :show, :auto_complete_search], :template_invocations => [:show],
182
182
  'api/v2/job_invocations' => [:index, :show, :output, :raw_output, :outputs] }, :resource_type => 'JobInvocation'
183
183
  permission :view_template_invocations, { :template_invocations => [:show],
184
- 'api/v2/template_invocations' => [:template_invocations] }, :resource_type => 'TemplateInvocation'
184
+ 'api/v2/template_invocations' => [:template_invocations], :ui_job_wizard => [:job_invocation] }, :resource_type => 'TemplateInvocation'
185
185
  permission :create_template_invocations, {}, :resource_type => 'TemplateInvocation'
186
186
  permission :execute_jobs_on_infrastructure_hosts, {}, :resource_type => 'JobInvocation'
187
187
  permission :cancel_job_invocations, { :job_invocations => [:cancel], 'api/v2/job_invocations' => [:cancel] }, :resource_type => 'JobInvocation'
@@ -242,7 +242,7 @@ module ForemanRemoteExecution
242
242
  url_hash: { controller: 'job_wizard', action: :index },
243
243
  caption: N_('Job wizard'),
244
244
  parent: :lab_features_menu,
245
- url: '/experimental/job_wizard',
245
+ url: '/experimental/job_wizard/new',
246
246
  after: :host_wizard
247
247
 
248
248
  register_custom_status HostStatus::ExecutionStatus
@@ -275,6 +275,7 @@ module ForemanRemoteExecution
275
275
 
276
276
  # Extend Registration module
277
277
  extend_allowed_registration_vars :remote_execution_interface
278
+ extend_allowed_registration_vars :setup_remote_execution_pull
278
279
  ForemanTasks.dynflow.eager_load_actions!
279
280
  extend_observable_events(
280
281
  ::Dynflow::Action.descendants.select do |klass|
@@ -1,3 +1,3 @@
1
1
  module ForemanRemoteExecution
2
- VERSION = '7.0.0'.freeze
2
+ VERSION = '8.0.0'.freeze
3
3
  end
@@ -82,6 +82,14 @@ module Api
82
82
  assert_response :success
83
83
  end
84
84
 
85
+ test 'should propagate errors from triggering' do
86
+ @attrs[:recurrence] = { cron_line: 'foo' }
87
+ post :create, params: { job_invocation: @attrs }
88
+ invocation = ActiveSupport::JSON.decode(@response.body)
89
+ assert_match(/foo is not valid format of cron line/, invocation['error']['message'])
90
+ assert_response 500
91
+ end
92
+
85
93
  test 'should create with schedule' do
86
94
  @attrs[:scheduling] = { start_at: Time.now.to_s }
87
95
  post :create, params: { job_invocation: @attrs }
@@ -37,5 +37,9 @@ class RemoteExecutionHelperTest < ActionView::TestCase
37
37
 
38
38
  assert_equal template.id, found_template.id
39
39
  end
40
+
41
+ it 'should not crash if the template cannot be found' do
42
+ assert_nil job_report_template
43
+ end
40
44
  end
41
45
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ class ApiParamsTest < ActiveSupport::TestCase
6
+ describe '#format_datetime' do
7
+ let(:params) { JobInvocationComposer::ApiParams.allocate }
8
+
9
+ it 'leaves empty string as is' do
10
+ assert_equal params.send(:format_datetime, ''), ''
11
+ end
12
+
13
+ it 'honors explicitly supplied time zone' do
14
+ in_time_zone(ActiveSupport::TimeZone['America/New_York']) do
15
+ assert_equal '2022-07-08 08:53', params.send(:format_datetime, '2022-07-08 12:53:20 UTC')
16
+ end
17
+ end
18
+
19
+ it 'implicitly honors current user\'s time zone' do
20
+ in_time_zone(ActiveSupport::TimeZone['America/New_York']) do
21
+ assert_equal '2022-07-08 12:53', params.send(:format_datetime, '2022-07-08 12:53:20')
22
+ end
23
+ end
24
+ end
25
+
26
+ def in_time_zone(zone)
27
+ old_tz = Time.zone
28
+ Time.zone = zone
29
+ yield
30
+ ensure
31
+ Time.zone = old_tz
32
+ end
33
+ end
@@ -9,7 +9,7 @@ class JobReportTemplateTest < ActiveSupport::TestCase
9
9
 
10
10
  context 'with valid job invocation report template' do
11
11
  let(:job_invocation_template) do
12
- file_path = File.read(File.expand_path(Rails.root + "app/views/unattended/report_templates/job_invocation_-_report_template.erb"))
12
+ file_path = File.read(File.expand_path(Rails.root + "app/views/unattended/report_templates/job_-_invocation_report.erb"))
13
13
  template = ReportTemplate.import_without_save("Job Invocation Report Template", file_path)
14
14
  template.save!
15
15
  template
@@ -95,9 +95,8 @@ class JobInvocationTest < ActiveSupport::TestCase
95
95
  end
96
96
 
97
97
  it 'truncates generated description to 255 characters' do
98
- column_limit = 255
98
+ column_limit = 255 # There is a 255 character limit on the database level
99
99
  expected_result = 'a' * column_limit
100
- JobInvocation.columns_hash['description'].expects(:limit).returns(column_limit)
101
100
  job_invocation.description_format = '%{job_category}'
102
101
  job_invocation.job_category = 'a' * 1000
103
102
  job_invocation.generate_description
@@ -33,6 +33,10 @@ class RemoteExecutionProviderTest < ActiveSupport::TestCase
33
33
  it 'accepts strings' do
34
34
  RemoteExecutionProvider.provider_for('SSH').must_equal SSHExecutionProvider
35
35
  end
36
+
37
+ it 'returns a default one if unknown value is provided' do
38
+ RemoteExecutionProvider.provider_for('WinRM').must_equal ScriptExecutionProvider
39
+ end
36
40
  end
37
41
 
38
42
  describe '.provider_names' do
@@ -52,6 +56,28 @@ class RemoteExecutionProviderTest < ActiveSupport::TestCase
52
56
  end
53
57
  end
54
58
 
59
+ describe '.provider_proxy_features' do
60
+ it 'returns correct values' do
61
+ RemoteExecutionProvider.stubs(:providers).returns(
62
+ :SSH => SSHExecutionProvider,
63
+ :script => ScriptExecutionProvider
64
+ )
65
+
66
+ features = RemoteExecutionProvider.provider_proxy_features
67
+ _(features).must_include 'SSH'
68
+ _(features).must_include 'Script'
69
+ RemoteExecutionProvider.unstub(:providers)
70
+ end
71
+
72
+ it 'can deal with non-arrays' do
73
+ provider = OpenStruct.new(proxy_feature: 'Testing')
74
+ RemoteExecutionProvider.stubs(:providers).returns(:testing => provider)
75
+ features = RemoteExecutionProvider.provider_proxy_features
76
+ _(features).must_include 'Testing'
77
+ RemoteExecutionProvider.unstub(:providers)
78
+ end
79
+ end
80
+
55
81
  describe '.host_setting' do
56
82
  let(:host) { FactoryBot.create(:host) }
57
83