@@ -60,3 +60,51 @@ describe('benchmark CPU window', () => {
6060 }
6161 } )
6262} )
63+
64+ // ps emits minutes, hours, and a day prefix as the accumulated CPU time grows.
65+ // Drive the reported percentage through the sampler, including boundary changes.
66+ describe ( 'cumulative CPU time formats' , ( ) => {
67+ it . each ( [
68+ [ 'minute boundary' , '00:59.90' , '01:00.10' , 20 ] ,
69+ [ 'hour boundary' , '59:59.90' , '01:00:00.10' , 20 ] ,
70+ [ 'first day boundary' , '23:59:59.90' , '1-00:00:00.10' , 20 ] ,
71+ [ 'later day boundary' , '1-23:59:59.90' , '2-00:00:00.10' , 20 ] ,
72+ [ 'day and hours' , '2-03:00:00' , '2-03:00:01' , 100 ] ,
73+ [ 'missing sample' , '' , '00:00.10' , null ] ,
74+ [ 'malformed sample' , '00:00oops' , '00:00.10' , null ] ,
75+ ] as const ) ( '%s' , async ( name , before , after , expected ) => {
76+ let wall = 0
77+ let sample : string = before
78+ const spawn = spyOn ( Bun , 'spawn' ) . mockImplementation ( ( ) => ( {
79+ stdout : new Response ( sample ) . body ,
80+ } ) as unknown as ReturnType < typeof Bun . spawn > )
81+ const now = spyOn ( performance , 'now' ) . mockImplementation ( ( ) => wall )
82+ try {
83+ const measured = await measureLoad ( {
84+ name,
85+ publishable : false ,
86+ supportsFixedRate : false ,
87+ isAvailable : async ( ) => true ,
88+ async run ( ) {
89+ wall = 1000
90+ sample = after
91+ return result
92+ } ,
93+ } , {
94+ url : 'http://127.0.0.1:39400/bench/json' ,
95+ method : 'GET' ,
96+ headers : { } ,
97+ connections : 1 ,
98+ warmupSeconds : 0 ,
99+ durationSeconds : 1 ,
100+ } , 123 )
101+ if ( expected == null ) expect ( measured . cpuPercent ) . toBeNull ( )
102+ else expect ( measured . cpuPercent ) . toBeCloseTo ( expected , 6 )
103+ expect ( measured . result ) . toBe ( result )
104+ }
105+ finally {
106+ now . mockRestore ( )
107+ spawn . mockRestore ( )
108+ }
109+ } )
110+ } )
0 commit comments