71
|
1 #!/usr/bin/env python3
|
|
2 # Run our tests. Basically, these use the python unittest framework, but
|
|
3 # are organized into a directory tree containing test code and the server
|
|
4 # files to run the tests against. The tests are done by creating a local
|
|
5 # server on the specified port (default 8080) and issuing requests to it.
|
|
6 #
|
|
7 # Note that some of the test suites we run require the requests and/or
|
|
8 # Beautiful Soup libraries (these are not needed for running TInCan, only
|
|
9 # for testing it.)
|
|
10
|
|
11 # I m p o r t s
|
|
12
|
|
13 import os, sys
|
|
14 import importlib
|
|
15 import logging
|
|
16 import unittest
|
|
17 from argparse import ArgumentParser
|
|
18
|
|
19 # V a r i a b l e s
|
|
20
|
|
21 MYNAME = os.path.basename(sys.argv[0])
|
|
22 TESTDIR = "tests"
|
|
23 FPREFIX = "suite_"
|
|
24 FILESDIR = "files"
|
|
25 FILESVAR = "files"
|
|
26 PORTVAR = "port"
|
|
27
|
|
28 # F u n c t i o n s
|
|
29
|
|
30 def is_test(d):
|
|
31 if not d.startswith(FPREFIX):
|
|
32 return False
|
|
33 return os.path.isdir(os.path.join(TESTDIR, d)) and os.path.isdir(os.path.join(TESTDIR, d, FILESDIR))
|
|
34
|
|
35 def is_subclass(a, b):
|
|
36 try:
|
|
37 return issubclass(a, b)
|
|
38 except TypeError:
|
|
39 return False
|
|
40
|
|
41 # M a i n P r o g r a m
|
|
42
|
|
43 # Parse arguments
|
|
44 parser = ArgumentParser(prog=sys.argv[0], usage="%(prog)s [options]")
|
|
45 parser.add_argument("-p", "--port", default=8080, help="port to use (default: 8080)")
|
|
46 args = parser.parse_args(sys.argv[1:])
|
|
47
|
|
48 # Reject attempts to run out of directory
|
|
49 if not os.path.isdir(TESTDIR):
|
|
50 sys.stderr.write("{0}: {1!r} - no such directory\n".format(MYNAME, TESTDIR))
|
|
51 sys.exit(2)
|
|
52
|
|
53 # Get the log file name and ensure the log file is cleared
|
|
54 from tests import LOGNAME, LOGGERNAME
|
|
55 open(LOGNAME, "w").close()
|
|
56
|
|
57 # Make a logger object for ServerFixture to use
|
|
58 mylog = logging.getLogger(LOGGERNAME)
|
|
59 handler = logging.FileHandler(LOGNAME)
|
|
60 handler.setFormatter(
|
|
61 logging.Formatter(fmt="%(asctime)s - %(levelname)s: %(message)s"))
|
|
62 mylog.addHandler(handler)
|
|
63 mylog.setLevel(logging.INFO)
|
|
64
|
|
65 # Locate all fixtures and operate on them
|
|
66 failures = 0
|
|
67 fixtures = sorted(filter(is_test, os.listdir(TESTDIR)))
|
|
68 if not fixtures:
|
|
69 sys.stderr.write("{0}: warning - no fixtures found\n".format(MYNAME))
|
|
70 for fixture in fixtures:
|
|
71 name = "{0}.{1}".format(TESTDIR, fixture)
|
|
72 sys.stderr.write("{0}: running {1} ...\n".format(MYNAME, name))
|
|
73 module = importlib.import_module(name)
|
|
74 directory = os.path.join(TESTDIR, fixture, FILESDIR)
|
|
75 for i in dir(module):
|
|
76 v = getattr(module, i)
|
|
77 if is_subclass(v, unittest.TestCase):
|
|
78 setattr(v, FILESVAR, directory)
|
|
79 setattr(v, PORTVAR, args.port)
|
|
80 suite = unittest.defaultTestLoader.loadTestsFromModule(module)
|
|
81 result = unittest.TextTestRunner(verbosity=1).run(suite)
|
|
82 if result.wasSuccessful():
|
|
83 sys.stderr.write("{0}: {1} passed\n".format(MYNAME, name))
|
|
84 else:
|
|
85 sys.stderr.write("{0}: {1} failed\n".format(MYNAME, name))
|
|
86 failures += 1
|
|
87
|
|
88 # AMF...
|
|
89 if failures:
|
|
90 sys.stderr.write("{0}: {1} suite{2} failed\n".format(
|
|
91 MYNAME,
|
|
92 failures,
|
|
93 "" if failures == 1 else "s"))
|
|
94
|
|
95 sys.stdout.write("Note: server log output is in {0!r}.\n".format(LOGNAME))
|
|
96 sys.exit(1 if failures else 0)
|