1/*------------------------------------------------------------------------- 2 * drawElements Quality Program Test Executor 3 * ------------------------------------------ 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Merge two test logs. 22 * 23 * \todo [2013-11-08 pyry] Write variant that can operate with less memory. 24 *//*--------------------------------------------------------------------*/ 25 26#include "xeTestLogParser.hpp" 27#include "xeTestResultParser.hpp" 28#include "xeTestLogWriter.hpp" 29#include "deString.h" 30 31#include <vector> 32#include <string> 33#include <cstdio> 34#include <cstdlib> 35#include <fstream> 36#include <iostream> 37#include <stdexcept> 38 39using std::vector; 40using std::string; 41using std::set; 42using std::map; 43 44enum Flags 45{ 46 FLAG_USE_LAST_INFO = (1<<0) 47}; 48 49struct CommandLine 50{ 51 CommandLine (void) 52 : flags(0) 53 { 54 } 55 56 vector<string> srcFilenames; 57 string dstFilename; 58 deUint32 flags; 59}; 60 61class LogHandler : public xe::TestLogHandler 62{ 63public: 64 LogHandler (xe::BatchResult* batchResult, deUint32 flags) 65 : m_batchResult (batchResult) 66 , m_flags (flags) 67 { 68 } 69 70 void setSessionInfo (const xe::SessionInfo& info) 71 { 72 xe::SessionInfo& combinedInfo = m_batchResult->getSessionInfo(); 73 74 if (m_flags & FLAG_USE_LAST_INFO) 75 { 76 if (!info.targetName.empty()) combinedInfo.targetName = info.targetName; 77 if (!info.releaseId.empty()) combinedInfo.releaseId = info.releaseId; 78 if (!info.releaseName.empty()) combinedInfo.releaseName = info.releaseName; 79 if (!info.candyTargetName.empty()) combinedInfo.candyTargetName = info.candyTargetName; 80 if (!info.configName.empty()) combinedInfo.configName = info.configName; 81 if (!info.resultName.empty()) combinedInfo.resultName = info.resultName; 82 if (!info.timestamp.empty()) combinedInfo.timestamp = info.timestamp; 83 } 84 else 85 { 86 if (combinedInfo.targetName.empty()) combinedInfo.targetName = info.targetName; 87 if (combinedInfo.releaseId.empty()) combinedInfo.releaseId = info.releaseId; 88 if (combinedInfo.releaseName.empty()) combinedInfo.releaseName = info.releaseName; 89 if (combinedInfo.candyTargetName.empty()) combinedInfo.candyTargetName = info.candyTargetName; 90 if (combinedInfo.configName.empty()) combinedInfo.configName = info.configName; 91 if (combinedInfo.resultName.empty()) combinedInfo.resultName = info.resultName; 92 if (combinedInfo.timestamp.empty()) combinedInfo.timestamp = info.timestamp; 93 } 94 } 95 96 xe::TestCaseResultPtr startTestCaseResult (const char* casePath) 97 { 98 if (m_batchResult->hasTestCaseResult(casePath)) 99 { 100 xe::TestCaseResultPtr existingResult = m_batchResult->getTestCaseResult(casePath); 101 existingResult->clear(); 102 return existingResult; 103 } 104 else 105 return m_batchResult->createTestCaseResult(casePath); 106 } 107 108 void testCaseResultUpdated (const xe::TestCaseResultPtr&) 109 { 110 // Ignored. 111 } 112 113 void testCaseResultComplete (const xe::TestCaseResultPtr&) 114 { 115 // Ignored. 116 } 117 118private: 119 xe::BatchResult* const m_batchResult; 120 const deUint32 m_flags; 121}; 122 123static void readLogFile (xe::BatchResult* dstResult, const char* filename, deUint32 flags) 124{ 125 std::ifstream in (filename, std::ifstream::binary|std::ifstream::in); 126 LogHandler resultHandler (dstResult, flags); 127 xe::TestLogParser parser (&resultHandler); 128 deUint8 buf [2048]; 129 int numRead = 0; 130 131 if (!in.good()) 132 throw std::runtime_error(string("Failed to open '") + filename + "'"); 133 134 for (;;) 135 { 136 in.read((char*)&buf[0], DE_LENGTH_OF_ARRAY(buf)); 137 numRead = (int)in.gcount(); 138 139 if (numRead <= 0) 140 break; 141 142 parser.parse(&buf[0], numRead); 143 } 144 145 in.close(); 146} 147 148static void mergeTestLogs (const CommandLine& cmdLine) 149{ 150 xe::BatchResult batchResult; 151 152 for (vector<string>::const_iterator filename = cmdLine.srcFilenames.begin(); filename != cmdLine.srcFilenames.end(); ++filename) 153 readLogFile(&batchResult, filename->c_str(), cmdLine.flags); 154 155 if (!cmdLine.dstFilename.empty()) 156 xe::writeBatchResultToFile(batchResult, cmdLine.dstFilename.c_str()); 157 else 158 xe::writeTestLog(batchResult, std::cout); 159} 160 161static void printHelp (const char* binName) 162{ 163 printf("%s: [filename] [[filename 2] ...]\n", binName); 164 printf(" --dst=[filename] Write final log to file, otherwise written to stdout.\n"); 165 printf(" --info=[first|last] Select which session info to use (default: first).\n"); 166} 167 168static bool parseCommandLine (CommandLine& cmdLine, int argc, const char* const* argv) 169{ 170 for (int argNdx = 1; argNdx < argc; argNdx++) 171 { 172 const char* arg = argv[argNdx]; 173 174 if (!deStringBeginsWith(arg, "--")) 175 cmdLine.srcFilenames.push_back(arg); 176 else if (deStringBeginsWith(arg, "--dst=")) 177 { 178 if (!cmdLine.dstFilename.empty()) 179 return false; 180 cmdLine.dstFilename = arg+6; 181 } 182 else if (deStringEqual(arg, "--info=first")) 183 cmdLine.flags &= ~FLAG_USE_LAST_INFO; 184 else if (deStringEqual(arg, "--info=last")) 185 cmdLine.flags |= FLAG_USE_LAST_INFO; 186 else 187 return false; 188 } 189 190 if (cmdLine.srcFilenames.empty()) 191 return false; 192 193 return true; 194} 195 196int main (int argc, const char* const* argv) 197{ 198 try 199 { 200 CommandLine cmdLine; 201 202 if (!parseCommandLine(cmdLine, argc, argv)) 203 { 204 printHelp(argv[0]); 205 return -1; 206 } 207 208 mergeTestLogs(cmdLine); 209 } 210 catch (const std::exception& e) 211 { 212 printf("FATAL ERROR: %s\n", e.what()); 213 return -1; 214 } 215 216 return 0; 217} 218