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 TIME_KEY = "time"; 46 private static final String REASON_KEY = "reason"; 47 private static final String START_TIME = "start_time"; 48 private static final String END_TIME = "end_time"; 49 50 private static final String DATA_NAME_KEY = "dataName"; 51 private static final String DATA_TYPE_KEY = "dataType"; 52 private static final String DATA_FILE_KEY = "dataFile"; 53 private static final String LOGGED_FILE_KEY = "loggedFile"; 54 55 private static final String TEST_TAG_KEY = "testTag"; 56 57 private static final String MODULE_CONTEXT_KEY = "moduleContextFileName"; 58 private static final String MODULE_NAME = "moduleName"; 59 60 /** 61 * Helper for testRunStarted information 62 */ 63 public static class TestRunStartedEventInfo { 64 public String mRunName = null; 65 public Integer mTestCount = null; 66 67 public TestRunStartedEventInfo(String runName, int testCount) { 68 mRunName = runName; 69 mTestCount = testCount; 70 } 71 72 public TestRunStartedEventInfo(JSONObject jsonObject) throws JSONException { 73 mRunName = jsonObject.getString(RUNNAME_KEY); 74 mTestCount = jsonObject.getInt(TESTCOUNT_KEY); 75 } 76 77 @Override 78 public String toString() { 79 JSONObject tags = new JSONObject(); 80 try { 81 if (mRunName != null) { 82 tags.put(RUNNAME_KEY, mRunName); 83 } 84 if (mTestCount != null) { 85 tags.put(TESTCOUNT_KEY, mTestCount.intValue()); 86 } 87 } catch (JSONException e) { 88 CLog.e(e); 89 } 90 return tags.toString(); 91 } 92 } 93 94 /** 95 * Helper for testRunFailed information 96 */ 97 public static class TestRunFailedEventInfo { 98 public String mReason = null; 99 100 public TestRunFailedEventInfo(String reason) { 101 mReason = reason; 102 } 103 104 public TestRunFailedEventInfo(JSONObject jsonObject) throws JSONException { 105 mReason = jsonObject.getString(REASON_KEY); 106 } 107 108 @Override 109 public String toString() { 110 JSONObject tags = new JSONObject(); 111 try { 112 if (mReason != null) { 113 tags.put(REASON_KEY, mReason); 114 } 115 } catch (JSONException e) { 116 CLog.e(e); 117 } 118 return tags.toString(); 119 } 120 } 121 122 /** 123 * Helper for testRunEnded Information. 124 */ 125 public static class TestRunEndedEventInfo { 126 public Long mTime = null; 127 public Map<String, String> mRunMetrics = null; 128 129 public TestRunEndedEventInfo(Long time, Map<String, String> runMetrics) { 130 mTime = time; 131 mRunMetrics = runMetrics; 132 } 133 134 public TestRunEndedEventInfo(JSONObject jsonObject) throws JSONException { 135 mTime = jsonObject.getLong(TIME_KEY); 136 jsonObject.remove(TIME_KEY); 137 Iterator<?> i = jsonObject.keys(); 138 mRunMetrics = new HashMap<String, String>(); 139 while(i.hasNext()) { 140 String key = (String) i.next(); 141 mRunMetrics.put(key, jsonObject.get(key).toString()); 142 } 143 } 144 145 @Override 146 public String toString() { 147 JSONObject tags = null; 148 try { 149 if (mRunMetrics != null) { 150 tags = new JSONObject(mRunMetrics); 151 } else { 152 tags = new JSONObject(); 153 } 154 if (mTime != null) { 155 tags.put(TIME_KEY, mTime.longValue()); 156 } 157 } catch (JSONException e) { 158 CLog.e(e); 159 } 160 return tags.toString(); 161 } 162 } 163 164 /** 165 * Helper for InvocationFailed information. 166 */ 167 public static class InvocationFailedEventInfo { 168 public Throwable mCause = null; 169 170 public InvocationFailedEventInfo(Throwable cause) { 171 mCause = cause; 172 } 173 174 public InvocationFailedEventInfo(JSONObject jsonObject) throws JSONException { 175 String stack = jsonObject.getString("cause"); 176 mCause = new Throwable(stack); 177 } 178 179 @Override 180 public String toString() { 181 JSONObject tags = new JSONObject(); 182 try { 183 if (mCause != null) { 184 StringWriter sw = new StringWriter(); 185 PrintWriter pw = new PrintWriter(sw); 186 mCause.printStackTrace(pw); 187 tags.put(CAUSE_KEY, sw.toString()); 188 } 189 } catch (JSONException e) { 190 CLog.e(e); 191 } 192 return tags.toString(); 193 } 194 } 195 196 /** Base Helper for TestIgnored information. */ 197 public static class BaseTestEventInfo { 198 public String mClassName = null; 199 public String mTestName = null; 200 201 public BaseTestEventInfo(String className, String testName) { 202 mClassName = className; 203 mTestName = testName; 204 } 205 206 public BaseTestEventInfo(JSONObject jsonObject) throws JSONException { 207 mClassName = jsonObject.getString(CLASSNAME_KEY); 208 jsonObject.remove(CLASSNAME_KEY); 209 mTestName = jsonObject.getString(TESTNAME_KEY); 210 jsonObject.remove(TESTNAME_KEY); 211 } 212 213 protected JSONObject getNewJson() { 214 return new JSONObject(); 215 } 216 217 @Override 218 public String toString() { 219 JSONObject tags = null; 220 try { 221 tags = getNewJson(); 222 if (mClassName != null) { 223 tags.put(CLASSNAME_KEY, mClassName); 224 } 225 if (mTestName != null) { 226 tags.put(TESTNAME_KEY, mTestName); 227 } 228 } catch (JSONException e) { 229 CLog.e(e); 230 } 231 return tags.toString(); 232 } 233 } 234 235 /** Helper for testStarted information */ 236 public static class TestStartedEventInfo extends BaseTestEventInfo { 237 public Long mStartTime = null; 238 239 public TestStartedEventInfo(String className, String testName, Long startTime) { 240 super(className, testName); 241 mStartTime = startTime; 242 } 243 244 public TestStartedEventInfo(JSONObject jsonObject) throws JSONException { 245 super(jsonObject); 246 if (jsonObject.has(START_TIME)) { 247 mStartTime = jsonObject.getLong(START_TIME); 248 } 249 jsonObject.remove(START_TIME); 250 } 251 252 @Override 253 protected JSONObject getNewJson() { 254 JSONObject json = new JSONObject(); 255 try { 256 json.put(START_TIME, mStartTime); 257 } catch (JSONException e) { 258 CLog.e(e); 259 } 260 return json; 261 } 262 } 263 264 /** Helper for testFailed information. */ 265 public static class FailedTestEventInfo extends BaseTestEventInfo { 266 public String mTrace = null; 267 268 public FailedTestEventInfo(String className, String testName, String trace) { 269 super(className, testName); 270 mTrace = trace; 271 } 272 273 public FailedTestEventInfo(JSONObject jsonObject) throws JSONException { 274 super(jsonObject); 275 mTrace = jsonObject.getString(TRACE_KEY); 276 } 277 278 @Override 279 public String toString() { 280 JSONObject tags = null; 281 try { 282 tags = new JSONObject(super.toString()); 283 if (mTrace != null) { 284 tags.put(TRACE_KEY, mTrace); 285 } 286 } catch (JSONException e) { 287 CLog.e(e); 288 } 289 return tags.toString(); 290 } 291 } 292 293 /** 294 * Helper for testEnded information. 295 */ 296 public static class TestEndedEventInfo extends BaseTestEventInfo { 297 public Map<String, String> mRunMetrics = null; 298 public Long mEndTime = null; 299 300 public TestEndedEventInfo(String className, String testName, 301 Map<String, String> runMetrics) { 302 super(className, testName); 303 mRunMetrics = runMetrics; 304 mEndTime = System.currentTimeMillis(); 305 } 306 307 /** 308 * Create an event object to represent the testEnded callback. 309 * 310 * @param className the classname of the tests 311 * @param testName the name of the tests 312 * @param endTime the timestamp at which the test ended (from {@link 313 * System#currentTimeMillis()}) 314 * @param runMetrics the metrics reported by the test. 315 */ 316 public TestEndedEventInfo( 317 String className, String testName, Long endTime, Map<String, String> runMetrics) { 318 super(className, testName); 319 mEndTime = endTime; 320 mRunMetrics = runMetrics; 321 } 322 323 /** Create and populate and event object for testEnded from a JSON. */ 324 public TestEndedEventInfo(JSONObject jsonObject) throws JSONException { 325 super(jsonObject); 326 if (jsonObject.has(END_TIME)) { 327 mEndTime = jsonObject.getLong(END_TIME); 328 } 329 jsonObject.remove(END_TIME); 330 Iterator<?> i = jsonObject.keys(); 331 mRunMetrics = new HashMap<String, String>(); 332 while(i.hasNext()) { 333 String key = (String) i.next(); 334 mRunMetrics.put(key, jsonObject.get(key).toString()); 335 } 336 } 337 338 @Override 339 protected JSONObject getNewJson() { 340 JSONObject json; 341 if (mRunMetrics != null) { 342 json = new JSONObject(mRunMetrics); 343 } else { 344 json = new JSONObject(); 345 } 346 try { 347 json.put(END_TIME, mEndTime); 348 } catch (JSONException e) { 349 CLog.e(e); 350 } 351 return json; 352 } 353 } 354 355 /** Helper for testLog information. */ 356 public static class TestLogEventInfo { 357 public String mDataName = null; 358 public LogDataType mLogType = null; 359 public File mDataFile = null; 360 361 public TestLogEventInfo(String dataName, LogDataType dataType, File dataFile) { 362 mDataName = dataName; 363 mLogType = dataType; 364 mDataFile = dataFile; 365 } 366 367 public TestLogEventInfo(JSONObject jsonObject) throws JSONException { 368 mDataName = jsonObject.getString(DATA_NAME_KEY); 369 jsonObject.remove(DATA_NAME_KEY); 370 mLogType = LogDataType.valueOf(jsonObject.getString(DATA_TYPE_KEY)); 371 jsonObject.remove(DATA_TYPE_KEY); 372 mDataFile = new File(jsonObject.getString(DATA_FILE_KEY)); 373 } 374 375 @Override 376 public String toString() { 377 JSONObject tags = null; 378 try { 379 tags = new JSONObject(); 380 if (mDataName != null) { 381 tags.put(DATA_NAME_KEY, mDataName); 382 } 383 if (mLogType != null) { 384 tags.put(DATA_TYPE_KEY, mLogType.toString()); 385 } 386 if (mDataFile != null) { 387 tags.put(DATA_FILE_KEY, mDataFile.getAbsolutePath()); 388 } 389 } catch (JSONException e) { 390 CLog.e(e); 391 } 392 return tags.toString(); 393 } 394 } 395 396 /** Helper for logAssociation information. */ 397 public static class LogAssociationEventInfo { 398 public String mDataName = null; 399 public LogFile mLoggedFile = null; 400 401 public LogAssociationEventInfo(String dataName, LogFile loggedFile) { 402 mDataName = dataName; 403 mLoggedFile = loggedFile; 404 } 405 406 public LogAssociationEventInfo(JSONObject jsonObject) throws JSONException { 407 mDataName = jsonObject.getString(DATA_NAME_KEY); 408 jsonObject.remove(DATA_NAME_KEY); 409 String file = jsonObject.getString(LOGGED_FILE_KEY); 410 try { 411 mLoggedFile = (LogFile) SerializationUtil.deserialize(new File(file), true); 412 } catch (IOException e) { 413 throw new JSONException(e.getMessage()); 414 } finally { 415 FileUtil.deleteFile(new File(file)); 416 } 417 } 418 419 @Override 420 public String toString() { 421 JSONObject tags = null; 422 try { 423 tags = new JSONObject(); 424 if (mDataName != null) { 425 tags.put(DATA_NAME_KEY, mDataName); 426 } 427 if (mLoggedFile != null) { 428 File serializedLoggedFile = SerializationUtil.serialize(mLoggedFile); 429 tags.put(LOGGED_FILE_KEY, serializedLoggedFile.getAbsolutePath()); 430 } 431 } catch (JSONException | IOException e) { 432 CLog.e(e); 433 throw new RuntimeException(e); 434 } 435 return tags.toString(); 436 } 437 } 438 439 /** Helper for invocation started information. */ 440 public static class InvocationStartedEventInfo { 441 public String mTestTag = null; 442 public Long mStartTime = null; 443 444 public InvocationStartedEventInfo(String testTag, Long startTime) { 445 mTestTag = testTag; 446 mStartTime = startTime; 447 } 448 449 public InvocationStartedEventInfo(JSONObject jsonObject) throws JSONException { 450 mTestTag = jsonObject.getString(TEST_TAG_KEY); 451 if (jsonObject.has(START_TIME)) { 452 mStartTime = jsonObject.getLong(START_TIME); 453 } 454 } 455 456 @Override 457 public String toString() { 458 JSONObject tags = null; 459 try { 460 tags = new JSONObject(); 461 if (mTestTag != null) { 462 tags.put(TEST_TAG_KEY, mTestTag); 463 } 464 if (mStartTime != null) { 465 tags.put(START_TIME, mStartTime); 466 } 467 } catch (JSONException e) { 468 CLog.e(e); 469 } 470 return tags.toString(); 471 } 472 } 473 474 /** Helper for test module started information. */ 475 public static class TestModuleStartedEventInfo { 476 public IInvocationContext mModuleContext; 477 478 public TestModuleStartedEventInfo(IInvocationContext moduleContext) { 479 mModuleContext = moduleContext; 480 } 481 482 public TestModuleStartedEventInfo(JSONObject jsonObject) throws JSONException { 483 String file = jsonObject.getString(MODULE_CONTEXT_KEY); 484 try { 485 mModuleContext = 486 (IInvocationContext) SerializationUtil.deserialize(new File(file), true); 487 } catch (IOException e) { 488 throw new RuntimeException(e); 489 } 490 } 491 492 @Override 493 public String toString() { 494 JSONObject tags = null; 495 try { 496 tags = new JSONObject(); 497 File serializedContext = SerializationUtil.serialize(mModuleContext); 498 tags.put(MODULE_CONTEXT_KEY, serializedContext.getAbsolutePath()); 499 // For easier debugging on the events for modules, add the module name 500 String moduleName = 501 mModuleContext 502 .getAttributes() 503 .getUniqueMap() 504 .get(ModuleDefinition.MODULE_NAME); 505 if (moduleName != null) { 506 tags.put(MODULE_NAME, moduleName); 507 } 508 } catch (IOException | JSONException e) { 509 CLog.e(e); 510 throw new RuntimeException(e); 511 } 512 return tags.toString(); 513 } 514 } 515 } 516