foreman_rh_cloud 12.2.13 → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman_rh_cloud/locale/fr/foreman_rh_cloud.js +24 -78
  3. data/app/assets/javascripts/foreman_rh_cloud/locale/ja/foreman_rh_cloud.js +24 -78
  4. data/app/assets/javascripts/foreman_rh_cloud/locale/ka/foreman_rh_cloud.js +23 -77
  5. data/app/assets/javascripts/foreman_rh_cloud/locale/ko/foreman_rh_cloud.js +23 -77
  6. data/app/assets/javascripts/foreman_rh_cloud/locale/zh_CN/foreman_rh_cloud.js +23 -77
  7. data/app/controllers/concerns/insights_cloud/package_profile_upload_extensions.rb +3 -2
  8. data/app/models/insights_hit.rb +1 -1
  9. data/app/services/foreman_rh_cloud/cert_auth.rb +3 -13
  10. data/app/services/foreman_rh_cloud/gateway_request.rb +26 -0
  11. data/app/services/foreman_rh_cloud/insights_api_forwarder.rb +1 -3
  12. data/app/services/foreman_rh_cloud/tags_auth.rb +1 -2
  13. data/lib/foreman_inventory_upload/async/generate_report_job.rb +8 -13
  14. data/lib/foreman_inventory_upload/async/queue_for_upload_job.rb +4 -4
  15. data/lib/foreman_inventory_upload/async/upload_report_job.rb +5 -6
  16. data/lib/foreman_inventory_upload/generators/fact_helpers.rb +2 -2
  17. data/lib/foreman_inventory_upload/generators/slice.rb +3 -3
  18. data/lib/foreman_inventory_upload/scripts/uploader.sh.erb +1 -7
  19. data/lib/foreman_inventory_upload.rb +2 -6
  20. data/lib/foreman_rh_cloud/engine.rb +15 -34
  21. data/lib/foreman_rh_cloud/plugin.rb +9 -9
  22. data/lib/foreman_rh_cloud/version.rb +1 -1
  23. data/lib/tasks/rh_cloud_inventory.rake +31 -14
  24. data/locale/foreman_rh_cloud.pot +157 -261
  25. data/locale/fr/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
  26. data/locale/fr/foreman_rh_cloud.po +26 -79
  27. data/locale/ja/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
  28. data/locale/ja/foreman_rh_cloud.po +26 -79
  29. data/locale/ka/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
  30. data/locale/ka/foreman_rh_cloud.po +24 -77
  31. data/locale/ko/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
  32. data/locale/ko/foreman_rh_cloud.po +25 -78
  33. data/locale/zh_CN/LC_MESSAGES/foreman_rh_cloud.mo +0 -0
  34. data/locale/zh_CN/foreman_rh_cloud.po +25 -78
  35. data/package.json +1 -1
  36. data/test/jobs/cloud_connector_announce_task_test.rb +2 -3
  37. data/test/jobs/connector_playbook_execution_reporter_task_test.rb +20 -32
  38. data/test/jobs/exponential_backoff_test.rb +8 -9
  39. data/test/jobs/insights_client_status_aging_test.rb +2 -3
  40. data/test/jobs/insights_full_sync_test.rb +7 -13
  41. data/test/jobs/insights_resolutions_sync_test.rb +5 -9
  42. data/test/jobs/insights_rules_sync_test.rb +3 -5
  43. data/test/jobs/inventory_full_sync_test.rb +5 -9
  44. data/test/jobs/inventory_hosts_sync_test.rb +6 -11
  45. data/test/jobs/inventory_scheduled_sync_test.rb +6 -10
  46. data/test/jobs/inventory_self_host_sync_test.rb +1 -1
  47. data/test/jobs/remove_insights_hosts_job_test.rb +15 -14
  48. data/test/jobs/upload_report_job_test.rb +5 -7
  49. data/test/unit/fact_helpers_test.rb +0 -47
  50. data/test/unit/slice_generator_test.rb +0 -57
  51. data/webpack/ForemanRhCloudFills.js +2 -6
  52. data/webpack/ForemanRhCloudHelpers.js +0 -4
  53. data/webpack/InsightsHostDetailsTab/InsightsTab.scss +0 -4
  54. data/webpack/InsightsHostDetailsTab/InsightsTotalRiskChart.js +23 -59
  55. data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +16 -3
  56. data/webpack/InsightsVulnerabilityHostIndexExtensions/CVECountCell.js +2 -8
  57. data/webpack/InsightsVulnerabilityHostIndexExtensions/__tests__/CVECountCell.test.js +2 -48
  58. data/webpack/__tests__/ForemanRhCloudHelpers.test.js +1 -16
  59. data/webpack/__tests__/__snapshots__/ForemanRhCloudHelpers.test.js.snap +0 -6
  60. metadata +4 -23
  61. data/app/controllers/concerns/foreman_rh_cloud/registration_manager_extensions.rb +0 -39
  62. data/lib/foreman_inventory_upload/async/create_missing_insights_facets.rb +0 -30
  63. data/lib/foreman_inventory_upload/async/generate_host_report.rb +0 -20
  64. data/lib/foreman_inventory_upload/async/host_inventory_report_job.rb +0 -39
  65. data/lib/foreman_inventory_upload/async/single_host_report_job.rb +0 -20
  66. data/test/jobs/create_missing_insights_facets_test.rb +0 -151
  67. data/test/jobs/generate_host_report_test.rb +0 -100
  68. data/test/jobs/generate_report_job_test.rb +0 -146
  69. data/test/jobs/host_inventory_report_job_test.rb +0 -244
  70. data/test/jobs/queue_for_upload_job_test.rb +0 -65
  71. data/test/jobs/single_host_report_job_test.rb +0 -155
  72. data/test/unit/lib/foreman_rh_cloud/registration_manager_extensions_test.rb +0 -192
  73. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTotalRiskChart.test.js +0 -194
