1
+ /*
2
+ * This file is part of CoCalc: Copyright © 2024 Sagemath, Inc.
3
+ * License: MS-RSL – see LICENSE.md for details
4
+ */
5
+
6
+ process . env . COCALC_PROJECT_MONITOR_INTERVAL_S = "1" ;
7
+
1
8
import { executeCode } from "./execute-code" ;
2
9
3
10
describe ( "hello world" , ( ) => {
@@ -90,6 +97,27 @@ describe("test timeout", () => {
90
97
} ) ;
91
98
} ) ;
92
99
100
+ describe ( "test longer execution" , ( ) => {
101
+ it (
102
+ "runs 5 seconds" ,
103
+ async ( ) => {
104
+ const t0 = Date . now ( ) ;
105
+ const { stdout, stderr, exit_code } = await executeCode ( {
106
+ command : "sh" ,
107
+ args : [ "-c" , "echo foo; sleep 5; echo bar" ] ,
108
+ err_on_exit : false ,
109
+ bash : false ,
110
+ } ) ;
111
+ expect ( stdout ) . toBe ( "foo\nbar\n" ) ;
112
+ expect ( stderr ) . toBe ( "" ) ;
113
+ expect ( exit_code ) . toBe ( 0 ) ;
114
+ const t1 = Date . now ( ) ;
115
+ expect ( ( t1 - t0 ) / 1000 ) . toBeGreaterThan ( 4.9 ) ;
116
+ } ,
117
+ 10 * 1000 ,
118
+ ) ;
119
+ } ) ;
120
+
93
121
describe ( "test env" , ( ) => {
94
122
it ( "allows to specify environment variables" , async ( ) => {
95
123
const { stdout, stderr, type } = await executeCode ( {
@@ -211,6 +239,7 @@ describe("async", () => {
211
239
expect ( typeof job_id ) . toEqual ( "string" ) ;
212
240
if ( typeof job_id !== "string" ) return ;
213
241
await new Promise ( ( done ) => setTimeout ( done , 250 ) ) ;
242
+ // now we check up on the job
214
243
const s = await executeCode ( { async_get : job_id } ) ;
215
244
expect ( s . type ) . toEqual ( "async" ) ;
216
245
if ( s . type !== "async" ) return ;
@@ -224,4 +253,57 @@ describe("async", () => {
224
253
) ;
225
254
expect ( s . exit_code ) . toEqual ( 1 ) ;
226
255
} ) ;
256
+
257
+ it (
258
+ "long running async job" ,
259
+ async ( ) => {
260
+ const c = await executeCode ( {
261
+ command : "sh" ,
262
+ args : [ "-c" , `echo foo; python3 -c '${ CPU_PY } '; echo bar;` ] ,
263
+ bash : false ,
264
+ err_on_exit : false ,
265
+ async_call : true ,
266
+ } ) ;
267
+ expect ( c . type ) . toEqual ( "async" ) ;
268
+ if ( c . type !== "async" ) return ;
269
+ const { status, job_id } = c ;
270
+ expect ( status ) . toEqual ( "running" ) ;
271
+ expect ( typeof job_id ) . toEqual ( "string" ) ;
272
+ if ( typeof job_id !== "string" ) return ;
273
+ await new Promise ( ( done ) => setTimeout ( done , 5500 ) ) ;
274
+ // now we check up on the job
275
+ const s = await executeCode ( { async_get : job_id , async_stats : true } ) ;
276
+ expect ( s . type ) . toEqual ( "async" ) ;
277
+ if ( s . type !== "async" ) return ;
278
+ expect ( s . elapsed_s ) . toBeGreaterThan ( 5 ) ;
279
+ expect ( s . exit_code ) . toBe ( 0 ) ;
280
+ expect ( s . pid ) . toBeGreaterThan ( 1 ) ;
281
+ expect ( s . stats ) . toBeDefined ( ) ;
282
+ if ( ! Array . isArray ( s . stats ) ) return ;
283
+ const pcts = Math . max ( ...s . stats . map ( ( s ) => s . cpu_pct ) ) ;
284
+ const secs = Math . max ( ...s . stats . map ( ( s ) => s . cpu_secs ) ) ;
285
+ const mems = Math . max ( ...s . stats . map ( ( s ) => s . mem_rss ) ) ;
286
+ expect ( pcts ) . toBeGreaterThan ( 10 ) ;
287
+ expect ( secs ) . toBeGreaterThan ( 1 ) ;
288
+ expect ( mems ) . toBeGreaterThan ( 1 ) ;
289
+ expect ( s . stdout ) . toEqual ( "foo\nbar\n" ) ;
290
+ // now without stats, after retrieving it
291
+ const s2 = await executeCode ( { async_get : job_id } ) ;
292
+ if ( s2 . type !== "async" ) return ;
293
+ expect ( s2 . stats ) . toBeUndefined ( ) ;
294
+ // and check, that this is not removing stats entirely
295
+ const s3 = await executeCode ( { async_get : job_id , async_stats : true } ) ;
296
+ if ( s3 . type !== "async" ) return ;
297
+ expect ( Array . isArray ( s3 . stats ) ) . toBeTruthy ( ) ;
298
+ } ,
299
+ 10 * 1000 ,
300
+ ) ;
227
301
} ) ;
302
+
303
+ // we burn a bit of CPU to get the cpu_pct and cpu_secs up
304
+ const CPU_PY = `
305
+ from time import time
306
+ t0=time()
307
+ while t0+5>time():
308
+ sum([_ for _ in range(10**6)])
309
+ ` ;
0 commit comments