1#!/usr/bin/env python 2# 3# Copyright (C) 2012 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 csv 18import os 19import re 20import subprocess 21import sys 22from xml.dom import Node 23from xml.dom import minidom 24 25 26def getChildrenWithTag(parent, tagName): 27 children = [] 28 for child in parent.childNodes: 29 if (child.nodeType == Node.ELEMENT_NODE) and (child.tagName == tagName): 30 #print "parent " + parent.getAttribute("name") + " " + tagName +\ 31 # " " + child.getAttribute("name") 32 children.append(child) 33 return children 34 35class TestCase(object): 36 def __init__(self, name, average, stddev, passFail): 37 self.name = name 38 self.average = average 39 self.stddev = stddev 40 self.passFail = passFail 41 42 def getName(self): 43 return self.name 44 45 def getStddev(self): 46 return self.stddev 47 48 def getAverage(self): 49 return self.average 50 51 def getPassFail(self): 52 return self.passFail 53 54def parseSuite(suite, parentName): 55 if parentName != "": 56 parentName += '.' 57 cases = {} 58 childSuites = getChildrenWithTag(suite, "TestSuite") 59 for child in childSuites: 60 cases.update(parseSuite(child, parentName + child.getAttribute("name"))) 61 childTestCases = getChildrenWithTag(suite, "TestCase") 62 for child in childTestCases: 63 className = parentName + child.getAttribute("name") 64 for test in getChildrenWithTag(child, "Test"): 65 methodName = test.getAttribute("name") 66 # do not include this 67 if methodName == "testAndroidTestCaseSetupProperly": 68 continue 69 caseName = className + "#" + methodName 70 passFail = test.getAttribute("result") 71 average = "" 72 stddev = "" 73 failedScene = getChildrenWithTag(test, "FailedScene") 74 if len(failedScene) > 0: 75 message = failedScene[0].getAttribute("message") 76 #print message 77 messages = message.split('|') 78 if len(messages) > 2: 79 average = messages[1].split()[1] 80 stddev = messages[2].split()[1] 81 testCase = TestCase(caseName, average, stddev, passFail) 82 cases[caseName] = testCase 83 return cases 84 85 86class Result(object): 87 def __init__(self, reportXml): 88 self.results = {} 89 self.infoKeys = [] 90 self.infoValues = [] 91 doc = minidom.parse(reportXml) 92 testResult = doc.getElementsByTagName("TestResult")[0] 93 buildInfo = testResult.getElementsByTagName("BuildInfo")[0] 94 buildId = buildInfo.getAttribute("buildID") 95 deviceId = buildInfo.getAttribute("deviceID") 96 deviceName = buildInfo.getAttribute("build_device") 97 boardName = buildInfo.getAttribute("build_board") 98 partitions = buildInfo.getAttribute("partitions") 99 m = re.search(r'.*;/data\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+);', partitions) 100 dataPartitionSize = m.group(1) 101 self.addKV("device", deviceName) 102 self.addKV("board", boardName) 103 self.addKV("serial", deviceId) 104 self.addKV("build", buildId) 105 self.addKV("data size", dataPartitionSize) 106 packages = getChildrenWithTag(testResult, "TestPackage") 107 for package in packages: 108 casesFromChild = parseSuite(package, "") 109 self.results.update(casesFromChild) 110 #print self.results.keys() 111 112 def addKV(self, key, value): 113 self.infoKeys.append(key) 114 self.infoValues.append(value) 115 116 def getResults(self): 117 return self.results 118 119 def getKeys(self): 120 return self.infoKeys 121 122 def getValues(self): 123 return self.infoValues 124 125def executeWithResult(command): 126 p = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 127 out, err = p.communicate() 128 return out 129 130def main(argv): 131 if len(argv) < 3: 132 print "get_csv_report.py pts_report_dir output_file" 133 sys.exit(1) 134 reportPath = os.path.abspath(argv[1]) 135 outputCsv = os.path.abspath(argv[2]) 136 137 deviceResults = [] 138 xmls = executeWithResult("find " + reportPath + " -name testResult.xml -print") 139 print "xml files found :" 140 print xmls 141 for xml in xmls.splitlines(): 142 result = Result(xml) 143 deviceResults.append(result) 144 reportInfo = [] 145 keys = deviceResults[0].getKeys() 146 noDevices = len(deviceResults) 147 for i in xrange(len(keys)): 148 reportInfo.append([]) 149 reportInfo[i].append(keys[i]) 150 # for worst/average 151 reportInfo[i].append("") 152 for j in xrange(noDevices): 153 reportInfo[i].append(deviceResults[j].getValues()[i]) 154 #print reportInfo 155 156 tests = [] 157 for deviceResult in deviceResults: 158 for key in deviceResult.getResults().keys(): 159 if not key in tests: 160 tests.append(key) 161 tests.sort() 162 #print tests 163 164 reportTests = [] 165 for i in xrange(len(tests)): 166 reportTests.append([]) 167 reportTests.append([]) 168 reportTests[2 * i].append(tests[i]) 169 reportTests[2 * i + 1].append(tests[i]) 170 reportTests[2 * i].append("average") 171 reportTests[2 * i + 1].append("stddev") 172 for j in xrange(noDevices): 173 if deviceResults[j].getResults().has_key(tests[i]): 174 result = deviceResults[j].getResults()[tests[i]] 175 if result.getPassFail() == "pass": 176 reportTests[2 * i].append(result.getAverage()) 177 reportTests[2 * i + 1].append(result.getStddev()) 178 else: 179 reportTests[2 * i].append("fail") 180 reportTests[2 * i + 1].append("fail") 181 else: 182 reportTests[2 * i].append("") 183 reportTests[2 * i + 1].append("") 184 185 #print reportTests 186 187 with open(outputCsv, 'wb') as f: 188 writer = csv.writer(f) 189 writer.writerows(reportInfo) 190 writer.writerows(reportTests) 191 192 193if __name__ == '__main__': 194 main(sys.argv) 195