nocompile_driver.py revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Implements a simple "negative compile" test for C++ on linux. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Sometimes a C++ API needs to ensure that various usages cannot compile. To 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enable unittesting of these assertions, we use this python script to 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)invoke gcc on a source file and assert that compilation fails. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)For more info, see: 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) http://dev.chromium.org/developers/testing/no-compile-tests 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import ast 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import locale 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import select 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import shlex 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import time 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Matches lines that start with #if and have the substring TEST in the 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# conditional. Also extracts the comment. This allows us to search for 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# lines like the following: 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# #ifdef NCTEST_NAME_OF_TEST // [r'expected output'] 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# #if defined(NCTEST_NAME_OF_TEST) // [r'expected output'] 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# #if NCTEST_NAME_OF_TEST // [r'expected output'] 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# #elif NCTEST_NAME_OF_TEST // [r'expected output'] 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# #elif DISABLED_NCTEST_NAME_OF_TEST // [r'expected output'] 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# inside the unittest file. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NCTEST_CONFIG_RE = re.compile(r'^#(?:el)?if.*\s+(\S*NCTEST\S*)\s*(//.*)?') 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Matches and removes the defined() preprocesor predicate. This is useful 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# for test cases that use the preprocessor if-statement form: 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# #if defined(NCTEST_NAME_OF_TEST) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Should be used to post-process the results found by NCTEST_CONFIG_RE. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STRIP_DEFINED_RE = re.compile(r'defined\((.*)\)') 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Used to grab the expectation from comment at the end of an #ifdef. See 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# NCTEST_CONFIG_RE's comment for examples of what the format should look like. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The extracted substring should be a python array of regular expressions. 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EXTRACT_EXPECTATION_RE = re.compile(r'//\s*(\[.*\])') 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The header for the result file so that it can be compiled. 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RESULT_FILE_HEADER = """ 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is generated by the no compile test from: 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// %s 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The GUnit test function to output on a successful test completion. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SUCCESS_GUNIT_TEMPLATE = """ 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(%s, %s) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "Took %f secs. Started at %f, ended at %f"; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The GUnit test function to output for a disabled test. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DISABLED_GUNIT_TEMPLATE = """ 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(%s, %s) { } 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Timeout constants. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NCTEST_TERMINATE_TIMEOUT_SEC = 60 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NCTEST_KILL_TIMEOUT_SEC = NCTEST_TERMINATE_TIMEOUT_SEC + 2 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BUSY_LOOP_MAX_TIME_SEC = NCTEST_KILL_TIMEOUT_SEC * 2 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ValidateInput(parallelism, sourcefile_path, cflags, resultfile_path): 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Make sure the arguments being passed in are sane.""" 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert parallelism >= 1 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert type(sourcefile_path) is str 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert type(cflags) is str 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert type(resultfile_path) is str 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ParseExpectation(expectation_string): 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Extracts expectation definition from the trailing comment on the ifdef. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) See the comment on NCTEST_CONFIG_RE for examples of the format we are parsing. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expectation_string: A string like "// [r'some_regex']" 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A list of compiled regular expressions indicating all possible valid 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) compiler outputs. If the list is empty, all outputs are considered valid. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert expectation_string is not None 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match = EXTRACT_EXPECTATION_RE.match(expectation_string) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert match 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raw_expectation = ast.literal_eval(match.group(1)) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert type(raw_expectation) is list 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expectation = [] 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for regex_str in raw_expectation: 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert type(regex_str) is str 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expectation.append(re.compile(regex_str)) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return expectation 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractTestConfigs(sourcefile_path): 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Parses the soruce file for test configurations. 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Each no-compile test in the file is separated by an ifdef macro. We scan 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the source file with the NCTEST_CONFIG_RE to find all ifdefs that look like 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) they demark one no-compile test and try to extract the test configuration 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) from that. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sourcefile_path: The path to the source file. 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A list of test configurations. Each test configuration is a dictionary of 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the form: 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { name: 'NCTEST_NAME' 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suite_name: 'SOURCE_FILE_NAME' 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expectations: [re.Pattern, re.Pattern] } 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The |suite_name| is used to generate a pretty gtest output on successful 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) completion of the no compile test. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The compiled regexps in |expectations| define the valid outputs of the 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) compiler. If any one of the listed patterns matches either the stderr or 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stdout from the compilation, and the compilation failed, then the test is 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) considered to have succeeded. If the list is empty, than we ignore the 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) compiler output and just check for failed compilation. If |expectations| 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is actually None, then this specifies a compiler sanity check test, which 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should expect a SUCCESSFUL compilation. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sourcefile = open(sourcefile_path, 'r') 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Convert filename from underscores to CamelCase. 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) words = os.path.splitext(os.path.basename(sourcefile_path))[0].split('_') 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) words = [w.capitalize() for w in words] 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suite_name = 'NoCompile' + ''.join(words) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Start with at least the compiler sanity test. You need to always have one 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # sanity test to show that compiler flags and configuration are not just 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # wrong. Otherwise, having a misconfigured compiler, or an error in the 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # shared portions of the .nc file would cause all tests to erroneously pass. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_configs = [{'name': 'NCTEST_SANITY', 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'suite_name': suite_name, 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'expectations': None}] 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for line in sourcefile: 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) match_result = NCTEST_CONFIG_RE.match(line) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not match_result: 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) groups = match_result.groups() 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Grab the name and remove the defined() predicate if there is one. 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name = groups[0] 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strip_result = STRIP_DEFINED_RE.match(name) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if strip_result: 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name = strip_result.group(1) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Read expectations if there are any. 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_configs.append({'name': name, 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'suite_name': suite_name, 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'expectations': ParseExpectation(groups[1])}) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sourcefile.close() 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return test_configs 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def StartTest(sourcefile_path, cflags, config): 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Start one negative compile test. 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sourcefile_path: The path to the source file. 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cflags: A string with all the CFLAGS to give to gcc. This string will be 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) split by shelex so be careful with escaping. 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) config: A dictionary describing the test. See ExtractTestConfigs 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for a description of the config format. 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A dictionary containing all the information about the started test. The 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fields in the dictionary are as follows: 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 'proc': A subprocess object representing the compiler run. 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'cmdline': The exectued command line. 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'name': The name of the test. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'suite_name': The suite name to use when generating the gunit test 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result. 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'terminate_timeout': The timestamp in seconds since the epoch after 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) which the test should be terminated. 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'kill_timeout': The timestamp in seconds since the epoch after which 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the test should be given a hard kill signal. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'started_at': A timestamp in seconds since the epoch for when this test 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was started. 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'aborted_at': A timestamp in seconds since the epoch for when this test 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was aborted. If the test completed successfully, 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this value is 0. 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'finished_at': A timestamp in seconds since the epoch for when this 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test was successfully complete. If the test is aborted, 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) or running, this value is 0. 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'expectations': A dictionary with the test expectations. See 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ParseExpectation() for the structure. 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # TODO(ajwong): Get the compiler from gyp. 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmdline = ['g++'] 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmdline.extend(shlex.split(cflags)) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name = config['name'] 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expectations = config['expectations'] 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if expectations is not None: 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmdline.append('-D%s' % name) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmdline.extend(['-o', '/dev/null', '-c', '-x', 'c++', sourcefile_path]) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stderr=subprocess.PIPE) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) now = time.time() 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return {'proc': process, 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'cmdline': ' '.join(cmdline), 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'name': name, 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'suite_name': config['suite_name'], 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'terminate_timeout': now + NCTEST_TERMINATE_TIMEOUT_SEC, 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'kill_timeout': now + NCTEST_KILL_TIMEOUT_SEC, 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'started_at': now, 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'aborted_at': 0, 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'finished_at': 0, 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'expectations': expectations} 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def PassTest(resultfile, test): 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Logs the result of a test started by StartTest(), or a disabled test 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) configuration. 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile: File object for .cc file that results are written to. 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test: An instance of the dictionary returned by StartTest(), a 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) configuration from ExtractTestConfigs(). 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The 'started_at' key is only added if a test has been started. 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'started_at' in test: 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile.write(SUCCESS_GUNIT_TEMPLATE % ( 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test['suite_name'], test['name'], 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test['finished_at'] - test['started_at'], 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test['started_at'], test['finished_at'])) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile.write(DISABLED_GUNIT_TEMPLATE % ( 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test['suite_name'], test['name'])) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def FailTest(resultfile, test, error, stdout=None, stderr=None): 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Logs the result of a test started by StartTest() 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile: File object for .cc file that results are written to. 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test: An instance of the dictionary returned by StartTest() 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error: The printable reason for the failure. 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stdout: The test's output to stdout. 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stderr: The test's output to stderr. 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile.write('#error %s Failed: %s\n' % (test['name'], error)) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile.write('#error compile line: %s\n' % test['cmdline']) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if stdout and len(stdout) != 0: 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile.write('#error %s stdout:\n' % test['name']) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for line in stdout.split('\n'): 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile.write('#error %s\n' % line) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if stderr and len(stderr) != 0: 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile.write('#error %s stderr:\n' % test['name']) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for line in stderr.split('\n'): 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile.write('#error %s\n' % line) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile.write('\n') 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def WriteStats(resultfile, suite_name, timings): 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Logs the peformance timings for each stage of the script into a fake test. 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile: File object for .cc file that results are written to. 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suite_name: The name of the GUnit suite this test belongs to. 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timings: Dictionary with timestamps for each stage of the script run. 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats_template = ("Started %f, Ended %f, Total %fs, Extract %fs, " 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Compile %fs, Process %fs") 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) total_secs = timings['results_processed'] - timings['started'] 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extract_secs = timings['extract_done'] - timings['started'] 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) compile_secs = timings['compile_done'] - timings['extract_done'] 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) process_secs = timings['results_processed'] - timings['compile_done'] 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile.write('TEST(%s, Stats) { LOG(INFO) << "%s"; }\n' % ( 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) suite_name, stats_template % ( 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timings['started'], timings['results_processed'], total_secs, 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extract_secs, compile_secs, process_secs))) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ProcessTestResult(resultfile, test): 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Interprets and logs the result of a test started by StartTest() 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile: File object for .cc file that results are written to. 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test: The dictionary from StartTest() to process. 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Snap a copy of stdout and stderr into the test dictionary immediately 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # cause we can only call this once on the Popen object, and lots of stuff 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # below will want access to it. 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) proc = test['proc'] 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (stdout, stderr) = proc.communicate() 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if test['aborted_at'] != 0: 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FailTest(resultfile, test, "Compile timed out. Started %f ended %f." % 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (test['started_at'], test['aborted_at'])) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if test['expectations'] is None: 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # This signals a compiler sanity check test. Fail iff compilation failed. 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if proc.poll() == 0: 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PassTest(resultfile, test) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FailTest(resultfile, test, 'Sanity compile failed. Is compiler borked?', 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stdout, stderr) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif proc.poll() == 0: 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Handle failure due to successful compile. 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FailTest(resultfile, test, 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'Unexpected successful compilation.', 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stdout, stderr) 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Check the output has the right expectations. If there are no 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # expectations, then we just consider the output "matched" by default. 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(test['expectations']) == 0: 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PassTest(resultfile, test) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Otherwise test against all expectations. 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for regexp in test['expectations']: 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (regexp.search(stdout) is not None or 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) regexp.search(stderr) is not None): 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PassTest(resultfile, test) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expectation_str = ', '.join( 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ["r'%s'" % regexp.pattern for regexp in test['expectations']]) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FailTest(resultfile, test, 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'Expectations [%s] did not match output.' % expectation_str, 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stdout, stderr) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CompleteAtLeastOneTest(resultfile, executing_tests): 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Blocks until at least one task is removed from executing_tests. 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This function removes completed tests from executing_tests, logging failures 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) and output. If no tests can be removed, it will enter a poll-loop until one 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test finishes or times out. On a timeout, this function is responsible for 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) terminating the process in the appropriate fashion. 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executing_tests: A dict mapping a string containing the test name to the 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test dict return from StartTest(). 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A list of tests that have finished. 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finished_tests = [] 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) busy_loop_timeout = time.time() + BUSY_LOOP_MAX_TIME_SEC 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while len(finished_tests) == 0: 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If we don't make progress for too long, assume the code is just dead. 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert busy_loop_timeout > time.time() 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Select on the output pipes. 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_set = [] 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for test in executing_tests.values(): 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_set.extend([test['proc'].stderr, test['proc'].stdout]) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = select.select(read_set, [], read_set, NCTEST_TERMINATE_TIMEOUT_SEC) 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Now attempt to process results. 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) now = time.time() 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for test in executing_tests.values(): 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) proc = test['proc'] 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if proc.poll() is not None: 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test['finished_at'] = now 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finished_tests.append(test) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif test['terminate_timeout'] < now: 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) proc.terminate() 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test['aborted_at'] = now 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif test['kill_timeout'] < now: 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) proc.kill() 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test['aborted_at'] = now 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for test in finished_tests: 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) del executing_tests[test['name']] 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return finished_tests 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main(): 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(sys.argv) != 5: 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print ('Usage: %s <parallelism> <sourcefile> <cflags> <resultfile>' % 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.argv[0]) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.exit(1) 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Force us into the "C" locale so the compiler doesn't localize its output. 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # In particular, this stops gcc from using smart quotes when in english UTF-8 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # locales. This makes the expectation writing much easier. 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.environ['LC_ALL'] = 'C' 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parallelism = int(sys.argv[1]) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sourcefile_path = sys.argv[2] 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cflags = sys.argv[3] 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile_path = sys.argv[4] 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timings = {'started': time.time()} 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ValidateInput(parallelism, sourcefile_path, cflags, resultfile_path) 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_configs = ExtractTestConfigs(sourcefile_path) 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timings['extract_done'] = time.time() 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile = open(resultfile_path, 'w') 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile.write(RESULT_FILE_HEADER % sourcefile_path) 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Run the no-compile tests, but ensure we do not run more than |parallelism| 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # tests at once. 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timings['header_written'] = time.time() 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executing_tests = {} 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finished_tests = [] 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for config in test_configs: 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # CompleteAtLeastOneTest blocks until at least one test finishes. Thus, this 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # acts as a semaphore. We cannot use threads + a real semaphore because 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # subprocess forks, which can cause all sorts of hilarity with threads. 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(executing_tests) >= parallelism: 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finished_tests.extend(CompleteAtLeastOneTest(resultfile, executing_tests)) 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if config['name'].startswith('DISABLED_'): 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PassTest(resultfile, config) 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test = StartTest(sourcefile_path, cflags, config) 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert test['name'] not in executing_tests 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) executing_tests[test['name']] = test 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If there are no more test to start, we still need to drain the running 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # ones. 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while len(executing_tests) > 0: 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finished_tests.extend(CompleteAtLeastOneTest(resultfile, executing_tests)) 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timings['compile_done'] = time.time() 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for test in finished_tests: 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessTestResult(resultfile, test) 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) timings['results_processed'] = time.time() 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # We always know at least a sanity test was run. 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteStats(resultfile, finished_tests[0]['suite_name'], timings) 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resultfile.close() 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__': 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) main() 473