1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program Tester Core 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 Test executor. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "tcuTestSessionExecutor.hpp" 25 #include "tcuCommandLine.hpp" 26 #include "tcuTestLog.hpp" 27 28 #include "deClock.h" 29 30 namespace tcu 31 { 32 33 using std::vector; 34 35 static qpTestCaseType nodeTypeToTestCaseType (TestNodeType nodeType) 36 { 37 switch (nodeType) 38 { 39 case NODETYPE_SELF_VALIDATE: return QP_TEST_CASE_TYPE_SELF_VALIDATE; 40 case NODETYPE_PERFORMANCE: return QP_TEST_CASE_TYPE_PERFORMANCE; 41 case NODETYPE_CAPABILITY: return QP_TEST_CASE_TYPE_CAPABILITY; 42 case NODETYPE_ACCURACY: return QP_TEST_CASE_TYPE_ACCURACY; 43 default: 44 DE_ASSERT(false); 45 return QP_TEST_CASE_TYPE_LAST; 46 } 47 } 48 49 TestSessionExecutor::TestSessionExecutor (TestPackageRoot& root, TestContext& testCtx) 50 : m_testCtx (testCtx) 51 , m_inflater (testCtx) 52 , m_caseListFilter (testCtx.getCommandLine().createCaseListFilter(testCtx.getArchive())) 53 , m_iterator (root, m_inflater, *m_caseListFilter) 54 , m_state (STATE_TRAVERSE_HIERARCHY) 55 , m_abortSession (false) 56 , m_isInTestCase (false) 57 , m_testStartTime (0) 58 { 59 } 60 61 TestSessionExecutor::~TestSessionExecutor (void) 62 { 63 } 64 65 bool TestSessionExecutor::iterate (void) 66 { 67 while (!m_abortSession) 68 { 69 switch (m_state) 70 { 71 case STATE_TRAVERSE_HIERARCHY: 72 { 73 const TestHierarchyIterator::State hierIterState = m_iterator.getState(); 74 75 if (hierIterState == TestHierarchyIterator::STATE_ENTER_NODE || 76 hierIterState == TestHierarchyIterator::STATE_LEAVE_NODE) 77 { 78 TestNode* const curNode = m_iterator.getNode(); 79 const TestNodeType nodeType = curNode->getNodeType(); 80 const bool isEnter = hierIterState == TestHierarchyIterator::STATE_ENTER_NODE; 81 82 switch (nodeType) 83 { 84 case NODETYPE_PACKAGE: 85 { 86 TestPackage* const testPackage = static_cast<TestPackage*>(curNode); 87 isEnter ? enterTestPackage(testPackage) : leaveTestPackage(testPackage); 88 break; 89 } 90 91 case NODETYPE_GROUP: 92 break; // nada 93 94 case NODETYPE_SELF_VALIDATE: 95 case NODETYPE_PERFORMANCE: 96 case NODETYPE_CAPABILITY: 97 case NODETYPE_ACCURACY: 98 { 99 TestCase* const testCase = static_cast<TestCase*>(curNode); 100 101 if (isEnter) 102 { 103 if (enterTestCase(testCase, m_iterator.getNodePath())) 104 m_state = STATE_EXECUTE_TEST_CASE; 105 // else remain in TRAVERSING_HIERARCHY => node will be exited from in the next iteration 106 } 107 else 108 leaveTestCase(testCase); 109 110 break; 111 } 112 113 default: 114 DE_ASSERT(false); 115 break; 116 } 117 118 m_iterator.next(); 119 break; 120 } 121 else 122 { 123 DE_ASSERT(hierIterState == TestHierarchyIterator::STATE_FINISHED); 124 m_status.isComplete = true; 125 return false; 126 } 127 } 128 129 case STATE_EXECUTE_TEST_CASE: 130 { 131 DE_ASSERT(m_iterator.getState() == TestHierarchyIterator::STATE_LEAVE_NODE && 132 isTestNodeTypeExecutable(m_iterator.getNode()->getNodeType())); 133 134 TestCase* const testCase = static_cast<TestCase*>(m_iterator.getNode()); 135 const TestCase::IterateResult iterResult = iterateTestCase(testCase); 136 137 if (iterResult == TestCase::STOP) 138 m_state = STATE_TRAVERSE_HIERARCHY; 139 140 return true; 141 } 142 143 default: 144 DE_ASSERT(false); 145 break; 146 } 147 } 148 149 return false; 150 } 151 152 void TestSessionExecutor::enterTestPackage (TestPackage* testPackage) 153 { 154 // Create test case wrapper 155 DE_ASSERT(!m_caseExecutor); 156 m_caseExecutor = de::MovePtr<TestCaseExecutor>(testPackage->createExecutor()); 157 } 158 159 void TestSessionExecutor::leaveTestPackage (TestPackage* testPackage) 160 { 161 DE_UNREF(testPackage); 162 m_caseExecutor.clear(); 163 } 164 165 bool TestSessionExecutor::enterTestCase (TestCase* testCase, const std::string& casePath) 166 { 167 TestLog& log = m_testCtx.getLog(); 168 const qpTestCaseType caseType = nodeTypeToTestCaseType(testCase->getNodeType()); 169 bool initOk = false; 170 171 print("\nTest case '%s'..\n", casePath.c_str()); 172 173 m_testCtx.setTestResult(QP_TEST_RESULT_LAST, ""); 174 m_testCtx.setTerminateAfter(false); 175 log.startCase(casePath.c_str(), caseType); 176 177 m_isInTestCase = true; 178 m_testStartTime = deGetMicroseconds(); 179 180 try 181 { 182 m_caseExecutor->init(testCase, casePath); 183 initOk = true; 184 } 185 catch (const std::bad_alloc&) 186 { 187 DE_ASSERT(!initOk); 188 m_testCtx.setTestResult(QP_TEST_RESULT_RESOURCE_ERROR, "Failed to allocate memory in test case init"); 189 m_testCtx.setTerminateAfter(true); 190 } 191 catch (const tcu::TestException& e) 192 { 193 DE_ASSERT(!initOk); 194 DE_ASSERT(e.getTestResult() != QP_TEST_RESULT_LAST); 195 m_testCtx.setTestResult(e.getTestResult(), e.getMessage()); 196 m_testCtx.setTerminateAfter(e.isFatal()); 197 log << e; 198 } 199 catch (const tcu::Exception& e) 200 { 201 DE_ASSERT(!initOk); 202 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, e.getMessage()); 203 log << e; 204 } 205 206 DE_ASSERT(initOk || m_testCtx.getTestResult() != QP_TEST_RESULT_LAST); 207 208 return initOk; 209 } 210 211 void TestSessionExecutor::leaveTestCase (TestCase* testCase) 212 { 213 TestLog& log = m_testCtx.getLog(); 214 215 // De-init case. 216 try 217 { 218 m_caseExecutor->deinit(testCase); 219 } 220 catch (const tcu::Exception& e) 221 { 222 log << e << TestLog::Message << "Error in test case deinit, test program will terminate." << TestLog::EndMessage; 223 m_testCtx.setTerminateAfter(true); 224 } 225 226 { 227 const deInt64 duration = deGetMicroseconds()-m_testStartTime; 228 m_testStartTime = 0; 229 m_testCtx.getLog() << TestLog::Integer("TestDuration", "Test case duration in microseconds", "us", QP_KEY_TAG_TIME, duration); 230 } 231 232 { 233 const qpTestResult testResult = m_testCtx.getTestResult(); 234 const char* const testResultDesc = m_testCtx.getTestResultDesc(); 235 const bool terminateAfter = m_testCtx.getTerminateAfter(); 236 DE_ASSERT(testResult != QP_TEST_RESULT_LAST); 237 238 m_isInTestCase = false; 239 m_testCtx.getLog().endCase(testResult, testResultDesc); 240 241 // Update statistics. 242 print(" %s (%s)\n", qpGetTestResultName(testResult), testResultDesc); 243 244 m_status.numExecuted += 1; 245 switch (testResult) 246 { 247 case QP_TEST_RESULT_PASS: m_status.numPassed += 1; break; 248 case QP_TEST_RESULT_NOT_SUPPORTED: m_status.numNotSupported += 1; break; 249 case QP_TEST_RESULT_QUALITY_WARNING: m_status.numWarnings += 1; break; 250 case QP_TEST_RESULT_COMPATIBILITY_WARNING: m_status.numWarnings += 1; break; 251 default: m_status.numFailed += 1; break; 252 } 253 254 // terminateAfter, Resource error or any error in deinit means that execution should end 255 if (terminateAfter || testResult == QP_TEST_RESULT_RESOURCE_ERROR) 256 m_abortSession = true; 257 } 258 259 if (m_testCtx.getWatchDog()) 260 qpWatchDog_reset(m_testCtx.getWatchDog()); 261 } 262 263 TestCase::IterateResult TestSessionExecutor::iterateTestCase (TestCase* testCase) 264 { 265 TestLog& log = m_testCtx.getLog(); 266 TestCase::IterateResult iterateResult = TestCase::STOP; 267 268 m_testCtx.touchWatchdog(); 269 270 try 271 { 272 iterateResult = m_caseExecutor->iterate(testCase); 273 } 274 catch (const std::bad_alloc&) 275 { 276 m_testCtx.setTestResult(QP_TEST_RESULT_RESOURCE_ERROR, "Failed to allocate memory during test execution"); 277 m_testCtx.setTerminateAfter(true); 278 } 279 catch (const tcu::TestException& e) 280 { 281 log << e; 282 m_testCtx.setTestResult(e.getTestResult(), e.getMessage()); 283 m_testCtx.setTerminateAfter(e.isFatal()); 284 } 285 catch (const tcu::Exception& e) 286 { 287 log << e; 288 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, e.getMessage()); 289 } 290 291 return iterateResult; 292 } 293 294 } // tcu 295