Skip to content

Instantly share code, notes, and snippets.

@ithena
Created December 19, 2014 07:05
Show Gist options
  • Select an option

  • Save ithena/51c7497234e4c4cdf261 to your computer and use it in GitHub Desktop.

Select an option

Save ithena/51c7497234e4c4cdf261 to your computer and use it in GitHub Desktop.
Generate report (incl. historical information) on test case and suite duration starting from a dir with jUnit xml test reports
@Grab(group = 'net.sf.opencsv', module = 'opencsv', version = '2.3')
import groovy.io.*
import groovy.json.*
import au.com.bytecode.opencsv.CSVWriter
dateFormat = 'dd/MM/yyyy HH:mm'
String testReportsDir = '/Users/rverlind/Projects/Doccle/ap_awl_trunk_only/mci/mci-front-end/mci-euui/target/test-reports'
String reportOuputDir = '/Users/rverlind/Projects/Doccle/'
String reportOutputBaseName = 'euui-test-report'
Date executionDate = new Date()
List testReports = findAllTestReports(testReportsDir)
def (testSuites, testCases) = readLatestReport(reportOuputDir, reportOutputBaseName)
// Uncomment the line below if you would like to start from scratch
//def (testSuites, testCases) = [[],[]]
// Read all test reports one file at a time
for(testReport in testReports) {
testReport.withInputStream {
String type = testReport.name.startsWith('TEST-functional') ? 'FUNC' : testReport.name.startsWith('TEST-integration') ? 'INTE' : 'UNIT'
def rootNode = new XmlParser(false, false).parse(it)
// Read the test suite execution
def testSuite = findTestSuite(testSuites, type, rootNode.@name)
if (!testSuite) {
testSuite = new TestSuite(type: type, name: rootNode.@name)
testSuites << testSuite
}
testSuite.executions << new SuiteExecution(time: new BigDecimal(rootNode.@time), tests: rootNode.@tests?.toInteger(), executionDate: executionDate)
rootNode?.testcase?.each { testcase ->
def result = findTestResult(testCases, type, testcase.@name, testcase.@classname)
if (!result) {
result = new TestResult(type: type, name: testcase.@name, testClass: testcase.@classname)
testCases << result
}
result.executions << new TestExecution(executionDate: executionDate, time: new BigDecimal(testcase.@time), success: testcase.success)
}
}
}
// Write JSON to file
String reportName = "${reportOutputBaseName}-${createReportNameDatePart(executionDate)}"
new File("${reportOuputDir}${reportName}.json").withWriter {
writeResultToJson(testSuites, testCases, executionDate).writeTo(it)
}
new File("${reportOuputDir}${reportName}.csv").withWriter {
def rows = createCsvReportLines(testSuites, testCases)
new CSVWriter(it).writeAll(rows)
}
class TestResult {
String name
String testClass
String type
List executions = []
String toString() {
"${type}: ${name}; executions: ${executions} }"
}
}
class TestExecution {
Date executionDate
BigDecimal time
boolean success = true
String toString() {
"[${executionDate?.format("dd/MM/yyyy HH:mm")};${time};${success ? 'SUCC' : 'FAIL'}]"
}
}
class TestSuite {
String type
String name
List executions = []
boolean equals(TestSuite suite) {
type?.equals(suite?.type) && name?.equals(suite?.name)
}
int hashCode() {
"${type}${name}".hashCode()
}
String toString() {
"${type} ${name}; executions: ${executions}"
}
}
class SuiteExecution {
Date executionDate
BigDecimal time
int tests
String toString() {
"[${executionDate?.format("dd/MM/yyyy HH:mm")};${time};${tests}]"
}
}
def readLatestReport(reportOutputDir, reportOutputBaseName) {
def testSuites = []
def testCases = []
File report = findLatestReport(reportOutputDir, reportOutputBaseName)
if (!report) { return [[],[]] }
report.withReader {
def result = new JsonSlurper().parse(it)
result.report.suites.each { ts ->
def suite = new TestSuite(type: ts.type, name: ts.name)
ts.executions.each { exec ->
suite.executions << new SuiteExecution(
executionDate: new Date().parse(dateFormat, exec.executionDate),
time: new BigDecimal(exec.time),
tests: exec.tests?.toInteger())
}
testSuites << suite
}
result.report.tests.each { tc ->
def tcase = new TestResult(type: tc.type, name: tc.name, testClass: tc.suite)
tc.executions.each { exec ->
tcase.executions << new TestExecution(
executionDate: new Date().parse(dateFormat, exec.executionDate),
time: new BigDecimal(exec.time),
success: exec.success)
}
testCases << tcase
}
}
[testSuites, testCases]
}
File findLatestReport(reportOutputDir, reportOutputBaseName) {
List reports = []
new File(reportOutputDir).eachFile(FileType.FILES) {
if (it.name.startsWith(reportOutputBaseName)) {
reports << it
}
}
reports = reports.sort { it.name }
reports ? reports.last() : null
}
TestSuite findTestSuite(testSuites, type, name) {
testSuites?.find { type == it?.type && name == it.name}
}
TestResult findTestResult(testCases, type, name, classname) {
testCases?.find { type == it?.type && name == it.name && it.testClass == classname}
}
List findAllTestReports(String baseDir) {
def tmpList = []
new File(baseDir).eachFileRecurse(FileType.FILES) {
if (it.name.endsWith('.xml') && it.name.startsWith('TEST-')) {
tmpList << it
}
}
tmpList
}
JsonBuilder writeResultToJson(testSuites, testCases, reportDate) {
def builder = new groovy.json.JsonBuilder()
builder.report {
creationDate reportDate.format(dateFormat)
suites testSuites.collect { ts ->
[type: ts.type,
name: ts.name,
executions: ts.executions.collect { exec ->
[executionDate: exec.executionDate?.format(dateFormat), time: String.valueOf(exec.time.doubleValue()), tests: exec.tests] }
]
}
tests testCases.collect { tc ->
[type: tc.type,
name: tc.name,
suite: tc.testClass,
executions: tc.executions.collect { exec ->
[executionDate: exec.executionDate?.format(dateFormat), time: String.valueOf(exec.time.doubleValue()), success: exec.success]}
]
}
}
builder
}
def createCsvReportLines(testSuites, testCases) {
List<String[]> rows = []
SortedSet executionDateColumns = findAllExecutionDates(testSuites, testCases)
rows << createCsvHeaderRow(executionDateColumns)
testSuites.each { ts ->
rows << createTestSuiteCsvRow(ts, executionDateColumns)
}
testCases.each { tc ->
rows << createTestCaseCsvRow(tc, executionDateColumns)
}
rows
}
SortedSet findAllExecutionDates(testSuites, testCases) {
new TreeSet((testSuites*.executions*.executionDate + testCases*.executions*.executionDate).flatten())
}
def createCsvHeaderRow(SortedSet executionDateColumns) {
List<String> headerRow = ['REPORT TYPE', 'TYPE', 'NAME']
for(executionDateColumn in executionDateColumns) {
headerRow << executionDateColumn
headerRow << '#tests'
}
headerRow as String[]
}
def createTestSuiteCsvRow(ts, executionDateColumns) {
List<String> tsRow = ['SUITE', ts.type, ts.name]
executionDateColumns.each { date ->
def exec = ts.executions.find { it.executionDate == date}
def time = exec?.time
tsRow << time ? String.valueOf(time.doubleValue()) : ''
tsRow << exec?.tests
}
tsRow as String[]
}
def createTestCaseCsvRow(tc, executionDateColumns) {
List<String> tcRow = ['TEST', tc.type, "${tc.testClass}.${tc.name}"]
executionDateColumns.each { date ->
def time = tc.executions.find { it.executionDate == date}?.time
if (time == null) {
tcRow << ''
} else {
tcRow << String.valueOf(time.doubleValue())
}
tcRow << '' // 2nd column only used for tests suites
}
tcRow as String[]
}
String createReportNameDatePart(Date reportDate = new Date()) {
reportDate.format('yyyy-MM-dd_HH-mm')
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment