1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
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 Class for executing tests.
22 *//*--------------------------------------------------------------------*/
24 #include "tcuTestExecutor.hpp"
25 #include "tcuCommandLine.hpp"
26 #include "tcuPlatform.hpp"
27 #include "tcuTestLog.hpp"
43 TestExecutor::TestExecutor (TestContext& testCtx, const CommandLine& cmdLine)
46 , m_rootNode (DE_NULL)
47 , m_testCaseWrapper (DE_NULL)
48 , m_testCaseListFile (DE_NULL)
49 , m_testCaseListWriter (DE_NULL)
51 m_abortSession = false;
52 m_isInTestCase = false;
54 // Create the root node.
55 TestPackageRegistry* packageRegistry = TestPackageRegistry::getSingleton();
56 vector<TestPackageRegistry::PackageInfo*> packageInfos = packageRegistry->getPackageInfos();
57 vector<TestNode*> testPackages;
59 for (int i = 0; i < (int)packageInfos.size(); i++)
60 testPackages.push_back(packageInfos[i]->createFunc(testCtx));
62 m_rootNode = new TestPackageRoot(testCtx, testPackages);
64 // Init traverse stack.
65 NodeIter iter(m_rootNode);
66 m_sessionStack.push_back(iter);
69 TestExecutor::~TestExecutor (void)
71 if (m_testCaseListWriter)
72 qpXmlWriter_destroy(m_testCaseListWriter);
74 if (m_testCaseListFile)
75 fclose(m_testCaseListFile);
80 // Test sub-case iteration.
81 void TestExecutor::enterTestPackage (TestPackage* testPackage, const char* packageName)
83 DE_ASSERT(testPackage && packageName);
85 // Open file/writer for case dumping.
86 const RunMode runMode = m_cmdLine.getRunMode();
87 if (runMode == RUNMODE_DUMP_XML_CASELIST || runMode == RUNMODE_DUMP_TEXT_CASELIST)
89 const char* const ext = (runMode == RUNMODE_DUMP_XML_CASELIST) ? "xml" : "txt";
90 const string fileName = string(packageName) + "-cases." + ext;
92 print("Dumping all test case names in '%s' to file '%s'..\n", packageName, fileName.c_str());
93 TCU_CHECK(m_testCaseListFile = fopen(fileName.c_str(), "wb"));
95 if (runMode == RUNMODE_DUMP_XML_CASELIST)
97 TCU_CHECK(m_testCaseListWriter = qpXmlWriter_createFileWriter(m_testCaseListFile, DE_FALSE));
99 qpXmlWriter_startDocument(m_testCaseListWriter);
100 qpXmlWriter_startElement(m_testCaseListWriter, "TestCaseList", 0, DE_NULL);
104 // Initialize package.
107 // Store test case wrapper
108 m_testCaseWrapper = &testPackage->getTestCaseWrapper();
109 DE_ASSERT(m_testCaseWrapper);
112 m_testCtx.setCurrentArchive(testPackage->getArchive());
115 void TestExecutor::leaveTestPackage (TestPackage* testPackage)
117 DE_ASSERT(testPackage);
119 const RunMode runMode = m_cmdLine.getRunMode();
120 if (runMode == RUNMODE_DUMP_XML_CASELIST)
122 qpXmlWriter_endElement(m_testCaseListWriter, "TestCaseList");
123 qpXmlWriter_endDocument(m_testCaseListWriter);
124 qpXmlWriter_destroy(m_testCaseListWriter);
125 m_testCaseListWriter = DE_NULL;
128 if (runMode == RUNMODE_DUMP_TEXT_CASELIST || runMode == RUNMODE_DUMP_XML_CASELIST)
130 fclose(m_testCaseListFile);
131 m_testCaseListFile = DE_NULL;
134 DE_ASSERT(!m_testCaseListWriter && !m_testCaseListFile);
136 m_testCaseWrapper = DE_NULL;
137 m_testCtx.setCurrentArchive(m_testCtx.getRootArchive());
139 // Deinitialize package.
140 testPackage->deinit();
143 void TestExecutor::enterGroupNode (TestCaseGroup* testGroup, const char* casePath)
149 void TestExecutor::leaveGroupNode (TestCaseGroup* testGroup)
154 static qpTestCaseType nodeTypeToTestCaseType (TestNodeType nodeType)
158 case NODETYPE_SELF_VALIDATE: return QP_TEST_CASE_TYPE_SELF_VALIDATE;
159 case NODETYPE_PERFORMANCE: return QP_TEST_CASE_TYPE_PERFORMANCE;
160 case NODETYPE_CAPABILITY: return QP_TEST_CASE_TYPE_CAPABILITY;
161 case NODETYPE_ACCURACY: return QP_TEST_CASE_TYPE_ACCURACY;
164 return QP_TEST_CASE_TYPE_LAST;
168 bool TestExecutor::enterTestCase (TestCase* testCase, const char* casePath)
170 const RunMode runMode = m_cmdLine.getRunMode();
171 const qpTestCaseType caseType = nodeTypeToTestCaseType(testCase->getNodeType());
173 if (runMode == RUNMODE_EXECUTE)
175 print("\nTest case '%s'..\n", casePath);
177 m_testCtx.getLog().startCase(casePath, caseType);
178 m_isInTestCase = true;
179 m_testCtx.setTestResult(QP_TEST_RESULT_LAST, "");
181 if (!m_testCaseWrapper->initTestCase(testCase))
183 if (m_testCtx.getTestResult() == QP_TEST_RESULT_LAST)
184 m_testCtx.setTestResult(QP_TEST_RESULT_INTERNAL_ERROR, "Unexpected error in subcase init");
192 void TestExecutor::leaveTestCase (TestCase* testCase)
194 const RunMode runMode = m_cmdLine.getRunMode();
195 if (runMode == RUNMODE_EXECUTE)
198 const bool deinitOk = m_testCaseWrapper->deinitTestCase(testCase);
199 const qpTestResult testResult = m_testCtx.getTestResult();
200 const char* const testResultDesc = m_testCtx.getTestResultDesc();
201 const bool terminateAfter = m_testCtx.getTerminateAfter();
202 DE_ASSERT(testResult != QP_TEST_RESULT_LAST);
204 m_isInTestCase = false;
205 m_testCtx.getLog().endCase(testResult, testResultDesc);
207 // Update statistics.
208 print(" %s (%s)\n", qpGetTestResultName(testResult), testResultDesc);
210 m_result.numExecuted += 1;
213 case QP_TEST_RESULT_PASS: m_result.numPassed += 1; break;
214 case QP_TEST_RESULT_NOT_SUPPORTED: m_result.numNotSupported += 1; break;
215 case QP_TEST_RESULT_QUALITY_WARNING: m_result.numWarnings += 1; break;
216 case QP_TEST_RESULT_COMPATIBILITY_WARNING: m_result.numWarnings += 1; break;
217 default: m_result.numFailed += 1; break;
220 // terminateAfter, Resource error or any error in deinit means that execution should end
221 if (terminateAfter || !deinitOk || testResult == QP_TEST_RESULT_RESOURCE_ERROR)
222 m_abortSession = true;
224 // \todo [2011-02-09 pyry] Disable watchdog temporarily?
225 if (m_testCtx.getWatchDog())
226 qpWatchDog_reset(m_testCtx.getWatchDog());
230 // Return true while session should still continue, false otherwise.
231 bool TestExecutor::iterate (void)
235 while (!m_sessionStack.empty())
237 // Get full path to node.
238 string nodePath = "";
239 for (int ndx = 0; ndx < (int)m_sessionStack.size(); ndx++)
241 NodeIter& iter = m_sessionStack[ndx];
242 if (ndx > 1) // ignore root package
244 nodePath += iter.node->getName();
248 NodeIter& iter = m_sessionStack[m_sessionStack.size()-1];
249 DE_ASSERT(iter.node != DE_NULL);
250 TestNode* node = iter.node;
251 bool isLeaf = isTestNodeTypeExecutable(node->getNodeType());
253 switch (iter.getState())
255 case NodeIter::STATE_BEGIN:
257 // Return to parent if name doesn't match filter.
258 if (!(isLeaf ? m_cmdLine.checkTestCaseName(nodePath.c_str()) : m_cmdLine.checkTestGroupName(nodePath.c_str())))
260 m_sessionStack.pop_back();
266 switch (node->getNodeType())
268 case NODETYPE_ROOT: /* nada */ break;
269 case NODETYPE_PACKAGE: enterTestPackage(static_cast<TestPackage*>(node), nodePath.c_str()); break;
270 case NODETYPE_GROUP: enterGroupNode(static_cast<TestCaseGroup*>(node), nodePath.c_str()); break;
271 case NODETYPE_PERFORMANCE:
272 case NODETYPE_CAPABILITY:
273 case NODETYPE_ACCURACY: /* fall-trough */
274 case NODETYPE_SELF_VALIDATE: enterOk = enterTestCase(static_cast<TestCase*>(node), nodePath.c_str()); break;
275 default: DE_ASSERT(false);
278 if (m_cmdLine.getRunMode() == RUNMODE_EXECUTE)
283 iter.setState(NodeIter::STATE_EXECUTE_TEST);
285 iter.setState(NodeIter::STATE_FINISH);
289 iter.setState(NodeIter::STATE_TRAVERSE_CHILDREN);
292 else if (m_cmdLine.getRunMode() == RUNMODE_DUMP_XML_CASELIST)
294 if (node->getNodeType() != NODETYPE_ROOT && node->getNodeType() != NODETYPE_PACKAGE)
296 string caseName = iter.node->getName();
297 string description = iter.node->getDescription();
298 qpXmlAttribute attribs[8];
300 const char* caseType = DE_NULL;
302 switch (node->getNodeType())
304 case NODETYPE_SELF_VALIDATE: caseType = "SelfValidate"; break;
305 case NODETYPE_CAPABILITY: caseType = "Capability"; break;
306 case NODETYPE_ACCURACY: caseType = "Accuracy"; break;
307 case NODETYPE_PERFORMANCE: caseType = "Performance"; break;
308 default: caseType = "TestGroup"; break;
311 attribs[numAttribs++] = qpSetStringAttrib("Name", caseName.c_str());
312 attribs[numAttribs++] = qpSetStringAttrib("CaseType", caseType);
313 attribs[numAttribs++] = qpSetStringAttrib("Description", description.c_str());
314 qpXmlWriter_startElement(m_testCaseListWriter, "TestCase", numAttribs, attribs);
317 iter.setState(isLeaf ? NodeIter::STATE_FINISH : NodeIter::STATE_TRAVERSE_CHILDREN);
319 else if (m_cmdLine.getRunMode() == RUNMODE_DUMP_TEXT_CASELIST)
321 // \note Case list file is not open until we are in test package.
323 fprintf(m_testCaseListFile, "TEST: %s\n", nodePath.c_str());
324 else if (node->getNodeType() != NODETYPE_ROOT)
325 fprintf(m_testCaseListFile, "GROUP: %s\n", nodePath.c_str());
326 iter.setState(isLeaf ? NodeIter::STATE_FINISH : NodeIter::STATE_TRAVERSE_CHILDREN);
332 case NodeIter::STATE_EXECUTE_TEST:
334 // Touch the watchdog.
335 m_testCtx.touchWatchdog();
337 // Iterate the sub-case.
338 TestCase::IterateResult iterateResult = m_testCaseWrapper->iterateTestCase(static_cast<TestCase*>(node));
340 if (iterateResult == TestCase::STOP)
341 iter.setState(NodeIter::STATE_FINISH);
343 return true; // return after each iteration (when another iteration follows).
346 case NodeIter::STATE_TRAVERSE_CHILDREN:
348 int numChildren = (int)iter.children.size();
349 if (++iter.curChildNdx < numChildren)
351 // Push child to stack.
352 TestNode* childNode = iter.children[iter.curChildNdx];
353 m_sessionStack.push_back(NodeIter(childNode));
356 iter.setState(NodeIter::STATE_FINISH);
361 case NodeIter::STATE_FINISH:
363 if (m_cmdLine.getRunMode() == RUNMODE_DUMP_XML_CASELIST)
365 if (node->getNodeType() != NODETYPE_ROOT && node->getNodeType() != NODETYPE_PACKAGE)
366 qpXmlWriter_endElement(m_testCaseListWriter, "TestCase");
370 switch (node->getNodeType())
372 case NODETYPE_ROOT: /* nada */ break;
373 case NODETYPE_PACKAGE: leaveTestPackage(static_cast<TestPackage*>(node)); break;
374 case NODETYPE_GROUP: leaveGroupNode(static_cast<TestCaseGroup*>(node)); break;
375 case NODETYPE_ACCURACY:
376 case NODETYPE_CAPABILITY:
377 case NODETYPE_PERFORMANCE: /* fall-thru */
378 case NODETYPE_SELF_VALIDATE: leaveTestCase(static_cast<TestCase*>(node)); break;
379 default: DE_ASSERT(false);
382 m_sessionStack.pop_back();
384 // Return if execution should abort.
388 // Otherwise continue iterating.
398 catch (const std::exception& e)
400 print("TestExecutor::iterateSession(): Caught unhandled %s: %s\n", typeid(e).name(), e.what());
404 m_result.isComplete = true;