blob: 80a82e71a59e10a574fa9441592c399c3c3e3979 [file] [log] [blame]
Roger Meier41ad4342015-03-24 22:30:40 +01001#
2# Licensed to the Apache Software Foundation (ASF) under one
3# or more contributor license agreements. See the NOTICE file
4# distributed with this work for additional information
5# regarding copyright ownership. The ASF licenses this file
6# to you under the Apache License, Version 2.0 (the
7# "License"); you may not use this file except in compliance
8# with the License. You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing,
13# software distributed under the License is distributed on an
14# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15# KIND, either express or implied. See the License for the
16# specific language governing permissions and limitations
17# under the License.
18#
19
20import platform
21from itertools import product
22
23from crossrunner.util import merge_dict
24
25# Those keys are passed to execution as is.
26# Note that there are keys other than these, namely:
27# delay: After server is started, client start is delayed for the value
28# (seconds).
29# timeout: Test timeout after client is started (seconds).
30# platforms: Supported platforms. Should match platform.system() value.
31# protocols: list of supported protocols
32# transports: list of supported transports
33# sockets: list of supported sockets
34VALID_JSON_KEYS = [
35 'name', # name of the library, typically a language name
36 'workdir', # work directory where command is executed
37 'command', # test command
38 'extra_args', # args appended to command after other args are appended
39 'join_args', # whether args should be passed as single concatenated string
40 'env', # additional environmental variable
41]
42
43DEFAULT_DELAY = 1
44DEFAULT_TIMEOUT = 5
45
46
47def collect_testlibs(config, server_match, client_match):
48 """Collects server/client configurations from library configurations"""
49 def expand_libs(config):
50 for lib in config:
51 sv = lib.pop('server', None)
52 cl = lib.pop('client', None)
53 yield lib, sv, cl
54
55 def yield_testlibs(base_configs, configs, match):
56 for base, conf in zip(base_configs, configs):
57 if conf:
58 if not match or base['name'] in match:
59 platforms = conf.get('platforms') or base.get('platforms')
60 if not platforms or platform.system() in platforms:
61 yield merge_dict(base, conf)
62
63 libs, svs, cls = zip(*expand_libs(config))
64 servers = list(yield_testlibs(libs, svs, server_match))
65 clients = list(yield_testlibs(libs, cls, client_match))
66 return servers, clients
67
68
69def do_collect_tests(servers, clients):
70 def intersection(key, o1, o2):
71 """intersection of two collections.
72 collections are replaced with sets the first time"""
73 def cached_set(o, key):
74 v = o[key]
75 if not isinstance(v, set):
76 v = set(v)
77 o[key] = v
78 return v
79 return cached_set(o1, key) & cached_set(o2, key)
80
81 # each entry can be spec:impl (e.g. binary:accel)
82 def intersect_with_spec(key, o1, o2):
83 # store as set of (spec, impl) tuple
84 def cached_set(o):
85 def to_spec_impl_tuples(values):
86 for v in values:
87 spec, _, impl = v.partition(':')
88 yield spec, impl or spec
89 v = o[key]
90 if not isinstance(v, set):
91 v = set(to_spec_impl_tuples(set(v)))
92 o[key] = v
93 return v
94 for spec1, impl1 in cached_set(o1):
95 for spec2, impl2 in cached_set(o2):
96 if spec1 == spec2:
97 name = impl1 if impl1 == impl2 else '%s-%s' % (impl1, impl2)
98 yield name, impl1, impl2
99
100 def maybe_max(key, o1, o2, default):
101 """maximum of two if present, otherwise defult value"""
102 v1 = o1.get(key)
103 v2 = o2.get(key)
104 return max(v1, v2) if v1 and v2 else v1 or v2 or default
105
106 def filter_with_validkeys(o):
107 ret = {}
108 for key in VALID_JSON_KEYS:
109 if key in o:
110 ret[key] = o[key]
111 return ret
112
113 def merge_metadata(o, **ret):
114 for key in VALID_JSON_KEYS:
115 if key in o:
116 ret[key] = o[key]
117 return ret
118
119 for sv, cl in product(servers, clients):
120 for proto, proto1, proto2 in intersect_with_spec('protocols', sv, cl):
121 for trans, trans1, trans2 in intersect_with_spec('transports', sv, cl):
122 for sock in intersection('sockets', sv, cl):
123 yield {
124 'server': merge_metadata(sv, **{'protocol': proto1, 'transport': trans1}),
125 'client': merge_metadata(cl, **{'protocol': proto2, 'transport': trans2}),
126 'delay': maybe_max('delay', sv, cl, DEFAULT_DELAY),
127 'timeout': maybe_max('timeout', sv, cl, DEFAULT_TIMEOUT),
128 'protocol': proto,
129 'transport': trans,
130 'socket': sock
131 }
132
133
134def collect_tests(tests_dict, server_match, client_match):
135 sv, cl = collect_testlibs(tests_dict, server_match, client_match)
136 return list(do_collect_tests(sv, cl))