Home | History | Annotate | Download | only in android
      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 Android JNI interface for instrumentations log parsing.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "tcuDefs.hpp"
     25 
     26 #include "xeTestResultParser.hpp"
     27 #include "xeTestCaseResult.hpp"
     28 #include "xeContainerFormatParser.hpp"
     29 #include "xeTestLogWriter.hpp"
     30 #include "xeXMLWriter.hpp"
     31 
     32 #include <jni.h>
     33 #include <stdlib.h>
     34 #include <android/log.h>
     35 
     36 #include <sstream>
     37 
     38 namespace
     39 {
     40 static const char*	TESTCASE_STYLESHEET	= "testlog.xsl";
     41 static const char*	LOG_TAG				= "dEQP-TestLog";
     42 
     43 class TestLogListener
     44 {
     45 public:
     46 						TestLogListener		(JNIEnv* env, jobject object);
     47 						~TestLogListener	(void);
     48 
     49 	void				beginSession		(void);
     50 	void				endSession			(void);
     51 	void				sessionInfo			(const char* name, const char* value);
     52 
     53 	void				beginTestCase		(const char* testCasePath);
     54 	void				endTestCase			(void);
     55 
     56 	void				terminateTestCase	(const char* reason);
     57 	void				testCaseResult		(const char* statusCode, const char* details);
     58 
     59 	void				testLogData			(const char* data);
     60 
     61 private:
     62 	JNIEnv*				m_env;
     63 	jobject				m_object;
     64 	jclass				m_class;
     65 
     66 	jmethodID			m_sessionInfoID;
     67 	jmethodID			m_beginSessionID;
     68 	jmethodID			m_endSessionID;
     69 
     70 	jmethodID			m_beginTestCaseID;
     71 	jmethodID			m_endTestCaseID;
     72 	jmethodID			m_terminateTestCaseID;
     73 	jmethodID			m_testCaseResultID;
     74 	jmethodID			m_testLogData;
     75 
     76 						TestLogListener		(const TestLogListener&);
     77 	TestLogListener&	operator=			(const TestLogListener&);
     78 };
     79 
     80 TestLogListener::TestLogListener (JNIEnv* env, jobject object)
     81 	: m_env		(env)
     82 	, m_object	(object)
     83 {
     84 	m_class					= m_env->GetObjectClass(m_object);
     85 	m_sessionInfoID			= m_env->GetMethodID(m_class, "sessionInfo",		"(Ljava/lang/String;Ljava/lang/String;)V");
     86 	m_beginSessionID		= m_env->GetMethodID(m_class, "beginSession",		"()V");
     87 	m_endSessionID			= m_env->GetMethodID(m_class, "endSession",			"()V");
     88 	m_beginTestCaseID		= m_env->GetMethodID(m_class, "beginTestCase",		"(Ljava/lang/String;)V");
     89 	m_endTestCaseID			= m_env->GetMethodID(m_class, "endTestCase",		"()V");
     90 	m_terminateTestCaseID	= m_env->GetMethodID(m_class, "terminateTestCase",	"(Ljava/lang/String;)V");
     91 	m_testCaseResultID		= m_env->GetMethodID(m_class, "testCaseResult",		"(Ljava/lang/String;Ljava/lang/String;)V");
     92 	m_testLogData			= m_env->GetMethodID(m_class, "testLogData",		"(Ljava/lang/String;)V");
     93 
     94 	TCU_CHECK_INTERNAL(m_beginSessionID);
     95 	TCU_CHECK_INTERNAL(m_endSessionID);
     96 	TCU_CHECK_INTERNAL(m_sessionInfoID);
     97 	TCU_CHECK_INTERNAL(m_beginTestCaseID);
     98 	TCU_CHECK_INTERNAL(m_endTestCaseID);
     99 	TCU_CHECK_INTERNAL(m_terminateTestCaseID);
    100 	TCU_CHECK_INTERNAL(m_testCaseResultID);
    101 	TCU_CHECK_INTERNAL(m_testLogData);
    102 }
    103 
    104 TestLogListener::~TestLogListener (void)
    105 {
    106 }
    107 
    108 void TestLogListener::beginSession (void)
    109 {
    110 	m_env->CallVoidMethod(m_object, m_beginSessionID);
    111 }
    112 
    113 void TestLogListener::endSession (void)
    114 {
    115 	m_env->CallVoidMethod(m_object, m_endSessionID);
    116 }
    117 
    118 void TestLogListener::sessionInfo (const char* name, const char* value)
    119 {
    120 	jstring jName	= m_env->NewStringUTF(name);
    121 	jstring jValue	= m_env->NewStringUTF(value);
    122 
    123 	m_env->CallVoidMethod(m_object, m_sessionInfoID, jName, jValue);
    124 	m_env->DeleteLocalRef(jName);
    125 	m_env->DeleteLocalRef(jValue);
    126 }
    127 
    128 void TestLogListener::beginTestCase (const char* testCasePath)
    129 {
    130 	jstring jTestCasePath = m_env->NewStringUTF(testCasePath);
    131 
    132 	m_env->CallVoidMethod(m_object, m_beginTestCaseID, jTestCasePath);
    133 	m_env->DeleteLocalRef(jTestCasePath);
    134 }
    135 
    136 void TestLogListener::endTestCase (void)
    137 {
    138 	m_env->CallVoidMethod(m_object, m_endTestCaseID);
    139 }
    140 
    141 void TestLogListener::terminateTestCase (const char* reason)
    142 {
    143 	jstring	 jReason = m_env->NewStringUTF(reason);
    144 
    145 	m_env->CallVoidMethod(m_object, m_terminateTestCaseID, jReason);
    146 	m_env->DeleteLocalRef(jReason);
    147 }
    148 
    149 void TestLogListener::testCaseResult (const char* statusCode, const char* details)
    150 {
    151 	jstring	 jStatusCode	= m_env->NewStringUTF(statusCode);
    152 	jstring	 jDetails		= m_env->NewStringUTF(details);
    153 
    154 	m_env->CallVoidMethod(m_object, m_testCaseResultID, jStatusCode, jDetails);
    155 	m_env->DeleteLocalRef(jStatusCode);
    156 	m_env->DeleteLocalRef(jDetails);
    157 }
    158 
    159 void TestLogListener::testLogData (const char* data)
    160 {
    161 	jstring logData = m_env->NewStringUTF(data);
    162 
    163 	m_env->CallVoidMethod(m_object, m_testLogData, logData);
    164 	m_env->DeleteLocalRef(logData);
    165 }
    166 
    167 class TestLogParser
    168 {
    169 public:
    170 								TestLogParser	(bool logData);
    171 								~TestLogParser	(void);
    172 
    173 	void						parse			(TestLogListener& listener, const char* buffer, size_t size);
    174 
    175 private:
    176 	const bool					m_logData;
    177 
    178 	bool						m_inTestCase;
    179 	bool						m_loggedResult;
    180 	xe::ContainerFormatParser	m_containerParser;
    181 	xe::TestCaseResult			m_testCaseResult;
    182 	xe::TestResultParser		m_testResultParser;
    183 
    184 								TestLogParser	(const TestLogParser&);
    185 	TestLogParser&				operator=		(const TestLogParser&);
    186 };
    187 
    188 TestLogParser::TestLogParser (bool logData)
    189 	: m_logData			(logData)
    190 	, m_inTestCase		(DE_FALSE)
    191 	, m_loggedResult	(DE_FALSE)
    192 {
    193 }
    194 
    195 TestLogParser::~TestLogParser (void)
    196 {
    197 }
    198 
    199 void TestLogParser::parse (TestLogListener& listener, const char* buffer, size_t size)
    200 {
    201 	m_containerParser.feed((const deUint8*)buffer, size);
    202 
    203 	while (m_containerParser.getElement() != xe::CONTAINERELEMENT_INCOMPLETE)
    204 	{
    205 		switch (m_containerParser.getElement())
    206 		{
    207 			case xe::CONTAINERELEMENT_END_OF_STRING:
    208 				// Do nothing
    209 				break;
    210 
    211 			case xe::CONTAINERELEMENT_BEGIN_SESSION:
    212 				listener.beginSession();
    213 				break;
    214 
    215 			case xe::CONTAINERELEMENT_END_SESSION:
    216 				listener.endSession();
    217 				break;
    218 
    219 			case xe::CONTAINERELEMENT_SESSION_INFO:
    220 				listener.sessionInfo(m_containerParser.getSessionInfoAttribute(), m_containerParser.getSessionInfoValue());
    221 				break;
    222 
    223 			case xe::CONTAINERELEMENT_BEGIN_TEST_CASE_RESULT:
    224 				listener.beginTestCase(m_containerParser.getTestCasePath());
    225 
    226 				m_inTestCase		= DE_TRUE;
    227 				m_loggedResult		= DE_FALSE;
    228 				m_testCaseResult	= xe::TestCaseResult();
    229 
    230 				m_testResultParser.init(&m_testCaseResult);
    231 				break;
    232 
    233 			case xe::CONTAINERELEMENT_END_TEST_CASE_RESULT:
    234 				if (m_testCaseResult.statusCode != xe::TESTSTATUSCODE_LAST && !m_loggedResult)
    235 				{
    236 					listener.testCaseResult(xe::getTestStatusCodeName(m_testCaseResult.statusCode), m_testCaseResult.statusDetails.c_str());
    237 					m_loggedResult = DE_TRUE;
    238 				}
    239 
    240 				if (m_logData)
    241 				{
    242 					std::ostringstream	testLog;
    243 					xe::xml::Writer		xmlWriter(testLog);
    244 
    245 					testLog << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
    246 							<< "<?xml-stylesheet href=\"" << TESTCASE_STYLESHEET << "\" type=\"text/xsl\"?>\n";
    247 
    248 					xe::writeTestResult(m_testCaseResult, xmlWriter);
    249 
    250 					listener.testLogData(testLog.str().c_str());
    251 				}
    252 
    253 				listener.endTestCase();
    254 
    255 				m_inTestCase = DE_FALSE;
    256 				break;
    257 
    258 			case xe::CONTAINERELEMENT_TERMINATE_TEST_CASE_RESULT:
    259 				if (m_logData)
    260 				{
    261 					std::ostringstream	testLog;
    262 					xe::xml::Writer		xmlWriter(testLog);
    263 
    264 					testLog << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
    265 							<< "<?xml-stylesheet href=\"" << TESTCASE_STYLESHEET << "\" type=\"text/xsl\"?>\n";
    266 
    267 					xe::writeTestResult(m_testCaseResult, xmlWriter);
    268 
    269 					listener.testLogData(testLog.str().c_str());
    270 				}
    271 
    272 				if (m_testCaseResult.statusCode != xe::TESTSTATUSCODE_LAST && !m_loggedResult)
    273 				{
    274 					listener.testCaseResult(xe::getTestStatusCodeName(m_testCaseResult.statusCode), m_testCaseResult.statusDetails.c_str());
    275 					m_loggedResult = DE_TRUE;
    276 				}
    277 
    278 				listener.terminateTestCase(m_containerParser.getTerminateReason());
    279 				m_inTestCase = DE_FALSE;
    280 				break;
    281 
    282 			case xe::CONTAINERELEMENT_TEST_LOG_DATA:
    283 			{
    284 				if (m_inTestCase)
    285 				{
    286 					std::vector<deUint8> data(m_containerParser.getDataSize());
    287 					m_containerParser.getData(&(data[0]), (int)data.size(), 0);
    288 
    289 					//tcu::print("%d %s :%s %s", __LINE__, std::string((const char*)&data[0], data.size()).c_str(), __func__, __FILE__);
    290 
    291 					if (m_testResultParser.parse(&(data[0]), (int)data.size()) == xe::TestResultParser::PARSERESULT_CHANGED)
    292 					{
    293 						if (m_testCaseResult.statusCode != xe::TESTSTATUSCODE_LAST && !m_loggedResult)
    294 						{
    295 							listener.testCaseResult(xe::getTestStatusCodeName(m_testCaseResult.statusCode), m_testCaseResult.statusDetails.c_str());
    296 							m_loggedResult = DE_TRUE;
    297 						}
    298 					}
    299 				}
    300 
    301 				break;
    302 			}
    303 
    304 			default:
    305 				DE_ASSERT(DE_FALSE);
    306 
    307 		};
    308 
    309 		m_containerParser.advance();
    310 	}
    311 }
    312 
    313 void throwJNIException (JNIEnv* env, const std::exception& e)
    314 {
    315 	jclass exClass;
    316 
    317 	exClass = env->FindClass("java/lang/Exception");
    318 
    319 	TCU_CHECK_INTERNAL(exClass != DE_NULL);
    320 
    321 	TCU_CHECK_INTERNAL(env->ThrowNew(exClass, e.what()) == 0);
    322 }
    323 
    324 } // anonymous
    325 
    326 DE_BEGIN_EXTERN_C
    327 
    328 JNIEXPORT jlong JNICALL Java_com_drawelements_deqp_testercore_TestLogParser_nativeCreate (JNIEnv* env, jclass, jboolean logData)
    329 {
    330 	DE_UNREF(env);
    331 
    332 	try
    333 	{
    334 		return (jlong)new TestLogParser(logData);
    335 	}
    336 	catch (const std::exception& e)
    337 	{
    338 		__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", e.what());
    339 
    340 		throwJNIException(env, e);
    341 		return 0;
    342 	}
    343 }
    344 
    345 JNIEXPORT void JNICALL Java_com_drawelements_deqp_testercore_TestLogParser_nativeDestroy (JNIEnv* env, jclass, jlong nativePointer)
    346 {
    347 	DE_UNREF(env);
    348 
    349 	try
    350 	{
    351 		delete ((TestLogParser*)nativePointer);
    352 	}
    353 	catch (const std::exception& e)
    354 	{
    355 		__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", e.what());
    356 
    357 		throwJNIException(env, e);
    358 	}
    359 }
    360 
    361 JNIEXPORT void JNICALL Java_com_drawelements_deqp_testercore_TestLogParser_nativeParse (JNIEnv* env, jclass, jlong nativePointer, jobject instrumentation, jbyteArray buffer, jint size)
    362 {
    363 	jbyte* logData = DE_NULL;
    364 
    365 	try
    366 	{
    367 		TestLogParser*	parser		= (TestLogParser*)nativePointer;
    368 		TestLogListener	listener	(env, instrumentation);
    369 
    370 		logData = env->GetByteArrayElements(buffer, NULL);
    371 
    372 		parser->parse(listener, (const char*)logData, (size_t)size);
    373 		env->ReleaseByteArrayElements(buffer, logData, JNI_ABORT);
    374 		logData = DE_NULL;
    375 	}
    376 	catch (const std::exception& e)
    377 	{
    378 		__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", e.what());
    379 
    380 		if (logData)
    381 			env->ReleaseByteArrayElements(buffer, logData, JNI_ABORT);
    382 
    383 		throwJNIException(env, e);
    384 	}
    385 }
    386 
    387 DE_END_EXTERN_C
    388