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