4747import  easybuild .tools .utilities 
4848from  easybuild .tools .build_log  import  EasyBuildError , init_logging , stop_logging 
4949from  easybuild .tools .filetools  import  adjust_permissions , read_file , write_file 
50- from  easybuild .tools .run  import  check_log_for_errors , complete_cmd , get_output_from_process 
50+ from  easybuild .tools .run  import  check_async_cmd ,  check_log_for_errors , complete_cmd , get_output_from_process 
5151from  easybuild .tools .run  import  parse_log_for_error , run_cmd , run_cmd_qa 
5252from  easybuild .tools .config  import  ERROR , IGNORE , WARN 
5353
@@ -575,7 +575,8 @@ def test_run_cmd_async(self):
575575
576576        os .environ ['TEST' ] =  'test123' 
577577
578-         cmd_info  =  run_cmd ("sleep 2; echo $TEST" , asynchronous = True )
578+         test_cmd  =  "echo 'sleeping...'; sleep 2; echo $TEST" 
579+         cmd_info  =  run_cmd (test_cmd , asynchronous = True )
579580        proc  =  cmd_info [0 ]
580581
581582        # change value of $TEST to check that command is completed with correct environment 
@@ -585,18 +586,51 @@ def test_run_cmd_async(self):
585586        ec  =  proc .poll ()
586587        self .assertEqual (ec , None )
587588
589+         # wait until command is done 
588590        while  ec  is  None :
589591            time .sleep (1 )
590592            ec  =  proc .poll ()
591593
592594        out , ec  =  complete_cmd (* cmd_info , simple = False )
593595        self .assertEqual (ec , 0 )
594-         self .assertEqual (out , 'test123\n ' )
596+         self .assertEqual (out , 'sleeping...\n test123\n ' )
597+ 
598+         # also test use of check_async_cmd function 
599+         os .environ ['TEST' ] =  'test123' 
600+         cmd_info  =  run_cmd (test_cmd , asynchronous = True )
601+ 
602+         # first check, only read first 12 output characters 
603+         # (otherwise we'll be waiting until command is completed) 
604+         res  =  check_async_cmd (* cmd_info , output_read_size = 12 )
605+         self .assertEqual (res , {'done' : False , 'exit_code' : None , 'output' : 'sleeping...\n ' })
606+ 
607+         # 2nd check with default output size (1024) gets full output 
608+         res  =  check_async_cmd (* cmd_info , output = res ['output' ])
609+         self .assertEqual (res , {'done' : True , 'exit_code' : 0 , 'output' : 'sleeping...\n test123\n ' })
610+ 
611+         # check asynchronous running of failing command 
612+         error_test_cmd  =  "echo 'FAIL!' >&2; exit 123" 
613+         cmd_info  =  run_cmd (error_test_cmd , asynchronous = True )
614+         error_pattern  =  'cmd ".*" exited with exit code 123' 
615+         self .assertErrorRegex (EasyBuildError , error_pattern , check_async_cmd , * cmd_info )
616+ 
617+         cmd_info  =  run_cmd (error_test_cmd , asynchronous = True )
618+         res  =  check_async_cmd (* cmd_info , fail_on_error = False )
619+         self .assertEqual (res , {'done' : True , 'exit_code' : 123 , 'output' : "FAIL!\n " })
595620
596621        # also test with a command that produces a lot of output, 
597622        # since that tends to lock up things unless we frequently grab some output... 
598-         cmd  =  "echo start; for i in $(seq 1 50); do sleep 0.1; for j in $(seq 1000); do echo foo; done; done; echo done" 
599-         cmd_info  =  run_cmd (cmd , asynchronous = True )
623+         verbose_test_cmd  =  ';' .join ([
624+             "echo start" ,
625+             "for i in $(seq 1 50)" ,
626+             "do sleep 0.1" ,
627+             "for j in $(seq 1000)" ,
628+             "do echo foo" ,
629+             "done" ,
630+             "done" ,
631+             "echo done" ,
632+         ])
633+         cmd_info  =  run_cmd (verbose_test_cmd , asynchronous = True )
600634        proc  =  cmd_info [0 ]
601635
602636        output  =  '' 
@@ -613,6 +647,32 @@ def test_run_cmd_async(self):
613647        self .assertTrue (out .startswith ('start\n ' ))
614648        self .assertTrue (out .endswith ('\n done\n ' ))
615649
650+         # also test use of check_async_cmd on verbose test command 
651+         cmd_info  =  run_cmd (verbose_test_cmd , asynchronous = True )
652+ 
653+         error_pattern  =  r"Number of output bytes to read should be a positive integer value \(or zero\)" 
654+         self .assertErrorRegex (EasyBuildError , error_pattern , check_async_cmd , * cmd_info , output_read_size = - 1 )
655+         self .assertErrorRegex (EasyBuildError , error_pattern , check_async_cmd , * cmd_info , output_read_size = 'foo' )
656+ 
657+         # with output_read_size set to 0, no output is read yet, only status of command is checked 
658+         res  =  check_async_cmd (* cmd_info , output_read_size = 0 )
659+         self .assertEqual (res ['done' ], False )
660+         self .assertEqual (res ['exit_code' ], None )
661+         self .assertEqual (res ['output' ], '' )
662+ 
663+         res  =  check_async_cmd (* cmd_info )
664+         self .assertEqual (res ['done' ], False )
665+         self .assertEqual (res ['exit_code' ], None )
666+         self .assertTrue (res ['output' ].startswith ('start\n ' ))
667+         self .assertFalse (res ['output' ].endswith ('\n done\n ' ))
668+         # keep checking until command is complete 
669+         while  not  res ['done' ]:
670+             res  =  check_async_cmd (* cmd_info , output = res ['output' ])
671+         self .assertEqual (res ['done' ], True )
672+         self .assertEqual (res ['exit_code' ], 0 )
673+         self .assertTrue (res ['output' ].startswith ('start\n ' ))
674+         self .assertTrue (res ['output' ].endswith ('\n done\n ' ))
675+ 
616676    def  test_check_log_for_errors (self ):
617677        fd , logfile  =  tempfile .mkstemp (suffix = '.log' , prefix = 'eb-test-' )
618678        os .close (fd )
0 commit comments