foreman_rh_cloud 12.2.13 → 12.2.15

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/foreman_rh_cloud/registration_manager_extensions.rb +2 -2
  3. data/app/controllers/concerns/insights_cloud/package_profile_upload_extensions.rb +3 -0
  4. data/app/controllers/foreman_inventory_upload/accounts_controller.rb +1 -1
  5. data/app/controllers/foreman_inventory_upload/uploads_controller.rb +1 -1
  6. data/app/controllers/insights_cloud/ui_requests_controller.rb +2 -3
  7. data/app/models/concerns/rh_cloud_host.rb +14 -0
  8. data/app/models/foreman_rh_cloud/ping.rb +2 -1
  9. data/app/services/foreman_rh_cloud/tags_auth.rb +13 -3
  10. data/app/views/api/v2/advisor_engine/host_details.json.rabl +1 -3
  11. data/app/views/api/v2/hosts/insights/base.rabl +3 -2
  12. data/lib/foreman_inventory_upload/async/queue_for_upload_job.rb +1 -23
  13. data/lib/foreman_inventory_upload/async/upload_report_direct_job.rb +200 -0
  14. data/lib/foreman_inventory_upload.rb +0 -4
  15. data/lib/foreman_rh_cloud/plugin.rb +11 -4
  16. data/lib/foreman_rh_cloud/version.rb +1 -1
  17. data/lib/foreman_rh_cloud.rb +3 -3
  18. data/lib/insights_cloud/async/connector_playbook_execution_reporter_task.rb +3 -3
  19. data/lib/inventory_sync/async/inventory_hosts_sync.rb +0 -2
  20. data/package.json +1 -1
  21. data/test/controllers/accounts_controller_test.rb +1 -1
  22. data/test/controllers/insights_cloud/api/advisor_engine_controller_test.rb +28 -1
  23. data/test/controllers/insights_cloud/ui_requests_controller_test.rb +26 -0
  24. data/test/controllers/uploads_controller_test.rb +1 -1
  25. data/test/factories/insights_factories.rb +29 -0
  26. data/test/jobs/queue_for_upload_job_test.rb +1 -12
  27. data/test/jobs/upload_report_direct_job_test.rb +399 -0
  28. data/test/unit/foreman_rh_cloud_iop_metadata_test.rb +200 -0
  29. data/test/unit/lib/foreman_rh_cloud/registration_manager_extensions_test.rb +4 -42
  30. data/test/unit/rh_cloud_host_test.rb +191 -0
  31. data/test/unit/services/foreman_rh_cloud/tags_auth_test.rb +14 -0
  32. data/webpack/ForemanColumnExtensions/index.js +2 -0
  33. data/webpack/ForemanInventoryUpload/Components/PageHeader/PageHeader.js +24 -17
  34. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/PageHeader.test.js +178 -8
  35. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +1 -1
  36. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/ToolbarButtons/ToolbarButtons.js +3 -1
  37. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/ToolbarButtons/__tests__/ToolbarButtons.test.js +69 -51
  38. data/webpack/ForemanInventoryUpload/ForemanInventoryHelpers.js +1 -1
  39. data/webpack/ForemanInventoryUpload/__tests__/__snapshots__/ForemanInventoryHelpers.test.js.snap +1 -1
  40. data/webpack/InsightsCloudSync/Components/InsightsSettings/InsightsSettings.js +3 -3
  41. data/webpack/InsightsCloudSync/Components/InsightsTable/InsightsTable.js +3 -9
  42. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/InsightsTable.test.js +24 -4
  43. data/webpack/InsightsCloudSync/Components/RemediationModal/RemediationModal.js +2 -2
  44. data/webpack/InsightsCloudSync/Components/ToolbarDropdown.js +3 -3
  45. data/webpack/InsightsCloudSync/InsightsCloudSync.js +3 -3
  46. data/webpack/InsightsCloudSync/InsightsCloudSync.test.js +10 -0
  47. data/webpack/InsightsCloudSync/__snapshots__/InsightsCloudSync.test.js.snap +1 -1
  48. data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +5 -5
  49. data/webpack/InsightsVulnerabilityHostIndexExtensions/CVECountCell.js +2 -2
  50. data/webpack/InsightsVulnerabilityHostIndexExtensions/__tests__/CVECountCell.test.js +77 -22
  51. data/webpack/common/Hooks/ConfigHooks.js +3 -16
  52. metadata +9 -9
  53. data/lib/foreman_inventory_upload/async/upload_report_job.rb +0 -97
  54. data/lib/foreman_inventory_upload/scripts/uploader.sh.erb +0 -55
  55. data/test/jobs/upload_report_job_test.rb +0 -38
  56. data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageHeader.test.js.snap +0 -36
  57. data/webpack/InsightsCloudSync/Components/InsightsTable/__tests__/__snapshots__/InsightsTable.test.js.snap +0 -112
  58. data/webpack/__mocks__/foremanReact/common/hooks/API/APIHooks.js +0 -3
