Skip to content

Commit

Permalink
Fixing #843: Tests should use CTest
Browse files Browse the repository at this point in the history
  • Loading branch information
sithhell committed Sep 11, 2013
1 parent 4094156 commit da101e6
Show file tree
Hide file tree
Showing 21 changed files with 283 additions and 271 deletions.
26 changes: 8 additions & 18 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ hpx_option(HPX_NATIVE_MIC BOOL

if(HPX_NATIVE_MIC)
hpx_option(HPX_MAX_CPU_COUNT STRING
"HPX applications will not use more than this amount of OS-threads (default: 256)."
"HPX applications will not use more than this amount of OS-threads (default: 256)."
"256" ADVANCED)
if(NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel"))
hpx_error("HPX on the MIC can only be compiled with the Intel compiler.")
Expand All @@ -208,7 +208,7 @@ if(HPX_NATIVE_MIC)
set(HPX_MALLOC "tbbmalloc")
else()
hpx_option(HPX_MAX_CPU_COUNT STRING
"HPX applications will not use more than this amount of OS-threads (default: 64)."
"HPX applications will not use more than this amount of OS-threads (default: 64)."
"64" ADVANCED)
endif()

Expand Down Expand Up @@ -1352,15 +1352,11 @@ if(HPX_BUILD_TESTS)

add_hpx_pseudo_target(tests)

enable_testing()
include(CTest)

add_custom_command(TARGET tests POST_BUILD
COMMAND ${CMAKE_SOURCE_DIR}/python/scripts/hpx_run_tests.py
ARGS --prefix=${CMAKE_BINARY_DIR}/bin/
--args=\${HPX_TEST_ARGUMENTS}
--log-stdout
--no-exit-code
${CMAKE_BINARY_DIR}/share/hpx-${HPX_VERSION}/tests/hpx_unit.tests
${CMAKE_BINARY_DIR}/share/hpx-${HPX_VERSION}/tests/hpx_regressions.tests
COMMENT "Running HPX tests")
COMMAND ctest)

hpx_include_directories(tests)
add_subdirectory(tests)
Expand Down Expand Up @@ -1744,11 +1740,9 @@ execute_process(COMMAND
"${CMAKE_COMMAND}" -E create_symlink "hpx-${HPX_VERSION}" "hpx"
WORKING_DIRECTORY ${output_dir}/share)

file(WRITE ${output_dir}/share/hpx-${HPX_VERSION}/tests/hpx_unit.tests
"[\n${HPX_UNIT_TEST_LIST}\n]\n")
file(WRITE ${output_dir}/share/hpx-${HPX_VERSION}/tests/hpx_unit.tests "\"-R tests.unit\"")

file(WRITE ${output_dir}/share/hpx-${HPX_VERSION}/tests/hpx_regressions.tests
"[\n${HPX_REGRESSION_TEST_LIST}\n]\n")
file(WRITE ${output_dir}/share/hpx-${HPX_VERSION}/tests/hpx_regressions.tests "\"-R tests.regression\"")

if(NOT HPX_NO_INSTALL)
install(FILES ${output_dir}/share/hpx-${HPX_VERSION}/tests/hpx_unit.tests
Expand All @@ -1757,7 +1751,3 @@ if(NOT HPX_NO_INSTALL)
DESTINATION share/hpx-${HPX_VERSION}/tests)
endif()

unset(HPX_UNIT_TEST_LIST CACHE)
unset(HPX_REGRESSION_TEST_LIST CACHE)


19 changes: 11 additions & 8 deletions cmake/HPX_AddTest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ macro(hpx_make_python_list input output)
set(${output} "${${output}}]")
endmacro()

macro(add_hpx_test name test_list)
macro(add_hpx_test name category)
hpx_parse_arguments(${name} "TIMEOUT;LOCALITIES;THREADS_PER_LOCALITY;ARGS"
"FAILURE_EXPECTED" ${ARGN})

Expand Down Expand Up @@ -47,7 +47,7 @@ macro(add_hpx_test name test_list)

hpx_make_python_list(args ${name}_ARGS)

set(test_input "'${name}'"
set(test_input "'$<TARGET_FILE:${name}_test_exe>'"
${${name}_TIMEOUT}
${expected}
${${name}_LOCALITIES}
Expand All @@ -58,15 +58,18 @@ macro(add_hpx_test name test_list)

set(test_output " ${test_output},\n")

set(${test_list} "${${test_list}}${test_output}"
CACHE STRING "Test description list" FORCE)
add_test(
NAME "${category}.${name}"
COMMAND ${CMAKE_SOURCE_DIR}/python/scripts/hpx_run_test.py
--log-stdout
"[${test_output}]")
endmacro()

macro(add_hpx_unit_test name)
add_hpx_test(${name} HPX_UNIT_TEST_LIST ${ARGN})
macro(add_hpx_unit_test category name)
add_hpx_test(${name} "tests.unit.${category}" ${ARGN})
endmacro()

macro(add_hpx_regression_test name)
add_hpx_test(${name} HPX_REGRESSION_TEST_LIST ${ARGN})
macro(add_hpx_regression_test category name)
add_hpx_test(${name} "tests.regressions.${category}" ${ARGN})
endmacro()

235 changes: 235 additions & 0 deletions python/scripts/hpx_run_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
#! /usr/bin/env python
#
# Copyright (c) 2012 Bryce Adelstein-Lelbach
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

# TODO: Fractional threads_per_locality

import sys, os, string
import os.path as osp

from types import StringType

from optparse import OptionParser

from errno import ENOENT

import signal, re

if osp.exists(osp.join(sys.path[0], "../hpx")):
sys.path.append(osp.join(sys.path[0], ".."))
if osp.exists(osp.join(sys.path[0], "../share/hpx/python/hpx")):
sys.path.append(osp.join(sys.path[0], "../share/hpx/python"))

from hpx.process import process, process_group

# Input files should be a list of lists. Each sublist should follow the
# following structure:
#
# format: [ name, timeout, success, nodes, threads_per_node, args ]
# types: [ string, float or None, bool, int, int, list ]

signal_map = dict((-1 * k, v) for v, k in signal.__dict__.iteritems() \
if re.match("SIG[A-Z]*$", v))

def exit_decode(exit_code):
# In Bash on Linux, programs exit with a code of -1 * signal when an unhandled
# signal occurs.
if exit_code < 0 and exit_code in signal_map:
return signal_map[exit_code]
else:
return exit_code

def quote_options(options, quoting_char = '"'):
no_quote = string.letters + string.digits + '-+=/_.'
s = ''

for option in options:
if type(option) is not StringType:
option = str(option)
for c in option:
if c not in no_quote:
s += ' ' + quoting_char + option + quoting_char
break
else:
s += ' ' + option

return string.strip(s)

class TestFailed(Exception):
pass

if __name__ == '__main__':
# {{{ main
usage = "Usage: %prog [options] [test to run]"

parser = OptionParser(usage=usage)

exe_dir = osp.normpath(osp.dirname(sys.argv[0])) + '/'

parser.add_option("--suffix",
action="store", type="string",
dest="suffix", default="_test",
help="Suffix added to test names [default: %default]")

parser.add_option("--args",
action="store", type="string",
dest="args", default="",
help="Command line arguments to add tests [default: %default]")

parser.add_option("--log",
action="store", type="string",
dest="log", default="fail",
help="Always log output (--log=always), never log "
+"output (--log=never) or log output for tests "
+"that fail (--log=fail) [default: %default]")

parser.add_option("--log-stdout",
action="store_true", dest="log_stdout", default=False,
help="Send logs to stdout (overrides --log-prefix)")

parser.add_option("--log-prefix",
action="store", type="string",
dest="log_prefix", default="./",
help="Prefix for log files [default: %default]")

parser.add_option("--no-exit-code",
action="store_false", dest="exit_code", default=True,
help="Don't return a non-zero exit code when tests fail")

(options, files) = parser.parse_args()

if not (lambda x: "always" == x or "never" == x or "fail" == x)(options.log):
print "Error: --log=" + quote_options([options.log]) + " is invalid\n"
parser.print_help()
sys.exit(1)

if 0 == len(files):
print "Error: no .tests files specified\n"
parser.print_help()
sys.exit(1)

tests = []
all_passed = True

for f in files:
tests += eval(f)#eval(open(f).read())

for [name, timeout, success, nodes, threads_per_node, args] in tests:
print "Running: " + name + " (Timeout:", timeout, "[s])",
sys.stdout.flush()

pg = process_group()
results = [] # [ cmd, cmd_passed, exit_code, timed_out, output ]
cmds = {}

if not osp.exists(name):
print "-", "Failed (test not found)"

all_passed = False

if "always" == options.log or "fail" == options.log:
f = None

if not options.log_stdout:
log = name + ".log"
f = open(log, "w+")
print (" " * 2) + "Log:", log
else:
f = sys.stdout

print >> f, ("#" * 80)
print >> f, "Test:", name
print >> f, "Result: Failed (test not found)"
print >> f, ("#" * 80)

continue

for node in range(nodes):
cmd = [ name
, '-t' + str(threads_per_node)
, '-l' + str(nodes)
, '-' + str(node)]

if options.args:
cmd += [options.args]

cmd += args

cmd = quote_options(cmd)

cmds[pg.create_process(cmd).fileno()] = cmd

def gather_results(fd, job, output):
cmd_passed = (job.poll() == 0 if success else job.poll() != 0) \
and not job.timed_out()

results.append([ cmds[job.fileno()]
, cmd_passed
, job.poll()
, job.timed_out()
, output])

if not cmd_passed:
raise TestFailed()

try:
pg.read_all(timeout, gather_results)
except TestFailed:
def read_callback(fd, job):
try:
gather_results(fd, job, job.read(0.5))
except TestFailed:
pass

pg.terminate_all(read_callback)

# all the commands are now done

test_passed = True

for result in results:
if not result[1]:
test_passed = False
break

all_passed = all_passed and test_passed

print "-", ("Passed" if test_passed else "Failed")

if "always" == options.log or ("fail" == options.log and not test_passed):
f = None

if not options.log_stdout:
log = name + ".log"
f = open(log, "w+")
print (" " * 2) + "Log:", log
else:
f = sys.stdout

print >> f, ("#" * 80)
print >> f, "Test:", name
print >> f, "Result:", ("Passed" if test_passed else "Failed")
print >> f, ("#" * 80)
print >> f, ""

for result in results:
print >> f, ("#" * 80)
print >> f, "Command:", result[0]
print >> f, "Result:", ("Passed" if result[1] else "Failed")
print >> f, "Exit code:", exit_decode(result[2])
print >> f, "Timed out:", result[3]
print >> f, ("#" * 80)

if 0 != len(result[4]):
print >> f, result[4],
print >> f, ("#" * 80)

print >> f, ""

if not all_passed and options.exit_code:
sys.exit(1)
# }}}

0 comments on commit da101e6

Please sign in to comment.