1
-
2
1
import os
3
2
import re
4
3
import signal
11
10
import irods .helpers
12
11
from irods .test import modules as test_modules
13
12
14
- OBJECT_SIZE = 2 * 1024 ** 3
15
- OBJECT_NAME = ' data_get_issue__722'
16
- LOCAL_TEMPFILE_NAME = ' data_object_for_issue_722.dat'
13
+ OBJECT_SIZE = 2 * 1024 ** 3
14
+ OBJECT_NAME = " data_get_issue__722"
15
+ LOCAL_TEMPFILE_NAME = " data_object_for_issue_722.dat"
17
16
18
17
19
- _clock_polling_interval = max (.01 , time .clock_getres (time .CLOCK_BOOTTIME ))
18
+ _clock_polling_interval = max (0 .01 , time .clock_getres (time .CLOCK_BOOTTIME ))
20
19
21
20
22
21
def wait_till_true (function , timeout = None ):
23
22
start_time = time .clock_gettime_ns (time .CLOCK_BOOTTIME )
24
23
while not (truth_value := function ()):
25
- if timeout is not None and (time .clock_gettime_ns (time .CLOCK_BOOTTIME )- start_time )* 1e-9 > timeout :
24
+ if (
25
+ timeout is not None
26
+ and (time .clock_gettime_ns (time .CLOCK_BOOTTIME ) - start_time ) * 1e-9
27
+ > timeout
28
+ ):
26
29
break
27
30
time .sleep (_clock_polling_interval )
28
31
return truth_value
29
32
30
33
31
- def test (test_case , signal_names = ("SIGTERM" , "SIGINT" )):
34
+ def test (test_case , signal_names = ("SIGTERM" , "SIGINT" )):
32
35
"""Creates a child process executing a long get() and ensures the process can be
33
36
terminated using SIGINT or SIGTERM.
34
37
"""
@@ -37,52 +40,68 @@ def test(test_case, signal_names = ("SIGTERM", "SIGINT")):
37
40
for signal_name in signal_names :
38
41
# Call into this same module as a command. This will initiate another Python process that
39
42
# performs a lengthy data object "get" operation (see the main body of the script, below.)
40
- process = subprocess .Popen ([sys .executable , program ],
41
- stderr = subprocess .PIPE ,
42
- stdout = subprocess .PIPE ,
43
- text = True )
43
+ process = subprocess .Popen (
44
+ [sys .executable , program ],
45
+ stderr = subprocess .PIPE ,
46
+ stdout = subprocess .PIPE ,
47
+ text = True ,
48
+ )
44
49
45
50
# Wait for download process to reach the point of spawning data transfer threads. In Python 3.9+ versions
46
51
# of the concurrent.futures module, these are nondaemon threads and will block the exit of the main thread
47
52
# unless measures are taken (#722).
48
53
localfile = process .stdout .readline ().strip ()
49
- test_case .assertTrue (wait_till_true (lambda :os .path .exists (localfile ) and os .stat (localfile ).st_size > OBJECT_SIZE // 2 ),
50
- "Parallel download from data_objects.get() probably experienced a fatal error before spawning auxiliary data transfer threads."
51
- )
54
+ test_case .assertTrue (
55
+ wait_till_true (
56
+ lambda : os .path .exists (localfile )
57
+ and os .stat (localfile ).st_size > OBJECT_SIZE // 2
58
+ ),
59
+ "Parallel download from data_objects.get() probably experienced a fatal error before spawning auxiliary data transfer threads." ,
60
+ )
52
61
53
62
signal_message_info = f"While testing signal { signal_name } "
54
63
sig = getattr (signal , signal_name )
55
64
56
65
# Interrupt the subprocess with the given signal.
57
66
process .send_signal (sig )
58
- # Assert that this signal is what killed the subprocess, rather than a timed out process "wait" or a natural exit
67
+ # Assert that this signal is what killed the subprocess, rather than a timed out process "wait" or a natural exit
59
68
# due to misproper or incomplete handling of the signal.
60
69
try :
61
- test_case .assertEqual (process .wait (timeout = 15 ), - sig , "{signal_message_info}: unexpected subprocess return code." )
70
+ test_case .assertEqual (
71
+ process .wait (timeout = 15 ),
72
+ - sig ,
73
+ "{signal_message_info}: unexpected subprocess return code." ,
74
+ )
62
75
except subprocess .TimeoutExpired as timeout_exc :
63
- test_case .fail (f"{ signal_message_info } : subprocess timed out before terminating. "
64
- "Non-daemon thread(s) probably prevented subprocess's main thread from exiting." )
76
+ test_case .fail (
77
+ f"{ signal_message_info } : subprocess timed out before terminating. "
78
+ "Non-daemon thread(s) probably prevented subprocess's main thread from exiting."
79
+ )
65
80
# Assert that in the case of SIGINT, the process registered a KeyboardInterrupt.
66
81
if sig == signal .SIGINT :
67
- test_case .assertTrue (re .search ('KeyboardInterrupt' , process .stderr .read ()),
68
- "{signal_message_info}: Expected 'KeyboardInterrupt' in log output." )
82
+ test_case .assertTrue (
83
+ re .search ("KeyboardInterrupt" , process .stderr .read ()),
84
+ "{signal_message_info}: Expected 'KeyboardInterrupt' in log output." ,
85
+ )
69
86
70
87
71
88
if __name__ == "__main__" :
72
89
# These lines are run only if the module is launched as a process.
73
90
session = irods .helpers .make_session ()
74
91
hc = irods .helpers .home_collection (session )
75
- TESTFILE_FILL = b'_' * (1024 * 1024 )
76
- object_path = f' { hc } /{ OBJECT_NAME } '
92
+ TESTFILE_FILL = b"_" * (1024 * 1024 )
93
+ object_path = f" { hc } /{ OBJECT_NAME } "
77
94
78
95
# Create the object to be downloaded.
79
- with session .data_objects .open (object_path ,'w' ) as f :
80
- for y in range (OBJECT_SIZE // len (TESTFILE_FILL )):
96
+ with session .data_objects .open (object_path , "w" ) as f :
97
+ for y in range (OBJECT_SIZE // len (TESTFILE_FILL )):
81
98
f .write (TESTFILE_FILL )
82
99
local_path = None
83
100
# Establish where (ie absolute path) to place the downloaded file, i.e. the get() target.
84
101
try :
85
- with tempfile .NamedTemporaryFile (prefix = 'local_file_issue_722.dat' , delete = True ) as t :
102
+ with tempfile .NamedTemporaryFile (
103
+ prefix = "local_file_issue_722.dat" , delete = True
104
+ ) as t :
86
105
local_path = t .name
87
106
88
107
# Tell the parent process the name of the local file being "get"ted (got) from iRODS
0 commit comments