@@ -0,0 +1,191 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class RhCloudHostTest < ActiveSupport::TestCase
4
+ setup do
5
+ @org = FactoryBot.create(:organization)
6
+ end
7
+
8
+ teardown do
9
+ ForemanRhCloud.unstub(:with_iop_smart_proxy?)
10
+ end
11
+
12
+ context 'insights_uuid method' do
13
+ test 'returns insights_facet uuid in non-IoP mode' do
14
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
15
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
16
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'insights-123')
17
+
18
+ assert_equal 'insights-123', @host.insights_uuid
19
+ assert_not_equal @host.subscription_facet.uuid, @host.insights_uuid
20
+ end
21
+
22
+ test 'returns subscription_facet uuid in IoP mode' do
23
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
24
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
25
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'insights-456')
26
+
27
+ assert_equal @host.subscription_facet.uuid, @host.insights_uuid
28
+ assert_not_equal 'insights-456', @host.insights_uuid
29
+ end
30
+
31
+ test 'returns nil when insights_facet missing in non-IoP mode' do
32
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
33
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
34
+
35
+ assert_nil @host.insights_uuid
36
+ end
37
+
38
+ test 'returns nil when subscription_facet missing in IoP mode' do
39
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
40
+ @host = FactoryBot.create(:host, :managed, organization: @org)
41
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'insights-789')
42
+
43
+ assert_nil @host.insights_uuid
44
+ end
45
+
46
+ test 'returns nil when both facets missing' do
47
+ @host = FactoryBot.create(:host, :managed, organization: @org)
48
+
49
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
50
+ assert_nil @host.insights_uuid
51
+
52
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
53
+ assert_nil @host.insights_uuid
54
+ end
55
+
56
+ test 'never returns stale insights_facet uuid in IoP mode' do
57
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
58
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
59
+ current_uuid = @host.subscription_facet.uuid
60
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'stale-456')
61
+
62
+ # Should return subscription_facet UUID, never the stale insights_facet UUID
63
+ assert_equal current_uuid, @host.insights_uuid
64
+ assert_not_equal 'stale-456', @host.insights_uuid
65
+
66
+ # Verify multiple calls always return subscription_facet UUID
67
+ 3.times do
68
+ assert_equal current_uuid, @host.insights_uuid
69
+ end
70
+ end
71
+
72
+ test 'dynamically responds to IoP mode changes' do
73
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
74
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'insights-123')
75
+ subscription_uuid = @host.subscription_facet.uuid
76
+
77
+ # Non-IoP mode: should return insights_facet UUID
78
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
79
+ assert_equal 'insights-123', @host.insights_uuid
80
+
81
+ # IoP mode: should return subscription_facet UUID
82
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
83
+ assert_equal subscription_uuid, @host.insights_uuid
84
+
85
+ # Toggle back to non-IoP mode
86
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
87
+ assert_equal 'insights-123', @host.insights_uuid
88
+ end
89
+ end
90
+
91
+ context 'ensure_iop_insights_uuid method' do
92
+ test 'updates insights_facet uuid when different from subscription_facet' do
93
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
94
+ correct_uuid = @host.subscription_facet.uuid
95
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'wrong-456')
96
+
97
+ assert_equal 'wrong-456', @host.insights_facet.uuid
98
+
99
+ @host.ensure_iop_insights_uuid
100
+
101
+ assert_equal correct_uuid, @host.insights_facet.reload.uuid
102
+ end
103
+
104
+ test 'does nothing when uuids already match' do
105
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
106
+ matching_uuid = @host.subscription_facet.uuid
107
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: matching_uuid)
108
+
109
+ # Expect no update call since UUIDs already match
110
+ @host.insights_facet.expects(:update!).never
111
+
112
+ @host.ensure_iop_insights_uuid
113
+
114
+ assert_equal matching_uuid, @host.insights_facet.uuid
115
+ end
116
+
117
+ test 'does nothing when insights_facet missing' do
118
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
119
+
120
+ assert_nothing_raised do
121
+ @host.ensure_iop_insights_uuid
122
+ end
123
+ end
124
+
125
+ test 'does nothing when subscription_facet missing' do
126
+ @host = FactoryBot.create(:host, :managed, organization: @org)
127
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'insights-999')
128
+ original_uuid = @host.insights_facet.uuid
129
+
130
+ assert_nothing_raised do
131
+ @host.ensure_iop_insights_uuid
132
+ end
133
+
134
+ assert_equal original_uuid, @host.insights_facet.uuid
135
+ end
136
+
137
+ test 'does nothing when both facets missing' do
138
+ @host = FactoryBot.create(:host, :managed, organization: @org)
139
+
140
+ assert_nothing_raised do
141
+ @host.ensure_iop_insights_uuid
142
+ end
143
+ end
144
+
145
+ test 'handles nil uuids gracefully' do
146
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
147
+
148
+ # Scenario 1: subscription_facet uuid is nil (shouldn't happen but test gracefully)
149
+ @host.subscription_facet.update(uuid: nil)
150
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'some-uuid')
151
+
152
+ assert_nothing_raised do
153
+ @host.ensure_iop_insights_uuid
154
+ end
155
+
156
+ # Scenario 2: insights_facet uuid is nil
157
+ @host.subscription_facet.update(uuid: 'valid-uuid')
158
+ @host.insights_facet.update(uuid: nil)
159
+
160
+ assert_nothing_raised do
161
+ @host.ensure_iop_insights_uuid
162
+ end
163
+
164
+ # Should update to match subscription_facet
165
+ assert_equal 'valid-uuid', @host.insights_facet.reload.uuid
166
+ end
167
+
168
+ test 'corrects stale uuid after cloud registration' do
169
+ # Simulate a host that was previously registered to cloud with cloud-assigned UUID
170
+ @host = FactoryBot.create(:host, :managed, :with_subscription, organization: @org)
171
+ local_uuid = @host.subscription_facet.uuid
172
+ @host.insights = FactoryBot.create(:insights_facet, host_id: @host.id, uuid: 'cloud-456')
173
+
174
+ # Before sync: insights_facet has stale cloud UUID
175
+ assert_equal 'cloud-456', @host.insights_facet.uuid
176
+
177
+ # In IoP mode, insights_uuid should return subscription_facet UUID (not stale)
178
+ ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
179
+ assert_equal local_uuid, @host.insights_uuid
180
+
181
+ # Call sync to correct the stale UUID
182
+ @host.ensure_iop_insights_uuid
183
+
184
+ # After sync: insights_facet UUID should match subscription_facet UUID
185
+ assert_equal local_uuid, @host.insights_facet.reload.uuid
186
+
187
+ # Verify insights_uuid still returns correct value
188
+ assert_equal local_uuid, @host.insights_uuid
189
+ end
190
+ end
191
+ end
@@ -40,4 +40,18 @@ class TagsAuthTest < ActiveSupport::TestCase
40
40
 
