|
#!/usr/bin/env python3 |
|
# |
|
# Copyright (c) 2015, Edward Hervey <edward@centricular.com> |
|
# |
|
# This program is free software; you can redistribute it and/or |
|
# modify it under the terms of the GNU Lesser General Public |
|
# License as published by the Free Software Foundation; either |
|
# version 2.1 of the License, or (at your option) any later version. |
|
# |
|
# This program is distributed in the hope that it will be useful, |
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
# Lesser General Public License for more details. |
|
# |
|
# You should have received a copy of the GNU Lesser General Public |
|
# License along with this program; if not, write to the |
|
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
|
# Boston, MA 02110-1301, USA. |
|
|
|
import os |
|
import sys |
|
import xml.etree.cElementTree |
|
|
|
|
|
def extract_info(xmlfile): |
|
e = xml.etree.cElementTree.parse(xmlfile).getroot() |
|
r = {} |
|
for i in e: |
|
r[(i.get("classname"), i.get("name"))] = i |
|
return r |
|
|
|
|
|
if "__main__" == __name__: |
|
if len(sys.argv) < 2: |
|
print("Usage : %s [<old run xml>] <new run xml>" % sys.argv[0]) |
|
if len(sys.argv) == 3: |
|
oldfile = extract_info(sys.argv[1]) |
|
newfile = extract_info(sys.argv[2]) |
|
else: |
|
oldfile = [] |
|
newfile = extract_info(sys.argv[1]) |
|
|
|
# new failures (pass in old run, fail in new run) |
|
newfail = [] |
|
# new fixes (fail in old run, pass in new run) |
|
newfix = [] |
|
# tests that are still failing |
|
stillfail = [] |
|
# tests that are still failling but for a different reason |
|
failchange = [] |
|
|
|
# failed tests sorted by reason |
|
reasons = {} |
|
|
|
# all files |
|
allfiles = [] |
|
|
|
# failed tests sorted by file |
|
failedfiles = {} |
|
|
|
if oldfile: |
|
# tests that weren't present in old run |
|
newtests = [x for x in newfile.keys() if x not in oldfile] |
|
# tests that are no longer present in new run |
|
gonetests = [x for x in oldfile.keys() if x not in newfile] |
|
|
|
# go over new tests |
|
for k, v in newfile.iteritems(): |
|
tn, fn = k |
|
if not fn in allfiles: |
|
allfiles.append(fn) |
|
newf = v.findall("error") |
|
if newf: |
|
# extract the failure reason |
|
r = newf[0].get("message") |
|
if "Application returned 18" in r or "Application returned -5" in r: |
|
rs = r.split('[')[1].split(']')[0].split(',') |
|
for la in rs: |
|
la = la.strip() |
|
if la not in reasons: |
|
reasons[la] = [] |
|
reasons[la].append(k) |
|
if fn not in failedfiles: |
|
failedfiles[fn] = [] |
|
failedfiles[fn].append((tn, r)) |
|
|
|
if k in oldfile: |
|
oldone = oldfile.get(k) |
|
|
|
# compare failures |
|
oldf = oldone.findall("error") |
|
if newf and not oldf: |
|
newfail.append(k) |
|
if oldf and not newf: |
|
newfix.append(k) |
|
if oldf and newf: |
|
stillfail.append(k) |
|
a = oldf[0] |
|
b = newf[0] |
|
print a, b |
|
# check if the failure reasons are the same |
|
if a.get("type") != b.get("type"): |
|
failchange.append(k) |
|
elif a.get("message") != b.get("message"): |
|
failchange.append(k) |
|
|
|
if newfail: |
|
print("New failures", len(newfail)) |
|
newfail.sort() |
|
for i in newfail: |
|
print " %s : %s" % (i[0], i[1]) |
|
f = newfile[i].find("error") |
|
print " ", f.get("type"), f.get("message") |
|
print |
|
|
|
if newfix: |
|
print "New fixes", len(newfix) |
|
newfix.sort() |
|
for i in newfix: |
|
print " %s : %s" % (i[0], i[1]) |
|
print |
|
|
|
if failchange: |
|
print "Failure changes", len(failchange) |
|
failchange.sort() |
|
for i in failchange: |
|
print " %s : %s" % (i[0], i[1]) |
|
oldt = oldfile[i].find("error").get("type") |
|
newt = newfile[i].find("error").get("type") |
|
if oldt != newt: |
|
print " Went from '%s' to '%s'" % (oldt, newt) |
|
print " Previous message :", oldfile[i].find("error").get("message") |
|
print " New message :", newfile[i].find("error").get("message") |
|
print |
|
|
|
for k, v in reasons.iteritems(): |
|
print "Failure type : ", k, len(v) |
|
v.sort() |
|
for i in v: |
|
print " %s : %s" % (i[0], i[1]) |
|
print |
|
|
|
nofailfiles = sorted([fn for fn in allfiles if fn not in failedfiles]) |
|
if nofailfiles: |
|
print "Files without failures", len(nofailfiles) |
|
for f in nofailfiles: |
|
print " ", f |
|
print |
|
|
|
for k, v in failedfiles.iteritems(): |
|
print "Failed File :", k |
|
for i in v: |
|
print " %s : %s" % (i[0], i[1]) |