@rancher/shell 3.0.9-rc.5 → 3.0.9
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/images/providers/oci-open-containers.svg +22 -0
- package/assets/images/providers/traefik.png +0 -0
- package/assets/styles/themes/_dark.scss +2 -0
- package/assets/styles/themes/_light.scss +2 -0
- package/assets/styles/themes/_modern.scss +6 -0
- package/assets/translations/en-us.yaml +129 -25
- package/components/CruResource.vue +3 -1
- package/components/ExplorerProjectsNamespaces.vue +12 -12
- package/components/IconOrSvg.vue +61 -42
- package/components/Resource/Detail/Card/StatusCard/__tests__/StatusCard.test.ts +109 -0
- package/components/Resource/Detail/Card/StatusCard/index.vue +21 -4
- package/components/Resource/Detail/Metadata/IdentifyingInformation/__tests__/identifying-fields.test.ts +19 -2
- package/components/Resource/Detail/Metadata/IdentifyingInformation/identifying-fields.ts +19 -11
- package/components/Resource/Detail/ResourcePopover/__tests__/index.test.ts +12 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +2 -0
- package/components/Resource/Detail/ResourceRow.vue +2 -2
- package/components/ResourceList/index.vue +7 -4
- package/components/SortableTable/index.vue +2 -2
- package/components/Window/ContainerLogs.vue +48 -37
- package/components/fleet/FleetClusterTargets/TargetsList.vue +2 -2
- package/components/fleet/FleetClusterTargets/index.vue +6 -1
- package/components/fleet/GitRepoAdvancedTab.vue +333 -0
- package/components/fleet/GitRepoMetadataTab.vue +43 -0
- package/components/fleet/GitRepoRepositoryTab.vue +101 -0
- package/components/fleet/GitRepoTargetTab.vue +77 -0
- package/components/fleet/HelmOpAdvancedTab.vue +247 -0
- package/components/fleet/HelmOpChartTab.vue +158 -0
- package/components/fleet/HelmOpMetadataTab.vue +46 -0
- package/components/fleet/HelmOpTargetTab.vue +84 -0
- package/components/fleet/HelmOpValuesTab.vue +147 -0
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +119 -70
- package/components/form/BannerSettings.vue +2 -2
- package/components/form/NodeScheduling.vue +81 -7
- package/components/form/NotificationSettings.vue +2 -2
- package/components/form/PodAffinity.vue +1 -36
- package/components/form/ResourceLabeledSelect.vue +8 -4
- package/components/form/ResourceQuota/Namespace.vue +30 -9
- package/components/form/ResourceQuota/NamespaceRow.vue +25 -7
- package/components/form/ResourceQuota/Project.vue +140 -82
- package/components/form/ResourceQuota/ResourceQuotaEntry.vue +145 -0
- package/components/form/ResourceQuota/__tests__/Namespace.test.ts +307 -0
- package/components/form/ResourceQuota/__tests__/NamespaceRow.test.ts +281 -0
- package/components/form/ResourceQuota/__tests__/Project.test.ts +274 -27
- package/components/form/ResourceQuota/__tests__/ResourceQuotaEntry.test.ts +215 -0
- package/components/form/SchedulingCustomization.vue +14 -6
- package/components/form/SelectOrCreateAuthSecret.vue +107 -18
- package/components/form/__tests__/NodeScheduling.test.ts +12 -9
- package/components/form/__tests__/PodAffinity.test.ts +21 -2
- package/components/form/__tests__/SchedulingCustomization.test.ts +240 -0
- package/components/formatter/ClusterLink.vue +8 -0
- package/components/formatter/SecretOrigin.vue +79 -0
- package/config/labels-annotations.js +7 -6
- package/config/pagination-table-headers.js +6 -4
- package/config/product/explorer.js +1 -11
- package/config/product/manager.js +0 -1
- package/config/query-params.js +3 -0
- package/config/settings.ts +15 -2
- package/config/table-headers.js +21 -17
- package/config/types.js +23 -8
- package/detail/fleet.cattle.io.cluster.vue +1 -1
- package/detail/workload/index.vue +11 -16
- package/dialog/DeactivateDriverDialog.vue +1 -1
- package/dialog/FeatureFlagListDialog.vue +1 -1
- package/dialog/Ipv6NetworkingDialog.vue +156 -0
- package/dialog/ScalePoolDownDialog.vue +2 -2
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +1 -1
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +1 -0
- package/edit/__tests__/management.cattle.io.project.test.js +56 -128
- package/edit/auth/oidc.vue +1 -1
- package/edit/catalog.cattle.io.clusterrepo.vue +155 -25
- package/edit/fleet.cattle.io.gitrepo.vue +153 -283
- package/edit/fleet.cattle.io.helmop.vue +190 -332
- package/edit/management.cattle.io.project.vue +5 -42
- package/edit/management.cattle.io.setting.vue +6 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/__tests__/auth.spec.ts +145 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/__tests__/index.test.ts +202 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/__tests__/tls.spec.ts +226 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/auth.vue +24 -21
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/__tests__/opsgenie.spec.ts +157 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/__tests__/pagerduty.spec.ts +132 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/__tests__/slack.spec.ts +108 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/pagerduty.vue +2 -1
- package/edit/monitoring.coreos.com.receiver/__tests__/auth.spec.ts +165 -0
- package/edit/monitoring.coreos.com.receiver/__tests__/index.test.ts +153 -0
- package/edit/monitoring.coreos.com.receiver/__tests__/tls.spec.ts +115 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/email.spec.ts +86 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/opsgenie.spec.ts +209 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/pagerduty.spec.ts +105 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/slack.spec.ts +92 -0
- package/edit/monitoring.coreos.com.receiver/types/__tests__/webhook.spec.ts +131 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/Basics.test.ts +55 -24
- package/edit/provisioning.cattle.io.cluster/__tests__/Networking.test.ts +1 -103
- package/edit/provisioning.cattle.io.cluster/__tests__/index.test.ts +13 -1
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2-fleet-cluster-agent.test.ts +283 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +65 -49
- package/edit/provisioning.cattle.io.cluster/ingress/IngressCards.vue +114 -0
- package/edit/provisioning.cattle.io.cluster/ingress/IngressConfiguration.vue +158 -0
- package/edit/provisioning.cattle.io.cluster/rke2.vue +167 -69
- package/edit/provisioning.cattle.io.cluster/shared.ts +36 -1
- package/edit/provisioning.cattle.io.cluster/tabs/AgentConfiguration.vue +2 -1
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +70 -7
- package/edit/provisioning.cattle.io.cluster/tabs/Ingress.vue +343 -0
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +2 -1
- package/edit/provisioning.cattle.io.cluster/tabs/etcd/__tests__/S3Config.test.ts +13 -1
- package/edit/provisioning.cattle.io.cluster/tabs/networking/index.vue +10 -44
- package/edit/secret/index.vue +1 -1
- package/edit/token.vue +68 -29
- package/edit/workload/__tests__/index.test.ts +2 -37
- package/edit/workload/index.vue +6 -2
- package/edit/workload/mixins/workload.js +0 -32
- package/list/__tests__/management.cattle.io.setting.test.ts +198 -0
- package/list/management.cattle.io.setting.vue +13 -0
- package/list/provisioning.cattle.io.cluster.vue +50 -1
- package/list/secret.vue +4 -9
- package/list/service.vue +6 -8
- package/machine-config/amazonec2.vue +11 -4
- package/machine-config/components/EC2Networking.vue +46 -30
- package/machine-config/components/__tests__/EC2Networking.test.ts +7 -7
- package/machine-config/components/__tests__/utils/vpcSubnetMockData.js +0 -9
- package/machine-config/digitalocean.vue +3 -3
- package/models/__tests__/chart.test.ts +2 -2
- package/models/__tests__/namespace.test.ts +11 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +96 -0
- package/models/__tests__/workload.test.ts +42 -1
- package/models/catalog.cattle.io.clusterrepo.js +30 -4
- package/models/chart.js +3 -3
- package/models/ext.cattle.io.token.js +48 -0
- package/models/kontainerdriver.js +2 -2
- package/models/namespace.js +7 -1
- package/models/nodedriver.js +2 -2
- package/models/provisioning.cattle.io.cluster.js +28 -7
- package/models/secret.js +0 -17
- package/models/service.js +44 -1
- package/models/token.js +4 -0
- package/models/workload.js +12 -6
- package/package.json +1 -1
- package/pages/account/index.vue +96 -67
- package/pages/auth/setup.vue +5 -14
- package/pages/c/_cluster/apps/charts/AppChartCardFooter.vue +45 -18
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +4 -1
- package/pages/c/_cluster/apps/charts/index.vue +82 -3
- package/pages/c/_cluster/apps/charts/install.vue +317 -42
- package/pages/c/_cluster/explorer/tools/index.vue +1 -1
- package/pages/c/_cluster/manager/cloudCredential/index.vue +1 -1
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -4
- package/pages/c/_cluster/settings/index.vue +3 -1
- package/pages/c/_cluster/uiplugins/index.vue +1 -1
- package/plugins/dashboard-store/__tests__/getters.test.ts +108 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +27 -0
- package/plugins/dashboard-store/actions.js +3 -8
- package/plugins/dashboard-store/getters.js +7 -5
- package/plugins/dashboard-store/mutations.js +4 -1
- package/plugins/dashboard-store/resource-class.js +3 -3
- package/plugins/steve/__tests__/steve-class.test.ts +102 -141
- package/plugins/steve/steve-class.js +12 -3
- package/plugins/steve/steve-pagination-utils.ts +6 -2
- package/rancher-components/RcIcon/types.ts +2 -0
- package/rancher-components/RcItemCard/RcItemCard.vue +72 -20
- package/store/prefs.js +3 -0
- package/types/aws-sdk.d.ts +121 -0
- package/types/resources/node.ts +15 -0
- package/types/shell/index.d.ts +537 -506
- package/types/store/pagination.types.ts +5 -5
- package/utils/__tests__/array.test.ts +1 -29
- package/utils/__tests__/cluster-agent-configuration.test.ts +203 -0
- package/utils/array.ts +0 -11
- package/utils/aws.ts +21 -0
- package/utils/cluster.js +22 -2
- package/utils/selector-typed.ts +1 -1
- package/utils/svg-filter.js +4 -3
- package/components/__tests__/ProjectRow.test.ts +0 -206
- package/components/form/ResourceQuota/ProjectRow.vue +0 -277
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import Namespace from '@shell/components/form/ResourceQuota/Namespace.vue';
|
|
3
|
+
|
|
4
|
+
describe('namespace', () => {
|
|
5
|
+
const makeProject = (overrides: Record<string, unknown> = {}) => ({
|
|
6
|
+
spec: {
|
|
7
|
+
resourceQuota: { limit: {} },
|
|
8
|
+
namespaceDefaultResourceQuota: { limit: {} }
|
|
9
|
+
},
|
|
10
|
+
namespaces: [],
|
|
11
|
+
...overrides
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const defaultProps = {
|
|
15
|
+
mode: 'edit',
|
|
16
|
+
types: [],
|
|
17
|
+
value: { resourceQuota: { limit: {} } },
|
|
18
|
+
project: makeProject()
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const createWrapper = (propsOverrides: Record<string, unknown> = {}) => {
|
|
22
|
+
return shallowMount(Namespace, { props: { ...defaultProps, ...propsOverrides } });
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
describe('computed: projectResourceQuotaLimits', () => {
|
|
26
|
+
it('passes standard quota keys through unchanged', () => {
|
|
27
|
+
const wrapper: any = createWrapper({
|
|
28
|
+
project: makeProject({
|
|
29
|
+
spec: {
|
|
30
|
+
resourceQuota: { limit: { limitsCpu: '2000m', configMaps: '10' } },
|
|
31
|
+
namespaceDefaultResourceQuota: { limit: {} }
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(wrapper.vm.projectResourceQuotaLimits).toStrictEqual({
|
|
37
|
+
limitsCpu: '2000m',
|
|
38
|
+
configMaps: '10'
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('flattens extended resources to dotted keys', () => {
|
|
43
|
+
const wrapper: any = createWrapper({
|
|
44
|
+
project: makeProject({
|
|
45
|
+
spec: {
|
|
46
|
+
resourceQuota: { limit: { extended: { 'requests.nvidia.com/gpu': '4' } } },
|
|
47
|
+
namespaceDefaultResourceQuota: { limit: {} }
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
expect(wrapper.vm.projectResourceQuotaLimits).toStrictEqual({ 'extended.requests.nvidia.com/gpu': '4' });
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('flattens multiple extended entries alongside standard keys', () => {
|
|
56
|
+
const wrapper: any = createWrapper({
|
|
57
|
+
project: makeProject({
|
|
58
|
+
spec: {
|
|
59
|
+
resourceQuota: {
|
|
60
|
+
limit: {
|
|
61
|
+
limitsCpu: '2000m',
|
|
62
|
+
extended: {
|
|
63
|
+
'requests.nvidia.com/gpu': '4',
|
|
64
|
+
'example.com/fpga': '2'
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
namespaceDefaultResourceQuota: { limit: {} }
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
expect(wrapper.vm.projectResourceQuotaLimits).toStrictEqual({
|
|
74
|
+
limitsCpu: '2000m',
|
|
75
|
+
'extended.requests.nvidia.com/gpu': '4',
|
|
76
|
+
'extended.example.com/fpga': '2'
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('returns an empty object when limit is empty', () => {
|
|
81
|
+
const wrapper: any = createWrapper();
|
|
82
|
+
|
|
83
|
+
expect(wrapper.vm.projectResourceQuotaLimits).toStrictEqual({});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('flattens an extended resource whose identifier itself starts with "extended."', () => {
|
|
87
|
+
const wrapper: any = createWrapper({
|
|
88
|
+
project: makeProject({
|
|
89
|
+
spec: {
|
|
90
|
+
resourceQuota: { limit: { extended: { 'extended.nvidia.com/gpu': '4' } } },
|
|
91
|
+
namespaceDefaultResourceQuota: { limit: {} }
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(wrapper.vm.projectResourceQuotaLimits).toStrictEqual({ 'extended.extended.nvidia.com/gpu': '4' });
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('returns an empty object when resourceQuota is not set on the project', () => {
|
|
100
|
+
const wrapper: any = createWrapper({
|
|
101
|
+
project: makeProject({
|
|
102
|
+
spec: {
|
|
103
|
+
resourceQuota: undefined,
|
|
104
|
+
namespaceDefaultResourceQuota: { limit: {} }
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(wrapper.vm.projectResourceQuotaLimits).toStrictEqual({});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('computed: namespaceResourceQuotaLimits', () => {
|
|
114
|
+
it('passes standard quota keys through and preserves namespace id', () => {
|
|
115
|
+
const wrapper: any = createWrapper({
|
|
116
|
+
project: makeProject({
|
|
117
|
+
namespaces: [
|
|
118
|
+
{ id: 'ns1', resourceQuota: { limit: { limitsCpu: '500m' } } }
|
|
119
|
+
]
|
|
120
|
+
})
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(wrapper.vm.namespaceResourceQuotaLimits).toStrictEqual([
|
|
124
|
+
{ id: 'ns1', limitsCpu: '500m' }
|
|
125
|
+
]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('flattens extended resources for each namespace', () => {
|
|
129
|
+
const wrapper: any = createWrapper({
|
|
130
|
+
project: makeProject({
|
|
131
|
+
namespaces: [
|
|
132
|
+
{ id: 'ns1', resourceQuota: { limit: { extended: { 'requests.nvidia.com/gpu': '2' } } } }
|
|
133
|
+
]
|
|
134
|
+
})
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
expect(wrapper.vm.namespaceResourceQuotaLimits).toStrictEqual([
|
|
138
|
+
{ id: 'ns1', 'extended.requests.nvidia.com/gpu': '2' }
|
|
139
|
+
]);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('handles multiple namespaces with a mix of standard and extended keys', () => {
|
|
143
|
+
const wrapper: any = createWrapper({
|
|
144
|
+
project: makeProject({
|
|
145
|
+
namespaces: [
|
|
146
|
+
{ id: 'ns1', resourceQuota: { limit: { limitsCpu: '500m' } } },
|
|
147
|
+
{ id: 'ns2', resourceQuota: { limit: { extended: { 'requests.nvidia.com/gpu': '1' } } } }
|
|
148
|
+
]
|
|
149
|
+
})
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
expect(wrapper.vm.namespaceResourceQuotaLimits).toHaveLength(2);
|
|
153
|
+
expect(wrapper.vm.namespaceResourceQuotaLimits[0]).toStrictEqual({ id: 'ns1', limitsCpu: '500m' });
|
|
154
|
+
expect(wrapper.vm.namespaceResourceQuotaLimits[1]).toStrictEqual({ id: 'ns2', 'extended.requests.nvidia.com/gpu': '1' });
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('returns an empty array when the project has no namespaces', () => {
|
|
158
|
+
const wrapper: any = createWrapper();
|
|
159
|
+
|
|
160
|
+
expect(wrapper.vm.namespaceResourceQuotaLimits).toStrictEqual([]);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
describe('computed: defaultResourceQuotaLimits', () => {
|
|
165
|
+
it('passes standard quota keys through unchanged', () => {
|
|
166
|
+
const wrapper: any = createWrapper({
|
|
167
|
+
project: makeProject({
|
|
168
|
+
spec: {
|
|
169
|
+
resourceQuota: { limit: {} },
|
|
170
|
+
namespaceDefaultResourceQuota: { limit: { limitsCpu: '1000m' } }
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
expect(wrapper.vm.defaultResourceQuotaLimits).toStrictEqual({ limitsCpu: '1000m' });
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('flattens extended quota keys', () => {
|
|
179
|
+
const wrapper: any = createWrapper({
|
|
180
|
+
project: makeProject({
|
|
181
|
+
spec: {
|
|
182
|
+
resourceQuota: { limit: {} },
|
|
183
|
+
namespaceDefaultResourceQuota: { limit: { extended: { 'requests.nvidia.com/gpu': '2' } } }
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
expect(wrapper.vm.defaultResourceQuotaLimits).toStrictEqual({ 'extended.requests.nvidia.com/gpu': '2' });
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('returns an empty object when the namespaceDefaultResourceQuota limit is missing', () => {
|
|
192
|
+
const wrapper: any = createWrapper({
|
|
193
|
+
project: makeProject({
|
|
194
|
+
spec: {
|
|
195
|
+
resourceQuota: { limit: {} },
|
|
196
|
+
namespaceDefaultResourceQuota: {}
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
expect(wrapper.vm.defaultResourceQuotaLimits).toStrictEqual({});
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe('computed: editableLimits', () => {
|
|
206
|
+
it('returns standard keys for standard quota types', () => {
|
|
207
|
+
const wrapper: any = createWrapper({
|
|
208
|
+
project: makeProject({
|
|
209
|
+
spec: {
|
|
210
|
+
resourceQuota: { limit: { limitsCpu: '2000m', configMaps: '10' } },
|
|
211
|
+
namespaceDefaultResourceQuota: { limit: {} }
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
expect(wrapper.vm.editableLimits).toStrictEqual(['limitsCpu', 'configMaps']);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('returns dotted keys for extended quota types', () => {
|
|
220
|
+
const wrapper: any = createWrapper({
|
|
221
|
+
project: makeProject({
|
|
222
|
+
spec: {
|
|
223
|
+
resourceQuota: { limit: { extended: { 'requests.nvidia.com/gpu': '4' } } },
|
|
224
|
+
namespaceDefaultResourceQuota: { limit: {} }
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
expect(wrapper.vm.editableLimits).toStrictEqual(['extended.requests.nvidia.com/gpu']);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('returns an empty array when there are no project quota limits', () => {
|
|
233
|
+
const wrapper: any = createWrapper();
|
|
234
|
+
|
|
235
|
+
expect(wrapper.vm.editableLimits).toStrictEqual([]);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe('method: update', () => {
|
|
240
|
+
it('sets standard keys directly on the limit object', () => {
|
|
241
|
+
const value = { resourceQuota: { limit: { limitsCpu: '1000m' } } };
|
|
242
|
+
const wrapper: any = createWrapper({ value });
|
|
243
|
+
|
|
244
|
+
wrapper.vm.update('configMaps', '20');
|
|
245
|
+
|
|
246
|
+
expect(value.resourceQuota.limit).toMatchObject({ configMaps: '20', limitsCpu: '1000m' });
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('writes an extended key into the nested limit.extended object', () => {
|
|
250
|
+
const value = { resourceQuota: { limit: {} } };
|
|
251
|
+
const wrapper: any = createWrapper({ value });
|
|
252
|
+
|
|
253
|
+
wrapper.vm.update('extended.requests.nvidia.com/gpu', '4');
|
|
254
|
+
|
|
255
|
+
expect(value.resourceQuota).toStrictEqual({ limit: { extended: { 'requests.nvidia.com/gpu': '4' } } });
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('merges a new extended key with existing extended entries', () => {
|
|
259
|
+
const value = { resourceQuota: { limit: { extended: { 'requests.nvidia.com/gpu': '2' } } } };
|
|
260
|
+
const wrapper: any = createWrapper({ value });
|
|
261
|
+
|
|
262
|
+
wrapper.vm.update('extended.example.com/fpga', '1');
|
|
263
|
+
|
|
264
|
+
expect(value.resourceQuota.limit.extended).toStrictEqual({
|
|
265
|
+
'requests.nvidia.com/gpu': '2',
|
|
266
|
+
'example.com/fpga': '1'
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('overwrites an existing extended key with the new value', () => {
|
|
271
|
+
const value = { resourceQuota: { limit: { extended: { 'requests.nvidia.com/gpu': '2' } } } };
|
|
272
|
+
const wrapper: any = createWrapper({ value });
|
|
273
|
+
|
|
274
|
+
wrapper.vm.update('extended.requests.nvidia.com/gpu', '8');
|
|
275
|
+
|
|
276
|
+
expect(value.resourceQuota.limit.extended).toStrictEqual({ 'requests.nvidia.com/gpu': '8' });
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('does not affect existing standard keys when setting an extended key', () => {
|
|
280
|
+
const value = { resourceQuota: { limit: { limitsCpu: '2000m' } } };
|
|
281
|
+
const wrapper: any = createWrapper({ value });
|
|
282
|
+
|
|
283
|
+
wrapper.vm.update('extended.requests.nvidia.com/gpu', '4');
|
|
284
|
+
|
|
285
|
+
expect((value.resourceQuota.limit as any).limitsCpu).toBe('2000m');
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it('correctly round-trips an extended resource whose identifier starts with "extended."', () => {
|
|
289
|
+
const value = { resourceQuota: { limit: {} } };
|
|
290
|
+
const wrapper: any = createWrapper({ value });
|
|
291
|
+
|
|
292
|
+
wrapper.vm.update('extended.extended.nvidia.com/gpu', '4');
|
|
293
|
+
|
|
294
|
+
expect(value.resourceQuota.limit).toStrictEqual({ extended: { 'extended.nvidia.com/gpu': '4' } });
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('does not write an extended entry into the standard keys when updating a standard key', () => {
|
|
298
|
+
const value = { resourceQuota: { limit: {} } };
|
|
299
|
+
const wrapper: any = createWrapper({ value });
|
|
300
|
+
|
|
301
|
+
wrapper.vm.update('limitsCpu', '500m');
|
|
302
|
+
|
|
303
|
+
expect((value.resourceQuota.limit as any).extended).toBeUndefined();
|
|
304
|
+
expect((value.resourceQuota.limit as any).limitsCpu).toBe('500m');
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
});
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import NamespaceRow from '@shell/components/form/ResourceQuota/NamespaceRow.vue';
|
|
3
|
+
|
|
4
|
+
describe('namespaceRow', () => {
|
|
5
|
+
const storeMock = { getters: { 'i18n/t': (key: string) => key } };
|
|
6
|
+
|
|
7
|
+
const standardType = {
|
|
8
|
+
value: 'limitsCpu',
|
|
9
|
+
inputExponent: -1,
|
|
10
|
+
baseUnit: '',
|
|
11
|
+
placeholder: 'Enter CPU',
|
|
12
|
+
increment: 1,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const extendedType = {
|
|
16
|
+
value: 'extended',
|
|
17
|
+
inputExponent: 0,
|
|
18
|
+
baseUnit: '',
|
|
19
|
+
placeholder: 'Enter value',
|
|
20
|
+
increment: 1,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const defaultProps = {
|
|
24
|
+
mode: 'edit',
|
|
25
|
+
type: 'limitsCpu',
|
|
26
|
+
types: [standardType, extendedType],
|
|
27
|
+
value: { limit: { limitsCpu: '1000m' } },
|
|
28
|
+
namespace: { id: 'test-ns' },
|
|
29
|
+
projectResourceQuotaLimits: { limitsCpu: '2000m' },
|
|
30
|
+
namespaceResourceQuotaLimits: [],
|
|
31
|
+
defaultResourceQuotaLimits: { limitsCpu: '500m' },
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const createWrapper = (propsOverrides: Record<string, unknown> = {}) => {
|
|
35
|
+
return shallowMount(NamespaceRow, {
|
|
36
|
+
props: { ...defaultProps, ...propsOverrides },
|
|
37
|
+
global: { mocks: { $store: storeMock } },
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
describe('computed: displayType', () => {
|
|
42
|
+
it('returns the type unchanged for standard quota types', () => {
|
|
43
|
+
const wrapper: any = createWrapper({ type: 'limitsCpu' });
|
|
44
|
+
|
|
45
|
+
expect(wrapper.vm.displayType).toBe('limitsCpu');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('strips the "extended." prefix for extended quota types', () => {
|
|
49
|
+
const wrapper: any = createWrapper({
|
|
50
|
+
type: 'extended.requests.nvidia.com/gpu',
|
|
51
|
+
value: { limit: { extended: { 'requests.nvidia.com/gpu': '4' } } },
|
|
52
|
+
projectResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '8' },
|
|
53
|
+
defaultResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '2' },
|
|
54
|
+
namespaceResourceQuotaLimits: [],
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(wrapper.vm.displayType).toBe('requests.nvidia.com/gpu');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('strips only the leading "extended." when the resource identifier itself starts with "extended."', () => {
|
|
61
|
+
const wrapper: any = createWrapper({
|
|
62
|
+
type: 'extended.extended.nvidia.com/gpu',
|
|
63
|
+
value: { limit: { extended: { 'extended.nvidia.com/gpu': '4' } } },
|
|
64
|
+
projectResourceQuotaLimits: { 'extended.extended.nvidia.com/gpu': '8' },
|
|
65
|
+
defaultResourceQuotaLimits: { 'extended.extended.nvidia.com/gpu': '2' },
|
|
66
|
+
namespaceResourceQuotaLimits: [],
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(wrapper.vm.displayType).toBe('extended.nvidia.com/gpu');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('computed: currentLimit', () => {
|
|
74
|
+
it('returns the limit value for a standard quota type', () => {
|
|
75
|
+
const wrapper: any = createWrapper({
|
|
76
|
+
type: 'limitsCpu',
|
|
77
|
+
value: { limit: { limitsCpu: '1000m' } },
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(wrapper.vm.currentLimit).toBe('1000m');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('returns undefined when the standard type key is absent from limit', () => {
|
|
84
|
+
const wrapper: any = createWrapper({
|
|
85
|
+
type: 'limitsCpu',
|
|
86
|
+
value: { limit: {} },
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(wrapper.vm.currentLimit).toBeUndefined();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('reads the value from limit.extended for an extended quota type', () => {
|
|
93
|
+
const wrapper: any = createWrapper({
|
|
94
|
+
type: 'extended.requests.nvidia.com/gpu',
|
|
95
|
+
value: { limit: { extended: { 'requests.nvidia.com/gpu': '4' } } },
|
|
96
|
+
projectResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '8' },
|
|
97
|
+
defaultResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '2' },
|
|
98
|
+
namespaceResourceQuotaLimits: [],
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(wrapper.vm.currentLimit).toBe('4');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('returns undefined when limit.extended is absent for an extended quota type', () => {
|
|
105
|
+
const wrapper: any = createWrapper({
|
|
106
|
+
type: 'extended.requests.nvidia.com/gpu',
|
|
107
|
+
value: { limit: {} },
|
|
108
|
+
projectResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '8' },
|
|
109
|
+
defaultResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '2' },
|
|
110
|
+
namespaceResourceQuotaLimits: [],
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
expect(wrapper.vm.currentLimit).toBeUndefined();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('reads the correct value when the resource identifier itself starts with "extended."', () => {
|
|
117
|
+
const wrapper: any = createWrapper({
|
|
118
|
+
type: 'extended.extended.nvidia.com/gpu',
|
|
119
|
+
value: { limit: { extended: { 'extended.nvidia.com/gpu': '4' } } },
|
|
120
|
+
projectResourceQuotaLimits: { 'extended.extended.nvidia.com/gpu': '8' },
|
|
121
|
+
defaultResourceQuotaLimits: { 'extended.extended.nvidia.com/gpu': '2' },
|
|
122
|
+
namespaceResourceQuotaLimits: [],
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
expect(wrapper.vm.currentLimit).toBe('4');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('returns undefined when the extended resource identifier is not in limit.extended', () => {
|
|
129
|
+
const wrapper: any = createWrapper({
|
|
130
|
+
type: 'extended.requests.nvidia.com/gpu',
|
|
131
|
+
value: { limit: { extended: { 'example.com/fpga': '1' } } },
|
|
132
|
+
projectResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '8' },
|
|
133
|
+
defaultResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '2' },
|
|
134
|
+
namespaceResourceQuotaLimits: [],
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
expect(wrapper.vm.currentLimit).toBeUndefined();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it.each([
|
|
141
|
+
['limitsCpu', { limitsCpu: '500m' }, '500m'],
|
|
142
|
+
['configMaps', { configMaps: '10' }, '10'],
|
|
143
|
+
['pods', { pods: '20' }, '20'],
|
|
144
|
+
])('returns the correct value for standard type "%s"', (type, limit, expected) => {
|
|
145
|
+
const wrapper: any = createWrapper({
|
|
146
|
+
type,
|
|
147
|
+
types: [
|
|
148
|
+
{
|
|
149
|
+
value: type, inputExponent: 0, baseUnit: '', placeholder: '', increment: 1
|
|
150
|
+
},
|
|
151
|
+
extendedType,
|
|
152
|
+
],
|
|
153
|
+
value: { limit },
|
|
154
|
+
projectResourceQuotaLimits: { [type]: '100' },
|
|
155
|
+
defaultResourceQuotaLimits: { [type]: '0' },
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
expect(wrapper.vm.currentLimit).toBe(expected);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('mounted(): initial value emission', () => {
|
|
163
|
+
it('emits update:value on mount with the type as the first argument', () => {
|
|
164
|
+
const wrapper: any = createWrapper({
|
|
165
|
+
type: 'limitsCpu',
|
|
166
|
+
value: { limit: { limitsCpu: '1000m' } },
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const emitted = wrapper.emitted('update:value');
|
|
170
|
+
|
|
171
|
+
expect(emitted).toBeTruthy();
|
|
172
|
+
expect(emitted![0][0]).toBe('limitsCpu');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('emits update:value on mount when currentLimit is not set, using defaultResourceQuotaLimits', () => {
|
|
176
|
+
const wrapper: any = createWrapper({
|
|
177
|
+
type: 'limitsCpu',
|
|
178
|
+
value: { limit: {} },
|
|
179
|
+
projectResourceQuotaLimits: { limitsCpu: '2000m' },
|
|
180
|
+
defaultResourceQuotaLimits: { limitsCpu: '500m' },
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const emitted = wrapper.emitted('update:value');
|
|
184
|
+
|
|
185
|
+
expect(emitted).toBeTruthy();
|
|
186
|
+
expect(emitted![0][0]).toBe('limitsCpu');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('emits update:value on mount for an extended quota type', () => {
|
|
190
|
+
const wrapper: any = createWrapper({
|
|
191
|
+
type: 'extended.requests.nvidia.com/gpu',
|
|
192
|
+
value: { limit: { extended: { 'requests.nvidia.com/gpu': '4' } } },
|
|
193
|
+
projectResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '8' },
|
|
194
|
+
defaultResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '2' },
|
|
195
|
+
namespaceResourceQuotaLimits: [],
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const emitted = wrapper.emitted('update:value');
|
|
199
|
+
|
|
200
|
+
expect(emitted).toBeTruthy();
|
|
201
|
+
expect(emitted![0][0]).toBe('extended.requests.nvidia.com/gpu');
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe('computed: totalContribution', () => {
|
|
206
|
+
it('equals zero when currentLimit is 0 and no other namespaces contribute', () => {
|
|
207
|
+
const wrapper: any = createWrapper({
|
|
208
|
+
type: 'limitsCpu',
|
|
209
|
+
value: { limit: { limitsCpu: '0' } },
|
|
210
|
+
projectResourceQuotaLimits: { limitsCpu: '2000m' },
|
|
211
|
+
namespaceResourceQuotaLimits: [],
|
|
212
|
+
defaultResourceQuotaLimits: { limitsCpu: '0' },
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
expect(wrapper.vm.totalContribution).toBe(0);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('includes contributions from other namespaces alongside the current limit', () => {
|
|
219
|
+
// ns2 contributes 500m, current namespace has 0
|
|
220
|
+
const wrapper: any = createWrapper({
|
|
221
|
+
type: 'limitsCpu',
|
|
222
|
+
value: { limit: { limitsCpu: '0' } },
|
|
223
|
+
projectResourceQuotaLimits: { limitsCpu: '2000m' },
|
|
224
|
+
namespaceResourceQuotaLimits: [
|
|
225
|
+
{ id: 'ns2', limitsCpu: '500m' },
|
|
226
|
+
],
|
|
227
|
+
defaultResourceQuotaLimits: { limitsCpu: '0' },
|
|
228
|
+
namespace: { id: 'test-ns' },
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// ns2's 500m contribution should be included
|
|
232
|
+
expect(wrapper.vm.totalContribution).toBeGreaterThan(0);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('uses currentLimit for the extended type in the total', () => {
|
|
236
|
+
const wrapper: any = createWrapper({
|
|
237
|
+
type: 'extended.requests.nvidia.com/gpu',
|
|
238
|
+
value: { limit: { extended: { 'requests.nvidia.com/gpu': '0' } } },
|
|
239
|
+
projectResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '8' },
|
|
240
|
+
namespaceResourceQuotaLimits: [],
|
|
241
|
+
defaultResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '0' },
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
expect(wrapper.vm.totalContribution).toBe(0);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
describe('computed: namespaceLimits', () => {
|
|
249
|
+
it('excludes the current namespace from the list', () => {
|
|
250
|
+
const wrapper: any = createWrapper({
|
|
251
|
+
type: 'limitsCpu',
|
|
252
|
+
value: { limit: { limitsCpu: '500m' } },
|
|
253
|
+
projectResourceQuotaLimits: { limitsCpu: '2000m' },
|
|
254
|
+
namespaceResourceQuotaLimits: [
|
|
255
|
+
{ id: 'test-ns', limitsCpu: '500m' },
|
|
256
|
+
{ id: 'other-ns', limitsCpu: '300m' },
|
|
257
|
+
],
|
|
258
|
+
namespace: { id: 'test-ns' },
|
|
259
|
+
defaultResourceQuotaLimits: { limitsCpu: '0' },
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Only the other namespace should contribute
|
|
263
|
+
expect(wrapper.vm.namespaceLimits).toHaveLength(1);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('handles flattened extended keys from namespaceResourceQuotaLimits', () => {
|
|
267
|
+
const wrapper: any = createWrapper({
|
|
268
|
+
type: 'extended.requests.nvidia.com/gpu',
|
|
269
|
+
value: { limit: { extended: { 'requests.nvidia.com/gpu': '1' } } },
|
|
270
|
+
projectResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '8' },
|
|
271
|
+
namespaceResourceQuotaLimits: [
|
|
272
|
+
{ id: 'other-ns', 'extended.requests.nvidia.com/gpu': '2' },
|
|
273
|
+
],
|
|
274
|
+
namespace: { id: 'test-ns' },
|
|
275
|
+
defaultResourceQuotaLimits: { 'extended.requests.nvidia.com/gpu': '0' },
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
expect(wrapper.vm.namespaceLimits).toHaveLength(1);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
});
|