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 virtual ~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 virtual void beginTestRunParamsCollection(void);
62 virtual void endTestRunParamsCollection(void);
63 virtual void beginTestRunParams(const char *testRunsParams);
64 virtual void endTestRunParams(void);
65
66 protected:
67 JNIEnv *m_env;
68 jobject m_object;
69 jclass m_class;
70
71 jmethodID m_sessionInfoID;
72 jmethodID m_beginSessionID;
73 jmethodID m_endSessionID;
74
75 jmethodID m_beginTestCaseID;
76 jmethodID m_endTestCaseID;
77 jmethodID m_terminateTestCaseID;
78 jmethodID m_testCaseResultID;
79 jmethodID m_testLogData;
80
81 TestLogListener(const TestLogListener &);
82 TestLogListener &operator=(const TestLogListener &);
83 };
84
TestLogListener(JNIEnv * env,jobject object)85 TestLogListener::TestLogListener(JNIEnv *env, jobject object) : m_env(env), m_object(object)
86 {
87 m_class = m_env->GetObjectClass(m_object);
88 m_sessionInfoID = m_env->GetMethodID(m_class, "sessionInfo", "(Ljava/lang/String;Ljava/lang/String;)V");
89 m_beginSessionID = m_env->GetMethodID(m_class, "beginSession", "()V");
90 m_endSessionID = m_env->GetMethodID(m_class, "endSession", "()V");
91 m_beginTestCaseID = m_env->GetMethodID(m_class, "beginTestCase", "(Ljava/lang/String;)V");
92 m_endTestCaseID = m_env->GetMethodID(m_class, "endTestCase", "()V");
93 m_terminateTestCaseID = m_env->GetMethodID(m_class, "terminateTestCase", "(Ljava/lang/String;)V");
94 m_testCaseResultID = m_env->GetMethodID(m_class, "testCaseResult", "(Ljava/lang/String;Ljava/lang/String;)V");
95 m_testLogData = m_env->GetMethodID(m_class, "testLogData", "(Ljava/lang/String;)V");
96
97 TCU_CHECK_INTERNAL(m_beginSessionID);
98 TCU_CHECK_INTERNAL(m_endSessionID);
99 TCU_CHECK_INTERNAL(m_sessionInfoID);
100 TCU_CHECK_INTERNAL(m_beginTestCaseID);
101 TCU_CHECK_INTERNAL(m_endTestCaseID);
102 TCU_CHECK_INTERNAL(m_terminateTestCaseID);
103 TCU_CHECK_INTERNAL(m_testCaseResultID);
104 TCU_CHECK_INTERNAL(m_testLogData);
105 }
106
~TestLogListener(void)107 TestLogListener::~TestLogListener(void)
108 {
109 }
110
beginSession(void)111 void TestLogListener::beginSession(void)
112 {
113 m_env->CallVoidMethod(m_object, m_beginSessionID);
114 }
115
endSession(void)116 void TestLogListener::endSession(void)
117 {
118 m_env->CallVoidMethod(m_object, m_endSessionID);
119 }
120
sessionInfo(const char * name,const char * value)121 void TestLogListener::sessionInfo(const char *name, const char *value)
122 {
123 jstring jName = m_env->NewStringUTF(name);
124 jstring jValue = m_env->NewStringUTF(value);
125
126 m_env->CallVoidMethod(m_object, m_sessionInfoID, jName, jValue);
127 m_env->DeleteLocalRef(jName);
128 m_env->DeleteLocalRef(jValue);
129 }
130
beginTestCase(const char * testCasePath)131 void TestLogListener::beginTestCase(const char *testCasePath)
132 {
133 jstring jTestCasePath = m_env->NewStringUTF(testCasePath);
134
135 m_env->CallVoidMethod(m_object, m_beginTestCaseID, jTestCasePath);
136 m_env->DeleteLocalRef(jTestCasePath);
137 }
138
endTestCase(void)139 void TestLogListener::endTestCase(void)
140 {
141 m_env->CallVoidMethod(m_object, m_endTestCaseID);
142 }
143
terminateTestCase(const char * reason)144 void TestLogListener::terminateTestCase(const char *reason)
145 {
146 jstring jReason = m_env->NewStringUTF(reason);
147
148 m_env->CallVoidMethod(m_object, m_terminateTestCaseID, jReason);
149 m_env->DeleteLocalRef(jReason);
150 }
151
testCaseResult(const char * statusCode,const char * details)152 void TestLogListener::testCaseResult(const char *statusCode, const char *details)
153 {
154 jstring jStatusCode = m_env->NewStringUTF(statusCode);
155 jstring jDetails = m_env->NewStringUTF(details);
156
157 m_env->CallVoidMethod(m_object, m_testCaseResultID, jStatusCode, jDetails);
158 m_env->DeleteLocalRef(jStatusCode);
159 m_env->DeleteLocalRef(jDetails);
160 }
161
testLogData(const char * data)162 void TestLogListener::testLogData(const char *data)
163 {
164 jstring logData = m_env->NewStringUTF(data);
165
166 m_env->CallVoidMethod(m_object, m_testLogData, logData);
167 m_env->DeleteLocalRef(logData);
168 }
169
beginTestRunParamsCollection(void)170 void TestLogListener::beginTestRunParamsCollection(void)
171 {
172 }
173
endTestRunParamsCollection(void)174 void TestLogListener::endTestRunParamsCollection(void)
175 {
176 }
177
beginTestRunParams(const char *)178 void TestLogListener::beginTestRunParams(const char *)
179 {
180 }
181
endTestRunParams(void)182 void TestLogListener::endTestRunParams(void)
183 {
184 }
185
186 class KhronosCTSTestLogListener : public TestLogListener
187 {
188 public:
189 KhronosCTSTestLogListener(JNIEnv *env, jobject object);
190 virtual ~KhronosCTSTestLogListener();
191
192 virtual void beginTestRunParamsCollection(void);
193 virtual void endTestRunParamsCollection(void);
194 virtual void beginTestRunParams(const char *testRunsParams);
195 virtual void endTestRunParams(void);
196
197 private:
198 jmethodID m_beginTestRunParamsCollectionID;
199 jmethodID m_endTestRunParamsCollectionID;
200 jmethodID m_beginTestRunParamsID;
201 jmethodID m_endTestRunParamsID;
202 };
203
KhronosCTSTestLogListener(JNIEnv * env,jobject object)204 KhronosCTSTestLogListener::KhronosCTSTestLogListener(JNIEnv *env, jobject object) : TestLogListener(env, object)
205 {
206
207 m_beginTestRunParamsCollectionID = m_env->GetMethodID(m_class, "beginTestRunParamsCollection", "()V");
208 m_endTestRunParamsCollectionID = m_env->GetMethodID(m_class, "endTestRunParamsCollection", "()V");
209 m_beginTestRunParamsID = m_env->GetMethodID(m_class, "beginTestRunParams", "(Ljava/lang/String;)V");
210 m_endTestRunParamsID = m_env->GetMethodID(m_class, "endTestRunParams", "()V");
211
212 TCU_CHECK_INTERNAL(m_beginTestRunParamsCollectionID);
213 TCU_CHECK_INTERNAL(m_endTestRunParamsCollectionID);
214 TCU_CHECK_INTERNAL(m_beginTestRunParamsID);
215 TCU_CHECK_INTERNAL(m_endTestRunParamsID);
216 }
217
~KhronosCTSTestLogListener(void)218 KhronosCTSTestLogListener::~KhronosCTSTestLogListener(void)
219 {
220 }
221
beginTestRunParamsCollection(void)222 void KhronosCTSTestLogListener::beginTestRunParamsCollection(void)
223 {
224 m_env->CallVoidMethod(m_object, m_beginTestRunParamsCollectionID);
225 }
226
endTestRunParamsCollection(void)227 void KhronosCTSTestLogListener::endTestRunParamsCollection(void)
228 {
229 m_env->CallVoidMethod(m_object, m_endTestRunParamsCollectionID);
230 }
231
beginTestRunParams(const char * testRunsParams)232 void KhronosCTSTestLogListener::beginTestRunParams(const char *testRunsParams)
233 {
234 jstring jTestRunsParams = m_env->NewStringUTF(testRunsParams);
235 m_env->CallVoidMethod(m_object, m_beginTestRunParamsID, jTestRunsParams);
236 m_env->DeleteLocalRef(jTestRunsParams);
237 }
238
endTestRunParams(void)239 void KhronosCTSTestLogListener::endTestRunParams(void)
240 {
241 m_env->CallVoidMethod(m_object, m_endTestRunParamsID);
242 }
243
244 class TestLogParser
245 {
246 public:
247 TestLogParser(bool logData);
248 ~TestLogParser(void);
249
250 void parse(TestLogListener *listener, const char *buffer, size_t size);
251
252 private:
253 const bool m_logData;
254
255 bool m_inTestCase;
256 bool m_loggedResult;
257 xe::ContainerFormatParser m_containerParser;
258 xe::TestCaseResult m_testCaseResult;
259 xe::TestResultParser m_testResultParser;
260
261 TestLogParser(const TestLogParser &);
262 TestLogParser &operator=(const TestLogParser &);
263 };
264
TestLogParser(bool logData)265 TestLogParser::TestLogParser(bool logData) : m_logData(logData), m_inTestCase(false), m_loggedResult(false)
266 {
267 }
268
~TestLogParser(void)269 TestLogParser::~TestLogParser(void)
270 {
271 }
272
parse(TestLogListener * listener,const char * buffer,size_t size)273 void TestLogParser::parse(TestLogListener *listener, const char *buffer, size_t size)
274 {
275 m_containerParser.feed((const uint8_t *)buffer, size);
276
277 while (m_containerParser.getElement() != xe::CONTAINERELEMENT_INCOMPLETE)
278 {
279 switch (m_containerParser.getElement())
280 {
281 case xe::CONTAINERELEMENT_END_OF_STRING:
282 // Do nothing
283 break;
284
285 case xe::CONTAINERELEMENT_BEGIN_SESSION:
286 listener->beginSession();
287 break;
288
289 case xe::CONTAINERELEMENT_END_SESSION:
290 listener->endSession();
291 break;
292
293 case xe::CONTAINERELEMENT_SESSION_INFO:
294 listener->sessionInfo(m_containerParser.getSessionInfoAttribute(), m_containerParser.getSessionInfoValue());
295 break;
296
297 case xe::CONTAINERELEMENT_BEGIN_TEST_CASE_RESULT:
298 listener->beginTestCase(m_containerParser.getTestCasePath());
299
300 m_inTestCase = true;
301 m_loggedResult = false;
302 m_testCaseResult = xe::TestCaseResult();
303
304 m_testResultParser.init(&m_testCaseResult);
305 break;
306
307 case xe::CONTAINERELEMENT_END_TEST_CASE_RESULT:
308 if (m_testCaseResult.statusCode != xe::TESTSTATUSCODE_LAST && !m_loggedResult)
309 {
310 listener->testCaseResult(xe::getTestStatusCodeName(m_testCaseResult.statusCode),
311 m_testCaseResult.statusDetails.c_str());
312 m_loggedResult = true;
313 }
314
315 if (m_logData)
316 {
317 std::ostringstream testLog;
318 xe::xml::Writer xmlWriter(testLog);
319
320 testLog << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
321 << "<?xml-stylesheet href=\"" << TESTCASE_STYLESHEET << "\" type=\"text/xsl\"?>\n";
322
323 xe::writeTestResult(m_testCaseResult, xmlWriter);
324
325 listener->testLogData(testLog.str().c_str());
326 }
327
328 listener->endTestCase();
329
330 m_inTestCase = false;
331 break;
332
333 case xe::CONTAINERELEMENT_TERMINATE_TEST_CASE_RESULT:
334 if (m_logData)
335 {
336 std::ostringstream testLog;
337 xe::xml::Writer xmlWriter(testLog);
338
339 testLog << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
340 << "<?xml-stylesheet href=\"" << TESTCASE_STYLESHEET << "\" type=\"text/xsl\"?>\n";
341
342 xe::writeTestResult(m_testCaseResult, xmlWriter);
343
344 listener->testLogData(testLog.str().c_str());
345 }
346
347 if (m_testCaseResult.statusCode != xe::TESTSTATUSCODE_LAST && !m_loggedResult)
348 {
349 listener->testCaseResult(xe::getTestStatusCodeName(m_testCaseResult.statusCode),
350 m_testCaseResult.statusDetails.c_str());
351 m_loggedResult = true;
352 }
353
354 listener->terminateTestCase(m_containerParser.getTerminateReason());
355 m_inTestCase = false;
356 break;
357
358 case xe::CONTAINERELEMENT_TEST_LOG_DATA:
359 {
360 if (m_inTestCase)
361 {
362 std::vector<uint8_t> data(m_containerParser.getDataSize());
363 m_containerParser.getData(&(data[0]), (int)data.size(), 0);
364
365 //tcu::print("%d %s :%s %s", __LINE__, std::string((const char*)&data[0], data.size()).c_str(), __func__, __FILE__);
366
367 if (m_testResultParser.parse(&(data[0]), (int)data.size()) == xe::TestResultParser::PARSERESULT_CHANGED)
368 {
369 if (m_testCaseResult.statusCode != xe::TESTSTATUSCODE_LAST && !m_loggedResult)
370 {
371 listener->testCaseResult(xe::getTestStatusCodeName(m_testCaseResult.statusCode),
372 m_testCaseResult.statusDetails.c_str());
373 m_loggedResult = true;
374 }
375 }
376 }
377
378 break;
379 }
380
381 case xe::CONTAINERELEMENT_TEST_RUN_PARAM_SESSION_BEGIN:
382 listener->beginTestRunParamsCollection();
383 break;
384
385 case xe::CONTAINERELEMENT_TEST_RUN_PARAM_SESSION_END:
386 listener->endTestRunParamsCollection();
387 break;
388
389 case xe::CONTAINERELEMENT_TEST_RUN_PARAM_BEGIN:
390 listener->beginTestRunParams(m_containerParser.getTestRunsParams());
391 break;
392
393 case xe::CONTAINERELEMENT_TEST_RUN_PARAM_END:
394 listener->endTestRunParams();
395 break;
396
397 default:
398 DE_ASSERT(false);
399 };
400
401 m_containerParser.advance();
402 }
403 }
404
throwJNIException(JNIEnv * env,const std::exception & e)405 void throwJNIException(JNIEnv *env, const std::exception &e)
406 {
407 jclass exClass;
408
409 exClass = env->FindClass("java/lang/Exception");
410
411 TCU_CHECK_INTERNAL(exClass != DE_NULL);
412
413 TCU_CHECK_INTERNAL(env->ThrowNew(exClass, e.what()) == 0);
414 }
415
416 } // namespace
417
418 DE_BEGIN_EXTERN_C
419
Java_com_drawelements_deqp_testercore_TestLogParser_nativeCreate(JNIEnv * env,jclass,jboolean logData)420 JNIEXPORT jlong JNICALL Java_com_drawelements_deqp_testercore_TestLogParser_nativeCreate(JNIEnv *env, jclass,
421 jboolean logData)
422 {
423 DE_UNREF(env);
424
425 try
426 {
427 return (jlong) new TestLogParser(logData);
428 }
429 catch (const std::exception &e)
430 {
431 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", e.what());
432
433 throwJNIException(env, e);
434 return 0;
435 }
436 }
437
Java_com_drawelements_deqp_testercore_TestLogParser_nativeDestroy(JNIEnv * env,jclass,jlong nativePointer)438 JNIEXPORT void JNICALL Java_com_drawelements_deqp_testercore_TestLogParser_nativeDestroy(JNIEnv *env, jclass,
439 jlong nativePointer)
440 {
441 DE_UNREF(env);
442
443 try
444 {
445 delete ((TestLogParser *)nativePointer);
446 }
447 catch (const std::exception &e)
448 {
449 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", e.what());
450
451 throwJNIException(env, e);
452 }
453 }
454
Java_com_drawelements_deqp_testercore_TestLogParser_nativeParse(JNIEnv * env,jclass,jlong nativePointer,jobject instrumentation,jbyteArray buffer,jint size)455 JNIEXPORT void JNICALL Java_com_drawelements_deqp_testercore_TestLogParser_nativeParse(JNIEnv *env, jclass,
456 jlong nativePointer,
457 jobject instrumentation,
458 jbyteArray buffer, jint size)
459 {
460 jbyte *logData = DE_NULL;
461
462 try
463 {
464 TestLogParser *parser = (TestLogParser *)nativePointer;
465 TestLogListener listener(env, instrumentation);
466
467 logData = env->GetByteArrayElements(buffer, NULL);
468
469 parser->parse(&listener, (const char *)logData, (size_t)size);
470 env->ReleaseByteArrayElements(buffer, logData, JNI_ABORT);
471 logData = DE_NULL;
472 }
473 catch (const std::exception &e)
474 {
475 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", e.what());
476
477 if (logData)
478 env->ReleaseByteArrayElements(buffer, logData, JNI_ABORT);
479
480 throwJNIException(env, e);
481 }
482 }
483
Java_org_khronos_cts_testercore_KhronosCTSTestLogParser_nativeCreate(JNIEnv * env,jclass,jboolean logData)484 JNIEXPORT jlong JNICALL Java_org_khronos_cts_testercore_KhronosCTSTestLogParser_nativeCreate(JNIEnv *env, jclass,
485 jboolean logData)
486 {
487 DE_UNREF(env);
488
489 try
490 {
491 return (jlong) new TestLogParser(logData);
492 }
493 catch (const std::exception &e)
494 {
495 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", e.what());
496
497 throwJNIException(env, e);
498 return 0;
499 }
500 }
501
Java_org_khronos_cts_testercore_KhronosCTSTestLogParser_nativeDestroy(JNIEnv * env,jclass,jlong nativePointer)502 JNIEXPORT void JNICALL Java_org_khronos_cts_testercore_KhronosCTSTestLogParser_nativeDestroy(JNIEnv *env, jclass,
503 jlong nativePointer)
504 {
505 DE_UNREF(env);
506
507 try
508 {
509 delete ((TestLogParser *)nativePointer);
510 }
511 catch (const std::exception &e)
512 {
513 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", e.what());
514
515 throwJNIException(env, e);
516 }
517 }
518
Java_org_khronos_cts_testercore_KhronosCTSTestLogParser_nativeParse(JNIEnv * env,jclass,jlong nativePointer,jobject instrumentation,jbyteArray buffer,jint size)519 JNIEXPORT void JNICALL Java_org_khronos_cts_testercore_KhronosCTSTestLogParser_nativeParse(JNIEnv *env, jclass,
520 jlong nativePointer,
521 jobject instrumentation,
522 jbyteArray buffer, jint size)
523 {
524 jbyte *logData = DE_NULL;
525
526 try
527 {
528 TestLogParser *parser = (TestLogParser *)nativePointer;
529 KhronosCTSTestLogListener listener(env, instrumentation);
530
531 logData = env->GetByteArrayElements(buffer, NULL);
532
533 parser->parse(&listener, (const char *)logData, (size_t)size);
534 env->ReleaseByteArrayElements(buffer, logData, JNI_ABORT);
535 logData = DE_NULL;
536 }
537 catch (const std::exception &e)
538 {
539 __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s", e.what());
540
541 if (logData)
542 env->ReleaseByteArrayElements(buffer, logData, JNI_ABORT);
543
544 throwJNIException(env, e);
545 }
546 }
547
548 DE_END_EXTERN_C
549