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 {
CommandLineCommandLine51 	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:
LogHandler(xe::BatchResult * batchResult,deUint32 flags)64 	LogHandler (xe::BatchResult* batchResult, deUint32 flags)
65 		: m_batchResult	(batchResult)
66 		, m_flags		(flags)
67 	{
68 	}
69 
setSessionInfo(const xe::SessionInfo & info)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 
startTestCaseResult(const char * casePath)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 
testCaseResultUpdated(const xe::TestCaseResultPtr &)108 	void testCaseResultUpdated (const xe::TestCaseResultPtr&)
109 	{
110 		// Ignored.
111 	}
112 
testCaseResultComplete(const xe::TestCaseResultPtr &)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 
readLogFile(xe::BatchResult * dstResult,const char * filename,deUint32 flags)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 
mergeTestLogs(const CommandLine & cmdLine)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 
printHelp(const char * binName)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 
parseCommandLine(CommandLine & cmdLine,int argc,const char * const * argv)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 
main(int argc,const char * const * argv)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