1#!/usr/bin/env python 2# 3# Copyright (C) 2013 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the 'License'); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an 'AS IS' BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import os 18import re 19import subprocess 20import sys 21from xml.dom import Node 22from xml.dom import minidom 23 24def getChildrenWithTag(parent, tagName): 25 children = [] 26 for child in parent.childNodes: 27 if (child.nodeType == Node.ELEMENT_NODE) and (child.tagName == tagName): 28 #print "parent " + parent.getAttribute("name") + " " + tagName +\ 29 # " " + child.getAttribute("name") 30 children.append(child) 31 return children 32 33def getText(tag): 34 return str(tag.firstChild.nodeValue) 35 36class TestCase(object): 37 def __init__(self, name, summary, details, result): 38 self.name = name 39 self.summary = summary 40 self.details = details 41 self.result = result 42 43 def getName(self): 44 return self.name 45 46 def getSummary(self): 47 return self.summary 48 49 def getDetails(self): 50 return self.details 51 52 def getResult(self): 53 return self.result 54 55def parseSuite(suite, parentName): 56 if parentName != "": 57 parentName += '.' 58 cases = {} 59 childSuites = getChildrenWithTag(suite, "TestSuite") 60 for child in childSuites: 61 cases.update(parseSuite(child, parentName + child.getAttribute("name"))) 62 childTestCases = getChildrenWithTag(suite, "TestCase") 63 for child in childTestCases: 64 className = parentName + child.getAttribute("name") 65 for test in getChildrenWithTag(child, "Test"): 66 methodName = test.getAttribute("name") 67 # do not include this 68 if methodName == "testAndroidTestCaseSetupProperly": 69 continue 70 caseName = str(className + "#" + methodName) 71 result = str(test.getAttribute("result")) 72 summary = {} 73 details = {} 74 if result == "pass": 75 sts = getChildrenWithTag(test, "Summary") 76 dts = getChildrenWithTag(test, "Details") 77 if len(sts) == len(dts) == 1: 78 summary[sts[0].getAttribute("message")] = getText(sts[0]) 79 for d in getChildrenWithTag(dts[0], "ValueArray"): 80 values = [] 81 for c in getChildrenWithTag(d, "Value"): 82 values.append(getText(c)) 83 details[d.getAttribute("message")] = values 84 else: 85 result = "no results" 86 testCase = TestCase(caseName, summary, details, result) 87 cases[caseName] = testCase 88 return cases 89 90 91class Result(object): 92 def __init__(self, reportXml): 93 self.results = {} 94 self.infoKeys = [] 95 self.infoValues = [] 96 doc = minidom.parse(reportXml) 97 testResult = doc.getElementsByTagName("TestResult")[0] 98 buildInfos = testResult.getElementsByTagName("BuildInfo") 99 if buildInfos != None and len(buildInfos) > 0: 100 buildInfo = buildInfos[0] 101 buildId = buildInfo.getAttribute("buildID") 102 deviceId = buildInfo.getAttribute("deviceID") 103 deviceName = buildInfo.getAttribute("build_device") 104 boardName = buildInfo.getAttribute("build_board") 105 partitions = buildInfo.getAttribute("partitions") 106 m = re.search(r'.*;/data\s+([\w\.]+)\s+([\w\.]+)\s+([\w\.]+)\s+([\w\.]+);', partitions) 107 dataPartitionSize = m.group(1) 108 self.addKV("device", deviceName) 109 self.addKV("board", boardName) 110 self.addKV("serial", deviceId) 111 self.addKV("build", buildId) 112 self.addKV("data size", dataPartitionSize) 113 packages = getChildrenWithTag(testResult, "TestPackage") 114 for package in packages: 115 casesFromChild = parseSuite(package, "") 116 self.results.update(casesFromChild) 117 #print self.results.keys() 118 119 def addKV(self, key, value): 120 self.infoKeys.append(key) 121 self.infoValues.append(value) 122 123 def getResults(self): 124 return self.results 125 126 def getKeys(self): 127 return self.infoKeys 128 129 def getValues(self): 130 return self.infoValues 131 132 def getDeviceName(self): 133 return self.getInfoV("device") 134 135 def getInfoV(self, key): 136 if key in self.infoKeys: 137 return self.infoValues[self.infoKeys.index(key)] 138 else: 139 return "unknown" 140 141def executeWithResult(command): 142 p = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 143 out, err = p.communicate() 144 return out 145 146def parseReports(path): 147 deviceResults = [] 148 xmls = executeWithResult("find " + path + " -name testResult.xml -print") 149 print "xml files found :" 150 print xmls 151 for xml in xmls.splitlines(): 152 result = Result(xml) 153 deviceResults.append(result) 154 reportInfo = {} 155 keys = ["device", "board", "serial", "build", "data size"] 156 numDevices = len(deviceResults) 157 for i in xrange(len(keys)): 158 values = [] 159 for j in xrange(numDevices): 160 values.append(str(deviceResults[j].getInfoV(keys[i]))) 161 reportInfo[keys[i]] = values 162 #print reportInfo 163 164 tests = [] 165 for deviceResult in deviceResults: 166 for key in deviceResult.getResults().keys(): 167 if not key in tests: 168 tests.append(key) 169 #print tests 170 171 reportTests = {} 172 for i in xrange(len(tests)): 173 test = tests[i] 174 reportTests[test] = [] 175 for j in xrange(numDevices): 176 values = {} 177 if deviceResults[j].getResults().has_key(test): 178 result = deviceResults[j].getResults()[test] 179 values["result"] = result.getResult() 180 values["summary"] = result.getSummary() 181 values["details"] = result.getDetails() 182 values["device"] = deviceResults[j].getDeviceName() 183 # even if report does not have test, put empty dict 184 # otherwise, there is no way to distinguish results from the same device 185 reportTests[test].append(values) 186 #print reportTests 187 return (reportInfo, reportTests) 188 189def main(argv): 190 if len(argv) < 3: 191 print "get_csv_report.py cts_report_dir output_file" 192 sys.exit(1) 193 reportPath = os.path.abspath(argv[1]) 194 outputCsv = os.path.abspath(argv[2]) 195 196 (reportInfo, reportTests) = parseReports(reportPath) 197 198 with open(outputCsv, 'w') as f: 199 for key in reportInfo: 200 f.write(key) 201 for value in reportInfo[key]: 202 f.write(',') 203 f.write(value) 204 f.write('\n') 205 sortedTest = sorted(reportTests) 206 for test in sortedTest: 207 f.write(test) 208 for report in reportTests[test]: 209 f.write(',') 210 if 'summary' in report: 211 summaryValues = report['summary'].values() 212 if len(summaryValues) > 0: 213 f.write(summaryValues[0]) 214 # else: no data printed but just empty cell 215 # close a test with line 216 f.write('\n') 217 218if __name__ == '__main__': 219 main(sys.argv) 220