41
41
  @auth.update_tag
42
42
  end
43
+
44
+ test 'Generates tags with wildcard location when location is nil' do
45
+ auth_with_nil_loc = ::ForemanRhCloud::TagsAuth.new(@user, @org, nil, @logger)
46
+ uuid1 = 'test_uuid1'
47
+
48
+ auth_with_nil_loc.expects(:allowed_hosts).returns([uuid1])
49
+ auth_with_nil_loc.expects(:execute_cloud_request).with do |actual_params|
50
+ actual = JSON.parse(actual_params[:payload])
51
+ assert_includes actual['host_id_list'], uuid1
52
+ assert_equal "U:\"#{@user.login}\"O:\"#{@org.name}\"L:\"*\"", actual['tags'].first['value']
53
+ end
54
+
55
+ auth_with_nil_loc.update_tag
56
+ end
43
57
  end
@@ -79,6 +79,8 @@ const hostsIndexColumnExtensions = [
79
79
  categoryName: insightsCategoryName,
80
80
  categoryKey: 'insights',
81
81
  isSorted: false,
82
+ // eslint-disable-next-line camelcase
83
+ isRelevant: contextData => contextData?.metadata?.foreman_rh_cloud?.iop,
82
84
  },
83
85
  ];
84
86
 
@@ -6,26 +6,33 @@ import InventoryFilter from '../InventoryFilter';
6
6
  import ToolbarButtons from './components/ToolbarButtons';
