| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.components.minidump_uploader; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| |
| import android.os.ParcelFileDescriptor; |
| import android.support.test.filters.MediumTest; |
| import android.support.test.filters.SmallTest; |
| |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import org.chromium.base.test.BaseJUnit4ClassRunner; |
| import org.chromium.base.test.util.Feature; |
| |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.util.Arrays; |
| import java.util.Date; |
| import java.util.concurrent.TimeUnit; |
| import java.util.regex.Pattern; |
| |
| /** |
| * Unittests for {@link CrashFileManager}. |
| */ |
| @RunWith(BaseJUnit4ClassRunner.class) |
| public class CrashFileManagerTest { |
| @Rule |
| public CrashTestRule mTestRule = new CrashTestRule(); |
| |
| private static final int TEST_PID = 23; |
| private static final int TEST_PID2 = 24; |
| |
| private long mInitialModificationTimestamp; |
| private long mModificationTimestamp; |
| |
| private static final int MAX_TRIES_ALLOWED = 3; |
| private static final int MULTI_DIGIT_MAX_TRIES_ALLOWED = 20; |
| |
| private File mTmpFile1; |
| private File mTmpFile2; |
| private File mTmpFile3; |
| |
| private File mDmpSansLogcatFile1; |
| private File mDmpSansLogcatFile2; |
| private File mDmpSansLogcatFileForPid2; |
| |
| private File mDmpFile1; |
| private File mDmpFile2; |
| |
| private File mOneBelowMaxTriesFile; // MAX_TRIES_ALLOWED-1 tries. |
| private File mMaxTriesFile; // MAX_TRIES_ALLOWED tries. |
| |
| private File mOneBelowMultiDigitMaxTriesFile; // MULTI_DIGIT_MAX_TRIES_ALLOWED-1 tries. |
| private File mMultiDigitMaxTriesFile; // MULTI_DIGIT_MAX_TRIES_ALLOWED tries. |
| |
| private File mUpFile1; |
| private File mUpFile2; |
| |
| private File mLogfile; |
| |
| @Before |
| public void setUp() throws Exception { |
| mInitialModificationTimestamp = new Date().getTime(); |
| mModificationTimestamp = mInitialModificationTimestamp; |
| |
| // The following files will be deleted in CrashTestRule#tearDown(). |
| mTmpFile1 = new File(mTestRule.getCrashDir(), "12345ABCDE" + CrashFileManager.TMP_SUFFIX); |
| mTmpFile1.createNewFile(); |
| mTmpFile1.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mTmpFile2 = new File(mTestRule.getCrashDir(), "abcde12345" + CrashFileManager.TMP_SUFFIX); |
| mTmpFile2.createNewFile(); |
| mTmpFile2.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mTmpFile3 = new File(mTestRule.getCrashDir(), "abcdefghi" + CrashFileManager.TMP_SUFFIX); |
| mTmpFile3.createNewFile(); |
| mTmpFile3.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mDmpSansLogcatFile1 = new File(mTestRule.getCrashDir(), "123_abc.dmp"); |
| mDmpSansLogcatFile1.createNewFile(); |
| mDmpSansLogcatFile1.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mDmpSansLogcatFile2 = |
| new File(mTestRule.getCrashDir(), "chromium-renderer_abc.dmp" + TEST_PID); |
| mDmpSansLogcatFile2.createNewFile(); |
| mDmpSansLogcatFile2.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mDmpSansLogcatFileForPid2 = new File(mTestRule.getCrashDir(), "321_cba.dmp" + TEST_PID2); |
| mDmpSansLogcatFileForPid2.createNewFile(); |
| mDmpSansLogcatFileForPid2.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mDmpFile1 = new File(mTestRule.getCrashDir(), "123_abc.dmp.try0"); |
| mDmpFile1.createNewFile(); |
| mDmpFile1.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mDmpFile2 = |
| new File(mTestRule.getCrashDir(), "chromium-renderer_abc.dmp" + TEST_PID + ".try1"); |
| mDmpFile2.createNewFile(); |
| mDmpFile2.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mOneBelowMaxTriesFile = new File(mTestRule.getCrashDir(), |
| "chromium-renderer_abc.dmp" + TEST_PID + ".try" + (MAX_TRIES_ALLOWED - 1)); |
| mOneBelowMaxTriesFile.createNewFile(); |
| mOneBelowMaxTriesFile.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mMaxTriesFile = new File(mTestRule.getCrashDir(), |
| "chromium-renderer_abc.dmp" + TEST_PID + ".try" + MAX_TRIES_ALLOWED); |
| mMaxTriesFile.createNewFile(); |
| mMaxTriesFile.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mOneBelowMultiDigitMaxTriesFile = new File(mTestRule.getCrashDir(), |
| "chromium-renderer_abc.dmp" + TEST_PID + ".try" |
| + (MULTI_DIGIT_MAX_TRIES_ALLOWED - 1)); |
| mOneBelowMultiDigitMaxTriesFile.createNewFile(); |
| mOneBelowMultiDigitMaxTriesFile.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mMultiDigitMaxTriesFile = new File(mTestRule.getCrashDir(), |
| "chromium-renderer_abc.dmp" + TEST_PID + ".try" + MULTI_DIGIT_MAX_TRIES_ALLOWED); |
| mMultiDigitMaxTriesFile.createNewFile(); |
| mMultiDigitMaxTriesFile.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mUpFile1 = new File(mTestRule.getCrashDir(), "123_abcd.up.try0"); |
| mUpFile1.createNewFile(); |
| mUpFile1.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mUpFile2 = |
| new File(mTestRule.getCrashDir(), "chromium-renderer_abcd.up" + TEST_PID + ".try0"); |
| mUpFile2.createNewFile(); |
| mUpFile2.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| mLogfile = new File(mTestRule.getCrashDir(), CrashFileManager.CRASH_DUMP_LOGFILE); |
| mLogfile.createNewFile(); |
| mLogfile.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testCrashFileManagerWithNull() { |
| try { |
| new CrashFileManager(null); |
| Assert.fail("Constructor should throw NullPointerException with null context."); |
| } catch (NullPointerException npe) { |
| return; |
| } |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testGetMatchingFiles() { |
| CrashFileManager crashFileManager = new CrashFileManager(mTestRule.getCacheDir()); |
| // Three files begin with 123. |
| File[] expectedFiles = new File[] {mUpFile1, mDmpFile1, mDmpSansLogcatFile1, mTmpFile1}; |
| Pattern testPattern = Pattern.compile("^123"); |
| File[] actualFiles = crashFileManager.listCrashFiles(testPattern); |
| Assert.assertNotNull(actualFiles); |
| assertArrayEquals("Failed to match file by pattern", expectedFiles, actualFiles); |
| } |
| |
| @Test |
| @MediumTest |
| @Feature({"Android-AppBase"}) |
| public void testFileComparator() { |
| File[] expectedFiles = new File[] {mTmpFile3, mTmpFile2, mTmpFile1}; |
| File[] originalFiles = new File[] {mTmpFile1, mTmpFile2, mTmpFile3}; |
| Arrays.sort(originalFiles, CrashFileManager.sFileComparator); |
| Assert.assertNotNull(originalFiles); |
| assertArrayEquals("File comparator failed to prioritize last modified file", expectedFiles, |
| originalFiles); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testGetAllFilesSorted() { |
| CrashFileManager crashFileManager = new CrashFileManager(mTestRule.getCacheDir()); |
| File[] expectedFiles = new File[] {mLogfile, mUpFile2, mUpFile1, mMultiDigitMaxTriesFile, |
| mOneBelowMultiDigitMaxTriesFile, mMaxTriesFile, mOneBelowMaxTriesFile, mDmpFile2, |
| mDmpFile1, mDmpSansLogcatFileForPid2, mDmpSansLogcatFile2, mDmpSansLogcatFile1, |
| mTmpFile3, mTmpFile2, mTmpFile1}; |
| File[] actualFiles = crashFileManager.listCrashFiles(null); |
| Assert.assertNotNull(actualFiles); |
| assertArrayEquals( |
| "Failed to sort all files by modification time", expectedFiles, actualFiles); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testGetCrashDirectory() { |
| CrashFileManager crashFileManager = new CrashFileManager(mTestRule.getCacheDir()); |
| File actualFile = crashFileManager.getCrashDirectory(); |
| Assert.assertTrue(actualFile.isDirectory()); |
| Assert.assertEquals(mTestRule.getCrashDir(), actualFile); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testDeleteFile() { |
| Assert.assertTrue(mTmpFile1.exists()); |
| Assert.assertTrue(CrashFileManager.deleteFile(mTmpFile1)); |
| Assert.assertFalse(mTmpFile1.exists()); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testIsMinidumpSansLogcat() { |
| Assert.assertTrue(CrashFileManager.isMinidumpSansLogcat("foo.dmp")); |
| Assert.assertTrue(CrashFileManager.isMinidumpSansLogcat("foo.dmp" + TEST_PID)); |
| |
| Assert.assertFalse(CrashFileManager.isMinidumpSansLogcat("foo")); |
| Assert.assertFalse(CrashFileManager.isMinidumpSansLogcat("foo.other")); |
| Assert.assertFalse(CrashFileManager.isMinidumpSansLogcat("foo.dmp.try0")); |
| Assert.assertFalse(CrashFileManager.isMinidumpSansLogcat("foo.dmp.try2")); |
| Assert.assertFalse(CrashFileManager.isMinidumpSansLogcat("foo.dmpblah")); |
| Assert.assertFalse(CrashFileManager.isMinidumpSansLogcat("foo.dmp.other")); |
| Assert.assertFalse(CrashFileManager.isMinidumpSansLogcat("foo.dmp" + TEST_PID + ".try0")); |
| Assert.assertFalse(CrashFileManager.isMinidumpSansLogcat("foo.dmp" + TEST_PID + ".try2")); |
| Assert.assertFalse(CrashFileManager.isMinidumpSansLogcat("foo.dmpblah" + TEST_PID)); |
| Assert.assertFalse(CrashFileManager.isMinidumpSansLogcat("foo.dmp" + TEST_PID + ".other")); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testSetReadyForUpload_MinidumpWithoutPid() throws IOException { |
| File minidumpWithoutLogcat = new File(mTestRule.getCrashDir(), "foo.dmp"); |
| minidumpWithoutLogcat.createNewFile(); |
| |
| File result = CrashFileManager.trySetReadyForUpload(minidumpWithoutLogcat); |
| Assert.assertEquals("foo.dmp.try0", result.getName()); |
| Assert.assertTrue(result.exists()); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testSetReadyForUpload_MinidumpWithPid() throws IOException { |
| File minidumpWithoutLogcat = new File(mTestRule.getCrashDir(), "foo.dmp" + TEST_PID); |
| minidumpWithoutLogcat.createNewFile(); |
| |
| File result = CrashFileManager.trySetReadyForUpload(minidumpWithoutLogcat); |
| Assert.assertEquals("foo.dmp" + TEST_PID + ".try0", result.getName()); |
| Assert.assertTrue(result.exists()); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testGetMinidumpSansLogcatForPid() { |
| CrashFileManager crashFileManager = new CrashFileManager(mTestRule.getCacheDir()); |
| File expectedFile = mDmpSansLogcatFileForPid2; |
| File actualFile = crashFileManager.getMinidumpSansLogcatForPid(TEST_PID2); |
| Assert.assertNotNull(actualFile); |
| Assert.assertEquals(expectedFile, actualFile); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testGetMinidumpsSansLogcat() { |
| CrashFileManager crashFileManager = new CrashFileManager(mTestRule.getCacheDir()); |
| File[] expectedFiles = |
| new File[] {mDmpSansLogcatFileForPid2, mDmpSansLogcatFile2, mDmpSansLogcatFile1}; |
| File[] actualFiles = crashFileManager.getMinidumpsSansLogcat(); |
| Assert.assertNotNull(actualFiles); |
| assertArrayEquals("Failed to get the correct minidump files in directory", expectedFiles, |
| actualFiles); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testGetMinidumpsReadyForUpload() throws IOException { |
| File forcedFile = new File(mTestRule.getCrashDir(), "456_def.forced" + TEST_PID + ".try2"); |
| forcedFile.createNewFile(); |
| forcedFile.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| CrashFileManager crashFileManager = new CrashFileManager(mTestRule.getCacheDir()); |
| File[] expectedFiles = new File[] {forcedFile, mOneBelowMaxTriesFile, mDmpFile2, mDmpFile1}; |
| File[] actualFiles = crashFileManager.getMinidumpsReadyForUpload(MAX_TRIES_ALLOWED); |
| Assert.assertNotNull(actualFiles); |
| assertArrayEquals("Failed to get the correct minidump files in directory", expectedFiles, |
| actualFiles); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testGetMinidumpsReadyForUpload_MultiDigitMaxTries() { |
| CrashFileManager crashFileManager = new CrashFileManager(mTestRule.getCacheDir()); |
| File[] expectedFiles = new File[] {mOneBelowMultiDigitMaxTriesFile, mMaxTriesFile, |
| mOneBelowMaxTriesFile, mDmpFile2, mDmpFile1}; |
| File[] actualFiles = |
| crashFileManager.getMinidumpsReadyForUpload(MULTI_DIGIT_MAX_TRIES_ALLOWED); |
| Assert.assertNotNull(actualFiles); |
| assertArrayEquals("Failed to get the correct minidump files in directory", expectedFiles, |
| actualFiles); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testGetFilesBelowMaxTries() { |
| // No files in input -> return empty |
| assertArrayEquals(new File[0], |
| CrashFileManager.getFilesBelowMaxTries(new File[0], MAX_TRIES_ALLOWED)); |
| // Only files above MAX_TRIES -> return empty |
| assertArrayEquals(new File[0], |
| CrashFileManager.getFilesBelowMaxTries( |
| new File[] {mMaxTriesFile}, MAX_TRIES_ALLOWED)); |
| // Keep only files below MAX_TRIES |
| assertArrayEquals(new File[] {mDmpFile1, mDmpFile2, mOneBelowMaxTriesFile}, |
| CrashFileManager.getFilesBelowMaxTries( |
| new File[] {mDmpFile1, mDmpFile2, mOneBelowMaxTriesFile, mMaxTriesFile}, |
| MAX_TRIES_ALLOWED)); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testGetAllUploadedFiles() { |
| CrashFileManager crashFileManager = new CrashFileManager(mTestRule.getCacheDir()); |
| File[] expectedFiles = new File[] { mUpFile2, mUpFile1 }; |
| File[] actualFiles = crashFileManager.getAllUploadedFiles(); |
| Assert.assertNotNull(actualFiles); |
| assertArrayEquals("Failed to get the correct uploaded files in directory", expectedFiles, |
| actualFiles); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testReadAttemptNumber() { |
| Assert.assertEquals(0, CrashFileManager.readAttemptNumber("file.dmp")); |
| Assert.assertEquals(-1, CrashFileManager.readAttemptNumberInternal("file.dmp")); |
| |
| Assert.assertEquals(0, CrashFileManager.readAttemptNumber(".try")); |
| Assert.assertEquals(-1, CrashFileManager.readAttemptNumberInternal(".try")); |
| |
| Assert.assertEquals(0, CrashFileManager.readAttemptNumber("try1")); |
| Assert.assertEquals(-1, CrashFileManager.readAttemptNumberInternal("try1")); |
| |
| Assert.assertEquals(1, CrashFileManager.readAttemptNumber("file.try1.dmp")); |
| Assert.assertEquals(1, CrashFileManager.readAttemptNumberInternal("file.try1.dmp")); |
| |
| Assert.assertEquals(1, CrashFileManager.readAttemptNumber("file.dmp.try1")); |
| Assert.assertEquals(1, CrashFileManager.readAttemptNumberInternal("file.dmp.try1")); |
| |
| Assert.assertEquals(2, CrashFileManager.readAttemptNumber(".try2")); |
| Assert.assertEquals(2, CrashFileManager.readAttemptNumberInternal(".try2")); |
| |
| Assert.assertEquals(2, CrashFileManager.readAttemptNumber("file.try2.dmp")); |
| Assert.assertEquals(2, CrashFileManager.readAttemptNumberInternal("file.try2.dmp")); |
| |
| Assert.assertEquals(2, CrashFileManager.readAttemptNumber("file.dmp.try2")); |
| Assert.assertEquals(2, CrashFileManager.readAttemptNumberInternal("file.dmp.try2")); |
| |
| Assert.assertEquals(2, CrashFileManager.readAttemptNumber(".try2")); |
| Assert.assertEquals(2, CrashFileManager.readAttemptNumberInternal(".try2")); |
| |
| Assert.assertEquals(0, CrashFileManager.readAttemptNumber("file.tryN.dmp")); |
| Assert.assertEquals(-1, CrashFileManager.readAttemptNumberInternal("file.tryN.dmp")); |
| |
| Assert.assertEquals(0, CrashFileManager.readAttemptNumber("file.tryN.dmp1")); |
| Assert.assertEquals(-1, CrashFileManager.readAttemptNumberInternal("file.tryN.dmp1")); |
| |
| Assert.assertEquals(9, CrashFileManager.readAttemptNumber("file.try9.dmp")); |
| Assert.assertEquals(9, CrashFileManager.readAttemptNumberInternal("file.try9.dmp")); |
| |
| Assert.assertEquals(10, CrashFileManager.readAttemptNumber("file.try10.dmp")); |
| Assert.assertEquals(10, CrashFileManager.readAttemptNumberInternal("file.try10.dmp")); |
| |
| Assert.assertEquals(9, CrashFileManager.readAttemptNumber("file.dmp.try9")); |
| Assert.assertEquals(9, CrashFileManager.readAttemptNumberInternal("file.dmp.try9")); |
| |
| Assert.assertEquals(10, CrashFileManager.readAttemptNumber("file.dmp.try10")); |
| Assert.assertEquals(10, CrashFileManager.readAttemptNumberInternal("file.dmp.try10")); |
| |
| Assert.assertEquals(300, CrashFileManager.readAttemptNumber("file.dmp.try300")); |
| Assert.assertEquals(300, CrashFileManager.readAttemptNumberInternal("file.dmp.try300")); |
| |
| Assert.assertEquals(0, CrashFileManager.readAttemptNumber("file.dmp202.try")); |
| Assert.assertEquals(-1, CrashFileManager.readAttemptNumberInternal("file.dmp202.try")); |
| |
| Assert.assertEquals(0, CrashFileManager.readAttemptNumber("file.try.dmp1")); |
| Assert.assertEquals(-1, CrashFileManager.readAttemptNumberInternal("file.try.dmp1")); |
| |
| Assert.assertEquals(0, CrashFileManager.readAttemptNumber("file.try-2.dmp1")); |
| Assert.assertEquals(-1, CrashFileManager.readAttemptNumberInternal("file.try-2.dmp1")); |
| |
| Assert.assertEquals(0, CrashFileManager.readAttemptNumber("file.try-20.dmp1")); |
| Assert.assertEquals(-1, CrashFileManager.readAttemptNumberInternal("file.try-20.dmp1")); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testAttemptNumberRename() { |
| Assert.assertEquals( |
| "file.dmp.try1", CrashFileManager.filenameWithIncrementedAttemptNumber("file.dmp")); |
| Assert.assertEquals( |
| "f.dmp.try2", CrashFileManager.filenameWithIncrementedAttemptNumber("f.dmp.try1")); |
| Assert.assertEquals( |
| "f.dmp.try10", CrashFileManager.filenameWithIncrementedAttemptNumber("f.dmp.try9")); |
| Assert.assertEquals("f.dmp.try11", |
| CrashFileManager.filenameWithIncrementedAttemptNumber("f.dmp.try10")); |
| Assert.assertEquals( |
| "f.try2.dmp", CrashFileManager.filenameWithIncrementedAttemptNumber("f.try1.dmp")); |
| Assert.assertEquals("f.tryN.dmp.try1", |
| CrashFileManager.filenameWithIncrementedAttemptNumber("f.tryN.dmp")); |
| // Cover the case where there exists a number after (but not immediately after) ".try". |
| Assert.assertEquals("f.tryN.dmp2.try1", |
| CrashFileManager.filenameWithIncrementedAttemptNumber("f.tryN.dmp2")); |
| Assert.assertEquals("f.forced.try3", |
| CrashFileManager.filenameWithIncrementedAttemptNumber("f.forced.try2")); |
| Assert.assertEquals("file.dmp.try1", |
| CrashFileManager.filenameWithIncrementedAttemptNumber("file.dmp.try0")); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testFilenameWithForcedUploadState() { |
| // The ".try0" suffix is sometimes implicit -- in particular, when logcat extraction fails. |
| Assert.assertEquals( |
| "file.forced", CrashFileManager.filenameWithForcedUploadState("file.dmp")); |
| // A not-yet-attempted upload. |
| Assert.assertEquals("file.forced0.try0", |
| CrashFileManager.filenameWithForcedUploadState("file.dmp0.try0")); |
| // A failed upload. |
| Assert.assertEquals("file.forced12.try0", |
| CrashFileManager.filenameWithForcedUploadState("file.dmp12.try3")); |
| |
| // The same set of tests as above, but for skipped uploads rather than failed or |
| // not-yet-attempted uploads. |
| Assert.assertEquals( |
| "file.forced", CrashFileManager.filenameWithForcedUploadState("file.skipped")); |
| Assert.assertEquals("file.forced0.try0", |
| CrashFileManager.filenameWithForcedUploadState("file.skipped0.try0")); |
| Assert.assertEquals("file.forced12.try0", |
| CrashFileManager.filenameWithForcedUploadState("file.skipped12.try3")); |
| |
| // A failed previously-forced upload. |
| Assert.assertEquals("file.forced0.try0", |
| CrashFileManager.filenameWithForcedUploadState("file.forced0.try3")); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testMarkUploadSuccess() { |
| CrashFileManager.markUploadSuccess(mDmpFile1); |
| Assert.assertFalse(mDmpFile1.exists()); |
| Assert.assertTrue(new File(mTestRule.getCrashDir(), "123_abc.up.try0").exists()); |
| |
| CrashFileManager.markUploadSuccess(mDmpFile2); |
| Assert.assertFalse(mDmpFile2.exists()); |
| Assert.assertTrue( |
| new File(mTestRule.getCrashDir(), "chromium-renderer_abc.up" + TEST_PID + ".try1") |
| .exists()); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testMarkUploadSuccess_ForcedUpload() throws IOException { |
| File forced = new File(mTestRule.getCrashDir(), "123_abc.forced" + TEST_PID + ".try0"); |
| forced.createNewFile(); |
| CrashFileManager.markUploadSuccess(forced); |
| Assert.assertFalse(forced.exists()); |
| Assert.assertTrue( |
| new File(mTestRule.getCrashDir(), "123_abc.up" + TEST_PID + ".try0").exists()); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testMarkUploadSkipped() { |
| CrashFileManager.markUploadSkipped(mDmpFile1); |
| Assert.assertFalse(mDmpFile1.exists()); |
| Assert.assertTrue(new File(mTestRule.getCrashDir(), "123_abc.skipped.try0").exists()); |
| |
| CrashFileManager.markUploadSkipped(mDmpFile2); |
| Assert.assertFalse(mDmpFile2.exists()); |
| Assert.assertTrue(new File( |
| mTestRule.getCrashDir(), "chromium-renderer_abc.skipped" + TEST_PID + ".try1") |
| .exists()); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testFilterMinidumpFilesOnUid() { |
| assertArrayEquals(new File[] {new File("1_md.dmp.try0")}, |
| CrashFileManager.filterMinidumpFilesOnUid(new File[] {new File("1_md.dmp.try0")}, 1) |
| .toArray()); |
| assertArrayEquals(new File[0], |
| CrashFileManager |
| .filterMinidumpFilesOnUid(new File[] {new File("1_md.dmp.try0")}, 12) |
| .toArray()); |
| assertArrayEquals(new File[0], |
| CrashFileManager |
| .filterMinidumpFilesOnUid(new File[] {new File("12_md.dmp.try0")}, 1) |
| .toArray()); |
| assertArrayEquals(new File[] {new File("1000_md.dmp.try0")}, |
| CrashFileManager |
| .filterMinidumpFilesOnUid(new File[] {new File("1000_md.dmp.try0")}, 1000) |
| .toArray()); |
| assertArrayEquals(new File[0], |
| CrashFileManager |
| .filterMinidumpFilesOnUid(new File[] {new File("-1000_md.dmp.try0")}, -10) |
| .toArray()); |
| assertArrayEquals(new File[] {new File("-10_md.dmp.try0")}, |
| CrashFileManager |
| .filterMinidumpFilesOnUid(new File[] {new File("-10_md.dmp.try0")}, -10) |
| .toArray()); |
| |
| File[] expected = new File[] {new File("12_md.dmp.try0"), new File("12_.dmp.try0"), |
| new File("12_minidump.dmp.try0"), new File("12_1_md.dmp.try0")}; |
| assertArrayEquals(expected, |
| CrashFileManager |
| .filterMinidumpFilesOnUid( |
| new File[] {new File("12_md.dmp.try0"), new File("100_.dmp.try0"), |
| new File("4000_.dmp.try0"), new File("12_.dmp.try0"), |
| new File("12_minidump.dmp.try0"), new File("23_.dmp.try0"), |
| new File("12-.dmp.try0"), new File("12*.dmp.try0"), |
| new File("12<.dmp.try0"), new File("12=.dmp.try0"), |
| new File("12+.dmp.try0"), new File("12_1_md.dmp.try0"), |
| new File("1_12_md.dmp.try0")}, |
| 12 /* uid */) |
| .toArray()); |
| } |
| |
| /** |
| * Ensure we handle minidump copying correctly when we have reached our limit on the number of |
| * stored minidumps for a certain uid. |
| */ |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testMinidumpStorageRestrictionsPerUid() throws IOException { |
| testMinidumpStorageRestrictions(true /* perUid */); |
| } |
| |
| /* |
| * Ensure we handle minidump copying correctly when we have reached our limit on the number of |
| * stored minidumps. |
| */ |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testMinidumpStorageRestrictionsGlobal() throws IOException { |
| testMinidumpStorageRestrictions(false /* perUid */); |
| } |
| |
| private static void deleteFilesInDirIfExists(File directory) { |
| if (directory.isDirectory()) { |
| File[] files = directory.listFiles(); |
| if (files != null) { |
| for (File file : files) { |
| if (!file.delete()) { |
| throw new RuntimeException( |
| "Couldn't delete file " + file.getAbsolutePath()); |
| } |
| } |
| } |
| } |
| } |
| |
| private void testMinidumpStorageRestrictions(boolean perUid) throws IOException { |
| CrashFileManager fileManager = new CrashFileManager(mTestRule.getCacheDir()); |
| // Delete existing minidumps to ensure they don't interfere with this test. |
| deleteFilesInDirIfExists(fileManager.getCrashDirectory()); |
| Assert.assertEquals(0, fileManager.getMinidumpsReadyForUpload(10000 /* maxTries */).length); |
| File tmpCopyDir = new File(mTestRule.getExistingCacheDir(), "tmpDir"); |
| |
| // Note that these minidump files are set up directly in the cache dir - not in the crash |
| // dir. This is to ensure the CrashFileManager doesn't see these minidumps without us first |
| // copying them. |
| File minidumpToCopy = new File(mTestRule.getExistingCacheDir(), "toCopy.dmp.try0"); |
| CrashTestRule.setUpMinidumpFile(minidumpToCopy, "BOUNDARY"); |
| // Ensure we didn't add any new minidumps to the crash directory. |
| Assert.assertEquals(0, fileManager.getMinidumpsReadyForUpload(10000 /* maxTries */).length); |
| |
| int minidumpLimit = perUid ? CrashFileManager.MAX_CRASH_REPORTS_TO_UPLOAD_PER_UID |
| : CrashFileManager.MAX_CRASH_REPORTS_TO_UPLOAD; |
| for (int n = 0; n < minidumpLimit; n++) { |
| // If we are testing the app-throttling we want to use the same uid for each |
| // minidump, otherwise use a different one for each minidump. |
| createFdForandCopyFile(fileManager, minidumpToCopy, tmpCopyDir, |
| perUid ? 1 : n /* uid */, true /* shouldSucceed */); |
| } |
| |
| // Update time-stamps of copied files. |
| long initialTimestamp = new Date().getTime(); |
| File[] minidumps = fileManager.getMinidumpsReadyForUpload(10000 /* maxTries */); |
| for (int n = 0; n < minidumps.length; n++) { |
| if (!minidumps[n].setLastModified(initialTimestamp + n * 1000)) { |
| throw new RuntimeException( |
| "Couldn't modify timestamp of " + minidumps[n].getAbsolutePath()); |
| } |
| } |
| |
| File[] allMinidumps = fileManager.getMinidumpsReadyForUpload(10000 /* maxTries */); |
| Assert.assertEquals(minidumpLimit, allMinidumps.length); |
| |
| File oldestMinidump = getOldestFile(allMinidumps); |
| |
| // Now the crash directory is full - so copying a new minidump should cause the oldest |
| // existing minidump to be deleted. |
| createFdForandCopyFile(fileManager, minidumpToCopy, tmpCopyDir, 1 /* uid */, |
| true /* shouldSucceed */); |
| Assert.assertEquals( |
| minidumpLimit, fileManager.getMinidumpsReadyForUpload(10000 /* maxTries */).length); |
| // Ensure we removed the oldest file. |
| Assert.assertFalse(oldestMinidump.exists()); |
| } |
| |
| /** |
| * Utility method that creates (and closes) a file descriptor to {@param minidumpToCopy} and |
| * calls CrashFileManager.copyMinidumpFromFD. |
| */ |
| private static void createFdForandCopyFile(CrashFileManager fileManager, File minidumpToCopy, |
| File tmpCopyDir, int uid, boolean shouldSucceed) throws IOException { |
| ParcelFileDescriptor minidumpFd = null; |
| try { |
| minidumpFd = |
| ParcelFileDescriptor.open(minidumpToCopy, ParcelFileDescriptor.MODE_READ_ONLY); |
| File copiedFile = |
| fileManager.copyMinidumpFromFD(minidumpFd.getFileDescriptor(), tmpCopyDir, uid); |
| if (shouldSucceed) { |
| Assert.assertNotNull(copiedFile); |
| } else { |
| Assert.assertNull(copiedFile); |
| } |
| } finally { |
| if (minidumpFd != null) minidumpFd.close(); |
| } |
| } |
| |
| /** |
| * Returns the oldest file in the set of files {@param files}. |
| */ |
| private static File getOldestFile(File[] files) { |
| File oldestFile = null; |
| for (File file : files) { |
| if (oldestFile == null || oldestFile.lastModified() > file.lastModified()) { |
| oldestFile = file; |
| } |
| } |
| return oldestFile; |
| } |
| |
| /** |
| * Ensure that we won't copy minidumps that are too large. |
| */ |
| @Test |
| @MediumTest |
| @Feature({"Android-AppBase"}) |
| public void testCantCopyLargeFile() throws IOException { |
| CrashFileManager fileManager = new CrashFileManager(mTestRule.getCacheDir()); |
| // Delete existing minidumps to ensure they don't interfere with this test. |
| deleteFilesInDirIfExists(fileManager.getCrashDirectory()); |
| Assert.assertEquals(0, fileManager.getMinidumpsReadyForUpload(10000 /* maxTries */).length); |
| File tmpCopyDir = new File(mTestRule.getExistingCacheDir(), "tmpDir"); |
| |
| // Note that these minidump files are set up directly in the cache dir - not in the crash |
| // dir. This is to ensure the CrashFileManager doesn't see these minidumps without us first |
| // copying them. |
| File minidumpToCopy = new File(mTestRule.getExistingCacheDir(), "toCopy.dmp.try0"); |
| CrashTestRule.setUpMinidumpFile(minidumpToCopy, "BOUNDARY"); |
| // Write ~1MB data into the minidump file. |
| final int kilo = 1024; |
| byte[] kiloByteArray = new byte[kilo]; |
| FileOutputStream minidumpOutputStream = |
| new FileOutputStream(minidumpToCopy, true /* append */); |
| try { |
| for (int n = 0; n < kilo; n++) { |
| minidumpOutputStream.write(kiloByteArray); |
| } |
| } finally { |
| minidumpOutputStream.close(); |
| } |
| createFdForandCopyFile(fileManager, minidumpToCopy, tmpCopyDir, 0 /* uid */, |
| false /* shouldSucceed */); |
| Assert.assertEquals(0, tmpCopyDir.listFiles().length); |
| Assert.assertEquals(0, fileManager.getMinidumpsReadyForUpload(10000 /* maxTries */).length); |
| } |
| |
| @Test |
| @SmallTest |
| @Feature({"Android-AppBase"}) |
| public void testCleanOutAllNonFreshMinidumpFiles() throws IOException { |
| // Create some simulated old files. |
| long oldTimestamp = mInitialModificationTimestamp |
| - TimeUnit.MILLISECONDS.convert(31, TimeUnit.DAYS); |
| File old1 = new File(mTestRule.getCrashDir(), "chromium-renderer-minidump-cooo10ff.dmp"); |
| File old2 = new File(mTestRule.getCrashDir(), "chromium-renderer-minidump-cooo10ff.up0"); |
| File old3 = new File(mTestRule.getCrashDir(), "chromium-renderer-minidump-cooo10ff.logcat"); |
| old1.setLastModified(oldTimestamp); |
| old2.setLastModified(oldTimestamp - 1); |
| old3.setLastModified(oldTimestamp - 2); |
| |
| // These will be the most recent files in the directory, after all successfully uploaded |
| // files and all temp files are removed. |
| File[] recentFiles = new File[CrashFileManager.MAX_CRASH_REPORTS_TO_KEEP]; |
| for (int i = 0; i < CrashFileManager.MAX_CRASH_REPORTS_TO_KEEP; ++i) { |
| File recentMinidump = new File( |
| mTestRule.getCrashDir(), "chromium-renderer-minidump-deadbeef" + i + ".dmp"); |
| recentMinidump.createNewFile(); |
| recentMinidump.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| recentFiles[i] = recentMinidump; |
| } |
| |
| // Create some additional successful uploads. |
| File success1 = |
| new File(mTestRule.getCrashDir(), "chromium-renderer-minidump-cafebebe1.up.try0"); |
| File success2 = new File(mTestRule.getCrashDir(), |
| "chromium-renderer-minidump-cafebebe2.up" + TEST_PID + ".try1"); |
| File success3 = new File(mTestRule.getCrashDir(), |
| "chromium-renderer-minidump-cafebebe3.up" + TEST_PID + ".try2"); |
| success1.createNewFile(); |
| success2.createNewFile(); |
| success3.createNewFile(); |
| success1.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| success2.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| success3.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| // Create some additional temp files. |
| File temp1 = new File(mTestRule.getCrashDir(), "chromium-renderer-minidump-oooff1ce1.tmp"); |
| File temp2 = new File(mTestRule.getCrashDir(), "chromium-renderer-minidump-oooff1ce2.tmp"); |
| temp1.createNewFile(); |
| temp2.createNewFile(); |
| temp1.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| temp2.setLastModified(mModificationTimestamp); |
| mModificationTimestamp += 1000; |
| |
| CrashFileManager crashFileManager = new CrashFileManager(mTestRule.getCacheDir()); |
| crashFileManager.cleanOutAllNonFreshMinidumpFiles(); |
| |
| Assert.assertFalse(old1.exists()); |
| Assert.assertFalse(old2.exists()); |
| Assert.assertFalse(old3.exists()); |
| for (File f : recentFiles) { |
| Assert.assertTrue(f.exists()); |
| } |
| Assert.assertTrue(mLogfile.exists()); |
| Assert.assertFalse(mTmpFile1.exists()); |
| Assert.assertFalse(mTmpFile2.exists()); |
| Assert.assertFalse(mTmpFile3.exists()); |
| Assert.assertFalse(mDmpFile1.exists()); |
| Assert.assertFalse(mDmpFile2.exists()); |
| Assert.assertFalse(mOneBelowMaxTriesFile.exists()); |
| Assert.assertFalse(mMaxTriesFile.exists()); |
| Assert.assertFalse(mOneBelowMultiDigitMaxTriesFile.exists()); |
| Assert.assertFalse(mMultiDigitMaxTriesFile.exists()); |
| Assert.assertFalse(mUpFile1.exists()); |
| Assert.assertFalse(mUpFile2.exists()); |
| Assert.assertFalse(temp1.exists()); |
| Assert.assertFalse(temp2.exists()); |
| Assert.assertFalse(success1.exists()); |
| Assert.assertFalse(success2.exists()); |
| Assert.assertFalse(success3.exists()); |
| } |
| } |