Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(471)

Side by Side Diff: expect_tests/pipeline.py

Issue 556313004: Added TempDir (Closed) Base URL: https://chromium.googlesource.com/infra/testing/expect_tests@shebang
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | expect_tests/tempdir.py » ('j') | expect_tests/tempdir.py » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import Queue 5 import Queue
6 import glob 6 import glob
7 import logging 7 import logging
8 import multiprocessing 8 import multiprocessing
9 import os 9 import os
10 import re 10 import re
11 import shutil 11 import shutil
12 import signal 12 import signal
13 import sys 13 import sys
14 import tempfile 14 import tempfile
15 import traceback 15 import traceback
16 16
17 from cStringIO import StringIO 17 from cStringIO import StringIO
18 18
19 from expect_tests.tempdir import TempDir
19 from expect_tests.type_definitions import ( 20 from expect_tests.type_definitions import (
20 Test, UnknownError, TestError, NoMatchingTestsError, MultiTest, 21 Test, UnknownError, TestError, NoMatchingTestsError, MultiTest,
21 Result, ResultStageAbort) 22 Result, ResultStageAbort)
22 23
23 from expect_tests import util 24 from expect_tests import util
24 25
25 26
26 OLD_TEMP_DIR = None
27 TEMP_PID_FILE = '.expect_tests_pidfile'
28
29
30 class ResetableStringIO(object): 27 class ResetableStringIO(object):
31 def __init__(self): 28 def __init__(self):
32 self._stream = StringIO() 29 self._stream = StringIO()
33 30
34 def reset(self): 31 def reset(self):
35 self._stream = StringIO() 32 self._stream = StringIO()
36 33
37 def __getattr__(self, key): 34 def __getattr__(self, key):
38 return getattr(self._stream, key) 35 return getattr(self._stream, key)
39 36
40 37
41 def set_temp_dir():
42 """Provides an automatically-cleaned temporary directory base for tests."""
43 global OLD_TEMP_DIR
44
45 if OLD_TEMP_DIR:
46 return
47
48 suffix = '.expect_tests_temp'
49 tempdir = tempfile.mkdtemp(suffix)
50 for p in glob.glob(os.path.join(os.path.dirname(tempdir), '*'+suffix)):
51 if p == tempdir:
52 continue
53
54 pfile = os.path.join(p, TEMP_PID_FILE)
55 if os.path.exists(pfile):
56 with open(pfile, 'rb') as f:
57 try:
58 os.kill(int(f.read()), 0)
59 continue
60 except (OSError, TypeError):
61 pass
62
63 shutil.rmtree(p, ignore_errors=True)
64
65 with open(os.path.join(tempdir, TEMP_PID_FILE), 'wb') as f:
66 f.write(str(os.getpid()))
67
68 OLD_TEMP_DIR = tempfile.tempdir
69 tempfile.tempdir = tempdir
70
71
72 def clear_temp_dir():
73 global OLD_TEMP_DIR
74 if OLD_TEMP_DIR:
75 # Try to nuke the pidfile first
76 pfile = os.path.join(tempfile.tempdir, TEMP_PID_FILE)
77 try:
78 os.unlink(pfile)
79 except OSError as e:
80 print >> sys.stderr, "Error removing %r: %s" % (pfile, e)
81 shutil.rmtree(tempfile.tempdir, ignore_errors=True)
82 tempfile.temdir = OLD_TEMP_DIR
83 OLD_TEMP_DIR = None
84
85
86 def gen_loop_process(gens, test_queue, result_queue, opts, kill_switch, 38 def gen_loop_process(gens, test_queue, result_queue, opts, kill_switch,
87 cover_ctx, temp_dir): 39 cover_ctx, temp_dir):
88 """Generate `Test`s from |gens|, and feed them into |test_queue|. 40 """Generate `Test`s from |gens|, and feed them into |test_queue|.
89 41
90 Non-Test instances will be translated into `UnknownError` objects. 42 Non-Test instances will be translated into `UnknownError` objects.
91 43
92 On completion, feed |opts.jobs| None objects into |test_queue|. 44 On completion, feed |opts.jobs| None objects into |test_queue|.
93 45
94 @param gens: list of generators yielding Test() instances. 46 @param gens: list of generators yielding Test() instances.
95 @type test_queue: multiprocessing.Queue() 47 @type test_queue: multiprocessing.Queue()
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 kill_switch.set() 207 kill_switch.set()
256 # Reset the signal to DFL so that double ctrl-C kills us for sure. 208 # Reset the signal to DFL so that double ctrl-C kills us for sure.
257 signal.signal(signal.SIGINT, signal.SIG_DFL) 209 signal.signal(signal.SIGINT, signal.SIG_DFL)
258 signal.signal(signal.SIGTERM, signal.SIG_DFL) 210 signal.signal(signal.SIGTERM, signal.SIG_DFL)
259 signal.signal(signal.SIGINT, handle_killswitch) 211 signal.signal(signal.SIGINT, handle_killswitch)
260 signal.signal(signal.SIGTERM, handle_killswitch) 212 signal.signal(signal.SIGTERM, handle_killswitch)
261 213
262 test_queue = multiprocessing.Queue() 214 test_queue = multiprocessing.Queue()
263 result_queue = multiprocessing.Queue() 215 result_queue = multiprocessing.Queue()
264 216
265 set_temp_dir() 217 with TempDir() as temp_dir:
218 test_gen_args = (
219 test_gens, test_queue, result_queue, opts, kill_switch, cover_ctx,
220 temp_dir
221 )
266 222
267 test_gen_args = ( 223 procs = []
268 test_gens, test_queue, result_queue, opts, kill_switch, cover_ctx, 224 if opts.handler.SKIP_RUNLOOP:
269 tempfile.tempdir 225 gen_loop_process(*test_gen_args)
270 ) 226 else:
227 procs = [multiprocessing.Process(
228 target=gen_loop_process, args=test_gen_args)]
271 229
272 procs = [] 230 procs += [
273 if opts.handler.SKIP_RUNLOOP: 231 multiprocessing.Process(
274 gen_loop_process(*test_gen_args) 232 target=run_loop_process, args=(
275 else: 233 test_queue, result_queue, opts, kill_switch, cover_ctx,
276 procs = [multiprocessing.Process( 234 temp_dir))
277 target=gen_loop_process, args=test_gen_args)] 235 for _ in xrange(opts.jobs)
236 ]
278 237
279 procs += [ 238 for p in procs:
280 multiprocessing.Process( 239 p.daemon = True
281 target=run_loop_process, args=( 240 p.start()
282 test_queue, result_queue, opts, kill_switch, cover_ctx,
283 tempfile.tempdir))
284 for _ in xrange(opts.jobs)
285 ]
286 241
287 for p in procs: 242 error = False
288 p.daemon = True
289 p.start()
290 243
291 error = False 244 try:
245 def generate_objects():
246 while not kill_switch.is_set():
247 while not kill_switch.is_set():
248 try:
249 yield result_queue.get(timeout=0.1)
250 except Queue.Empty:
251 break
292 252
293 try: 253 if not any(p.is_alive() for p in procs):
294 def generate_objects(): 254 break
295 while not kill_switch.is_set(): 255
256 # Get everything still in the queue. Still need timeout, but since
257 # nothing is going to be adding stuff to the queue, use a very short
258 # timeout.
296 while not kill_switch.is_set(): 259 while not kill_switch.is_set():
297 try: 260 try:
298 yield result_queue.get(timeout=0.1) 261 yield result_queue.get(timeout=0.00001)
299 except Queue.Empty: 262 except Queue.Empty:
300 break 263 break
301 264
302 if not any(p.is_alive() for p in procs): 265 if kill_switch.is_set():
303 break 266 raise ResultStageAbort()
304 267 error = opts.handler.result_stage_loop(opts, generate_objects())
305 # Get everything still in the queue. Still need timeout, but since nothing 268 except ResultStageAbort:
306 # is going to be adding stuff to the queue, use a very short timeout. 269 pass
307 while not kill_switch.is_set():
308 try:
309 yield result_queue.get(timeout=0.00001)
310 except Queue.Empty:
311 break
312
313 if kill_switch.is_set():
314 raise ResultStageAbort()
315 error = opts.handler.result_stage_loop(opts, generate_objects())
316 except ResultStageAbort:
317 pass
318 finally:
319 clear_temp_dir()
320 270
321 for p in procs: 271 for p in procs:
322 p.join() 272 p.join()
323 273
324 if not kill_switch.is_set() and not result_queue.empty(): 274 if not kill_switch.is_set() and not result_queue.empty():
325 error = True 275 error = True
326 276
327 return error, kill_switch.is_set() 277 return error, kill_switch.is_set()
OLDNEW
« no previous file with comments | « no previous file | expect_tests/tempdir.py » ('j') | expect_tests/tempdir.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698