1+ import { expect } from 'chai' ;
2+ import sinon from 'sinon' ;
3+ import { MemoryUtils } from '../../src/utils/memory-utils' ;
4+
5+ describe ( 'Memory Optimization Integration' , ( ) => {
6+ let memoryUtilsSpy : sinon . SinonSpy ;
7+ let processMemoryUsageStub : sinon . SinonStub ;
8+
9+ beforeEach ( ( ) => {
10+ // Mock process.memoryUsage to simulate memory pressure
11+ processMemoryUsageStub = sinon . stub ( process , 'memoryUsage' ) . returns ( {
12+ rss : 2000 * 1024 * 1024 , // 2GB
13+ heapTotal : 1500 * 1024 * 1024 , // 1.5GB
14+ heapUsed : 1200 * 1024 * 1024 , // 1.2GB (above 1GB threshold)
15+ external : 100 * 1024 * 1024 ,
16+ arrayBuffers : 50 * 1024 * 1024 ,
17+ } ) ;
18+
19+ memoryUtilsSpy = sinon . spy ( MemoryUtils ) ;
20+ } ) ;
21+
22+ afterEach ( ( ) => {
23+ processMemoryUsageStub . restore ( ) ;
24+ sinon . restore ( ) ;
25+ } ) ;
26+
27+ describe ( 'Memory Pressure Detection' , ( ) => {
28+ it ( 'should detect memory pressure with large heap usage' , ( ) => {
29+ const isUnderPressure = MemoryUtils . checkMemoryPressure ( 1024 ) ; // 1GB threshold
30+ expect ( isUnderPressure ) . to . be . true ;
31+ } ) ;
32+
33+ it ( 'should not detect memory pressure with normal heap usage' , ( ) => {
34+ // Mock lower memory usage
35+ processMemoryUsageStub . returns ( {
36+ rss : 500 * 1024 * 1024 ,
37+ heapTotal : 400 * 1024 * 1024 ,
38+ heapUsed : 300 * 1024 * 1024 , // 300MB < 1GB threshold
39+ external : 50 * 1024 * 1024 ,
40+ arrayBuffers : 25 * 1024 * 1024 ,
41+ } ) ;
42+
43+ const isUnderPressure = MemoryUtils . checkMemoryPressure ( 1024 ) ;
44+ expect ( isUnderPressure ) . to . be . false ;
45+ } ) ;
46+ } ) ;
47+
48+ describe ( 'Periodic Cleanup Logic' , ( ) => {
49+ it ( 'should trigger cleanup at correct intervals' , ( ) => {
50+ // Test cleanup intervals
51+ expect ( MemoryUtils . shouldCleanup ( 1000 , 1000 ) ) . to . be . true ;
52+ expect ( MemoryUtils . shouldCleanup ( 2000 , 1000 ) ) . to . be . true ;
53+ expect ( MemoryUtils . shouldCleanup ( 999 , 1000 ) ) . to . be . false ;
54+ expect ( MemoryUtils . shouldCleanup ( 1001 , 1000 ) ) . to . be . false ;
55+ } ) ;
56+
57+ it ( 'should use default interval of 1000' , ( ) => {
58+ expect ( MemoryUtils . shouldCleanup ( 1000 ) ) . to . be . true ;
59+ expect ( MemoryUtils . shouldCleanup ( 2000 ) ) . to . be . true ;
60+ expect ( MemoryUtils . shouldCleanup ( 3000 ) ) . to . be . true ;
61+ } ) ;
62+ } ) ;
63+
64+ describe ( 'Memory Statistics' , ( ) => {
65+ it ( 'should provide accurate memory statistics' , ( ) => {
66+ const stats = MemoryUtils . getMemoryStats ( ) ;
67+
68+ expect ( stats . heapUsedMB ) . to . equal ( 1200 ) ; // 1.2GB in MB
69+ expect ( stats . heapTotalMB ) . to . equal ( 1500 ) ; // 1.5GB in MB
70+ expect ( stats . rssMB ) . to . equal ( 2000 ) ; // 2GB in MB
71+
72+ expect ( stats . heapUsed ) . to . equal ( 1200 * 1024 * 1024 ) ;
73+ expect ( stats . heapTotal ) . to . equal ( 1500 * 1024 * 1024 ) ;
74+ expect ( stats . rss ) . to . equal ( 2000 * 1024 * 1024 ) ;
75+ } ) ;
76+ } ) ;
77+
78+ describe ( 'Garbage Collection' , ( ) => {
79+ it ( 'should handle garbage collection gracefully when not available' , async ( ) => {
80+ // Ensure global.gc is not available
81+ delete ( global as any ) . gc ;
82+
83+ // Should not throw an error
84+ await MemoryUtils . forceGarbageCollection ( ) ;
85+ } ) ;
86+
87+ it ( 'should call garbage collection when available' , async ( ) => {
88+ const mockGc = sinon . stub ( ) ;
89+ ( global as any ) . gc = mockGc ;
90+
91+ await MemoryUtils . forceGarbageCollection ( ) ;
92+
93+ expect ( mockGc . calledOnce ) . to . be . true ;
94+
95+ delete ( global as any ) . gc ;
96+ } ) ;
97+ } ) ;
98+
99+ describe ( 'Memory Cleanup Simulation' , ( ) => {
100+ it ( 'should simulate asset processing memory cleanup' , ( ) => {
101+ // Simulate processing 5000 assets
102+ let memoryCleanupCount = 0 ;
103+
104+ for ( let i = 1 ; i <= 5000 ; i ++ ) {
105+ if ( MemoryUtils . shouldCleanup ( i , 1000 ) ) {
106+ memoryCleanupCount ++ ;
107+ }
108+ }
109+
110+ // Should trigger cleanup 5 times (at 1000, 2000, 3000, 4000, 5000)
111+ expect ( memoryCleanupCount ) . to . equal ( 5 ) ;
112+ } ) ;
113+
114+ it ( 'should demonstrate memory pressure detection throughout processing' , ( ) => {
115+ const memoryReadings = [ ] ;
116+
117+ // Simulate increasing memory usage
118+ for ( let i = 0 ; i < 5 ; i ++ ) {
119+ const memoryUsageMB = 500 + ( i * 200 ) ; // 500MB, 700MB, 900MB, 1100MB, 1300MB
120+
121+ processMemoryUsageStub . returns ( {
122+ rss : memoryUsageMB * 1024 * 1024 ,
123+ heapTotal : ( memoryUsageMB - 100 ) * 1024 * 1024 ,
124+ heapUsed : ( memoryUsageMB - 200 ) * 1024 * 1024 ,
125+ external : 50 * 1024 * 1024 ,
126+ arrayBuffers : 25 * 1024 * 1024 ,
127+ } ) ;
128+
129+ const isUnderPressure = MemoryUtils . checkMemoryPressure ( 1024 ) ; // 1GB threshold
130+ memoryReadings . push ( { memoryUsageMB : memoryUsageMB - 200 , isUnderPressure } ) ;
131+ }
132+
133+ // Should detect pressure when memory exceeds 1GB (1024MB)
134+ expect ( memoryReadings [ 0 ] . isUnderPressure ) . to . be . false ; // 300MB
135+ expect ( memoryReadings [ 1 ] . isUnderPressure ) . to . be . false ; // 500MB
136+ expect ( memoryReadings [ 2 ] . isUnderPressure ) . to . be . false ; // 700MB
137+ expect ( memoryReadings [ 3 ] . isUnderPressure ) . to . be . true ; // 900MB (close to threshold)
138+ expect ( memoryReadings [ 4 ] . isUnderPressure ) . to . be . true ; // 1100MB (over threshold)
139+ } ) ;
140+ } ) ;
141+ } ) ;
0 commit comments