apache-ignite

Форк
0
242 строки · 8.8 Кб
1
# Licensed to the Apache Software Foundation (ASF) under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#    http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15

16
"""
17
Module contains useful test decorators.
18
"""
19

20
import copy
21
from collections.abc import Iterable
22

23
from ducktape.cluster.cluster_spec import ClusterSpec
24
from ducktape.mark._mark import Ignore, Mark, _inject
25

26
from ignitetest.utils.version import IgniteVersion
27
from ignitetest.utils.ignite_test import IgniteTestContext
28

29

30
class IgnoreIf(Ignore):
31
    """
32
    Ignore test if version or global parameters correspond to condition.
33
    """
34
    def __init__(self, condition, variable_name):
35
        super().__init__()
36
        self.condition = condition
37
        self.variable_name = variable_name
38

39
    def apply(self, seed_context, context_list):
40
        assert len(context_list) > 0, "ignore if decorator is not being applied to any test cases"
41

42
        for ctx in context_list:
43
            if self.variable_name in ctx.injected_args:
44
                version = ctx.injected_args[self.variable_name]
45
                assert isinstance(version, str), "'%s'n injected args must be a string" % (self.variable_name,)
46
                ctx.ignore = ctx.ignore or self.condition(IgniteVersion(version), ctx.globals)
47

48
        return context_list
49

50
    def __eq__(self, other):
51
        return super().__eq__(other) and self.condition == other.condition
52

53

54
class IgniteVersionParametrize(Mark):
55
    """
56
    Parametrize function with ignite_version
57
    """
58
    def __init__(self, *args, version_prefix):
59
        """
60
        :param args: Can be string, tuple of strings or iterable of them.
61
        :param version_prefix: prefix for variable to inject into test function.
62
        """
63
        self.versions = list(args)
64
        self.version_prefix = version_prefix
65

66
    def apply(self, seed_context, context_list):
67
        if 'ignite_versions' in seed_context.globals:
68
            ver = seed_context.globals['ignite_versions']
69
            if isinstance(ver, str):
70
                self.versions = [ver]
71
            elif isinstance(ver, Iterable):
72
                self.versions = list(ver)
73
            else:
74
                raise AssertionError("Expected string or iterable as parameter in ignite_versions, "
75
                                     "%s of type %s passed" % (ver, type(ver)))
76

77
        self.versions = self._inject_global_project(self.versions, seed_context.globals.get("project"))
78

79
        new_context_list = []
80
        if context_list:
81
            for ctx in context_list:
82
                for version in self.versions:
83
                    if self._check_injected(ctx):
84
                        continue
85

86
                    new_context_list.insert(0, self._prepare_new_ctx(version, seed_context, ctx))
87
        else:
88
            for version in self.versions:
89
                new_context_list.insert(0, self._prepare_new_ctx(version, seed_context))
90

91
        return new_context_list
92

93
    @staticmethod
94
    def _inject_global_project(version, project):
95
        if isinstance(version, (list, tuple)):
96
            return list(map(lambda v: IgniteVersionParametrize._inject_global_project(v, project), version))
97

98
        if (version.lower() == "dev" or version[0].isdigit()) and project:
99
            version = "%s-%s" % (project, version)
100

101
        return version
102

103
    def _prepare_new_ctx(self, version, seed_context, ctx=None):
104
        injected_args = dict(ctx.injected_args) if ctx and ctx.injected_args else {}
105

106
        if isinstance(version, (list, tuple)) and len(version) >= 2:
107
            for idx, ver in enumerate(version):
108
                injected_args["%s_%s" % (self.version_prefix, idx + 1)] = ver
109
        elif isinstance(version, str):
110
            injected_args[self.version_prefix] = version
111
        else:
112
            raise AssertionError("Expected string or iterable of size greater than 2 as element in ignite_versions,"
113
                                 "%s of type %s passed" % (version, type(version)))
114

115
        injected_fun = _inject(**injected_args)(seed_context.function)
116

117
        return seed_context.copy(function=injected_fun, injected_args=injected_args)
118

119
    def _check_injected(self, ctx):
120
        if ctx.injected_args:
121
            for arg_name in ctx.injected_args.keys():
122
                if arg_name.startswith(self.version_prefix):
123
                    return True
124

125
        return False
126

127
    @property
128
    def name(self):
129
        """
130
        This function should return "PARAMETRIZE" string in order to ducktape's method parametrization works.
131
        Should be fixed after apropriate patch in ducktape will be merged.
132
        """
133
        return "PARAMETRIZE"
134

135
    def __eq__(self, other):
136
        return super().__eq__(other) and self.versions == other.versions
137

138

139
CLUSTER_SPEC_KEYWORD = "cluster_spec"
140
CLUSTER_SIZE_KEYWORD = "num_nodes"
141

142

143
class ParametrizableClusterMetadata(Mark):
144
    """Provide a hint about how a given test will use the cluster."""
145

146
    def __init__(self, **kwargs):
147
        self.metadata = copy.copy(kwargs)
148

149
    @property
150
    def name(self):
151
        return "PARAMETRIZABLE_RESOURCE_HINT_CLUSTER_USE"
152

153
    def apply(self, seed_context, context_list):
154
        assert len(context_list) > 0, "parametrizable cluster use annotation is not being applied to any test cases"
155

156
        cluster_size_param = self._extract_cluster_size(seed_context)
157

158
        for ctx in context_list:
159
            if cluster_size_param:
160
                self._modify_metadata(cluster_size_param)
161

162
            if not ctx.cluster_use_metadata:
163
                ctx.cluster_use_metadata = self.metadata
164

165
        return list(map(lambda _ctx: IgniteTestContext.resolve(_ctx), context_list))
166

167
    @staticmethod
168
    def _extract_cluster_size(seed_context):
169
        cluster_size = seed_context.globals.get('cluster_size')
170

171
        if cluster_size is None:
172
            return None
173

174
        res = int(cluster_size) if isinstance(cluster_size, str) else cluster_size
175

176
        if not isinstance(res, int):
177
            raise ValueError(f"Expected string or int param, {cluster_size} of {type(cluster_size)} passed instead.")
178

179
        if res <= 0:
180
            raise ValueError(f"Expected cluster_size greater than 0, {cluster_size} passed instead.")
181

182
        return res
183

184
    def _modify_metadata(self, new_size):
185
        cluster_spec = self.metadata.get(CLUSTER_SPEC_KEYWORD)
186
        cluster_size = self.metadata.get(CLUSTER_SIZE_KEYWORD)
187

188
        if cluster_spec is not None and not cluster_spec.empty():
189
            node_spec = next(iter(cluster_spec))
190
            self.metadata[CLUSTER_SPEC_KEYWORD] = ClusterSpec.from_nodes([node_spec] * new_size)
191
        elif cluster_size is not None:
192
            self.metadata[CLUSTER_SIZE_KEYWORD] = new_size
193

194

195
def ignite_versions(*args, version_prefix="ignite_version"):
196
    """
197
    Decorate test function to inject ignite versions. Versions will be overriden by globals "ignite_versions" param.
198
    :param args: Can be string, tuple of strings or iterable of them.
199
    :param version_prefix: prefix for variable to inject into test function.
200
    """
201
    def parametrizer(func):
202
        Mark.mark(func, IgniteVersionParametrize(*args, version_prefix=version_prefix))
203

204
        return func
205
    return parametrizer
206

207

208
def ignore_if(condition, *, variable_name='ignite_version'):
209
    """
210
    Mark decorated test method as IGNORE if version or global parameters correspond to condition.
211

212
    :param condition: function(IgniteVersion, Globals) -> bool
213
    :param variable_name: version variable name
214
    """
215
    def ignorer(func):
216
        Mark.mark(func, IgnoreIf(condition, variable_name))
217
        return func
218

219
    return ignorer
220

221

222
def cluster(**kwargs):
223
    """Test method decorator used to provide hints about how the test will use the given cluster.
224

225
    :Keywords:
226

227
      - ``num_nodes`` provide hint about how many nodes the test will consume
228
      - ``cluster_spec`` provide hint about how many nodes of each type the test will consume
229
    """
230
    def cluster_use_metadata_adder(func):
231
        def extended_test(self, *args, **kwargs):
232
            self.test_context.before()
233
            test_result = func(self, *args, **kwargs)
234
            return self.test_context.after(test_result)
235

236
        extended_test.__dict__.update(**func.__dict__)
237
        extended_test.__name__ = func.__name__
238

239
        Mark.mark(extended_test, ParametrizableClusterMetadata(**kwargs))
240
        return extended_test
241

242
    return cluster_use_metadata_adder
243

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.