88 createConcurrentTestData ,
99 createErrorTestCases ,
1010 createPerformanceAssertion ,
11+ forceGc ,
1112} from '../helpers/prettier-test-utils' ;
1213import '@cardstack/runtime-common/helpers/code-equality-assertion' ;
1314
@@ -341,27 +342,43 @@ export class MyCard extends CardDef {
341342 } ) ;
342343
343344 test ( 'memory usage during lint operations' , async function ( assert ) {
344- const initialMemory = process . memoryUsage ( ) . heapUsed ;
345-
346345 const testSource = `import { CardDef } from 'https://cardstack.com/base/card-api';
347346export class MyCard extends CardDef {
348347 @field name = contains(StringField);
349348}` ;
350349
350+ const lintOnce = ( ) =>
351+ request
352+ . post ( '/_lint' )
353+ . set (
354+ 'Authorization' ,
355+ `Bearer ${ createJWT ( testRealm , 'john' , [ 'read' , 'write' ] ) } ` ,
356+ )
357+ . set ( 'X-HTTP-Method-Override' , 'QUERY' )
358+ . set ( 'Accept' , 'application/json' )
359+ . send ( testSource ) ;
360+
361+ // Warm up first so one-time, legitimately-retained initialization (eslint
362+ // rule definitions, prettier plugins, module caches) is established before
363+ // the baseline reading and isn't misattributed to the measured loop.
364+ const warmup = await lintOnce ( ) ;
365+ assert . strictEqual (
366+ warmup . status ,
367+ 200 ,
368+ 'warm-up lint request should succeed so the baseline is a steady-state lint path' ,
369+ ) ;
370+
371+ // Force a collection before each reading so the delta reflects retained
372+ // memory, not transient garbage that GC simply hasn't reclaimed yet.
373+ // Without this the reading is dominated by collectible allocations from
374+ // ten concurrent lint requests, which is noise, not a leak signal.
375+ const gcForced = forceGc ( ) ;
376+ const initialMemory = process . memoryUsage ( ) . heapUsed ;
377+
351378 // Run multiple lint operations to test memory usage
352379 const operations = [ ] ;
353380 for ( let i = 0 ; i < 10 ; i ++ ) {
354- operations . push (
355- request
356- . post ( '/_lint' )
357- . set (
358- 'Authorization' ,
359- `Bearer ${ createJWT ( testRealm , 'john' , [ 'read' , 'write' ] ) } ` ,
360- )
361- . set ( 'X-HTTP-Method-Override' , 'QUERY' )
362- . set ( 'Accept' , 'application/json' )
363- . send ( testSource ) ,
364- ) ;
381+ operations . push ( lintOnce ( ) ) ;
365382 }
366383
367384 const results = await Promise . all ( operations ) ;
@@ -375,13 +392,29 @@ export class MyCard extends CardDef {
375392 ) ;
376393 } ) ;
377394
395+ forceGc ( ) ;
378396 const finalMemory = process . memoryUsage ( ) . heapUsed ;
379397 const memoryIncrease = finalMemory - initialMemory ;
398+ const memoryIncreaseMb = memoryIncrease / 1024 / 1024 ;
399+
400+ // Always record the retained-growth number (and whether GC actually ran)
401+ // so a CI failure — or a passing run drifting toward the bound — can be
402+ // told apart from measurement noise without another CI cycle.
403+ console . log (
404+ `[lint-memory-test] initial=${ ( initialMemory / 1024 / 1024 ) . toFixed ( 2 ) } MB ` +
405+ `final=${ ( finalMemory / 1024 / 1024 ) . toFixed ( 2 ) } MB ` +
406+ `retainedGrowth=${ memoryIncreaseMb . toFixed ( 2 ) } MB gcForced=${ gcForced } ` ,
407+ ) ;
380408
381- // Memory increase should be reasonable (less than 45MB for lint operations)
409+ // The bound only means "retained memory" when a collection actually ran;
410+ // with warm caches and a forced GC ten idempotent lint operations retain
411+ // almost nothing, so 20MB is a generous leak guard. If GC could not be
412+ // forced the delta still includes transient garbage, so fall back to the
413+ // looser historical bound rather than flaking against the tight one.
414+ const thresholdMb = gcForced ? 20 : 45 ;
382415 assert . ok (
383- memoryIncrease < 45 * 1024 * 1024 ,
384- `Memory increase should be under 45MB , got ${ ( memoryIncrease / 1024 / 1024 ) . toFixed ( 2 ) } MB` ,
416+ memoryIncrease < thresholdMb * 1024 * 1024 ,
417+ `Memory increase should be under ${ thresholdMb } MB , got ${ memoryIncreaseMb . toFixed ( 2 ) } MB (gcForced= ${ gcForced } ) ` ,
385418 ) ;
386419 } ) ;
387420
0 commit comments