Browse Source

test: make test runner multi-arch/mode compatible

Make `python tools/test.py --arch=ia32,x64 --mode=debug,release` work.
The test runner looks for the `node` binary in `out/${arch}.${mode}/`.

Running tools/test.py without --arch makes it use `out/Release/node` or
`out/Debug/node` like before.

This commit removes `test/simple/test-executable-path.js` because the
assumptions it makes about the locations of the debug and release
binaries are now outdated.

PR-URL: https://github.com/node-forward/node/pull/24
Reviewed-By: Fedor Indutny <fedor@indutny.com>
archived-io.js-v0.12
Ben Noordhuis 10 years ago
parent
commit
edaf7af30b
  1. 13
      test/message/testcfg.py
  2. 61
      test/simple/test-executable-path.js
  3. 15
      test/testpy/__init__.py
  4. 12
      test/timers/testcfg.py
  5. 65
      tools/test.py

13
test/message/testcfg.py

@ -34,11 +34,12 @@ FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
class MessageTestCase(test.TestCase): class MessageTestCase(test.TestCase):
def __init__(self, path, file, expected, mode, context, config): def __init__(self, path, file, expected, arch, mode, context, config):
super(MessageTestCase, self).__init__(context, path, mode) super(MessageTestCase, self).__init__(context, path, arch, mode)
self.file = file self.file = file
self.expected = expected self.expected = expected
self.config = config self.config = config
self.arch = arch
self.mode = mode self.mode = mode
def IgnoreLine(self, str): def IgnoreLine(self, str):
@ -92,7 +93,7 @@ class MessageTestCase(test.TestCase):
return self.path[-1] return self.path[-1]
def GetCommand(self): def GetCommand(self):
result = [self.config.context.GetVm(self.mode)] result = [self.config.context.GetVm(self.arch, self.mode)]
source = open(self.file).read() source = open(self.file).read()
flags_match = FLAGS_PATTERN.search(source) flags_match = FLAGS_PATTERN.search(source)
if flags_match: if flags_match:
@ -117,7 +118,7 @@ class MessageTestConfiguration(test.TestConfiguration):
else: else:
return [] return []
def ListTests(self, current_path, path, mode): def ListTests(self, current_path, path, arch, mode):
all_tests = [current_path + [t] for t in self.Ls(self.root)] all_tests = [current_path + [t] for t in self.Ls(self.root)]
result = [] result = []
for test in all_tests: for test in all_tests:
@ -128,8 +129,8 @@ class MessageTestConfiguration(test.TestConfiguration):
if not exists(output_path): if not exists(output_path):
print "Could not find %s" % output_path print "Could not find %s" % output_path
continue continue
result.append(MessageTestCase(test, file_path, output_path, mode, result.append(MessageTestCase(test, file_path, output_path,
self.context, self)) arch, mode, self.context, self))
return result return result
def GetBuildRequirements(self): def GetBuildRequirements(self):

61
test/simple/test-executable-path.js

@ -1,61 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var path = require('path');
var match = false;
var isDebug = process.features.debug;
var isWindows = process.platform === 'win32';
var debugPaths = [path.normalize(path.join(__dirname, '..', '..',
'out', 'Debug', 'node')),
path.normalize(path.join(__dirname, '..', '..',
'Debug', 'node'))];
var defaultPaths = [path.normalize(path.join(__dirname, '..', '..',
'out', 'Release', 'node')),
path.normalize(path.join(__dirname, '..', '..',
'Release', 'node'))];
console.error('debugPaths: ' + debugPaths);
console.error('defaultPaths: ' + defaultPaths);
console.error('process.execPath: ' + process.execPath);
function pathStartsWith(a, b) {
if (isWindows)
return (a.toLowerCase().indexOf(b.toLowerCase()) == 0);
else
return (a.indexOf(b) == 0);
}
if (isDebug) {
debugPaths.forEach(function(path) {
match = match || pathStartsWith(process.execPath, path);
});
} else {
defaultPaths.forEach(function(path) {
match = match || pathStartsWith(process.execPath, path);
});
}
assert.ok(match);

