blob: b1f2e2c0bb67fd9b39c4e993342bd07098bb52d7 [file] [log] [blame]
Josh Haberman67c727c2016-03-04 14:21:18 -08001"""Gathers output from test runs and create an XML file in JUnit format.
Josh Haberman38bc1552016-02-23 14:28:02 -08002
3The output files from the individual tests have been written in a directory
4structure like:
5
Josh Haberman67c727c2016-03-04 14:21:18 -08006 $DIR/joblog (output from "parallel --joblog joblog")
Josh Haberman38bc1552016-02-23 14:28:02 -08007 $DIR/logs/1/cpp/stdout
8 $DIR/logs/1/cpp/stderr
9 $DIR/logs/1/csharp/stdout
10 $DIR/logs/1/csharp/stderr
11 $DIR/logs/1/java_jdk7/stdout
12 $DIR/logs/1/java_jdk7/stderr
13 etc.
14
15This script bundles them into a single output XML file so Jenkins can show
Josh Haberman67c727c2016-03-04 14:21:18 -080016detailed test results. It runs as the last step before the Jenkins build
17finishes.
Josh Haberman38bc1552016-02-23 14:28:02 -080018"""
19
20import os;
21import sys;
22from yattag import Doc
23from collections import defaultdict
24
25def readtests(basedir):
26 tests = defaultdict(dict)
27
28 # Sample input (note: separators are tabs).
29 #
30 # Seq Host Starttime Runtime Send Receive Exitval Signal Command
31 # 1 : 1456263838.313 0.005 0 0 0 0 echo A
32 with open(basedir + "/joblog") as jobs:
33 firstline = next(jobs)
34 for line in jobs:
35 values = line.split("\t")
36
37 name = values[8].split()[-1]
38 test = tests[name]
39 test["name"] = name
40 test["time"] = values[3]
41
42 exitval = values[6]
43 if int(exitval):
44 # We don't have a more specific message. User should look at stderr.
45 test["failure"] = "TEST FAILURE"
46 else:
47 test["failure"] = False
48
49 for testname in os.listdir(basedir + "/logs/1"):
50 test = tests[testname]
51
52 with open(basedir + "/logs/1/" + testname + "/stdout") as f:
53 test["stdout"] = f.read()
54
55 with open(basedir + "/logs/1/" + testname + "/stderr") as f:
56 test["stderr"] = f.read()
57
58 # The cpp test is special since it doesn't run under parallel so doesn't show
59 # up in the job log.
60 tests["cpp"]["name"] = "cpp"
61
Josh Haberman2bda98f2016-03-03 17:04:36 -080062 with open(basedir + '/logs/1/cpp/build_time', 'r') as f:
63 tests["cpp"]["time"] = f.read().strip()
Josh Haberman38bc1552016-02-23 14:28:02 -080064 tests["cpp"]["failure"] = False
65
66 ret = tests.values()
67 ret.sort(key=lambda x: x["name"])
68
69 return ret
70
71def genxml(tests):
72 doc, tag, text = Doc().tagtext()
73
74 with tag("testsuites"):
75 with tag("testsuite", name="Protobuf Tests"):
76 for test in tests:
77 with tag("testcase", name=test["name"], classname=test["name"],
78 time=test["time"]):
79 with tag("system-out"):
80 text(test["stdout"])
81 with tag("system-err"):
82 text(test["stderr"])
83 if test["failure"]:
84 with tag("failure"):
85 text(test["failure"])
86
87 return doc.getvalue()
88
89sys.stderr.write("make_test_output.py: writing XML from directory: " +
90 sys.argv[1] + "\n");
91print genxml(readtests(sys.argv[1]))