diff --git a/elastic_recheck/bot.py b/elastic_recheck/bot.py index ebc4cde2..07302ed3 100755 --- a/elastic_recheck/bot.py +++ b/elastic_recheck/bot.py @@ -144,8 +144,7 @@ class RecheckWatch(threading.Thread): change_id = "%s,%s" % (change, rev) project = event['change']['project'] try: - bug_numbers = classifier.classify(change, rev, - event['comment']) + bug_numbers = classifier.classify(change, rev) if not bug_numbers: self._read(event) else: diff --git a/elastic_recheck/elasticRecheck.py b/elastic_recheck/elasticRecheck.py index 83d98a5e..48ddcf65 100755 --- a/elastic_recheck/elasticRecheck.py +++ b/elastic_recheck/elasticRecheck.py @@ -17,7 +17,6 @@ import gerritlib.gerrit import pyelasticsearch -import urllib2 import ConfigParser import logging @@ -32,16 +31,24 @@ from elastic_recheck import results logging.basicConfig() +ES_URL = "http://logstash.openstack.org/elasticsearch" -REQUIRED_FILES = [ - 'console.html', - 'logs/screen-n-api.txt', - 'logs/screen-n-cpu.txt', - 'logs/screen-n-sch.txt', - 'logs/screen-c-api.txt', - 'logs/screen-c-vol.txt', - 'logs/syslog.txt', -] + +def required_files(job): + files = ['console.html'] + if re.match("tempest-dsvm", job): + files.extend([ + 'logs/screen-n-api.txt', + 'logs/screen-n-cpu.txt', + 'logs/screen-n-sch.txt', + 'logs/screen-c-api.txt', + 'logs/screen-c-vol.txt', + 'logs/syslog.txt']) + return files + + +class ResultNotReady(Exception): + pass class Stream(object): @@ -55,6 +62,7 @@ class Stream(object): def __init__(self, user, host, key, thread=True): port = 29418 self.gerrit = gerritlib.gerrit.Gerrit(host, user, port, key) + self.es = results.SearchEngine(ES_URL) if thread: self.gerrit.startWatching() @@ -79,40 +87,82 @@ class Stream(object): failed_tests[m.group(1)] = m.group(2) return failed_tests - def _failed_unit_tests(self, line): - """Did we fail unit tests? If so not a valid failure.""" - fail = ("FAILURE" in line and ("python2" in line or "pep8" in line)) - if fail: - self.log.debug("Failed unit tests, skipping this result") - return fail + def _job_console_uploaded(self, change, patch, name): + query = qb.result_ready(change, patch, name) + r = self.es.search(query, size='10') + if len(r) == 0: + raise ResultNotReady() - def _valid_failure(self, line): - """Is this the kind of failure we track.""" - return "FAILURE" in line and "tempest" in line + def _has_required_files(self, change, patch, name): + query = qb.files_ready(change, patch) + r = self.es.search(query, size='80') + files = [x['term'] for x in r.terms] + required = required_files(name) + missing_files = [x for x in required if x not in files] + if len(missing_files) != 0: + raise ResultNotReady() + + def _does_es_have_data(self, change_number, patch_number, job_fails): + """Wait till ElasticSearch is ready, but return False if timeout.""" + NUMBER_OF_RETRIES = 20 + SLEEP_TIME = 40 + # this checks that we've got the console log uploaded, need to retry + # in case ES goes bonkers on cold data, which it does some times. + for i in range(NUMBER_OF_RETRIES): + try: + for job_name in job_fails: + self._job_console_uploaded( + change_number, patch_number, job_name) + break + + except ResultNotReady: + time.sleep(SLEEP_TIME) + continue + except pyelasticsearch.exceptions.InvalidJsonResponseError: + # If ElasticSearch returns an error code, sleep and retry + # TODO(jogo): if this works pull out search into a helper + # function that does this. + self.log.exception( + "Elastic Search not responding on attempt %d" % i) + time.sleep(NUMBER_OF_RETRIES) + continue + + if i == NUMBER_OF_RETRIES - 1: + return False + + self.log.debug( + "Found hits for change_number: %s, patch_number: %s" + % (change_number, patch_number)) + + for i in range(NUMBER_OF_RETRIES): + try: + for job_name in job_fails: + self._has_required_files( + change_number, patch_number, job_name) + self.log.debug( + "All files present for change_number: %s, patch_number: %s" + % (change_number, patch_number)) + time.sleep(10) + return True + except ResultNotReady: + time.sleep(SLEEP_TIME) + + # if we get to the end, we're broken + return False def get_failed_tempest(self): self.log.debug("entering get_failed_tempest") while True: event = self.gerrit.getEvent() - failed_jobs = Stream.parse_jenkin_failure(event) + failed_jobs = Stream.parse_jenkins_failure(event) if not failed_jobs: # nothing to see here, lets try the next event continue - self.log.debug("potential failed_tempest") - found = False - for line in event['comment'].split('\n'): - if self._failed_unit_tests(line): - found = False - break - if self._valid_failure(line): - url = [x for x in line.split() if "http" in x][0] - if RequiredFiles.files_at_url(url): - self.log.debug("All file present") - found = True - if found: + change = event['change']['number'] + rev = event['patchSet']['number'] + if self._does_es_have_data(change, rev, failed_jobs): return event - continue def leave_comment(self, project, commit, bugs=None): if bugs: @@ -147,12 +197,11 @@ class Classifier(): that are mapped to specific bugs. """ log = logging.getLogger("recheckwatchbot") - ES_URL = "http://logstash.openstack.org/elasticsearch" queries = None def __init__(self, queries_dir): - self.es = results.SearchEngine(self.ES_URL) + self.es = results.SearchEngine(ES_URL) self.queries_dir = queries_dir self.queries = loader.load(self.queries_dir) @@ -160,20 +209,11 @@ class Classifier(): es_query = qb.generic(query, facet=facet) return self.es.search(es_query, size=size) - def classify(self, change_number, patch_number, comment, - skip_resolved=True): + def classify(self, change_number, patch_number, skip_resolved=True): """Returns either empty list or list with matched bugs.""" self.log.debug("Entering classify") #Reload each time self.queries = loader.load(self.queries_dir, skip_resolved) - #Wait till Elastic search is ready - self.log.debug("checking if ElasticSearch is ready") - if not self._is_ready(change_number, patch_number, comment): - self.log.error( - "something went wrong, ElasticSearch is still not ready, " - "giving up and trying next failure") - return None - self.log.debug("ElasticSearch is ready, starting to classify") bug_matches = [] for x in self.queries: self.log.debug( @@ -181,89 +221,10 @@ class Classifier(): % x['bug']) query = qb.single_patch(x['query'], change_number, patch_number) results = self.es.search(query, size='10') - if self._urls_match(comment, results): + if len(results) > 0: bug_matches.append(x['bug']) return bug_matches - def _is_ready(self, change_number, patch_number, comment): - """Wait till ElasticSearch is ready, but return False if timeout.""" - NUMBER_OF_RETRIES = 20 - SLEEP_TIME = 40 - query = qb.result_ready(change_number, patch_number) - for i in range(NUMBER_OF_RETRIES): - try: - results = self.es.search(query, size='10') - except pyelasticsearch.exceptions.InvalidJsonResponseError: - # If ElasticSearch returns an error code, sleep and retry - # TODO(jogo): if this works pull out search into a helper - # function that does this. - print "UHUH hit InvalidJsonResponseError" - time.sleep(NUMBER_OF_RETRIES) - continue - if (len(results) > 0 and self._urls_match(comment, results)): - break - else: - time.sleep(SLEEP_TIME) - if i == NUMBER_OF_RETRIES - 1: - return False - self.log.debug( - "Found hits for change_number: %s, patch_number: %s" - % (change_number, patch_number)) - - query = qb.files_ready(change_number, patch_number) - for i in range(NUMBER_OF_RETRIES): - results = self.es.search(query, size='80') - files = [x['term'] for x in results.terms] - missing_files = [x for x in REQUIRED_FILES if x not in files] - if len(missing_files) is 0: - break - else: - time.sleep(SLEEP_TIME) - if i == NUMBER_OF_RETRIES - 1: - return False - self.log.debug( - "All files present for change_number: %s, patch_number: %s" - % (change_number, patch_number)) - # Just because one file is parsed doesn't mean all are, so wait a - # bit - time.sleep(10) - return True - - def _urls_match(self, comment, results): - for result in results: - url = result.log_url - if RequiredFiles.prep_url(url) in comment: - return True - return False - - -class RequiredFiles(object): - - log = logging.getLogger("recheckwatchbot") - - @staticmethod - def prep_url(url): - if isinstance(url, list): - # The url is sometimes a list of one value - url = url[0] - if "/logs/" in url: - return '/'.join(url.split('/')[:-2]) - return '/'.join(url.split('/')[:-1]) - - @staticmethod - def files_at_url(url): - for f in REQUIRED_FILES: - try: - urllib2.urlopen(url + '/' + f) - except urllib2.HTTPError: - try: - urllib2.urlopen(url + '/' + f + '.gz') - except urllib2.HTTPError: - # File does not exist at URL - RequiredFiles.log.debug("missing file %s" % f) - return False - return True - def main(): config = ConfigParser.ConfigParser() @@ -285,7 +246,7 @@ def main(): rev = event['patchSet']['number'] print "=======================" print "https://review.openstack.org/#/c/%(change)s/%(rev)s" % locals() - bug_numbers = classifier.classify(change, rev, event['comment']) + bug_numbers = classifier.classify(change, rev) if not bug_numbers: print "unable to classify failure" else: diff --git a/elastic_recheck/query_builder.py b/elastic_recheck/query_builder.py index c7824b66..289ab10d 100644 --- a/elastic_recheck/query_builder.py +++ b/elastic_recheck/query_builder.py @@ -59,7 +59,7 @@ def generic(raw_query, facet=None): return query -def result_ready(review=None, patch=None): +def result_ready(review=None, patch=None, name=None): """A query to determine if we have a failure for a particular patch. This is looking for a particular FAILURE line in the console log, which @@ -70,8 +70,9 @@ def result_ready(review=None, patch=None): 'OR message:"[SCP] Copying console log") ' 'AND build_status:"FAILURE" ' 'AND build_change:"%s" ' - 'AND build_patchset:"%s"' % - (review, patch)) + 'AND build_patchset:"%s" ' + 'AND build_name:"%s"' % + (review, patch, name)) def files_ready(review, patch): diff --git a/elastic_recheck/tests/unit/fake_gerrit.py b/elastic_recheck/tests/unit/fake_gerrit.py new file mode 100644 index 00000000..4005eedb --- /dev/null +++ b/elastic_recheck/tests/unit/fake_gerrit.py @@ -0,0 +1,35 @@ +# Copyright 2014 Samsung Electronics. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json + + +class GerritDone(Exception): + pass + + +class Gerrit(object): + """A fake gerrit libobject that emits a bunch of events.""" + def __init__(self, *args): + with open("elastic_recheck/tests/unit/gerrit/events.json") as f: + self.events = json.load(f) + + def startWatching(self): + pass + + def getEvent(self): + if len(self.events) > 0: + return self.events.pop() + else: + raise GerritDone() diff --git a/elastic_recheck/tests/unit/gerrit/events.json b/elastic_recheck/tests/unit/gerrit/events.json new file mode 100644 index 00000000..7b086156 --- /dev/null +++ b/elastic_recheck/tests/unit/gerrit/events.json @@ -0,0 +1,402 @@ +[ + { + "comment": "Build succeeded.\n\n- gate-keystone-pep8 http:\/\/logs.openstack.org\/44\/60244\/12\/check\/gate-keystone-pep8\/5ef9f24 : SUCCESS in 1m 40s\n- gate-keystone-docs http:\/\/docs-draft.openstack.org\/44\/60244\/12\/check\/gate-keystone-docs\/60c7b1b\/doc\/build\/html\/ : SUCCESS in 4m 01s\n- gate-keystone-python26 http:\/\/logs.openstack.org\/44\/60244\/12\/check\/gate-keystone-python26\/d66253a : SUCCESS in 18m 02s\n- gate-keystone-python27 http:\/\/logs.openstack.org\/44\/60244\/12\/check\/gate-keystone-python27\/04102a5 : SUCCESS in 13m 57s\n- check-tempest-dsvm-full http:\/\/logs.openstack.org\/44\/60244\/12\/check\/check-tempest-dsvm-full\/0893acf : SUCCESS in 42m 30s\n- check-tempest-dsvm-postgres-full http:\/\/logs.openstack.org\/44\/60244\/12\/check\/check-tempest-dsvm-postgres-full\/671d371 : SUCCESS in 49m 30s\n- check-tempest-dsvm-neutron http:\/\/logs.openstack.org\/44\/60244\/12\/check\/check-tempest-dsvm-neutron\/4981e54 : SUCCESS in 35m 09s\n- gate-tempest-dsvm-large-ops http:\/\/logs.openstack.org\/44\/60244\/12\/check\/gate-tempest-dsvm-large-ops\/9e825fb : SUCCESS in 13m 11s\n- gate-tempest-dsvm-neutron-large-ops http:\/\/logs.openstack.org\/44\/60244\/12\/check\/gate-tempest-dsvm-neutron-large-ops\/286d887 : SUCCESS in 13m 22s\n- check-grenade-dsvm http:\/\/logs.openstack.org\/44\/60244\/12\/check\/check-grenade-dsvm\/b3b7478 : SUCCESS in 32m 01s\n- check-swift-dsvm-functional http:\/\/logs.openstack.org\/44\/60244\/12\/check\/check-swift-dsvm-functional\/350f34c : SUCCESS in 13m 12s\n", + "author": { + "username": "jenkins", + "name": "Jenkins" + }, + "approvals": [ + { + "type": "VRIF", + "description": "Verified", + "value": "1" + } + ], + "patchSet": { + "createdOn": 1389371115, + "ref": "refs\/changes\/44\/60244\/12", + "number": "12", + "uploader": { + "username": "stevemar", + "name": "Steve Martinelli", + "email": "stevemar@ca.ibm.com" + }, + "revision": "74d75a1050c96eef498e9daaa80fcb9652003a20" + }, + "type": "comment-added", + "change": { + "topic": "bp\/mapping", + "url": "https:\/\/review.openstack.org\/60244", + "number": "60244", + "project": "openstack\/keystone", + "branch": "master", + "owner": { + "username": "marek-denis", + "name": "Marek Denis", + "email": "marek.denis@cern.ch" + }, + "id": "I0ce62e720e797718dbfde6bfcd4b22a213985867", + "subject": "Identity Providers CRUD operations." + } + }, + { + "comment": "Build failed. For information on how to proceed, see https:\/\/wiki.openstack.org\/wiki\/GerritJenkinsGit#Test_Failures\n\n- gate-requirements-pep8 http:\/\/logs.openstack.org\/61\/65361\/2\/check\/gate-requirements-pep8\/e8429d9 : SUCCESS in 25s\n- gate-requirements-python27 http:\/\/logs.openstack.org\/61\/65361\/2\/check\/gate-requirements-python27\/fb66d97 : SUCCESS in 1m 09s\n- gate-requirements-pypy http:\/\/logs.openstack.org\/61\/65361\/2\/check\/gate-requirements-pypy\/592002c : SUCCESS in 2m 09s\n- check-requirements-integration-dsvm http:\/\/logs.openstack.org\/61\/65361\/2\/check\/check-requirements-integration-dsvm\/8209fb4 : FAILURE in 9m 44s\n- check-tempest-dsvm-full http:\/\/logs.openstack.org\/61\/65361\/2\/check\/check-tempest-dsvm-full\/0db6b3f : SUCCESS in 48m 02s\n- check-tempest-dsvm-postgres-full http:\/\/logs.openstack.org\/61\/65361\/2\/check\/check-tempest-dsvm-postgres-full\/4a0c319 : SUCCESS in 45m 10s\n- check-tempest-dsvm-neutron http:\/\/logs.openstack.org\/61\/65361\/2\/check\/check-tempest-dsvm-neutron\/f4323cc : SUCCESS in 36m 49s\n- gate-tempest-dsvm-large-ops http:\/\/logs.openstack.org\/61\/65361\/2\/check\/gate-tempest-dsvm-large-ops\/1e625fc : SUCCESS in 17m 31s\n- gate-tempest-dsvm-neutron-large-ops http:\/\/logs.openstack.org\/61\/65361\/2\/check\/gate-tempest-dsvm-neutron-large-ops\/ffa7ae8 : SUCCESS in 14m 24s\n- check-grenade-dsvm http:\/\/logs.openstack.org\/61\/65361\/2\/check\/check-grenade-dsvm\/c416726 : SUCCESS in 31m 26s\n- check-swift-dsvm-functional http:\/\/logs.openstack.org\/61\/65361\/2\/check\/check-swift-dsvm-functional\/d027be3 : SUCCESS in 14m 30s\n", + "author": { + "username": "jenkins", + "name": "Jenkins" + }, + "approvals": [ + { + "type": "VRIF", + "description": "Verified", + "value": "-1" + } + ], + "patchSet": { + "createdOn": 1389384794, + "ref": "refs\/changes\/61\/65361\/2", + "number": "2", + "uploader": { + "username": "jaegerandi", + "name": "Andreas Jaeger", + "email": "jaegerandi@gmail.com" + }, + "revision": "10d31584a0696cd77200a8fee45900d2343e295e" + }, + "type": "comment-added", + "change": { + "topic": "65361", + "url": "https:\/\/review.openstack.org\/65361", + "number": "65361", + "project": "openstack\/requirements", + "branch": "master", + "owner": { + "username": "jaegerandi", + "name": "Andreas Jaeger", + "email": "jaegerandi@gmail.com" + }, + "id": "Id6a79d3596c6cfaab92cfb8fc89d4298db61b7f0", + "subject": "Add openstack-doc-tools" + } + }, + { + "comment": "Build failed. For information on how to proceed, see https:\/\/wiki.openstack.org\/wiki\/GerritJenkinsGit#Test_Failures\n\n- gate-horizon-pep8 http:\/\/logs.openstack.org\/78\/63078\/19\/check\/gate-horizon-pep8\/37c96e0 : SUCCESS in 2m 54s\n- gate-horizon-docs http:\/\/docs-draft.openstack.org\/78\/63078\/19\/check\/gate-horizon-docs\/53f3535\/doc\/build\/html\/ : SUCCESS in 7m 10s\n- gate-horizon-python26 http:\/\/logs.openstack.org\/78\/63078\/19\/check\/gate-horizon-python26\/1006347 : SUCCESS in 4m 15s\n- gate-horizon-python27 http:\/\/logs.openstack.org\/78\/63078\/19\/check\/gate-horizon-python27\/a9fb840 : SUCCESS in 4m 07s\n- gate-horizon-python27-django14 http:\/\/logs.openstack.org\/78\/63078\/19\/check\/gate-horizon-python27-django14\/1f9c8e5 : SUCCESS in 5m 18s\n- gate-horizon-selenium http:\/\/logs.openstack.org\/78\/63078\/19\/check\/gate-horizon-selenium\/b215898 : SUCCESS in 3m 08s\n- check-tempest-dsvm-full http:\/\/logs.openstack.org\/78\/63078\/19\/check\/check-tempest-dsvm-full\/ab07162 : FAILURE in 54m 09s\n- check-tempest-dsvm-postgres-full http:\/\/logs.openstack.org\/78\/63078\/19\/check\/check-tempest-dsvm-postgres-full\/9bed62d : SUCCESS in 52m 49s\n- check-tempest-dsvm-neutron http:\/\/logs.openstack.org\/78\/63078\/19\/check\/check-tempest-dsvm-neutron\/06a24c0 : SUCCESS in 36m 00s\n- gate-tempest-dsvm-large-ops http:\/\/logs.openstack.org\/78\/63078\/19\/check\/gate-tempest-dsvm-large-ops\/a522f39 : SUCCESS in 13m 33s\n- gate-tempest-dsvm-neutron-large-ops http:\/\/logs.openstack.org\/78\/63078\/19\/check\/gate-tempest-dsvm-neutron-large-ops\/bcbe1da : SUCCESS in 13m 38s\n- check-grenade-dsvm http:\/\/logs.openstack.org\/78\/63078\/19\/check\/check-grenade-dsvm\/9c5b5d0 : SUCCESS in 27m 49s\n", + "author": { + "username": "jenkins", + "name": "Jenkins" + }, + "approvals": [ + { + "type": "VRIF", + "description": "Verified", + "value": "-1" + } + ], + "patchSet": { + "createdOn": 1389383805, + "ref": "refs\/changes\/78\/63078\/19", + "number": "19", + "uploader": { + "username": "yves", + "name": "Yves-Gwenael Bourhis", + "email": "yves-gwenael.bourhis@cloudwatt.com" + }, + "revision": "2e5a51c3f4e0121dbaf47c13b12809f6e7820d09" + }, + "type": "comment-added", + "change": { + "topic": "bp\/image-flavor-selection-ux-enhancement", + "url": "https:\/\/review.openstack.org\/63078", + "number": "63078", + "project": "openstack\/horizon", + "branch": "master", + "owner": { + "username": "yves", + "name": "Yves-Gwenael Bourhis", + "email": "yves-gwenael.bourhis@cloudwatt.com" + }, + "id": "I6674ed1983904334c98a7b7d71c58a393858cbc4", + "subject": "Changed LaunchInstance workflow to wizard mode" + } + }, + { + "comment": "Build succeeded.\n\n- check-dg-tempest-dsvm-full http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-dg-tempest-dsvm-full\/6762ddb : SUCCESS in 51m 22s\n- check-dg-tempest-dsvm-full-reexec http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-dg-tempest-dsvm-full-reexec\/e97d803 : SUCCESS in 55m 24s\n- check-tempest-dsvm-full http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-full\/9181576 : SUCCESS in 1h 04m 35s\n- check-tempest-dsvm-postgres-full http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-postgres-full\/74b4386 : SUCCESS in 1h 29m 32s\n- check-tempest-dsvm-neutron http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-neutron\/54850dd : SUCCESS in 39m 48s\n- gate-tempest-dsvm-large-ops http:\/\/logs.openstack.org\/05\/65805\/1\/check\/gate-tempest-dsvm-large-ops\/18d9e01 : SUCCESS in 13m 58s\n- gate-tempest-dsvm-neutron-large-ops http:\/\/logs.openstack.org\/05\/65805\/1\/check\/gate-tempest-dsvm-neutron-large-ops\/ee4b7eb : SUCCESS in 14m 12s\n- check-grenade-dsvm http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-grenade-dsvm\/d1e83f8 : SUCCESS in 35m 05s\n- check-swift-dsvm-functional http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-swift-dsvm-functional\/5f30c9f : SUCCESS in 15m 23s\n- check-tempest-dsvm-full-grizzly http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-full-grizzly\/1b8d155 : FAILURE in 57m 18s (non-voting)\n- check-tempest-dsvm-neutron-grizzly http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-neutron-grizzly\/70ee0a6 : SUCCESS in 22m 14s (non-voting)\n- check-tempest-dsvm-postgres-full-grizzly http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-postgres-full-grizzly\/fa497b2 : FAILURE in 46m 51s (non-voting)\n- check-devstack-dsvm-cells-grizzly http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-devstack-dsvm-cells-grizzly\/5318390 : FAILURE in 13m 30s (non-voting)\n- check-tempest-dsvm-cells-grizzly http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-cells-grizzly\/c01c8a0 : FAILURE in 28m 36s (non-voting)\n- check-tempest-dsvm-cells-full-grizzly http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-cells-full-grizzly\/78b0d12 : FAILURE in 42m 59s (non-voting)\n- check-tempest-dsvm-full-havana http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-full-havana\/183d433 : SUCCESS in 51m 17s (non-voting)\n- check-tempest-dsvm-neutron-havana http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-neutron-havana\/85453e1 : SUCCESS in 31m 06s (non-voting)\n- check-tempest-dsvm-postgres-full-havana http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-postgres-full-havana\/5243bb4 : SUCCESS in 41m 37s (non-voting)\n- check-devstack-dsvm-cells-havana http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-devstack-dsvm-cells-havana\/9432a96 : SUCCESS in 11m 11s (non-voting)\n- check-tempest-dsvm-cells-havana http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-cells-havana\/d856118 : FAILURE in 15m 25s (non-voting)\n- check-tempest-dsvm-cells-full-havana http:\/\/logs.openstack.org\/05\/65805\/1\/check\/check-tempest-dsvm-cells-full-havana\/cc09d3c : FAILURE in 25m 32s (non-voting)\n", + "author": { + "username": "jenkins", + "name": "Jenkins" + }, + "approvals": [ + { + "type": "VRIF", + "description": "Verified", + "value": "1" + } + ], + "patchSet": { + "createdOn": 1389306576, + "ref": "refs\/changes\/05\/65805\/1", + "number": "1", + "uploader": { + "username": "russellb", + "name": "Russell Bryant", + "email": "rbryant@redhat.com" + }, + "revision": "3ca110f8dc6a552e951074faaca3a11ce65e40f3" + }, + "type": "comment-added", + "change": { + "topic": "slow-down-there-cowboy", + "url": "https:\/\/review.openstack.org\/65805", + "number": "65805", + "project": "openstack-infra\/devstack-gate", + "branch": "master", + "owner": { + "username": "russellb", + "name": "Russell Bryant", + "email": "rbryant@redhat.com" + }, + "id": "I2338ebf5df8bced935e9ed9b0ebd2d4e859b5dbe", + "subject": "Cut tempest concurrency in half" + } + }, + { + "comment": "Build succeeded.\n\n- gate-noop http:\/\/logs.openstack.org\/78\/65378\/15\/check\/gate-noop\/05e95c4 : SUCCESS in 0s\n", + "author": { + "username": "jenkins", + "name": "Jenkins" + }, + "approvals": [ + { + "type": "VRIF", + "description": "Verified", + "value": "1" + } + ], + "patchSet": { + "createdOn": 1389391347, + "ref": "refs\/changes\/78\/65378\/15", + "number": "15", + "uploader": { + "username": "diane-fleming", + "name": "Diane Fleming", + "email": "diane.fleming@rackspace.com" + }, + "revision": "4fe4f8b6dda390c432b2c6d2f6cff2152d3475f3" + }, + "type": "comment-added", + "change": { + "topic": "1187119-a", + "url": "https:\/\/review.openstack.org\/65378", + "number": "65378", + "project": "openstack\/api-site", + "branch": "master", + "owner": { + "username": "diane-fleming", + "name": "Diane Fleming", + "email": "diane.fleming@rackspace.com" + }, + "id": "I82331b1c3cfc5b19f91f7ac1379476e6a9e6806d", + "subject": "Update object-api wadl with comments from Donagh" + } + }, + { + "comment": "Build failed. For information on how to proceed, see https:\/\/wiki.openstack.org\/wiki\/GerritJenkinsGit#Test_Failures\n\n- gate-keystone-pep8 http:\/\/logs.openstack.org\/49\/64749\/6\/check\/gate-keystone-pep8\/16e0b97 : SUCCESS in 2m 25s\n- gate-keystone-docs http:\/\/docs-draft.openstack.org\/49\/64749\/6\/check\/gate-keystone-docs\/77c8f7a\/doc\/build\/html\/ : SUCCESS in 5m 25s\n- gate-keystone-python26 http:\/\/logs.openstack.org\/49\/64749\/6\/check\/gate-keystone-python26\/d3fd328 : FAILURE in 18m 04s\n- gate-keystone-python27 http:\/\/logs.openstack.org\/49\/64749\/6\/check\/gate-keystone-python27\/5dd41fe : FAILURE in 10m 01s\n- check-tempest-dsvm-full http:\/\/logs.openstack.org\/49\/64749\/6\/check\/check-tempest-dsvm-full\/fce905d : SUCCESS in 46m 00s\n- check-tempest-dsvm-postgres-full http:\/\/logs.openstack.org\/49\/64749\/6\/check\/check-tempest-dsvm-postgres-full\/e5cd968 : SUCCESS in 53m 30s\n- check-tempest-dsvm-neutron http:\/\/logs.openstack.org\/49\/64749\/6\/check\/check-tempest-dsvm-neutron\/0673b30 : SUCCESS in 37m 25s\n- gate-tempest-dsvm-large-ops http:\/\/logs.openstack.org\/49\/64749\/6\/check\/gate-tempest-dsvm-large-ops\/bdc661a : SUCCESS in 13m 21s\n- gate-tempest-dsvm-neutron-large-ops http:\/\/logs.openstack.org\/49\/64749\/6\/check\/gate-tempest-dsvm-neutron-large-ops\/991887c : SUCCESS in 12m 28s\n- check-grenade-dsvm http:\/\/logs.openstack.org\/49\/64749\/6\/check\/check-grenade-dsvm\/d098069 : SUCCESS in 31m 05s\n- check-swift-dsvm-functional http:\/\/logs.openstack.org\/49\/64749\/6\/check\/check-swift-dsvm-functional\/2f9377b : SUCCESS in 11m 56s\n", + "author": { + "username": "jenkins", + "name": "Jenkins" + }, + "approvals": [ + { + "type": "VRIF", + "description": "Verified", + "value": "-1" + } + ], + "patchSet": { + "createdOn": 1389378289, + "ref": "refs\/changes\/49\/64749\/6", + "number": "6", + "uploader": { + "username": "blk-u", + "name": "Brant Knudson", + "email": "bknudson@us.ibm.com" + }, + "revision": "06b14616cb2a11514b0c151cc213c1ab5cea324b" + }, + "type": "comment-added", + "change": { + "topic": "bug\/1265108", + "url": "https:\/\/review.openstack.org\/64749", + "number": "64749", + "project": "openstack\/keystone", + "branch": "master", + "owner": { + "username": "blk-u", + "name": "Brant Knudson", + "email": "bknudson@us.ibm.com" + }, + "id": "I890a1c798d7f4a8a345404cd7754708ab0d36651", + "subject": "Enhance auth tests for non-default default_domain_id" + } + }, + { + "comment": "Build succeeded.\n\n- gate-neutron-pep8 http:\/\/logs.openstack.org\/02\/65902\/3\/check\/gate-neutron-pep8\/0ef123c : SUCCESS in 2m 13s\n- gate-neutron-docs http:\/\/docs-draft.openstack.org\/02\/65902\/3\/check\/gate-neutron-docs\/4a7a2ce\/doc\/build\/html\/ : SUCCESS in 1m 43s\n- gate-neutron-python26 http:\/\/logs.openstack.org\/02\/65902\/3\/check\/gate-neutron-python26\/d3e596e : SUCCESS in 43m 38s\n- gate-neutron-python27 http:\/\/logs.openstack.org\/02\/65902\/3\/check\/gate-neutron-python27\/525acec : SUCCESS in 27m 10s\n- check-tempest-dsvm-neutron http:\/\/logs.openstack.org\/02\/65902\/3\/check\/check-tempest-dsvm-neutron\/469682a : SUCCESS in 35m 59s\n- check-tempest-dsvm-neutron-pg http:\/\/logs.openstack.org\/02\/65902\/3\/check\/check-tempest-dsvm-neutron-pg\/91e8f4f : SUCCESS in 37m 11s\n- check-tempest-dsvm-neutron-isolated http:\/\/logs.openstack.org\/02\/65902\/3\/check\/check-tempest-dsvm-neutron-isolated\/90021b9 : SUCCESS in 41m 27s\n- check-tempest-dsvm-neutron-pg-isolated http:\/\/logs.openstack.org\/02\/65902\/3\/check\/check-tempest-dsvm-neutron-pg-isolated\/7bc809a : SUCCESS in 45m 35s\n- gate-tempest-dsvm-neutron-large-ops http:\/\/logs.openstack.org\/02\/65902\/3\/check\/gate-tempest-dsvm-neutron-large-ops\/aea24f9 : SUCCESS in 15m 01s\n- check-grenade-dsvm-neutron http:\/\/logs.openstack.org\/02\/65902\/3\/check\/check-grenade-dsvm-neutron\/59354b6 : FAILURE in 20m 16s (non-voting)\n- check-devstack-dsvm-neutron http:\/\/logs.openstack.org\/02\/65902\/3\/check\/check-devstack-dsvm-neutron\/d347313 : FAILURE in 17m 10s (non-voting)\n", + "author": { + "username": "jenkins", + "name": "Jenkins" + }, + "approvals": [ + { + "type": "VRIF", + "description": "Verified", + "value": "1" + } + ], + "patchSet": { + "createdOn": 1389387264, + "ref": "refs\/changes\/02\/65902\/3", + "number": "3", + "uploader": { + "username": "nanjj", + "name": "Jun Jie Nan", + "email": "nanjj@cn.ibm.com" + }, + "revision": "8044bcbfe8f10aa3f965992e30e9548258d6c736" + }, + "type": "comment-added", + "change": { + "topic": "bugs\/1267682", + "url": "https:\/\/review.openstack.org\/65902", + "number": "65902", + "project": "openstack\/neutron", + "branch": "master", + "owner": { + "username": "nanjj", + "name": "Jun Jie Nan", + "email": "nanjj@cn.ibm.com" + }, + "id": "Id52c04b4739d2d11fe52d4b1631cb4f39e6b577f", + "subject": "Check vxlan enablement via modinfo" + } + }, + { + "comment": "Build succeeded.\n\n- gate-glance-pep8 http:\/\/logs.openstack.org\/64\/66064\/1\/check\/gate-glance-pep8\/250a70c : SUCCESS in 1m 50s\n- gate-glance-docs http:\/\/docs-draft.openstack.org\/64\/66064\/1\/check\/gate-glance-docs\/c641b72\/doc\/build\/html\/ : SUCCESS in 1m 55s\n- gate-glance-python26 http:\/\/logs.openstack.org\/64\/66064\/1\/check\/gate-glance-python26\/c36e87a : SUCCESS in 8m 57s\n- gate-glance-python27 http:\/\/logs.openstack.org\/64\/66064\/1\/check\/gate-glance-python27\/fb29142 : SUCCESS in 12m 30s\n- check-tempest-dsvm-full http:\/\/logs.openstack.org\/64\/66064\/1\/check\/check-tempest-dsvm-full\/21c38f3 : SUCCESS in 43m 54s\n- check-tempest-dsvm-postgres-full http:\/\/logs.openstack.org\/64\/66064\/1\/check\/check-tempest-dsvm-postgres-full\/958323e : SUCCESS in 42m 43s\n- check-tempest-dsvm-neutron http:\/\/logs.openstack.org\/64\/66064\/1\/check\/check-tempest-dsvm-neutron\/3824a0d : SUCCESS in 35m 09s\n- gate-tempest-dsvm-large-ops http:\/\/logs.openstack.org\/64\/66064\/1\/check\/gate-tempest-dsvm-large-ops\/3f113a8 : SUCCESS in 13m 20s\n- gate-tempest-dsvm-neutron-large-ops http:\/\/logs.openstack.org\/64\/66064\/1\/check\/gate-tempest-dsvm-neutron-large-ops\/f527f8c : SUCCESS in 12m 49s\n- check-grenade-dsvm http:\/\/logs.openstack.org\/64\/66064\/1\/check\/check-grenade-dsvm\/ab6a585 : SUCCESS in 28m 47s\n", + "author": { + "username": "jenkins", + "name": "Jenkins" + }, + "approvals": [ + { + "type": "VRIF", + "description": "Verified", + "value": "1" + } + ], + "patchSet": { + "createdOn": 1389388172, + "ref": "refs\/changes\/64\/66064\/1", + "number": "1", + "uploader": { + "username": "arnaud", + "name": "Arnaud Legendre", + "email": "arnaudleg@gmail.com" + }, + "revision": "b05c9313f6873239897d7c88babdfa8ebe5fefed" + }, + "type": "comment-added", + "change": { + "topic": "bug\/1253497", + "url": "https:\/\/review.openstack.org\/66064", + "number": "66064", + "project": "openstack\/glance", + "branch": "master", + "owner": { + "username": "arnaud", + "name": "Arnaud Legendre", + "email": "arnaudleg@gmail.com" + }, + "id": "I657e20ac39fbace60f230652912a4bf792836206", + "subject": "Update `openstack\/common\/context.py' from Oslo" + } + }, + { + "comment": "Build succeeded.\n\n- gate-savanna-docs http:\/\/docs-draft.openstack.org\/25\/65925\/1\/gate\/gate-savanna-docs\/412dd7e\/doc\/build\/html\/ : SUCCESS in 2m 19s\n- gate-savanna-pep8 http:\/\/logs.openstack.org\/25\/65925\/1\/gate\/gate-savanna-pep8\/0e076e8 : SUCCESS in 2m 40s\n- gate-savanna-python26 http:\/\/logs.openstack.org\/25\/65925\/1\/gate\/gate-savanna-python26\/6f15ba8 : SUCCESS in 1m 57s\n- gate-savanna-python27 http:\/\/logs.openstack.org\/25\/65925\/1\/gate\/gate-savanna-python27\/e0545bd : SUCCESS in 2m 12s\n- gate-tempest-dsvm-savanna-full http:\/\/logs.openstack.org\/25\/65925\/1\/gate\/gate-tempest-dsvm-savanna-full\/04a5c22 : SUCCESS in 53m 34s (non-voting)\n- gate-tempest-dsvm-savanna-postgres-full http:\/\/logs.openstack.org\/25\/65925\/1\/gate\/gate-tempest-dsvm-savanna-postgres-full\/0143007 : SUCCESS in 43m 15s (non-voting)\n- gate-tempest-dsvm-savanna-neutron http:\/\/logs.openstack.org\/25\/65925\/1\/gate\/gate-tempest-dsvm-savanna-neutron\/350d103 : SUCCESS in 39m 27s (non-voting)\n", + "author": { + "username": "jenkins", + "name": "Jenkins" + }, + "approvals": [ + { + "type": "VRIF", + "description": "Verified", + "value": "2" + } + ], + "patchSet": { + "createdOn": 1389354908, + "ref": "refs\/changes\/25\/65925\/1", + "number": "1", + "uploader": { + "username": "sreshetniak", + "name": "Sergey Reshetnyak", + "email": "sreshetniak@mirantis.com" + }, + "revision": "fd9bee400259d370e837799236b0a4a6f0343438" + }, + "type": "comment-added", + "change": { + "topic": "del-param", + "url": "https:\/\/review.openstack.org\/65925", + "number": "65925", + "project": "openstack\/savanna", + "branch": "master", + "owner": { + "username": "sreshetniak", + "name": "Sergey Reshetnyak", + "email": "sreshetniak@mirantis.com" + }, + "id": "I3e48e344b079c8eef81a18176147b8aec3c9f3b1", + "subject": "Remove unused node_group parameter in get_config_value" + } + }, + { + "comment": "Build succeeded.\n\n- gate-heat-docs http:\/\/docs-draft.openstack.org\/74\/61074\/12\/gate\/gate-heat-docs\/6afb5bb\/doc\/build\/html\/ : SUCCESS in 2m 20s\n- gate-heat-pep8 http:\/\/logs.openstack.org\/74\/61074\/12\/gate\/gate-heat-pep8\/9e7f091 : SUCCESS in 2m 33s\n- gate-heat-python26 http:\/\/logs.openstack.org\/74\/61074\/12\/gate\/gate-heat-python26\/011dd18 : SUCCESS in 2m 50s\n- gate-heat-python27 http:\/\/logs.openstack.org\/74\/61074\/12\/gate\/gate-heat-python27\/c883c86 : SUCCESS in 1m 54s\n- gate-tempest-dsvm-full http:\/\/logs.openstack.org\/74\/61074\/12\/gate\/gate-tempest-dsvm-full\/f228dfb : SUCCESS in 42m 46s\n- gate-tempest-dsvm-postgres-full http:\/\/logs.openstack.org\/74\/61074\/12\/gate\/gate-tempest-dsvm-postgres-full\/6f05326 : SUCCESS in 1h 21m 14s\n- gate-tempest-dsvm-neutron http:\/\/logs.openstack.org\/74\/61074\/12\/gate\/gate-tempest-dsvm-neutron\/3b361dc : SUCCESS in 43m 33s\n- gate-tempest-dsvm-large-ops http:\/\/logs.openstack.org\/74\/61074\/12\/gate\/gate-tempest-dsvm-large-ops\/47d0217 : SUCCESS in 14m 39s\n- gate-tempest-dsvm-neutron-large-ops http:\/\/logs.openstack.org\/74\/61074\/12\/gate\/gate-tempest-dsvm-neutron-large-ops\/cb67ba1 : SUCCESS in 15m 26s\n", + "author": { + "username": "jenkins", + "name": "Jenkins" + }, + "approvals": [ + { + "type": "VRIF", + "description": "Verified", + "value": "2" + } + ], + "patchSet": { + "createdOn": 1387806669, + "ref": "refs\/changes\/74\/61074\/12", + "number": "12", + "uploader": { + "username": "smelikyan", + "name": "Serg Melikyan", + "email": "smelikyan@mirantis.com" + }, + "revision": "af064c7a5304c672f7d71e4c8df5f69c195c739a" + }, + "type": "comment-added", + "change": { + "topic": "bug\/1259078", + "url": "https:\/\/review.openstack.org\/61074", + "number": "61074", + "project": "openstack\/heat", + "branch": "master", + "owner": { + "username": "smelikyan", + "name": "Serg Melikyan", + "email": "smelikyan@mirantis.com" + }, + "id": "I9afd1a8c222110899a90a940e7a549278c4467b7", + "subject": "Added session_persistence property to VIP" + } + } +] diff --git a/elastic_recheck/tests/unit/test_classifier.py b/elastic_recheck/tests/unit/test_classifier.py deleted file mode 100644 index ac7ebe74..00000000 --- a/elastic_recheck/tests/unit/test_classifier.py +++ /dev/null @@ -1,116 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from elastic_recheck import elasticRecheck -from elastic_recheck import loader -from elastic_recheck import results -from elastic_recheck import tests - - -def fake_queries(directory='queries', skip_resolved=True): - queries = [ - {'query': '@message:"fake query" AND @fields.filename:"fake"\n', - 'bug': 1226337}, - {'query': 'magic query', - 'bug': 1234567}, - {'query': '@message:"fake_query3" AND @fields.filename:"fake"\n', - 'bug': 1235437}] - if not skip_resolved: - queries.append({'query': 'magic query', - 'bug': 1252514, - 'resolved_at': 'Tue Dec 10 12:08:42 EST 2013'}) - return queries - - -def _fake_search(query, size=None): - files = ['console.html', 'logs/screen-n-api.txt', - 'logs/screen-n-cpu.txt', 'logs/screen-n-sch.txt', - 'logs/screen-c-api.txt', 'logs/screen-c-vol.txt', - 'logs/syslog.txt'] - file_list = [] - for f in files: - file_list.append({'term': f}) - log_url = ('http://logs.openstack.org/57/51057/1/gate/gate-tempest-' - 'devstack-vm-full/f8965ee/console.html') - hit_dict = {'_source': {'@fields': {'log_url': log_url}}} - if 'magic query' in query['query']['query_string']['query']: - fake_result = results.ResultSet( - {'hits': {'total': 2, 'hits': [hit_dict, hit_dict]}, - 'facets': {'tag': {'terms': file_list}}}) - else: - fake_result = results.ResultSet( - {'hits': {'total': 1, 'hits': [hit_dict]}, - 'facets': {'tag': {'terms': file_list}}}) - return fake_result - - -def _fake_urls_match(comment, results): - # TODO(sdague): this is not a good fake url work around, however it will - # get us through the merge in of the new result sets. We'll eventually - # make this actual life like data. - if len(results) == 2: - return True - else: - return False - - -def _fake_is_ready_urls_match(comment, results): - return True - - -def _fake_is_ready(change_number, patch_number, comment): - return True - - -class TestClassifier(tests.TestCase): - - def setUp(self): - super(TestClassifier, self).setUp() - self.stubs.Set(loader, 'load', fake_queries) - self.classifier = elasticRecheck.Classifier('queries.yaml') - - def test_is_ready(self): - self.stubs.Set(self.classifier.es, 'search', _fake_search) - result = self.classifier._is_ready( - '49282', - '3', - 'BLAH http://logs.openstack.org/57/51057/1/gate/' - 'gate-tempest-devstack-vm-full/f8965ee' - ) - self.assertTrue(result) - - def test_classify(self): - self.stubs.Set(self.classifier.es, 'search', _fake_search) - self.stubs.Set(self.classifier, '_urls_match', _fake_urls_match) - self.stubs.Set(self.classifier, '_is_ready', _fake_is_ready) - bug_numbers = self.classifier.classify( - '47463', - '3', - ' blah http://logs.openstack.org/63/47463/3/gate/gate-tempest' - '-devstack-vm-postgres-full/99bb8f6' - ) - self.assertEqual(bug_numbers, [1234567]) - - def test_classify_without_skipping_resolved_bugs(self): - self.stubs.Set(self.classifier.es, 'search', _fake_search) - self.stubs.Set(self.classifier, '_urls_match', _fake_urls_match) - self.stubs.Set(self.classifier, '_is_ready', _fake_is_ready) - bug_numbers = self.classifier.classify( - '47463', - '3', - ' blah http://logs.openstack.org/63/47463/3/gate/gate-tempest' - '-devstack-vm-postgres-full/99bb8f6', - False - ) - self.assertEqual(bug_numbers, [1234567, 1252514]) diff --git a/elastic_recheck/tests/unit/test_required_files.py b/elastic_recheck/tests/unit/test_required_files.py deleted file mode 100644 index d8bd4b86..00000000 --- a/elastic_recheck/tests/unit/test_required_files.py +++ /dev/null @@ -1,51 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import urllib2 - -from elastic_recheck import elasticRecheck -from elastic_recheck import tests - - -class TestRequiredFiles(tests.TestCase): - def test_url(self): - url = elasticRecheck.RequiredFiles.prep_url( - 'http://logs.openstack.org/13/46613/2/check/' - 'gate-tempest-devstack-vm-full/864bf44/console.html') - self.assertEqual( - url, - 'http://logs.openstack.org/13/46613/2/check/' - 'gate-tempest-devstack-vm-full/864bf44') - - def _fake_urlopen(self, url): - pass - - def test_files_at_url_pass(self): - self.stubs.Set(urllib2, 'urlopen', self._fake_urlopen) - result = elasticRecheck.RequiredFiles.files_at_url( - 'http://logs.openstack.org/13/46613/2/check/' - 'gate-tempest-devstack-vm-full/864bf44') - self.assertTrue(result) - - def _invalid_url_open(self, url): - raise urllib2.HTTPError(url, 404, 'NotFound', '', None) - - def test_files_at_url_fail(self): - self.stubs.Set(urllib2, 'urlopen', self._invalid_url_open) - self.assertFalse(elasticRecheck.RequiredFiles.files_at_url( - 'http://logs.openstack.org/02/44502/7/check/' - 'gate-tempest-devstack-vm-neutron/4f386e5')) - self.assertFalse(elasticRecheck.RequiredFiles.files_at_url( - 'http://logs.openstack.org/45/47445/3/check/' - 'gate-tempest-devstack-vm-full/0e43e09/')) diff --git a/elastic_recheck/tests/unit/test_stream.py b/elastic_recheck/tests/unit/test_stream.py index 7a27eecf..ac6e983e 100644 --- a/elastic_recheck/tests/unit/test_stream.py +++ b/elastic_recheck/tests/unit/test_stream.py @@ -14,26 +14,50 @@ import json +import fixtures +import mock + from elastic_recheck import elasticRecheck from elastic_recheck import tests +import elastic_recheck.tests.unit.fake_gerrit as fg class TestStream(tests.TestCase): def setUp(self): super(TestStream, self).setUp() - with open("elastic_recheck/tests/unit/jenkins/events.json") as f: - j = json.load(f) - self.events = j['events'] + self.useFixture(fixtures.MonkeyPatch( + 'gerritlib.gerrit.Gerrit', + fg.Gerrit)) - def test_gerrit_parsing_none(self): - self.assertFalse( - elasticRecheck.Stream.parse_jenkins_failure(self.events[1])) - self.assertFalse( - elasticRecheck.Stream.parse_jenkins_failure(self.events[2])) + def test_gerrit_stream(self): + """Tests that we can use our mock gerrit to process events.""" + with mock.patch.object( + elasticRecheck.Stream, '_does_es_have_data') as mock_data: + mock_data.return_value = True + stream = elasticRecheck.Stream("", "", "") + + # there are currently 10 events in the stream, 3 are + # failures + for i in xrange(3): + event = stream.get_failed_tempest() + self.assertEqual(event['author']['username'], 'jenkins') + self.assertIn('Build failed', event['comment']) + self.assertRaises( + fg.GerritDone, + stream.get_failed_tempest) def test_gerrit_parsing(self): - jobs = elasticRecheck.Stream.parse_jenkins_failure(self.events[0]) + with open("elastic_recheck/tests/unit/jenkins/events.json") as f: + j = json.load(f) + events = j['events'] + + self.assertFalse( + elasticRecheck.Stream.parse_jenkins_failure(events[1])) + self.assertFalse( + elasticRecheck.Stream.parse_jenkins_failure(events[2])) + + jobs = elasticRecheck.Stream.parse_jenkins_failure(events[0]) self.assertIn('check-requirements-integration-dsvm', jobs) self.assertIn('check-tempest-dsvm-full', jobs) self.assertIn('check-tempest-dsvm-postgres-full', jobs) diff --git a/test-requirements.txt b/test-requirements.txt index ca3785cd..6091d7a7 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -10,3 +10,4 @@ testrepository>=0.0.17 testscenarios>=0.4,<0.5 testtools>=0.9.32 mox>=0.5.3 +mock>=1.0