@ -50,21 +50,27 @@ class TestController(object):
process = None
#: str, process stdout+stderr
stdout = None
#: bool, whether to capture process stdout & stderr
buffer_output = False
def __init__ ( self ) :
self . cmd = [ ]
self . env = { }
self . dirs = [ ]
def launch ( self ) :
def setup ( self ) :
""" Create temporary directories etc.
This is only called when we know the test group will be run . Things
created here may be cleaned up by self . cleanup ( ) .
"""
pass
def launch ( self , buffer_output = False ) :
# print('*** ENV:', self.env) # dbg
# print('*** CMD:', self.cmd) # dbg
env = os . environ . copy ( )
env . update ( self . env )
output = subprocess . PIPE if self . buffer_output else None
stdout = subprocess . STDOUT if self . buffer_output else None
output = subprocess . PIPE if buffer_output else None
stdout = subprocess . STDOUT if buffer_output else None
self . process = subprocess . Popen ( self . cmd , stdout = output ,
stderr = stdout , env = env )
@ -72,14 +78,17 @@ class TestController(object):
self . stdout , _ = self . process . communicate ( )
return self . process . returncode
def dump_failure ( self ) :
""" Print buffered results of a test failure.
def print_extra_info ( self ) :
""" Print extra information about this test run.
If we ' re running in parallel and showing the concise view, this is only
called if the test group fails . Otherwise , it ' s called before the test
group is started .
Called after tests fail while running in parallel . The base
implementation just prints the output from the test subprocess , but
subclasses can override it to add extra information .
The base implementation does nothing , but it can be overridden by
subclasses .
"""
print ( self . stdout )
return
def cleanup_process ( self ) :
""" Cleanup on exit by killing any leftover processes. """
@ -125,6 +134,8 @@ class PyTestController(TestController):
# pycmd is put into cmd[2] in PyTestController.launch()
self . cmd = [ sys . executable , ' -c ' , None , section ]
self . pycmd = " from IPython.testing.iptest import run_iptest; run_iptest() "
def setup ( self ) :
ipydir = TemporaryDirectory ( )
self . dirs . append ( ipydir )
self . env [ ' IPYTHONDIR ' ] = ipydir . name
@ -164,9 +175,9 @@ class PyTestController(TestController):
self . env [ ' COVERAGE_PROCESS_START ' ] = config_file
self . pycmd = " import coverage; coverage.process_startup(); " + self . pycmd
def launch ( self ):
def launch ( self , buffer_output = False ):
self . cmd [ 2 ] = self . pycmd
super ( PyTestController , self ) . launch ( )
super ( PyTestController , self ) . launch ( buffer_output = buffer_output )
js_prefix = ' js/ '
@ -187,14 +198,13 @@ class JSController(TestController):
TestController . __init__ ( self )
self . section = section
def launch ( self ) :
def setup ( self ) :
self . ipydir = TemporaryDirectory ( )
self . nbdir = TemporaryDirectory ( )
os . makedirs ( os . path . join ( self . nbdir . name , os . path . join ( u ' sub ∂ir1 ' , u ' sub ∂ir 1a ' ) ) )
os . makedirs ( os . path . join ( self . nbdir . name , os . path . join ( u ' sub ∂ir2 ' , u ' sub ∂ir 1b ' ) ) )
self . dirs . append ( self . ipydir )
self . dirs . append ( self . nbdir )
os . makedirs ( os . path . join ( self . nbdir . name , os . path . join ( u ' sub ∂ir1 ' , u ' sub ∂ir 1a ' ) ) )
os . makedirs ( os . path . join ( self . nbdir . name , os . path . join ( u ' sub ∂ir2 ' , u ' sub ∂ir 1b ' ) ) )
# start the ipython notebook, so we get the port number
self . _init_server ( )
@ -203,7 +213,9 @@ class JSController(TestController):
test_cases = os . path . join ( js_test_dir , self . section [ len ( js_prefix ) : ] )
port = ' --port= ' + str ( self . server_port )
self . cmd = [ ' casperjs ' , ' test ' , port , includes , test_cases ]
super ( JSController , self ) . launch ( )
def print_extra_info ( self ) :
print ( " Running tests with notebook directory %r " % self . nbdir . name )
@property
def will_run ( self ) :
@ -216,10 +228,6 @@ class JSController(TestController):
self . server . start ( )
self . server_port = q . get ( )
def dump_failure ( self ) :
print ( " Ran tests with notebook directory %r " % self . nbdir . name )
super ( JSController , self ) . dump_failure ( )
def cleanup ( self ) :
self . server . terminate ( )
self . server . join ( )
@ -287,10 +295,27 @@ def configure_py_controllers(controllers, xunit=False, coverage=False,
controller . env [ ' IPTEST_SUBPROC_STREAMS ' ] = subproc_streams
controller . cmd . extend ( extra_args )
def do_run ( controller ) :
def do_run ( controller , buffer_output = True ) :
""" Setup and run a test controller.
If buffer_output is True , no output is displayed , to avoid it appearing
interleaved . In this case , the caller is responsible for displaying test
output on failure .
Returns
- - - - - - -
controller : TestController
The same controller as passed in , as a convenience for using map ( ) type
APIs .
exitcode : int
The exit code of the test subprocess . Non - zero indicates failure .
"""
try :
try :
controller . launch ( )
controller . setup ( )
if not buffer_output :
controller . print_extra_info ( )
controller . launch ( buffer_output = buffer_output )
except Exception :
import traceback
traceback . print_exc ( )
@ -377,10 +402,6 @@ def run_iptestall(options):
extra_args : list
Extra arguments to pass to the test subprocesses , e . g . ' -v '
"""
if options . fast != 1 :
# If running in parallel, capture output so it doesn't get interleaved
TestController . buffer_output = True
to_run , not_run = prepare_controllers ( options )
def justify ( ltext , rtext , width = 70 , fill = ' - ' ) :
@ -398,7 +419,7 @@ def run_iptestall(options):
for controller in to_run :
print ( ' IPython test group: ' , controller . section )
sys . stdout . flush ( ) # Show in correct order when output is piped
controller , res = do_run ( controller )
controller , res = do_run ( controller , buffer_output = False )
if res :
failed . append ( controller )
if res == - signal . SIGINT :
@ -414,7 +435,8 @@ def run_iptestall(options):
res_string = ' OK ' if res == 0 else ' FAILED '
print ( justify ( ' Test group: ' + controller . section , res_string ) )
if res :
controller . dump_failure ( )
controller . print_extra_info ( )
print ( bytes_to_str ( controller . stdout ) )
failed . append ( controller )
if res == - signal . SIGINT :
print ( " Interrupted " )