foreman_rh_cloud 13.0.6 → 13.0.8
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.
- checksums.yaml +4 -4
- data/app/controllers/concerns/foreman_rh_cloud/registration_manager_extensions.rb +39 -0
- data/lib/foreman_inventory_upload/async/create_missing_insights_facets.rb +3 -2
- data/lib/foreman_inventory_upload/scripts/uploader.sh.erb +1 -1
- data/lib/foreman_inventory_upload.rb +6 -2
- data/lib/foreman_rh_cloud/engine.rb +1 -0
- data/lib/foreman_rh_cloud/plugin.rb +4 -0
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/tasks/rh_cloud_inventory.rake +11 -1
- data/package.json +1 -1
- data/test/jobs/cloud_connector_announce_task_test.rb +3 -2
- data/test/jobs/connector_playbook_execution_reporter_task_test.rb +32 -20
- data/test/jobs/create_missing_insights_facets_test.rb +151 -0
- data/test/jobs/exponential_backoff_test.rb +9 -8
- data/test/jobs/generate_host_report_test.rb +100 -0
- data/test/jobs/generate_report_job_test.rb +146 -0
- data/test/jobs/host_inventory_report_job_test.rb +244 -0
- data/test/jobs/insights_client_status_aging_test.rb +3 -2
- data/test/jobs/insights_full_sync_test.rb +13 -7
- data/test/jobs/insights_resolutions_sync_test.rb +9 -5
- data/test/jobs/insights_rules_sync_test.rb +5 -3
- data/test/jobs/inventory_full_sync_test.rb +9 -5
- data/test/jobs/inventory_hosts_sync_test.rb +11 -6
- data/test/jobs/inventory_scheduled_sync_test.rb +10 -6
- data/test/jobs/inventory_self_host_sync_test.rb +1 -1
- data/test/jobs/queue_for_upload_job_test.rb +9 -7
- data/test/jobs/remove_insights_hosts_job_test.rb +14 -15
- data/test/jobs/single_host_report_job_test.rb +155 -0
- data/test/jobs/upload_report_job_test.rb +5 -4
- data/test/unit/lib/foreman_rh_cloud/registration_manager_extensions_test.rb +192 -0
- data/webpack/ForemanColumnExtensions/index.js +2 -0
- data/webpack/InsightsCloudSync/Components/InsightsSettings/InsightsSettings.js +3 -3
- data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +3 -9
- data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/InsightsTable.test.js +13 -0
- data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +2 -2
- data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +3 -3
- data/webpack/InsightsCloudSync/InsightsCloudSync.js +3 -3
- data/webpack/InsightsCloudSync/InsightsCloudSync.test.js +10 -0
- data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +1 -1
- data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +5 -5
- data/webpack/InsightsVulnerabilityHostIndexExtensions/CVECountCell.js +2 -2
- data/webpack/InsightsVulnerabilityHostIndexExtensions/__tests__/CVECountCell.test.js +7 -7
- data/webpack/common/Hooks/ConfigHooks.js +3 -16
- metadata +14 -1
|
@@ -2,7 +2,7 @@ require 'test_plugin_helper'
|
|
|
2
2
|
require 'foreman_tasks/test_helpers'
|
|
3
3
|
|
|
4
4
|
class InventoryScheduledSyncTest < ActiveSupport::TestCase
|
|
5
|
-
include
|
|
5
|
+
include Dynflow::Testing::Factories
|
|
6
6
|
|
|
7
7
|
test 'Schedules an execution if auto upload is enabled' do
|
|
8
8
|
Setting[:allow_auto_inventory_upload] = true
|
|
@@ -11,7 +11,8 @@ class InventoryScheduledSyncTest < ActiveSupport::TestCase
|
|
|
11
11
|
InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_org_sync).times(Organization.unscoped.count)
|
|
12
12
|
InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_remove_insights_hosts).times(Organization.unscoped.count)
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
action = create_and_plan_action(InventorySync::Async::InventoryScheduledSync)
|
|
15
|
+
run_action(action)
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
test 'Skips execution if with_iop_smart_proxy? is true' do
|
|
@@ -19,8 +20,9 @@ class InventoryScheduledSyncTest < ActiveSupport::TestCase
|
|
|
19
20
|
|
|
20
21
|
InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_org_sync).never
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
action = create_and_plan_action(InventorySync::Async::InventoryScheduledSync)
|
|
24
|
+
action = run_action(action)
|
|
25
|
+
status = action.output[:status].to_s
|
|
24
26
|
assert_match(/Foreman is configured with a local IoP Smart Proxy/, status)
|
|
25
27
|
end
|
|
26
28
|
|
|
@@ -29,7 +31,8 @@ class InventoryScheduledSyncTest < ActiveSupport::TestCase
|
|
|
29
31
|
|
|
30
32
|
InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_org_sync).never
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
action = create_and_plan_action(InventorySync::Async::InventoryScheduledSync)
|
|
35
|
+
run_action(action)
|
|
33
36
|
end
|
|
34
37
|
|
|
35
38
|
test 'Skips mismatch deletion if the setting is disabled' do
|
|
@@ -39,6 +42,7 @@ class InventoryScheduledSyncTest < ActiveSupport::TestCase
|
|
|
39
42
|
InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_org_sync).times(Organization.unscoped.count)
|
|
40
43
|
InventorySync::Async::InventoryScheduledSync.any_instance.expects(:plan_remove_insights_hosts).never
|
|
41
44
|
|
|
42
|
-
|
|
45
|
+
action = create_and_plan_action(InventorySync::Async::InventoryScheduledSync)
|
|
46
|
+
run_action(action)
|
|
43
47
|
end
|
|
44
48
|
end
|
|
@@ -2,15 +2,13 @@ require 'test_plugin_helper'
|
|
|
2
2
|
require 'foreman_tasks/test_helpers'
|
|
3
3
|
|
|
4
4
|
class QueueForUploadJobTest < ActiveSupport::TestCase
|
|
5
|
-
include
|
|
6
|
-
include FolderIsolation
|
|
5
|
+
include Dynflow::Testing::Factories
|
|
7
6
|
|
|
8
7
|
let(:organization) { FactoryBot.create(:organization) }
|
|
9
|
-
let(:base_folder) {
|
|
8
|
+
let(:base_folder) { Dir.mktmpdir }
|
|
10
9
|
let(:report_file) { 'test_report.tar.xz' }
|
|
11
10
|
let(:report_path) { File.join(base_folder, report_file) }
|
|
12
11
|
let(:uploads_folder) { ForemanInventoryUpload.uploads_folder }
|
|
13
|
-
subject { ForemanTasks.sync_task(ForemanInventoryUpload::Async::QueueForUploadJob, base_folder, report_file, organization.id) }
|
|
14
12
|
|
|
15
13
|
setup do
|
|
16
14
|
# Stub the script template source
|
|
@@ -29,19 +27,22 @@ class QueueForUploadJobTest < ActiveSupport::TestCase
|
|
|
29
27
|
|
|
30
28
|
teardown do
|
|
31
29
|
FileUtils.rm_rf(uploads_folder) if Dir.exist?(uploads_folder)
|
|
30
|
+
FileUtils.remove_entry base_folder if Dir.exist?(base_folder)
|
|
32
31
|
end
|
|
33
32
|
|
|
34
33
|
test 'plan method sets up the job correctly and calls plan_upload_report' do
|
|
35
34
|
# Mock plan_upload_report to verify it's called
|
|
36
35
|
ForemanInventoryUpload::Async::QueueForUploadJob.any_instance.expects(:plan_upload_report).once
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
action = create_and_plan_action(ForemanInventoryUpload::Async::QueueForUploadJob, base_folder, report_file, organization.id)
|
|
38
|
+
run_action(action)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
test 'run method processes file and moves it to uploads folder' do
|
|
42
42
|
ForemanInventoryUpload::Async::QueueForUploadJob.any_instance.stubs(:plan_upload_report)
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
action = create_and_plan_action(ForemanInventoryUpload::Async::QueueForUploadJob, base_folder, report_file, organization.id)
|
|
45
|
+
run_action(action)
|
|
45
46
|
|
|
46
47
|
# Verify the file was moved
|
|
47
48
|
refute File.exist?(report_path), "Original file should be moved"
|
|
@@ -51,7 +52,8 @@ class QueueForUploadJobTest < ActiveSupport::TestCase
|
|
|
51
52
|
test 'creates necessary folders and scripts' do
|
|
52
53
|
ForemanInventoryUpload::Async::QueueForUploadJob.any_instance.stubs(:plan_upload_report)
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
action = create_and_plan_action(ForemanInventoryUpload::Async::QueueForUploadJob, base_folder, report_file, organization.id)
|
|
56
|
+
run_action(action)
|
|
55
57
|
|
|
56
58
|
# Verify the uploads folder was created
|
|
57
59
|
assert Dir.exist?(uploads_folder), "Uploads folder should be created"
|
|
@@ -2,7 +2,7 @@ require 'test_plugin_helper'
|
|
|
2
2
|
require 'foreman_tasks/test_helpers'
|
|
3
3
|
|
|
4
4
|
class RemoveInsightsHostJobTest < ActiveSupport::TestCase
|
|
5
|
-
include
|
|
5
|
+
include Dynflow::Testing::Factories
|
|
6
6
|
|
|
7
7
|
setup do
|
|
8
8
|
User.current = User.find_by(login: 'secret_admin')
|
|
@@ -18,10 +18,10 @@ class RemoveInsightsHostJobTest < ActiveSupport::TestCase
|
|
|
18
18
|
|
|
19
19
|
FactoryBot.create(:insights_missing_host, organization: @org)
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
action = create_and_plan_action(ForemanInventoryUpload::Async::RemoveInsightsHostsJob, '', @org.id)
|
|
22
|
+
run_action(action)
|
|
22
23
|
|
|
23
24
|
assert_equal 0, InsightsMissingHost.count
|
|
24
|
-
assert_equal 'success', task.result
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
test 'Does not delete hosts on cloud failure' do
|
|
@@ -31,14 +31,13 @@ class RemoveInsightsHostJobTest < ActiveSupport::TestCase
|
|
|
31
31
|
|
|
32
32
|
FactoryBot.create(:insights_missing_host, organization: @org)
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
action = create_and_plan_action(ForemanInventoryUpload::Async::RemoveInsightsHostsJob, '', @org.id)
|
|
35
|
+
|
|
36
|
+
assert_raises(StandardError) do
|
|
37
|
+
run_action(action)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
assert_equal 1, InsightsMissingHost.count
|
|
41
|
-
assert_equal 'error', task.result
|
|
42
41
|
end
|
|
43
42
|
|
|
44
43
|
test 'Paginates the hosts list' do
|
|
@@ -54,12 +53,12 @@ class RemoveInsightsHostJobTest < ActiveSupport::TestCase
|
|
|
54
53
|
FactoryBot.create(:insights_missing_host, organization: @org)
|
|
55
54
|
FactoryBot.create(:insights_missing_host, organization: @org)
|
|
56
55
|
|
|
57
|
-
|
|
56
|
+
action = create_and_plan_action(ForemanInventoryUpload::Async::RemoveInsightsHostsJob, '', @org.id)
|
|
57
|
+
action = run_action(action)
|
|
58
58
|
|
|
59
59
|
assert_equal 0, InsightsMissingHost.count
|
|
60
|
-
assert_equal '
|
|
61
|
-
assert_equal '
|
|
62
|
-
assert_equal 'response2', task.output[:response_page2]
|
|
60
|
+
assert_equal 'response1', action.output[:response_page1]
|
|
61
|
+
assert_equal 'response2', action.output[:response_page2]
|
|
63
62
|
end
|
|
64
63
|
|
|
65
64
|
test 'Uses scoped_search to select hosts' do
|
|
@@ -73,12 +72,12 @@ class RemoveInsightsHostJobTest < ActiveSupport::TestCase
|
|
|
73
72
|
FactoryBot.create(:insights_missing_host, name: 'test a', organization: @org)
|
|
74
73
|
FactoryBot.create(:insights_missing_host, name: 'test b', organization: @org)
|
|
75
74
|
|
|
76
|
-
|
|
75
|
+
action = create_and_plan_action(ForemanInventoryUpload::Async::RemoveInsightsHostsJob, 'name ~ b', @org.id)
|
|
76
|
+
action = run_action(action)
|
|
77
77
|
|
|
78
78
|
assert_equal 1, InsightsMissingHost.count
|
|
79
79
|
assert_equal 'test a', InsightsMissingHost.first.name
|
|
80
|
-
assert_equal '
|
|
81
|
-
assert_equal 'response1', task.output[:response_page1]
|
|
80
|
+
assert_equal 'response1', action.output[:response_page1]
|
|
82
81
|
end
|
|
83
82
|
|
|
84
83
|
def mock_response(code: 200, body: '')
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
require 'test_plugin_helper'
|
|
2
|
+
require 'foreman_tasks/test_helpers'
|
|
3
|
+
|
|
4
|
+
class SingleHostReportJobTest < ActiveSupport::TestCase
|
|
5
|
+
include Dynflow::Testing::Factories
|
|
6
|
+
include Dynflow::Testing::Assertions
|
|
7
|
+
include KatelloCVEHelper
|
|
8
|
+
|
|
9
|
+
let(:base_folder) { Dir.mktmpdir }
|
|
10
|
+
|
|
11
|
+
setup do
|
|
12
|
+
User.current = User.find_by(login: 'secret_admin')
|
|
13
|
+
cve = make_cve
|
|
14
|
+
env = cve.lifecycle_environment
|
|
15
|
+
|
|
16
|
+
@host = FactoryBot.create(
|
|
17
|
+
:host,
|
|
18
|
+
:with_subscription,
|
|
19
|
+
:with_content,
|
|
20
|
+
content_view: cve.content_view,
|
|
21
|
+
lifecycle_environment: env,
|
|
22
|
+
organization: env.organization
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
teardown do
|
|
27
|
+
FileUtils.remove_entry base_folder if Dir.exist?(base_folder)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
test 'plan sets host_id in input' do
|
|
31
|
+
action = create_and_plan_action(
|
|
32
|
+
ForemanInventoryUpload::Async::SingleHostReportJob,
|
|
33
|
+
base_folder,
|
|
34
|
+
@host.organization_id,
|
|
35
|
+
@host.id
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
assert_equal @host.id, action.input[:host_id]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
test 'plan calls super with id filter' do
|
|
42
|
+
expected_filter = "id=#{@host.id}"
|
|
43
|
+
|
|
44
|
+
action = create_and_plan_action(
|
|
45
|
+
ForemanInventoryUpload::Async::SingleHostReportJob,
|
|
46
|
+
base_folder,
|
|
47
|
+
@host.organization_id,
|
|
48
|
+
@host.id
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
assert_action_planned_with(
|
|
52
|
+
action,
|
|
53
|
+
ForemanInventoryUpload::Async::GenerateHostReport,
|
|
54
|
+
base_folder,
|
|
55
|
+
@host.organization_id,
|
|
56
|
+
expected_filter
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
test 'inherits behavior from HostInventoryReportJob' do
|
|
61
|
+
action = create_and_plan_action(
|
|
62
|
+
ForemanInventoryUpload::Async::SingleHostReportJob,
|
|
63
|
+
base_folder,
|
|
64
|
+
@host.organization_id,
|
|
65
|
+
@host.id
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Should schedule all parent actions
|
|
69
|
+
assert_action_planned(action, ForemanInventoryUpload::Async::GenerateHostReport)
|
|
70
|
+
assert_action_planned(action, ForemanInventoryUpload::Async::QueueForUploadJob)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
test 'humanized_name includes hostname' do
|
|
74
|
+
action = create_and_plan_action(
|
|
75
|
+
ForemanInventoryUpload::Async::SingleHostReportJob,
|
|
76
|
+
base_folder,
|
|
77
|
+
@host.organization_id,
|
|
78
|
+
@host.id
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
assert_equal "Single-host report job for host #{@host.name}", action.humanized_name
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
test 'humanized_name handles missing host' do
|
|
85
|
+
non_existent_host_id = 999_999
|
|
86
|
+
|
|
87
|
+
action = create_and_plan_action(
|
|
88
|
+
ForemanInventoryUpload::Async::SingleHostReportJob,
|
|
89
|
+
base_folder,
|
|
90
|
+
@host.organization_id,
|
|
91
|
+
non_existent_host_id
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
assert_equal 'Single-host report job', action.humanized_name
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
test 'hostname method returns correct name' do
|
|
98
|
+
action = create_and_plan_action(
|
|
99
|
+
ForemanInventoryUpload::Async::SingleHostReportJob,
|
|
100
|
+
base_folder,
|
|
101
|
+
@host.organization_id,
|
|
102
|
+
@host.id
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
assert_equal @host.name, action.hostname(@host.id)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
test 'hostname method handles nil gracefully' do
|
|
109
|
+
action = create_and_plan_action(
|
|
110
|
+
ForemanInventoryUpload::Async::SingleHostReportJob,
|
|
111
|
+
base_folder,
|
|
112
|
+
@host.organization_id,
|
|
113
|
+
@host.id
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
assert_nil action.hostname(999_999)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
test 'generates report with correct archive name for single host' do
|
|
120
|
+
expected_filter = "id=#{@host.id}"
|
|
121
|
+
expected_archive_name = ForemanInventoryUpload.facts_archive_name(@host.organization_id, expected_filter)
|
|
122
|
+
|
|
123
|
+
action = create_and_plan_action(
|
|
124
|
+
ForemanInventoryUpload::Async::SingleHostReportJob,
|
|
125
|
+
base_folder,
|
|
126
|
+
@host.organization_id,
|
|
127
|
+
@host.id
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
assert_action_planned_with(
|
|
131
|
+
action,
|
|
132
|
+
ForemanInventoryUpload::Async::QueueForUploadJob,
|
|
133
|
+
base_folder,
|
|
134
|
+
expected_archive_name,
|
|
135
|
+
@host.organization_id
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
test 'respects IoP mode for facet creation' do
|
|
140
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
141
|
+
|
|
142
|
+
action = create_and_plan_action(
|
|
143
|
+
ForemanInventoryUpload::Async::SingleHostReportJob,
|
|
144
|
+
base_folder,
|
|
145
|
+
@host.organization_id,
|
|
146
|
+
@host.id
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
assert_action_planned_with(
|
|
150
|
+
action,
|
|
151
|
+
ForemanInventoryUpload::Async::CreateMissingInsightsFacets,
|
|
152
|
+
@host.organization_id
|
|
153
|
+
)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
@@ -2,8 +2,7 @@ require 'test_plugin_helper'
|
|
|
2
2
|
require 'foreman_tasks/test_helpers'
|
|
3
3
|
|
|
4
4
|
class UploadReportJobTest < ActiveSupport::TestCase
|
|
5
|
-
include
|
|
6
|
-
include FolderIsolation
|
|
5
|
+
include Dynflow::Testing::Factories
|
|
7
6
|
|
|
8
7
|
test 'returns aborted state when disconnected' do
|
|
9
8
|
organization = FactoryBot.create(:organization)
|
|
@@ -14,7 +13,8 @@ class UploadReportJobTest < ActiveSupport::TestCase
|
|
|
14
13
|
)
|
|
15
14
|
ForemanInventoryUpload::Async::UploadReportJob.any_instance.expects(:content_disconnected?).returns(true)
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
action = create_and_plan_action(ForemanInventoryUpload::Async::UploadReportJob, '', organization.id)
|
|
17
|
+
run_action(action)
|
|
18
18
|
|
|
19
19
|
label = ForemanInventoryUpload::Async::UploadReportJob.output_label(organization.id)
|
|
20
20
|
progress_output = ForemanInventoryUpload::Async::ProgressOutput.get(label)
|
|
@@ -27,7 +27,8 @@ class UploadReportJobTest < ActiveSupport::TestCase
|
|
|
27
27
|
organization = FactoryBot.create(:organization)
|
|
28
28
|
Organization.any_instance.expects(:owner_details).returns(nil)
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
action = create_and_plan_action(ForemanInventoryUpload::Async::UploadReportJob, '', organization.id)
|
|
31
|
+
run_action(action)
|
|
31
32
|
|
|
32
33
|
label = ForemanInventoryUpload::Async::UploadReportJob.output_label(organization.id)
|
|
33
34
|
progress_output = ForemanInventoryUpload::Async::ProgressOutput.get(label)
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
require 'test_plugin_helper'
|
|
2
|
+
|
|
3
|
+
module ForemanRhCloud
|
|
4
|
+
class RegistrationManagerExtensionsTest < ActiveSupport::TestCase
|
|
5
|
+
setup do
|
|
6
|
+
@org = FactoryBot.create(:organization)
|
|
7
|
+
@host = FactoryBot.create(:host, :managed, organization: @org)
|
|
8
|
+
@insights_facet = ::InsightsFacet.create!(host: @host, uuid: 'test-uuid-123')
|
|
9
|
+
|
|
10
|
+
# Stub Candlepin interaction (from Katello)
|
|
11
|
+
::Katello::Resources::Candlepin::Consumer.stubs(:destroy)
|
|
12
|
+
|
|
13
|
+
# Stub the cloud request to avoid actual HTTP calls
|
|
14
|
+
Katello::RegistrationManager.stubs(:execute_cloud_request).returns(true)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
context 'unregister_host' do
|
|
18
|
+
test 'should call HBI delete in IoP mode when host has insights facet with UUID' do
|
|
19
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
20
|
+
expected_url = ForemanInventoryUpload.host_by_id_url('test-uuid-123')
|
|
21
|
+
|
|
22
|
+
# Expect the cloud request to be made
|
|
23
|
+
Katello::RegistrationManager.expects(:execute_cloud_request).with do |params|
|
|
24
|
+
params[:organization] == @org &&
|
|
25
|
+
params[:method] == :delete &&
|
|
26
|
+
params[:url] == expected_url &&
|
|
27
|
+
params[:headers][:content_type] == :json
|
|
28
|
+
end.returns(true)
|
|
29
|
+
|
|
30
|
+
Katello::RegistrationManager.unregister_host(@host, unregistering: true)
|
|
31
|
+
|
|
32
|
+
# Verify insights_facet was destroyed
|
|
33
|
+
assert_nil InsightsFacet.find_by(id: @insights_facet.id)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
test 'should NOT call HBI delete in non-IoP mode' do
|
|
37
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
|
|
38
|
+
|
|
39
|
+
# Should NOT attempt to delete from HBI
|
|
40
|
+
Katello::RegistrationManager.expects(:execute_cloud_request).never
|
|
41
|
+
|
|
42
|
+
Katello::RegistrationManager.unregister_host(@host, unregistering: true)
|
|
43
|
+
|
|
44
|
+
# Verify insights_facet was still destroyed
|
|
45
|
+
assert_nil InsightsFacet.find_by(id: @insights_facet.id)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
test 'should NOT call HBI delete when host has no insights_facet' do
|
|
49
|
+
host_without_facet = FactoryBot.create(:host, :managed, organization: @org)
|
|
50
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
51
|
+
|
|
52
|
+
Katello::RegistrationManager.expects(:execute_cloud_request).never
|
|
53
|
+
|
|
54
|
+
assert_nothing_raised do
|
|
55
|
+
Katello::RegistrationManager.unregister_host(host_without_facet, unregistering: true)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
test 'should NOT call HBI delete when host has insights_facet with empty UUID' do
|
|
60
|
+
host_with_empty_uuid_facet = FactoryBot.create(:host, :managed, organization: @org)
|
|
61
|
+
empty_uuid_facet = InsightsFacet.create!(host: host_with_empty_uuid_facet, uuid: '')
|
|
62
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
63
|
+
|
|
64
|
+
Katello::RegistrationManager.expects(:execute_cloud_request).never
|
|
65
|
+
|
|
66
|
+
assert_nothing_raised do
|
|
67
|
+
Katello::RegistrationManager.unregister_host(host_with_empty_uuid_facet, unregistering: true)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
assert_nil InsightsFacet.find_by(id: empty_uuid_facet.id)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
test 'should NOT call HBI delete when insights_facet has no UUID' do
|
|
74
|
+
facet_id = @insights_facet.id
|
|
75
|
+
@insights_facet.update(uuid: nil)
|
|
76
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
77
|
+
|
|
78
|
+
Katello::RegistrationManager.expects(:execute_cloud_request).never
|
|
79
|
+
|
|
80
|
+
Katello::RegistrationManager.unregister_host(@host, unregistering: true)
|
|
81
|
+
|
|
82
|
+
# Verify facet was still destroyed
|
|
83
|
+
assert_nil InsightsFacet.find_by(id: facet_id)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
test 'should always destroy insights_facet regardless of IoP mode' do
|
|
87
|
+
facet_id = @insights_facet.id
|
|
88
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
|
|
89
|
+
|
|
90
|
+
assert_not_nil InsightsFacet.find_by(id: facet_id)
|
|
91
|
+
|
|
92
|
+
Katello::RegistrationManager.unregister_host(@host, unregistering: true)
|
|
93
|
+
|
|
94
|
+
assert_nil InsightsFacet.find_by(id: facet_id)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
context 'hbi_host_destroy error handling' do
|
|
99
|
+
setup do
|
|
100
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
101
|
+
@expected_url = ForemanInventoryUpload.host_by_id_url('test-uuid-123')
|
|
102
|
+
@facet_id = @insights_facet.id
|
|
103
|
+
# Unstub execute_cloud_request for error tests
|
|
104
|
+
Katello::RegistrationManager.unstub(:execute_cloud_request)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
test 'should handle RestClient::NotFound gracefully' do
|
|
108
|
+
Katello::RegistrationManager.stubs(:execute_cloud_request).raises(RestClient::NotFound)
|
|
109
|
+
|
|
110
|
+
# Should log warning but not raise
|
|
111
|
+
Rails.logger.expects(:warn).with(regexp_matches(/host does not exist in HBI/))
|
|
112
|
+
|
|
113
|
+
assert_nothing_raised do
|
|
114
|
+
Katello::RegistrationManager.unregister_host(@host, unregistering: true)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Facet should still be destroyed
|
|
118
|
+
assert_nil InsightsFacet.find_by(id: @facet_id)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
test 'should handle server errors gracefully' do
|
|
122
|
+
error = RestClient::InternalServerError.new
|
|
123
|
+
Katello::RegistrationManager.stubs(:execute_cloud_request).raises(error)
|
|
124
|
+
|
|
125
|
+
# Should log error but not raise
|
|
126
|
+
Rails.logger.expects(:error).with(regexp_matches(/Failed to destroy HBI host/))
|
|
127
|
+
|
|
128
|
+
assert_nothing_raised do
|
|
129
|
+
Katello::RegistrationManager.unregister_host(@host, unregistering: true)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Facet should still be destroyed
|
|
133
|
+
assert_nil InsightsFacet.find_by(id: @facet_id)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
test 'should handle timeout errors gracefully' do
|
|
137
|
+
error = RestClient::Exceptions::ReadTimeout.new
|
|
138
|
+
Katello::RegistrationManager.stubs(:execute_cloud_request).raises(error)
|
|
139
|
+
|
|
140
|
+
# Should log error but not raise
|
|
141
|
+
Rails.logger.expects(:error).with(regexp_matches(/Failed to destroy HBI host/))
|
|
142
|
+
|
|
143
|
+
assert_nothing_raised do
|
|
144
|
+
Katello::RegistrationManager.unregister_host(@host, unregistering: true)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Facet should still be destroyed
|
|
148
|
+
assert_nil InsightsFacet.find_by(id: @facet_id)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
test 'should handle connection errors gracefully' do
|
|
152
|
+
error = Errno::ECONNREFUSED.new
|
|
153
|
+
Katello::RegistrationManager.stubs(:execute_cloud_request).raises(error)
|
|
154
|
+
|
|
155
|
+
# Should log error but not raise
|
|
156
|
+
Rails.logger.expects(:error).with(regexp_matches(/Failed to destroy HBI host/))
|
|
157
|
+
|
|
158
|
+
assert_nothing_raised do
|
|
159
|
+
Katello::RegistrationManager.unregister_host(@host, unregistering: true)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Facet should still be destroyed
|
|
163
|
+
assert_nil InsightsFacet.find_by(id: @facet_id)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
context 'integration' do
|
|
168
|
+
test 'should be properly prepended to RegistrationManager' do
|
|
169
|
+
assert_includes Katello::RegistrationManager.singleton_class.ancestors,
|
|
170
|
+
ForemanRhCloud::RegistrationManagerExtensions
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
test 'should preserve original unregister_host behavior' do
|
|
174
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
|
|
175
|
+
|
|
176
|
+
# Just verify the extension is properly integrated
|
|
177
|
+
# Detailed Katello behavior is tested in Katello's own tests
|
|
178
|
+
assert_nothing_raised do
|
|
179
|
+
Katello::RegistrationManager.unregister_host(@host, unregistering: true)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
context 'URL generation' do
|
|
185
|
+
test 'host_by_id_url should return correct format' do
|
|
186
|
+
url = ForemanInventoryUpload.host_by_id_url('test-uuid-123')
|
|
187
|
+
|
|
188
|
+
assert_match %r{/hosts/test-uuid-123$}, url
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
@@ -3,19 +3,19 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
4
4
|
import SwitcherPF4 from '../../../common/Switcher/SwitcherPF4';
|
|
5
5
|
import './insightsSettings.scss';
|
|
6
|
-
import {
|
|
6
|
+
import { useIopConfig } from '../../../common/Hooks/ConfigHooks';
|
|
7
7
|
|
|
8
8
|
const InsightsSettings = ({
|
|
9
9
|
insightsSyncEnabled,
|
|
10
10
|
getInsightsSyncSettings,
|
|
11
11
|
setInsightsSyncEnabled,
|
|
12
12
|
}) => {
|
|
13
|
-
const
|
|
13
|
+
const isIop = useIopConfig();
|
|
14
14
|
useEffect(() => {
|
|
15
15
|
getInsightsSyncSettings();
|
|
16
16
|
}, [getInsightsSyncSettings]);
|
|
17
17
|
|
|
18
|
-
if (
|
|
18
|
+
if (isIop) return null;
|
|
19
19
|
|
|
20
20
|
return (
|
|
21
21
|
<div className="insights_settings">
|
|
@@ -16,7 +16,7 @@ import TableEmptyState from '../../../common/table/EmptyState';
|
|
|
16
16
|
import { modifySelectedRows, getSortColumnIndex } from './InsightsTableHelpers';
|
|
17
17
|
import Pagination from './Pagination';
|
|
18
18
|
import './table.scss';
|
|
19
|
-
import {
|
|
19
|
+
import { useIopConfig } from '../../../common/Hooks/ConfigHooks';
|
|
20
20
|
|
|
21
21
|
const InsightsTable = ({
|
|
22
22
|
page,
|
|
@@ -48,17 +48,11 @@ const InsightsTable = ({
|
|
|
48
48
|
fetchInsights({ page, perPage, query, sortBy, sortOrder });
|
|
49
49
|
}, [hostname]);
|
|
50
50
|
|
|
51
|
-
const
|
|
51
|
+
const isIop = useIopConfig();
|
|
52
52
|
|
|
53
53
|
useEffect(() => {
|
|
54
54
|
setRows(
|
|
55
|
-
modifySelectedRows(
|
|
56
|
-
hits,
|
|
57
|
-
selectedIds,
|
|
58
|
-
showSelectAllAlert,
|
|
59
|
-
hideHost,
|
|
60
|
-
isLocalAdvisorEngine
|
|
61
|
-
)
|
|
55
|
+
modifySelectedRows(hits, selectedIds, showSelectAllAlert, hideHost, isIop)
|
|
62
56
|
);
|
|
63
57
|
|
|
64
58
|
if (hideHost) setColumns(getColumnsWithoutHostname());
|
|
@@ -3,6 +3,19 @@ import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
|
|
|
3
3
|
import InsightsTable from '../InsightsTable';
|
|
4
4
|
import { tableProps } from './fixtures';
|
|
5
5
|
|
|
6
|
+
jest.mock('foremanReact/Root/Context/ForemanContext', () => ({
|
|
7
|
+
useForemanContext: () => ({
|
|
8
|
+
metadata: {
|
|
9
|
+
foreman_rh_cloud: {
|
|
10
|
+
iop: true,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
}),
|
|
14
|
+
useForemanSettings: () => ({
|
|
15
|
+
perPage: 20,
|
|
16
|
+
}),
|
|
17
|
+
}));
|
|
18
|
+
|
|
6
19
|
const fixtures = {
|
|
7
20
|
'render with Props': tableProps,
|
|
8
21
|
};
|
|
@@ -16,7 +16,7 @@ import { modifyRows } from './RemediationHelpers';
|
|
|
16
16
|
import ModalFooter from './RemediationModalFooter';
|
|
17
17
|
import TableEmptyState from '../../../common/table/EmptyState';
|
|
18
18
|
import './RemediationModal.scss';
|
|
19
|
-
import {
|
|
19
|
+
import { useIopConfig } from '../../../common/Hooks/ConfigHooks';
|
|
20
20
|
|
|
21
21
|
/* eslint-disable spellcheck/spell-checker */
|
|
22
22
|
|
|
@@ -82,7 +82,7 @@ const RemediationModal = ({
|
|
|
82
82
|
const [rows, setRows] = React.useState([]);
|
|
83
83
|
const toggleModal = () => setOpen(prevValue => !prevValue);
|
|
84
84
|
|
|
85
|
-
const isIop =
|
|
85
|
+
const isIop = useIopConfig();
|
|
86
86
|
useEffect(() => {
|
|
87
87
|
// only fetch for Hosted. IoP provides via props.
|
|
88
88
|
if (!isIop && open)
|
|
@@ -8,12 +8,12 @@ import {
|
|
|
8
8
|
} from '@patternfly/react-core/deprecated';
|
|
9
9
|
import { ExternalLinkAltIcon } from '@patternfly/react-icons';
|
|
10
10
|
import { redHatAdvisorSystems } from '../InsightsCloudSyncHelpers';
|
|
11
|
-
import {
|
|
11
|
+
import { useIopConfig } from '../../common/Hooks/ConfigHooks';
|
|
12
12
|
|
|
13
13
|
const ToolbarDropdown = ({ onRecommendationSync }) => {
|
|
14
14
|
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
|
15
|
-
const
|
|
16
|
-
if (
|
|
15
|
+
const isIop = useIopConfig();
|
|
16
|
+
if (isIop) {
|
|
17
17
|
return null;
|
|
18
18
|
}
|
|
19
19
|
const dropdownItems = [
|