From c88be67fc40471b8edbaf671b8fbfc6a18792f38 Mon Sep 17 00:00:00 2001 From: Nancy <42977925+mantis-toboggan-md@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:49:00 -0700 Subject: [PATCH] fix aks pool count validator and add some unit tests (#11908) --- pkg/aks/components/AksNodePool.vue | 9 ++-- pkg/aks/components/CruAks.vue | 38 ++-------------- .../components/__tests__/AksNodePool.test.ts | 35 +++++++++++++++ pkg/aks/l10n/en-us.yaml | 4 +- pkg/aks/util/__tests__/validators.test.ts | 45 +++++++++++++++++++ pkg/aks/util/validators.ts | 36 +++++++++++++++ 6 files changed, 127 insertions(+), 40 deletions(-) diff --git a/pkg/aks/components/AksNodePool.vue b/pkg/aks/components/AksNodePool.vue index 9f6ad5d5fee..b3d5670cbb0 100644 --- a/pkg/aks/components/AksNodePool.vue +++ b/pkg/aks/components/AksNodePool.vue @@ -174,7 +174,9 @@ export default defineComponent({ }, poolCountValidator() { - return (val: number) => this.validationRules?.count?.[0](val, this.pool.enableAutoScaling); + const canBeZero: boolean = this.pool.mode === 'User'; + + return (val: number) => this.validationRules?.count?.[0](val, canBeZero); } }, }); @@ -305,9 +307,10 @@ export default defineComponent({ type="number" :mode="mode" label-key="aks.nodePools.count.label" - :rules="[poolCountValidator]" - :min="pool.enableAutoScaling ? 0 : 1" + :rules="[poolCountValidator()]" + :min="pool.mode === 'User' ? 0 : 1" :max="1000" + data-testid="aks-pool-count-input" />
diff --git a/pkg/aks/components/CruAks.vue b/pkg/aks/components/CruAks.vue index 8cdbbab1db4..dd00b9d896c 100644 --- a/pkg/aks/components/CruAks.vue +++ b/pkg/aks/components/CruAks.vue @@ -52,7 +52,8 @@ import { outboundTypeUserDefined, privateDnsZone, nodePoolNames, - nodePoolNamesUnique + nodePoolNamesUnique, + nodePoolCount } from '../util/validators'; export const defaultNodePool = { @@ -342,6 +343,7 @@ export default defineComponent({ privateDnsZone: privateDnsZone(this, 'aks.privateDnsZone.label', 'aksConfig.privateDnsZone'), poolNames: nodePoolNames(this), poolNamesUnique: nodePoolNamesUnique(this), + poolCount: nodePoolCount(this), vmSizeAvailable: () => { if (this.touchedVmSize) { @@ -433,40 +435,6 @@ export default defineComponent({ return this.canUseAvailabilityZones || !isUsingAvailabilityZones ? undefined : this.t('aks.errors.availabilityZones'); }, - poolCount: (count?: number, autoscale = false) => { - let min = 1; - let errMsg = this.t('aks.errors.poolCount'); - - if (autoscale) { - min = 0; - errMsg = this.t('aks.errors.poolAutoscaleCount'); - } - if (count || count === 0) { - return count >= min ? undefined : errMsg; - } else { - let allValid = true; - - this.nodePools.forEach((pool: AKSNodePool) => { - const { count = 0, enableAutoScaling } = pool; - - if (enableAutoScaling) { - min = 0; - } else { - min = 1; - } - - if (count < min) { - this.$set(pool._validation, '_validCount', false); - allValid = false; - } else { - this.$set(pool._validation, '_validCount', true); - } - }); - - return allValid ? undefined : this.t('aks.errors.poolCount'); - } - }, - poolMin: (min?:number) => { if (min || min === 0) { return min < 0 || min > 1000 ? this.t('aks.errors.poolMin') : undefined; diff --git a/pkg/aks/components/__tests__/AksNodePool.test.ts b/pkg/aks/components/__tests__/AksNodePool.test.ts index 77ed63330d0..23011edf8bf 100644 --- a/pkg/aks/components/__tests__/AksNodePool.test.ts +++ b/pkg/aks/components/__tests__/AksNodePool.test.ts @@ -226,4 +226,39 @@ describe('aks node pool component', () => { expect(wrapper.props().pool.nodeLabels).toStrictEqual(newLabels); }); + + it('should validate pool count using the provided count validator function', async() => { + const countValidator = jest.fn(); + + mount(AksNodePool, { + propsData: { + pool: { ...defaultPool, count: -1 }, + validationRules: { count: [countValidator] } + }, + ...requiredSetup() + + }); + + expect(countValidator).toHaveBeenCalledWith(-1, false); + }); + + it.each([ + ['System', false], + ['User', true], + ])('should validate node pool count differently if the pool mode is User', async(mode, allowZeroCount) => { + const countValidator = jest.fn(); + + mount(AksNodePool, { + propsData: { + pool: { + ...defaultPool, count: -1, mode + }, + validationRules: { count: [countValidator] } + }, + ...requiredSetup() + + }); + + expect(countValidator).toHaveBeenCalledWith(-1, allowZeroCount); + }); }); diff --git a/pkg/aks/l10n/en-us.yaml b/pkg/aks/l10n/en-us.yaml index 1f7798242b8..4ee4dd73bef 100644 --- a/pkg/aks/l10n/en-us.yaml +++ b/pkg/aks/l10n/en-us.yaml @@ -163,8 +163,8 @@ aks: availabilityZones: Availability zones are not available in the selected region. privateDnsZone: Private DNS Zone Resource ID must be in the format /subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCEGROUP_NAME/providers/Microsoft.Network/privateDnsZones/PRIVATE_DNS_ZONE_NAME. The Private DNS Zone Resource Name must be in the format privatelink.REGION.azmk8s.io, SUBZONE.privatelink.REGION.azmk8s.io, private.REGION.azmk8s.io, or SUBZONE.private.REGION.azmk8s.io poolName: Node pool names must be 1-12 characters long, consist only of lowercase letters and numbers, and start with a letter. - poolCount: Node count must be at least one when autoscaling is disabled. - poolAutoscaleCount: Node count cannot be less than zero. + poolCount: Node count must be at least one in System pools. + poolUserCount: Node count cannot be less than zero. poolMinMax: The minimum number of nodes must be less than or equal to the maximum number of nodes, and the node count must be between or equal to the minimum and maximum. poolMin: The minimum number of nodes must be greater than 0 and at most 1000. poolMax: The maximum number of nodes must be greater than 0 and at most 1000. diff --git a/pkg/aks/util/__tests__/validators.test.ts b/pkg/aks/util/__tests__/validators.test.ts index fefcbb1bdb5..94ab855b6e8 100644 --- a/pkg/aks/util/__tests__/validators.test.ts +++ b/pkg/aks/util/__tests__/validators.test.ts @@ -139,3 +139,48 @@ describe('fx: nodePoolNames', () => { expect(validator(name)).toStrictEqual(expected); }); }); + +describe('fx: nodePoolCount', () => { + // AksNodePool unit tests check that the second arg is passed in as expected + it('validates that count is at least 1 when second arg is false', () => { + const validator = validators.nodePoolCount(mockCtx); + + expect(validator(1, false)).toBeUndefined(); + expect(validator(0, false)).toStrictEqual(MOCK_TRANSLATION); + }); + + it('validates that count is at least 0 when second arg is true', () => { + const validator = validators.nodePoolCount(mockCtx); + + expect(validator(1, true)).toBeUndefined(); + expect(validator(0, true)).toBeUndefined(); + expect(validator(-1, true)).toStrictEqual(MOCK_TRANSLATION); + }); + + it('validates each node pool in the provided context when not passed a count value', () => { + const ctx = { + ...mockCtx, + nodePools: [ + { + name: 'abc', _validation: {}, mode: 'System', count: 0 + }, + { + name: 'def', _validation: {}, mode: 'System', count: 1 + }, + { + name: 'hij', _validation: {}, mode: 'User', count: 0 + }, + { + name: 'klm', _validation: {}, mode: 'User', count: -1 + } + ] as unknown as AKSNodePool[] + }; + const validator = validators.nodePoolCount(ctx); + + validator(); + expect(ctx.nodePools[0]?._validation?._validCount).toStrictEqual(false); + expect(ctx.nodePools[1]?._validation?._validCount).toStrictEqual(true); + expect(ctx.nodePools[2]?._validation?._validCount).toStrictEqual(true); + expect(ctx.nodePools[3]?._validation?._validCount).toStrictEqual(false); + }); +}); diff --git a/pkg/aks/util/validators.ts b/pkg/aks/util/validators.ts index 4f0dfdc5df3..993e94648a4 100644 --- a/pkg/aks/util/validators.ts +++ b/pkg/aks/util/validators.ts @@ -177,3 +177,39 @@ export const nodePoolNamesUnique = (ctx: any) => { } }; }; + +export const nodePoolCount = (ctx:any) => { + return (count?: number, canBeZero = false) => { + let min = 1; + let errMsg = ctx.t('aks.errors.poolCount'); + + if (canBeZero) { + min = 0; + errMsg = ctx.t('aks.errors.poolUserCount'); + } + if (count || count === 0) { + return count >= min ? undefined : errMsg; + } else { + let allValid = true; + + ctx.nodePools.forEach((pool: AKSNodePool) => { + const { count = 0, mode } = pool; + + if (mode === 'User') { + min = 0; + } else { + min = 1; + } + + if (count < min) { + ctx.$set(pool._validation, '_validCount', false); + allValid = false; + } else { + ctx.$set(pool._validation, '_validCount', true); + } + }); + + return allValid ? undefined : ctx.t('aks.errors.poolCount'); + } + }; +};