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::map;
40 using std::set;
41 using std::string;
42 using std::vector;
43
44 enum Flags
45 {
46 FLAG_USE_LAST_INFO = (1 << 0)
47 };
48
49 struct CommandLine
50 {
CommandLineCommandLine51 CommandLine(void) : flags(0)
52 {
53 }
54
55 vector<string> srcFilenames;
56 string dstFilename;
57 uint32_t flags;
58 };
59
60 class LogHandler : public xe::TestLogHandler
61 {
62 public:
LogHandler(xe::BatchResult * batchResult,uint32_t flags)63 LogHandler(xe::BatchResult *batchResult, uint32_t flags) : m_batchResult(batchResult), m_flags(flags)
64 {
65 }
66
setSessionInfo(const xe::SessionInfo & info)67 void setSessionInfo(const xe::SessionInfo &info)
68 {
69 xe::SessionInfo &combinedInfo = m_batchResult->getSessionInfo();
70
71 if (m_flags & FLAG_USE_LAST_INFO)
72 {
73 if (!info.targetName.empty())
74 combinedInfo.targetName = info.targetName;
75 if (!info.releaseId.empty())
76 combinedInfo.releaseId = info.releaseId;
77 if (!info.releaseName.empty())
78 combinedInfo.releaseName = info.releaseName;
79 if (!info.candyTargetName.empty())
80 combinedInfo.candyTargetName = info.candyTargetName;
81 if (!info.configName.empty())
82 combinedInfo.configName = info.configName;
83 if (!info.resultName.empty())
84 combinedInfo.resultName = info.resultName;
85 if (!info.timestamp.empty())
86 combinedInfo.timestamp = info.timestamp;
87 }
88 else
89 {
90 if (combinedInfo.targetName.empty())
91 combinedInfo.targetName = info.targetName;
92 if (combinedInfo.releaseId.empty())
93 combinedInfo.releaseId = info.releaseId;
94 if (combinedInfo.releaseName.empty())
95 combinedInfo.releaseName = info.releaseName;
96 if (combinedInfo.candyTargetName.empty())
97 combinedInfo.candyTargetName = info.candyTargetName;
98 if (combinedInfo.configName.empty())
99 combinedInfo.configName = info.configName;
100 if (combinedInfo.resultName.empty())
101 combinedInfo.resultName = info.resultName;
102 if (combinedInfo.timestamp.empty())
103 combinedInfo.timestamp = info.timestamp;
104 }
105 }
106
startTestCaseResult(const char * casePath)107 xe::TestCaseResultPtr startTestCaseResult(const char *casePath)
108 {
109 if (m_batchResult->hasTestCaseResult(casePath))
110 {
111 xe::TestCaseResultPtr existingResult = m_batchResult->getTestCaseResult(casePath);
112 existingResult->clear();
113 return existingResult;
114 }
115 else
116 return m_batchResult->createTestCaseResult(casePath);
117 }
118
testCaseResultUpdated(const xe::TestCaseResultPtr &)119 void testCaseResultUpdated(const xe::TestCaseResultPtr &)
120 {
121 // Ignored.
122 }
123
testCaseResultComplete(const xe::TestCaseResultPtr &)124 void testCaseResultComplete(const xe::TestCaseResultPtr &)
125 {
126 // Ignored.
127 }
128
129 private:
130 xe::BatchResult *const m_batchResult;
131 const uint32_t m_flags;
132 };
133
readLogFile(xe::BatchResult * dstResult,const char * filename,uint32_t flags)134 static void readLogFile(xe::BatchResult *dstResult, const char *filename, uint32_t flags)
135 {
136 std::ifstream in(filename, std::ifstream::binary | std::ifstream::in);
137 LogHandler resultHandler(dstResult, flags);
138 xe::TestLogParser parser(&resultHandler);
139 uint8_t buf[2048];
140 int numRead = 0;
141
142 if (!in.good())
143 throw std::runtime_error(string("Failed to open '") + filename + "'");
144
145 for (;;)
146 {
147 in.read((char *)&buf[0], DE_LENGTH_OF_ARRAY(buf));
148 numRead = (int)in.gcount();
149
150 if (numRead <= 0)
151 break;
152
153 parser.parse(&buf[0], numRead);
154 }
155
156 in.close();
157 }
158
mergeTestLogs(const CommandLine & cmdLine)159 static void mergeTestLogs(const CommandLine &cmdLine)
160 {
161 xe::BatchResult batchResult;
162
163 for (vector<string>::const_iterator filename = cmdLine.srcFilenames.begin(); filename != cmdLine.srcFilenames.end();
164 ++filename)
165 readLogFile(&batchResult, filename->c_str(), cmdLine.flags);
166
167 if (!cmdLine.dstFilename.empty())
168 xe::writeBatchResultToFile(batchResult, cmdLine.dstFilename.c_str());
169 else
170 xe::writeTestLog(batchResult, std::cout);
171 }
172
printHelp(const char * binName)173 static void printHelp(const char *binName)
174 {
175 printf("%s: [filename] [[filename 2] ...]\n", binName);
176 printf(" --dst=[filename] Write final log to file, otherwise written to stdout.\n");
177 printf(" --info=[first|last] Select which session info to use (default: first).\n");
178 }
179
parseCommandLine(CommandLine & cmdLine,int argc,const char * const * argv)180 static bool parseCommandLine(CommandLine &cmdLine, int argc, const char *const *argv)
181 {
182 for (int argNdx = 1; argNdx < argc; argNdx++)
183 {
184 const char *arg = argv[argNdx];
185
186 if (!deStringBeginsWith(arg, "--"))
187 cmdLine.srcFilenames.push_back(arg);
188 else if (deStringBeginsWith(arg, "--dst="))
189 {
190 if (!cmdLine.dstFilename.empty())
191 return false;
192 cmdLine.dstFilename = arg + 6;
193 }
194 else if (deStringEqual(arg, "--info=first"))
195 cmdLine.flags &= ~FLAG_USE_LAST_INFO;
196 else if (deStringEqual(arg, "--info=last"))
197 cmdLine.flags |= FLAG_USE_LAST_INFO;
198 else
199 return false;
200 }
201
202 if (cmdLine.srcFilenames.empty())
203 return false;
204
205 return true;
206 }
207
main(int argc,const char * const * argv)208 int main(int argc, const char *const *argv)
209 {
210 try
211 {
212 CommandLine cmdLine;
213
214 if (!parseCommandLine(cmdLine, argc, argv))
215 {
216 printHelp(argv[0]);
217 return -1;
218 }
219
220 mergeTestLogs(cmdLine);
221 }
222 catch (const std::exception &e)
223 {
224 printf("FATAL ERROR: %s\n", e.what());
225 return -1;
226 }
227
228 return 0;
229 }
230