moving readiness checks into stream

this changes the interface to move the readiness check out of
the classifier and into the stream object. This massively
simplifies the logic connecting these pieces, as classifier is
now just a thin wrapper to elastic search.

This also adds unit testing for the stream processing through the
creation of a fake_gerrit mock class. That lets us run gerrit
event interactions in a sane way.

It also drops all the unit testing for the classifier which is now
largely useless, because all it tests is we can execute a for loop.

Change-Id: I1971c121276412e31f01eb5680b9c41fc7e442d3
This commit is contained in:
Sean Dague 2014-01-10 09:13:18 -05:00
parent 7624203006
commit 7f42043155
9 changed files with 563 additions and 307 deletions

View File

@ -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:

View File

@ -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:

View File

@ -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):

View File

@ -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()

View File

@ -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"
}
}
]

View File

@ -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])

View File

@ -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/'))

View File

@ -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)

View File

@ -10,3 +10,4 @@ testrepository>=0.0.17
testscenarios>=0.4,<0.5
testtools>=0.9.32
mox>=0.5.3
mock>=1.0