53
53
54
54
#Create a set to store arguments and create the passon string
55
55
opts = set ()
56
- passon_args = ""
56
+ passon_args = []
57
57
PASSON_REGEX = re .compile ("^--" )
58
+ PARALLEL_REGEX = re .compile ('^-parallel=' )
58
59
59
60
print_help = False
61
+ run_parallel = 4
60
62
61
63
for arg in sys .argv [1 :]:
62
64
if arg == "--help" or arg == "-h" or arg == "-?" :
65
67
if arg == '--coverage' :
66
68
ENABLE_COVERAGE = 1
67
69
elif PASSON_REGEX .match (arg ):
68
- passon_args += " " + arg
70
+ passon_args .append (arg )
71
+ elif PARALLEL_REGEX .match (arg ):
72
+ run_parallel = int (arg .split (sep = '=' , maxsplit = 1 )[1 ])
69
73
else :
70
74
opts .add (arg )
71
75
96
100
97
101
#Tests
98
102
testScripts = [
103
+ 'walletbackup.py' ,
99
104
'bip68-112-113-p2p.py' ,
100
105
'wallet.py' ,
101
106
'listtransactions.py' ,
116
121
'merkle_blocks.py' ,
117
122
'fundrawtransaction.py' ,
118
123
'signrawtransactions.py' ,
119
- 'walletbackup.py' ,
120
124
'nodehandling.py' ,
121
125
'reindex.py' ,
122
126
'decodescript.py' ,
131
135
'abandonconflict.py' ,
132
136
'p2p-versionbits-warning.py' ,
133
137
'importprunedfunds.py' ,
134
- 'signmessages.py'
138
+ 'signmessages.py' ,
135
139
]
136
140
if ENABLE_ZMQ :
137
141
testScripts .append ('zmq_test.py' )
160
164
'pruning.py' , # leave pruning last as it takes a REALLY long time
161
165
]
162
166
167
+
163
168
def runtests ():
164
169
test_list = []
165
170
if '-extended' in opts :
@@ -173,30 +178,92 @@ def runtests():
173
178
174
179
if print_help :
175
180
# Only print help of the first script and exit
176
- subprocess .check_call (RPC_TESTS_DIR + test_list [0 ] + ' -h', shell = True )
181
+ subprocess .check_call (( RPC_TESTS_DIR + test_list [0 ]). split () + [ ' -h'] )
177
182
sys .exit (0 )
178
183
179
184
coverage = None
180
185
181
186
if ENABLE_COVERAGE :
182
187
coverage = RPCCoverage ()
183
188
print ("Initializing coverage directory at %s\n " % coverage .dir )
184
- flags = " --srcdir %s/src %s %s" % (BUILDDIR , coverage .flag if coverage else '' , passon_args )
189
+ flags = ["--srcdir=%s/src" % BUILDDIR ] + passon_args
190
+ if coverage :
191
+ flags .append (coverage .flag )
192
+
193
+ if len (test_list ) > 1 :
194
+ # Populate cache
195
+ subprocess .check_output ([RPC_TESTS_DIR + 'create_cache.py' ] + flags )
185
196
186
197
#Run Tests
187
- for t in test_list :
188
- print ("Running testscript %s%s%s ..." % (BOLD [1 ], t , BOLD [0 ]))
189
- time0 = time .time ()
190
- subprocess .check_call (
191
- RPC_TESTS_DIR + t + flags , shell = True )
192
- print ("Duration: %s s\n " % (int (time .time () - time0 )))
198
+ max_len_name = len (max (test_list , key = len ))
199
+ time_sum = 0
200
+ time0 = time .time ()
201
+ job_queue = RPCTestHandler (run_parallel , test_list , flags )
202
+ results = BOLD [1 ] + "%s | %s | %s\n \n " % ("TEST" .ljust (max_len_name ), "PASSED" , "DURATION" ) + BOLD [0 ]
203
+ all_passed = True
204
+ for _ in range (len (test_list )):
205
+ (name , stdout , stderr , passed , duration ) = job_queue .get_next ()
206
+ all_passed = all_passed and passed
207
+ time_sum += duration
208
+
209
+ print ('\n ' + BOLD [1 ] + name + BOLD [0 ] + ":" )
210
+ print (stdout )
211
+ print ('stderr:\n ' if not stderr == '' else '' , stderr )
212
+ results += "%s | %s | %s s\n " % (name .ljust (max_len_name ), str (passed ).ljust (6 ), duration )
213
+ print ("Pass: %s%s%s, Duration: %s s\n " % (BOLD [1 ], passed , BOLD [0 ], duration ))
214
+ results += BOLD [1 ] + "\n %s | %s | %s s (accumulated)" % ("ALL" .ljust (max_len_name ), str (all_passed ).ljust (6 ), time_sum ) + BOLD [0 ]
215
+ print (results )
216
+ print ("\n Runtime: %s s" % (int (time .time () - time0 )))
193
217
194
218
if coverage :
195
219
coverage .report_rpc_coverage ()
196
220
197
221
print ("Cleaning up coverage data" )
198
222
coverage .cleanup ()
199
223
224
+ sys .exit (not all_passed )
225
+
226
+
227
+ class RPCTestHandler :
228
+ """
229
+ Trigger the testscrips passed in via the list.
230
+ """
231
+
232
+ def __init__ (self , num_tests_parallel , test_list = None , flags = None ):
233
+ assert (num_tests_parallel >= 1 )
234
+ self .num_jobs = num_tests_parallel
235
+ self .test_list = test_list
236
+ self .flags = flags
237
+ self .num_running = 0
238
+ self .jobs = []
239
+
240
+ def get_next (self ):
241
+ while self .num_running < self .num_jobs and self .test_list :
242
+ # Add tests
243
+ self .num_running += 1
244
+ t = self .test_list .pop (0 )
245
+ port_seed = ["--portseed=%s" % len (self .test_list )]
246
+ self .jobs .append ((t ,
247
+ time .time (),
248
+ subprocess .Popen ((RPC_TESTS_DIR + t ).split () + self .flags + port_seed ,
249
+ universal_newlines = True ,
250
+ stdout = subprocess .PIPE ,
251
+ stderr = subprocess .PIPE )))
252
+ if not self .jobs :
253
+ raise IndexError ('%s from empty list' % __name__ )
254
+ while True :
255
+ # Return first proc that finishes
256
+ time .sleep (.5 )
257
+ for j in self .jobs :
258
+ (name , time0 , proc ) = j
259
+ if proc .poll () is not None :
260
+ (stdout , stderr ) = proc .communicate (timeout = 3 )
261
+ passed = stderr == "" and proc .returncode == 0
262
+ self .num_running -= 1
263
+ self .jobs .remove (j )
264
+ return name , stdout , stderr , passed , int (time .time () - time0 )
265
+ print ('.' , end = '' , flush = True )
266
+
200
267
201
268
class RPCCoverage (object ):
202
269
"""
@@ -215,7 +282,7 @@ class RPCCoverage(object):
215
282
"""
216
283
def __init__ (self ):
217
284
self .dir = tempfile .mkdtemp (prefix = "coverage" )
218
- self .flag = '--coveragedir %s' % self .dir
285
+ self .flag = '--coveragedir= %s' % self .dir
219
286
220
287
def report_rpc_coverage (self ):
221
288
"""
0 commit comments