@rancher/shell 3.0.12-rc.3 → 3.0.12-rc.5
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.
- package/assets/styles/global/_button.scss +1 -1
- package/assets/styles/global/_layout.scss +4 -0
- package/assets/translations/en-us.yaml +183 -51
- package/assets/translations/zh-hans.yaml +1 -7
- package/chart/monitoring/ClusterSelector.vue +0 -21
- package/chart/monitoring/prometheus/index.vue +6 -3
- package/components/ActionDropdownShell.vue +5 -3
- package/components/ButtonGroup.vue +26 -1
- package/components/CruResource.vue +212 -16
- package/components/ExplorerMembers.vue +8 -4
- package/components/ExplorerProjectsNamespaces.vue +10 -6
- package/components/GrowlManager.vue +4 -0
- package/components/MgmtNodeList.vue +184 -0
- package/components/PromptRestore.vue +93 -32
- package/components/Questions/index.vue +1 -0
- package/components/Resource/Detail/Card/StateCard/__tests__/composables.test.ts +90 -1
- package/components/Resource/Detail/Card/StateCard/composables.ts +57 -87
- package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +61 -0
- package/components/Resource/Detail/Card/StatusCard/index.vue +61 -15
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +2 -0
- package/components/Resource/Detail/Metadata/KeyValue.vue +5 -2
- package/components/Resource/Detail/Metadata/KeyValueRow.vue +2 -6
- package/components/ResourceDetail/index.vue +1 -1
- package/components/ResourceList/Masthead.vue +7 -1
- package/components/ResourceList/index.vue +82 -1
- package/components/ResourceTable.vue +1 -0
- package/components/RichTranslation.vue +5 -2
- package/components/Setting.vue +1 -0
- package/components/SortableTable/index.vue +4 -3
- package/components/SubtleLink.vue +31 -6
- package/components/Tabbed/Tab.vue +29 -3
- package/components/Tabbed/index.vue +25 -3
- package/components/TableOfContents/TableOfContents.vue +109 -0
- package/components/TableOfContents/composables.ts +258 -0
- package/components/Window/ContainerShell.vue +21 -11
- package/components/Window/__tests__/ContainerShell.test.ts +107 -37
- package/components/Wizard.vue +23 -5
- package/components/__tests__/ButtonGroup.test.ts +56 -0
- package/components/__tests__/PromptRestore.test.ts +169 -19
- package/components/fleet/AppCoChartGrid.vue +401 -0
- package/components/fleet/AppCoEmptyState.vue +127 -0
- package/components/fleet/AppCoPageHeader.vue +119 -0
- package/components/fleet/AppCoVersionSelect.vue +70 -0
- package/components/fleet/FleetClusterTargets/ClusterSelectionFields.vue +217 -0
- package/components/fleet/FleetClusterTargets/TargetsList.vue +123 -35
- package/components/fleet/FleetClusterTargets/index.vue +189 -146
- package/components/fleet/FleetIntro.vue +7 -3
- package/components/fleet/FleetNoWorkspaces.vue +7 -3
- package/components/fleet/FleetSecretSelector.vue +5 -3
- package/components/fleet/FleetValuesFrom.vue +8 -2
- package/components/fleet/GitRepoAdvancedTab.vue +1 -0
- package/components/fleet/GitRepoMetadataTab.vue +5 -0
- package/components/fleet/GitRepoTargetTab.vue +0 -2
- package/components/fleet/HelmOpAdvancedTab.vue +19 -53
- package/components/fleet/HelmOpAppCoConfigTab.vue +597 -0
- package/components/fleet/HelmOpAppCoResourcesSection.vue +162 -0
- package/components/fleet/HelmOpMetadataTab.vue +5 -0
- package/components/fleet/HelmOpResourcesSection.vue +82 -0
- package/components/fleet/HelmOpTargetOptionsSection.vue +89 -0
- package/components/fleet/HelmOpTargetTab.vue +64 -60
- package/components/fleet/HelmOpValuesTab.vue +129 -105
- package/components/fleet/__tests__/AppCoEmptyState.test.ts +71 -0
- package/components/fleet/__tests__/AppCoVersionSelect.test.ts +36 -0
- package/components/fleet/__tests__/ClusterSelectionFields.test.ts +62 -0
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +253 -0
- package/components/fleet/__tests__/FleetSecretSelector.test.ts +16 -0
- package/components/fleet/__tests__/FleetValuesFrom.test.ts +44 -0
- package/components/fleet/__tests__/HelmOpAppCoConfigTab.test.ts +59 -0
- package/components/fleet/__tests__/HelmOpAppCoResourcesSection.test.ts +62 -0
- package/components/fleet/__tests__/HelmOpResourcesSection.test.ts +43 -0
- package/components/fleet/__tests__/HelmOpTargetOptionsSection.test.ts +34 -0
- package/components/fleet/__tests__/HelmOpValuesTab.test.ts +39 -0
- package/components/fleet/__tests__/__snapshots__/AppCoEmptyState.test.ts.snap +97 -0
- package/components/fleet/__tests__/__snapshots__/AppCoVersionSelect.test.ts.snap +30 -0
- package/components/fleet/__tests__/__snapshots__/ClusterSelectionFields.test.ts.snap +209 -0
- package/components/fleet/__tests__/__snapshots__/HelmOpTargetOptionsSection.test.ts.snap +140 -0
- package/components/fleet/dashboard/Empty.vue +8 -4
- package/components/fleet/dashboard/ResourceCard.vue +28 -0
- package/components/fleet/dashboard/ResourceDetails.vue +28 -0
- package/components/fleet/dashboard/__tests__/ResourceCard.test.ts +87 -0
- package/components/form/ArrayList.vue +61 -4
- package/components/form/FileSelector.vue +39 -1
- package/components/form/KeyValue.vue +23 -2
- package/components/form/LabeledSelect.vue +39 -1
- package/components/form/Labels.vue +22 -3
- package/components/form/NameNsDescription.vue +13 -5
- package/components/form/PrivateRegistry.constants.ts +7 -0
- package/components/form/PrivateRegistry.vue +253 -18
- package/components/form/ResourceTabs/index.vue +1 -0
- package/components/form/SelectOrCreateAuthSecret.vue +140 -17
- package/components/form/__tests__/FileSelector.test.ts +23 -0
- package/components/form/__tests__/NameNsDescription.test.ts +75 -0
- package/components/form/__tests__/PrivateRegistry.test.ts +463 -73
- package/components/form/__tests__/SelectOrCreateAuthSecret.test.ts +122 -0
- package/components/formatter/EtcdSnapshotName.vue +73 -0
- package/components/formatter/InternalExternalIP.vue +10 -4
- package/components/formatter/ServiceTargets.vue +26 -7
- package/components/formatter/__tests__/InternalExternalIP.test.ts +132 -0
- package/components/formatter/__tests__/ServiceTargets.test.ts +412 -0
- package/components/nav/Header.vue +12 -1
- package/components/nav/TopLevelMenu.vue +7 -2
- package/components/nav/__tests__/Header.test.ts +15 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +120 -2
- package/components/templates/default.vue +16 -4
- package/components/templates/home.vue +9 -4
- package/components/templates/plain.vue +9 -4
- package/composables/useHelmOpResources.test.ts +56 -0
- package/composables/useHelmOpResources.ts +32 -0
- package/composables/useStateColor.test.ts +325 -0
- package/composables/useStateColor.ts +128 -0
- package/config/features.js +1 -0
- package/config/home-links.js +1 -1
- package/config/labels-annotations.js +3 -0
- package/config/product/explorer.js +17 -4
- package/config/product/manager.js +8 -0
- package/config/router/index.js +16 -0
- package/config/router/navigation-guards/__tests__/authentication.test.ts +130 -0
- package/config/router/navigation-guards/authentication.js +10 -4
- package/config/router/routes.js +20 -6
- package/config/secret.ts +10 -0
- package/config/settings.ts +6 -4
- package/config/table-headers.js +3 -4
- package/config/types.js +16 -0
- package/core/plugin-products-base.ts +3 -3
- package/core/plugin-types.ts +83 -30
- package/core/plugin.ts +3 -0
- package/core/types-provisioning.ts +34 -1
- package/core/types.ts +15 -2
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +114 -0
- package/detail/__tests__/workload.test.ts +3 -152
- package/detail/catalog.cattle.io.clusterrepo.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +109 -7
- package/detail/workload/index.vue +12 -55
- package/dialog/RotateEncryptionKeyDialog.vue +33 -9
- package/dialog/__tests__/RotateEncryptionKeyDialog.test.ts +78 -0
- package/edit/__tests__/catalog.cattle.io.clusterrepo.test.ts +248 -0
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +92 -0
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +206 -0
- package/edit/__tests__/management.cattle.io.setting.test.ts +2 -1
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/index.test.ts.snap +1 -0
- package/edit/auth/__tests__/azuread.test.ts +34 -9
- package/edit/auth/__tests__/github.test.ts +234 -0
- package/edit/auth/__tests__/oidc.test.ts +26 -6
- package/edit/auth/__tests__/saml.test.ts +196 -0
- package/edit/auth/azuread.vue +128 -95
- package/edit/auth/github.vue +72 -13
- package/edit/auth/ldap/__tests__/index.test.ts +206 -0
- package/edit/auth/ldap/config.vue +8 -0
- package/edit/auth/ldap/index.vue +75 -1
- package/edit/auth/oidc.vue +119 -73
- package/edit/auth/saml.vue +76 -12
- package/edit/catalog.cattle.io.clusterrepo.vue +140 -32
- package/edit/compliance.cattle.io.clusterscanprofile.vue +39 -41
- package/edit/fleet.cattle.io.gitrepo.vue +70 -16
- package/edit/fleet.cattle.io.helmop.vue +542 -141
- package/edit/helm.cattle.io.projecthelmchart.vue +1 -0
- package/edit/{management.cattle.io.setting.vue → management.cattle.io.setting/index.vue} +32 -9
- package/edit/management.cattle.io.setting/system-default-registry-pull-secrets.vue +81 -0
- package/edit/management.cattle.io.user.vue +5 -2
- package/edit/provisioning.cattle.io.cluster/SelectCredential.vue +3 -12
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +18 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +89 -11
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/index.vue +0 -1
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +14 -55
- package/list/group.principal.vue +5 -4
- package/list/harvesterhci.io.management.cluster.vue +8 -9
- package/list/management.cattle.io.user.vue +12 -9
- package/list/provisioning.cattle.io.cluster.vue +16 -10
- package/mixins/__tests__/auth-config.test.ts +90 -0
- package/mixins/__tests__/chart.test.ts +94 -0
- package/mixins/__tests__/resource-fetch-api-pagination.test.ts +48 -0
- package/mixins/auth-config.js +7 -0
- package/mixins/chart.js +11 -2
- package/mixins/child-hook.js +12 -6
- package/mixins/create-edit-view/impl.js +5 -3
- package/mixins/resource-fetch-api-pagination.js +21 -1
- package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +57 -0
- package/models/__tests__/compliance.cattle.io.clusterscan.test.ts +144 -0
- package/models/__tests__/fleet-application.test.ts +175 -0
- package/models/__tests__/fleet.cattle.io.bundle.test.ts +169 -0
- package/models/__tests__/fleet.cattle.io.helmop.test.ts +84 -0
- package/models/__tests__/management.cattle.io.node.ts +22 -0
- package/models/__tests__/namespace.test.ts +36 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +205 -0
- package/models/__tests__/secret.test.ts +68 -1
- package/models/__tests__/workload.test.ts +401 -26
- package/models/catalog.cattle.io.clusterrepo.js +28 -4
- package/models/compliance.cattle.io.clusterscan.js +39 -4
- package/models/fleet-application.js +4 -0
- package/models/fleet.cattle.io.helmop.js +20 -1
- package/models/management.cattle.io.cluster.js +39 -5
- package/models/management.cattle.io.node.js +44 -3
- package/models/namespace.js +1 -1
- package/models/pod.js +46 -3
- package/models/provisioning.cattle.io.cluster.js +64 -14
- package/models/rke.cattle.io.etcdsnapshot.js +17 -9
- package/models/secret.js +19 -0
- package/models/workload.js +120 -20
- package/models/workload.service.js +5 -0
- package/package.json +14 -13
- package/pages/about.vue +5 -6
- package/pages/auth/login.vue +0 -35
- package/pages/auth/setup.vue +11 -0
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +2 -2
- package/pages/c/_cluster/apps/charts/AppChartCardSubHeader.vue +10 -1
- package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +93 -0
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +485 -107
- package/pages/c/_cluster/apps/charts/chart.vue +2 -1
- package/pages/c/_cluster/apps/charts/index.vue +48 -10
- package/pages/c/_cluster/apps/charts/install.vue +236 -144
- package/pages/c/_cluster/auth/roles/index.vue +5 -4
- package/pages/c/_cluster/explorer/workload-dashboard/ByNamespaceSection.vue +31 -0
- package/pages/c/_cluster/explorer/workload-dashboard/ByStateSection.vue +138 -0
- package/pages/c/_cluster/explorer/workload-dashboard/ByTypeSection.vue +30 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadCard.vue +155 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadNamespaceCard.vue +142 -0
- package/pages/c/_cluster/explorer/workload-dashboard/WorkloadTypeCard.vue +159 -0
- package/pages/c/_cluster/explorer/workload-dashboard/__tests__/composable.test.ts +561 -0
- package/pages/c/_cluster/explorer/workload-dashboard/composable.ts +440 -0
- package/pages/c/_cluster/explorer/workload-dashboard/index.vue +187 -0
- package/pages/c/_cluster/explorer/workload-dashboard/types.ts +80 -0
- package/pages/c/_cluster/fleet/application/create.vue +187 -136
- package/pages/c/_cluster/fleet/application/index.vue +5 -3
- package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailBody.vue +338 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/ChartDetailHeader.vue +121 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/chart.vue +369 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/charts.vue +248 -0
- package/pages/c/_cluster/fleet/application/suse-app-collection/credentials.vue +310 -0
- package/pages/c/_cluster/fleet/index.vue +2 -2
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +96 -0
- package/pages/c/_cluster/uiplugins/index.vue +15 -0
- package/pages/fail-whale.vue +16 -11
- package/pages/home.vue +16 -46
- package/pkg/require-asset.lib.js +25 -0
- package/pkg/vue.config.js +7 -0
- package/plugins/clean-html.d.ts +9 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +177 -0
- package/plugins/dashboard-store/getters.js +0 -1
- package/plugins/dashboard-store/resource-class.js +114 -19
- package/plugins/steve/__tests__/actions.test.ts +212 -0
- package/plugins/steve/actions.js +96 -0
- package/plugins/steve/steve-pagination-utils.ts +1 -1
- package/rancher-components/Accordion/Accordion.vue +53 -9
- package/rancher-components/Form/Checkbox/Checkbox.vue +14 -0
- package/rancher-components/Form/Radio/RadioButton.vue +17 -1
- package/rancher-components/Form/Radio/RadioGroup.vue +10 -0
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +30 -0
- package/rancher-components/Form/TextArea/__tests__/TextAreaAutoGrow.test.ts +95 -0
- package/rancher-components/Pill/RcTag/RcTag.vue +3 -2
- package/rancher-components/RcButton/RcButton.test.ts +103 -0
- package/rancher-components/RcButton/RcButton.vue +94 -15
- package/rancher-components/RcButton/index.ts +1 -1
- package/rancher-components/RcButton/types.ts +3 -0
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +6 -1
- package/rancher-components/RcItemCard/RcItemCard.test.ts +18 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +2 -2
- package/rancher-components/RcSection/RcSection.vue +28 -3
- package/scripts/extension/helm/package/Dockerfile +1 -1
- package/scripts/test-plugins-build.sh +2 -1
- package/store/__tests__/features.test.ts +131 -0
- package/store/__tests__/growl.test.ts +374 -0
- package/store/__tests__/modal.test.ts +131 -0
- package/store/__tests__/notifications.test.ts +434 -0
- package/store/__tests__/slideInPanel.test.ts +88 -0
- package/store/__tests__/type-map.utils.test.ts +433 -0
- package/store/catalog.js +57 -0
- package/store/features.js +4 -0
- package/store/plugins.js +7 -4
- package/types/components/buttonGroup.ts +5 -0
- package/types/shell/index.d.ts +166 -70
- package/utils/__tests__/auth.test.ts +273 -0
- package/utils/__tests__/computed.test.ts +193 -0
- package/utils/__tests__/cspAdaptor.test.ts +163 -0
- package/utils/__tests__/dom.test.ts +81 -0
- package/utils/__tests__/duration.test.ts +37 -1
- package/utils/__tests__/dynamic-importer.test.ts +102 -0
- package/utils/__tests__/fleet-appco.test.ts +312 -0
- package/utils/__tests__/monitoring.test.ts +130 -0
- package/utils/__tests__/object.test.ts +22 -0
- package/utils/__tests__/operation-cr.test.ts +34 -0
- package/utils/__tests__/platform.test.ts +91 -0
- package/utils/__tests__/position.test.ts +237 -0
- package/utils/__tests__/provider.test.ts +51 -1
- package/utils/__tests__/queue.test.ts +232 -0
- package/utils/__tests__/release-notes.test.ts +221 -0
- package/utils/__tests__/router.test.js +254 -1
- package/utils/__tests__/select.test.ts +208 -0
- package/utils/__tests__/time.test.ts +265 -1
- package/utils/__tests__/title.test.ts +47 -0
- package/utils/__tests__/width.test.ts +53 -0
- package/utils/__tests__/window.test.ts +158 -0
- package/utils/__tests__/xccdf.test.ts +126 -6
- package/utils/crypto/__tests__/browserHashUtils.test.ts +98 -0
- package/utils/crypto/__tests__/index.test.ts +144 -0
- package/utils/duration.ts +104 -0
- package/utils/dynamic-content/__tests__/notification-handler.test.ts +196 -0
- package/utils/dynamic-content/info.ts +2 -1
- package/utils/error.js +13 -0
- package/utils/fleet-appco.ts +323 -0
- package/utils/object.js +22 -2
- package/utils/operation-cr.js +19 -0
- package/utils/provider.ts +12 -0
- package/utils/require-asset.ts +7 -0
- package/utils/validators/__tests__/container-images.test.ts +104 -0
- package/utils/validators/__tests__/flow-output.test.ts +91 -0
- package/utils/validators/__tests__/logging-outputs.test.ts +58 -0
- package/utils/validators/__tests__/monitoring-route.test.ts +119 -0
- package/utils/validators/__tests__/private-registry.test.ts +27 -15
- package/utils/validators/private-registry.ts +15 -4
- package/utils/xccdf.ts +39 -42
- package/vue.config.js +1 -1
- package/pages/support/index.vue +0 -264
- package/utils/duration.js +0 -43
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import ClusterScan from '@shell/models/compliance.cattle.io.clusterscan';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build a ClusterScan model wired to a mocked store `dispatch`.
|
|
5
|
+
* `$dispatch` resolves to `this.$ctx.dispatch`, so injecting it via the
|
|
6
|
+
* constructor context is enough to exercise `_resolveExportMetadata`.
|
|
7
|
+
*/
|
|
8
|
+
const makeScan = (dispatch: jest.Mock) => new ClusterScan({}, {
|
|
9
|
+
getters: {},
|
|
10
|
+
rootGetters: {},
|
|
11
|
+
dispatch,
|
|
12
|
+
} as any) as any;
|
|
13
|
+
|
|
14
|
+
const benchmarkWithConfigMap = {
|
|
15
|
+
spec: {
|
|
16
|
+
customBenchmarkConfigMapName: 'metadata-cm',
|
|
17
|
+
customBenchmarkConfigMapNamespace: 'compliance',
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
describe('class: ClusterScan', () => {
|
|
22
|
+
describe('method: _resolveExportMetadata', () => {
|
|
23
|
+
it('returns empty metadata and decorations when the benchmark is undefined', async() => {
|
|
24
|
+
const dispatch = jest.fn();
|
|
25
|
+
const scan = makeScan(dispatch);
|
|
26
|
+
|
|
27
|
+
const result = await scan._resolveExportMetadata(undefined);
|
|
28
|
+
|
|
29
|
+
expect(result).toStrictEqual({ metadata: {}, decorations: {} });
|
|
30
|
+
expect(dispatch).not.toHaveBeenCalled();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('returns empty when the ConfigMap name is missing', async() => {
|
|
34
|
+
const dispatch = jest.fn();
|
|
35
|
+
const scan = makeScan(dispatch);
|
|
36
|
+
|
|
37
|
+
const result = await scan._resolveExportMetadata({ spec: { customBenchmarkConfigMapNamespace: 'compliance' } });
|
|
38
|
+
|
|
39
|
+
expect(result).toStrictEqual({ metadata: {}, decorations: {} });
|
|
40
|
+
expect(dispatch).not.toHaveBeenCalled();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('returns empty when the ConfigMap namespace is missing', async() => {
|
|
44
|
+
const dispatch = jest.fn();
|
|
45
|
+
const scan = makeScan(dispatch);
|
|
46
|
+
|
|
47
|
+
const result = await scan._resolveExportMetadata({ spec: { customBenchmarkConfigMapName: 'metadata-cm' } });
|
|
48
|
+
|
|
49
|
+
expect(result).toStrictEqual({ metadata: {}, decorations: {} });
|
|
50
|
+
expect(dispatch).not.toHaveBeenCalled();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('fetches the ConfigMap by namespace/name from the configmap type', async() => {
|
|
54
|
+
const dispatch = jest.fn().mockResolvedValue({ data: {} });
|
|
55
|
+
const scan = makeScan(dispatch);
|
|
56
|
+
|
|
57
|
+
await scan._resolveExportMetadata(benchmarkWithConfigMap);
|
|
58
|
+
|
|
59
|
+
expect(dispatch).toHaveBeenCalledWith('find', { type: 'configmap', id: 'compliance/metadata-cm' });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('returns empty when the ConfigMap has no metadata.yaml data key', async() => {
|
|
63
|
+
const dispatch = jest.fn().mockResolvedValue({ data: { 'other.yaml': 'title: x' } });
|
|
64
|
+
const scan = makeScan(dispatch);
|
|
65
|
+
|
|
66
|
+
const result = await scan._resolveExportMetadata(benchmarkWithConfigMap);
|
|
67
|
+
|
|
68
|
+
expect(result).toStrictEqual({ metadata: {}, decorations: {} });
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('returns empty when the ConfigMap itself is not found', async() => {
|
|
72
|
+
const dispatch = jest.fn().mockResolvedValue(undefined);
|
|
73
|
+
const scan = makeScan(dispatch);
|
|
74
|
+
|
|
75
|
+
const result = await scan._resolveExportMetadata(benchmarkWithConfigMap);
|
|
76
|
+
|
|
77
|
+
expect(result).toStrictEqual({ metadata: {}, decorations: {} });
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('splits top-level fields into metadata and the checks map into decorations', async() => {
|
|
81
|
+
const yaml = [
|
|
82
|
+
'title: CIS Kubernetes Benchmark',
|
|
83
|
+
'description: A CIS profile',
|
|
84
|
+
'referenceType: cis',
|
|
85
|
+
'checks:',
|
|
86
|
+
' "5.1.1":',
|
|
87
|
+
' ruleId: CIS-5.1.1-rule',
|
|
88
|
+
' severity: high',
|
|
89
|
+
' idents:',
|
|
90
|
+
' - system: https://www.cisecurity.org/controls/',
|
|
91
|
+
' value: CIS-CSC-3',
|
|
92
|
+
' "5.1.2":',
|
|
93
|
+
' ruleId: CIS-5.1.2-rule',
|
|
94
|
+
].join('\n');
|
|
95
|
+
const dispatch = jest.fn().mockResolvedValue({ data: { 'metadata.yaml': yaml } });
|
|
96
|
+
const scan = makeScan(dispatch);
|
|
97
|
+
|
|
98
|
+
const result = await scan._resolveExportMetadata(benchmarkWithConfigMap);
|
|
99
|
+
|
|
100
|
+
expect(result.metadata).toStrictEqual({
|
|
101
|
+
title: 'CIS Kubernetes Benchmark',
|
|
102
|
+
description: 'A CIS profile',
|
|
103
|
+
referenceType: 'cis',
|
|
104
|
+
});
|
|
105
|
+
expect(result.decorations).toStrictEqual({
|
|
106
|
+
'5.1.1': {
|
|
107
|
+
ruleId: 'CIS-5.1.1-rule',
|
|
108
|
+
severity: 'high',
|
|
109
|
+
idents: [{ system: 'https://www.cisecurity.org/controls/', value: 'CIS-CSC-3' }],
|
|
110
|
+
},
|
|
111
|
+
'5.1.2': { ruleId: 'CIS-5.1.2-rule' },
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('returns empty decorations when metadata.yaml has no checks map', async() => {
|
|
116
|
+
const yaml = ['title: STIG', 'source: disa'].join('\n');
|
|
117
|
+
const dispatch = jest.fn().mockResolvedValue({ data: { 'metadata.yaml': yaml } });
|
|
118
|
+
const scan = makeScan(dispatch);
|
|
119
|
+
|
|
120
|
+
const result = await scan._resolveExportMetadata(benchmarkWithConfigMap);
|
|
121
|
+
|
|
122
|
+
expect(result.metadata).toStrictEqual({ title: 'STIG', source: 'disa' });
|
|
123
|
+
expect(result.decorations).toStrictEqual({});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('returns empty when the ConfigMap lookup rejects', async() => {
|
|
127
|
+
const dispatch = jest.fn().mockRejectedValue(new Error('not found'));
|
|
128
|
+
const scan = makeScan(dispatch);
|
|
129
|
+
|
|
130
|
+
const result = await scan._resolveExportMetadata(benchmarkWithConfigMap);
|
|
131
|
+
|
|
132
|
+
expect(result).toStrictEqual({ metadata: {}, decorations: {} });
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('returns empty when metadata.yaml is malformed YAML', async() => {
|
|
136
|
+
const dispatch = jest.fn().mockResolvedValue({ data: { 'metadata.yaml': 'title: "unterminated' } });
|
|
137
|
+
const scan = makeScan(dispatch);
|
|
138
|
+
|
|
139
|
+
const result = await scan._resolveExportMetadata(benchmarkWithConfigMap);
|
|
140
|
+
|
|
141
|
+
expect(result).toStrictEqual({ metadata: {}, decorations: {} });
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import FleetApplication from '@shell/models/fleet-application.js';
|
|
2
|
+
|
|
3
|
+
describe('class FleetApplication', () => {
|
|
4
|
+
afterEach(() => {
|
|
5
|
+
jest.restoreAllMocks();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
describe('applicationType', () => {
|
|
9
|
+
it('should return the kind property', () => {
|
|
10
|
+
const instance = new FleetApplication({ kind: 'GitRepo' });
|
|
11
|
+
|
|
12
|
+
expect(instance.applicationType).toStrictEqual('GitRepo');
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('targetClusters', () => {
|
|
17
|
+
function createFleetApplication(targets: any[] | undefined, clusters: any[], workspaceId = 'fleet-default', groups: any[] = []) {
|
|
18
|
+
const workspace = {
|
|
19
|
+
id: workspaceId,
|
|
20
|
+
clusters,
|
|
21
|
+
clusterGroups: groups,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
jest.spyOn(FleetApplication.prototype, '$getters', 'get').mockReturnValue({ byId: () => workspace });
|
|
25
|
+
|
|
26
|
+
return new FleetApplication({
|
|
27
|
+
metadata: { namespace: workspaceId },
|
|
28
|
+
spec: { targets },
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
it.each([
|
|
33
|
+
[
|
|
34
|
+
'metadata.name',
|
|
35
|
+
[{ clusterName: 'c-m-abc123' }],
|
|
36
|
+
[{
|
|
37
|
+
id: 'fleet-default/c-m-abc123', metadata: { name: 'c-m-abc123' }, nameDisplay: 'my-cluster'
|
|
38
|
+
}],
|
|
39
|
+
[{
|
|
40
|
+
id: 'fleet-default/c-m-abc123', metadata: { name: 'c-m-abc123' }, nameDisplay: 'my-cluster'
|
|
41
|
+
}],
|
|
42
|
+
],
|
|
43
|
+
[
|
|
44
|
+
'nameDisplay when metadata.name does not match',
|
|
45
|
+
[{ clusterName: 'my-display-name' }],
|
|
46
|
+
[{
|
|
47
|
+
id: 'fleet-default/c-m-abc123', metadata: { name: 'c-m-abc123' }, nameDisplay: 'my-display-name'
|
|
48
|
+
}],
|
|
49
|
+
[{
|
|
50
|
+
id: 'fleet-default/c-m-abc123', metadata: { name: 'c-m-abc123' }, nameDisplay: 'my-display-name'
|
|
51
|
+
}],
|
|
52
|
+
],
|
|
53
|
+
])('should find cluster by %s', (_label, targets, clusters, expected) => {
|
|
54
|
+
const app = createFleetApplication(targets, clusters);
|
|
55
|
+
|
|
56
|
+
expect(app.targetClusters).toStrictEqual(expected);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should prefer metadata.name match over nameDisplay match', () => {
|
|
60
|
+
const clusters = [
|
|
61
|
+
{
|
|
62
|
+
id: 'fleet-default/exact-match',
|
|
63
|
+
metadata: { name: 'exact-match' },
|
|
64
|
+
nameDisplay: 'display-a',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'fleet-default/c-m-other',
|
|
68
|
+
metadata: { name: 'c-m-other' },
|
|
69
|
+
nameDisplay: 'exact-match',
|
|
70
|
+
}
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
const app = createFleetApplication([{ clusterName: 'exact-match' }], clusters);
|
|
74
|
+
|
|
75
|
+
expect(app.targetClusters).toStrictEqual([clusters[0]]);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should return empty array when no cluster matches by name or nameDisplay', () => {
|
|
79
|
+
const clusters = [
|
|
80
|
+
{
|
|
81
|
+
id: 'fleet-default/c-m-abc123',
|
|
82
|
+
metadata: { name: 'c-m-abc123' },
|
|
83
|
+
nameDisplay: 'my-cluster',
|
|
84
|
+
}
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
const app = createFleetApplication([{ clusterName: 'non-existent' }], clusters);
|
|
88
|
+
|
|
89
|
+
expect(app.targetClusters).toStrictEqual([]);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should handle multiple targets with mixed name and nameDisplay matches', () => {
|
|
93
|
+
const clusters = [
|
|
94
|
+
{
|
|
95
|
+
id: 'fleet-default/c-m-abc123',
|
|
96
|
+
metadata: { name: 'c-m-abc123' },
|
|
97
|
+
nameDisplay: 'cluster-alpha',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: 'fleet-default/c-m-def456',
|
|
101
|
+
metadata: { name: 'c-m-def456' },
|
|
102
|
+
nameDisplay: 'cluster-beta',
|
|
103
|
+
}
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
const targets = [
|
|
107
|
+
{ clusterName: 'c-m-abc123' },
|
|
108
|
+
{ clusterName: 'cluster-beta' },
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
const app = createFleetApplication(targets, clusters);
|
|
112
|
+
|
|
113
|
+
expect(app.targetClusters).toStrictEqual([clusters[0], clusters[1]]);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should return empty array when targets is empty', () => {
|
|
117
|
+
const app = createFleetApplication([], []);
|
|
118
|
+
|
|
119
|
+
expect(app.targetClusters).toStrictEqual([]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should return empty array when targets is undefined', () => {
|
|
123
|
+
const app = createFleetApplication(undefined, []);
|
|
124
|
+
|
|
125
|
+
expect(app.targetClusters).toStrictEqual([]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should return empty array when workspace has no clusters', () => {
|
|
129
|
+
const app = createFleetApplication([{ clusterName: 'any-name' }], []);
|
|
130
|
+
|
|
131
|
+
expect(app.targetClusters).toStrictEqual([]);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('should handle cluster with undefined nameDisplay gracefully', () => {
|
|
135
|
+
const clusters = [
|
|
136
|
+
{
|
|
137
|
+
id: 'fleet-default/c-m-abc123',
|
|
138
|
+
metadata: { name: 'c-m-abc123' },
|
|
139
|
+
nameDisplay: undefined,
|
|
140
|
+
}
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
const app = createFleetApplication([{ clusterName: 'c-m-abc123' }], clusters);
|
|
144
|
+
|
|
145
|
+
expect(app.targetClusters).toStrictEqual([clusters[0]]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should return local cluster targets when workspace is fleet-local', () => {
|
|
149
|
+
const localTargetClusters = [
|
|
150
|
+
{
|
|
151
|
+
id: 'fleet-local/local',
|
|
152
|
+
metadata: { name: 'local' },
|
|
153
|
+
nameDisplay: 'local',
|
|
154
|
+
}
|
|
155
|
+
];
|
|
156
|
+
|
|
157
|
+
const groups = [
|
|
158
|
+
{
|
|
159
|
+
id: 'fleet-local/default',
|
|
160
|
+
targetClusters: localTargetClusters,
|
|
161
|
+
}
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
const app = createFleetApplication([], [], 'fleet-local', groups);
|
|
165
|
+
|
|
166
|
+
expect(app.targetClusters).toStrictEqual(localTargetClusters);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should return empty array when workspace is fleet-local and default group is missing', () => {
|
|
170
|
+
const app = createFleetApplication([], [], 'fleet-local', []);
|
|
171
|
+
|
|
172
|
+
expect(app.targetClusters).toStrictEqual([]);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
});
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import FleetBundle from '@shell/models/fleet.cattle.io.bundle.js';
|
|
2
|
+
|
|
3
|
+
describe('class FleetBundle', () => {
|
|
4
|
+
afterEach(() => {
|
|
5
|
+
jest.restoreAllMocks();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
describe('targetClusters', () => {
|
|
9
|
+
function createFleetBundle(targets: any[], clusters: any[], workspaceId = 'fleet-default', groups: any[] = []) {
|
|
10
|
+
const workspace = {
|
|
11
|
+
id: workspaceId,
|
|
12
|
+
clusters,
|
|
13
|
+
clusterGroups: groups,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
jest.spyOn(FleetBundle.prototype, '$getters', 'get').mockReturnValue({ byId: () => workspace });
|
|
17
|
+
|
|
18
|
+
return new FleetBundle({
|
|
19
|
+
metadata: { namespace: workspaceId },
|
|
20
|
+
spec: { targets },
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
it.each([
|
|
25
|
+
[
|
|
26
|
+
'metadata.name',
|
|
27
|
+
[{ clusterName: 'c-m-abc123' }],
|
|
28
|
+
[{
|
|
29
|
+
id: 'fleet-default/c-m-abc123', metadata: { name: 'c-m-abc123' }, nameDisplay: 'my-cluster'
|
|
30
|
+
}],
|
|
31
|
+
[{
|
|
32
|
+
id: 'fleet-default/c-m-abc123', metadata: { name: 'c-m-abc123' }, nameDisplay: 'my-cluster'
|
|
33
|
+
}],
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
'nameDisplay when metadata.name does not match',
|
|
37
|
+
[{ clusterName: 'my-display-name' }],
|
|
38
|
+
[{
|
|
39
|
+
id: 'fleet-default/c-m-abc123', metadata: { name: 'c-m-abc123' }, nameDisplay: 'my-display-name'
|
|
40
|
+
}],
|
|
41
|
+
[{
|
|
42
|
+
id: 'fleet-default/c-m-abc123', metadata: { name: 'c-m-abc123' }, nameDisplay: 'my-display-name'
|
|
43
|
+
}],
|
|
44
|
+
],
|
|
45
|
+
])('should find cluster by %s', (_label, targets, clusters, expected) => {
|
|
46
|
+
const bundle = createFleetBundle(targets, clusters);
|
|
47
|
+
|
|
48
|
+
expect(bundle.targetClusters).toStrictEqual(expected);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should prefer metadata.name match over nameDisplay match', () => {
|
|
52
|
+
const clusters = [
|
|
53
|
+
{
|
|
54
|
+
id: 'fleet-default/exact-match',
|
|
55
|
+
metadata: { name: 'exact-match' },
|
|
56
|
+
nameDisplay: 'display-a',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'fleet-default/c-m-other',
|
|
60
|
+
metadata: { name: 'c-m-other' },
|
|
61
|
+
nameDisplay: 'exact-match',
|
|
62
|
+
}
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
const bundle = createFleetBundle([{ clusterName: 'exact-match' }], clusters);
|
|
66
|
+
|
|
67
|
+
expect(bundle.targetClusters).toStrictEqual([clusters[0]]);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should return empty array when no cluster matches by name or nameDisplay', () => {
|
|
71
|
+
const clusters = [
|
|
72
|
+
{
|
|
73
|
+
id: 'fleet-default/c-m-abc123',
|
|
74
|
+
metadata: { name: 'c-m-abc123' },
|
|
75
|
+
nameDisplay: 'my-cluster',
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
const bundle = createFleetBundle([{ clusterName: 'non-existent' }], clusters);
|
|
80
|
+
|
|
81
|
+
expect(bundle.targetClusters).toStrictEqual([]);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should handle multiple targets with mixed name and nameDisplay matches', () => {
|
|
85
|
+
const clusters = [
|
|
86
|
+
{
|
|
87
|
+
id: 'fleet-default/c-m-abc123',
|
|
88
|
+
metadata: { name: 'c-m-abc123' },
|
|
89
|
+
nameDisplay: 'cluster-alpha',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 'fleet-default/c-m-def456',
|
|
93
|
+
metadata: { name: 'c-m-def456' },
|
|
94
|
+
nameDisplay: 'cluster-beta',
|
|
95
|
+
}
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
const targets = [
|
|
99
|
+
{ clusterName: 'c-m-abc123' },
|
|
100
|
+
{ clusterName: 'cluster-beta' },
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
const bundle = createFleetBundle(targets, clusters);
|
|
104
|
+
|
|
105
|
+
expect(bundle.targetClusters).toStrictEqual([clusters[0], clusters[1]]);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should return empty array when workspace has no clusters', () => {
|
|
109
|
+
const bundle = createFleetBundle([{ clusterName: 'any-name' }], []);
|
|
110
|
+
|
|
111
|
+
expect(bundle.targetClusters).toStrictEqual([]);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should handle cluster with undefined nameDisplay gracefully', () => {
|
|
115
|
+
const clusters = [
|
|
116
|
+
{
|
|
117
|
+
id: 'fleet-default/c-m-abc123',
|
|
118
|
+
metadata: { name: 'c-m-abc123' },
|
|
119
|
+
nameDisplay: undefined,
|
|
120
|
+
}
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
const bundle = createFleetBundle([{ clusterName: 'c-m-abc123' }], clusters);
|
|
124
|
+
|
|
125
|
+
expect(bundle.targetClusters).toStrictEqual([clusters[0]]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should not match by nameDisplay when nameDisplay is undefined and target uses a different name', () => {
|
|
129
|
+
const clusters = [
|
|
130
|
+
{
|
|
131
|
+
id: 'fleet-default/c-m-abc123',
|
|
132
|
+
metadata: { name: 'c-m-abc123' },
|
|
133
|
+
nameDisplay: undefined,
|
|
134
|
+
}
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
const bundle = createFleetBundle([{ clusterName: 'some-other-name' }], clusters);
|
|
138
|
+
|
|
139
|
+
expect(bundle.targetClusters).toStrictEqual([]);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should return local cluster targets when workspace is fleet-local', () => {
|
|
143
|
+
const localTargetClusters = [
|
|
144
|
+
{
|
|
145
|
+
id: 'fleet-local/local',
|
|
146
|
+
metadata: { name: 'local' },
|
|
147
|
+
nameDisplay: 'local',
|
|
148
|
+
}
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
const groups = [
|
|
152
|
+
{
|
|
153
|
+
id: 'fleet-local/default',
|
|
154
|
+
targetClusters: localTargetClusters,
|
|
155
|
+
}
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
const bundle = createFleetBundle([], [], 'fleet-local', groups);
|
|
159
|
+
|
|
160
|
+
expect(bundle.targetClusters).toStrictEqual(localTargetClusters);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should return empty array when workspace is fleet-local and default group is missing', () => {
|
|
164
|
+
const bundle = createFleetBundle([], [], 'fleet-local', []);
|
|
165
|
+
|
|
166
|
+
expect(bundle.targetClusters).toStrictEqual([]);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import HelmOp from '@shell/models/fleet.cattle.io.helmop.js';
|
|
2
|
+
import { SUSE_APP_COLLECTION_REPO_URL } from '@shell/utils/fleet-appco';
|
|
3
|
+
|
|
4
|
+
const mockIsRancherPrime = jest.fn(() => true);
|
|
5
|
+
|
|
6
|
+
jest.mock('@shell/config/version', () => ({ isRancherPrime: () => mockIsRancherPrime() }));
|
|
2
7
|
|
|
3
8
|
describe('class HelmOp', () => {
|
|
4
9
|
let instance;
|
|
5
10
|
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
mockIsRancherPrime.mockReturnValue(true);
|
|
13
|
+
});
|
|
14
|
+
|
|
6
15
|
describe('source getter', () => {
|
|
7
16
|
it('should return correct source for SOURCE_TYPE.REPO (HTTPS)', () => {
|
|
8
17
|
instance = new HelmOp({
|
|
@@ -221,4 +230,79 @@ describe('class HelmOp', () => {
|
|
|
221
230
|
expect(sourceSub.display).toBe('');
|
|
222
231
|
});
|
|
223
232
|
});
|
|
233
|
+
|
|
234
|
+
describe('isSuseAppCollectionFromUI', () => {
|
|
235
|
+
it('should return true when annotation is set', () => {
|
|
236
|
+
instance = new HelmOp({ metadata: { annotations: { 'catalog.cattle.io/suse-application-collection': 'true' } }, spec: { helm: {} } });
|
|
237
|
+
|
|
238
|
+
expect(instance.isSuseAppCollectionFromUI).toBe(true);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should return false when annotation is missing', () => {
|
|
242
|
+
instance = new HelmOp({ metadata: { annotations: {} }, spec: { helm: {} } });
|
|
243
|
+
|
|
244
|
+
expect(instance.isSuseAppCollectionFromUI).toBe(false);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
describe('isSuseAppCollection', () => {
|
|
249
|
+
it('should return true even when not Rancher Prime if annotation is set', () => {
|
|
250
|
+
mockIsRancherPrime.mockReturnValue(false);
|
|
251
|
+
instance = new HelmOp({
|
|
252
|
+
metadata: { annotations: { 'catalog.cattle.io/suse-application-collection': 'true' } },
|
|
253
|
+
spec: { helm: {} }
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
expect(instance.isSuseAppCollection).toBe(true);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('should return true when annotation is set and Rancher Prime', () => {
|
|
260
|
+
instance = new HelmOp({
|
|
261
|
+
metadata: { annotations: { 'catalog.cattle.io/suse-application-collection': 'true' } },
|
|
262
|
+
spec: { helm: {} }
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
expect(instance.isSuseAppCollection).toBe(true);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('should return true when repo URL starts with SUSE_APP_COLLECTION_REPO_URL', () => {
|
|
269
|
+
instance = new HelmOp({
|
|
270
|
+
metadata: {},
|
|
271
|
+
spec: { helm: { repo: `${ SUSE_APP_COLLECTION_REPO_URL }/my-chart` } }
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
expect(instance.isSuseAppCollection).toBe(true);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('should return false when no annotation and different repo URL', () => {
|
|
278
|
+
instance = new HelmOp({
|
|
279
|
+
metadata: {},
|
|
280
|
+
spec: { helm: { repo: 'oci://other-registry.io/charts' } }
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
expect(instance.isSuseAppCollection).toBe(false);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
describe('applicationType', () => {
|
|
288
|
+
it('should return "SUSE AppCo" when isSuseAppCollectionFromUI is true', () => {
|
|
289
|
+
instance = new HelmOp({
|
|
290
|
+
metadata: { annotations: { 'catalog.cattle.io/suse-application-collection': 'true' } },
|
|
291
|
+
spec: { helm: {} },
|
|
292
|
+
kind: 'HelmOp'
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
expect(instance.applicationType).toStrictEqual('SUSE AppCo');
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('should return kind when not SUSE App Collection from UI', () => {
|
|
299
|
+
instance = new HelmOp({
|
|
300
|
+
metadata: {},
|
|
301
|
+
spec: { helm: {} },
|
|
302
|
+
kind: 'HelmOp'
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
expect(instance.applicationType).toStrictEqual('HelmOp');
|
|
306
|
+
});
|
|
307
|
+
});
|
|
224
308
|
});
|
|
@@ -94,6 +94,28 @@ describe('class MgmtNode', () => {
|
|
|
94
94
|
});
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
+
describe('pool', () => {
|
|
98
|
+
it('should return undefined if nodePoolName is not set', () => {
|
|
99
|
+
const mgmtNode = new MgmtNode({ spec: {} });
|
|
100
|
+
|
|
101
|
+
expect(mgmtNode.pool).toBeUndefined();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should return the node pool when nodePoolName is set', () => {
|
|
105
|
+
const nodePool = { id: 'fleet-local/np1' };
|
|
106
|
+
const mgmtNodeCtx = {
|
|
107
|
+
rootGetters: {
|
|
108
|
+
'i18n/t': t,
|
|
109
|
+
'management/byId': jest.fn(() => nodePool)
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const mgmtNode = new MgmtNode({ spec: { nodePoolName: 'fleet-local:np1' } }, mgmtNodeCtx);
|
|
113
|
+
|
|
114
|
+
expect(mgmtNode.pool).toStrictEqual(nodePool);
|
|
115
|
+
expect(mgmtNodeCtx.rootGetters['management/byId']).toHaveBeenCalledWith('management.cattle.io.nodepool', 'fleet-local/np1');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
97
119
|
describe('canScaleDown', () => {
|
|
98
120
|
const mgmtClusterId = 'test';
|
|
99
121
|
const nodeId = 'test/id';
|
|
@@ -150,6 +150,42 @@ describe('class Namespace', () => {
|
|
|
150
150
|
it.todo('should disableAutoInjection');
|
|
151
151
|
it.todo('should check if confirmRemove');
|
|
152
152
|
|
|
153
|
+
describe('move action availability', () => {
|
|
154
|
+
const SteveModelProto = Object.getPrototypeOf(Namespace.prototype);
|
|
155
|
+
|
|
156
|
+
const makeNamespace = ({ canUpdate }: { canUpdate: boolean }) => {
|
|
157
|
+
const namespace = new Namespace({});
|
|
158
|
+
|
|
159
|
+
jest.spyOn(namespace, '$rootGetters', 'get').mockReturnValue({
|
|
160
|
+
isRancher: true,
|
|
161
|
+
isSingleProduct: false,
|
|
162
|
+
'i18n/t': (key: string) => key,
|
|
163
|
+
});
|
|
164
|
+
Object.defineProperty(namespace, 'istioInstalled', { get: () => false, configurable: true });
|
|
165
|
+
Object.defineProperty(namespace, 'canUpdate', { get: () => canUpdate, configurable: true });
|
|
166
|
+
jest.spyOn(SteveModelProto, '_availableActions', 'get').mockReturnValue([]);
|
|
167
|
+
|
|
168
|
+
return namespace;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
it('should include the move action when user can update the namespace', () => {
|
|
172
|
+
const namespace = makeNamespace({ canUpdate: true });
|
|
173
|
+
|
|
174
|
+
const moveAction = namespace.availableActions.find((a: any) => a.action === 'move');
|
|
175
|
+
|
|
176
|
+
expect(moveAction).toBeDefined();
|
|
177
|
+
expect(moveAction.enabled).toBe(true);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should exclude the move action when user cannot update the namespace', () => {
|
|
181
|
+
const namespace = makeNamespace({ canUpdate: false });
|
|
182
|
+
|
|
183
|
+
const moveAction = namespace.availableActions.find((a: any) => a.action === 'move');
|
|
184
|
+
|
|
185
|
+
expect(moveAction).toBeUndefined();
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
153
189
|
describe('handling listLocation', () => {
|
|
154
190
|
it.each([
|
|
155
191
|
['c-cluster-product-projectsnamespaces', true],
|