foreman_remote_execution 4.3.1 → 4.5.2

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/job_invocations_controller.rb +27 -22
  3. data/app/controllers/foreman_remote_execution/concerns/api/v2/registration_commands_controller_extensions.rb +19 -0
  4. data/app/controllers/job_invocations_controller.rb +1 -1
  5. data/app/controllers/job_templates_controller.rb +4 -4
  6. data/app/controllers/ui_job_wizard_controller.rb +19 -0
  7. data/app/helpers/job_invocations_helper.rb +2 -2
  8. data/app/helpers/remote_execution_helper.rb +40 -9
  9. data/app/lib/actions/remote_execution/run_host_job.rb +36 -6
  10. data/app/lib/foreman_remote_execution/provider_input.rb +29 -0
  11. data/app/models/concerns/foreman_remote_execution/host_extensions.rb +7 -5
  12. data/app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb +6 -0
  13. data/app/models/host_proxy_invocation.rb +4 -0
  14. data/app/models/host_status/execution_status.rb +5 -5
  15. data/app/models/invocation_provider_input_value.rb +12 -0
  16. data/app/models/job_invocation.rb +35 -12
  17. data/app/models/job_invocation_composer.rb +74 -19
  18. data/app/models/remote_execution_provider.rb +18 -3
  19. data/app/models/setting/remote_execution.rb +11 -1
  20. data/app/models/ssh_execution_provider.rb +4 -4
  21. data/app/models/targeting.rb +5 -1
  22. data/app/models/template_invocation.rb +2 -0
  23. data/app/overrides/execution_interface.rb +8 -8
  24. data/app/overrides/subnet_proxies.rb +6 -6
  25. data/app/services/renderer_methods.rb +12 -0
  26. data/app/views/job_invocations/_form.html.erb +8 -0
  27. data/app/views/job_invocations/index.html.erb +1 -1
  28. data/app/views/templates/ssh/module_action.erb +1 -0
  29. data/app/views/templates/ssh/puppet_run_once.erb +1 -0
  30. data/config/routes.rb +1 -0
  31. data/db/migrate/20180110104432_rename_template_invocation_permission.rb +1 -1
  32. data/db/migrate/20190111153330_remove_remote_execution_without_proxy_setting.rb +4 -4
  33. data/db/migrate/20210312074713_add_provider_inputs.rb +10 -0
  34. data/db/migrate/2021051713291621250977_add_host_proxy_invocations.rb +12 -0
  35. data/extra/cockpit/foreman-cockpit-session +6 -6
  36. data/foreman_remote_execution.gemspec +1 -1
  37. data/lib/foreman_remote_execution/engine.rb +14 -12
  38. data/lib/foreman_remote_execution/version.rb +1 -1
  39. data/locale/action_names.rb +1 -0
  40. data/locale/de/foreman_remote_execution.po +77 -27
  41. data/locale/en/foreman_remote_execution.po +77 -27
  42. data/locale/en_GB/foreman_remote_execution.po +77 -27
  43. data/locale/es/foreman_remote_execution.po +77 -27
  44. data/locale/foreman_remote_execution.pot +241 -163
  45. data/locale/fr/foreman_remote_execution.po +77 -27
  46. data/locale/ja/foreman_remote_execution.po +77 -27
  47. data/locale/ko/foreman_remote_execution.po +77 -27
  48. data/locale/pt_BR/foreman_remote_execution.po +77 -27
  49. data/locale/ru/foreman_remote_execution.po +77 -27
  50. data/locale/zh_CN/foreman_remote_execution.po +77 -27
  51. data/locale/zh_TW/foreman_remote_execution.po +77 -27
  52. data/package.json +4 -2
  53. data/test/functional/api/v2/job_invocations_controller_test.rb +14 -1
  54. data/test/helpers/remote_execution_helper_test.rb +16 -0
  55. data/test/unit/job_invocation_composer_test.rb +100 -3
  56. data/test/unit/job_invocation_report_template_test.rb +57 -0
  57. data/test/unit/job_invocation_test.rb +1 -1
  58. data/webpack/JobWizard/JobWizard.js +95 -11
  59. data/webpack/JobWizard/JobWizard.scss +53 -0
  60. data/webpack/JobWizard/JobWizardConstants.js +16 -0
  61. data/webpack/JobWizard/JobWizardSelectors.js +47 -0
  62. data/webpack/JobWizard/__tests__/__snapshots__/integration.test.js.snap +43 -0
  63. data/webpack/JobWizard/__tests__/fixtures.js +128 -0
  64. data/webpack/JobWizard/__tests__/integration.test.js +84 -0
  65. data/webpack/JobWizard/steps/AdvancedFields/AdvancedFields.js +110 -0
  66. data/webpack/JobWizard/steps/AdvancedFields/DescriptionField.js +67 -0
  67. data/webpack/JobWizard/steps/AdvancedFields/Fields.js +195 -0
  68. data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +144 -0
  69. data/webpack/JobWizard/steps/AdvancedFields/__tests__/DescriptionField.test.js +23 -0
  70. data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.js +109 -0
  71. data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +123 -0
  72. data/webpack/JobWizard/steps/CategoryAndTemplate/index.js +94 -0
  73. data/webpack/JobWizard/steps/Schedule/QueryType.js +48 -0
  74. data/webpack/JobWizard/steps/Schedule/RepeatOn.js +61 -0
  75. data/webpack/JobWizard/steps/Schedule/ScheduleType.js +25 -0
  76. data/webpack/JobWizard/steps/Schedule/StartEndDates.js +51 -0
  77. data/webpack/JobWizard/steps/Schedule/__tests__/StartEndDates.test.js +22 -0
  78. data/webpack/JobWizard/steps/Schedule/index.js +41 -0
  79. data/webpack/JobWizard/steps/form/FormHelpers.js +20 -0
  80. data/webpack/JobWizard/steps/form/Formatter.js +149 -0
  81. data/webpack/JobWizard/steps/form/GroupedSelectField.js +91 -0
  82. data/webpack/JobWizard/steps/form/NumberInput.js +33 -0
  83. data/webpack/JobWizard/steps/form/SelectField.js +60 -0
  84. data/webpack/JobWizard/steps/form/__tests__/Formatter.test.js.example +76 -0
  85. data/webpack/__mocks__/foremanReact/common/helpers.js +1 -0
  86. data/webpack/__mocks__/foremanReact/components/SearchBar.js +18 -1
  87. data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +21 -2
  88. data/webpack/__mocks__/foremanReact/redux/API/index.js +5 -0
  89. data/webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js +10 -0
  90. data/webpack/global_index.js +6 -0
  91. data/webpack/index.js +3 -4
  92. data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +83 -0
  93. data/webpack/react_app/components/RecentJobsCard/constants.js +1 -0
  94. data/webpack/react_app/components/RecentJobsCard/index.js +1 -0
  95. data/webpack/react_app/components/RecentJobsCard/styles.css +15 -0
  96. data/webpack/react_app/components/RegistrationExtension/RexInterface.js +50 -0
  97. data/webpack/react_app/components/RegistrationExtension/__tests__/RexInterface.test.js +9 -0
  98. data/webpack/react_app/components/RegistrationExtension/__tests__/__snapshots__/RexInterface.test.js.snap +35 -0
  99. data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsSelectors.test.js +8 -3
  100. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +1 -0
  101. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsSelectors.test.js.snap +7 -2
  102. data/webpack/react_app/extend/fillRecentJobsCard.js +11 -0
  103. data/webpack/react_app/extend/fillregistrationAdvanced.js +11 -0
  104. data/webpack/react_app/extend/reducers.js +5 -0
  105. metadata +52 -8
  106. data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +0 -70
  107. data/app/views/api/v2/registration/_form.html.erb +0 -12
  108. data/test/models/orchestration/ssh_test.rb +0 -56