15
test/testpy/__init__.py

@ -41,10 +41,11 @@ FILES_PATTERN = re.compile(r"//\s+Files:(.*)")
class SimpleTestCase(test.TestCase): class SimpleTestCase(test.TestCase):
def __init__(self, path, file, mode, context, config, additional=[]): def __init__(self, path, file, arch, mode, context, config, additional=[]):
super(SimpleTestCase, self).__init__(context, path, mode) super(SimpleTestCase, self).__init__(context, path, arch, mode)
self.file = file self.file = file
self.config = config self.config = config
self.arch = arch
self.mode = mode self.mode = mode
self.tmpdir = join(dirname(self.config.root), 'tmp') self.tmpdir = join(dirname(self.config.root), 'tmp')
self.additional_flags = additional self.additional_flags = additional
@ -82,7 +83,7 @@ class SimpleTestCase(test.TestCase):
return self.path[-1] return self.path[-1]
def GetCommand(self): def GetCommand(self):
result = [self.config.context.GetVm(self.mode)] result = [self.config.context.GetVm(self.arch, self.mode)]
source = open(self.file).read() source = open(self.file).read()
flags_match = FLAGS_PATTERN.search(source) flags_match = FLAGS_PATTERN.search(source)
if flags_match: if flags_match:
@ -117,14 +118,14 @@ class SimpleTestConfiguration(test.TestConfiguration):
return name.startswith('test-') and name.endswith('.js') return name.startswith('test-') and name.endswith('.js')
return [f[:-3] for f in os.listdir(path) if SelectTest(f)] return [f[:-3] for f in os.listdir(path) if SelectTest(f)]
def ListTests(self, current_path, path, mode): def ListTests(self, current_path, path, arch, mode):
all_tests = [current_path + [t] for t in self.Ls(join(self.root))] all_tests = [current_path + [t] for t in self.Ls(join(self.root))]
result = [] result = []
for test in all_tests: for test in all_tests:
if self.Contains(path, test): if self.Contains(path, test):
file_path = join(self.root, reduce(join, test[1:], "") + ".js") file_path = join(self.root, reduce(join, test[1:], "") + ".js")
result.append(SimpleTestCase(test, file_path, mode, self.context, self, result.append(SimpleTestCase(test, file_path, arch, mode, self.context,
self.additional_flags)) self, self.additional_flags))
return result return result
def GetBuildRequirements(self): def GetBuildRequirements(self):
@ -151,7 +152,7 @@ class AddonTestConfiguration(SimpleTestConfiguration):
result.append([subpath, f[:-3]]) result.append([subpath, f[:-3]])
return result return result
def ListTests(self, current_path, path, mode): def ListTests(self, current_path, path, arch, mode):
all_tests = [current_path + t for t in self.Ls(join(self.root))] all_tests = [current_path + t for t in self.Ls(join(self.root))]
result = [] result = []
for test in all_tests: for test in all_tests:

12
test/timers/testcfg.py

