@@ -38,31 +38,41 @@ def logcat_thread():
3838            for  line  in  self .logcat_process .stdout :
3939                self .logcat_queue .put (line .rstrip ("\n " ))
4040            self .logcat_process .stdout .close ()
41+ 
4142        self .logcat_thread  =  Thread (target = logcat_thread )
4243        self .logcat_thread .start ()
4344
44-         from  ctypes  import  CDLL , c_char_p , c_int 
45-         android_log_write  =  getattr (CDLL ("liblog.so" ), "__android_log_write" )
46-         android_log_write .argtypes  =  (c_int , c_char_p , c_char_p )
47-         ANDROID_LOG_INFO  =  4 
48- 
49-         # Separate tests using a marker line with a different tag. 
50-         tag , message  =  "python.test" , f"{ self .id ()}   { time ()}  " 
51-         android_log_write (
52-             ANDROID_LOG_INFO , tag .encode ("UTF-8" ), message .encode ("UTF-8" ))
53-         self .assert_log ("I" , tag , message , skip = True , timeout = 5 )
45+         try :
46+             from  ctypes  import  CDLL , c_char_p , c_int 
47+             android_log_write  =  getattr (CDLL ("liblog.so" ), "__android_log_write" )
48+             android_log_write .argtypes  =  (c_int , c_char_p , c_char_p )
49+             ANDROID_LOG_INFO  =  4 
50+ 
51+             # Separate tests using a marker line with a different tag. 
52+             tag , message  =  "python.test" , f"{ self .id ()}   { time ()}  " 
53+             android_log_write (
54+                 ANDROID_LOG_INFO , tag .encode ("UTF-8" ), message .encode ("UTF-8" ))
55+             self .assert_log ("I" , tag , message , skip = True )
56+         except :
57+             # If setUp throws an exception, tearDown is not automatically 
58+             # called. Avoid leaving a dangling thread which would keep the 
59+             # Python process alive indefinitely. 
60+             self .tearDown ()
61+             raise 
5462
5563    def  assert_logs (self , level , tag , expected , ** kwargs ):
5664        for  line  in  expected :
5765            self .assert_log (level , tag , line , ** kwargs )
5866
59-     def  assert_log (self , level , tag , expected , * , skip = False ,  timeout = 0.5 ):
60-         deadline  =  time () +  timeout 
67+     def  assert_log (self , level , tag , expected , * , skip = False ):
68+         deadline  =  time () +  LOOPBACK_TIMEOUT 
6169        while  True :
6270            try :
6371                line  =  self .logcat_queue .get (timeout = (deadline  -  time ()))
6472            except  queue .Empty :
65-                 self .fail (f"line not found: { expected !r}  " )
73+                 raise  self .failureException (
74+                     f"line not found: { expected !r}  " 
75+                 ) from  None 
6676            if  match  :=  re .fullmatch (fr"(.)/{ tag }  : (.*)" , line ):
6777                try :
6878                    self .assertEqual (level , match [1 ])
@@ -77,6 +87,9 @@ def tearDown(self):
7787        self .logcat_process .wait (LOOPBACK_TIMEOUT )
7888        self .logcat_thread .join (LOOPBACK_TIMEOUT )
7989
90+         # Avoid an irrelevant warning about threading._dangling. 
91+         self .logcat_thread  =  None 
92+ 
8093    @contextmanager  
8194    def  unbuffered (self , stream ):
8295        stream .reconfigure (write_through = True )
0 commit comments