s3-libsmb: Remove obsolete support for dns_host_file.
[obnox/samba/samba-obnox.git] / selftest / testlist.py
1 # testlist.py -- Test list
2 # Copyright (C) 2012 Jelmer Vernooij <jelmer@samba.org>
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; version 3
7 # of the License or (at your option) any later version of
8 # the License.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA  02110-1301, USA.
19
20 """Selftest test list management."""
21
22 __all__ = ['find_in_list', 'read_test_regexes', 'read_testlist']
23
24 import os
25 import re
26 import sys
27
28 def find_in_list(list, fullname):
29     """Find test in list.
30
31     :param list: List with 2-tuples with regex and reason
32     """
33     for (regex, reason) in list:
34         if re.match(regex, fullname):
35             if reason is not None:
36                 return reason
37             else:
38                 return ""
39     return None
40
41
42 def read_test_regexes(f):
43     """Read tuples with regular expression and optional string from a file.
44
45     :param f: File-like object to read from
46     :return: Iterator over tuples with regular expression and test name
47     """
48     for l in f.readlines():
49         l = l.strip()
50         if l[0] == "#":
51             continue
52         try:
53             (test, reason) = l.split("#", 1)
54         except ValueError:
55             yield l, None
56         else:
57             yield test.strip(), reason.strip()
58
59
60 def should_run_test(tests, name):
61     if tests == []:
62         return True
63     for test in tests:
64         if re.match(test, name):
65             return True
66     return False
67
68
69 def read_testlist(inf, outf):
70     """Read a list of tests from a file.
71
72     :param inf: File-like object to read from.
73     :param outf: File-like object to write to.
74     :return: Iterator over tuples describing tests
75     """
76     while True:
77         l = inf.readline()
78         if l == '':
79             return
80         if l.startswith("-- TEST") and l.endswith(" --\n"):
81             supports_loadlist = l.startswith("-- TEST-LOADLIST")
82             name = inf.readline().rstrip("\n")
83             env = inf.readline().rstrip("\n")
84             if supports_loadlist:
85                 loadlist = inf.readline().rstrip("\n")
86             else:
87                 loadlist = None
88             cmdline = inf.readline().rstrip("\n")
89             yield (name, env, cmdline, loadlist)
90         else:
91             outf.write(l)
92
93
94 def read_restricted_test_list(f):
95     for l in f.readlines():
96         yield l.strip()
97
98
99 class RestrictedTestManager(object):
100     """Test manager which can filter individual tests that should be run."""
101
102     def __init__(self, test_list):
103         self.test_list = test_list
104         self.unused = set(self.test_list)
105
106     @classmethod
107     def from_path(cls, path):
108         f = open(path, 'r')
109         try:
110             return cls(read_restricted_test_list(f))
111         finally:
112             f.close()
113
114     def should_run_testsuite(self, name):
115         """Determine whether a testsuite should be run.
116
117         :param name: Name of the testsuite
118         :return: None if full testsuite should be run,
119             a list of subtests to run or [] if it should
120             not be run.
121         """
122         match = []
123         for r in self.test_list:
124             if r == name:
125                 match = None
126                 if r in self.unused:
127                     self.unused.remove(r)
128             elif r.startswith(name + "."):
129                 if match is not None:
130                     match.append(r[len(name+"."):])
131                 if r in self.unused:
132                     self.unused.remove(r)
133         return match
134
135     def iter_unused(self):
136         """Iterate over entry entries that were unused.
137
138         :return: Iterator over test list entries that were not used.
139         """
140         return iter(self.unused)
141
142
143 def open_file_or_pipe(path, mode):
144     """Open a file or pipe.
145
146     :param path: Path to open; if it ends with | it is assumed to be a
147         command to run
148     :param mode: Mode with which to open it
149     :return: File-like object
150     """
151     if path.endswith("|"):
152         return os.popen(path[:-1], mode)
153     return open(path, mode)
154
155
156 def read_testlist_file(fn, outf=None):
157     """Read testlist file.
158
159     :param fn: Path to read (assumed to be a command to run if it ends with |)
160     :param outf: File-like object to pass non-test data through to
161         (defaults to stdout)
162     :return: Iterator over test suites (see read_testlist)
163     """
164     if outf is None:
165         outf = sys.stdout
166     inf = open_file_or_pipe(fn, 'r')
167     try:
168         for testsuite in read_testlist(inf, outf):
169             yield testsuite
170     finally:
171         inf.close()