@ -40,10 +40,11 @@ FAKETIME_BIN_PATH = os.path.join("tools", "faketime", "src", "faketime")
class TimersTestCase(test.TestCase): class TimersTestCase(test.TestCase):
def __init__(self, path, file, mode, context, config): def __init__(self, path, file, arch, mode, context, config):
super(TimersTestCase, self).__init__(context, path, mode) super(TimersTestCase, self).__init__(context, path, arch, mode)
self.file = file self.file = file
self.config = config self.config = config
self.arch = arch
self.mode = mode self.mode = mode
def GetLabel(self): def GetLabel(self):
@ -60,7 +61,7 @@ class TimersTestCase(test.TestCase):
if faketime_flags_match: if faketime_flags_match:
result += shlex.split(faketime_flags_match.group(1).strip()) result += shlex.split(faketime_flags_match.group(1).strip())
result += [self.config.context.GetVm(self.mode)] result += [self.config.context.GetVm(self.arch, self.mode)]
result += [self.file] result += [self.file]
return result return result
@ -79,13 +80,14 @@ class TimersTestConfiguration(test.TestConfiguration):
return name.startswith('test-') and name.endswith('.js') return name.startswith('test-') and name.endswith('.js')
return [f[:-3] for f in os.listdir(path) if SelectTest(f)] return [f[:-3] for f in os.listdir(path) if SelectTest(f)]
def ListTests(self, current_path, path, mode): def ListTests(self, current_path, path, arch, mode):
all_tests = [current_path + [t] for t in self.Ls(join(self.root))] all_tests = [current_path + [t] for t in self.Ls(join(self.root))]
result = [] result = []
for test in all_tests: for test in all_tests:
if self.Contains(path, test): if self.Contains(path, test):
file_path = join(self.root, reduce(join, test[1:], "") + ".js") file_path = join(self.root, reduce(join, test[1:], "") + ".js")
result.append(TimersTestCase(test, file_path, mode, self.context, self)) result.append(TimersTestCase(test, file_path, arch, mode,
self.context, self))
return result return result
def GetBuildRequirements(self): def GetBuildRequirements(self):

65
tools/test.py

