• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.tradefed.util;
17 
18 import com.android.tradefed.invoker.IInvocationContext;
19 import com.android.tradefed.log.LogUtil.CLog;
20 import com.android.tradefed.result.LogDataType;
21 import com.android.tradefed.result.LogFile;
22 import com.android.tradefed.testtype.suite.ModuleDefinition;
23 
24 import org.json.JSONException;
25 import org.json.JSONObject;
26 
27 import java.io.File;
28 import java.io.IOException;
29 import java.io.PrintWriter;
30 import java.io.StringWriter;
31 import java.util.HashMap;
32 import java.util.Iterator;
33 import java.util.Map;
34 
35 /**
36  * Helper to serialize/deserialize the events to be passed to the log.
37  */
38 public class SubprocessEventHelper {
39     private static final String CLASSNAME_KEY = "className";
40     private static final String TESTNAME_KEY = "testName";
41     private static final String TRACE_KEY = "trace";
42     private static final String CAUSE_KEY = "cause";
43     private static final String RUNNAME_KEY = "runName";
44     private static final String TESTCOUNT_KEY = "testCount";
45     private static final String ATTEMPT_KEY = "runAttempt";
46     private static final String TIME_KEY = "time";
47     private static final String REASON_KEY = "reason";
48     private static final String START_TIME = "start_time";
49     private static final String END_TIME = "end_time";
50 
51     private static final String DATA_NAME_KEY = "dataName";
52     private static final String DATA_TYPE_KEY = "dataType";
53     private static final String DATA_FILE_KEY = "dataFile";
54     private static final String LOGGED_FILE_KEY = "loggedFile";
55 
56     private static final String TEST_TAG_KEY = "testTag";
57 
58     private static final String MODULE_CONTEXT_KEY = "moduleContextFileName";
59     private static final String MODULE_NAME = "moduleName";
60 
61     /**
62      * Helper for testRunStarted information
63      */
64     public static class TestRunStartedEventInfo {
65         public String mRunName = null;
66         public Integer mTestCount = null;
67         public Integer mAttempt = null;
68 
69         /** Keep this constructor for legacy compatibility. */
TestRunStartedEventInfo(String runName, int testCount)70         public TestRunStartedEventInfo(String runName, int testCount) {
71             mRunName = runName;
72             mTestCount = testCount;
73             mAttempt = 0;
74         }
75 
TestRunStartedEventInfo(String runName, int testCount, int attempt)76         public TestRunStartedEventInfo(String runName, int testCount, int attempt) {
77             mRunName = runName;
78             mTestCount = testCount;
79             mAttempt = attempt;
80         }
81 
TestRunStartedEventInfo(JSONObject jsonObject)82         public TestRunStartedEventInfo(JSONObject jsonObject) throws JSONException {
83             mRunName = jsonObject.getString(RUNNAME_KEY);
84             mTestCount = jsonObject.getInt(TESTCOUNT_KEY);
85             mAttempt = jsonObject.optInt(ATTEMPT_KEY, 0);
86         }
87 
88         @Override
toString()89         public String toString() {
90             JSONObject tags = new JSONObject();
91             try {
92                 if (mRunName != null) {
93                     tags.put(RUNNAME_KEY, mRunName);
94                 }
95                 if (mTestCount != null) {
96                     tags.put(TESTCOUNT_KEY, mTestCount.intValue());
97                 }
98                 if (mAttempt != null) {
99                     tags.put(ATTEMPT_KEY, mAttempt.intValue());
100                 }
101             } catch (JSONException e) {
102                 CLog.e(e);
103             }
104             return tags.toString();
105         }
106     }
107 
108     /**
109      * Helper for testRunFailed information
110      */
111     public static class TestRunFailedEventInfo {
112         public String mReason = null;
113 
TestRunFailedEventInfo(String reason)114         public TestRunFailedEventInfo(String reason) {
115             mReason = reason;
116         }
117 
TestRunFailedEventInfo(JSONObject jsonObject)118         public TestRunFailedEventInfo(JSONObject jsonObject) throws JSONException {
119             mReason = jsonObject.getString(REASON_KEY);
120         }
121 
122         @Override
toString()123         public String toString() {
124             JSONObject tags = new JSONObject();
125             try {
126                 if (mReason != null) {
127                     tags.put(REASON_KEY, mReason);
128                 }
129             } catch (JSONException e) {
130                 CLog.e(e);
131             }
132             return tags.toString();
133         }
134     }
135 
136     /**
137      * Helper for testRunEnded Information.
138      */
139     public static class TestRunEndedEventInfo {
140         public Long mTime = null;
141         public Map<String, String> mRunMetrics = null;
142 
TestRunEndedEventInfo(Long time, Map<String, String> runMetrics)143         public TestRunEndedEventInfo(Long time, Map<String, String> runMetrics) {
144             mTime = time;
145             mRunMetrics = runMetrics;
146         }
147 
TestRunEndedEventInfo(JSONObject jsonObject)148         public TestRunEndedEventInfo(JSONObject jsonObject) throws JSONException {
149             mTime = jsonObject.getLong(TIME_KEY);
150             jsonObject.remove(TIME_KEY);
151             Iterator<?> i = jsonObject.keys();
152             mRunMetrics = new HashMap<String, String>();
153             while(i.hasNext()) {
154                 String key = (String) i.next();
155                 mRunMetrics.put(key, jsonObject.get(key).toString());
156             }
157         }
158 
159         @Override
toString()160         public String toString() {
161             JSONObject tags = null;
162             try {
163                 if (mRunMetrics != null) {
164                     tags = new JSONObject(mRunMetrics);
165                 } else {
166                     tags = new JSONObject();
167                 }
168                 if (mTime != null) {
169                     tags.put(TIME_KEY, mTime.longValue());
170                 }
171             } catch (JSONException e) {
172                 CLog.e(e);
173             }
174             return tags.toString();
175         }
176     }
177 
178     /**
179      * Helper for InvocationFailed information.
180      */
181     public static class InvocationFailedEventInfo {
182         public Throwable mCause = null;
183 
InvocationFailedEventInfo(Throwable cause)184         public InvocationFailedEventInfo(Throwable cause) {
185             mCause = cause;
186         }
187 
InvocationFailedEventInfo(JSONObject jsonObject)188         public InvocationFailedEventInfo(JSONObject jsonObject) throws JSONException {
189             String stack = jsonObject.getString("cause");
190             mCause = new Throwable(stack);
191         }
192 
193         @Override
toString()194         public String toString() {
195             JSONObject tags = new JSONObject();
196             try {
197                 if (mCause != null) {
198                     StringWriter sw = new StringWriter();
199                     PrintWriter pw = new PrintWriter(sw);
200                     mCause.printStackTrace(pw);
201                     tags.put(CAUSE_KEY, sw.toString());
202                 }
203             } catch (JSONException e) {
204                 CLog.e(e);
205             }
206             return tags.toString();
207         }
208     }
209 
210     /** Base Helper for TestIgnored information. */
211     public static class BaseTestEventInfo {
212         public String mClassName = null;
213         public String mTestName = null;
214 
BaseTestEventInfo(String className, String testName)215         public BaseTestEventInfo(String className, String testName) {
216             mClassName = className;
217             mTestName = testName;
218         }
219 
BaseTestEventInfo(JSONObject jsonObject)220         public BaseTestEventInfo(JSONObject jsonObject) throws JSONException {
221             mClassName = jsonObject.getString(CLASSNAME_KEY);
222             jsonObject.remove(CLASSNAME_KEY);
223             mTestName = jsonObject.getString(TESTNAME_KEY);
224             jsonObject.remove(TESTNAME_KEY);
225         }
226 
getNewJson()227         protected JSONObject getNewJson() {
228             return new JSONObject();
229         }
230 
231         @Override
toString()232         public String toString() {
233             JSONObject tags = null;
234             try {
235                 tags = getNewJson();
236                 if (mClassName != null) {
237                     tags.put(CLASSNAME_KEY, mClassName);
238                 }
239                 if (mTestName != null) {
240                     tags.put(TESTNAME_KEY, mTestName);
241                 }
242             } catch (JSONException e) {
243                 CLog.e(e);
244             }
245             return tags.toString();
246         }
247     }
248 
249     /** Helper for testStarted information */
250     public static class TestStartedEventInfo extends BaseTestEventInfo {
251         public Long mStartTime = null;
252 
TestStartedEventInfo(String className, String testName, Long startTime)253         public TestStartedEventInfo(String className, String testName, Long startTime) {
254             super(className, testName);
255             mStartTime = startTime;
256         }
257 
TestStartedEventInfo(JSONObject jsonObject)258         public TestStartedEventInfo(JSONObject jsonObject) throws JSONException {
259             super(jsonObject);
260             if (jsonObject.has(START_TIME)) {
261                 mStartTime = jsonObject.getLong(START_TIME);
262             }
263             jsonObject.remove(START_TIME);
264         }
265 
266         @Override
getNewJson()267         protected JSONObject getNewJson() {
268             JSONObject json = new JSONObject();
269             try {
270                 json.put(START_TIME, mStartTime);
271             } catch (JSONException e) {
272                 CLog.e(e);
273             }
274             return json;
275         }
276     }
277 
278     /** Helper for testFailed information. */
279     public static class FailedTestEventInfo extends BaseTestEventInfo {
280         public String mTrace = null;
281 
FailedTestEventInfo(String className, String testName, String trace)282         public FailedTestEventInfo(String className, String testName, String trace) {
283             super(className, testName);
284             mTrace = trace;
285         }
286 
FailedTestEventInfo(JSONObject jsonObject)287         public FailedTestEventInfo(JSONObject jsonObject) throws JSONException {
288             super(jsonObject);
289             mTrace = jsonObject.getString(TRACE_KEY);
290         }
291 
292         @Override
toString()293         public String toString() {
294             JSONObject tags = null;
295             try {
296                 tags = new JSONObject(super.toString());
297                 if (mTrace != null) {
298                     tags.put(TRACE_KEY, mTrace);
299                 }
300             } catch (JSONException e) {
301                 CLog.e(e);
302             }
303             return tags.toString();
304         }
305     }
306 
307     /**
308      * Helper for testEnded information.
309      */
310     public static class TestEndedEventInfo extends BaseTestEventInfo {
311         public Map<String, String> mRunMetrics = null;
312         public Long mEndTime = null;
313 
TestEndedEventInfo(String className, String testName, Map<String, String> runMetrics)314         public TestEndedEventInfo(String className, String testName,
315                 Map<String, String> runMetrics) {
316             super(className, testName);
317             mRunMetrics = runMetrics;
318             mEndTime = System.currentTimeMillis();
319         }
320 
321         /**
322          * Create an event object to represent the testEnded callback.
323          *
324          * @param className the classname of the tests
325          * @param testName the name of the tests
326          * @param endTime the timestamp at which the test ended (from {@link
327          *     System#currentTimeMillis()})
328          * @param runMetrics the metrics reported by the test.
329          */
TestEndedEventInfo( String className, String testName, Long endTime, Map<String, String> runMetrics)330         public TestEndedEventInfo(
331                 String className, String testName, Long endTime, Map<String, String> runMetrics) {
332             super(className, testName);
333             mEndTime = endTime;
334             mRunMetrics = runMetrics;
335         }
336 
337         /** Create and populate and event object for testEnded from a JSON. */
TestEndedEventInfo(JSONObject jsonObject)338         public TestEndedEventInfo(JSONObject jsonObject) throws JSONException {
339             super(jsonObject);
340             if (jsonObject.has(END_TIME)) {
341                 mEndTime = jsonObject.getLong(END_TIME);
342             }
343             jsonObject.remove(END_TIME);
344             Iterator<?> i = jsonObject.keys();
345             mRunMetrics = new HashMap<String, String>();
346             while(i.hasNext()) {
347                 String key = (String) i.next();
348                 mRunMetrics.put(key, jsonObject.get(key).toString());
349             }
350         }
351 
352         @Override
getNewJson()353         protected JSONObject getNewJson() {
354             JSONObject json;
355             if (mRunMetrics != null) {
356                 json = new JSONObject(mRunMetrics);
357             } else {
358                 json = new JSONObject();
359             }
360             try {
361                 json.put(END_TIME, mEndTime);
362             } catch (JSONException e) {
363                 CLog.e(e);
364             }
365             return json;
366         }
367     }
368 
369     /** Helper for testLog information. */
370     public static class TestLogEventInfo {
371         public String mDataName = null;
372         public LogDataType mLogType = null;
373         public File mDataFile = null;
374 
TestLogEventInfo(String dataName, LogDataType dataType, File dataFile)375         public TestLogEventInfo(String dataName, LogDataType dataType, File dataFile) {
376             mDataName = dataName;
377             mLogType = dataType;
378             mDataFile = dataFile;
379         }
380 
TestLogEventInfo(JSONObject jsonObject)381         public TestLogEventInfo(JSONObject jsonObject) throws JSONException {
382             mDataName = jsonObject.getString(DATA_NAME_KEY);
383             jsonObject.remove(DATA_NAME_KEY);
384             mLogType = LogDataType.valueOf(jsonObject.getString(DATA_TYPE_KEY));
385             jsonObject.remove(DATA_TYPE_KEY);
386             mDataFile = new File(jsonObject.getString(DATA_FILE_KEY));
387         }
388 
389         @Override
toString()390         public String toString() {
391             JSONObject tags = null;
392             try {
393                 tags = new JSONObject();
394                 if (mDataName != null) {
395                     tags.put(DATA_NAME_KEY, mDataName);
396                 }
397                 if (mLogType != null) {
398                     tags.put(DATA_TYPE_KEY, mLogType.toString());
399                 }
400                 if (mDataFile != null) {
401                     tags.put(DATA_FILE_KEY, mDataFile.getAbsolutePath());
402                 }
403             } catch (JSONException e) {
404                 CLog.e(e);
405             }
406             return tags.toString();
407         }
408     }
409 
410     /** Helper for logAssociation information. */
411     public static class LogAssociationEventInfo {
412         public String mDataName = null;
413         public LogFile mLoggedFile = null;
414 
LogAssociationEventInfo(String dataName, LogFile loggedFile)415         public LogAssociationEventInfo(String dataName, LogFile loggedFile) {
416             mDataName = dataName;
417             mLoggedFile = loggedFile;
418         }
419 
LogAssociationEventInfo(JSONObject jsonObject)420         public LogAssociationEventInfo(JSONObject jsonObject) throws JSONException {
421             mDataName = jsonObject.getString(DATA_NAME_KEY);
422             jsonObject.remove(DATA_NAME_KEY);
423             String file = jsonObject.getString(LOGGED_FILE_KEY);
424             try {
425                 mLoggedFile = (LogFile) SerializationUtil.deserialize(new File(file), true);
426             } catch (IOException e) {
427                 throw new JSONException(e.getMessage());
428             } finally {
429                 FileUtil.deleteFile(new File(file));
430             }
431         }
432 
433         @Override
toString()434         public String toString() {
435             JSONObject tags = null;
436             try {
437                 tags = new JSONObject();
438                 if (mDataName != null) {
439                     tags.put(DATA_NAME_KEY, mDataName);
440                 }
441                 if (mLoggedFile != null) {
442                     File serializedLoggedFile = SerializationUtil.serialize(mLoggedFile);
443                     tags.put(LOGGED_FILE_KEY, serializedLoggedFile.getAbsolutePath());
444                 }
445             } catch (JSONException | IOException e) {
446                 CLog.e(e);
447                 throw new RuntimeException(e);
448             }
449             return tags.toString();
450         }
451     }
452 
453     /** Helper for invocation started information. */
454     public static class InvocationStartedEventInfo {
455         public String mTestTag = null;
456         public Long mStartTime = null;
457 
InvocationStartedEventInfo(String testTag, Long startTime)458         public InvocationStartedEventInfo(String testTag, Long startTime) {
459             mTestTag = testTag;
460             mStartTime = startTime;
461         }
462 
InvocationStartedEventInfo(JSONObject jsonObject)463         public InvocationStartedEventInfo(JSONObject jsonObject) throws JSONException {
464             mTestTag = jsonObject.getString(TEST_TAG_KEY);
465             if (jsonObject.has(START_TIME)) {
466                 mStartTime = jsonObject.getLong(START_TIME);
467             }
468         }
469 
470         @Override
toString()471         public String toString() {
472             JSONObject tags = null;
473             try {
474                 tags = new JSONObject();
475                 if (mTestTag != null) {
476                     tags.put(TEST_TAG_KEY, mTestTag);
477                 }
478                 if (mStartTime != null) {
479                     tags.put(START_TIME, mStartTime);
480                 }
481             } catch (JSONException e) {
482                 CLog.e(e);
483             }
484             return tags.toString();
485         }
486     }
487 
488     /** Helper for invocation ended information. */
489     public static class InvocationEndedEventInfo {
490         public Map<String, String> mBuildAttributes;
491 
InvocationEndedEventInfo(Map<String, String> buildAttributes)492         public InvocationEndedEventInfo(Map<String, String> buildAttributes) {
493             mBuildAttributes = new HashMap<String, String>(buildAttributes);
494         }
495 
InvocationEndedEventInfo(JSONObject jsonObject)496         public InvocationEndedEventInfo(JSONObject jsonObject) throws JSONException {
497             mBuildAttributes = new HashMap<String, String>();
498             Iterator<?> i = jsonObject.keys();
499             while (i.hasNext()) {
500                 String key = (String) i.next();
501                 mBuildAttributes.put(key, jsonObject.get(key).toString());
502             }
503         }
504 
505         @Override
toString()506         public String toString() {
507             JSONObject jsonObject = new JSONObject(mBuildAttributes);
508             return jsonObject.toString();
509         }
510     }
511 
512     /** Helper for test module started information. */
513     public static class TestModuleStartedEventInfo {
514         public IInvocationContext mModuleContext;
515 
TestModuleStartedEventInfo(IInvocationContext moduleContext)516         public TestModuleStartedEventInfo(IInvocationContext moduleContext) {
517             mModuleContext = moduleContext;
518         }
519 
TestModuleStartedEventInfo(JSONObject jsonObject)520         public TestModuleStartedEventInfo(JSONObject jsonObject) throws JSONException {
521             String file = jsonObject.getString(MODULE_CONTEXT_KEY);
522             try {
523                 mModuleContext =
524                         (IInvocationContext) SerializationUtil.deserialize(new File(file), true);
525             } catch (IOException e) {
526                 throw new RuntimeException(e);
527             }
528         }
529 
530         @Override
toString()531         public String toString() {
532             JSONObject tags = null;
533             try {
534                 tags = new JSONObject();
535                 File serializedContext = SerializationUtil.serialize(mModuleContext);
536                 tags.put(MODULE_CONTEXT_KEY, serializedContext.getAbsolutePath());
537                 // For easier debugging on the events for modules, add the module name
538                 String moduleName =
539                         mModuleContext
540                                 .getAttributes()
541                                 .getUniqueMap()
542                                 .get(ModuleDefinition.MODULE_NAME);
543                 if (moduleName != null) {
544                     tags.put(MODULE_NAME, moduleName);
545                 }
546             } catch (IOException | JSONException e) {
547                 CLog.e(e);
548                 throw new RuntimeException(e);
549             }
550             return tags.toString();
551         }
552     }
553 }
554