7
7
  import SettingsWarning from './components/SettingsWarning';
8
8
  import PageTitle from './PageTitle';
9
+ import { useIopConfig } from '../../../common/Hooks/ConfigHooks';
9
10
  import './PageHeader.scss';
10
11
 
11
- const PageHeader = () => (
12
- <div className="inventory-upload-header">
13
- <SettingsWarning />
14
- <PageTitle />
15
- <div className="inventory-upload-header-description">
16
- <InventorySettings />
17
- <PageDescription />
12
+ const PageHeader = () => {
13
+ const isIop = useIopConfig();
14
+
15
+ return (
16
+ <div className="inventory-upload-header">
17
+ <SettingsWarning />
18
+ <PageTitle />
19
+ {!isIop && (
20
+ <div className="inventory-upload-header-description">
21
+ <InventorySettings />
22
+ <PageDescription />
23
+ </div>
24
+ )}
25
+ <Grid.Row>
26
+ <Grid.Col xs={4}>
27
+ <InventoryFilter />
28
+ </Grid.Col>
29
+ <Grid.Col xs={7} xsOffset={1}>
30
+ <ToolbarButtons />
31
+ </Grid.Col>
32
+ </Grid.Row>
18
33
  </div>
19
- <Grid.Row>
20
- <Grid.Col xs={4}>
21
- <InventoryFilter />
22
- </Grid.Col>
23
- <Grid.Col xs={7} xsOffset={1}>
24
- <ToolbarButtons />
25
- </Grid.Col>
26
- </Grid.Row>
27
- </div>
28
- );
34
+ );
35
+ };
29
36
 
30
37
  PageHeader.propTypes = {};
31
38
 
@@ -1,13 +1,183 @@
1
- import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
2
-
1
+ import React from 'react';
2
+ import { screen } from '@testing-library/react';
3
+ import { rtlHelpers } from 'foremanReact/common/rtlTestHelpers';
3
4
  import PageHeader from '../PageHeader';
4
5
 
