Skip to content

Commit 5201240

Browse files
committed
Support tags
Usage: ```sh ./test-run.py --tags foo ./test-run.py --tags foo,bar app/ app-tap/ ``` test-run will run only those tests, which have at least one of the provided tags. The tags metainfo should be placed within a first comment of a test file (see examples in the README.md file). Unsupported features: * Marking unit tests with tags. * Multiline comments (use singleline ones for now). Fixes #22
1 parent c345003 commit 5201240

File tree

5 files changed

+141
-2
lines changed

5 files changed

+141
-2
lines changed

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,55 @@ The following files will be removed:
353353
* `*.inprogress`
354354
* `[0-9]*/`
355355

356+
### Tags
357+
358+
Usage:
359+
360+
```sh
361+
./test-run.py --tags foo
362+
./test-run.py --tags foo,bar app/ app-tap/
363+
```
364+
365+
test-run will run only those tests, which have at least one of the
366+
provided tags.
367+
368+
The tags metainfo should be placed within a first comment of a test
369+
file.
370+
371+
Examples:
372+
373+
* .lua file:
374+
375+
```lua
376+
#!/usr/bin/tarantool
377+
378+
-- tags: foo, bar
379+
-- tags: one, more
380+
381+
<...>
382+
```
383+
384+
* .sql file:
385+
386+
```sql
387+
-- tags: foo
388+
-- tags: bar
389+
<...>
390+
```
391+
392+
* .py file:
393+
394+
```python
395+
# tags: foo
396+
397+
<...>
398+
```
399+
400+
Unsupported features:
401+
402+
* Marking unit tests with tags.
403+
* Multiline comments (use singleline ones for now).
404+
356405
### Used By
357406

358407
- [Tarantool](https://github.com/tarantool/tarantool) - in-memory database and application server

lib/options.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ def env_list(name, default):
2222
return value_list or default
2323

2424

25+
def split_list(tags_str):
26+
# Accept both ', ' and ',' as a separator.
27+
#
28+
# It is consistent with parsing of tags within a test file.
29+
return [tag.strip() for tag in tags_str.split(',')]
30+
31+
2532
class Options(object):
2633
"""Handle options of test-runner"""
2734

@@ -270,6 +277,17 @@ def __init__(self):
270277
dest="memtx_allocator",
271278
default=os.environ.get("MEMTX_ALLOCATOR", "small"),
272279
help="""Memtx allocator type for tests""")
280+
parser.add_argument(
281+
'--tags',
282+
dest='tags',
283+
default=None,
284+
type=split_list,
285+
help="""Comma separated list of tags.
286+
287+
If tags are provided, test-run will run only those
288+
tests, which are marked with ANY of the provided
289+
tags.
290+
""")
273291

274292
# XXX: We can use parser.parse_intermixed_args() on
275293
# Python 3.7 to understand commands like

lib/server.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from lib.options import Options
1515
from lib.utils import print_tail_n
1616
from lib.utils import bytes_to_str
17+
from lib.utils import find_tags
1718

1819
DEFAULT_CHECKPOINT_PATTERNS = ["*.snap", "*.xlog", "*.vylog", "*.inprogress",
1920
"[0-9]*/"]
@@ -156,14 +157,40 @@ def print_log(self, lines=None):
156157

157158
@staticmethod
158159
def exclude_tests(test_names, exclude_patterns):
159-
def match_any(test_name, patterns):
160+
""" Filter out test files by several criteria:
161+
162+
exclude_patters: a list of strings. If a string is
163+
a substring of the test full name, exclude it.
164+
165+
If --tags option is provided, exclude tests, which
166+
have no a tag from the provided list.
167+
"""
168+
169+
# TODO: Support filtering by another file (for unit
170+
# tests). Transform a test name into a test source name.
171+
# Don't forget about out of source build.
172+
# TODO: Support multiline comments (mainly for unit
173+
# tests).
174+
175+
def match_any_pattern(test_name, patterns):
160176
for pattern in patterns:
161177
if pattern in test_name:
162178
return True
163179
return False
164180

181+
def match_any_tag(test_name, accepted_tags):
182+
tags = find_tags(test_name)
183+
for tag in tags:
184+
if tag in accepted_tags:
185+
return True
186+
return False
187+
188+
accepted_tags = Options().args.tags
189+
165190
res = []
166191
for test_name in test_names:
167-
if not match_any(test_name, exclude_patterns):
192+
if match_any_pattern(test_name, exclude_patterns):
193+
continue
194+
if accepted_tags is None or match_any_tag(test_name, accepted_tags):
168195
res.append(test_name)
169196
return res

lib/tarantool_server.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class LuaTest(Test):
7676
RESULT_FILE_VERSION_LINE_RE = re.compile(
7777
r'^-- test-run result file version (?P<version>\d+)$')
7878
RESULT_FILE_VERSION_TEMPLATE = '-- test-run result file version {}'
79+
TAGS_LINE_RE = re.compile(r'^-- tags:')
7980

8081
def __init__(self, *args, **kwargs):
8182
super(LuaTest, self).__init__(*args, **kwargs)
@@ -251,6 +252,16 @@ def exec_loop(self, ts):
251252
# Normalize a line.
252253
line = line.rstrip('\n')
253254

255+
# Skip metainformation (only tags at the moment).
256+
#
257+
# It is to reduce noise changes in result files, when
258+
# tags are added or edited.
259+
#
260+
# TODO: Ideally we should do that only on a first
261+
# comment in the file.
262+
if self.TAGS_LINE_RE.match(line):
263+
continue
264+
254265
# Show empty lines / comments in a result file, but
255266
# don't send them to tarantool.
256267
line_is_empty = line.strip() == ''

lib/utils.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,3 +376,37 @@ def str_to_bytes(s):
376376
if PY2:
377377
return s
378378
return s.encode('utf-8')
379+
380+
381+
def parse_tag_line(line):
382+
tags_str = line.split(':', 1)[1].strip()
383+
return [tag.strip() for tag in tags_str.split(',')]
384+
385+
386+
def find_tags(filename):
387+
""" Extract tags from a first comment in the file.
388+
"""
389+
# TODO: Support multiline comments. See exclude_tests() in
390+
# lib/server.py.
391+
if filename.endswith('.lua') or filename.endswith('.sql'):
392+
singleline_comment = '--'
393+
elif filename.endswith('.py'):
394+
singleline_comment = '#'
395+
else:
396+
return []
397+
398+
tags = []
399+
with open(filename, 'r') as f:
400+
for line in f:
401+
line = line.rstrip('\n')
402+
if line.startswith('#!'):
403+
pass
404+
elif line == '':
405+
pass
406+
elif line.startswith(singleline_comment + ' tags:'):
407+
tags.extend(parse_tag_line(line))
408+
elif line.startswith(singleline_comment):
409+
pass
410+
else:
411+
break
412+
return tags

0 commit comments

Comments
 (0)