1 /* 2 * Copyright (C) 2018 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 android.device.loggers; 17 18 import org.junit.rules.ExternalResource; 19 import org.junit.rules.TestRule; 20 import org.junit.runner.Description; 21 import org.junit.runners.model.Statement; 22 23 import java.io.File; 24 import java.lang.annotation.Annotation; 25 import java.util.ArrayList; 26 import java.util.List; 27 import java.util.Objects; 28 29 /** 30 * Implementation of {@link ExternalResource} and {@link TestRule}. This rule allows to log logs 31 * during a test case (inside @Test). It guarantees that the log list is cleaned between tests, 32 * so the same rule object can be re-used. 33 * 34 * <pre>Example: 35 * @Rule 36 * public TestLogData logs = new TestLogData(); 37 * 38 * @Test 39 * public void testFoo() { 40 * logs.addTestLog("logcat", LogDataType.LOGCAT, new FileInputStreamSource(logcatFile)); 41 * } 42 * 43 * @Test 44 * public void testFoo2() { 45 * logs.addTestLog("logcat2", LogDataType.LOGCAT, new FileInputStreamSource(logcatFile2)); 46 * } 47 * </pre> 48 * 49 * TODO: The naming is in sync with the Tradefed host-side one, but they should be refactored in a 50 * single place. 51 */ 52 public class TestLogData extends ExternalResource { 53 private Description mDescription; 54 private List<LogHolder> mLogs = new ArrayList<>(); 55 56 @Override apply(Statement base, Description description)57 public Statement apply(Statement base, Description description) { 58 mDescription = description; 59 return super.apply(base, description); 60 } 61 addTestLog(String dataName, File logFile)62 public final void addTestLog(String dataName, File logFile) { 63 mLogs.add(new LogHolder(dataName, logFile)); 64 } 65 66 @Override after()67 protected void after() { 68 // we inject a Description with an annotation carrying metrics. 69 // Since Description cannot be extended and RunNotifier does not give us a lot of 70 // flexibility to find our metrics back, we have to pass the information via a placeholder 71 // annotation in the Description. 72 mDescription.addChild( 73 Description.createTestDescription("LOGS", "LOGS", new LogAnnotation(mLogs))); 74 } 75 76 /** Fake annotation meant to carry logs to the reporters. */ 77 static class LogAnnotation implements Annotation { 78 79 public List<LogHolder> mLogs = new ArrayList<>(); 80 LogAnnotation(List<LogHolder> logs)81 public LogAnnotation(List<LogHolder> logs) { 82 mLogs.addAll(logs); 83 } 84 85 @Override annotationType()86 public Class<? extends Annotation> annotationType() { 87 return null; 88 } 89 90 @Override equals(Object other)91 public boolean equals(Object other) { 92 if (other == this) { 93 return true; 94 } 95 if (!(other instanceof LogAnnotation)) { 96 return false; 97 } 98 LogAnnotation o = (LogAnnotation) other; 99 return Objects.equals(mLogs, o.mLogs); 100 } 101 102 @Override hashCode()103 public int hashCode() { 104 return Objects.hashCode(mLogs); 105 } 106 } 107 108 /** Structure to hold a log file to be reported. */ 109 static class LogHolder { 110 public final String mDataName; 111 public final File mLogFile; 112 LogHolder(String dataName, File logFile)113 public LogHolder(String dataName, File logFile) { 114 mDataName = dataName; 115 mLogFile = logFile; 116 } 117 118 @Override equals(Object other)119 public boolean equals(Object other) { 120 if (other == this) { 121 return true; 122 } 123 if (!(other instanceof LogHolder)) { 124 return false; 125 } 126 LogHolder o = (LogHolder) other; 127 return Objects.equals(mDataName, o.mDataName) && Objects.equals(mLogFile, o.mLogFile); 128 } 129 130 @Override hashCode()131 public int hashCode() { 132 return Objects.hash(mDataName, mLogFile); 133 } 134 } 135 } 136