@@ -1,192 +0,0 @@
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
@@ -1,194 +0,0 @@
1
- import React from 'react';
2
- import { render, screen, waitFor } from '@testing-library/react';
3
- import '@testing-library/jest-dom';
4
- import { Provider } from 'react-redux';
5
- import { ConnectedRouter } from 'connected-react-router';
6
- import { createMemoryHistory } from 'history';
7
- import configureMockStore from 'redux-mock-store';
8
- import { STATUS } from 'foremanReact/constants';
9
- import * as APIHooks from 'foremanReact/common/hooks/API/APIHooks';
10
- import InsightsTotalRiskCard from '../InsightsTotalRiskChart';
11
-
12
- jest.mock('foremanReact/common/hooks/API/APIHooks');
13
- jest.mock('foremanReact/common/I18n', () => ({
14
- translate: jest.fn(str => str),
15
- }));
16
-
17
- const mockStore = configureMockStore();
18
- const history = createMemoryHistory();
19
- const store = mockStore({
20
- router: {
21
- location: {
22
- pathname: '/',
23
- search: '',
24
- hash: '',
25
- state: null,
26
- },
27
- action: 'POP',
28
- },
29
- });
30
-
31
- const defaultHostDetails = {
32
- id: 1,
33
- insights_attributes: {
34
- uuid: 'test-uuid',
35
- use_iop_mode: false,
36
- },
37
- };
38
-
39
- const renderComponent = (props = {}) => {
40
- const allProps = {
41
- hostDetails: defaultHostDetails,
42
- ...props,
43
- };
44
-
45
- return render(
46
- <Provider store={store}>
47
- <ConnectedRouter history={history}>
48
- <InsightsTotalRiskCard {...allProps} />
49
- </ConnectedRouter>
50
- </Provider>
51
- );
52
- };
53
-
54
- describe('InsightsTotalRiskChart', () => {
55
- beforeEach(() => {
56
- store.clearActions();
57
- jest.clearAllMocks();
58
- });
59
-
60
- it('should show loading state initially', () => {
61
- APIHooks.useAPI.mockReturnValue({
62
- status: STATUS.PENDING,
63
- response: null,
64
- });
65
-
66
- renderComponent();
67
- // SkeletonLoader shows loading state when status is PENDING
68
- expect(screen.queryByText('No results found')).not.toBeInTheDocument();
69
- expect(
70
- screen.queryByTestId('rh-cloud-total-risk-card')
71
- ).not.toBeInTheDocument();
72
- });
73
-
74
- it('should display error state when API fails', async () => {
75
- APIHooks.useAPI.mockReturnValue({
76
- status: STATUS.ERROR,
77
- response: null,
78
- });
79
-
80
- renderComponent();
81
- expect(screen.getByText('No results found')).toBeInTheDocument();
82
- expect(
83
- screen.queryByTestId('rh-cloud-total-risk-card')
84
- ).not.toBeInTheDocument();
85
- });
86
-
87
- it('should handle non-IoP mode API response correctly', async () => {
88
- const mockResponse = {
89
- hits: [
90
- { total_risk: 1 },
91
- { total_risk: 2 },
92
- { total_risk: 2 },
93
- { total_risk: 3 },
94
- { total_risk: 4 },
95
- ],
96
- };
97
-
98
- APIHooks.useAPI.mockReturnValue({
99
- status: STATUS.RESOLVED,
100
- response: mockResponse,
101
- });
102
-
103
- renderComponent();
104
-
105
- await waitFor(() => {
106
- // Check if total number of recommendations is displayed
107
- expect(screen.getByText('5')).toBeInTheDocument();
108
- // Check if risk levels are displayed correctly
109
- expect(screen.getByText(/Low: 1/)).toBeInTheDocument();
110
- expect(screen.getByText(/Moderate: 2/)).toBeInTheDocument();
111
- expect(screen.getByText(/Important: 1/)).toBeInTheDocument();
112
- expect(screen.getByText(/Critical: 1/)).toBeInTheDocument();
113
- });
114
- });
115
-
116
- it('should handle IOP mode API response correctly', async () => {
117
- const mockResponse = {
118
- low_hits: 2,
119
- moderate_hits: 3,
120
- important_hits: 1,
121
- critical_hits: 2,
122
- hits: 8,
123
- };
124
-
125
- APIHooks.useAPI.mockReturnValue({
126
- status: STATUS.RESOLVED,
127
- response: mockResponse,
128
- });
129
-
130
- renderComponent({
131
- hostDetails: {
132
- ...defaultHostDetails,
133
- insights_attributes: {
134
- ...defaultHostDetails.insights_attributes,
135
- use_iop_mode: true,
136
- },
137
- },
138
- });
139
-
140
- await waitFor(() => {
141
- // Check if total number of recommendations is displayed
142
- expect(screen.getByText('8')).toBeInTheDocument();
143
- // Check if risk levels are displayed correctly
144
- expect(screen.getByText(/Low: 2/)).toBeInTheDocument();
145
- expect(screen.getByText(/Moderate: 3/)).toBeInTheDocument();
146
- expect(screen.getByText(/Important: 1/)).toBeInTheDocument();
147
- expect(screen.getByText(/Critical: 2/)).toBeInTheDocument();
148
- });
149
- });
150
-
151
- it('should show empty state when no recommendations exist', async () => {
152
- APIHooks.useAPI.mockReturnValue({
153
- status: STATUS.RESOLVED,
154
- response: { hits: [] },
155
- });
156
-
157
- renderComponent();
158
-
159
- await waitFor(() => {
160
- expect(screen.getByText(/Low: 0/)).toBeInTheDocument();
161
- expect(screen.getByText(/Moderate: 0/)).toBeInTheDocument();
162
- expect(screen.getByText(/Important: 0/)).toBeInTheDocument();
163
- expect(screen.getByText(/Critical: 0/)).toBeInTheDocument();
164
- });
165
- });
166
-
167
- it('should use correct API endpoint based on IOP mode', () => {
168
- renderComponent({
169
- hostDetails: {
170
- ...defaultHostDetails,
171
- insights_attributes: {
172
- ...defaultHostDetails.insights_attributes,
173
- use_iop_mode: true,
174
- },
175
- },
176
- });
177
-
178
- expect(APIHooks.useAPI).toHaveBeenCalledWith(
179
- 'get',
180
- expect.stringContaining('/api/insights/v1/system/test-uuid'),
181
- expect.any(Object)
182
- );
183
-
184
- jest.clearAllMocks();
185
-
186
- renderComponent();
187
-
188
- expect(APIHooks.useAPI).toHaveBeenCalledWith(
189
- 'get',
190
- expect.stringContaining('/hits/1'),
191
- expect.any(Object)
192
- );
193
- });
194
- });