diff --git a/HISTORY b/HISTORY index 673fe8a..5aff123 100644 --- a/HISTORY +++ b/HISTORY @@ -2,6 +2,13 @@ History ======= +0.2.5 (2018-01-03) +------------------ +* Follow DUPLICATE status if BZ is CLOSED DUPLICATE +* Fix infinite loops when circular referenced BZ is decorated +* Added more status_resolution to BZ_CLOSED_STATUSES +* On decorators follow_duplicates will default to True (but will follow only for status DUPLICATE) + 0.2.4 (2017-12-22) ------------------ * Ignore BZ clones for different versions of satellite if there's a clone for current one @@ -14,6 +21,14 @@ History ------------------ * Bugzilla status to "ON_DEV" has been added to open status. +0.2.1 (2017-10-17) +------------------ +* Added default pickers to get version and config from environment variables + +0.2.0 (2017-07-25) +------------------ +* Added decorator for pytest parametrized tests + 0.1.8 (2017-03-02) ------------------ * implement subcommands scan and coverage @@ -21,11 +36,9 @@ History 0.1.7 (2017-02-14) ------------------ - * Handle None bug returned when missing bugzilla credentials * Better handle credentials when set in environment 0.1.6 (2017-02-10) ------------------ - * First official release. diff --git a/robozilla/bz.py b/robozilla/bz.py index 4620882..10cc4fe 100644 --- a/robozilla/bz.py +++ b/robozilla/bz.py @@ -69,12 +69,16 @@ def __init__(self, if self.follow_clones and CLONES_FIELD not in self.include_fields: self.include_fields.append(CLONES_FIELD) - if self.follow_duplicates and ( - DUPLICATES_FIELD not in self.include_fields): - self.include_fields.append(DUPLICATES_FIELD) + # DUPLICATES_FIELD is not included because it depends on `resolution` if self.follow_depends and DEPENDENT_FIELD not in self.include_fields: self.include_fields.append(DEPENDENT_FIELD) + # To hold the id that started the call + # also all already processed ids + # and avoid circular infinite loops + self.root_bug_id = None + self.processed_bugs = [] + def _get_query_include_fields(self): if self._always_use_all_fields: # always return a copy of the list @@ -102,11 +106,13 @@ def _get_clones(self, bug_ids): query[CLONES_FIELD] = bug_ids return _filter_none(bz_conn.query(query)) - def get_bug_data_in_bulk(self, bugs): + def get_bug_data_in_bulk(self, bugs, include_fields=None): """Get bug_data in bulk by given chunk in bugs bugs: a list of ids""" bz_conn = self._get_connection() - include_fields = self._get_query_include_fields() + include_fields = include_fields or self._get_query_include_fields() + # To follow duplicates in bulk mode `dupe_of` must be part of + # include_fields list result_bugs = list(_filter_none( bz_conn.getbugs(bugs, include_fields=include_fields))) chunk_data = {} @@ -137,16 +143,37 @@ def get_bug_data_in_bulk(self, bugs): return chunk_data - def get_bug_data(self, bug_id): + def get_bug_data(self, bug_id, include_fields=None, use_cache=True): """Get data for a single bug_id""" + if not bug_id: + return + + if self.root_bug_id is None: + self.root_bug_id = bug_id + + self.processed_bugs.append(bug_id) + + include_fields = include_fields or self.include_fields[:] bug_data = self._cache.get(str(bug_id)) - if not bug_data: + if not bug_data or not use_cache: bz_conn = self._get_connection() try: bug = bz_conn.getbug( bug_id, - include_fields=self.include_fields + include_fields=include_fields ) + + if self.follow_duplicates and getattr(bug, 'resolution') == 'DUPLICATE': # noqa + # in case of a DUPLICATE, call again taking the dupes + # but only if self.follow_duplicates is True + inc_fields = include_fields[:] # avoid shadowing + if DUPLICATES_FIELD not in inc_fields: + inc_fields.append(DUPLICATES_FIELD) + bug = bz_conn.getbug( + bug_id, + include_fields=inc_fields + ) + if bug is not None: bug_clones_data = [] if self.follow_clones: @@ -184,7 +211,12 @@ def set_bug_data_fields(self, bug, bugs_clones_data=None, bugs_clones_data = [] bug_data = {} - for field in self.include_fields: + + include_fields = self.include_fields[:] + if self.follow_duplicates and getattr(bug, 'resolution') == 'DUPLICATE': # noqa + include_fields.append(DUPLICATES_FIELD) + + for field in include_fields: if field in bug.__dict__: # field can exist with hasattr(bug, field), but not returned # by getattr, and if we use getattr(bug, field, None) @@ -229,27 +261,34 @@ def set_bug_data_fields(self, bug, bugs_clones_data=None, if not base_data_only: # getting dupes and clones are expensive and makes the elapsed time # to be 20x slow so they are by default disabled - if (DUPLICATES_FIELD in self.include_fields and - self.follow_duplicates): - if bug_data[DUPLICATES_FIELD]: + if self.follow_duplicates: + dupe_of = bug_data.get(DUPLICATES_FIELD) + if dupe_of and dupe_of not in self.processed_bugs: bug_data['duplicate_of'] = self.get_bug_data( - bug_data[DUPLICATES_FIELD]) + bug_data[DUPLICATES_FIELD], + use_cache=False + ) else: bug_data['duplicate_of'] = None if (CLONES_FIELD in self.include_fields and self.follow_clones): - if bug_data[CLONES_FIELD]: - bug_data['clone_of'] = self.get_bug_data( - bug_data[CLONES_FIELD]) + cf_clone_of = bug_data.get(CLONES_FIELD) + if cf_clone_of and cf_clone_of not in self.processed_bugs: + bug_data['clone_of'] = self.get_bug_data(cf_clone_of) else: bug_data['clone_of'] = None if (DEPENDENT_FIELD in self.include_fields and self.follow_depends): - if bug_data[DEPENDENT_FIELD]: + depends_on = [ + dep_id for dep_id in + bug_data.get(DEPENDENT_FIELD, []) + if dep_id not in self.processed_bugs + ] + if depends_on: bug_data['dependent_on'] = [] - for depend_on in bug_data[DEPENDENT_FIELD]: + for depend_on in depends_on: bug_data['dependent_on'].append( self.get_bug_data(depend_on)) else: diff --git a/robozilla/constants.py b/robozilla/constants.py index 521d8a9..0f8e179 100644 --- a/robozilla/constants.py +++ b/robozilla/constants.py @@ -45,9 +45,16 @@ 'MODIFIED', 'ON_DEV' ] + +# STATUS_RESOLUTION BZ_CLOSED_STATUSES = [ 'ON_QA', 'VERIFIED', 'RELEASE_PENDING', - 'CLOSED' + 'CLOSED', + 'CLOSED_NEXTRELEASE', + 'CLOSED_NOTABUG', + 'CLOSED_WORKSFORME', + 'CLOSED_ERRATA', + 'CLOSED_CURRENTRELEASE', ] diff --git a/robozilla/decorators/__init__.py b/robozilla/decorators/__init__.py index e469d35..9137e3b 100644 --- a/robozilla/decorators/__init__.py +++ b/robozilla/decorators/__init__.py @@ -15,6 +15,7 @@ BUGZILLA_ENVIRON_SAT_VERSION, BUGZILLA_ENVIRON_USER_NAME, BUGZILLA_ENVIRON_USER_PASSWORD_NAME, + BZ_CLOSED_STATUSES, BZ_OPEN_STATUSES, REDMINE_URL ) @@ -133,22 +134,34 @@ def rm_bug_is_open(bug_id, sat_version_picker=None, return True -def _to_float_version(regular_exp, possible_version): - """extract version using regular_exp againt possible_version string. - Returns None if extraction is not possible""" +def _extract_version(regular_exp, possible_version): + """Extract version using regular_exp against possible_version string. + Returns None if extraction is not possible + arguments defaults to None for backwards compatibility + :param regular_exp: A `re.compile` instance + :param possible_version: The string in the form sat-x.x.x or x.x.x + """ result = regular_exp.search(possible_version) if result: return float(result.group('version')) +# To get specifically the .z version as in sat-6.2.z _to_zstream_version = partial( - _to_float_version, re.compile(r'sat-(?P\d\.\d)\.z')) + _extract_version, re.compile(r'sat-(?P\d\.\d)\.z')) +# To get specifically versions as in sat-6.2.3 _to_downstream_version = partial( - _to_float_version, re.compile(r'sat-(?P\d\.\d)\.\d')) + _extract_version, re.compile(r'sat-(?P\d\.\d)\.\d')) +# to get untagged as in 6.2.9 _to_target_milestone_version = partial( - _to_float_version, re.compile(r'(?P\d\.\d)\.\d')) + _extract_version, re.compile(r'(?P\d\.\d)\.\d')) + +# match any version as in `sat-6.2.x` or `sat-6.2.0` or `6.2.9` +# will all result in `float(6.2)` +_to_float_version = partial( + _extract_version, re.compile(r'(?:sat-)*?(?P\d\.\d)\.\w*')) def _skip_downstream_condition(bug, sat_version_picker=None): @@ -217,21 +230,23 @@ def _check_skip_condition_for_one_bug(bug, consider_flags, # NEW, ASSIGNED, MODIFIED, POST if bug['status'] in BZ_OPEN_STATUSES: return True + # elif bug.get('status_resolution', bug['status']) in BZ_CLOSED_STATUSES: + # return False elif config.get('upstream'): return False - def skip_upstream_conditions(flags): + def skip_upstream_conditions(): """do not test bugs with whiteboard 'verified in upstream' in downstream until they are in 'CLOSED' state Verify all conditions are True, stopping evaluation when first condition is False """ - yield bug['status'] != 'CLOSED' - whiteboard = bug['whiteboard'] + yield bug['status'] not in BZ_CLOSED_STATUSES + whiteboard = bug.get('whiteboard', '') yield whiteboard yield 'verified in upstream' in whiteboard.lower() - return (all(skip_upstream_conditions(bug.get('flags', {}))) or + return (all(skip_upstream_conditions()) or (consider_flags and _skip_downstream_condition( bug, sat_version_picker))) @@ -254,57 +269,72 @@ def _check_skip_conditions_for_bug_and_clones(bug, consider_flags=True, :return: boolean indicating if it must be skipped or not """ + config = config or {} if bug is None: return False - all_bugs = chain([bug], bug.get('other_clones', {}).values()) - # If BZ was fixed in zstream of previous sat version it doesn't - # necessarily mean it was ported to future sat version immediately, - # thus we shouldn't rely on such closed BZ; - # filter out clones for previous versions if there's a clone for the same - # version as satellite - filtered_bugs = list(all_bugs) - if ( - len(filtered_bugs) > 1 - and sat_version_picker is not None - and sat_version_picker() is not None - and (not config or not config.get('upstream'))): - - def get_bug_versions(bug): - """Form a set of satellite versions affected by BZ""" - flags = bug.get('flags', {}) - positive_flags = [k for k, v in flags.items() if v == '+'] - zstream_versions = list(filter( - lambda version: version is not None, - map(_to_zstream_version, positive_flags) - )) - downstream_versions = list(filter( - lambda version: version is not None, - map(_to_downstream_version, positive_flags) - )) - return set(zstream_versions+downstream_versions) - - affected_clone_present = any( - float(sat_version_picker()) in get_bug_versions(bug_or_clone) - for bug_or_clone in filtered_bugs + + if bug.get('resolution') == 'DUPLICATE' and bug.get('duplicate_of') is not None: # noqa + # if is a DUPLICATE, unconsider the BZ and look only for the DUP and its clones # noqa + all_open = _check_skip_conditions_for_bug_and_clones( + bug.get('duplicate_of'), + consider_flags=consider_flags, + sat_version_picker=sat_version_picker, + config=config ) - if affected_clone_present: - # remove not actual bugs from list - filtered_bugs = [ - bug_or_clone for bug_or_clone in filtered_bugs - if float(sat_version_picker()) in get_bug_versions( - bug_or_clone) - ] - - skip_results = ( - _check_skip_condition_for_one_bug( - bug_or_clone, consider_flags, sat_version_picker, config + else: + # If not DUPLICATE then look to all clones and chain results + all_bugs = chain([bug], bug.get('other_clones', {}).values()) + # If BZ was fixed in zstream of previous sat version it doesn't + # necessarily mean it was ported to future sat version immediately, + # thus we shouldn't rely on such closed BZ; + # filter out clones for previous versions if there's a clone for the + # same version as satellite + filtered_bugs = list(all_bugs) + if ( + len(filtered_bugs) > 1 + and sat_version_picker is not None + and sat_version_picker() is not None + and (not config or not config.get('upstream'))): + + def get_bug_versions(bug): + """Form a set of satellite versions affected by BZ""" + flags = bug.get('flags', {}) + positive_flags = [k for k, v in flags.items() if v == '+'] + zstream_versions = list(filter( + lambda version: version is not None, + map(_to_zstream_version, positive_flags) + )) + downstream_versions = list(filter( + lambda version: version is not None, + map(_to_downstream_version, positive_flags) + )) + return set(zstream_versions + downstream_versions) + + affected_clone_present = any( + _to_float_version(sat_version_picker()) + in get_bug_versions(bug_or_clone) + for bug_or_clone in filtered_bugs + ) + if affected_clone_present: + # remove not actual bugs from list + filtered_bugs = [ + bug_or_clone for bug_or_clone in filtered_bugs + if _to_float_version(sat_version_picker()) + in get_bug_versions(bug_or_clone) + ] + + skip_results = ( + _check_skip_condition_for_one_bug( + bug_or_clone, consider_flags, sat_version_picker, config + ) + for bug_or_clone in filtered_bugs ) - for bug_or_clone in filtered_bugs - ) - all_open = all(skip_results) + all_open = all(skip_results) + if all_open: LOGGER.debug('Bugzilla {0} is open'.format(bug.get('id'))) + return all_open @@ -349,7 +379,8 @@ def _get_bugzilla_bug(bug_id, bz_credentials=None): 'id', 'status', 'whiteboard', 'flags', 'resolution', 'target_milestone' ], - follow_clones=True + follow_clones=True, + follow_duplicates=True # only when resolution is 'DUPLICATE' ) _bugzilla[bug_id] = reader.get_bug_data(bug_id) if not bz_credentials: @@ -358,6 +389,7 @@ def _get_bugzilla_bug(bug_id, bz_credentials=None): 'Unauthenticated call made to BZ API, no flags data will ' 'be available' ) + return _bugzilla[bug_id] diff --git a/setup.py b/setup.py index 790a3fb..41e0762 100755 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setup( name='robozilla', - version='0.2.4', + version='0.2.5', packages=packages, url='https://github.com/ldjebran/robozilla', license='GNU General Public License v3 (GPLv3)', diff --git a/tests/base.py b/tests/base.py index adc9991..c661067 100644 --- a/tests/base.py +++ b/tests/base.py @@ -6,6 +6,15 @@ files_path = os.path.join(this_path, 'files') +class DummyConnection(object): + def __init__(self, cache): + self.cache = cache + + def getbug(self, bug_id, **kw): + print(self.cache) + return self.cache[str(bug_id)] + + class BZReaderForTest(BZReader): _cache_data = None @@ -17,7 +26,7 @@ def __init__(self, *args, **kwargs): def _get_connection(self): """This object has not to connect to bugzilla, work only with cache""" - return None + return DummyConnection(self._cache) def get_bug_data_in_bulk(self, bugs): bugs_data = {} diff --git a/tests/data.py b/tests/data.py index 1462c04..27a381b 100644 --- a/tests/data.py +++ b/tests/data.py @@ -1,41 +1,180 @@ # , 981639, 1372372 -cache_data = {'1123360': {'status': 'CLOSED', - 'status_resolution': 'CLOSED_ERRATA', - 'whiteboard': '', - 'flags': {'sat-6.1.0': '+'}, - 'resolution': 'ERRATA', 'id': '1123360'}, - '1405428': {'status': 'CLOSED', - 'status_resolution': 'CLOSED_DUPLICATE', - 'whiteboard': '', - 'flags': {'sat-6.3.0': '?', 'sat-6.2.z': '?'}, - 'resolution': 'DUPLICATE', 'id': '1405428'}, - '1402826': {'status': 'CLOSED', - 'status_resolution': 'CLOSED_DUPLICATE', - 'whiteboard': '', - 'flags': {'sat-6.2.z': '?'}, - 'resolution': 'DUPLICATE', - 'id': '1402826'}, - '1328925': {'status': 'CLOSED', - 'status_resolution': 'CLOSED_ERRATA', - 'whiteboard': '', - 'flags': {'sat-6.2.0': '+'}, - 'resolution': 'ERRATA', - 'id': '1328925'}, - '1333805': {'status': 'CLOSED', - 'status_resolution': 'CLOSED_ERRATA', - 'whiteboard': '', - 'flags': {'sat-6.2.0': '+'}, - 'resolution': 'ERRATA', - 'id': '1333805'}, - '1219610': {'status': 'CLOSED', - 'status_resolution': 'CLOSED_WONTFIX', - 'whiteboard': '', - 'flags': {'sat-backlog': '+'}, - 'resolution': 'WONTFIX', - 'id': '1219610'}, - '1461026': {'status': 'NEW', - 'flags': {'sat-6.2.0': '+'}, - 'id': '1461026'} - } +cache_data = { + '1123360': {'status': 'CLOSED', + 'status_resolution': 'CLOSED_ERRATA', + 'whiteboard': '', + 'flags': {'sat-6.1.0': '+'}, + 'resolution': 'ERRATA', 'id': '1123360'}, + '1405428': {'status': 'CLOSED', + 'status_resolution': 'CLOSED_DUPLICATE', + 'whiteboard': '', + 'flags': {'sat-6.3.0': '?', 'sat-6.2.z': '?'}, + 'resolution': 'DUPLICATE', 'id': '1405428'}, + '1402826': {'status': 'CLOSED', + 'status_resolution': 'CLOSED_DUPLICATE', + 'whiteboard': '', + 'flags': {'sat-6.2.z': '?'}, + 'resolution': 'DUPLICATE', + 'id': '1402826'}, + '1328925': {'status': 'CLOSED', + 'status_resolution': 'CLOSED_ERRATA', + 'whiteboard': '', + 'flags': {'sat-6.2.0': '+'}, + 'resolution': 'ERRATA', + 'id': '1328925'}, + '1333805': {'status': 'CLOSED', + 'status_resolution': 'CLOSED_ERRATA', + 'whiteboard': '', + 'flags': {'sat-6.2.0': '+'}, + 'resolution': 'ERRATA', + 'id': '1333805'}, + '1219610': {'status': 'CLOSED', + 'status_resolution': 'CLOSED_WONTFIX', + 'whiteboard': '', + 'flags': {'sat-backlog': '+'}, + 'resolution': 'WONTFIX', + 'id': '1219610'}, + '1461026': {'status': 'NEW', + 'flags': {'sat-6.2.0': '+'}, + 'id': '1461026'}, + '9999999': {'status': 'VERIFIED', + 'flags': {'sat-6.2.0': '+'}, + 'id': '9999999'}, + '1377676': { + 'status': 'CLOSED', + 'other_clones': {}, + 'duplicate_of': { + 'status': 'CLOSED', + 'other_clones': {}, + 'duplicate_of': { + 'status': 'CLOSED', + 'other_clones': { + '1426382': { + 'status': 'VERIFIED', + 'other_clones': {}, + 'status_resolution': 'VERIFIED_', + 'target_milestone': 'GA', + 'whiteboard': '', + 'dupe_of': None, + 'flags': {'sat-6.3.0': '+'}, + 'cf_clone_of': 1351464, + 'depends_on': [1351464], + 'clones': [], + 'resolution': '', + 'id': '1426382' + } + }, + 'duplicate_of': None, + 'status_resolution': 'CLOSED_ERRATA', + 'target_milestone': '6.2.9', + 'dependent_on': None, + 'whiteboard': '', + 'dupe_of': None, + 'flags': {'sat-6.2.z': '+'}, + 'cf_clone_of': None, + 'depends_on': [], + 'clones': [ + { + 'status': 'VERIFIED', + 'other_clones': {}, + 'status_resolution': + 'VERIFIED_', + 'target_milestone': 'GA', + 'whiteboard': '', + 'dupe_of': None, + 'flags': {'sat-6.3.0': '+'}, + 'cf_clone_of': 1351464, + 'depends_on': [1351464], + 'clones': [], + 'resolution': '', + 'id': '1426382' + } + ], + 'resolution': 'ERRATA', + 'id': '1351464', + 'clone_of': None + }, + 'status_resolution': 'CLOSED_DUPLICATE', + 'target_milestone': 'Unspecified', + 'dependent_on': None, + 'whiteboard': '', + 'dupe_of': 1351464, + 'flags': {}, + 'cf_clone_of': None, + 'depends_on': [], + 'clones': [], + 'resolution': 'DUPLICATE', + 'id': '1376046', + 'clone_of': None + }, + 'status_resolution': 'CLOSED_DUPLICATE', + 'target_milestone': 'Unspecified', + 'dependent_on': None, + 'whiteboard': '', + 'dupe_of': 1376046, + 'flags': {'sat-6.3.0': '?'}, + 'cf_clone_of': None, + 'depends_on': [], + 'clones': [], + 'resolution': 'DUPLICATE', + 'id': '1377676', + 'clone_of': None + }, + '8888888': { + 'status_resolution': 'CLOSED_DUPLICATE', + 'resolution': 'DUPLICATE', + 'status': 'CLOSED', + 'dupe_of': 7777777, + 'cf_dupe_of': 7777777, + 'target_milestone': 'Unspecified', + 'duplicate_of': { + 'id': '7777777', + 'status': 'ASSIGNED', + 'flags': {'sat-6.2.z': '+'}, + 'target_milestone': '6.2.9', + }, + 'flags': {'sat-6.2.z': '+'} + }, + '7777777': { + 'id': '7777777', + 'status': 'ASSIGNED', + 'flags': {'sat-6.2.z': '+'}, + 'target_milestone': '6.2.9', + }, + '5555555': { + 'id': '5555555', + 'status': 'CLOSED', + 'resolution': 'NEXTRELEASE', + 'status_resolution': 'CLOSED_NEXTRELEASE', + 'flags': {'sat-6.3.0': '?'}, + 'target_milestone': 'Unspecified', + }, + '4444444': { + 'id': '4444444', + 'status': 'CLOSED', + 'resolution': 'NOTABUG', + 'status_resolution': 'CLOSED_NOTABUG', + 'flags': {'sat-6.3.0': '?'}, + 'target_milestone': 'Unspecified', + }, + '3333333': { + 'id': '3333333', + 'status': 'CLOSED', + 'resolution': 'WORKSFORME', + 'status_resolution': 'CLOSED_WORKSFORME', + 'flags': {'sat-6.3.0': '?'}, + 'target_milestone': 'Unspecified', + }, + '2222222': { + 'id': '2222222', + 'status': 'CLOSED', + 'resolution': 'ERRATA', + 'status_resolution': 'CLOSED_ERRATA', + 'flags': {'sat-6.2.z': '+'}, + 'target_milestone': '6.2.9', + }, + + +} diff --git a/tests/test_decorators.py b/tests/test_decorators.py index 2ce7e26..e1cc06b 100644 --- a/tests/test_decorators.py +++ b/tests/test_decorators.py @@ -1,6 +1,8 @@ import pytest import robozilla -from robozilla.decorators import pytest_skip_if_bug_open, skip_if_bug_open +from robozilla.decorators import ( + pytest_skip_if_bug_open, skip_if_bug_open, bz_bug_is_open +) from .data import cache_data # MOCK BZ READER to avoid connection to bugzilla @@ -33,3 +35,48 @@ def test_default_pickers(): def test_default_pickers_for_pytest(): print('this should never run') assert 1 == 2 + + +@skip_if_bug_open('bugzilla', 9999999) +def test_closed_runs(): + assert 2 == 2 + + +@skip_if_bug_open('bugzilla', 5555555) +def test_closed_next_release_runs(): + assert 2 == 2 + + +@skip_if_bug_open('bugzilla', 4444444) +def test_closed_not_a_bug_runs(): + assert 2 == 2 + + +@skip_if_bug_open('bugzilla', 3333333) +def test_closed_worksforme_runs(): + assert 2 == 2 + + +@skip_if_bug_open('bugzilla', 2222222) +def test_closed_errata_runs(): + assert 2 == 2 + + +def test_all_open(): + open_bugs = [ + int(key) for key, val in cache_data.items() + if val.get('status_resolution', val['status']) + in robozilla.constants.BZ_OPEN_STATUSES + ] + for bug_id in open_bugs: + assert bz_bug_is_open(bug_id) is True + + +def test_all_closed(): + closed_bugs = [ + int(key) for key, val in cache_data.items() + if val.get('status_resolution', val['status']) + in robozilla.constants.BZ_CLOSED_STATUSES + ] + for bug_id in closed_bugs: + assert bz_bug_is_open(bug_id) is False diff --git a/tests/test_decorators_dupes.py b/tests/test_decorators_dupes.py new file mode 100644 index 0000000..b1fa4f0 --- /dev/null +++ b/tests/test_decorators_dupes.py @@ -0,0 +1,41 @@ +import robozilla +from robozilla.decorators import skip_if_bug_open +from .data import cache_data + +# MOCK BZ READER to avoid connection to bugzilla +from .base import BZReaderForTest +BZReaderForTest._cache_data = cache_data +robozilla.decorators.BZReader = BZReaderForTest + + +@skip_if_bug_open( + 'bugzilla', + 1377676, + sat_version_picker=lambda: '6.2.9', + config_picker=lambda: {'bz_credentials': {'user': '', 'password': ''}} +) +def test_closed_duplicate_runs(): + """ + 1377676 is closed as DUPLICATE + the duplicate BZ is also a DUPLICATE of another + the final BZ in the chain is CLOSED ERRATA + so the test runs + """ + assert 1 == 1 + + +@skip_if_bug_open( + 'bugzilla', + 8888888, + sat_version_picker=lambda: '6.2.9', + config_picker=lambda: {'bz_credentials': {'user': '', 'password': ''}} +) +def test_closed_duplicate_with_opened_dupe_never_run(): + """ + Bz 8888888 is flagged for 6.2.z + CLOSED DUPLICATE + but it is DUPLICATE of 7777777 + which is flagged for 6.2.z + + and is ASSIGNED so.. + This test should be SKIPPED as version here is 6.2.9 + """ + assert 1 == 2 diff --git a/tests/test_parse.py b/tests/test_parse.py index 5f7d607..ea8c530 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -6,8 +6,7 @@ def test_parse_simple(): - bugs_set = {'1123360', '1405428', '1402826', '1328925', '1333805', - '1219610', '1461026'} + bugs_set = set(cache_data.keys()) bz_reader = BZReaderForTest() bz_reader.set_cache(cache_data)