1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Test Executor
3 * ------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Test batch executor.
22 *//*--------------------------------------------------------------------*/
24 #include "xeBatchExecutor.hpp"
25 #include "xeTestResultParser.hpp"
38 TEST_LOG_TMP_BUFFER_SIZE = 1024,
39 INFO_LOG_TMP_BUFFER_SIZE = 256
42 // \todo [2012-11-01 pyry] Update execute set in handler.
44 static inline bool isExecutedInBatch (const BatchResult* batchResult, const TestCase* testCase)
47 testCase->getFullPath(fullPath);
49 if (batchResult->hasTestCaseResult(fullPath.c_str()))
51 ConstTestCaseResultPtr data = batchResult->getTestCaseResult(fullPath.c_str());
52 return data->getStatusCode() != TESTSTATUSCODE_PENDING && data->getStatusCode() != TESTSTATUSCODE_RUNNING;
58 // \todo [2012-06-19 pyry] These can be optimized using TestSetIterator (once implemented)
60 static void computeExecuteSet (TestSet& executeSet, const TestNode* root, const TestSet& testSet, const BatchResult* batchResult)
62 ConstTestNodeIterator iter = ConstTestNodeIterator::begin(root);
63 ConstTestNodeIterator end = ConstTestNodeIterator::end(root);
65 for (; iter != end; ++iter)
67 const TestNode* node = *iter;
69 if (node->getNodeType() == TESTNODETYPE_TEST_CASE && testSet.hasNode(node))
71 const TestCase* testCase = static_cast<const TestCase*>(node);
73 if (!isExecutedInBatch(batchResult, testCase))
74 executeSet.addCase(testCase);
79 static void computeBatchRequest (TestSet& requestSet, const TestSet& executeSet, const TestNode* root, int maxCasesInSet)
81 ConstTestNodeIterator iter = ConstTestNodeIterator::begin(root);
82 ConstTestNodeIterator end = ConstTestNodeIterator::end(root);
85 for (; (iter != end) && (numCases < maxCasesInSet); ++iter)
87 const TestNode* node = *iter;
89 if (node->getNodeType() == TESTNODETYPE_TEST_CASE && executeSet.hasNode(node))
91 const TestCase* testCase = static_cast<const TestCase*>(node);
92 requestSet.addCase(testCase);
98 static int removeExecuted (TestSet& set, const TestNode* root, const BatchResult* batchResult)
100 TestSet oldSet (set);
101 ConstTestNodeIterator iter = ConstTestNodeIterator::begin(root);
102 ConstTestNodeIterator end = ConstTestNodeIterator::end(root);
105 for (; iter != end; ++iter)
107 const TestNode* node = *iter;
109 if (node->getNodeType() == TESTNODETYPE_TEST_CASE && oldSet.hasNode(node))
111 const TestCase* testCase = static_cast<const TestCase*>(node);
113 if (isExecutedInBatch(batchResult, testCase))
115 set.removeCase(testCase);
124 BatchExecutorLogHandler::BatchExecutorLogHandler (BatchResult* batchResult)
125 : m_batchResult(batchResult)
129 BatchExecutorLogHandler::~BatchExecutorLogHandler (void)
133 void BatchExecutorLogHandler::setSessionInfo (const SessionInfo& sessionInfo)
135 m_batchResult->getSessionInfo() = sessionInfo;
138 TestCaseResultPtr BatchExecutorLogHandler::startTestCaseResult (const char* casePath)
140 // \todo [2012-11-01 pyry] What to do with duplicate results?
141 if (m_batchResult->hasTestCaseResult(casePath))
142 return m_batchResult->getTestCaseResult(casePath);
144 return m_batchResult->createTestCaseResult(casePath);
147 void BatchExecutorLogHandler::testCaseResultUpdated (const TestCaseResultPtr&)
151 void BatchExecutorLogHandler::testCaseResultComplete (const TestCaseResultPtr& result)
153 // \todo [2012-11-01 pyry] Remove from execute set here instead of updating it between sessions.
154 printf("%s\n", result->getTestCasePath());
157 BatchExecutor::BatchExecutor (const TargetConfiguration& config, CommLink* commLink, const TestNode* root, const TestSet& testSet, BatchResult* batchResult, InfoLog* infoLog)
159 , m_commLink (commLink)
161 , m_testSet (testSet)
162 , m_logHandler (batchResult)
163 , m_batchResult (batchResult)
164 , m_infoLog (infoLog)
165 , m_state (STATE_NOT_STARTED)
166 , m_testLogParser (&m_logHandler)
170 BatchExecutor::~BatchExecutor (void)
174 void BatchExecutor::run (void)
176 XE_CHECK(m_state == STATE_NOT_STARTED);
178 // Check commlink state.
180 CommLinkState commState = COMMLINKSTATE_LAST;
181 std::string stateStr = "";
183 commState = m_commLink->getState(stateStr);
185 if (commState == COMMLINKSTATE_ERROR)
188 XE_FAIL((string("CommLink error: '") + stateStr + "'").c_str());
190 else if (commState != COMMLINKSTATE_READY)
191 XE_FAIL("CommLink is not ready");
194 // Compute initial execute set.
195 computeExecuteSet(m_casesToExecute, m_root, m_testSet, m_batchResult);
197 // Register callbacks.
198 m_commLink->setCallbacks(enqueueStateChanged, enqueueTestLogData, enqueueInfoLogData, this);
202 if (!m_casesToExecute.empty())
204 TestSet batchRequest;
205 computeBatchRequest(batchRequest, m_casesToExecute, m_root, m_config.maxCasesPerSession);
206 launchTestSet(batchRequest);
208 m_state = STATE_STARTED;
211 m_state = STATE_FINISHED;
213 // Run handler loop until we are finished.
214 while (m_state != STATE_FINISHED)
215 m_dispatcher.callNext();
219 m_commLink->setCallbacks(DE_NULL, DE_NULL, DE_NULL, DE_NULL);
223 // De-register callbacks.
224 m_commLink->setCallbacks(DE_NULL, DE_NULL, DE_NULL, DE_NULL);
227 void BatchExecutor::cancel (void)
229 m_state = STATE_FINISHED;
230 m_dispatcher.cancel();
233 void BatchExecutor::onStateChanged (CommLinkState state, const char* message)
237 case COMMLINKSTATE_READY:
238 case COMMLINKSTATE_TEST_PROCESS_LAUNCHING:
239 case COMMLINKSTATE_TEST_PROCESS_RUNNING:
242 case COMMLINKSTATE_TEST_PROCESS_FINISHED:
244 // Feed end of string to parser. This terminates open test case if such exists.
247 onTestLogData(&eos, 1);
250 int numExecuted = removeExecuted(m_casesToExecute, m_root, m_batchResult);
252 // \note No new batch is launched if no cases were executed in last one. Otherwise excutor
253 // could end up in infinite loop.
254 if (!m_casesToExecute.empty() && numExecuted > 0)
256 // Reset state and start batch.
257 m_testLogParser.reset();
260 XE_CHECK(m_commLink->getState() == COMMLINKSTATE_READY);
262 TestSet batchRequest;
263 computeBatchRequest(batchRequest, m_casesToExecute, m_root, m_config.maxCasesPerSession);
264 launchTestSet(batchRequest);
267 m_state = STATE_FINISHED;
272 case COMMLINKSTATE_TEST_PROCESS_LAUNCH_FAILED:
273 printf("Failed to start test process: '%s'\n", message);
274 m_state = STATE_FINISHED;
277 case COMMLINKSTATE_ERROR:
278 printf("CommLink error: '%s'\n", message);
279 m_state = STATE_FINISHED;
283 XE_FAIL("Unknown state");
287 void BatchExecutor::onTestLogData (const deUint8* bytes, size_t numBytes)
291 m_testLogParser.parse(bytes, numBytes);
293 catch (const ParseError& e)
295 // \todo [2012-07-06 pyry] Log error.
300 void BatchExecutor::onInfoLogData (const deUint8* bytes, size_t numBytes)
302 if (numBytes > 0 && m_infoLog)
303 m_infoLog->append(bytes, numBytes);
306 static void writeCaseListNode (std::ostream& str, const TestNode* node, const TestSet& testSet)
308 DE_ASSERT(testSet.hasNode(node));
310 TestNodeType nodeType = node->getNodeType();
312 if (nodeType != TESTNODETYPE_ROOT)
313 str << node->getName();
315 if (nodeType == TESTNODETYPE_ROOT || nodeType == TESTNODETYPE_GROUP)
317 const TestGroup* group = static_cast<const TestGroup*>(node);
322 for (int ndx = 0; ndx < group->getNumChildren(); ndx++)
324 const TestNode* child = group->getChild(ndx);
326 if (testSet.hasNode(child))
331 writeCaseListNode(str, child, testSet);
340 void BatchExecutor::launchTestSet (const TestSet& testSet)
342 std::ostringstream caseList;
343 XE_CHECK(testSet.hasNode(m_root));
344 XE_CHECK(m_root->getNodeType() == TESTNODETYPE_ROOT);
345 writeCaseListNode(caseList, m_root, testSet);
347 m_commLink->startTestProcess(m_config.binaryName.c_str(), m_config.cmdLineArgs.c_str(), m_config.workingDir.c_str(), caseList.str().c_str());
350 void BatchExecutor::enqueueStateChanged (void* userPtr, CommLinkState state, const char* message)
352 BatchExecutor* executor = static_cast<BatchExecutor*>(userPtr);
353 CallWriter writer (&executor->m_dispatcher, BatchExecutor::dispatchStateChanged);
362 void BatchExecutor::enqueueTestLogData (void* userPtr, const deUint8* bytes, size_t numBytes)
364 BatchExecutor* executor = static_cast<BatchExecutor*>(userPtr);
365 CallWriter writer (&executor->m_dispatcher, BatchExecutor::dispatchTestLogData);
370 writer.write(bytes, numBytes);
374 void BatchExecutor::enqueueInfoLogData (void* userPtr, const deUint8* bytes, size_t numBytes)
376 BatchExecutor* executor = static_cast<BatchExecutor*>(userPtr);
377 CallWriter writer (&executor->m_dispatcher, BatchExecutor::dispatchInfoLogData);
382 writer.write(bytes, numBytes);
386 void BatchExecutor::dispatchStateChanged (CallReader& data)
388 BatchExecutor* executor = DE_NULL;
389 CommLinkState state = COMMLINKSTATE_LAST;
396 executor->onStateChanged(state, message.c_str());
399 void BatchExecutor::dispatchTestLogData (CallReader& data)
401 BatchExecutor* executor = DE_NULL;
407 executor->onTestLogData(data.getDataBlock(numBytes), numBytes);
410 void BatchExecutor::dispatchInfoLogData (CallReader& data)
412 BatchExecutor* executor = DE_NULL;
418 executor->onInfoLogData(data.getDataBlock(numBytes), numBytes);