make_test_output.py 2.6 KB

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