Skip to content

Commit 9ca5dcd

Browse files
committed
adapt bugzilla plugin for rhevm-qe usage
1. Now we take into consideration engine and storage 2. Bugzilla marker looks like 2.1. @bz({'bz-id': {'engine': [], 'storage': []}}) bz affects all engines and all storages 2.2. @bz({'bz-id': {'engine': ['cli'], 'storage': []}}) bz afects CLI and all storages 2.3. @bz({'bz-id': {'engine': ['cli', 'rest'], 'storage': ['iscsi']}}) bz affects rest and cli and iscsi
1 parent 12c31ff commit 9ca5dcd

File tree

4 files changed

+194
-45
lines changed

4 files changed

+194
-45
lines changed

pytest_marker_bugzilla.py

Lines changed: 128 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os
66
import pytest
77
import re
8+
import logging
89
from distutils.version import LooseVersion
910
from functools import wraps
1011
"""This plugin integrates pytest with bugzilla
@@ -56,6 +57,7 @@ def test_something():
5657
Eric L. Sammons
5758
Milan Falešník
5859
"""
60+
logger = logging.getLogger(__name__)
5961
_bugs_pool = {} # Cache bugs for greater speed
6062
_default_looseversion_fields = "fixed_in,target_release"
6163

@@ -149,45 +151,117 @@ def add_bug_to_cache(self, bug_obj):
149151
"""For test purposes only"""
150152
_bugs_pool[bug_obj.id] = BugWrapper(bug_obj, self.loose)
151153

154+
def _should_skip_due_to_api(self, item, engines):
155+
156+
if not engines:
157+
return True
158+
159+
return item.parent.obj.api in engines
160+
161+
def _should_skip_due_to_storage(self, item, storages):
162+
163+
if not storages:
164+
return True
165+
166+
return item.parent.obj.storage in storages
167+
168+
def _should_skip_due_to_ppc(self, item, is_ppc):
169+
return is_ppc is None or is_ppc is True
170+
171+
def _should_skip(self, item, bz_mark):
172+
173+
is_ppc_affected = self._should_skip_due_to_ppc(
174+
item, bz_mark.get('ppc')
175+
)
176+
177+
is_api_affected = self._should_skip_due_to_api(
178+
item, bz_mark.get('engine')
179+
)
180+
181+
is_storage_affected = self._should_skip_due_to_storage(
182+
item, bz_mark.get('storage')
183+
)
184+
185+
if is_api_affected and is_storage_affected and is_ppc_affected:
186+
return True
187+
188+
return False
189+
152190
def pytest_runtest_setup(self, item):
153191
"""
154192
Run test setup.
155193
:param item: test being run.
156194
"""
195+
157196
if "bugzilla" not in item.keywords:
158197
return
159-
bugs = item.funcargs["bugs"]
160-
will_skip = True
198+
199+
bugs_in_cache = item.funcargs["bugs_in_cache"]
200+
bugzilla_marker_related_to_case = item.get_marker('bugzilla')
201+
bugs_related_to_case = bugzilla_marker_related_to_case.args[0]
202+
bugs_objs = []
203+
204+
for bug_id in bugs_related_to_case.keys():
205+
bugs_objs.append(bugs_in_cache[bug_id])
206+
161207
skippers = []
162-
for bug in bugs.bugs_gen:
163-
if bug.status not in ["NEW", "ASSIGNED", "ON_DEV"]:
164-
will_skip = False
165-
else:
166-
skippers.append(bug)
208+
209+
for bz in bugs_objs:
210+
for bug in bz.bugs_gen:
211+
if bug.status == "CLOSED":
212+
logger.info(
213+
"Id:{0}; Status:{1}; Resolution:{2}; [RUNNING]".format(
214+
bug.id, bug.status, bug.resolution
215+
)
216+
)
217+
elif bug.status in ["VERIFIED", "ON_QA"]:
218+
logger.info(
219+
"Id: {0}; Status: {1}; [RUNNING]".format(
220+
bug.id, bug.status
221+
)
222+
)
223+
elif self._should_skip(
224+
item, bugs_related_to_case[str(bug.id)]
225+
):
226+
skippers.append(bug)
227+
logger.info(
228+
"Id: {0}; Status: {1}; [SKIPPING]".format(
229+
bug.id, bug.status
230+
)
231+
)
232+
167233
url = "{0}?id=".format(
168234
self.bugzilla.url.replace("xmlrpc.cgi", "show_bug.cgi"),
169235
)
170236

