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+
18import { executeCode } from "./execute-code" ;
29
310describe ( "hello world" , ( ) => {
@@ -90,6 +97,27 @@ describe("test timeout", () => {
9097 } ) ;
9198} ) ;
9299
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+
93121describe ( "test env" , ( ) => {
94122 it ( "allows to specify environment variables" , async ( ) => {
95123 const { stdout, stderr, type } = await executeCode ( {
@@ -211,6 +239,7 @@ describe("async", () => {
211239 expect ( typeof job_id ) . toEqual ( "string" ) ;
212240 if ( typeof job_id !== "string" ) return ;
213241 await new Promise ( ( done ) => setTimeout ( done , 250 ) ) ;
242+ // now we check up on the job
214243 const s = await executeCode ( { async_get : job_id } ) ;
215244 expect ( s . type ) . toEqual ( "async" ) ;
216245 if ( s . type !== "async" ) return ;
@@ -224,4 +253,57 @@ describe("async", () => {
224253 ) ;
225254 expect ( s . exit_code ) . toEqual ( 1 ) ;
226255 } ) ;
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+ ) ;
227301} ) ;
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