Chromium Code Reviews| Index: android_webview/javatests/src/org/chromium/android_webview/test/crash/WebViewMinidumpUploaderTest.java |
| diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/crash/WebViewMinidumpUploaderTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/crash/WebViewMinidumpUploaderTest.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..5bd262a64e5935399d06fe9f17458cd687355b5b |
| --- /dev/null |
| +++ b/android_webview/javatests/src/org/chromium/android_webview/test/crash/WebViewMinidumpUploaderTest.java |
| @@ -0,0 +1,242 @@ |
| +// Copyright 2017 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.android_webview.test.crash; |
| + |
| +import android.content.Context; |
| +import android.os.ParcelFileDescriptor; |
| +import android.support.test.filters.MediumTest; |
| + |
| +import org.chromium.android_webview.PlatformServiceBridge; |
| +import org.chromium.android_webview.crash.CrashReceiverService; |
| +import org.chromium.android_webview.crash.MinidumpUploader; |
| +import org.chromium.android_webview.crash.MinidumpUploaderImpl; |
| +import org.chromium.components.minidump_uploader.CrashFileManager; |
| +import org.chromium.components.minidump_uploader.MinidumpUploadCallable; |
| +import org.chromium.components.minidump_uploader.MinidumpUploadCallableTest; |
| +import org.chromium.components.minidump_uploader.util.CrashReportingPermissionManager; |
| + |
| +import java.io.File; |
| +import java.io.FileInputStream; |
| +import java.io.FileNotFoundException; |
| +import java.io.IOException; |
| + |
| +/** |
| + * WebView-specific instrumentation tests for MinidumpUploader. |
| + * These tests target the WebView-specific parts of MinidumpUploaderImpl, and the combined use of |
| + * CrashReceiverService and MinidumpUploaderImpl. |
| + */ |
| +public class WebViewMinidumpUploaderTest extends MinidumpUploaderTest { |
|
Ilya Sherman
2017/02/28 04:00:04
FWIW, I'd prefer not to use inheritance like this
gsennton
2017/02/28 16:30:05
Alright, makes sense :) (I'll update this to do so
|
| + /** |
| + * MinidumpUploaderImpl sub-class that uses WebView's MinidumpUploaderImpl implementation of |
| + * CrashReportingPermissionManager.isUsageAndCrashReportingPermittedByUser(). |
| + */ |
| + private static class WebViewUserConsentMinidumpUploaderImpl extends MinidumpUploaderImpl { |
| + boolean mUserConsent; |
| + WebViewUserConsentMinidumpUploaderImpl( |
| + Context context, boolean cleanOutMinidumps, boolean userConsent) { |
| + super(context, cleanOutMinidumps); |
| + mUserConsent = userConsent; |
| + } |
| + @Override |
| + public PlatformServiceBridge createPlatformServiceBridge() { |
| + return new TestPlatformServiceBridge(true /* canUseGms */, mUserConsent); |
| + } |
| + @Override |
| + public MinidumpUploadCallable createMinidumpUploadCallable( |
| + File minidumpFile, File logfile) { |
| + return new MinidumpUploadCallable(minidumpFile, logfile, |
| + new MinidumpUploadCallableTest.TestHttpURLConnectionFactory(), |
| + createWebViewCrashReportingManager()); |
| + } |
| + @Override |
| + protected CrashReportingPermissionManager createWebViewCrashReportingManager() { |
| + final CrashReportingPermissionManager realPermissionManager = |
| + super.createWebViewCrashReportingManager(); |
| + return new MockCrashReportingPermissionManager() { |
| + { |
| + // This setup ensures we depend on isUsageAndCrashReportingPermittedByUser(). |
| + mIsInSample = true; |
| + mIsPermitted = true; |
| + mIsCommandLineDisabled = false; |
| + mIsNetworkAvailable = true; |
| + mIsEnabledForTests = false; |
| + } |
| + @Override |
| + public boolean isUsageAndCrashReportingPermittedByUser() { |
| + // Ensure that we use the real implementation of |
| + // isUsageAndCrashReportingPermittedByUser. |
| + boolean userPermitted = |
| + realPermissionManager.isUsageAndCrashReportingPermittedByUser(); |
| + assertEquals(mUserConsent, userPermitted); |
| + return userPermitted; |
| + } |
| + }; |
| + } |
| + } |
| + |
| + /** |
| + * Ensure that when PlatformServiceBridge returns true we do upload minidumps. |
| + */ |
| + @MediumTest |
| + public void testPlatformServicesBridgeIsUsedUserConsent() throws IOException { |
| + testPlatformServicesBridgeIsUsed(true); |
| + } |
| + |
| + /** |
| + * Ensure that when PlatformServiceBridge returns false we do not upload minidumps. |
| + */ |
| + @MediumTest |
| + public void testPlatformServicesBridgeIsUsedNoUserConsent() throws IOException { |
| + testPlatformServicesBridgeIsUsed(false); |
| + } |
| + |
| + private void testPlatformServicesBridgeIsUsed(final boolean userConsent) throws IOException { |
| + MinidumpUploader minidumpUploader = |
| + new WebViewUserConsentMinidumpUploaderImpl(getInstrumentation().getTargetContext(), |
| + false /* cleanOutMinidumps */, userConsent); |
| + |
| + File firstFile = createMinidumpFileInCrashDir("1_abc.dmp0"); |
| + File secondFile = createMinidumpFileInCrashDir("12_abcd.dmp0"); |
| + File expectedFirstFile = new File( |
| + mCrashDir, firstFile.getName().replace(".dmp", userConsent ? ".up" : ".skipped")); |
| + File expectedSecondFile = new File( |
| + mCrashDir, secondFile.getName().replace(".dmp", userConsent ? ".up" : ".skipped")); |
| + |
| + MinidumpUploaderTest.uploadMinidumpsSync(minidumpUploader, false /* expectReschedule */); |
| + |
| + assertFalse(firstFile.exists()); |
| + assertTrue(expectedFirstFile.exists()); |
| + assertFalse(secondFile.exists()); |
| + assertTrue(expectedSecondFile.exists()); |
| + } |
| + |
| + /** |
| + * Ensures that the minidump copying works together with the minidump uploading. |
| + */ |
| + @MediumTest |
| + public void testCopyAndUploadWebViewMinidump() throws FileNotFoundException, IOException { |
| + final CrashFileManager fileManager = new CrashFileManager( |
| + CrashReceiverService.getWebViewCrashDir(getInstrumentation().getTargetContext())); |
| + // Note that these minidump files are set up directly in the cache dir - not in the WebView |
| + // crash dir. This is to ensure the CrashFileManager doesn't see these minidumps without us |
| + // first copying them. |
| + File minidumpToCopy = |
| + new File(getInstrumentation().getTargetContext().getCacheDir(), "toCopy.dmp"); |
| + setUpMinidumpFile(minidumpToCopy, BOUNDARY, "browser"); |
| + final String expectedFileContent = readEntireFile(minidumpToCopy); |
| + |
| + File[] uploadedFiles = copyAndUploadMinidumpsSync( |
| + fileManager, new File[][] {{minidumpToCopy}}, new int[] {0}); |
| + |
| + // CrashReceiverService will rename the minidumps to some globally unique file name |
| + // meaning that we have to check the contents of the minidump rather than the file |
| + // name. |
| + assertEquals(expectedFileContent, readEntireFile(uploadedFiles[0])); |
|
gsennton
2017/02/23 14:48:48
This is the only change I did except just moving c
|
| + File webviewTmpDir = |
| + CrashReceiverService.getWebViewTmpCrashDir(getInstrumentation().getTargetContext()); |
| + assertEquals(0, webviewTmpDir.listFiles().length); |
| + } |
| + |
| + /** |
| + * Ensure we can copy and upload several batches of files (i.e. emulate several copying-calls in |
| + * a row without the copying-service being destroyed in between). |
| + */ |
| + @MediumTest |
| + public void testCopyAndUploadSeveralMinidumpBatches() throws IOException { |
| + final CrashFileManager fileManager = new CrashFileManager( |
| + CrashReceiverService.getWebViewCrashDir(getInstrumentation().getTargetContext())); |
| + // Note that these minidump files are set up directly in the cache dir - not in the WebView |
| + // crash dir. This is to ensure the CrashFileManager doesn't see these minidumps without us |
| + // first copying them. |
| + File firstMinidumpToCopy = |
| + new File(getInstrumentation().getTargetContext().getCacheDir(), "firstToCopy.dmp"); |
| + File secondMinidumpToCopy = |
| + new File(getInstrumentation().getTargetContext().getCacheDir(), "secondToCopy.dmp"); |
| + setUpMinidumpFile(firstMinidumpToCopy, BOUNDARY, "browser"); |
| + setUpMinidumpFile(secondMinidumpToCopy, BOUNDARY, "renderer"); |
| + final String expectedFirstFileContent = readEntireFile(firstMinidumpToCopy); |
| + final String expectedSecondFileContent = readEntireFile(secondMinidumpToCopy); |
| + |
| + File[] uploadedFiles = copyAndUploadMinidumpsSync(fileManager, |
| + new File[][] {{firstMinidumpToCopy}, {secondMinidumpToCopy}}, new int[] {0, 0}); |
| + |
| + // CrashReceiverService will rename the minidumps to some globally unique file name |
| + // meaning that we have to check the contents of the minidump rather than the file |
| + // name. |
| + final String actualFileContent0 = readEntireFile(uploadedFiles[0]); |
| + final String actualFileContent1 = readEntireFile(uploadedFiles[1]); |
| + if (expectedFirstFileContent.equals(actualFileContent0)) { |
|
gsennton
2017/02/23 14:48:48
Same as above here - remove try-catch-rethrow of I
|
| + assertEquals(expectedSecondFileContent, actualFileContent1); |
| + } else { |
| + assertEquals(expectedFirstFileContent, actualFileContent1); |
| + assertEquals(expectedSecondFileContent, actualFileContent0); |
| + } |
| + } |
| + |
| + private static String readEntireFile(File file) throws IOException { |
| + FileInputStream fileInputStream = new FileInputStream(file); |
| + try { |
| + byte[] data = new byte[(int) file.length()]; |
| + fileInputStream.read(data); |
| + return new String(data); |
| + } finally { |
| + fileInputStream.close(); |
| + } |
| + } |
| + |
| + /** |
| + * Copy and upload {@param minidumps} by one array at a time - i.e. the minidumps in a single |
| + * array in {@param minidumps} will all be copied in the same call into CrashReceiverService. |
| + * @param fileManager the CrashFileManager to use when copying/renaming minidumps. |
| + * @param minidumps an array of arrays of minidumps to copy and upload, by copying one array at |
| + * a time. |
| + * @param uids an array of uids declaring the uids used when calling into CrashReceiverService. |
| + * @return the uploaded files. |
| + */ |
| + private File[] copyAndUploadMinidumpsSync(CrashFileManager fileManager, File[][] minidumps, |
| + int[] uids) throws FileNotFoundException { |
| + CrashReceiverService crashReceiverService = new CrashReceiverService(); |
| + assertEquals(minidumps.length, uids.length); |
| + // Ensure the upload service minidump directory is empty before we start copying files. |
| + File[] initialMinidumps = |
| + fileManager.getAllMinidumpFiles(MinidumpUploaderImpl.MAX_UPLOAD_TRIES_ALLOWED); |
| + assertEquals(0, initialMinidumps.length); |
| + |
| + // Open file descriptors to the files and then delete the files. |
| + ParcelFileDescriptor[][] fileDescriptors = new ParcelFileDescriptor[minidumps.length][]; |
| + int numMinidumps = 0; |
| + for (int n = 0; n < minidumps.length; n++) { |
| + File[] currentMinidumps = minidumps[n]; |
| + numMinidumps += currentMinidumps.length; |
| + fileDescriptors[n] = new ParcelFileDescriptor[currentMinidumps.length]; |
| + for (int m = 0; m < currentMinidumps.length; m++) { |
| + fileDescriptors[n][m] = ParcelFileDescriptor.open( |
| + currentMinidumps[m], ParcelFileDescriptor.MODE_READ_ONLY); |
| + assertTrue(currentMinidumps[m].delete()); |
| + } |
| + crashReceiverService.performMinidumpCopyingSerially( |
| + getInstrumentation().getTargetContext(), uids[n] /* uid */, fileDescriptors[n], |
| + false /* scheduleUploads */); |
| + } |
| + |
| + final CrashReportingPermissionManager permManager = |
| + new MockCrashReportingPermissionManager() { |
| + { mIsEnabledForTests = true; } |
| + }; |
| + MinidumpUploader minidumpUploader = |
| + new TestMinidumpUploaderImpl(getInstrumentation().getTargetContext(), permManager, |
| + false /* cleanOutMinidumps */); |
| + |
| + MinidumpUploaderTest.uploadMinidumpsSync(minidumpUploader, false /* expectReschedule */); |
| + // Ensure there are no minidumps left to upload. |
| + File[] nonUploadedMinidumps = |
| + fileManager.getAllMinidumpFiles(MinidumpUploaderImpl.MAX_UPLOAD_TRIES_ALLOWED); |
| + assertEquals(0, nonUploadedMinidumps.length); |
| + |
| + File[] uploadedFiles = fileManager.getAllUploadedFiles(); |
| + assertEquals(numMinidumps, uploadedFiles.length); |
| + return uploadedFiles; |
| + } |
| +} |