Home | History | Annotate | Download | only in tools
      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 
     39 using std::vector;
     40 using std::string;
     41 using std::set;
     42 using std::map;
     43 
     44 enum Flags
     45 {
     46 	FLAG_USE_LAST_INFO = (1<<0)
     47 };
     48 
     49 struct CommandLine
     50 {
     51 	CommandLine (void)
     52 		: flags(0)
     53 	{
     54 	}
     55 
     56 	vector<string>	srcFilenames;
     57 	string			dstFilename;
     58 	deUint32		flags;
     59 };
     60 
     61 class LogHandler : public xe::TestLogHandler
     62 {
     63 public:
     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 
    118 private:
    119 	xe::BatchResult* const	m_batchResult;
    120 	const deUint32			m_flags;
    121 };
    122 
    123 static 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 
    148 static 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 
    161 static 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 
    168 static 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 
    196 int 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