5
- const fixtures = {
6
- 'render without Props': {},
7
- /** fixtures, props for the component */
8
- };
6
+ // Create a variable to control IoP mode in tests
7
+ let mockIopMode = false;
8
+
9
+ // Mock ForemanContext
10
+ jest.mock('foremanReact/Root/Context/ForemanContext', () => ({
11
+ useForemanContext: () => ({
12
+ metadata: {
13
+ foreman_rh_cloud: {
14
+ iop: mockIopMode,
15
+ },
16
+ },
17
+ UI: {},
18
+ }),
19
+ }));
20
+
21
+ // Mock child components to isolate PageHeader testing
22
+ // This prevents child component complexity from affecting our tests
23
+ jest.mock('../components/SettingsWarning', () => () => (
24
+ <div data-testid="settings-warning">SettingsWarning</div>
25
+ ));
26
+ jest.mock('../PageTitle', () => () => (
27
+ <div data-testid="page-title">PageTitle</div>
28
+ ));
29
+ jest.mock('../../InventorySettings', () => () => (
30
+ <div data-testid="inventory-settings">InventorySettings</div>
31
+ ));
32
+ jest.mock('../components/PageDescription', () => () => (
33
+ <div data-testid="page-description">PageDescription</div>
34
+ ));
35
+ jest.mock('../../InventoryFilter', () => () => (
36
+ <div data-testid="inventory-filter">InventoryFilter</div>
37
+ ));
38
+ jest.mock('../components/ToolbarButtons', () => () => (
39
+ <div data-testid="toolbar-buttons">ToolbarButtons</div>
40
+ ));
41
+
42
+ const { renderWithStore } = rtlHelpers;
9
43
 
10
44
  describe('PageHeader', () => {
11
- describe('rendering', () =>
12
- testComponentSnapshotsWithFixtures(PageHeader, fixtures));
45
+ describe('component behavior', () => {
46
+ test('renders all components when not in IoP mode', () => {
47
+ mockIopMode = false; // Ensure IoP mode is disabled for this test
48
+
49
+ renderWithStore(<PageHeader />, {
50
+ API: {
51
+ INVENTORY_SETTINGS: {
52
+ response: { subscriptionConnectionEnabled: true },
53
+ },
54
+ ADVISOR_ENGINE_CONFIG: {
55
+ response: { use_iop_mode: false },
56
+ status: 'RESOLVED',
57
+ },
58
+ },
59
+ });
60
+
61
+ // All components should be present when not in IoP mode
62
+ expect(screen.getByTestId('settings-warning')).toBeTruthy();
63
+ expect(screen.getByTestId('page-title')).toBeTruthy();
64
+ expect(screen.getByTestId('inventory-settings')).toBeTruthy();
65
+ expect(screen.getByTestId('page-description')).toBeTruthy();
66
+ expect(screen.getByTestId('inventory-filter')).toBeTruthy();
67
+ expect(screen.getByTestId('toolbar-buttons')).toBeTruthy();
68
+ });
69
+
70
+ test('hides inventory settings and description when in IoP mode', () => {
71
+ mockIopMode = true; // Enable IoP mode for this test
72
+
73
+ renderWithStore(<PageHeader />, {
74
+ API: {
75
+ INVENTORY_SETTINGS: {
76
+ response: { subscriptionConnectionEnabled: true },
77
+ },
78
+ ADVISOR_ENGINE_CONFIG: {
79
+ response: { use_iop_mode: true },
80
+ status: 'RESOLVED',
81
+ },
82
+ },
83
+ });
84
+
85
+ // Core components should still be present
86
+ expect(screen.getByTestId('settings-warning')).toBeTruthy();
87
+ expect(screen.getByTestId('page-title')).toBeTruthy();
88
+ expect(screen.getByTestId('inventory-filter')).toBeTruthy();
89
+ expect(screen.getByTestId('toolbar-buttons')).toBeTruthy();
90
+
91
+ // These components should be hidden in IoP mode
92
+ expect(screen.queryByTestId('inventory-settings')).toBeNull();
93
+ expect(screen.queryByTestId('page-description')).toBeNull();
94
+ });
95
+
96
+ test('renders with correct CSS class', () => {
97
+ mockIopMode = false; // Ensure IoP mode is disabled for this test
98
+
99
+ const { container } = renderWithStore(<PageHeader />, {
100
+ API: {
101
+ INVENTORY_SETTINGS: {
102
+ response: { subscriptionConnectionEnabled: true },
103
+ },
104
+ ADVISOR_ENGINE_CONFIG: {
105
+ response: { use_iop_mode: false },
106
+ status: 'RESOLVED',
107
+ },
108
+ },
109
+ });
110
+
111
+ expect(container.querySelector('.inventory-upload-header')).toBeTruthy();
112
+ });
113
+
114
+ test('renders grid layout with correct structure', () => {
115
+ mockIopMode = false; // Ensure IoP mode is disabled for this test
116
+
117
+ const { container } = renderWithStore(<PageHeader />, {
118
+ API: {
119
+ INVENTORY_SETTINGS: {
120
+ response: { subscriptionConnectionEnabled: true },
121
+ },
122
+ ADVISOR_ENGINE_CONFIG: {
123
+ response: { use_iop_mode: false },
124
+ status: 'RESOLVED',
125
+ },
126
+ },
127
+ });
128
+
129
+ const gridRow = container.querySelector('.row');
130
+ expect(gridRow).toBeTruthy();
131
+
132
+ const filterColumn = container.querySelector('.col-xs-4');
133
+ expect(filterColumn).toBeTruthy();
134
+
135
+ const toolbarColumn = container.querySelector('.col-xs-7');
136
+ expect(toolbarColumn).toBeTruthy();
137
+ });
138
+
139
+ test('renders description section only when not in IoP mode', () => {
140
+ mockIopMode = false; // Ensure IoP mode is disabled for this test
141
+
142
+ const { container } = renderWithStore(<PageHeader />, {
143
+ API: {
144
+ INVENTORY_SETTINGS: {
145
+ response: { subscriptionConnectionEnabled: true },
146
+ },
147
+ ADVISOR_ENGINE_CONFIG: {
148
+ response: { use_iop_mode: false },
149
+ status: 'RESOLVED',
150
+ },
151
+ },
152
+ });
153
+
154
+ // Description section should be present when not in IoP mode
155
+ const descriptionSection = container.querySelector(
156
+ '.inventory-upload-header-description'
157
+ );
158
+ expect(descriptionSection).toBeTruthy();
159
+ });
160
+
161
+ test('does not render description section when in IoP mode', () => {
162
+ mockIopMode = true; // Enable IoP mode for this test
163
+
164
+ const { container } = renderWithStore(<PageHeader />, {
165
+ API: {
166
+ INVENTORY_SETTINGS: {
167
+ response: { subscriptionConnectionEnabled: true },
168
+ },
169
+ ADVISOR_ENGINE_CONFIG: {
170
+ response: { use_iop_mode: true },
171
+ status: 'RESOLVED',
172
+ },
173
+ },
174
+ });
175
+
176
+ // Description section should not be present in IoP mode
177
+ const descriptionSection = container.querySelector(
178
+ '.inventory-upload-header-description'
179
+ );
180
+ expect(descriptionSection).toBeNull();
181
+ });
182
+ });
13
183
  });
