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 17 import os 18 import re 19 import subprocess 20 import sys 21 from xml.dom import Node 22 from xml.dom import minidom 23 24 def 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 33 def getText(tag): 34 return str(tag.firstChild.nodeValue) 35 36 class 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 55 def 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 91 class 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 141 def executeWithResult(command): 142 p = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 143 out, err = p.communicate() 144 return out 145 146 def 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 189 def 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 218 if __name__ == '__main__': 219 main(sys.argv) 220