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
TestLogListener(JNIEnv * env,jobject object)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
~TestLogListener(void)104 TestLogListener::~TestLogListener (void)
105 {
106 }
107
beginSession(void)108 void TestLogListener::beginSession (void)
109 {
110 m_env->CallVoidMethod(m_object, m_beginSessionID);
111 }
112
endSession(void)113 void TestLogListener::endSession (void)
114 {
115 m_env->CallVoidMethod(m_object, m_endSessionID);
116 }
117
sessionInfo(const char * name,const char * value)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
beginTestCase(const char * testCasePath)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
endTestCase(void)136 void TestLogListener::endTestCase (void)
137 {
138 m_env->CallVoidMethod(m_object, m_endTestCaseID);
139 }
140
terminateTestCase(const char * reason)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
testCaseResult(const char * statusCode,const char * details)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
testLogData(const char * data)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
TestLogParser(bool logData)188 TestLogParser::TestLogParser (bool logData)
189 : m_logData (logData)
190 , m_inTestCase (DE_FALSE)
191 , m_loggedResult (DE_FALSE)
192 {
193 }
194
~TestLogParser(void)195 TestLogParser::~TestLogParser (void)
196 {
197 }
198
parse(TestLogListener & listener,const char * buffer,size_t size)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
throwJNIException(JNIEnv * env,const std::exception & e)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
Java_com_drawelements_deqp_testercore_TestLogParser_nativeCreate(JNIEnv * env,jclass,jboolean logData)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
Java_com_drawelements_deqp_testercore_TestLogParser_nativeDestroy(JNIEnv * env,jclass,jlong nativePointer)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
Java_com_drawelements_deqp_testercore_TestLogParser_nativeParse(JNIEnv * env,jclass,jlong nativePointer,jobject instrumentation,jbyteArray buffer,jint size)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