• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
nodeTypeToTestCaseType(TestNodeType nodeType)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 
TestSessionExecutor(TestPackageRoot & root,TestContext & testCtx)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 
~TestSessionExecutor(void)61 TestSessionExecutor::~TestSessionExecutor (void)
62 {
63 }
64 
iterate(void)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 
enterTestPackage(TestPackage * testPackage)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 
leaveTestPackage(TestPackage * testPackage)159 void TestSessionExecutor::leaveTestPackage (TestPackage* testPackage)
160 {
161 	DE_UNREF(testPackage);
162 	m_caseExecutor.clear();
163 }
164 
enterTestCase(TestCase * testCase,const std::string & casePath)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 
leaveTestCase(TestCase * testCase)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 
iterateTestCase(TestCase * testCase)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