|
| 1 | +'use strict'; |
| 2 | + |
| 3 | +// This test validates the --max-old-space-size-percentage flag functionality |
| 4 | + |
| 5 | +require('../common'); |
| 6 | +const assert = require('node:assert'); |
| 7 | +const { spawnSync } = require('child_process'); |
| 8 | +const os = require('os'); |
| 9 | + |
| 10 | +// Valid cases |
| 11 | +const validPercentages = [ |
| 12 | + '1', '10', '25', '50', '75', '99', '100', '25.5', |
| 13 | +]; |
| 14 | + |
| 15 | +// Invalid cases |
| 16 | +const invalidPercentages = [ |
| 17 | + ['', /--max-old-space-size-percentage= requires an argument/], |
| 18 | + ['0', /--max-old-space-size-percentage must be greater than 0 and up to 100\. Got: 0/], |
| 19 | + ['101', /--max-old-space-size-percentage must be greater than 0 and up to 100\. Got: 101/], |
| 20 | + ['-1', /--max-old-space-size-percentage must be greater than 0 and up to 100\. Got: -1/], |
| 21 | + ['abc', /--max-old-space-size-percentage must be greater than 0 and up to 100\. Got: abc/], |
| 22 | + ['1%', /--max-old-space-size-percentage must be greater than 0 and up to 100\. Got: 1%/], |
| 23 | +]; |
| 24 | + |
| 25 | +// Test valid cases |
| 26 | +validPercentages.forEach((input) => { |
| 27 | + const result = spawnSync(process.execPath, [ |
| 28 | + `--max-old-space-size-percentage=${input}`, |
| 29 | + ], { stdio: ['pipe', 'pipe', 'pipe'] }); |
| 30 | + assert.strictEqual(result.status, 0, `Expected exit code 0 for valid input ${input}`); |
| 31 | + assert.strictEqual(result.stderr.toString(), '', `Expected empty stderr for valid input ${input}`); |
| 32 | +}); |
| 33 | + |
| 34 | +// Test invalid cases |
| 35 | +invalidPercentages.forEach((input) => { |
| 36 | + const result = spawnSync(process.execPath, [ |
| 37 | + `--max-old-space-size-percentage=${input[0]}`, |
| 38 | + ], { stdio: ['pipe', 'pipe', 'pipe'] }); |
| 39 | + assert.notStrictEqual(result.status, 0, `Expected non-zero exit for invalid input ${input[0]}`); |
| 40 | + assert(input[1].test(result.stderr.toString()), `Unexpected error message for invalid input ${input[0]}`); |
| 41 | +}); |
| 42 | + |
| 43 | +// Test NODE_OPTIONS with valid percentages |
| 44 | +validPercentages.forEach((input) => { |
| 45 | + const result = spawnSync(process.execPath, [], { |
| 46 | + stdio: ['pipe', 'pipe', 'pipe'], |
| 47 | + env: { ...process.env, NODE_OPTIONS: `--max-old-space-size-percentage=${input}` } |
| 48 | + }); |
| 49 | + assert.strictEqual(result.status, 0, `NODE_OPTIONS: Expected exit code 0 for valid input ${input}`); |
| 50 | + assert.strictEqual(result.stderr.toString(), '', `NODE_OPTIONS: Expected empty stderr for valid input ${input}`); |
| 51 | +}); |
| 52 | + |
| 53 | +// Test NODE_OPTIONS with invalid percentages |
| 54 | +invalidPercentages.forEach((input) => { |
| 55 | + const result = spawnSync(process.execPath, [], { |
| 56 | + stdio: ['pipe', 'pipe', 'pipe'], |
| 57 | + env: { ...process.env, NODE_OPTIONS: `--max-old-space-size-percentage=${input[0]}` } |
| 58 | + }); |
| 59 | + assert.notStrictEqual(result.status, 0, `NODE_OPTIONS: Expected non-zero exit for invalid input ${input[0]}`); |
| 60 | + assert(input[1].test(result.stderr.toString()), `NODE_OPTIONS: Unexpected error message for invalid input ${input[0]}`); |
| 61 | +}); |
| 62 | + |
| 63 | +// Test percentage calculation validation |
| 64 | +function getHeapSizeForPercentage(percentage) { |
| 65 | + const result = spawnSync(process.execPath, [ |
| 66 | + '--max-old-space-size=3000', // This value should be ignored, since percentage takes precedence |
| 67 | + `--max-old-space-size-percentage=${percentage}`, |
| 68 | + '--max-old-space-size=1000', // This value should be ignored, since percentage take precedence |
| 69 | + '-e', ` |
| 70 | + const v8 = require('v8'); |
| 71 | + const stats = v8.getHeapStatistics(); |
| 72 | + const heapSizeLimitMB = Math.floor(stats.heap_size_limit / 1024 / 1024); |
| 73 | + console.log(heapSizeLimitMB); |
| 74 | + `, |
| 75 | + ], { |
| 76 | + stdio: ['pipe', 'pipe', 'pipe'], |
| 77 | + env: { |
| 78 | + ...process.env, |
| 79 | + NODE_OPTIONS: `--max-old-space-size=2000` // This value should be ignored, since percentage takes precedence |
| 80 | + } |
| 81 | + }); |
| 82 | + |
| 83 | + if (result.status !== 0) { |
| 84 | + throw new Error(`Failed to get heap size for ${percentage}: ${result.stderr.toString()}`); |
| 85 | + } |
| 86 | + |
| 87 | + return parseInt(result.stdout.toString(), 10); |
| 88 | +} |
| 89 | + |
| 90 | +const testPercentages = [25, 50, 75, 100]; |
| 91 | +const heapSizes = {}; |
| 92 | + |
| 93 | +// Get heap sizes for all test percentages |
| 94 | +testPercentages.forEach((percentage) => { |
| 95 | + heapSizes[percentage] = getHeapSizeForPercentage(percentage); |
| 96 | +}); |
| 97 | + |
| 98 | +// Test relative relationships between percentages |
| 99 | +// 50% should be roughly half of 100% |
| 100 | +const ratio50to100 = heapSizes[50] / heapSizes[100]; |
| 101 | +assert( |
| 102 | + ratio50to100 >= 0.4 && ratio50to100 <= 0.6, |
| 103 | + `50% heap size should be roughly half of 100% (got ${ratio50to100.toFixed(2)}, expected ~0.5)` |
| 104 | +); |
| 105 | + |
| 106 | +// 25% should be roughly quarter of 100% |
| 107 | +const ratio25to100 = heapSizes[25] / heapSizes[100]; |
| 108 | +assert( |
| 109 | + ratio25to100 >= 0.15 && ratio25to100 <= 0.35, |
| 110 | + `25% heap size should be roughly quarter of 100% (got ${ratio25to100.toFixed(2)}, expected ~0.25)` |
| 111 | +); |
| 112 | + |
| 113 | +// 75% should be roughly three-quarters of 100% |
| 114 | +const ratio75to100 = heapSizes[75] / heapSizes[100]; |
| 115 | +assert( |
| 116 | + ratio75to100 >= 0.65 && ratio75to100 <= 0.85, |
| 117 | + `75% heap size should be roughly three-quarters of 100% (got ${ratio75to100.toFixed(2)}, expected ~0.75)` |
| 118 | +); |
| 119 | + |
| 120 | +// Validate heap sizes against system memory |
| 121 | +const totalMemoryMB = Math.floor(os.totalmem() / 1024 / 1024); |
| 122 | +const margin = 10; // 5% margin |
| 123 | +testPercentages.forEach((percentage) => { |
| 124 | + const upperLimit = totalMemoryMB * ((percentage + margin) / 100); |
| 125 | + assert( |
| 126 | + heapSizes[percentage] <= upperLimit, |
| 127 | + `Heap size for ${percentage}% (${heapSizes[percentage]} MB) should not exceed upper limit (${upperLimit} MB)` |
| 128 | + ); |
| 129 | + const lowerLimit = totalMemoryMB * ((percentage - margin) / 100); |
| 130 | + assert( |
| 131 | + heapSizes[percentage] >= lowerLimit, |
| 132 | + `Heap size for ${percentage}% (${heapSizes[percentage]} MB) should not be less than lower limit (${lowerLimit} MB)` |
| 133 | + ); |
| 134 | +}); |
0 commit comments