From 3dc19387981b88d9f5eb9a3e78d2ce4266c42b8c Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 2 Jun 2009 14:24:57 +0000 Subject: first commit of new messaging API and test harness git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@781044 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 450 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 450 insertions(+) create mode 100755 qpid/python/qpid-python-test (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test new file mode 100755 index 0000000000..287637d7a0 --- /dev/null +++ b/qpid/python/qpid-python-test @@ -0,0 +1,450 @@ +#!/usr/bin/env python +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import optparse, os, sys, logging, traceback, types +from fnmatch import fnmatchcase as match +from getopt import GetoptError +from logging import getLogger, StreamHandler, Formatter, Filter, \ + WARN, DEBUG, ERROR +from qpid.util import URL + +levels = { + "DEBUG": DEBUG, + "WARN": WARN, + "ERROR": ERROR + } + +sorted_levels = [(v, k) for k, v in levels.items()] +sorted_levels.sort() +sorted_levels = [v for k, v in sorted_levels] + +parser = optparse.OptionParser(usage="usage: %prog [options] PATTERN ...", + description="Run tests matching the specified PATTERNs.") +parser.add_option("-l", "--list", action="store_true", default=False, + help="list tests instead of executing them") +parser.add_option("-b", "--broker", default="localhost", + help="run tests against BROKER (default %default)") +parser.add_option("-f", "--log-file", metavar="FILE", help="log output to FILE") +parser.add_option("-v", "--log-level", metavar="LEVEL", default="WARN", + help="only display log messages of LEVEL or higher severity: " + "%s (default %%default)" % ", ".join(sorted_levels)) +parser.add_option("-c", "--log-category", metavar="CATEGORY", action="append", + dest="log_categories", default=[], + help="log only categories matching CATEGORY pattern") +parser.add_option("-i", "--ignore", action="append", default=[], + help="ignore tests matching IGNORE pattern") +parser.add_option("-I", "--ignore-file", metavar="IFILE", action="append", + default=[], + help="ignore tests matching patterns in IFILE") + +class Config: + + def __init__(self): + self.broker = URL("localhost") + self.work = None + self.log_file = None + self.log_level = WARN + self.log_categories = [] + +opts, args = parser.parse_args() + +includes = [] +excludes = ["*__*__"] +config = Config() +list_only = opts.list +config.broker = URL(opts.broker) +config.log_file = opts.log_file +config.log_level = levels[opts.log_level.upper()] +config.log_categories = opts.log_categories +excludes.extend([v.strip() for v in opts.ignore]) +for v in opts.ignore_file: + f = open(v) + for line in f: + line = line.strip() + if line.startswith("#"): + continue + excludes.append(line) + f.close() + +for a in args: + includes.append(a.strip()) + +if not includes: + includes.append("*") + +def included(path): + for p in excludes: + if match(path, p): + return False + for p in includes: + if match(path, p): + return True + return False + +def vt100_attrs(*attrs): + return "\x1B[%sm" % ";".join(map(str, attrs)) + +vt100_reset = vt100_attrs(0) + +KEYWORDS = {"pass": (32,), + "fail": (31,), + "start": (34,), + "total": (34,)} + +COLORIZE = sys.stdout.isatty() + +def colorize_word(word, text=None): + if text is None: + text = word + return colorize(text, *KEYWORDS.get(word, ())) + +def colorize(text, *attrs): + if attrs and COLORIZE: + return "%s%s%s" % (vt100_attrs(*attrs), text, vt100_reset) + else: + return text + +def indent(text): + lines = text.split("\n") + return " %s" % "\n ".join(lines) + +from qpid.testlib import testrunner +testrunner.setBroker(str(config.broker)) + +class Interceptor: + + def __init__(self): + self.newline = False + self.indent = False + self.passthrough = True + self.dirty = False + self.last = None + + def begin(self): + self.newline = True + self.indent = True + self.passthrough = False + self.dirty = False + self.last = None + + def reset(self): + self.newline = False + self.indent = False + self.passthrough = True + +class StreamWrapper: + + def __init__(self, interceptor, stream, prefix=" "): + self.interceptor = interceptor + self.stream = stream + self.prefix = prefix + + def isatty(self): + return self.stream.isatty() + + def write(self, s): + if self.interceptor.passthrough: + self.stream.write(s) + return + + if s: + self.interceptor.dirty = True + + if self.interceptor.newline: + self.interceptor.newline = False + self.stream.write(" %s\n" % colorize_word("start")) + self.interceptor.indent = True + if self.interceptor.indent: + self.stream.write(self.prefix) + if s.endswith("\n"): + s = s.replace("\n", "\n%s" % self.prefix)[:-2] + self.interceptor.indent = True + else: + s = s.replace("\n", "\n%s" % self.prefix) + self.interceptor.indent = False + self.stream.write(s) + + if s: + self.interceptor.last = s[-1] + + def flush(self): + self.stream.flush() + +interceptor = Interceptor() + +out_wrp = StreamWrapper(interceptor, sys.stdout) +err_wrp = StreamWrapper(interceptor, sys.stderr) + +out = sys.stdout +err = sys.stderr +sys.stdout = out_wrp +sys.stderr = err_wrp + +class PatternFilter(Filter): + + def __init__(self, *patterns): + Filter.__init__(self, patterns) + self.patterns = patterns + + def filter(self, record): + if not self.patterns: + return True + for p in self.patterns: + if match(record.name, p): + return True + return False + +root = getLogger() +handler = StreamHandler(sys.stdout) +filter = PatternFilter(*config.log_categories) +handler.addFilter(filter) +handler.setFormatter(Formatter("%(asctime)s %(levelname)s %(message)s")) +root.addHandler(handler) +root.setLevel(WARN) + +log = getLogger("qpid.test") + +class Runner: + + def __init__(self): + self.exceptions = [] + + def passed(self): + return not self.exceptions + + def failed(self): + return self.exceptions + + def run(self, name, phase): + try: + phase() + except KeyboardInterrupt: + raise + except: + self.exceptions.append((name, sys.exc_info())) + + def status(self): + if self.passed(): + return "pass" + else: + return "fail" + + def print_exceptions(self): + for name, info in self.exceptions: + print "Error during %s:" % name + print indent("".join(traceback.format_exception(*info))).rstrip() + +def run_test(name, test, config): + patterns = filter.patterns + level = root.level + filter.patterns = config.log_categories + root.setLevel(config.log_level) + + parts = name.split(".") + line = None + output = "" + for part in parts: + if line: + if len(line) + len(part) >= 71: + output += "%s. \\\n" % line + line = " %s" % part + else: + line = "%s.%s" % (line, part) + else: + line = part + + if line: + output += "%s %s" % (line, ((72 - len(line))*".")) + sys.stdout.write(output) + sys.stdout.flush() + interceptor.begin() + try: + runner = test() + finally: + interceptor.reset() + if interceptor.dirty: + if interceptor.last != "\n": + sys.stdout.write("\n") + sys.stdout.write(output) + print " %s" % colorize_word(runner.status()) + if runner.failed(): + runner.print_exceptions() + root.setLevel(level) + filter.patterns = patterns + return runner.passed() + +class FunctionTest: + + def __init__(self, test): + self.test = test + + def name(self): + return "%s.%s" % (self.test.__module__, self.test.__name__) + + def run(self): + return run_test(self.name(), self._run, config) + + def _run(self): + runner = Runner() + runner.run("test", lambda: self.test(config)) + return runner + + def __repr__(self): + return "FunctionTest(%r)" % self.test + +class MethodTest: + + def __init__(self, cls, method): + self.cls = cls + self.method = method + + def name(self): + return "%s.%s.%s" % (self.cls.__module__, self.cls.__name__, self.method) + + def run(self): + return run_test(self.name(), self._run, config) + + def _run(self): + runner = Runner() + inst = self.cls(self.method) + test = getattr(inst, self.method) + + if hasattr(inst, "configure"): + runner.run("configure", lambda: inst.configure(config)) + if runner.failed(): return runner + if hasattr(inst, "setUp"): + runner.run("setup", inst.setUp) + if runner.failed(): return runner + elif hasattr(inst, "setup"): + runner.run("setup", inst.setup) + if runner.failed(): return runner + + runner.run("test", test) + + if hasattr(inst, "tearDown"): + runner.run("teardown", inst.tearDown) + elif hasattr(inst, "teardown"): + runner.run("teardown", inst.teardown) + + return runner + + def __repr__(self): + return "MethodTest(%r, %r)" % (self.cls, self.method) + +class PatternMatcher: + + def __init__(self, *patterns): + self.patterns = patterns + + def matches(self, name): + for p in self.patterns: + if match(name, p): + return True + return False + +class FunctionScanner(PatternMatcher): + + def inspect(self, obj): + return type(obj) == types.FunctionType and self.matches(name) + + def descend(self, func): + return; yield + + def extract(self, func): + yield FunctionTest(func) + +class ClassScanner(PatternMatcher): + + def inspect(self, obj): + return type(obj) in (types.ClassType, types.TypeType) and self.matches(obj.__name__) + + def descend(self, cls): + return; yield + + def extract(self, cls): + names = dir(cls) + names.sort() + for name in names: + obj = getattr(cls, name) + t = type(obj) + if t == types.MethodType and name.startswith("test"): + yield MethodTest(cls, name) + +class ModuleScanner: + + def inspect(self, obj): + return type(obj) == types.ModuleType + + def descend(self, obj): + names = dir(obj) + names.sort() + for name in names: + yield getattr(obj, name) + + def extract(self, obj): + return; yield + +class Harness: + + def __init__(self): + self.scanners = [ + ModuleScanner(), + ClassScanner("*Test", "*Tests", "*TestCase"), + FunctionScanner("test_*") + ] + self.tests = [] + self.scanned = [] + + def scan(self, *roots): + objects = list(roots) + + while objects: + obj = objects.pop(0) + for s in self.scanners: + if s.inspect(obj): + self.tests.extend(s.extract(obj)) + for child in s.descend(obj): + if not (child in self.scanned or child in objects): + objects.append(child) + self.scanned.append(obj) + +modules = "qpid.tests", "tests", "tests_0-10" +h = Harness() +for name in modules: + m = __import__(name, fromlist=["dummy"]) + h.scan(m) + +filtered = [t for t in h.tests if included(t.name())] +passed = 0 +failed = 0 +for t in filtered: + if list_only: + print t.name() + else: + if t.run(): + passed += 1 + else: + failed += 1 + +if not list_only: + print colorize("Totals:", 1), \ + colorize_word("total", "%s tests" % len(filtered)) + ",", \ + colorize_word("pass", "%s passed" % passed) + ",", \ + colorize_word("fail" if failed else "pass", "%s failed" % failed) -- cgit v1.2.1 From 007d1f6de841dde064df0f0eac9f35f88a540ccb Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 2 Jun 2009 15:17:42 +0000 Subject: modified empty generator idiom to work on python 2.4 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@781056 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index 287637d7a0..1e342386cd 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -365,7 +365,8 @@ class FunctionScanner(PatternMatcher): return type(obj) == types.FunctionType and self.matches(name) def descend(self, func): - return; yield + # the None is required for older versions of python + return; yield None def extract(self, func): yield FunctionTest(func) @@ -376,7 +377,8 @@ class ClassScanner(PatternMatcher): return type(obj) in (types.ClassType, types.TypeType) and self.matches(obj.__name__) def descend(self, cls): - return; yield + # the None is required for older versions of python + return; yield None def extract(self, cls): names = dir(cls) @@ -399,7 +401,8 @@ class ModuleScanner: yield getattr(obj, name) def extract(self, obj): - return; yield + # the None is required for older versions of python + return; yield None class Harness: -- cgit v1.2.1 From 1274bc5a6c6cc55604fc248417ddb66b1e29986c Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 2 Jun 2009 15:22:34 +0000 Subject: removed turnary if git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@781058 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index 1e342386cd..edfce21fec 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -447,7 +447,11 @@ for t in filtered: failed += 1 if not list_only: + if failed: + outcome = "fail" + else: + outcome = "pass" print colorize("Totals:", 1), \ colorize_word("total", "%s tests" % len(filtered)) + ",", \ colorize_word("pass", "%s passed" % passed) + ",", \ - colorize_word("fail" if failed else "pass", "%s failed" % failed) + colorize_word(outcome, "%s failed" % failed) -- cgit v1.2.1 From 6a4cfc28039f2ac0254b04f6417cd54ba7f83663 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 2 Jun 2009 15:28:27 +0000 Subject: removed keyword arg from __import__ call for python 2.4 git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@781059 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index edfce21fec..b893d3698f 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -431,7 +431,7 @@ class Harness: modules = "qpid.tests", "tests", "tests_0-10" h = Harness() for name in modules: - m = __import__(name, fromlist=["dummy"]) + m = __import__(name, None, None, ["dummy"]) h.scan(m) filtered = [t for t in h.tests if included(t.name())] -- cgit v1.2.1 From b40a5efb567758c0aef5358de3c9ec88a5e5c7ab Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 2 Jun 2009 17:28:12 +0000 Subject: detect the terminal width when possible git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@781087 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index b893d3698f..d02f2ac6cc 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -18,7 +18,7 @@ # under the License. # -import optparse, os, sys, logging, traceback, types +import fcntl, logging, optparse, os, struct, sys, termios, traceback, types from fnmatch import fnmatchcase as match from getopt import GetoptError from logging import getLogger, StreamHandler, Formatter, Filter, \ @@ -98,6 +98,18 @@ def included(path): return True return False +def width(): + if sys.stdout.isatty(): + s = struct.pack("HHHH", 0, 0, 0, 0) + fd_stdout = sys.stdout.fileno() + x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s) + rows, cols, xpx, ypx = struct.unpack("HHHH", x) + return cols + else: + return 80 + +WIDTH = width() + def vt100_attrs(*attrs): return "\x1B[%sm" % ";".join(map(str, attrs)) @@ -156,6 +168,9 @@ class StreamWrapper: self.stream = stream self.prefix = prefix + def fileno(self): + return self.stream.fileno() + def isatty(self): return self.stream.isatty() @@ -251,6 +266,8 @@ class Runner: print "Error during %s:" % name print indent("".join(traceback.format_exception(*info))).rstrip() +ST_WIDTH = 8 + def run_test(name, test, config): patterns = filter.patterns level = root.level @@ -262,7 +279,7 @@ def run_test(name, test, config): output = "" for part in parts: if line: - if len(line) + len(part) >= 71: + if len(line) + len(part) >= (WIDTH - ST_WIDTH - 1): output += "%s. \\\n" % line line = " %s" % part else: @@ -271,7 +288,7 @@ def run_test(name, test, config): line = part if line: - output += "%s %s" % (line, ((72 - len(line))*".")) + output += "%s %s" % (line, (((WIDTH - ST_WIDTH) - len(line))*".")) sys.stdout.write(output) sys.stdout.flush() interceptor.begin() -- cgit v1.2.1 From fa5e48e323ec34e10674f7419287470e35dbfff1 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 2 Jun 2009 17:41:11 +0000 Subject: added a signal handler for terminal resize git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@781091 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index d02f2ac6cc..8d56311dbe 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -110,6 +110,13 @@ def width(): WIDTH = width() +def resize(sig, frm): + global WIDTH + WIDTH = width() + +import signal +signal.signal(signal.SIGWINCH, resize) + def vt100_attrs(*attrs): return "\x1B[%sm" % ";".join(map(str, attrs)) -- cgit v1.2.1 From 661942f75301b0f6fb2d1efa26f9403e80bce2d8 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 2 Jun 2009 22:19:07 +0000 Subject: added defines to the test harness and made the delay used by the tests configurable git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@781187 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index 8d56311dbe..bdad3f3688 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -53,12 +53,14 @@ parser.add_option("-i", "--ignore", action="append", default=[], parser.add_option("-I", "--ignore-file", metavar="IFILE", action="append", default=[], help="ignore tests matching patterns in IFILE") +parser.add_option("-D", "--define", metavar="DEFINE", dest="defines", + action="append", default=[], help="define test parameters") class Config: def __init__(self): self.broker = URL("localhost") - self.work = None + self.defines = {} self.log_file = None self.log_level = WARN self.log_categories = [] @@ -70,6 +72,14 @@ excludes = ["*__*__"] config = Config() list_only = opts.list config.broker = URL(opts.broker) +for d in opts.defines: + try: + idx = d.index("=") + name = d[:idx] + value = d[idx+1:] + config.defines[name] = value + except ValueError: + config.defines[d] = None config.log_file = opts.log_file config.log_level = levels[opts.log_level.upper()] config.log_categories = opts.log_categories -- cgit v1.2.1 From 1687704cc70b66166edf20ac38e9b7ad666c3339 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Fri, 12 Jun 2009 15:26:54 +0000 Subject: added halt-on-error option and display ignored tests git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@784159 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index bdad3f3688..3bf0e6ccce 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -18,6 +18,8 @@ # under the License. # +# TODO: summarize, test harness preconditions (e.g. broker is alive) + import fcntl, logging, optparse, os, struct, sys, termios, traceback, types from fnmatch import fnmatchcase as match from getopt import GetoptError @@ -53,6 +55,8 @@ parser.add_option("-i", "--ignore", action="append", default=[], parser.add_option("-I", "--ignore-file", metavar="IFILE", action="append", default=[], help="ignore tests matching patterns in IFILE") +parser.add_option("-H", "--halt-on-error", action="store_true", default=False, + dest="hoe", help="halt if an error is encountered") parser.add_option("-D", "--define", metavar="DEFINE", dest="defines", action="append", default=[], help="define test parameters") @@ -99,10 +103,15 @@ for a in args: if not includes: includes.append("*") -def included(path): +def is_ignored(path): for p in excludes: if match(path, p): - return False + return True + return False + +def is_included(path): + if is_ignored(path): + return False for p in includes: if match(path, p): return True @@ -135,7 +144,9 @@ vt100_reset = vt100_attrs(0) KEYWORDS = {"pass": (32,), "fail": (31,), "start": (34,), - "total": (34,)} + "total": (34,), + "ignored": (33,), + "selected": (34,)} COLORIZE = sys.stdout.isatty() @@ -468,7 +479,10 @@ for name in modules: m = __import__(name, None, None, ["dummy"]) h.scan(m) -filtered = [t for t in h.tests if included(t.name())] +filtered = [t for t in h.tests if is_included(t.name())] +ignored = [t for t in h.tests if is_ignored(t.name())] +total = len(filtered) + len(ignored) + passed = 0 failed = 0 for t in filtered: @@ -479,13 +493,26 @@ for t in filtered: passed += 1 else: failed += 1 + if opts.hoe: + break + +run = passed + failed if not list_only: if failed: outcome = "fail" else: outcome = "pass" + if ignored: + ign = "ignored" + else: + ign = "pass" print colorize("Totals:", 1), \ - colorize_word("total", "%s tests" % len(filtered)) + ",", \ + colorize_word("total", "%s tests" % total) + ",", \ colorize_word("pass", "%s passed" % passed) + ",", \ - colorize_word(outcome, "%s failed" % failed) + colorize_word(ign, "%s ignored" % len(ignored)) + ",", \ + colorize_word(outcome, "%s failed" % failed), + if opts.hoe and failed > 0: + print " -- (halted after %s)" % run + else: + print -- cgit v1.2.1 From e419dd6f187b5d135701f17f4b4382ece95068e5 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 11 Aug 2009 15:40:19 +0000 Subject: - removed old and redundent tests - removed old test harness in favor of qpid-python-test - modified qpid-python-test to support "skipped" tests, these are tests that failed due to an anticipated environmental reason such as the broker is not running or it is the wrong version - modified the qpid-python-test harness to exit with appropriate error codes based on the test results - modified the python clients to report version mismatches rather than framing errors - made qpid_config provide variables for 0-8, 0-9, and 0-10 versions of the spec - modified the 0-10 client to directly codegen classes - added new 0-10 framing layer based on push parsing rather than pull parsing - added numerous framing tests git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803168 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 76 +++++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 19 deletions(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index 3bf0e6ccce..b9e69c782e 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -25,6 +25,7 @@ from fnmatch import fnmatchcase as match from getopt import GetoptError from logging import getLogger, StreamHandler, Formatter, Filter, \ WARN, DEBUG, ERROR +from qpid.harness import Skipped from qpid.util import URL levels = { @@ -101,7 +102,7 @@ for a in args: includes.append(a.strip()) if not includes: - includes.append("*") + includes.extend(["qpid.tests.*", "tests.*", "tests_0-10.*"]) def is_ignored(path): for p in excludes: @@ -142,6 +143,7 @@ def vt100_attrs(*attrs): vt100_reset = vt100_attrs(0) KEYWORDS = {"pass": (32,), + "skip": (33,), "fail": (31,), "start": (34,), "total": (34,), @@ -165,9 +167,6 @@ def indent(text): lines = text.split("\n") return " %s" % "\n ".join(lines) -from qpid.testlib import testrunner -testrunner.setBroker(str(config.broker)) - class Interceptor: def __init__(self): @@ -264,16 +263,27 @@ root.setLevel(WARN) log = getLogger("qpid.test") +PASS = "pass" +SKIP = "skip" +FAIL = "fail" + class Runner: def __init__(self): self.exceptions = [] + self.skip = False def passed(self): return not self.exceptions + def skipped(self): + return self.skip + def failed(self): - return self.exceptions + return self.exceptions and not self.skip + + def halt(self): + return self.exceptions or self.skip def run(self, name, phase): try: @@ -281,18 +291,28 @@ class Runner: except KeyboardInterrupt: raise except: - self.exceptions.append((name, sys.exc_info())) + exi = sys.exc_info() + if issubclass(exi[0], Skipped): + self.skip = True + self.exceptions.append((name, exi)) def status(self): if self.passed(): - return "pass" + return PASS + elif self.skipped(): + return SKIP + elif self.failed(): + return FAIL else: - return "fail" + return None def print_exceptions(self): for name, info in self.exceptions: - print "Error during %s:" % name - print indent("".join(traceback.format_exception(*info))).rstrip() + if issubclass(info[0], Skipped): + print indent("".join(traceback.format_exception_only(*info[:2]))).rstrip() + else: + print "Error during %s:" % name + print indent("".join(traceback.format_exception(*info))).rstrip() ST_WIDTH = 8 @@ -329,11 +349,11 @@ def run_test(name, test, config): sys.stdout.write("\n") sys.stdout.write(output) print " %s" % colorize_word(runner.status()) - if runner.failed(): + if runner.failed() or runner.skipped(): runner.print_exceptions() root.setLevel(level) filter.patterns = patterns - return runner.passed() + return runner.status() class FunctionTest: @@ -373,13 +393,13 @@ class MethodTest: if hasattr(inst, "configure"): runner.run("configure", lambda: inst.configure(config)) - if runner.failed(): return runner + if runner.halt(): return runner if hasattr(inst, "setUp"): runner.run("setup", inst.setUp) - if runner.failed(): return runner + if runner.halt(): return runner elif hasattr(inst, "setup"): runner.run("setup", inst.setup) - if runner.failed(): return runner + if runner.halt(): return runner runner.run("test", test) @@ -473,7 +493,7 @@ class Harness: objects.append(child) self.scanned.append(obj) -modules = "qpid.tests", "tests", "tests_0-10" +modules = "qpid.tests", "tests", "tests_0-8", "tests_0-9", "tests_0-10" h = Harness() for name in modules: m = __import__(name, None, None, ["dummy"]) @@ -485,13 +505,17 @@ total = len(filtered) + len(ignored) passed = 0 failed = 0 +skipped = 0 for t in filtered: if list_only: print t.name() else: - if t.run(): + st = t.run() + if st == PASS: passed += 1 - else: + elif st == SKIP: + skipped += 1 + elif st == FAIL: failed += 1 if opts.hoe: break @@ -499,6 +523,10 @@ for t in filtered: run = passed + failed if not list_only: + if passed: + _pass = "pass" + else: + _pass = "fail" if failed: outcome = "fail" else: @@ -507,12 +535,22 @@ if not list_only: ign = "ignored" else: ign = "pass" + if skipped: + skip = "skip" + else: + skip = "pass" print colorize("Totals:", 1), \ colorize_word("total", "%s tests" % total) + ",", \ - colorize_word("pass", "%s passed" % passed) + ",", \ + colorize_word(_pass, "%s passed" % passed) + ",", \ + colorize_word(skip, "%s skipped" % skipped) + ",", \ colorize_word(ign, "%s ignored" % len(ignored)) + ",", \ colorize_word(outcome, "%s failed" % failed), if opts.hoe and failed > 0: print " -- (halted after %s)" % run else: print + +if failed or skipped: + sys.exit(1) +else: + sys.exit(0) -- cgit v1.2.1 From 04213eae5ea065238c99495fe19ac109857f4c1f Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 11 Aug 2009 19:47:34 +0000 Subject: added support for specify the modules searched for tests from the command line git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803263 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index b9e69c782e..68f9622710 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -51,6 +51,8 @@ parser.add_option("-v", "--log-level", metavar="LEVEL", default="WARN", parser.add_option("-c", "--log-category", metavar="CATEGORY", action="append", dest="log_categories", default=[], help="log only categories matching CATEGORY pattern") +parser.add_option("-m", "--module", action="append", default=[], + dest="modules", help="add module to test search path") parser.add_option("-i", "--ignore", action="append", default=[], help="ignore tests matching IGNORE pattern") parser.add_option("-I", "--ignore-file", metavar="IFILE", action="append", @@ -101,8 +103,10 @@ for v in opts.ignore_file: for a in args: includes.append(a.strip()) -if not includes: +if not includes and not opts.modules: includes.extend(["qpid.tests.*", "tests.*", "tests_0-10.*"]) +else: + includes.append("*") def is_ignored(path): for p in excludes: @@ -493,7 +497,9 @@ class Harness: objects.append(child) self.scanned.append(obj) -modules = "qpid.tests", "tests", "tests_0-8", "tests_0-9", "tests_0-10" +modules = opts.modules +if not modules: + modules.extend(["qpid.tests", "tests", "tests_0-8", "tests_0-9", "tests_0-10"]) h = Harness() for name in modules: m = __import__(name, None, None, ["dummy"]) -- cgit v1.2.1 From 1a474f025951d776a5a51ecf007dfe6c48bc89ae Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Wed, 12 Aug 2009 15:40:29 +0000 Subject: fixed bug in default includes git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803563 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index 68f9622710..3785af559f 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -103,10 +103,11 @@ for v in opts.ignore_file: for a in args: includes.append(a.strip()) -if not includes and not opts.modules: - includes.extend(["qpid.tests.*", "tests.*", "tests_0-10.*"]) -else: - includes.append("*") +if not includes: + if not opts.modules: + includes.extend(["qpid.tests.*", "tests.*", "tests_0-10.*"]) + else: + includes.append("*") def is_ignored(path): for p in excludes: -- cgit v1.2.1 From 7d7100fb4ae5deec284e5bb79ada61364c7a9457 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Wed, 12 Aug 2009 15:49:29 +0000 Subject: made if test slightly less obtuse git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803568 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index 3785af559f..ca6bec00fb 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -104,10 +104,10 @@ for a in args: includes.append(a.strip()) if not includes: - if not opts.modules: - includes.extend(["qpid.tests.*", "tests.*", "tests_0-10.*"]) - else: + if opts.modules: includes.append("*") + else: + includes.extend(["qpid.tests.*", "tests.*", "tests_0-10.*"]) def is_ignored(path): for p in excludes: -- cgit v1.2.1 From bcf296290a524c0d775bc9c741d212ba6aa62d40 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Wed, 12 Aug 2009 20:02:47 +0000 Subject: check the TERM environment variable as well as isatty to determine how smart the terminal is git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803687 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index ca6bec00fb..22063185b2 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -123,8 +123,11 @@ def is_included(path): return True return False +def is_smart(): + return sys.stdout.isatty() and os.environ.get("TERM", "dumb") != "dumb" + def width(): - if sys.stdout.isatty(): + if is_smart(): s = struct.pack("HHHH", 0, 0, 0, 0) fd_stdout = sys.stdout.fileno() x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s) @@ -155,7 +158,7 @@ KEYWORDS = {"pass": (32,), "ignored": (33,), "selected": (34,)} -COLORIZE = sys.stdout.isatty() +COLORIZE = is_smart() def colorize_word(word, text=None): if text is None: -- cgit v1.2.1 From 6a3db97ca8720884c79ce8e05729a458e063d406 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Wed, 12 Aug 2009 20:08:48 +0000 Subject: made width default pay attention to the COLUMNS environment variable git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@803692 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index 22063185b2..528acaa124 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -134,7 +134,10 @@ def width(): rows, cols, xpx, ypx = struct.unpack("HHHH", x) return cols else: - return 80 + try: + return int(os.environ.get("COLUMNS", "80")) + except ValueError: + return 80 WIDTH = width() -- cgit v1.2.1 From e87bb8426a55f9e4a80fbfda25af759e34e7ce60 Mon Sep 17 00:00:00 2001 From: "Stephen D. Huston" Date: Mon, 5 Oct 2009 23:35:23 +0000 Subject: Get remaining tests running on Windows git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@822091 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index 528acaa124..b569020368 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -20,7 +20,7 @@ # TODO: summarize, test harness preconditions (e.g. broker is alive) -import fcntl, logging, optparse, os, struct, sys, termios, traceback, types +import logging, optparse, os, struct, sys, traceback, types from fnmatch import fnmatchcase as match from getopt import GetoptError from logging import getLogger, StreamHandler, Formatter, Filter, \ @@ -126,27 +126,33 @@ def is_included(path): def is_smart(): return sys.stdout.isatty() and os.environ.get("TERM", "dumb") != "dumb" -def width(): - if is_smart(): - s = struct.pack("HHHH", 0, 0, 0, 0) - fd_stdout = sys.stdout.fileno() - x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s) - rows, cols, xpx, ypx = struct.unpack("HHHH", x) - return cols - else: - try: - return int(os.environ.get("COLUMNS", "80")) - except ValueError: - return 80 +try: + import fcntl, termios -WIDTH = width() + def width(): + if is_smart(): + s = struct.pack("HHHH", 0, 0, 0, 0) + fd_stdout = sys.stdout.fileno() + x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s) + rows, cols, xpx, ypx = struct.unpack("HHHH", x) + return cols + else: + try: + return int(os.environ.get("COLUMNS", "80")) + except ValueError: + return 80 -def resize(sig, frm): - global WIDTH WIDTH = width() -import signal -signal.signal(signal.SIGWINCH, resize) + def resize(sig, frm): + global WIDTH + WIDTH = width() + + import signal + signal.signal(signal.SIGWINCH, resize) + +except ImportError: + WIDTH = 80 def vt100_attrs(*attrs): return "\x1B[%sm" % ";".join(map(str, attrs)) -- cgit v1.2.1 From 3df1424a43244ee1c347ff9163650753601c6893 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Fri, 5 Feb 2010 15:08:44 +0000 Subject: moved protocol tests from qpid/python to qpid/tests git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@906961 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index b569020368..5aedcb68ea 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -107,7 +107,7 @@ if not includes: if opts.modules: includes.append("*") else: - includes.extend(["qpid.tests.*", "tests.*", "tests_0-10.*"]) + includes.extend(["qpid.tests.*", "tests.*"]) def is_ignored(path): for p in excludes: @@ -512,7 +512,7 @@ class Harness: modules = opts.modules if not modules: - modules.extend(["qpid.tests", "tests", "tests_0-8", "tests_0-9", "tests_0-10"]) + modules.extend(["qpid.tests", "tests"]) h = Harness() for name in modules: m = __import__(name, None, None, ["dummy"]) -- cgit v1.2.1 From 62ea3272e4e7a6d0acf338820068b816418b826e Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Fri, 5 Feb 2010 15:27:54 +0000 Subject: moved tests/*.py underneath qpid/tests/*.py git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@906969 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index 5aedcb68ea..f7955a4a9d 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -107,7 +107,7 @@ if not includes: if opts.modules: includes.append("*") else: - includes.extend(["qpid.tests.*", "tests.*"]) + includes.extend(["qpid.tests.*"]) def is_ignored(path): for p in excludes: @@ -512,7 +512,7 @@ class Harness: modules = opts.modules if not modules: - modules.extend(["qpid.tests", "tests"]) + modules.extend(["qpid.tests"]) h = Harness() for name in modules: m = __import__(name, None, None, ["dummy"]) -- cgit v1.2.1 From 2f478ad7f82d996e1b20f1a4b25d66c8272d3beb Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Mon, 22 Feb 2010 12:26:05 +0000 Subject: added an option for timing test runs git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@912547 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index f7955a4a9d..cf6007cd79 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -20,7 +20,7 @@ # TODO: summarize, test harness preconditions (e.g. broker is alive) -import logging, optparse, os, struct, sys, traceback, types +import logging, optparse, os, struct, sys, time, traceback, types from fnmatch import fnmatchcase as match from getopt import GetoptError from logging import getLogger, StreamHandler, Formatter, Filter, \ @@ -60,6 +60,8 @@ parser.add_option("-I", "--ignore-file", metavar="IFILE", action="append", help="ignore tests matching patterns in IFILE") parser.add_option("-H", "--halt-on-error", action="store_true", default=False, dest="hoe", help="halt if an error is encountered") +parser.add_option("-t", "--time", action="store_true", default=False, + help="report timing information on test run") parser.add_option("-D", "--define", metavar="DEFINE", dest="defines", action="append", default=[], help="define test parameters") @@ -165,7 +167,9 @@ KEYWORDS = {"pass": (32,), "start": (34,), "total": (34,), "ignored": (33,), - "selected": (34,)} + "selected": (34,), + "elapsed": (34,), + "average": (34,)} COLORIZE = is_smart() @@ -525,6 +529,7 @@ total = len(filtered) + len(ignored) passed = 0 failed = 0 skipped = 0 +start = time.time() for t in filtered: if list_only: print t.name() @@ -538,6 +543,7 @@ for t in filtered: failed += 1 if opts.hoe: break +end = time.time() run = passed + failed @@ -558,16 +564,22 @@ if not list_only: skip = "skip" else: skip = "pass" - print colorize("Totals:", 1), \ - colorize_word("total", "%s tests" % total) + ",", \ - colorize_word(_pass, "%s passed" % passed) + ",", \ - colorize_word(skip, "%s skipped" % skipped) + ",", \ - colorize_word(ign, "%s ignored" % len(ignored)) + ",", \ - colorize_word(outcome, "%s failed" % failed), + print colorize("Totals:", 1), + totals = [colorize_word("total", "%s tests" % total), + colorize_word(_pass, "%s passed" % passed), + colorize_word(skip, "%s skipped" % skipped), + colorize_word(ign, "%s ignored" % len(ignored)), + colorize_word(outcome, "%s failed" % failed)] + print ", ".join(totals), if opts.hoe and failed > 0: print " -- (halted after %s)" % run else: print + if opts.time: + print colorize("Timing:", 1), + timing = [colorize_word("elapsed", "%.2fs elapsed" % (end - start)), + colorize_word("average", "%.2fs average" % ((end - start)/run))] + print ", ".join(timing) if failed or skipped: sys.exit(1) -- cgit v1.2.1 From 27f0d3d1eadb702d6d12449a0418ab26b01beb00 Mon Sep 17 00:00:00 2001 From: "Rafael H. Schloming" Date: Tue, 23 Feb 2010 11:53:44 +0000 Subject: fixed divide by zero when no tests match git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@915293 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/python/qpid-python-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'qpid/python/qpid-python-test') diff --git a/qpid/python/qpid-python-test b/qpid/python/qpid-python-test index cf6007cd79..a47f633565 100755 --- a/qpid/python/qpid-python-test +++ b/qpid/python/qpid-python-test @@ -575,7 +575,7 @@ if not list_only: print " -- (halted after %s)" % run else: print - if opts.time: + if opts.time and run > 0: print colorize("Timing:", 1), timing = [colorize_word("elapsed", "%.2fs elapsed" % (end - start)), colorize_word("average", "%.2fs average" % ((end - start)/run))] -- cgit v1.2.1