171-
if will_skip:
172-
pytest.skip(
173-
"Skipping this test because all of these assigned bugs:\n"
174-
"{0}".format(
175-
"\n".join(
176-
[
177-
"{0} {1}{2}".format(bug.status, url, bug.id)
178-
for bug in skippers
179-
]
180-
)
237+
if skippers:
238+
skipping_summary = (
239+
"Skipping due to: "
240+
"\n".join(
241+
[
242+
"Bug summary: {0} Status: {1} URL: {2}{3}".format(
243+
bug.summary, bug.status, url, bug.id
244+
)
245+
for bug in skippers
246+
]
247+
)
248+
)
249+
250+
logger.info(
251+
"Test case {0} will be skipped due to:\n {1}".format(
252+
item.name, skipping_summary
181253
)
182254
)
183255

256+
pytest.skip(skipping_summary)
257+
184258
marker = item.get_marker('bugzilla')
185259
xfail = kwargify(marker.kwargs.get("xfail_when", lambda: False))
186260
skip = kwargify(marker.kwargs.get("skip_when", lambda: False))
187261
if skip:
188-
self.evaluate_skip(skip, bugs)
262+
self.evaluate_skip(skip, bugs_in_cache)
189263
if xfail:
190-
xfailed = self.evaluate_xfail(xfail, bugs)
264+
xfailed = self.evaluate_xfail(xfail, bugs_in_cache)
191265
if xfailed:
192266
item.add_marker(
193267
pytest.mark.xfail(
@@ -204,25 +278,33 @@ def pytest_runtest_setup(self, item):
204278
)
205279

206280
def evaluate_skip(self, skip, bugs):
207-
for bug in bugs.bugs_gen:
208-
context = {"bug": bug}
209-
if self.version:
210-
context["version"] = LooseVersion(self.version)
211-
if skip(**context):
212-
pytest.skip(
213-
"Skipped due to a given condition: {0}".format(
214-
inspect.getsource(skip)
281+
bugs_obj = bugs.values()
282+
283+
for bug_obj in bugs_obj:
284+
for bz in bug_obj.bugs_gen:
285+
context = {"bug": bz}
286+
if self.version:
287+
context["version"] = LooseVersion(self.version)
288+
if skip(**context):
289+
pytest.skip(
290+
"Skipped due to a given condition: {0}".format(
291+
inspect.getsource(skip)
292+
)
215293
)
216-
)
217294

218295
def evaluate_xfail(self, xfail, bugs):
219296
results = []
220-
for bug in bugs.bugs_gen:
221-
context = {"bug": bug}
222-
if self.version:
223-
context["version"] = LooseVersion(self.version)
224-
if xfail(**context):
225-
results.append(bug)
297+
298+
# for bug in bugs.bugs_gen:
299+
bugs_obj = bugs.values()
300+
301+
for bug_obj in bugs_obj:
302+
for bz in bug_obj.bugs_gen:
303+
context = {"bug": bz}
304+
if self.version:
305+
context["version"] = LooseVersion(self.version)
306+
if xfail(**context):
307+
results.append(bz)
226308
return results
227309

228310
def pytest_collection_modifyitems(self, session, config, items):
@@ -233,12 +315,17 @@ def pytest_collection_modifyitems(self, session, config, items):
233315
filter(lambda i: i.get_marker("bugzilla") is not None, items)
234316
):
235317
marker = item.get_marker('bugzilla')
236-
# (O_O) for caching
237-
bugs = tuple(sorted(set(map(int, marker.args))))
238-
if bugs not in cache:
239-
reporter.write(".")
240-
cache[bugs] = BugzillaBugs(self.bugzilla, self.loose, *bugs)
241-
item.funcargs["bugs"] = cache[bugs]
318+
bugs = marker.args[0]
319+
bugs_ids = bugs.keys()
320+
321+
for bz_id in bugs_ids:
322+
if bz_id not in cache:
323+
reporter.write(".")
324+
cache[bz_id] = BugzillaBugs(
325+
self.bugzilla, self.loose, bz_id
326+
)
327+
328+
item.funcargs["bugs_in_cache"] = cache
242329
reporter.write(
243330
"\nChecking for bugzilla-related tests has finished\n", bold=True,
244331
)
@@ -323,6 +410,7 @@ def pytest_configure(config):
323410
324411
:param config: configuration object
325412
"""
413+
326414
config.addinivalue_line(
327415
"markers",
328416
"bugzilla(*bug_ids, **guards): Bugzilla integration",

tests/conftest.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,49 @@
44

55
FAKE_BUGS = {
66
"1": {
7-
"id": 1,
7+
"id": '1',
88
"version": None,
99
"fixed_in": None,
1010
"status": 'NEW',
1111
"target_release": None,
12+
"resolution": 'foo',
13+
"summary": 'ONE',
1214
},
1315
"2": {
14-
"id": 2,
16+
"id": '2',
17+
"version": None,
18+
"fixed_in": None,
19+
"status": 'ON_QA',
20+
"target_release": None,
21+
"resolution": 'foo',
22+
"summary": 'TWO',
23+
},
24+
"3": {
25+
"id": '3',
26+
"version": None,
27+
"fixed_in": None,
28+
"status": 'VERIFIED',
29+
"target_release": None,
30+
"resolution": 'foo',
31+
"summary": 'THREE',
32+
},
33+
"4": {
34+
"id": '4',
1535
"version": None,
1636
"fixed_in": None,
1737
"status": 'CLOSED',
1838
"target_release": None,
39+
"resolution": 'DUPLICATE',
40+
"summary": 'FOUR',
41+
},
42+
"5": {
43+
"id": '5',
44+
"version": None,
45+
"fixed_in": None,
46+
"status": 'MODIFIED',
47+
"target_release": None,
48+
"resolution": 'foo',
49+
"summary": 'FIVE',
1950
},
2051
}
2152

tests/test_bugzilla.py.in

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ import pytest
99
@pytest.mark.nondestructive
1010
class TestNothing(object):
1111

12-
@pytest.mark.bugzilla('1')
12+
@pytest.mark.bugzilla({'1': {}})
1313
def test_new_bz(self):
1414
assert(os.path.exists('/etcccc'))
1515

16-
@pytest.mark.bugzilla('2')
16+
@pytest.mark.bugzilla({'2': {}})
1717
def test_closed_bz(self):
1818
assert(os.path.exists('/etc'))
1919

20-
@pytest.mark.bugzilla('2')
20+
@pytest.mark.bugzilla({'2': {}})
2121
def test_closed_bz_with_failure(self):
2222
assert(os.path.exists('/etcccc'))
2323

@@ -26,3 +26,15 @@ class TestNothing(object):
2626

2727
def test_fail_without_bugzilla(self):
2828
assert(os.path.exists('/etc123'))
29+
30+
@pytest.mark.bugzilla({'3': {}})
31+
def test_verified_bz(self):
32+
assert(os.path.exists('/etc'))
33+
34+
@pytest.mark.bugzilla({'4': {}})
35+
def test_closed_bz_2(self):
36+
assert(os.path.exists('/etc'))
37+
38+
@pytest.mark.bugzilla({'5': {}})
39+
def test_modified_bz(self):
40+
assert(os.path.exists('/etc'))

tests/test_nothing.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,21 @@ def test_fail_without_bugzilla(self):
103103
No decorator, failing test-case, it should fail.
104104
"""
105105
self._assert_result('F', 'test_fail_without_bugzilla')
106+
107+
def test_verified_bz(self):
108+
"""
109+
verified bug, passing test-case, it should pass.
110+
"""
111+
self._assert_result('.', 'test_verified_bz')
112+
113+
def test_closed_bz_2(self):
114+
"""
115+
closed bug, passing test-case, it should pass.
116+
"""
117+
self._assert_result('.', 'test_closed_bz_2')
118+
119+
def test_modified_bz(self):
120+
"""
121+
modified bug, test-case should skip.
122+
"""
123+
self._assert_result('s', 'test_modified_bz')

0 commit comments

Comments
 (0)