xref: /aosp_15_r20/external/deqp/framework/platform/android/tcuTestLogParserJNI.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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