@@ -42,31 +42,41 @@ def logcat_thread():
4242            for  line  in  self .logcat_process .stdout :
4343                self .logcat_queue .put (line .rstrip ("\n " ))
4444            self .logcat_process .stdout .close ()
45+ 
4546        self .logcat_thread  =  Thread (target = logcat_thread )
4647        self .logcat_thread .start ()
4748
48-         from  ctypes  import  CDLL , c_char_p , c_int 
49-         android_log_write  =  getattr (CDLL ("liblog.so" ), "__android_log_write" )
50-         android_log_write .argtypes  =  (c_int , c_char_p , c_char_p )
51-         ANDROID_LOG_INFO  =  4 
52- 
53-         # Separate tests using a marker line with a different tag. 
54-         tag , message  =  "python.test" , f"{ self .id ()} { time ()}  
55-         android_log_write (
56-             ANDROID_LOG_INFO , tag .encode ("UTF-8" ), message .encode ("UTF-8" ))
57-         self .assert_log ("I" , tag , message , skip = True , timeout = 5 )
49+         try :
50+             from  ctypes  import  CDLL , c_char_p , c_int 
51+             android_log_write  =  getattr (CDLL ("liblog.so" ), "__android_log_write" )
52+             android_log_write .argtypes  =  (c_int , c_char_p , c_char_p )
53+             ANDROID_LOG_INFO  =  4 
54+ 
55+             # Separate tests using a marker line with a different tag. 
56+             tag , message  =  "python.test" , f"{ self .id ()} { time ()}  
57+             android_log_write (
58+                 ANDROID_LOG_INFO , tag .encode ("UTF-8" ), message .encode ("UTF-8" ))
59+             self .assert_log ("I" , tag , message , skip = True )
60+         except :
61+             # If setUp throws an exception, tearDown is not automatically 
62+             # called. Avoid leaving a dangling thread which would keep the 
63+             # Python process alive indefinitely. 
64+             self .tearDown ()
65+             raise 
5866
5967    def  assert_logs (self , level , tag , expected , ** kwargs ):
6068        for  line  in  expected :
6169            self .assert_log (level , tag , line , ** kwargs )
6270
63-     def  assert_log (self , level , tag , expected , * , skip = False ,  timeout = 0.5 ):
64-         deadline  =  time () +  timeout 
71+     def  assert_log (self , level , tag , expected , * , skip = False ):
72+         deadline  =  time () +  LOOPBACK_TIMEOUT 
6573        while  True :
6674            try :
6775                line  =  self .logcat_queue .get (timeout = (deadline  -  time ()))
6876            except  queue .Empty :
69-                 self .fail (f"line not found: { expected !r}  )
77+                 raise  self .failureException (
78+                     f"line not found: { expected !r}  
79+                 ) from  None 
7080            if  match  :=  re .fullmatch (fr"(.)/{ tag }  , line ):
7181                try :
7282                    self .assertEqual (level , match [1 ])
@@ -81,6 +91,9 @@ def tearDown(self):
8191        self .logcat_process .wait (LOOPBACK_TIMEOUT )
8292        self .logcat_thread .join (LOOPBACK_TIMEOUT )
8393
94+         # Avoid an irrelevant warning about threading._dangling. 
95+         self .logcat_thread  =  None 
96+ 
8497    @contextmanager  
8598    def  unbuffered (self , stream ):
8699        stream .reconfigure (write_through = True )
0 commit comments