@@ -32,7 +32,7 @@ exports[`PageTitle rendering render without Props 1`] = `
32
32
  Actions history
33
33
  </DropdownItem>,
34
34
  <DropdownItem
35
- href="/links/manual/?root_url=https%3A%2F%2Faccess.redhat.com%2Fdocumentation%2Fen-us%2Fred_hat_insights%2F2023%2Fhtml%2Fred_hat_insights_remediations_guide%2Fhost-communication-with-insights_red-hat-insights-remediation-guide%23uploading-satellite-host-inventory-to-insights_configuring-satellite-cloud-connector"
35
+ href="/links/manual/?root_url=https%3A%2F%2Fdocs.redhat.com%2Fen%2Fdocumentation%2Fred_hat_lightspeed%2F1-latest%2Fhtml-single%2Fred_hat_lightspeed_remediations_guide%2Findex"
36
36
  ouiaId="inventory-documentation-button"
37
37
  rel="noopener noreferrer"
38
38
  target="_blank"
@@ -4,11 +4,13 @@ import SyncButton from '../SyncButton';
4
4
  import CloudConnectorButton from '../CloudConnectorButton';
5
5
  import './toolbarButtons.scss';
6
6
  import { selectSubscriptionConnectionEnabled } from '../../../InventorySettings/InventorySettingsSelectors';
7
+ import { useIopConfig } from '../../../../../common/Hooks/ConfigHooks';
7
8
 
8
9
  const ToolbarButtons = () => {
9
10
  const subscriptionConnectionEnabled = useSelector(
10
11
  selectSubscriptionConnectionEnabled
11
12
  );
13
+ const isIop = useIopConfig();
12
14
 
13
15
  if (!subscriptionConnectionEnabled) {
14
16
  return null;
@@ -16,7 +18,7 @@ const ToolbarButtons = () => {
16
18
 
17
19
  return (
18
20
  <div className="inventory_toolbar_buttons">
19
- <CloudConnectorButton />
21
+ {!isIop && <CloudConnectorButton />}
20
22
  <SyncButton />
21
23
  </div>
22
24
  );
@@ -1,60 +1,78 @@
1
1
  import React from 'react';
2
- import { Provider } from 'react-redux';
3
- import configureMockStore from 'redux-mock-store';
4
- import thunk from 'redux-thunk';
5
- import { screen, render } from '@testing-library/react';
2
+ import { screen } from '@testing-library/react';
3
+ import { rtlHelpers } from 'foremanReact/common/rtlTestHelpers';
6
4
  import ToolbarButtons from '../ToolbarButtons';
5
+ import { useIopConfig } from '../../../../../../common/Hooks/ConfigHooks';
6
+ import { selectSubscriptionConnectionEnabled } from '../../../../InventorySettings/InventorySettingsSelectors';
7
7
 
8
- const middlewares = [thunk];
9
- const mockStore = configureMockStore(middlewares);
10
-
11
- const renderOptions = {
12
- API: {
13
- INVENTORY_SETTINGS: {
14
- response: { subscriptionConnectionEnabled: true },
15
- },
16
- },
17
- ForemanRhCloud: {
18
- inventoryUpload: {
19
- accountsList: {
20
- CloudConnectorStatus: {},
21
- },
22
- },
23
- },
24
- };
8
+ // Mock the config hook
9
+ jest.mock('../../../../../../common/Hooks/ConfigHooks', () => ({
10
+ useIopConfig: jest.fn(),
11
+ }));
12
+
13
+ // Mock the selector
14
+ jest.mock('../../../../InventorySettings/InventorySettingsSelectors', () => ({
15
+ selectSubscriptionConnectionEnabled: jest.fn(),
16
+ }));
17
+
18
+ // Mock child components to isolate ToolbarButtons testing
19
+ jest.mock(
20
+ '../../SyncButton',
21
+ () =>
22
+ function MockSyncButton() {
23
+ return <div data-testid="sync-button">Sync all inventory status</div>;
24
+ }
25
+ );
26
+ jest.mock(
27
+ '../../CloudConnectorButton',
28
+ () =>
29
+ function MockCloudConnectorButton() {
30
+ return (
31
+ <div data-testid="cloud-connector-button">
32
+ Configure cloud connector
33
+ </div>
34
+ );
35
+ }
36
+ );
37
+
38
+ const { renderWithStore } = rtlHelpers;
25
39
 
26
40
  describe('ToolbarButtons', () => {
27
- test('when subscription connection is enabled', () => {
28
- const store = mockStore(renderOptions);
29
-
30
- render(
31
- <Provider store={store}>
32
- <ToolbarButtons />
33
- </Provider>
34
- );
35
- expect(screen.queryAllByText('Configure cloud connector')).toHaveLength(1);
36
- expect(screen.queryAllByText('Sync all inventory status')).toHaveLength(1);
41
+ test('renders both buttons when subscription connection is enabled and not in IOP mode', () => {
42
+ useIopConfig.mockReturnValue(false);
43
+ selectSubscriptionConnectionEnabled.mockReturnValue(true);
44
+
45
+ renderWithStore(<ToolbarButtons />);
46
+
47
+ expect(screen.getByTestId('cloud-connector-button')).toBeTruthy();
48
+ expect(screen.getByTestId('sync-button')).toBeTruthy();
37
49
  });
38
50
 
39
- test('when subscription connection is not enabled', () => {
40
- const localSetting = {
41
- API: {
42
- INVENTORY_SETTINGS: {
43
- response: { subscriptionConnectionEnabled: false },
44
- },
45
- },
46
- };
47
- const store = mockStore({
48
- ...renderOptions,
49
- ...localSetting,
50
- });
51
-
52
- render(
53
- <Provider store={store}>
54
- <ToolbarButtons />
55
- </Provider>
56
- );
57
- expect(screen.queryAllByText('Configure cloud connector')).toHaveLength(0);
58
- expect(screen.queryAllByText('Sync all inventory status')).toHaveLength(0);
51
+ test('renders only sync button when in IOP mode', () => {
52
+ useIopConfig.mockReturnValue(true);
53
+ selectSubscriptionConnectionEnabled.mockReturnValue(true);
54
+
55
+ renderWithStore(<ToolbarButtons />);
56
+
57
+ expect(screen.queryByTestId('cloud-connector-button')).toBeNull();
58
+ expect(screen.getByTestId('sync-button')).toBeTruthy();
59
+ });
60
+
61
+ test('renders nothing when subscription connection is not enabled', () => {
62
+ useIopConfig.mockReturnValue(false);
63
+ selectSubscriptionConnectionEnabled.mockReturnValue(false);
64
+
65
+ const { container } = renderWithStore(<ToolbarButtons />);
66
+
67
+ expect(container.firstChild).toBeNull();
68
+ });
69
+
70
+ test('renders toolbar buttons container with correct className when enabled', () => {
71
+ useIopConfig.mockReturnValue(false);
72
+ selectSubscriptionConnectionEnabled.mockReturnValue(true);
73
+
74
+ const { container } = renderWithStore(<ToolbarButtons />);
75
+
76
+ expect(container.querySelector('.inventory_toolbar_buttons')).toBeTruthy();
59
77
  });
60
78
  });
@@ -7,7 +7,7 @@ export const inventoryUrl = path =>
7
7
  export const getInventoryDocsUrl = () =>
8
8
  foremanUrl(
9
9
  `/links/manual/?root_url=${URI.encode(
10
- 'https://access.redhat.com/documentation/en-us/red_hat_insights/2023/html/red_hat_insights_remediations_guide/host-communication-with-insights_red-hat-insights-remediation-guide#uploading-satellite-host-inventory-to-insights_configuring-satellite-cloud-connector'
10
+ 'https://docs.redhat.com/en/documentation/red_hat_lightspeed/1-latest/html-single/red_hat_lightspeed_remediations_guide/index'
11
11
  )}`
12
12
  );
13
13
 
@@ -2,4 +2,4 @@
2
2
 
3
3
  exports[`ForemanInventoryUpload helpers should return inventory Url 1`] = `"/foreman_inventory_upload/test_path"`;
4
4
 
5
- exports[`ForemanInventoryUpload helpers should return inventory docs url 1`] = `"/links/manual/?root_url=https%3A%2F%2Faccess.redhat.com%2Fdocumentation%2Fen-us%2Fred_hat_insights%2F2023%2Fhtml%2Fred_hat_insights_remediations_guide%2Fhost-communication-with-insights_red-hat-insights-remediation-guide%23uploading-satellite-host-inventory-to-insights_configuring-satellite-cloud-connector"`;
5
+ exports[`ForemanInventoryUpload helpers should return inventory docs url 1`] = `"/links/manual/?root_url=https%3A%2F%2Fdocs.redhat.com%2Fen%2Fdocumentation%2Fred_hat_lightspeed%2F1-latest%2Fhtml-single%2Fred_hat_lightspeed_remediations_guide%2Findex"`;
@@ -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 { useAdvisorEngineConfig } from '../../../common/Hooks/ConfigHooks';
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 isLocalAdvisorEngine = useAdvisorEngineConfig();
13
+ const isIop = useIopConfig();
14
14
  useEffect(() => {
15
15
  getInsightsSyncSettings();
16
16
  }, [getInsightsSyncSettings]);
17
17
 
18
- if (isLocalAdvisorEngine) return null;
18
+ if (isIop) return null;
19
19
 
20
20
  return (
21
21
  <div className="insights_settings">