DiskManagement.test.ts171 lines · main
1import { describe, expect, test } from 'vitest'
2
3import {
4 calculateBaselineIopsForComputeSize,
5 calculateComputeSizeRequiredForIops,
6 calculateDiskSizePrice,
7 calculateIOPSPrice,
8 calculateMaxIopsAllowedForDiskSizeWithGp3,
9 calculateMaxIopsForComputeSize,
10 calculateThroughputPrice,
11 mapAddOnVariantIdToComputeSize,
12 mapComputeSizeNameToAddonVariantId,
13} from './DiskManagement.utils'
14import { DiskType } from './ui/DiskManagement.constants'
15
16describe('DiskManagement utils', () => {
17 describe('mapComputeSizeNameToAddonVariantId', () => {
18 test('maps known infra sizes to addon variant ids', () => {
19 expect(mapComputeSizeNameToAddonVariantId('4xlarge')).toBe('ci_4xlarge')
20 })
21
22 test('falls back to nano for unknown infra sizes', () => {
23 // @ts-expect-error intentional invalid value for runtime guard
24 expect(mapComputeSizeNameToAddonVariantId('unknown-size')).toBe('ci_nano')
25 })
26 })
27
28 describe('mapAddOnVariantIdToComputeSize', () => {
29 test('maps known addon ids to display names', () => {
30 expect(mapAddOnVariantIdToComputeSize('ci_4xlarge')).toBe('4XL')
31 })
32
33 test('falls back to Nano on invalid addon id', () => {
34 // @ts-expect-error intentional invalid value for runtime guard
35 expect(mapAddOnVariantIdToComputeSize('ci_invalid')).toBe('Nano')
36 })
37 })
38
39 describe('calculateBaselineIopsForComputeSize / calculateMaxIopsForComputeSize', () => {
40 test('returns 0 for invalid compute ids', () => {
41 expect(calculateBaselineIopsForComputeSize('invalid')).toBe(0)
42 expect(calculateMaxIopsForComputeSize('invalid')).toBe(0)
43 })
44
45 test('returns baseline and max for valid compute ids', () => {
46 expect(calculateBaselineIopsForComputeSize('ci_2xlarge')).toBe(12000)
47 expect(calculateMaxIopsForComputeSize('ci_2xlarge')).toBe(20000)
48 })
49 })
50
51 describe('calculateComputeSizeRequiredForIops', () => {
52 test('returns smallest size that satisfies requested IOPS', () => {
53 expect(calculateComputeSizeRequiredForIops(500)).toBe('ci_nano')
54 expect(calculateComputeSizeRequiredForIops(19000)).toBe('ci_large')
55 expect(calculateComputeSizeRequiredForIops(45000)).toBe('ci_12xlarge')
56 })
57
58 test('falls back to largest size when exceeding known max', () => {
59 const fallback = calculateComputeSizeRequiredForIops(500000)
60 expect([
61 'ci_48xlarge',
62 'ci_48xlarge_optimized_cpu',
63 'ci_48xlarge_optimized_memory',
64 'ci_48xlarge_high_memory',
65 ]).toContain(fallback)
66 })
67 })
68})
69
70describe('calculateMaxIopsAllowedForDiskSizeWithGp3', () => {
71 // Regression: old code returned `3000 * size`, letting a 2 GB disk request 6000 IOPS
72 // which the platform rejects. The real ceiling is 500 IOPS/GB capped at 16 000.
73 test('caps a sub-6 GB disk at the 3000 IOPS floor (not 3000 × size)', () => {
74 expect(calculateMaxIopsAllowedForDiskSizeWithGp3(2)).toBe(3000)
75 })
76
77 test('caps large disks at 16 000 IOPS', () => {
78 expect(calculateMaxIopsAllowedForDiskSizeWithGp3(100)).toBe(16000)
79 })
80})
81
82describe('DiskManagement.utils.ts:calculateDiskSizePrice', () => {
83 test('GP3 with 8GB to GP3 with 10GB for pro plan', () => {
84 const result = calculateDiskSizePrice({
85 planId: 'pro',
86 oldSize: 8,
87 oldStorageType: DiskType.GP3,
88 newSize: 10,
89 newStorageType: DiskType.GP3,
90 })
91 expect(result.oldPrice).toBe('0.00')
92 expect(result.newPrice).toBe('0.25')
93 })
94 test('IO2 with 8GB to IO2 with 10GB for pro plan', () => {
95 const result = calculateDiskSizePrice({
96 planId: 'pro',
97 oldSize: 8,
98 oldStorageType: DiskType.IO2,
99 newSize: 10,
100 newStorageType: DiskType.IO2,
101 })
102 expect(result.oldPrice).toBe('1.56')
103 expect(result.newPrice).toBe('1.95')
104 })
105 test('GP3 with 8GB to GP3 with 10GB, with 2 replicas', () => {
106 const result = calculateDiskSizePrice({
107 planId: 'pro',
108 oldSize: 8,
109 oldStorageType: DiskType.GP3,
110 newSize: 10,
111 newStorageType: DiskType.GP3,
112 numReplicas: 2,
113 })
114 expect(result.oldPrice).toBe('2.50')
115 expect(result.newPrice).toBe('3.38')
116 })
117})
118
119describe('DiskManagement.utils.ts:calculateIOPSPrice', () => {
120 test('GP3 with 3000 to IO2 with 3000', () => {
121 const result = calculateIOPSPrice({
122 oldStorageType: DiskType.GP3,
123 oldProvisionedIOPS: 3000,
124 newStorageType: DiskType.IO2,
125 newProvisionedIOPS: 3000,
126 })
127 expect(result.oldPrice).toBe('0.00')
128 expect(result.newPrice).toBe('357.00')
129 })
130 test('GP3 with 3000 to GP3 with 5000', () => {
131 const result = calculateIOPSPrice({
132 oldStorageType: DiskType.GP3,
133 oldProvisionedIOPS: 3000,
134 newStorageType: DiskType.GP3,
135 newProvisionedIOPS: 5000,
136 })
137 expect(result.oldPrice).toBe('0.00')
138 expect(result.newPrice).toBe('48.00')
139 })
140 test('IO2 with 3000 to IO2 with 5000', () => {
141 const result = calculateIOPSPrice({
142 oldStorageType: DiskType.IO2,
143 oldProvisionedIOPS: 3000,
144 newStorageType: DiskType.IO2,
145 newProvisionedIOPS: 5000,
146 })
147 expect(result.oldPrice).toBe('357.00')
148 expect(result.newPrice).toBe('595.00')
149 })
150})
151
152describe('DiskManagement.utils.ts:calculateThroughputPrice', () => {
153 test('GP3 with 125 MB/s 150 MB/s', () => {
154 const result = calculateThroughputPrice({
155 storageType: DiskType.GP3,
156 oldThroughput: 125,
157 newThroughput: 150,
158 })
159 expect(result.oldPrice).toBe('0.00')
160 expect(result.newPrice).toBe('2.38')
161 })
162 test('IO1 with 125 MB/s 150 MB/s', () => {
163 const result = calculateThroughputPrice({
164 storageType: DiskType.IO2,
165 oldThroughput: 125,
166 newThroughput: 150,
167 })
168 expect(result.oldPrice).toBe('0.00')
169 expect(result.newPrice).toBe('0.00')
170 })
171})