1
1
import os
2
- import shutil
3
2
import sys
4
3
import time
4
+ from queue import Empty
5
+ from queue import Queue
5
6
from subprocess import PIPE
6
7
from subprocess import Popen
7
- from tempfile import mkdtemp
8
+ from threading import Thread
8
9
9
10
10
11
def _launch (extra_env ):
@@ -21,44 +22,80 @@ def _launch(extra_env):
21
22
POLL_FREQ = 10
22
23
23
24
24
- def test_kernelapp_lifecycle ():
25
+ def test_kernelapp_lifecycle (request , tmpdir ):
25
26
# Check that 'jupyter kernel' starts and terminates OK.
26
- runtime_dir = mkdtemp ( )
27
- startup_dir = mkdtemp ( )
27
+ runtime_dir = str ( tmpdir . join ( "runtime" ). mkdir () )
28
+ startup_dir = str ( tmpdir . join ( "startup" ). mkdir () )
28
29
started = os .path .join (startup_dir , "started" )
29
- try :
30
- p = _launch (
31
- {
32
- "JUPYTER_RUNTIME_DIR" : runtime_dir ,
33
- "JUPYTER_CLIENT_TEST_RECORD_STARTUP_PRIVATE" : started ,
34
- }
35
- )
36
- # Wait for start
37
- for _ in range (WAIT_TIME * POLL_FREQ ):
38
- if os .path .isfile (started ):
39
- break
40
- time .sleep (1 / POLL_FREQ )
41
- else :
42
- raise AssertionError ("No started file created in {} seconds" .format (WAIT_TIME ))
43
-
44
- # Connection file should be there by now
45
- for _ in range (WAIT_TIME * POLL_FREQ ):
46
- files = os .listdir (runtime_dir )
47
- if files :
30
+ p = _launch (
31
+ {
32
+ "JUPYTER_RUNTIME_DIR" : runtime_dir ,
33
+ "JUPYTER_CLIENT_TEST_RECORD_STARTUP_PRIVATE" : started ,
34
+ }
35
+ )
36
+ request .addfinalizer (p .terminate )
37
+
38
+ # Wait for start
39
+ for _ in range (WAIT_TIME * POLL_FREQ ):
40
+ if os .path .isfile (started ):
41
+ break
42
+ time .sleep (1 / POLL_FREQ )
43
+ else :
44
+ raise AssertionError ("No started file created in {} seconds" .format (WAIT_TIME ))
45
+
46
+ # Connection file should be there by now
47
+ for _ in range (WAIT_TIME * POLL_FREQ ):
48
+ files = os .listdir (runtime_dir )
49
+ if files :
50
+ break
51
+ time .sleep (1 / POLL_FREQ )
52
+ else :
53
+ raise AssertionError ("No connection file created in {} seconds" .format (WAIT_TIME ))
54
+
55
+ assert len (files ) == 1
56
+ cf = files [0 ]
57
+ assert cf .startswith ("kernel" )
58
+ assert cf .endswith (".json" )
59
+
60
+ # pexpect-style wait-for-text with timeout
61
+ # use blocking background thread to read output
62
+ # so this works on Windows
63
+ t = time .perf_counter ()
64
+ deadline = t + WAIT_TIME
65
+ remaining = WAIT_TIME
66
+
67
+ stderr = ""
68
+ q = Queue ()
69
+
70
+ def _readlines ():
71
+ while True :
72
+ line = p .stderr .readline ()
73
+ q .put (line .decode ("utf8" , "replace" ))
74
+ if not line :
48
75
break
49
- time .sleep (1 / POLL_FREQ )
50
- else :
51
- raise AssertionError ("No connection file created in {} seconds" .format (WAIT_TIME ))
52
- assert len (files ) == 1
53
- cf = files [0 ]
54
- assert cf .startswith ("kernel" )
55
- assert cf .endswith (".json" )
56
-
57
- # Send SIGTERM to shut down
58
- time .sleep (1 )
76
+
77
+ stderr_thread = Thread (target = _readlines , daemon = True )
78
+ stderr_thread .start ()
79
+
80
+ while remaining >= 0 and p .poll () is None :
81
+ try :
82
+ line = q .get (timeout = remaining )
83
+ except Empty :
84
+ break
85
+ stderr += line
86
+ if cf in stderr :
87
+ break
88
+ remaining = deadline - time .perf_counter ()
89
+
90
+ if p .poll () is None :
59
91
p .terminate ()
60
- _ , stderr = p .communicate (timeout = WAIT_TIME )
61
- assert cf in stderr .decode ("utf-8" , "replace" )
62
- finally :
63
- shutil .rmtree (runtime_dir )
64
- shutil .rmtree (startup_dir )
92
+
93
+ # finish reading stderr
94
+ stderr_thread .join ()
95
+ while True :
96
+ try :
97
+ line = q .get_nowait ()
98
+ except Empty :
99
+ break
100
+ stderr += line
101
+ assert cf in stderr
0 commit comments