foreman_rh_cloud 14.5.0 → 14.6.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.
- checksums.yaml +4 -4
- data/app/services/foreman_rh_cloud/cert_auth.rb +2 -1
- data/app/services/foreman_rh_cloud/cloud_request.rb +2 -1
- data/app/services/foreman_rh_cloud/cloud_request_forwarder.rb +9 -5
- data/lib/foreman_rh_cloud/plugin.rb +1 -0
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/foreman_rh_cloud.rb +16 -0
- data/package.json +1 -1
- data/test/unit/foreman_rh_cloud_iop_metadata_test.rb +27 -0
- data/test/unit/services/foreman_rh_cloud/cloud_request_forwarder_test.rb +28 -0
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/components/__tests__/Toast.test.js +62 -61
- data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabIntegration.test.js +69 -8
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6c5686d5268a4028cc883b95daa1948748a56a41cb54495668a4170cd1fcaab9
|
|
4
|
+
data.tar.gz: 533e44e09c87944392c120d57cc34e9244fbe3cf176dddb6c8d7ab7334ce4f92
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ca9d76abf073cb2f31f74822d45c40d18f6f735f2d6251d67c3ebae1bec9d26c33fe6c9098e8bb6f1b21f922003eaecbfe0da7249111e28ea4cd0f04e0d25138
|
|
7
|
+
data.tar.gz: cbe8078e2ef86cde32ad7feef2c0dd19850de71cefec7aa61939d71605d749e0ad18225492c160b5f5d57ba15bea691f0af0a5978e5300979e4858bc959b0e72
|
|
@@ -11,8 +11,9 @@ module ForemanRhCloud
|
|
|
11
11
|
|
|
12
12
|
def execute_cloud_request(params)
|
|
13
13
|
organization = params.delete(:organization)
|
|
14
|
+
force_cloud = params[:force_cloud]
|
|
14
15
|
# Cache the value of with_iop_smart_proxy? to avoid multiple calls to the database
|
|
15
|
-
with_iop_smart_proxy = ForemanRhCloud.with_iop_smart_proxy?
|
|
16
|
+
with_iop_smart_proxy = ForemanRhCloud.with_iop_smart_proxy? && !force_cloud
|
|
16
17
|
certs = with_iop_smart_proxy ? foreman_certificate : candlepin_id_cert(organization)
|
|
17
18
|
default_params = {
|
|
18
19
|
ssl_client_cert: OpenSSL::X509::Certificate.new(certs[:cert]),
|
|
@@ -3,12 +3,13 @@ module ForemanRhCloud
|
|
|
3
3
|
extend ActiveSupport::Concern
|
|
4
4
|
|
|
5
5
|
def execute_cloud_request(params)
|
|
6
|
+
force_cloud = params.delete(:force_cloud)
|
|
6
7
|
final_params = {
|
|
7
8
|
verify_ssl: ForemanRhCloud.verify_ssl_method,
|
|
8
9
|
proxy: ForemanRhCloud.transformed_http_proxy_string,
|
|
9
10
|
}.deep_merge(params)
|
|
10
11
|
|
|
11
|
-
if ForemanRhCloud.with_iop_smart_proxy?
|
|
12
|
+
if ForemanRhCloud.with_iop_smart_proxy? && !force_cloud
|
|
12
13
|
final_params[:ssl_ca_file] ||= ForemanRhCloud.ca_cert
|
|
13
14
|
end
|
|
14
15
|
|
|
@@ -36,8 +36,9 @@ module ForemanRhCloud
|
|
|
36
36
|
}
|
|
37
37
|
requested_url = original_request.original_fullpath.end_with?('/') ? original_request.path + '/' : original_request.path
|
|
38
38
|
params = path_params(requested_url)
|
|
39
|
+
force_cloud = params[:force_cloud]
|
|
39
40
|
|
|
40
|
-
if ForemanRhCloud.with_iop_smart_proxy?
|
|
41
|
+
if ForemanRhCloud.with_iop_smart_proxy? && !force_cloud
|
|
41
42
|
params[:ssl_ca_file] = ForemanRhCloud.ca_cert
|
|
42
43
|
end
|
|
43
44
|
|
|
@@ -70,10 +71,13 @@ module ForemanRhCloud
|
|
|
70
71
|
|
|
71
72
|
def path_params(request_path)
|
|
72
73
|
case request_path
|
|
73
|
-
when
|
|
74
|
+
when lightspeed_cla?
|
|
75
|
+
force_cloud = ForemanRhCloud.with_iop_smart_proxy? && Setting[:force_cla_connection]
|
|
74
76
|
{
|
|
75
|
-
url: ForemanRhCloud.
|
|
76
|
-
|
|
77
|
+
url: ForemanRhCloud.cloud_cert_base_url + request_path,
|
|
78
|
+
force_cloud: force_cloud,
|
|
79
|
+
proxy: (force_cloud ? ForemanRhCloud.transformed_cloud_http_proxy_string : nil),
|
|
80
|
+
}.compact
|
|
77
81
|
when platform_request?
|
|
78
82
|
{
|
|
79
83
|
url: ForemanRhCloud.cert_base_url + request_path.sub('/redhat_access/r/insights/platform', '/api'),
|
|
@@ -104,7 +108,7 @@ module ForemanRhCloud
|
|
|
104
108
|
"for=\"_#{host.subscription_facet.uuid}\""
|
|
105
109
|
end
|
|
106
110
|
|
|
107
|
-
def
|
|
111
|
+
def lightspeed_cla?
|
|
108
112
|
->(request_path) { request_path.include? '/lightspeed' }
|
|
109
113
|
end
|
|
110
114
|
|
|
@@ -22,6 +22,7 @@ module ForemanRhCloud
|
|
|
22
22
|
setting('include_parameter_tags', type: :boolean, description: N_('Should import include parameter tags from Foreman? Ignored when using local Insights.'), default: false, full_name: N_('Include parameters in insights-client reports'))
|
|
23
23
|
setting('rhc_instance_id', type: :string, description: N_('RHC daemon id. Ignored when using local Insights.'), default: nil, full_name: N_('ID of the RHC(Yggdrasil) daemon'))
|
|
24
24
|
setting('insights_minimal_data_collection', type: :boolean, default: false, full_name: N_('Minimal data collection'), description: N_('Only include the minimum required data in inventory reports for uploading to Red Hat cloud. When this is true, installed packages are excluded from the report regardless of the exclude_installed_packages setting, and host names and IPv4 addresses are excluded from the report regardless of obfuscation settings. Ignored when using local Insights.'))
|
|
25
|
+
setting('force_cla_connection', type: :boolean, default: false, full_name: N_('Force RHEL Lightspeed CLA connection'), description: N_('Forward requests to Lightspeed CLA even when in IoP mode. Ignored when IoP mode is off.'))
|
|
25
26
|
end
|
|
26
27
|
end
|
|
27
28
|
|
data/lib/foreman_rh_cloud.rb
CHANGED
|
@@ -21,6 +21,14 @@ module ForemanRhCloud
|
|
|
21
21
|
env_or_on_premise_url('SATELLITE_CERT_RH_CLOUD_URL') || 'https://cert.cloud.redhat.com'
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
# Lightspeed/CLA is cloud-only. Use the cloud URL only when the admin
|
|
25
|
+
# enables force_cla_connection; otherwise follow cert_base_url (IoP when IoP is on).
|
|
26
|
+
def self.cloud_cert_base_url
|
|
27
|
+
return cert_base_url unless Setting[:force_cla_connection]
|
|
28
|
+
|
|
29
|
+
ENV['SATELLITE_CERT_RH_CLOUD_URL'] || 'https://cert.cloud.redhat.com'
|
|
30
|
+
end
|
|
31
|
+
|
|
24
32
|
def self.legacy_insights_url
|
|
25
33
|
env_or_on_premise_url('SATELLITE_LEGACY_INSIGHTS_URL') || 'https://cert-api.access.redhat.com'
|
|
26
34
|
end
|
|
@@ -48,11 +56,19 @@ module ForemanRhCloud
|
|
|
48
56
|
def self.proxy_string
|
|
49
57
|
return '' if ForemanRhCloud.with_iop_smart_proxy?
|
|
50
58
|
|
|
59
|
+
cloud_proxy_string
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.cloud_proxy_string
|
|
51
63
|
HttpProxy.default_global_content_proxy&.full_url ||
|
|
52
64
|
ForemanRhCloud.global_foreman_proxy ||
|
|
53
65
|
''
|
|
54
66
|
end
|
|
55
67
|
|
|
68
|
+
def self.transformed_cloud_http_proxy_string
|
|
69
|
+
transform_scheme(fix_port(cloud_proxy_string))
|
|
70
|
+
end
|
|
71
|
+
|
|
56
72
|
def self.fix_port(uri_string)
|
|
57
73
|
return '' if uri_string.empty?
|
|
58
74
|
|
data/package.json
CHANGED
|
@@ -101,6 +101,22 @@ class ForemanRhCloudIopMetadataTest < ActiveSupport::TestCase
|
|
|
101
101
|
assert_equal 'https://iop.example.com', ForemanRhCloud.cert_base_url
|
|
102
102
|
end
|
|
103
103
|
|
|
104
|
+
test 'cloud_cert_base_url returns IoP URL when IoP exists and force_cla_connection is off' do
|
|
105
|
+
create_iop_proxy
|
|
106
|
+
Setting[:force_cla_connection] = false
|
|
107
|
+
|
|
108
|
+
assert_equal 'https://iop.example.com', ForemanRhCloud.cloud_cert_base_url
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
test 'cloud_cert_base_url returns cloud URL when IoP exists and force_cla_connection is on' do
|
|
112
|
+
create_iop_proxy
|
|
113
|
+
Setting[:force_cla_connection] = true
|
|
114
|
+
|
|
115
|
+
assert_equal 'https://cert.cloud.redhat.com', ForemanRhCloud.cloud_cert_base_url
|
|
116
|
+
ensure
|
|
117
|
+
Setting[:force_cla_connection] = false
|
|
118
|
+
end
|
|
119
|
+
|
|
104
120
|
test 'legacy_insights_url returns IoP URL when IoP smart proxy exists' do
|
|
105
121
|
create_iop_proxy
|
|
106
122
|
|
|
@@ -153,6 +169,17 @@ class ForemanRhCloudIopMetadataTest < ActiveSupport::TestCase
|
|
|
153
169
|
ENV.delete('SATELLITE_CERT_RH_CLOUD_URL')
|
|
154
170
|
end
|
|
155
171
|
|
|
172
|
+
test 'cloud_cert_base_url uses ENV var when force_cla_connection is on' do
|
|
173
|
+
ENV['SATELLITE_CERT_RH_CLOUD_URL'] = 'https://env-cert.cloud.test'
|
|
174
|
+
Setting[:force_cla_connection] = true
|
|
175
|
+
create_iop_proxy
|
|
176
|
+
|
|
177
|
+
assert_equal 'https://env-cert.cloud.test', ForemanRhCloud.cloud_cert_base_url
|
|
178
|
+
ensure
|
|
179
|
+
ENV.delete('SATELLITE_CERT_RH_CLOUD_URL')
|
|
180
|
+
Setting[:force_cla_connection] = false
|
|
181
|
+
end
|
|
182
|
+
|
|
156
183
|
test 'legacy_insights_url prefers IoP URL over ENV var' do
|
|
157
184
|
ENV['SATELLITE_LEGACY_INSIGHTS_URL'] = 'https://env-legacy.insights.test'
|
|
158
185
|
|
|
@@ -10,7 +10,9 @@ class CloudRequestForwarderTest < ActiveSupport::TestCase
|
|
|
10
10
|
|
|
11
11
|
ForemanRhCloud.stubs(:base_url).returns('https://cloud.example.com')
|
|
12
12
|
ForemanRhCloud.stubs(:cert_base_url).returns('https://cert.cloud.example.com')
|
|
13
|
+
ForemanRhCloud.stubs(:cloud_cert_base_url).returns('https://cert.cloud.example.com')
|
|
13
14
|
ForemanRhCloud.stubs(:legacy_insights_url).returns('https://cert-api.access.example.com')
|
|
15
|
+
ForemanRhCloud.stubs(:transformed_cloud_http_proxy_string).returns(nil)
|
|
14
16
|
|
|
15
17
|
UpstreamOnlySettingsTestHelper.set_if_available('allow_multiple_content_views')
|
|
16
18
|
env = FactoryBot.create(:katello_k_t_environment)
|
|
@@ -34,6 +36,7 @@ class CloudRequestForwarderTest < ActiveSupport::TestCase
|
|
|
34
36
|
|
|
35
37
|
test 'should prepare correct cloud url' do
|
|
36
38
|
paths = {
|
|
39
|
+
"/api/lightspeed/v1/query" => "https://cert.cloud.example.com/api/lightspeed/v1/query",
|
|
37
40
|
"/redhat_access/r/insights/platform/module-update-router/v1/channel?module=insights-core" => "https://cert.cloud.example.com/api/module-update-router/v1/channel?module=insights-core",
|
|
38
41
|
"/redhat_access/r/insights/v1/static/release/insights-core.egg" => "https://cert-api.access.example.com/r/insights/v1/static/release/insights-core.egg",
|
|
39
42
|
"/redhat_access/r/insights/v1/static/uploader.v2.json" => "https://cert-api.access.example.com/r/insights/v1/static/uploader.v2.json",
|
|
@@ -50,6 +53,31 @@ class CloudRequestForwarderTest < ActiveSupport::TestCase
|
|
|
50
53
|
end
|
|
51
54
|
end
|
|
52
55
|
|
|
56
|
+
test 'does not force CLA to cloud when IoP is enabled and setting is off' do
|
|
57
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
58
|
+
ForemanRhCloud.stubs(:cert_base_url).returns('https://iop.example.com')
|
|
59
|
+
ForemanRhCloud.stubs(:cloud_cert_base_url).returns('https://iop.example.com')
|
|
60
|
+
Setting.stubs(:[]).with(:force_cla_connection).returns(false)
|
|
61
|
+
|
|
62
|
+
actual = @forwarder.path_params('/api/lightspeed/v1/query')
|
|
63
|
+
|
|
64
|
+
assert_equal 'https://iop.example.com/api/lightspeed/v1/query', actual[:url]
|
|
65
|
+
refute actual[:force_cloud]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
test 'forwards CLA to cloud when IoP is enabled and force_cla_connection is on' do
|
|
69
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
70
|
+
ForemanRhCloud.stubs(:cert_base_url).returns('https://iop.example.com')
|
|
71
|
+
ForemanRhCloud.stubs(:cloud_cert_base_url).returns('https://cert.cloud.example.com')
|
|
72
|
+
ForemanRhCloud.stubs(:transformed_cloud_http_proxy_string).returns(nil)
|
|
73
|
+
Setting.stubs(:[]).with(:force_cla_connection).returns(true)
|
|
74
|
+
|
|
75
|
+
actual = @forwarder.path_params('/api/lightspeed/v1/query')
|
|
76
|
+
|
|
77
|
+
assert_equal 'https://cert.cloud.example.com/api/lightspeed/v1/query', actual[:url]
|
|
78
|
+
assert actual[:force_cloud]
|
|
79
|
+
end
|
|
80
|
+
|
|
53
81
|
test 'should forward payload from request parameters' do
|
|
54
82
|
params = { 'pumpkin' => 'pie' }
|
|
55
83
|
req = ActionDispatch::Request.new(
|
|
@@ -1,82 +1,83 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { MemoryRouter } from 'react-router-dom';
|
|
4
|
+
import '@testing-library/jest-dom';
|
|
3
5
|
import Toast from '../Toast';
|
|
4
6
|
|
|
7
|
+
jest.mock('foremanReact/common/I18n', () => ({
|
|
8
|
+
translate: jest.fn(str => str),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
const renderToast = (props = {}) =>
|
|
12
|
+
render(
|
|
13
|
+
<MemoryRouter>
|
|
14
|
+
<Toast syncHosts={5} disconnectHosts={3} {...props} />
|
|
15
|
+
</MemoryRouter>
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const omittedText =
|
|
19
|
+
'Excluded from upload to console.redhat.com Inventory service because host_registration_insights_inventory parameter value is false:';
|
|
20
|
+
|
|
5
21
|
describe('Toast', () => {
|
|
6
22
|
it('renders with all three status counts including user_omitted', () => {
|
|
7
|
-
|
|
8
|
-
<Toast syncHosts={5} disconnectHosts={3} userOmittedHosts={2} />
|
|
9
|
-
);
|
|
10
|
-
|
|
11
|
-
const links = wrapper.find('HostsWithStatusLink');
|
|
12
|
-
expect(links).toHaveLength(3);
|
|
23
|
+
renderToast({ userOmittedHosts: 2 });
|
|
13
24
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
.text()
|
|
32
|
-
).toBe('2');
|
|
25
|
+
expect(screen.getByRole('link', { name: '10' })).toHaveAttribute(
|
|
26
|
+
'href',
|
|
27
|
+
'/new/hosts?search=set%3F+subscription_uuid&page=1'
|
|
28
|
+
);
|
|
29
|
+
expect(screen.getByRole('link', { name: '5' })).toHaveAttribute(
|
|
30
|
+
'href',
|
|
31
|
+
'/new/hosts?search=insights_inventory_sync_status+%3D+sync&page=1'
|
|
32
|
+
);
|
|
33
|
+
expect(screen.getByRole('link', { name: '3' })).toHaveAttribute(
|
|
34
|
+
'href',
|
|
35
|
+
'/new/hosts?search=insights_inventory_sync_status+%3D+disconnect&page=1'
|
|
36
|
+
);
|
|
37
|
+
expect(screen.getByRole('link', { name: '2' })).toHaveAttribute(
|
|
38
|
+
'href',
|
|
39
|
+
'/new/hosts?search=insights_inventory_sync_status+%3D+user_omitted&page=1'
|
|
40
|
+
);
|
|
41
|
+
expect(screen.getByText(omittedText, { exact: false })).toBeInTheDocument();
|
|
33
42
|
});
|
|
34
43
|
|
|
35
44
|
it('does not render user_omitted section when count is 0', () => {
|
|
36
|
-
|
|
37
|
-
<Toast syncHosts={5} disconnectHosts={3} userOmittedHosts={0} />
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
// Should have only 2 HostsWithStatusLink components (sync and disconnect)
|
|
41
|
-
const links = wrapper.find('HostsWithStatusLink');
|
|
42
|
-
expect(links).toHaveLength(2);
|
|
45
|
+
renderToast({ userOmittedHosts: 0 });
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
expect(
|
|
46
|
-
|
|
47
|
-
);
|
|
47
|
+
expect(screen.getByRole('link', { name: '8' })).toBeInTheDocument();
|
|
48
|
+
expect(screen.getByRole('link', { name: '5' })).toBeInTheDocument();
|
|
49
|
+
expect(screen.getByRole('link', { name: '3' })).toBeInTheDocument();
|
|
50
|
+
expect(screen.queryByRole('link', { name: '2' })).not.toBeInTheDocument();
|
|
51
|
+
expect(
|
|
52
|
+
screen.queryByText(omittedText, { exact: false })
|
|
53
|
+
).not.toBeInTheDocument();
|
|
48
54
|
});
|
|
49
55
|
|
|
50
56
|
it('renders without crashing when userOmittedHosts is not provided (default)', () => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// Should use default value of 0, so only 2 links
|
|
54
|
-
const links = wrapper.find('HostsWithStatusLink');
|
|
55
|
-
expect(links).toHaveLength(2);
|
|
57
|
+
renderToast();
|
|
56
58
|
|
|
57
|
-
|
|
59
|
+
expect(screen.getByRole('link', { name: '8' })).toBeInTheDocument();
|
|
60
|
+
expect(screen.getByRole('link', { name: '5' })).toBeInTheDocument();
|
|
61
|
+
expect(screen.getByRole('link', { name: '3' })).toBeInTheDocument();
|
|
58
62
|
expect(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
.children()
|
|
62
|
-
.text()
|
|
63
|
-
).toBe('5');
|
|
64
|
-
expect(
|
|
65
|
-
links
|
|
66
|
-
.at(1)
|
|
67
|
-
.children()
|
|
68
|
-
.text()
|
|
69
|
-
).toBe('3');
|
|
63
|
+
screen.queryByText(omittedText, { exact: false })
|
|
64
|
+
).not.toBeInTheDocument();
|
|
70
65
|
});
|
|
71
66
|
|
|
72
67
|
it('renders correct status links for each category', () => {
|
|
73
|
-
|
|
74
|
-
<Toast syncHosts={5} disconnectHosts={3} userOmittedHosts={2} />
|
|
75
|
-
);
|
|
68
|
+
renderToast({ userOmittedHosts: 2 });
|
|
76
69
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
expect(screen.getByRole('link', { name: '5' })).toHaveAttribute(
|
|
71
|
+
'href',
|
|
72
|
+
expect.stringContaining('sync')
|
|
73
|
+
);
|
|
74
|
+
expect(screen.getByRole('link', { name: '3' })).toHaveAttribute(
|
|
75
|
+
'href',
|
|
76
|
+
expect.stringContaining('disconnect')
|
|
77
|
+
);
|
|
78
|
+
expect(screen.getByRole('link', { name: '2' })).toHaveAttribute(
|
|
79
|
+
'href',
|
|
80
|
+
expect.stringContaining('user_omitted')
|
|
81
|
+
);
|
|
81
82
|
});
|
|
82
83
|
});
|
|
@@ -1,17 +1,78 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { screen, waitFor } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
import { Provider } from 'react-redux';
|
|
5
|
+
import { applyMiddleware, combineReducers, createStore } from 'redux';
|
|
6
|
+
import thunk from 'redux-thunk';
|
|
7
|
+
import { rtlHelpers } from 'foremanReact/common/rtlTestHelpers';
|
|
8
|
+
import { API } from 'foremanReact/redux/API';
|
|
3
9
|
|
|
4
10
|
import InsightsTab from '../index';
|
|
5
11
|
import reducers from '../../ForemanRhCloudReducers';
|
|
6
|
-
import {
|
|
12
|
+
import { INSIGHTS_HITS_SUCCESS } from '../InsightsTabConstants';
|
|
13
|
+
import { hostID, hits } from './InsightsTab.fixtures';
|
|
7
14
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
const { renderWithI18n } = rtlHelpers;
|
|
16
|
+
|
|
17
|
+
jest.mock('foremanReact/redux/API');
|
|
18
|
+
|
|
19
|
+
const recommendationTitle =
|
|
20
|
+
'New Ansible Engine packages are inaccessible when dedicated Ansible repo is not enabled';
|
|
21
|
+
|
|
22
|
+
const createTabStore = () =>
|
|
23
|
+
createStore(combineReducers({ ...reducers }), applyMiddleware(thunk));
|
|
24
|
+
|
|
25
|
+
const renderConnectedTab = (store = createTabStore()) =>
|
|
26
|
+
renderWithI18n(
|
|
27
|
+
<Provider store={store}>
|
|
12
28
|
<InsightsTab hostID={hostID} />
|
|
29
|
+
</Provider>
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
describe('InsightsTab integration test', () => {
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
jest.clearAllMocks();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('requests hits for the host and shows empty state when there are none', async () => {
|
|
38
|
+
let resolveHits;
|
|
39
|
+
API.get.mockReturnValue(
|
|
40
|
+
new Promise(resolve => {
|
|
41
|
+
resolveHits = resolve;
|
|
42
|
+
})
|
|
13
43
|
);
|
|
14
|
-
|
|
15
|
-
|
|
44
|
+
|
|
45
|
+
const store = createTabStore();
|
|
46
|
+
store.dispatch({
|
|
47
|
+
type: INSIGHTS_HITS_SUCCESS,
|
|
48
|
+
payload: { hits },
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
renderConnectedTab(store);
|
|
52
|
+
|
|
53
|
+
expect(await screen.findByText(recommendationTitle)).toBeInTheDocument();
|
|
54
|
+
|
|
55
|
+
await waitFor(() => {
|
|
56
|
+
expect(API.get).toHaveBeenCalledWith(`/insights_cloud/hits/${hostID}`);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
resolveHits({ data: { hits: [] } });
|
|
60
|
+
|
|
61
|
+
expect(
|
|
62
|
+
await screen.findByRole('heading', {
|
|
63
|
+
name: 'No recommendations were found for this host!',
|
|
64
|
+
})
|
|
65
|
+
).toBeInTheDocument();
|
|
66
|
+
expect(screen.queryByText(recommendationTitle)).not.toBeInTheDocument();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('shows recommendation titles from the hits API response', async () => {
|
|
70
|
+
API.get.mockResolvedValue({ data: { hits } });
|
|
71
|
+
|
|
72
|
+
renderConnectedTab();
|
|
73
|
+
|
|
74
|
+
expect(await screen.findByText(recommendationTitle)).toBeInTheDocument();
|
|
75
|
+
|
|
76
|
+
expect(API.get).toHaveBeenCalledWith(`/insights_cloud/hits/${hostID}`);
|
|
16
77
|
});
|
|
17
78
|
});
|