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:
parent
7624203006
commit
7f42043155
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
|
35
elastic_recheck/tests/unit/fake_gerrit.py
Normal file
35
elastic_recheck/tests/unit/fake_gerrit.py
Normal 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()
|
402
elastic_recheck/tests/unit/gerrit/events.json
Normal file
402
elastic_recheck/tests/unit/gerrit/events.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
@ -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])
|
@ -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/'))
|
@ -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)
|
||||
|
@ -10,3 +10,4 @@ testrepository>=0.0.17
|
||||
testscenarios>=0.4,<0.5
|
||||
testtools>=0.9.32
|
||||
mox>=0.5.3
|
||||
mock>=1.0
|
||||
|
Loading…
Reference in New Issue
Block a user