@ -368,10 +368,11 @@ class CommandOutput(object):
class TestCase(object): class TestCase(object):
def __init__(self, context, path, mode): def __init__(self, context, path, arch, mode):
self.path = path self.path = path
self.context = context self.context = context
self.duration = None self.duration = None
self.arch = arch
self.mode = mode self.mode = mode
def IsNegative(self): def IsNegative(self):
@ -644,9 +645,10 @@ class TestRepository(TestSuite):
def GetBuildRequirements(self, path, context): def GetBuildRequirements(self, path, context):
return self.GetConfiguration(context).GetBuildRequirements() return self.GetConfiguration(context).GetBuildRequirements()
def AddTestsToList(self, result, current_path, path, context, mode): def AddTestsToList(self, result, current_path, path, context, arch, mode):
for v in VARIANT_FLAGS: for v in VARIANT_FLAGS:
tests = self.GetConfiguration(context).ListTests(current_path, path, mode) tests = self.GetConfiguration(context).ListTests(current_path, path,
arch, mode)
for t in tests: t.variant_flags = v for t in tests: t.variant_flags = v
result += tests result += tests
@ -669,14 +671,14 @@ class LiteralTestSuite(TestSuite):
result += test.GetBuildRequirements(rest, context) result += test.GetBuildRequirements(rest, context)
return result return result
def ListTests(self, current_path, path, context, mode): def ListTests(self, current_path, path, context, arch, mode):
(name, rest) = CarCdr(path) (name, rest) = CarCdr(path)
result = [ ] result = [ ]
for test in self.tests: for test in self.tests:
test_name = test.GetName() test_name = test.GetName()
if not name or name.match(test_name): if not name or name.match(test_name):
full_path = current_path + [test_name] full_path = current_path + [test_name]
test.AddTestsToList(result, full_path, path, context, mode) test.AddTestsToList(result, full_path, path, context, arch, mode)
result.sort(cmp=lambda a, b: cmp(a.GetName(), b.GetName())) result.sort(cmp=lambda a, b: cmp(a.GetName(), b.GetName()))
return result return result
@ -708,11 +710,11 @@ class Context(object):
self.suppress_dialogs = suppress_dialogs self.suppress_dialogs = suppress_dialogs
self.store_unexpected_output = store_unexpected_output self.store_unexpected_output = store_unexpected_output
def GetVm(self, mode): def GetVm(self, arch, mode):
if mode == 'debug': if arch == 'none':
name = 'out/Debug/node' name = 'out/Debug/node' if mode == 'debug' else 'out/Release/node'
else: else:
name = 'out/Release/node' name = 'out/%s.%s/node' % (arch, mode)
# Currently GYP does not support output_dir for MSVS. # Currently GYP does not support output_dir for MSVS.
# http://code.google.com/p/gyp/issues/detail?id=40 # http://code.google.com/p/gyp/issues/detail?id=40
@ -729,9 +731,6 @@ class Context(object):
return name return name
def GetVmCommand(self, testcase, mode):
return [self.GetVm(mode)] + self.GetVmFlags(testcase, mode)
def GetVmFlags(self, testcase, mode): def GetVmFlags(self, testcase, mode):
return testcase.variant_flags + FLAGS[mode] return testcase.variant_flags + FLAGS[mode]
@ -1203,8 +1202,6 @@ def BuildOptions():
default='none') default='none')
result.add_option("--snapshot", help="Run the tests with snapshot turned on", result.add_option("--snapshot", help="Run the tests with snapshot turned on",
default=False, action="store_true") default=False, action="store_true")
result.add_option("--simulator", help="Run tests with architecture simulator",
default='none')
result.add_option("--special-command", default=None) result.add_option("--special-command", default=None)
result.add_option("--use-http1", help="Pass --use-http1 switch to node", result.add_option("--use-http1", help="Pass --use-http1 switch to node",
default=False, action="store_true") default=False, action="store_true")
@ -1235,29 +1232,8 @@ def BuildOptions():
def ProcessOptions(options): def ProcessOptions(options):
global VERBOSE global VERBOSE
VERBOSE = options.verbose VERBOSE = options.verbose
options.arch = options.arch.split(',')
options.mode = options.mode.split(',') options.mode = options.mode.split(',')
for mode in options.mode:
if not mode in ['debug', 'release']:
print "Unknown mode %s" % mode
return False
if options.simulator != 'none':
# Simulator argument was set. Make sure arch and simulator agree.
if options.simulator != options.arch:
if options.arch == 'none':
options.arch = options.simulator
else:
print "Architecture %s does not match sim %s" %(options.arch, options.simulator)
return False
# Ensure that the simulator argument is handed down to scons.
options.scons_flags.append("simulator=" + options.simulator)
else:
# If options.arch is not set by the command line and no simulator setting
# was found, set the arch to the guess.
if options.arch == 'none':
options.arch = ARCH_GUESS
options.scons_flags.append("arch=" + options.arch)
if options.snapshot:
options.scons_flags.append("snapshot=on")
return True return True
@ -1415,23 +1391,26 @@ def Main():
unclassified_tests = [ ] unclassified_tests = [ ]
globally_unused_rules = None globally_unused_rules = None
for path in paths: for path in paths:
for arch in options.arch:
for mode in options.mode: for mode in options.mode:
if not exists(context.GetVm(mode)): vm = context.GetVm(arch, mode)
print "Can't find shell executable: '%s'" % context.GetVm(mode) if not exists(vm):
print "Can't find shell executable: '%s'" % vm
continue continue
env = { env = {
'mode': mode, 'mode': mode,
'system': utils.GuessOS(), 'system': utils.GuessOS(),
'arch': options.arch, 'arch': arch,
'simulator': options.simulator
} }
test_list = root.ListTests([], path, context, mode) test_list = root.ListTests([], path, context, arch, mode)
unclassified_tests += test_list unclassified_tests += test_list
(cases, unused_rules, all_outcomes) = config.ClassifyTests(test_list, env) (cases, unused_rules, all_outcomes) = (
config.ClassifyTests(test_list, env))
if globally_unused_rules is None: if globally_unused_rules is None:
globally_unused_rules = set(unused_rules) globally_unused_rules = set(unused_rules)
else: else:
globally_unused_rules = globally_unused_rules.intersection(unused_rules) globally_unused_rules = (
globally_unused_rules.intersection(unused_rules))
all_cases += cases all_cases += cases
all_unused.append(unused_rules) all_unused.append(unused_rules)

Loading…
Cancel
Save