foreman_rh_cloud 13.2.9 → 13.2.11
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/insights_cloud/api/machine_telemetries_controller.rb +4 -8
- data/app/controllers/insights_cloud/ui_requests_controller.rb +3 -7
- data/app/models/concerns/rh_cloud_host.rb +36 -1
- data/app/services/foreman_rh_cloud/url_remediations_retriever.rb +19 -5
- data/lib/foreman_inventory_upload/async/upload_report_direct_job.rb +2 -0
- data/lib/foreman_inventory_upload/generators/fact_helpers.rb +26 -4
- data/lib/foreman_inventory_upload.rb +8 -1
- data/lib/foreman_rh_cloud/version.rb +1 -1
- data/lib/foreman_rh_cloud.rb +36 -9
- data/lib/insights_cloud/async/insights_generate_notifications.rb +10 -1
- data/lib/inventory_sync/async/inventory_self_host_sync.rb +12 -2
- data/package.json +1 -1
- data/test/controllers/insights_cloud/api/machine_telemetries_controller_test.rb +16 -2
- data/test/controllers/insights_cloud/ui_requests_controller_test.rb +16 -2
- data/test/jobs/insights_generate_notifications_test.rb +26 -0
- data/test/jobs/inventory_self_host_sync_test.rb +9 -0
- data/test/jobs/upload_report_direct_job_test.rb +29 -0
- data/test/unit/foreman_rh_cloud_self_host_test.rb +50 -2
- data/test/unit/insights_facet_test.rb +5 -0
- data/test/unit/metadata_generator_test.rb +24 -1
- data/test/unit/rh_cloud_host_test.rb +68 -0
- data/test/unit/services/foreman_rh_cloud/url_remediations_retriever_test.rb +82 -5
- data/webpack/CVEsHostDetailsTab/CVEsHostDetailsTab.js +24 -2
- data/webpack/CVEsHostDetailsTab/__tests__/CVEsHostDetailsTab.test.js +73 -10
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyResults/__tests__/EmptyResults.test.js +10 -9
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyState/__tests__/EmptyState.test.js +13 -9
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ErrorState/__tests__/ErrorState.test.js +20 -9
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/__tests__/ListItem.test.js +31 -8
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/__tests__/ListItemStatus.test.js +26 -10
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountList.test.js +33 -9
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountListReducer.test.js +55 -35
- data/webpack/ForemanInventoryUpload/Components/FileDownload/__tests__/FileDownload.test.js +13 -9
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/InventoryFilter.test.js +12 -15
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/integration.test.js +32 -12
- data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/PageTitle.test.js +15 -7
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/CloudConnectorButton.test.js +47 -18
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SettingsWarning/SettingsWarning.test.js +58 -15
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButton.test.js +23 -9
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/SyncButtonSelectors.test.js +19 -17
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/integrations.test.js +25 -37
- data/webpack/ForemanInventoryUpload/Components/ScheduledRun/__tests__/ScheduledRun.test.js +28 -8
- data/webpack/ForemanInventoryUpload/Components/StatusChart/__tests__/StatusChart.test.js +25 -8
- data/webpack/ForemanInventoryUpload/Components/TabContainer/__tests__/TabContainer.test.js +11 -9
- data/webpack/ForemanInventoryUpload/Components/TabFooter/__tests__/TabFooter.test.js +11 -9
- data/webpack/ForemanInventoryUpload/ForemanInventoryHelpers.js +4 -4
- data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/__tests__/InventoryAutoUpload.test.js +33 -12
- data/webpack/ForemanInventoryUpload/__tests__/ForemanInventoryHelpers.test.js +36 -8
- data/webpack/ForemanRhCloudHelpers.js +22 -0
- data/webpack/InsightsHostDetailsTab/NewHostDetailsTab.js +27 -1
- data/webpack/InsightsHostDetailsTab/__tests__/NewHostDetailsTab.test.js +134 -22
- metadata +10 -43
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyResults/__tests__/__snapshots__/EmptyResults.test.js.snap +0 -18
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/EmptyState/__tests__/__snapshots__/EmptyState.test.js.snap +0 -25
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ErrorState/__tests__/__snapshots__/ErrorState.test.js.snap +0 -20
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItem/__tests__/__snapshots__/ListItem.test.js.snap +0 -47
- data/webpack/ForemanInventoryUpload/Components/AccountList/Components/ListItemStatus/__tests__/__snapshots__/ListItemStatus.test.js.snap +0 -59
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountListActions.test.js +0 -34
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountListIntegration.test.js +0 -14
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/AccountListSelectors.test.js +0 -25
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountList.test.js.snap +0 -49
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListActions.test.js.snap +0 -86
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListReducer.test.js.snap +0 -75
- data/webpack/ForemanInventoryUpload/Components/AccountList/__tests__/__snapshots__/AccountListSelectors.test.js.snap +0 -46
- data/webpack/ForemanInventoryUpload/Components/FileDownload/__tests__/__snapshots__/FileDownload.test.js.snap +0 -26
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/InventoryFilterActions.test.js +0 -14
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/InventoryFilterReducer.test.js +0 -28
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/InventoryFilterSelectors.test.js +0 -21
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilter.test.js.snap +0 -21
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilterActions.test.js.snap +0 -17
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilterReducer.test.js.snap +0 -19
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/InventoryFilterSelectors.test.js.snap +0 -9
- data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/integration.test.js.snap +0 -43
- data/webpack/ForemanInventoryUpload/Components/InventorySettings/AdvancedSetting/__tests__/AdvancedSettingActions.test.js +0 -9
- data/webpack/ForemanInventoryUpload/Components/InventorySettings/AdvancedSetting/__tests__/__snapshots__/AdvancedSettingActions.test.js.snap +0 -18
- data/webpack/ForemanInventoryUpload/Components/InventorySettings/__tests__/InventorySettingsActions.test.js +0 -14
- data/webpack/ForemanInventoryUpload/Components/InventorySettings/__tests__/__snapshots__/InventorySettingsActions.test.js.snap +0 -26
- data/webpack/ForemanInventoryUpload/Components/PageHeader/__tests__/__snapshots__/PageTitle.test.js.snap +0 -68
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/CloudConnectorActions.test.js +0 -9
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/__snapshots__/CloudConnectorActions.test.js.snap +0 -11
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/CloudConnectorButton/__tests__/__snapshots__/CloudConnectorButton.test.js.snap +0 -59
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SettingsWarning/__snapshots__/SettingsWarning.test.js.snap +0 -32
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButton.test.js.snap +0 -15
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/SyncButtonSelectors.test.js.snap +0 -3
- data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/__tests__/__snapshots__/integrations.test.js.snap +0 -58
- data/webpack/ForemanInventoryUpload/Components/ScheduledRun/__tests__/__snapshots__/ScheduledRun.test.js.snap +0 -23
- data/webpack/ForemanInventoryUpload/Components/StatusChart/__tests__/__snapshots__/StatusChart.test.js.snap +0 -74
- data/webpack/ForemanInventoryUpload/Components/TabContainer/__tests__/__snapshots__/TabContainer.test.js.snap +0 -18
- data/webpack/ForemanInventoryUpload/Components/TabFooter/__tests__/__snapshots__/TabFooter.test.js.snap +0 -12
- data/webpack/ForemanInventoryUpload/SubscriptionsPageExtension/InventoryAutoUpload/__tests__/__snapshots__/InventoryAutoUpload.test.js.snap +0 -96
- data/webpack/ForemanInventoryUpload/__tests__/ForemanInventoryUpload.test.js +0 -10
- data/webpack/ForemanInventoryUpload/__tests__/__snapshots__/ForemanInventoryHelpers.test.js.snap +0 -5
- data/webpack/ForemanInventoryUpload/__tests__/__snapshots__/ForemanInventoryUpload.test.js.snap +0 -14
|
@@ -343,6 +343,74 @@ class RhCloudHostTest < ActiveSupport::TestCase
|
|
|
343
343
|
end
|
|
344
344
|
end
|
|
345
345
|
|
|
346
|
+
context 'scoped search on insights_recommendations_count' do
|
|
347
|
+
setup do
|
|
348
|
+
@org = FactoryBot.create(:organization)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
teardown do
|
|
352
|
+
ForemanRhCloud.unstub(:with_iop_smart_proxy?)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
test 'searches insights_facets.hits_count in non-IoP mode' do
|
|
356
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
|
|
357
|
+
host_with_hits = FactoryBot.create(:host, :with_insights_hits, organization: @org)
|
|
358
|
+
InsightsFacet.reset_counters(host_with_hits.insights.id, :hits_count)
|
|
359
|
+
host_without_hits = FactoryBot.create(:host, :managed, organization: @org)
|
|
360
|
+
|
|
361
|
+
results = Host::Managed.search_for('insights_recommendations_count = 1')
|
|
362
|
+
|
|
363
|
+
assert_includes results, host_with_hits
|
|
364
|
+
assert_not_includes results, host_without_hits
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
test 'supports greater-than operator in non-IoP mode' do
|
|
368
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
|
|
369
|
+
host_with_hits = FactoryBot.create(:host, :with_insights_hits, organization: @org)
|
|
370
|
+
InsightsFacet.reset_counters(host_with_hits.insights.id, :hits_count)
|
|
371
|
+
host_without_hits = FactoryBot.create(:host, :managed, organization: @org)
|
|
372
|
+
|
|
373
|
+
results = Host::Managed.search_for('insights_recommendations_count > 0')
|
|
374
|
+
|
|
375
|
+
assert_includes results, host_with_hits
|
|
376
|
+
assert_not_includes results, host_without_hits
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
test 'raises QueryNotSupported in IoP mode' do
|
|
380
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(true)
|
|
381
|
+
|
|
382
|
+
error = assert_raises(ScopedSearch::QueryNotSupported) do
|
|
383
|
+
Host::Managed.search_for('insights_recommendations_count = 1')
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
assert_match(/not available in IoP mode/, error.message)
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
test 'supports IN operator in non-IoP mode' do
|
|
390
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
|
|
391
|
+
host_with_hits = FactoryBot.create(:host, :with_insights_hits, organization: @org)
|
|
392
|
+
InsightsFacet.reset_counters(host_with_hits.insights.id, :hits_count)
|
|
393
|
+
host_without_hits = FactoryBot.create(:host, :managed, organization: @org)
|
|
394
|
+
|
|
395
|
+
results = Host::Managed.search_for('insights_recommendations_count ^ (1,2,3)')
|
|
396
|
+
|
|
397
|
+
assert_includes results, host_with_hits
|
|
398
|
+
assert_not_includes results, host_without_hits
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
test 'handles hosts without insights facets in non-IoP mode' do
|
|
402
|
+
ForemanRhCloud.stubs(:with_iop_smart_proxy?).returns(false)
|
|
403
|
+
host_without_facet = FactoryBot.create(:host, :managed, organization: @org)
|
|
404
|
+
host_with_facet = FactoryBot.create(:host, :with_insights_hits, organization: @org)
|
|
405
|
+
InsightsFacet.reset_counters(host_with_facet.insights.id, :hits_count)
|
|
406
|
+
|
|
407
|
+
results = Host::Managed.search_for('insights_recommendations_count = 1')
|
|
408
|
+
|
|
409
|
+
assert_includes results, host_with_facet
|
|
410
|
+
assert_not_includes results, host_without_facet
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
346
414
|
test 'scoped search for user_omitted inventory status works' do
|
|
347
415
|
host1 = FactoryBot.create(:host, :managed)
|
|
348
416
|
host2 = FactoryBot.create(:host, :managed)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require 'test_plugin_helper'
|
|
2
2
|
|
|
3
3
|
class URLRemediationsRetrieverTest < ActiveSupport::TestCase
|
|
4
|
-
test 'Calls the given url' do
|
|
5
|
-
|
|
4
|
+
test 'Calls the given url with GET when no hosts in URL' do
|
|
5
|
+
retriever = ForemanRhCloud::URLRemediationsRetriever.new(
|
|
6
6
|
organization_id: FactoryBot.create(:organization).id,
|
|
7
7
|
url: 'http://test.example.com',
|
|
8
8
|
payload: 'TEST_PAYLOAD',
|
|
@@ -11,19 +11,96 @@ class URLRemediationsRetrieverTest < ActiveSupport::TestCase
|
|
|
11
11
|
}
|
|
12
12
|
)
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
retriever.stubs(:cert_auth_available?).returns(true)
|
|
15
15
|
|
|
16
16
|
response = mock('response')
|
|
17
17
|
response.stubs(:body).returns('TEST_RESPONSE')
|
|
18
|
-
|
|
18
|
+
retriever.expects(:execute_cloud_request).with do |params|
|
|
19
19
|
params[:method] == :get &&
|
|
20
20
|
params[:url] == 'http://test.example.com' &&
|
|
21
21
|
params[:headers][:custom1] == 'TEST_HEADER' &&
|
|
22
22
|
params[:payload] == "\"TEST_PAYLOAD\""
|
|
23
23
|
end.returns(response)
|
|
24
24
|
|
|
25
|
-
actual =
|
|
25
|
+
actual = retriever.create_playbook
|
|
26
26
|
|
|
27
27
|
assert_equal 'TEST_RESPONSE', actual
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
test 'Uses POST with hosts in body when URL contains hosts query param' do
|
|
31
|
+
retriever = ForemanRhCloud::URLRemediationsRetriever.new(
|
|
32
|
+
organization_id: FactoryBot.create(:organization).id,
|
|
33
|
+
url: 'http://test.example.com/api/remediations/1234/playbook?hosts=uuid-1,uuid-2,uuid-3'
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
retriever.stubs(:cert_auth_available?).returns(true)
|
|
37
|
+
|
|
38
|
+
response = mock('response')
|
|
39
|
+
response.stubs(:body).returns('TEST_PLAYBOOK')
|
|
40
|
+
retriever.expects(:execute_cloud_request).with do |params|
|
|
41
|
+
params[:method] == :post &&
|
|
42
|
+
params[:url] == 'http://test.example.com/api/remediations/1234/playbook' &&
|
|
43
|
+
JSON.parse(params[:payload]) == ['uuid-1', 'uuid-2', 'uuid-3']
|
|
44
|
+
end.returns(response)
|
|
45
|
+
|
|
46
|
+
actual = retriever.create_playbook
|
|
47
|
+
|
|
48
|
+
assert_equal 'TEST_PLAYBOOK', actual
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
test 'Preserves other query params when extracting hosts' do
|
|
52
|
+
retriever = ForemanRhCloud::URLRemediationsRetriever.new(
|
|
53
|
+
organization_id: FactoryBot.create(:organization).id,
|
|
54
|
+
url: 'http://test.example.com/api/remediations/1234/playbook?hosts=uuid-1,uuid-2&localhost=false'
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
retriever.stubs(:cert_auth_available?).returns(true)
|
|
58
|
+
|
|
59
|
+
response = mock('response')
|
|
60
|
+
response.stubs(:body).returns('TEST_PLAYBOOK')
|
|
61
|
+
retriever.expects(:execute_cloud_request).with do |params|
|
|
62
|
+
params[:method] == :post &&
|
|
63
|
+
params[:url].include?('localhost=false') &&
|
|
64
|
+
!params[:url].include?('hosts=') &&
|
|
65
|
+
JSON.parse(params[:payload]) == ['uuid-1', 'uuid-2']
|
|
66
|
+
end.returns(response)
|
|
67
|
+
|
|
68
|
+
retriever.create_playbook
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
test 'Merges multiple hosts query params into a single array' do
|
|
72
|
+
retriever = ForemanRhCloud::URLRemediationsRetriever.new(
|
|
73
|
+
organization_id: FactoryBot.create(:organization).id,
|
|
74
|
+
url: 'http://test.example.com/api/remediations/1234/playbook?hosts=uuid-1&hosts=uuid-2'
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
retriever.stubs(:cert_auth_available?).returns(true)
|
|
78
|
+
|
|
79
|
+
response = mock('response')
|
|
80
|
+
response.stubs(:body).returns('TEST_PLAYBOOK')
|
|
81
|
+
retriever.expects(:execute_cloud_request).with do |params|
|
|
82
|
+
params[:method] == :post &&
|
|
83
|
+
params[:url] == 'http://test.example.com/api/remediations/1234/playbook' &&
|
|
84
|
+
JSON.parse(params[:payload]) == ['uuid-1', 'uuid-2']
|
|
85
|
+
end.returns(response)
|
|
86
|
+
|
|
87
|
+
retriever.create_playbook
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
test 'Falls back to GET when hosts query param is empty' do
|
|
91
|
+
retriever = ForemanRhCloud::URLRemediationsRetriever.new(
|
|
92
|
+
organization_id: FactoryBot.create(:organization).id,
|
|
93
|
+
url: 'http://test.example.com/api/remediations/1234/playbook?hosts='
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
retriever.stubs(:cert_auth_available?).returns(true)
|
|
97
|
+
|
|
98
|
+
response = mock('response')
|
|
99
|
+
response.stubs(:body).returns('TEST_PLAYBOOK')
|
|
100
|
+
retriever.expects(:execute_cloud_request).with do |params|
|
|
101
|
+
params[:method] == :get
|
|
102
|
+
end.returns(response)
|
|
103
|
+
|
|
104
|
+
retriever.create_playbook
|
|
105
|
+
end
|
|
29
106
|
end
|
|
@@ -3,6 +3,10 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import { ScalprumComponent, ScalprumProvider } from '@scalprum/react-core';
|
|
4
4
|
import { createProviderOptions } from '../common/ScalprumModule/ScalprumContext';
|
|
5
5
|
import { useInsightsPermissions } from '../common/Hooks/PermissionsHooks';
|
|
6
|
+
import {
|
|
7
|
+
vulnerabilityDisabled,
|
|
8
|
+
useTabRedirect,
|
|
9
|
+
} from '../ForemanRhCloudHelpers';
|
|
6
10
|
import './CVEsHostDetailsTab.scss';
|
|
7
11
|
|
|
8
12
|
const CVEsHostDetailsTab = ({ systemId }) => {
|
|
@@ -26,6 +30,15 @@ CVEsHostDetailsTab.propTypes = {
|
|
|
26
30
|
|
|
27
31
|
const CVEsHostDetailsTabWrapper = ({ response }) => {
|
|
28
32
|
const permissions = useInsightsPermissions();
|
|
33
|
+
const isHostDataLoaded = Boolean(response?.id);
|
|
34
|
+
const shouldHideTab = useTabRedirect(
|
|
35
|
+
isHostDataLoaded && vulnerabilityDisabled({ hostDetails: response })
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (shouldHideTab) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
29
42
|
return (
|
|
30
43
|
<ScalprumProvider {...createProviderOptions(permissions)}>
|
|
31
44
|
<CVEsHostDetailsTab
|
|
@@ -38,10 +51,19 @@ const CVEsHostDetailsTabWrapper = ({ response }) => {
|
|
|
38
51
|
|
|
39
52
|
CVEsHostDetailsTabWrapper.propTypes = {
|
|
40
53
|
response: PropTypes.shape({
|
|
54
|
+
id: PropTypes.number,
|
|
55
|
+
operatingsystem_name: PropTypes.string,
|
|
56
|
+
vulnerability: PropTypes.shape({
|
|
57
|
+
enabled: PropTypes.bool,
|
|
58
|
+
}),
|
|
41
59
|
subscription_facet_attributes: PropTypes.shape({
|
|
42
|
-
uuid: PropTypes.string
|
|
60
|
+
uuid: PropTypes.string,
|
|
43
61
|
}),
|
|
44
|
-
})
|
|
62
|
+
}),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
CVEsHostDetailsTabWrapper.defaultProps = {
|
|
66
|
+
response: {},
|
|
45
67
|
};
|
|
46
68
|
|
|
47
69
|
export default CVEsHostDetailsTabWrapper;
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { render } from '@testing-library/react';
|
|
3
|
+
import { MemoryRouter } from 'react-router-dom';
|
|
3
4
|
import CVEsHostDetailsTabWrapper from '../CVEsHostDetailsTab';
|
|
5
|
+
import { OVERVIEW_TAB_PATH } from '../../ForemanRhCloudHelpers';
|
|
6
|
+
|
|
7
|
+
const mockHistoryReplace = jest.fn();
|
|
8
|
+
|
|
9
|
+
jest.mock('react-router-dom', () => ({
|
|
10
|
+
...jest.requireActual('react-router-dom'),
|
|
11
|
+
useHistory: () => ({
|
|
12
|
+
replace: mockHistoryReplace,
|
|
13
|
+
}),
|
|
14
|
+
}));
|
|
4
15
|
|
|
5
16
|
jest.mock('foremanReact/Root/Context/ForemanContext', () => ({
|
|
6
17
|
useForemanContext: () => ({
|
|
@@ -25,31 +36,44 @@ jest.mock('@scalprum/react-core', () => {
|
|
|
25
36
|
};
|
|
26
37
|
});
|
|
27
38
|
|
|
39
|
+
const defaultResponse = {
|
|
40
|
+
id: 1,
|
|
41
|
+
operatingsystem_name: 'Red Hat Enterprise Linux 8',
|
|
42
|
+
vulnerability: { enabled: true },
|
|
43
|
+
subscription_facet_attributes: { uuid: '1-2-3' },
|
|
44
|
+
};
|
|
45
|
+
|
|
28
46
|
describe('CVEsHostDetailsTabWrapper', () => {
|
|
29
47
|
beforeEach(() => {
|
|
30
48
|
jest.clearAllMocks();
|
|
31
49
|
});
|
|
32
50
|
|
|
33
|
-
it('renders without crashing', () => {
|
|
51
|
+
it('renders without crashing and does not redirect for valid host', () => {
|
|
34
52
|
const { container } = render(
|
|
35
|
-
<
|
|
36
|
-
response={
|
|
37
|
-
|
|
53
|
+
<MemoryRouter>
|
|
54
|
+
<CVEsHostDetailsTabWrapper response={defaultResponse} />
|
|
55
|
+
</MemoryRouter>
|
|
38
56
|
);
|
|
39
57
|
expect(
|
|
40
58
|
container.querySelector(
|
|
41
59
|
'.rh-cloud-insights-vulnerability-host-details-component'
|
|
42
60
|
)
|
|
43
61
|
).toBeTruthy();
|
|
62
|
+
expect(mockHistoryReplace).not.toHaveBeenCalled();
|
|
44
63
|
});
|
|
45
64
|
|
|
46
65
|
it('remounts ScalprumComponent when systemId changes', () => {
|
|
47
66
|
const { ScalprumComponent } = require('@scalprum/react-core');
|
|
48
67
|
|
|
68
|
+
const responseHostA = {
|
|
69
|
+
...defaultResponse,
|
|
70
|
+
subscription_facet_attributes: { uuid: 'uuid-host-A' },
|
|
71
|
+
};
|
|
72
|
+
|
|
49
73
|
const { rerender } = render(
|
|
50
|
-
<
|
|
51
|
-
response={
|
|
52
|
-
|
|
74
|
+
<MemoryRouter>
|
|
75
|
+
<CVEsHostDetailsTabWrapper response={responseHostA} />
|
|
76
|
+
</MemoryRouter>
|
|
53
77
|
);
|
|
54
78
|
|
|
55
79
|
expect(mockUnmountTracker).not.toHaveBeenCalled();
|
|
@@ -58,10 +82,15 @@ describe('CVEsHostDetailsTabWrapper', () => {
|
|
|
58
82
|
expect.anything()
|
|
59
83
|
);
|
|
60
84
|
|
|
85
|
+
const responseHostB = {
|
|
86
|
+
...defaultResponse,
|
|
87
|
+
subscription_facet_attributes: { uuid: 'uuid-host-B' },
|
|
88
|
+
};
|
|
89
|
+
|
|
61
90
|
rerender(
|
|
62
|
-
<
|
|
63
|
-
response={
|
|
64
|
-
|
|
91
|
+
<MemoryRouter>
|
|
92
|
+
<CVEsHostDetailsTabWrapper response={responseHostB} />
|
|
93
|
+
</MemoryRouter>
|
|
65
94
|
);
|
|
66
95
|
|
|
67
96
|
expect(mockUnmountTracker).toHaveBeenCalledTimes(1);
|
|
@@ -70,4 +99,38 @@ describe('CVEsHostDetailsTabWrapper', () => {
|
|
|
70
99
|
expect.anything()
|
|
71
100
|
);
|
|
72
101
|
});
|
|
102
|
+
|
|
103
|
+
it('redirects to Overview when tab should be hidden', () => {
|
|
104
|
+
const nonRhelResponse = {
|
|
105
|
+
id: 2,
|
|
106
|
+
operatingsystem_name: 'Ubuntu 20.04',
|
|
107
|
+
vulnerability: { enabled: false },
|
|
108
|
+
subscription_facet_attributes: { uuid: '1-2-3' },
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const { container } = render(
|
|
112
|
+
<MemoryRouter>
|
|
113
|
+
<CVEsHostDetailsTabWrapper response={nonRhelResponse} />
|
|
114
|
+
</MemoryRouter>
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
expect(mockHistoryReplace).toHaveBeenCalledWith(OVERVIEW_TAB_PATH);
|
|
118
|
+
expect(
|
|
119
|
+
container.querySelector(
|
|
120
|
+
'.rh-cloud-insights-vulnerability-host-details-component'
|
|
121
|
+
)
|
|
122
|
+
).toBeNull();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('does not redirect when host data is not yet loaded', () => {
|
|
126
|
+
const emptyResponse = { subscription_facet_attributes: { uuid: '1-2-3' } };
|
|
127
|
+
|
|
128
|
+
render(
|
|
129
|
+
<MemoryRouter>
|
|
130
|
+
<CVEsHostDetailsTabWrapper response={emptyResponse} />
|
|
131
|
+
</MemoryRouter>
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
expect(mockHistoryReplace).not.toHaveBeenCalled();
|
|
135
|
+
});
|
|
73
136
|
});
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import EmptyResults from '../EmptyResults';
|
|
4
4
|
|
|
5
|
-
const fixtures = {
|
|
6
|
-
'render without Props': {},
|
|
7
|
-
/** fixtures, props for the component */
|
|
8
|
-
};
|
|
9
|
-
|
|
10
5
|
describe('EmptyResults', () => {
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
it('renders the empty results message', () => {
|
|
7
|
+
render(<EmptyResults />);
|
|
8
|
+
expect(
|
|
9
|
+
screen.getByText(
|
|
10
|
+
"Oops! Couldn't find organization that matches your query"
|
|
11
|
+
)
|
|
12
|
+
).toBeTruthy();
|
|
13
|
+
});
|
|
13
14
|
});
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import EmptyState from '../EmptyState';
|
|
4
4
|
|
|
5
|
-
const fixtures = {
|
|
6
|
-
'render without Props': {},
|
|
7
|
-
/** fixtures, props for the component */
|
|
8
|
-
};
|
|
9
|
-
|
|
10
5
|
describe('EmptyState', () => {
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
it('renders fetching data message', () => {
|
|
7
|
+
render(<EmptyState />);
|
|
8
|
+
expect(
|
|
9
|
+
screen.getByText('Fetching data about your accounts')
|
|
10
|
+
).toBeTruthy();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('renders loading indicator', () => {
|
|
14
|
+
render(<EmptyState />);
|
|
15
|
+
expect(screen.getByText('Loading...')).toBeTruthy();
|
|
16
|
+
});
|
|
13
17
|
});
|
|
@@ -1,13 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import ErrorState from '../ErrorState';
|
|
4
4
|
|
|
5
|
-
const fixtures = {
|
|
6
|
-
'render without Props': {},
|
|
7
|
-
/** fixtures, props for the component */
|
|
8
|
-
};
|
|
9
|
-
|
|
10
5
|
describe('ErrorState', () => {
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
it('renders the error message heading', () => {
|
|
7
|
+
render(<ErrorState error="Something went wrong" />);
|
|
8
|
+
expect(
|
|
9
|
+
screen.getByText(
|
|
10
|
+
'Encountered an error while trying to access the server:'
|
|
11
|
+
)
|
|
12
|
+
).toBeTruthy();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('renders the error description', () => {
|
|
16
|
+
render(<ErrorState error="Connection refused" />);
|
|
17
|
+
expect(screen.getByText('Connection refused')).toBeTruthy();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('renders with empty error by default', () => {
|
|
21
|
+
const { container } = render(<ErrorState />);
|
|
22
|
+
expect(container.querySelector('.error_description')).toBeTruthy();
|
|
23
|
+
});
|
|
13
24
|
});
|
|
@@ -1,13 +1,36 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { Accordion } from '@patternfly/react-core';
|
|
3
4
|
import ListItem from '../ListItem';
|
|
4
|
-
import { props } from '../ListItem.fixtures';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
jest.mock('../../../../Dashboard', () => () => null);
|
|
7
|
+
|
|
8
|
+
const renderListItem = props =>
|
|
9
|
+
render(
|
|
10
|
+
<Accordion>
|
|
11
|
+
<ListItem {...props} />
|
|
12
|
+
</Accordion>
|
|
13
|
+
);
|
|
9
14
|
|
|
10
15
|
describe('ListItem', () => {
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
const defaultProps = {
|
|
17
|
+
label: 'test-org',
|
|
18
|
+
account: {
|
|
19
|
+
generated_status: 'unknown',
|
|
20
|
+
uploaded_status: 'unknown',
|
|
21
|
+
id: 1,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
it('renders the account label', () => {
|
|
26
|
+
renderListItem(defaultProps);
|
|
27
|
+
expect(screen.getByText('test-org')).toBeTruthy();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('renders Generated and Uploaded status labels', () => {
|
|
31
|
+
renderListItem(defaultProps);
|
|
32
|
+
expect(screen.getByText('Generated')).toBeTruthy();
|
|
33
|
+
expect(screen.getByText('Uploaded')).toBeTruthy();
|
|
34
|
+
});
|
|
35
|
+
|
|
13
36
|
});
|
|
@@ -1,14 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import ListItemStatus from '../ListItemStatus';
|
|
4
|
-
import { props } from '../ListItemStatus.fixtures';
|
|
5
|
-
|
|
6
|
-
const fixtures = {
|
|
7
|
-
'render without Props': {},
|
|
8
|
-
'render with Props': props,
|
|
9
|
-
};
|
|
10
4
|
|
|
11
5
|
describe('ListItemStatus', () => {
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
it('renders Generated and Uploaded labels', () => {
|
|
7
|
+
render(<ListItemStatus />);
|
|
8
|
+
expect(screen.getByText('Generated')).toBeTruthy();
|
|
9
|
+
expect(screen.getByText('Uploaded')).toBeTruthy();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('shows dash placeholders for unknown status', () => {
|
|
13
|
+
render(
|
|
14
|
+
<ListItemStatus
|
|
15
|
+
account={{ generated_status: 'unknown', uploaded_status: 'unknown' }}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
expect(screen.getAllByText('--')).toHaveLength(2);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('renders with provided account statuses', () => {
|
|
22
|
+
render(
|
|
23
|
+
<ListItemStatus
|
|
24
|
+
account={{ generated_status: 'success', uploaded_status: 'running' }}
|
|
25
|
+
/>
|
|
26
|
+
);
|
|
27
|
+
expect(screen.getByText('Generated')).toBeTruthy();
|
|
28
|
+
expect(screen.getByText('Uploaded')).toBeTruthy();
|
|
29
|
+
});
|
|
14
30
|
});
|
|
@@ -1,14 +1,38 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
3
|
import AccountList from '../AccountList';
|
|
4
|
-
import {
|
|
4
|
+
import { accounts } from '../AccountList.fixtures';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
};
|
|
6
|
+
jest.mock('../Components/ListItem', () => ({ label }) => (
|
|
7
|
+
<div>{label}</div>
|
|
8
|
+
));
|
|
10
9
|
|
|
11
10
|
describe('AccountList', () => {
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
it('renders account labels', () => {
|
|
12
|
+
render(<AccountList accounts={accounts} />);
|
|
13
|
+
Object.keys(accounts).forEach(label => {
|
|
14
|
+
expect(screen.getByText(label)).toBeTruthy();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('shows empty results when filterTerm matches nothing', () => {
|
|
19
|
+
render(<AccountList accounts={accounts} filterTerm="not_matching_term" />);
|
|
20
|
+
expect(
|
|
21
|
+
screen.getByText(
|
|
22
|
+
"Oops! Couldn't find organization that matches your query"
|
|
23
|
+
)
|
|
24
|
+
).toBeTruthy();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('shows empty state when accounts are empty', () => {
|
|
28
|
+
render(<AccountList accounts={{}} />);
|
|
29
|
+
expect(
|
|
30
|
+
screen.getByText('Fetching data about your accounts')
|
|
31
|
+
).toBeTruthy();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('shows error state when error is present', () => {
|
|
35
|
+
render(<AccountList accounts={{}} error="Server error" />);
|
|
36
|
+
expect(screen.getByText('Server error')).toBeTruthy();
|
|
37
|
+
});
|
|
14
38
|
});
|