1 /* 2 * Copyright (C) 2011 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.result; 17 18 import com.android.tradefed.device.ITestDevice; 19 import com.android.tradefed.util.ArrayUtil; 20 21 import junit.framework.TestCase; 22 23 import org.easymock.EasyMock; 24 25 import java.io.File; 26 import java.util.HashMap; 27 import java.util.List; 28 import java.util.Map; 29 30 /** 31 * Unit tests for {@link DeviceFileReporter} 32 */ 33 public class DeviceFileReporterTest extends TestCase { 34 DeviceFileReporter dfr = null; 35 ITestDevice mDevice = null; 36 ITestInvocationListener mListener = null; 37 38 // Used to control what ISS is returned 39 InputStreamSource mDfrIss = null; 40 41 @SuppressWarnings("serial") 42 private static class FakeFile extends File { 43 private final String mName; 44 private final long mSize; 45 46 FakeFile(String name, long size) { 47 super(name); 48 mName = name; 49 mSize = size; 50 } 51 @Override 52 public String toString() { 53 return mName; 54 } 55 @Override 56 public long length() { 57 return mSize; 58 } 59 } 60 61 @Override 62 public void setUp() throws Exception { 63 mDevice = EasyMock.createMock(ITestDevice.class); 64 EasyMock.expect(mDevice.getSerialNumber()).andStubReturn("serial"); 65 66 mListener = EasyMock.createMock(ITestInvocationListener.class); 67 dfr = 68 new DeviceFileReporter(mDevice, mListener) { 69 @Override 70 InputStreamSource createIssForFile(File file) { 71 return mDfrIss; 72 } 73 }; 74 } 75 76 public void testSimple() throws Exception { 77 final String result = "/data/tombstones/tombstone_00\r\n"; 78 final String filename = "/data/tombstones/tombstone_00"; 79 final String tombstone = "What do you want on your tombstone?"; 80 dfr.addPatterns("/data/tombstones/*"); 81 82 EasyMock.expect(mDevice.executeShellCommand(EasyMock.eq("ls /data/tombstones/*"))) 83 .andReturn(result); 84 // This gets passed verbatim to createIssForFile above 85 EasyMock.expect(mDevice.pullFile(EasyMock.eq(filename))) 86 .andReturn(new FakeFile(filename, tombstone.length())); 87 88 mDfrIss = new ByteArrayInputStreamSource(tombstone.getBytes()); 89 // FIXME: use captures here to make sure we get the string back out 90 mListener.testLog(EasyMock.eq(filename), EasyMock.eq(LogDataType.UNKNOWN), 91 EasyMock.eq(mDfrIss)); 92 93 replayMocks(); 94 dfr.run(); 95 verifyMocks(); 96 } 97 98 // Files' paths should be trimmed to remove white spaces at the end of the lines. 99 public void testTrim() throws Exception { 100 // Result with trailing white spaces. 101 final String result = "/data/tombstones/tombstone_00 \r\n"; 102 103 final String filename = "/data/tombstones/tombstone_00"; 104 final String tombstone = "What do you want on your tombstone?"; 105 dfr.addPatterns("/data/tombstones/*"); 106 107 EasyMock.expect(mDevice.executeShellCommand(EasyMock.eq("ls /data/tombstones/*"))) 108 .andReturn(result); 109 // This gets passed verbatim to createIssForFile above 110 EasyMock.expect(mDevice.pullFile(EasyMock.eq(filename))) 111 .andReturn(new FakeFile(filename, tombstone.length())); 112 113 mDfrIss = new ByteArrayInputStreamSource(tombstone.getBytes()); 114 mListener.testLog(EasyMock.eq(filename), EasyMock.eq(LogDataType.UNKNOWN), 115 EasyMock.eq(mDfrIss)); 116 117 replayMocks(); 118 List<String> filenames = dfr.run(); 119 assertEquals(filename, filenames.get(0)); 120 verifyMocks(); 121 } 122 123 public void testLineEnding_LF() throws Exception { 124 final String[] filenames = {"/data/tombstones/tombstone_00", 125 "/data/tombstones/tombstone_01", 126 "/data/tombstones/tombstone_02", 127 "/data/tombstones/tombstone_03", 128 "/data/tombstones/tombstone_04"}; 129 String result = ArrayUtil.join("\n", (Object[])filenames); 130 final String tombstone = "What do you want on your tombstone?"; 131 dfr.addPatterns("/data/tombstones/*"); 132 133 EasyMock.expect(mDevice.executeShellCommand((String)EasyMock.anyObject())) 134 .andReturn(result); 135 mDfrIss = new ByteArrayInputStreamSource(tombstone.getBytes()); 136 // This gets passed verbatim to createIssForFile above 137 for (String filename : filenames) { 138 EasyMock.expect(mDevice.pullFile(EasyMock.eq(filename))).andReturn( 139 new FakeFile(filename, tombstone.length())); 140 141 // FIXME: use captures here to make sure we get the string back out 142 mListener.testLog(EasyMock.eq(filename), EasyMock.eq(LogDataType.UNKNOWN), 143 EasyMock.eq(mDfrIss)); 144 } 145 replayMocks(); 146 dfr.run(); 147 verifyMocks(); 148 } 149 150 public void testLineEnding_CRLF() throws Exception { 151 final String[] filenames = {"/data/tombstones/tombstone_00", 152 "/data/tombstones/tombstone_01", 153 "/data/tombstones/tombstone_02", 154 "/data/tombstones/tombstone_03", 155 "/data/tombstones/tombstone_04"}; 156 String result = ArrayUtil.join("\r\n", (Object[])filenames); 157 final String tombstone = "What do you want on your tombstone?"; 158 dfr.addPatterns("/data/tombstones/*"); 159 160 EasyMock.expect(mDevice.executeShellCommand((String)EasyMock.anyObject())) 161 .andReturn(result); 162 mDfrIss = new ByteArrayInputStreamSource(tombstone.getBytes()); 163 // This gets passed verbatim to createIssForFile above 164 for (String filename : filenames) { 165 EasyMock.expect(mDevice.pullFile(EasyMock.eq(filename))).andReturn( 166 new FakeFile(filename, tombstone.length())); 167 168 // FIXME: use captures here to make sure we get the string back out 169 mListener.testLog(EasyMock.eq(filename), EasyMock.eq(LogDataType.UNKNOWN), 170 EasyMock.eq(mDfrIss)); 171 } 172 replayMocks(); 173 dfr.run(); 174 verifyMocks(); 175 } 176 177 /** 178 * Make sure that the Reporter behaves as expected when a file is matched by multiple patterns 179 */ 180 public void testRepeat_skip() throws Exception { 181 final String result1 = "/data/files/file.png\r\n"; 182 final String result2 = "/data/files/file.png\r\n/data/files/file.xml\r\n"; 183 final String pngFilename = "/data/files/file.png"; 184 final String xmlFilename = "/data/files/file.xml"; 185 final Map<String, LogDataType> patMap = new HashMap<>(2); 186 patMap.put("/data/files/*.png", LogDataType.PNG); 187 patMap.put("/data/files/*", LogDataType.UNKNOWN); 188 189 final String pngContents = "This is PNG data"; 190 final String xmlContents = "<!-- This is XML data -->"; 191 final InputStreamSource pngIss = new ByteArrayInputStreamSource(pngContents.getBytes()); 192 final InputStreamSource xmlIss = new ByteArrayInputStreamSource(xmlContents.getBytes()); 193 194 dfr = 195 new DeviceFileReporter(mDevice, mListener) { 196 @Override 197 InputStreamSource createIssForFile(File file) { 198 if (file.toString().endsWith(".png")) { 199 return pngIss; 200 } else if (file.toString().endsWith(".xml")) { 201 return xmlIss; 202 } 203 return null; 204 } 205 }; 206 dfr.addPatterns(patMap); 207 dfr.setInferUnknownDataTypes(false); 208 209 // Set file listing pulling, and reporting expectations 210 // Expect that we go through the entire process for the PNG file, and then go through 211 // the entire process again for the XML file 212 EasyMock.expect(mDevice.executeShellCommand((String)EasyMock.anyObject())) 213 .andReturn(result1); 214 EasyMock.expect(mDevice.pullFile(EasyMock.eq(pngFilename))) 215 .andReturn(new FakeFile(pngFilename, pngContents.length())); 216 mListener.testLog(EasyMock.eq(pngFilename), EasyMock.eq(LogDataType.PNG), 217 EasyMock.eq(pngIss)); 218 219 EasyMock.expect(mDevice.executeShellCommand((String)EasyMock.anyObject())) 220 .andReturn(result2); 221 EasyMock.expect(mDevice.pullFile(EasyMock.eq(xmlFilename))) 222 .andReturn(new FakeFile(xmlFilename, xmlContents.length())); 223 mListener.testLog(EasyMock.eq(xmlFilename), EasyMock.eq(LogDataType.UNKNOWN), 224 EasyMock.eq(xmlIss)); 225 226 replayMocks(); 227 dfr.run(); 228 verifyMocks(); 229 // FIXME: use captures here to make sure we get the string back out 230 } 231 232 /** 233 * Make sure that the Reporter behaves as expected when a file is matched by multiple patterns 234 */ 235 public void testRepeat_noSkip() throws Exception { 236 final String result1 = "/data/files/file.png\r\n"; 237 final String result2 = "/data/files/file.png\r\n/data/files/file.xml\r\n"; 238 final String pngFilename = "/data/files/file.png"; 239 final String xmlFilename = "/data/files/file.xml"; 240 final Map<String, LogDataType> patMap = new HashMap<>(2); 241 patMap.put("/data/files/*.png", LogDataType.PNG); 242 patMap.put("/data/files/*", LogDataType.UNKNOWN); 243 244 final String pngContents = "This is PNG data"; 245 final String xmlContents = "<!-- This is XML data -->"; 246 final InputStreamSource pngIss = new ByteArrayInputStreamSource(pngContents.getBytes()); 247 final InputStreamSource xmlIss = new ByteArrayInputStreamSource(xmlContents.getBytes()); 248 249 dfr = 250 new DeviceFileReporter(mDevice, mListener) { 251 @Override 252 InputStreamSource createIssForFile(File file) { 253 if (file.toString().endsWith(".png")) { 254 return pngIss; 255 } else if (file.toString().endsWith(".xml")) { 256 return xmlIss; 257 } 258 return null; 259 } 260 }; 261 dfr.addPatterns(patMap); 262 dfr.setInferUnknownDataTypes(false); 263 // this should cause us to see three pulls instead of two 264 dfr.setSkipRepeatFiles(false); 265 266 // Set file listing pulling, and reporting expectations 267 // Expect that we go through the entire process for the PNG file, and then go through 268 // the entire process again for the PNG file (again) and the XML file 269 EasyMock.expect(mDevice.executeShellCommand((String)EasyMock.anyObject())) 270 .andReturn(result1); 271 EasyMock.expect(mDevice.pullFile(EasyMock.eq(pngFilename))) 272 .andReturn(new FakeFile(pngFilename, pngContents.length())); 273 mListener.testLog(EasyMock.eq(pngFilename), EasyMock.eq(LogDataType.PNG), 274 EasyMock.eq(pngIss)); 275 276 // Note that the PNG file is picked up with the UNKNOWN data type this time 277 EasyMock.expect(mDevice.executeShellCommand((String)EasyMock.anyObject())) 278 .andReturn(result2); 279 EasyMock.expect(mDevice.pullFile(EasyMock.eq(pngFilename))) 280 .andReturn(new FakeFile(pngFilename, pngContents.length())); 281 mListener.testLog(EasyMock.eq(pngFilename), EasyMock.eq(LogDataType.UNKNOWN), 282 EasyMock.eq(pngIss)); 283 EasyMock.expect(mDevice.pullFile(EasyMock.eq(xmlFilename))) 284 .andReturn(new FakeFile(xmlFilename, xmlContents.length())); 285 mListener.testLog(EasyMock.eq(xmlFilename), EasyMock.eq(LogDataType.UNKNOWN), 286 EasyMock.eq(xmlIss)); 287 288 replayMocks(); 289 dfr.run(); 290 verifyMocks(); 291 // FIXME: use captures here to make sure we get the string back out 292 } 293 294 /** 295 * Make sure that we correctly handle the case where a file doesn't exist while matching the 296 * exact name. 297 * <p /> 298 * This verifies a fix for a bug where we would mistakenly treat the 299 * "file.txt: No such file or directory" message as a filename. This would happen when we tried 300 * to match an exact filename that doesn't exist, rather than using a shell glob. 301 */ 302 public void testNoExist() throws Exception { 303 final String file = "/data/traces.txt"; 304 final String result = file + ": No such file or directory\r\n"; 305 dfr.addPatterns(file); 306 307 EasyMock.expect(mDevice.executeShellCommand((String)EasyMock.anyObject())) 308 .andReturn(result); 309 310 replayMocks(); 311 dfr.run(); 312 // No pull attempt should happen 313 verifyMocks(); 314 } 315 316 public void testTwoFiles() throws Exception { 317 final String result = "/data/tombstones/tombstone_00\r\n/data/tombstones/tombstone_01\r\n"; 318 final String filename1 = "/data/tombstones/tombstone_00"; 319 final String filename2 = "/data/tombstones/tombstone_01"; 320 final String tombstone = "What do you want on your tombstone?"; 321 dfr.addPatterns("/data/tombstones/*"); 322 323 // Search the filesystem 324 EasyMock.expect(mDevice.executeShellCommand((String)EasyMock.anyObject())) 325 .andReturn(result); 326 327 // Log the first file 328 // This gets passed verbatim to createIssForFile above 329 EasyMock.expect(mDevice.pullFile(EasyMock.eq(filename1))) 330 .andReturn(new FakeFile(filename1, tombstone.length())); 331 mDfrIss = new ByteArrayInputStreamSource(tombstone.getBytes()); 332 // FIXME: use captures here to make sure we get the string back out 333 mListener.testLog(EasyMock.eq(filename1), EasyMock.eq(LogDataType.UNKNOWN), 334 EasyMock.eq(mDfrIss)); 335 336 // Log the second file 337 // This gets passed verbatim to createIssForFile above 338 EasyMock.expect(mDevice.pullFile(EasyMock.eq(filename2))) 339 .andReturn(new FakeFile(filename2, tombstone.length())); 340 // FIXME: use captures here to make sure we get the string back out 341 mListener.testLog(EasyMock.eq(filename2), EasyMock.eq(LogDataType.UNKNOWN), 342 EasyMock.eq(mDfrIss)); 343 344 replayMocks(); 345 dfr.run(); 346 verifyMocks(); 347 } 348 349 /** 350 * Make sure that data type inference works as expected 351 */ 352 public void testInferDataTypes() throws Exception { 353 final String result = "/data/files/file.png\r\n/data/files/file.xml\r\n" + 354 "/data/files/file.zip\r\n"; 355 final String[] filenames = {"/data/files/file.png", "/data/files/file.xml", 356 "/data/files/file.zip"}; 357 final LogDataType[] expTypes = {LogDataType.PNG, LogDataType.XML, LogDataType.ZIP}; 358 dfr.addPatterns("/data/files/*"); 359 360 final String contents = "these are file contents"; 361 mDfrIss = new ByteArrayInputStreamSource(contents.getBytes()); 362 363 EasyMock.expect(mDevice.executeShellCommand((String)EasyMock.anyObject())) 364 .andReturn(result); 365 // This gets passed verbatim to createIssForFile above 366 for (int i = 0; i < filenames.length; ++i) { 367 final String filename = filenames[i]; 368 final LogDataType expType = expTypes[i]; 369 EasyMock.expect(mDevice.pullFile(EasyMock.eq(filename))) 370 .andReturn(new FakeFile(filename, contents.length())); 371 372 // FIXME: use captures here to make sure we get the string back out 373 mListener.testLog(EasyMock.eq(filename), EasyMock.eq(expType), 374 EasyMock.eq(mDfrIss)); 375 } 376 377 replayMocks(); 378 dfr.run(); 379 verifyMocks(); 380 } 381 382 383 private void replayMocks() { 384 EasyMock.replay(mDevice, mListener); 385 } 386 387 private void verifyMocks() { 388 EasyMock.verify(mDevice, mListener); 389 } 390 } 391