@@ -0,0 +1,57 @@
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/jobs_-_invocation_report_template.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 = Setting::RemoteExecution.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", 'timestamp' => Time.new(2020, 12, 1, 0, 0, 0).utc },
32
+ { 'output_type' => 'stdout', 'output' => "output", 'timestamp' => Time.new(2020, 12, 1, 0, 0, 0).utc },
33
+ { 'output_type' => 'stdebug', 'output' => "debug", 'timestamp' => Time.new(2020, 12, 1, 0, 0, 0).utc },
34
+ ]
35
+ end
36
+ let(:fake_task) { FakeTask.new(result: 'success', action_continuous_output: fake_outputs) }
37
+
38
+ it 'should render task outputs' do
39
+ job_invocation = FactoryBot.create(:job_invocation, :with_task)
40
+ JobInvocation.any_instance.expects(:sub_task_for_host).returns(fake_task)
41
+
42
+ input = job_invocation_template.template_inputs.first
43
+ composer_params = { template_id: job_invocation_template.id, input_values: { input.id.to_s => { value: job_invocation.id.to_s } } }
44
+ result = ReportComposer.new(composer_params).render
45
+
46
+ # parsing the CSV result
47
+ CSV.parse(result.strip, headers: true).each_with_index do |row, i|
48
+ row_hash = row.to_h
49
+ assert_equal 'success', row_hash['result']
50
+ assert_equal fake_outputs[i]['output_type'], row_hash['type']
51
+ assert_equal fake_outputs[i]['output'], row_hash['message']
52
+ assert_kind_of Time, Time.zone.parse(row_hash['time']), 'Parsing of time column failed'
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -10,7 +10,7 @@ class JobInvocationTest < ActiveSupport::TestCase
10
10
  end
