options only for describing combinations represented by a suite:
-c, --combinations Describe test combinations rather than
individual yaml fragments
- --filter <keywords> Only list jobs whose filenames contain at
- least one of the keywords in the comma
- separated keyword string specified.
- --filter-out <keywords> Do not list jobs whose filenames contain
+ -s, --summary Print summary
+ --filter <keywords> Only list tests whose description contains
+ at least one of the keywords in the comma
+ separated keyword string specified
+ --filter-out <keywords> Do not list tests whose description contains
any of the keywords in the comma separated
- keyword string specified.
+ keyword string specified
+ --filter-all <keywords> Only list tests whose description contains
+ each of the keywords in the comma separated
+ keyword string specified
+ -F, --filter-fragments Check fragments additionaly to descriptions
+ using keywords specified with 'filter',
+ 'filter-out' and 'filter-all' options.
+ -D, --print-description Print job descriptions for the suite,
+ used only in combination with 'summary'
+ -L, --print-fragments Print file list inovolved for each facet,
+ used only in combination with 'summary'
-l <jobs>, --limit <jobs> List at most this many jobs
[default: 0]
--subset <index/outof> Instead of listing the entire
2/<outof> ... <outof>-1/<outof>
will list all jobs in the
suite (many more than once).
+ -S <seed>, --seed <seed> Used for pseudo-random tests generation
+ involving facet whose path ends with '$'
+ operator, where negative value used for
+ a random seed
+ [default: -1]
"""
import sys
import yaml
-from teuthology.exceptions import ParseError
-from teuthology.suite.build_matrix import build_matrix, combine_path
+import random
+from distutils.util import strtobool
+from teuthology.exceptions import ParseError
+from teuthology.suite.build_matrix import \
+ build_matrix, generate_combinations, _get_matrix
+from teuthology.suite import util
def main(args):
try:
def describe_tests(args):
suite_dir = os.path.abspath(args["<suite_dir>"])
- fields = args["--fields"].split(',')
- include_facet = args['--show-facet'] == 'yes'
output_format = args['--format']
+ conf=dict()
+ rename_args = {
+ 'filter': 'filter_in',
+ }
+ for (key, value) in args.items():
+ key = key.lstrip('--').replace('-', '_')
+ key = rename_args.get(key) or key
+ if key in ('filter_all', 'filter_in', 'filter_out', 'fields'):
+ if not value:
+ value = []
+ else:
+ value = [_ for _ in
+ (x.strip() for x in value.split(',')) if _]
+ elif key in ('limit'):
+ value = int(value)
+ elif key in ('seed'):
+ value = int(value)
+ if value < 0:
+ value = None
+ elif key == 'subset' and value is not None:
+ # take input string '2/3' and turn into (2, 3)
+ value = tuple(map(int, value.split('/')))
+ elif key in ('show_facet'):
+ value = strtobool(value)
+ conf[key] = value
+
if args['--combinations']:
- limit = int(args['--limit'])
- filter_in = None
- if args['--filter']:
- filter_in = [f.strip() for f in args['--filter'].split(',')]
- filter_out = None
- if args['--filter-out']:
- filter_out = [f.strip() for f in args['--filter-out'].split(',')]
- subset = None
- if args['--subset']:
- subset = map(int, args['--subset'].split('/'))
- headers, rows = get_combinations(suite_dir, fields, subset,
- limit, filter_in,
- filter_out, include_facet)
+ headers, rows = get_combinations(suite_dir,
+ limit=conf['limit'],
+ seed=conf['seed'],
+ subset=conf['subset'],
+ fields=conf['fields'],
+ filter_in=conf['filter_in'],
+ filter_out=conf['filter_out'],
+ filter_all=conf['filter_all'],
+ filter_fragments=conf['filter_fragments'],
+ include_facet=conf['show_facet'])
hrule = ALL
+ elif args['--summary']:
+ output_summary(suite_dir,
+ limit=conf['limit'],
+ seed=conf['seed'],
+ subset=conf['subset'],
+ show_desc=conf['print_description'],
+ show_frag=conf['print_fragments'],
+ filter_in=conf['filter_in'],
+ filter_out=conf['filter_out'],
+ filter_all=conf['filter_all'],
+ filter_fragments=conf['filter_fragments'])
+ exit(0)
else:
- headers, rows = describe_suite(suite_dir, fields, include_facet,
+ headers, rows = describe_suite(suite_dir, conf['fields'], conf['show_facet'],
output_format)
hrule = FRAME
print(table)
-def get_combinations(suite_dir, fields, subset,
- limit, filter_in, filter_out,
- include_facet):
+def output_summary(path, limit=0,
+ seed=None,
+ subset=None,
+ show_desc=True,
+ show_frag=False,
+ show_matrix=False,
+ filter_in=None,
+ filter_out=None,
+ filter_all=None,
+ filter_fragments=True):
+ """
+ Prints number of all facets for a given suite for inspection,
+ taking into accout such options like --subset, --filter,
+ --filter-out and --filter-all. Optionally dumps matrix objects,
+ yaml files which is used for generating combinations.
+ """
+
+ random.seed(seed)
+ mat, first, matlimit = _get_matrix(path, subset)
+ configs = generate_combinations(path, mat, first, matlimit)
+ print("# {} (not filtered) {}".format(len(configs), path))
+ count = 0
+ suite = os.path.basename(path)
+ config_list = util.filter_configs(configs,
+ suite_name=suite,
+ filter_in=filter_in,
+ filter_out=filter_out,
+ filter_all=filter_all,
+ filter_fragments=filter_fragments)
+ if show_desc or show_frag:
+ for c in config_list:
+ if limit and count >= limit:
+ break
+ count += 1
+ print(" {}".format(c[0]))
+ if show_frag:
+ for path in c[1]:
+ print(" {}".format(util.strip_fragment_path(path)))
+ else:
+ count=sum(1 for _ in config_list)
+ if show_matrix:
+ print(mat.tostr(1))
+ print(" {} (total filtered)".format(count))
+
+def get_combinations(suite_dir,
+ limit=0,
+ seed=None,
+ subset=None,
+ fields=[],
+ filter_in=None,
+ filter_out=None,
+ filter_all=None,
+ filter_fragments=False,
+ include_facet=True):
"""
Describes the combinations of a suite, optionally limiting
or filtering output based on the given parameters. Includes
Returns a tuple of (headers, rows) where both elements are lists
of strings.
"""
- configs = [(combine_path(suite_dir, item[0]), item[1]) for item in
- build_matrix(suite_dir, subset)]
+ suite = os.path.basename(suite_dir)
+ configs = build_matrix(suite_dir, subset, seed)
num_listed = 0
rows = []
dirs = {}
max_dir_depth = 0
+ configs = util.filter_configs(configs,
+ suite_name=suite,
+ filter_in=filter_in,
+ filter_out=filter_out,
+ filter_all=filter_all,
+ filter_fragments=filter_fragments)
for _, fragment_paths in configs:
if limit > 0 and num_listed >= limit:
break
- if filter_in and not any([f in path for f in filter_in
- for path in fragment_paths]):
- continue
- if filter_out and any([f in path for f in filter_out
- for path in fragment_paths]):
- continue
fragment_fields = [extract_info(path, fields)
for path in fragment_paths]
- desc: single node cluster
roles:
- [osd.0, osd.1, osd.2, mon.a, mon.b, mon.c, client.0]
+""",
+ 'fixed-2.yaml':
+ """meta:
+- desc: couple node cluster
+roles:
+- [osd.0, osd.1, osd.2, mon.a, mon.b, mon.c]
+- [client.0]
+""",
+ 'fixed-3.yaml':
+ """meta:
+- desc: triple node cluster
+roles:
+- [osd.0, osd.1, osd.2, mon.a, mon.b, mon.c]
+- [client.0]
+- [client.1]
"""
},
'workloads': {
├── base
│ └── install.yaml
├── clusters
-│ └── fixed-1.yaml
+│ ├── fixed-1.yaml
+│ ├── fixed-2.yaml
+│ └── fixed-3.yaml
└── workloads
├── rbd_api_tests.yaml
└── rbd_api_tests_old_format.yaml""".split('\n')
'base',
'',
'clusters',
+ 'clusters',
+ 'clusters',
'',
'workloads',
'workloads',
'install ceph',
'',
'single node cluster',
+ 'couple node cluster',
+ 'triple node cluster',
'',
'c/c++ librbd api tests with default settings',
'c/c++ librbd api tests with format 1 images',
'',
'',
'',
+ '',
+ '',
'default',
'none',
]
expected_desc)]
def test_combinations_only_facets(self):
- headers, rows = get_combinations('basic', [], None, 1, None, None, True)
+ headers, rows = get_combinations('basic',
+ fields=[], subset=None, limit=1,
+ filter_in=None, filter_out=None, filter_all=None,
+ include_facet=True)
self.assert_expected_combo_headers(headers)
assert rows == [['basic', 'install', 'fixed-1', 'rbd_api_tests']]
def test_combinations_desc_features(self):
- headers, rows = get_combinations('basic', ['desc', 'rbd_features'],
- None, 1, None, None, False)
+ headers, rows = get_combinations('basic',
+ fields=['desc', 'rbd_features'], subset=None, limit=1,
+ filter_in=None, filter_out=None, filter_all=None,
+ include_facet=False)
assert headers == ['desc', 'rbd_features']
descriptions = '\n'.join([
'install ceph',
assert rows == [[descriptions, 'default']]
def test_combinations_filter_in(self):
- headers, rows = get_combinations('basic', [], None, 0, ['old_format'],
- None, True)
+ headers, rows = get_combinations('basic',
+ fields=[], subset=None, limit=0,
+ filter_in=['old_format'], filter_out=None, filter_all=None,
+ include_facet=True)
self.assert_expected_combo_headers(headers)
- assert rows == [['basic', 'install', 'fixed-1',
- 'rbd_api_tests_old_format']]
+ assert rows == [
+ ['basic', 'install', 'fixed-1', 'rbd_api_tests_old_format'],
+ ['basic', 'install', 'fixed-2', 'rbd_api_tests_old_format'],
+ ['basic', 'install', 'fixed-3', 'rbd_api_tests_old_format'],
+ ]
def test_combinations_filter_out(self):
- headers, rows = get_combinations('basic', [], None, 0, None,
- ['old_format'], True)
+ headers, rows = get_combinations('basic',
+ fields=[], subset=None, limit=0,
+ filter_in=None, filter_out=['old_format'], filter_all=None,
+ include_facet=True)
self.assert_expected_combo_headers(headers)
- assert rows == [['basic', 'install', 'fixed-1', 'rbd_api_tests']]
+ assert rows == [
+ ['basic', 'install', 'fixed-1', 'rbd_api_tests'],
+ ['basic', 'install', 'fixed-2', 'rbd_api_tests'],
+ ['basic', 'install', 'fixed-3', 'rbd_api_tests'],
+ ]
+
+ def test_combinations_filter_all(self):
+ headers, rows = get_combinations('basic',
+ fields=[], subset=None, limit=0,
+ filter_in=None, filter_out=None,
+ filter_all=['fixed-2', 'old_format'],
+ include_facet=True)
+ self.assert_expected_combo_headers(headers)
+ assert rows == [
+ ['basic', 'install', 'fixed-2', 'rbd_api_tests_old_format']
+ ]
@patch('teuthology.describe_tests.open')