11
11
 
12
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).with_task.order('job_invocations.id DESC')
13
+ found_jobs = JobInvocation.search_for(%{job_category = "#{job_invocation.job_category}"}).paginate(:page => 1).order('job_invocations.id DESC')
14
14
  _(found_jobs).must_equal [job_invocation]
15
15
  end
16
16
 
@@ -1,30 +1,114 @@
1
- import React from 'react';
1
+ /* eslint-disable camelcase */
2
+ import React, { useState, useEffect, useCallback } from 'react';
3
+ import { useDispatch, useSelector } from 'react-redux';
2
4
  import { Wizard } from '@patternfly/react-core';
5
+ import { get } from 'foremanReact/redux/API';
3
6
  import { translate as __ } from 'foremanReact/common/I18n';
4
7
  import history from 'foremanReact/history';
8
+ import CategoryAndTemplate from './steps/CategoryAndTemplate/';
9
+ import { AdvancedFields } from './steps/AdvancedFields/AdvancedFields';
10
+ import { JOB_TEMPLATE } from './JobWizardConstants';
11
+ import { selectTemplateError } from './JobWizardSelectors';
12
+ import Schedule from './steps/Schedule/';
13
+ import './JobWizard.scss';
5
14
 
6
15
  export const JobWizard = () => {
16
+ const [jobTemplateID, setJobTemplateID] = useState(null);
17
+ const [category, setCategory] = useState('');
18
+ const [advancedValues, setAdvancedValues] = useState({});
19
+ const dispatch = useDispatch();
20
+
21
+ const setDefaults = useCallback(
22
+ ({
23
+ data: {
24
+ advanced_template_inputs,
25
+ effective_user,
26
+ job_template: { executionTimeoutInterval, description_format },
27
+ },
28
+ }) => {
29
+ const advancedTemplateValues = {};
30
+ const advancedInputs = advanced_template_inputs;
31
+ if (advancedInputs) {
32
+ advancedInputs.forEach(input => {
33
+ advancedTemplateValues[input.name] = input?.default || '';
34
+ });
35
+ }
36
+ setAdvancedValues(currentAdvancedValues => ({
37
+ ...currentAdvancedValues,
38
+ effectiveUserValue: effective_user?.value || '',
39
+ timeoutToKill: executionTimeoutInterval || '',
40
+ templateValues: advancedTemplateValues,
41
+ description: description_format || '',
42
+ }));
43
+ },
44
+ []
45
+ );
46
+ useEffect(() => {
47
+ if (jobTemplateID) {
48
+ dispatch(
49
+ get({
50
+ key: JOB_TEMPLATE,
51
+ url: `/ui_job_wizard/template/${jobTemplateID}`,
52
+ handleSuccess: setDefaults,
53
+ })
54
+ );
55
+ }
56
+ }, [jobTemplateID, setDefaults, dispatch]);
57
+
58
+ const templateError = !!useSelector(selectTemplateError);
59
+ const isTemplate = !templateError && !!jobTemplateID;
7
60
  const steps = [
8
61
  {
9
- name: __('Category and template'),
10
- component: <p>Category and template</p>,
62
+ name: __('Category and Template'),
63
+ component: (
64
+ <CategoryAndTemplate
65
+ jobTemplate={jobTemplateID}
66
+ setJobTemplate={setJobTemplateID}
67
+ category={category}
68
+ setCategory={setCategory}
69
+ />
70
+ ),
71
+ },
72
+ {
73
+ name: __('Target Hosts'),
74
+ component: <p>Target Hosts</p>,
75
+ canJumpTo: isTemplate,
76
+ },
77
+ {
78
+ name: __('Advanced Fields'),
79
+ component: (
80
+ <AdvancedFields
81
+ advancedValues={advancedValues}
82
+ setAdvancedValues={newValues => {
83
+ setAdvancedValues(currentAdvancedValues => ({
84
+ ...currentAdvancedValues,
85
+ ...newValues,
86
+ }));
87
+ }}
88
+ jobTemplateID={jobTemplateID}
89
+ />
90
+ ),
91
+ canJumpTo: isTemplate,
92
+ },
93
+ {
94
+ name: __('Schedule'),
95
+ component: <Schedule />,
96
+ canJumpTo: isTemplate,
11
97
  },
12
- { name: __('Target hosts'), component: <p>TargetHosts </p> },
13
- { name: __('Advanced fields'), component: <p> AdvancedFields </p> },
14
- { name: __('Schedule'), component: <p>Schedule</p> },
15
98
  {
16
- name: __('Review details'),
17
- component: <p>ReviewDetails</p>,
99
+ name: __('Review Details'),
100
+ component: <p>Review Details</p>,
18
101
  nextButtonText: 'Run',
102
+ canJumpTo: isTemplate,
19
103
  },
20
104
  ];
21
- const title = __('Run Job');
22
105
  return (
23
106
  <Wizard
24
107
  onClose={() => history.goBack()}
25
- navAriaLabel={`${title} steps`}
108
+ navAriaLabel="Run Job steps"
26
109
  steps={steps}
27
- height="70vh"
110
+ height="100%"
111
+ className="job-wizard"
28
112
  />
29
113
  );
30
114
  };
@@ -0,0 +1,53 @@
1
+ .job-wizard {
2
+ .pf-c-wizard__main {
3
+ z-index: calc(
4
+ var(--pf-c-wizard__footer--ZIndex) + 1
5
+ ); // So the select box can be shown above the wizard footer
6
+ }
7
+
8
+ .pf-c-wizard__main-body {
9
+ max-width: 500px;
10
+ .advanced-fields-title {
11
+ margin-bottom: 10px;
12
+ }
13
+ #advanced-fields-job-template {
14
+ .foreman-search-field {
15
+ // Giving pf3 search bar a pf4 look
16
+ .search-bar {
17
+ display: block;
18
+ }
19
+ .input-group-btn {
20
+ display: none;
21
+ }
22
+ li {
23
+ font-size: 16px;
24
+ }
25
+ input {
26
+ font-size: 16px;
27
+ height: 36px;
28
+ }
29
+ .foreman-autocomplete .autocomplete-focus-shortcut {
30
+ top: 8px;
31
+ font-size: 16px;
32
+ }
33
+ .foreman-autocomplete .autocomplete-aux {
34
+ top: 8px;
35
+ font-size: 16px;
36
+ .autocomplete-clear-button {
37
+ font-size: 16px;
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+
44
+ .schedule-tab {
45
+ input[type='radio'],
46
+ input[type='checkbox'] {
47
+ margin: 0;
48
+ }
49
+ .advanced-scheduling-button {
50
+ text-align: start;
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,16 @@
1
+ import { translate as __ } from 'foremanReact/common/I18n';
2
+ import { foremanUrl } from 'foremanReact/common/helpers';
3
+
4
+ export const JOB_TEMPLATES = 'JOB_TEMPLATES';
5
+ export const JOB_CATEGORIES = 'JOB_CATEGORIES';
6
+ export const JOB_TEMPLATE = 'JOB_TEMPLATE';
7
+ export const templatesUrl = foremanUrl('/api/v2/job_templates');
8
+
9
+ export const repeatTypes = {
10
+ noRepeat: __('Does not repeat'),
11
+ cronline: __('Cronline'),
12
+ monthly: __('Monthly'),
13
+ weekly: __('Weekly'),
14
+ daily: __('Daily'),
15
+ hourly: __('Hourly'),
16
+ };
@@ -0,0 +1,47 @@
1
+ import {
2
+ selectAPIResponse,
3
+ selectAPIStatus,
4
+ selectAPIErrorMessage,
5
+ } from 'foremanReact/redux/API/APISelectors';
6
+
7
+ import {
8
+ JOB_TEMPLATES,
9
+ JOB_CATEGORIES,
10
+ JOB_TEMPLATE,
11
+ } from './JobWizardConstants';
12
+
13
+ export const selectJobTemplatesStatus = state =>
14
+ selectAPIStatus(state, JOB_TEMPLATES);
15
+
16
+ export const filterJobTemplates = templates =>
17
+ templates?.filter(template => !template.snippet) || [];
18
+
19
+ export const selectJobTemplates = state =>
20
+ filterJobTemplates(selectAPIResponse(state, JOB_TEMPLATES)?.results);
21
+
22
+ export const selectJobCategories = state =>
23
+ selectAPIResponse(state, JOB_CATEGORIES).job_categories || [];
24
+
25
+ export const selectJobCategoriesStatus = state =>
26
+ selectAPIStatus(state, JOB_CATEGORIES);
27
+
28
+ export const selectCategoryError = state =>
29
+ selectAPIErrorMessage(state, JOB_CATEGORIES);
30
+
31
+ export const selectAllTemplatesError = state =>
32
+ selectAPIErrorMessage(state, JOB_TEMPLATES);
33
+
34
+ export const selectTemplateError = state =>
35
+ selectAPIErrorMessage(state, JOB_TEMPLATE);
36
+
37
+ export const selectJobTemplate = state =>
38
+ selectAPIResponse(state, JOB_TEMPLATE);
39
+
40
+ export const selectEffectiveUser = state =>
41
+ selectAPIResponse(state, JOB_TEMPLATE).effective_user;
42
+
43
+ export const selectAdvancedTemplateInputs = state =>
44
+ selectAPIResponse(state, JOB_TEMPLATE).advanced_template_inputs || [];
45
+
46
+ export const selectTemplateInputs = state =>
47
+ selectAPIResponse(state, JOB_TEMPLATE).template_inputs || [];
@@ -0,0 +1,43 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Job wizard fill should select template: initial 1`] = `
4
+ Array [
5
+ Object {
6
+ "key": "JOB_CATEGORIES",
7
+ "type": "get",
8
+ "url": "/ui_job_wizard/categories",
9
+ },
10
+ Object {
11
+ "key": "JOB_TEMPLATES",
12
+ "type": "get",
13
+ "url": URI {
14
+ "_deferred_build": true,
15
+ "_parts": Object {
16
+ "duplicateQueryParameters": false,
17
+ "escapeQuerySpace": true,
18
+ "fragment": null,
19
+ "hostname": null,
20
+ "password": null,
21
+ "path": "foreman/api/v2/job_templates",
22
+ "port": null,
23
+ "preventInvalidHostname": false,
24
+ "protocol": null,
25
+ "query": "search=job_category%3D%22Ansible+Commands%22&per_page=all",
26
+ "urn": null,
27
+ "username": null,
28
+ },
29
+ "_string": "",
30
+ },
31
+ },
32
+ ]
33
+ `;
34
+
35
+ exports[`Job wizard fill should select template: select template 1`] = `
36
+ Array [
37
+ Object {
38
+ "key": "JOB_TEMPLATE",
39
+ "type": "get",
40
+ "url": "/ui_job_wizard/template/178",
41
+ },
42
+ ]
43
+ `;
@@ -0,0 +1,128 @@
1
+ import configureMockStore from 'redux-mock-store';
2
+
3
+ export const jobTemplate = {
4
+ id: 178,
5
+ name: 'template1',
6
+ template:
7
+ "---\n- hosts: all\n tasks:\n - shell:\n cmd: |\n<%= indent(10) { input('command') } %>\n register: out\n - debug: var=out",
8
+ snippet: false,
9
+ default: true,
10
+ job_category: 'Ansible Commands',
11
+ provider_type: 'Ansible',
12
+ description_format: 'Run %{command}',
13
+ execution_timeout_interval: 2,
14
+ description: null,
15
+ };
16
+
17
+ export const jobTemplates = [jobTemplate];
18
+
19
+ export const jobTemplateResponse = {
20
+ job_template: jobTemplate,
21
+ effective_user: {
22
+ id: null,
23
+ job_template_id: 178,
24
+ value: 'default effective user',
25
+ overridable: true,
26
+ current_user: false,
27
+ },
28
+ advanced_template_inputs: [
29
+ {
30
+ name: 'adv plain hidden',
31
+ required: true,
32
+ input_type: 'user',
33
+ description: 'some Description',
34
+ advanced: true,
35
+ value_type: 'plain',
36
+ resource_type: 'ansible_roles',
37
+ default: 'Default val',
38
+ hidden_value: true,
39
+ },
40
+ {
41
+ name: 'adv plain select',
42
+ required: false,
43
+ input_type: 'user',
44
+ options: 'option 1\r\noption 2\r\noption 3\r\noption 4',
45
+ advanced: true,
46
+ value_type: 'plain',
47
+ resource_type: 'ansible_roles',
48
+ default: '',
49
+ hidden_value: false,
50
+ },
51
+ {
52
+ name: 'adv search',
53
+ required: false,
54
+ options: '',
55
+ advanced: true,
56
+ value_type: 'search',
57
+ resource_type: 'foreman_tasks/tasks',
58
+ default: '',
59
+ hidden_value: false,
60
+ },
61
+ {
62
+ name: 'adv date',
63
+ required: false,
64
+ options: '',
65
+ advanced: true,
66
+ value_type: 'date',
67
+ resource_type: 'ansible_roles',
68
+ default: '',
69
+ hidden_value: false,
70
+ },
71
+ ],
72
+ template_inputs: [
73
+ {
74
+ name: 'plain hidden',
75
+ required: true,
76
+ input_type: 'user',
77
+ description: 'some Description',
78
+ advanced: false,
79
+ value_type: 'plain',
80
+ resource_type: 'ansible_roles',
81
+ default: 'Default val',
82
+ hidden_value: true,
83
+ },
84
+ ],
85
+ };
86
+
87
+ export const jobCategories = ['Ansible Commands', 'Puppet', 'Services'];
88
+
89
+ export const testSetup = (selectors, api) => {
90
+ jest.spyOn(api, 'get');
91
+ jest.spyOn(selectors, 'selectJobTemplate');
92
+ jest.spyOn(selectors, 'selectJobTemplates');
93
+ jest.spyOn(selectors, 'selectJobCategories');
94
+ jest.spyOn(selectors, 'selectJobCategoriesStatus');
95
+
96
+ selectors.selectJobCategories.mockImplementation(() => jobCategories);
97
+ selectors.selectJobTemplates.mockImplementation(() => [
98
+ jobTemplate,
99
+ { ...jobTemplate, id: 2, name: 'template2' },
100
+ ]);
101
+ const mockStore = configureMockStore([]);
102
+ const store = mockStore({});
103
+ return store;
104
+ };
105
+
106
+ export const mockTemplate = selectors => {
107
+ selectors.selectJobTemplate.mockImplementation(() => jobTemplate);
108
+ selectors.selectJobCategoriesStatus.mockImplementation(() => 'RESOLVED');
109
+ };
110
+ export const mockApi = api => {
111
+ api.get.mockImplementation(({ handleSuccess, ...action }) => {
112
+ if (action.key === 'JOB_CATEGORIES') {
113
+ handleSuccess &&
114
+ handleSuccess({ data: { job_categories: jobCategories } });
115
+ } else if (action.key === 'JOB_TEMPLATE') {
116
+ handleSuccess &&
117
+ handleSuccess({
118
+ data: jobTemplateResponse,
119
+ });
120
+ } else if (action.key === 'JOB_TEMPLATES') {
121
+ handleSuccess &&
122
+ handleSuccess({
123
+ data: { results: [jobTemplate] },
124
+ });
125
+ }
126
+ return { type: 'get', ...action };
127
+ });
128
+ };