Index: chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadCallableTest.java |
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadCallableTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadCallableTest.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..95a873d447107e17b8133b69b91f6d892c48782a |
--- /dev/null |
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadCallableTest.java |
@@ -0,0 +1,319 @@ |
+// Copyright 2015 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.chrome.browser.crash; |
+ |
+import android.content.SharedPreferences; |
+import android.preference.PreferenceManager; |
+import android.test.suitebuilder.annotation.SmallTest; |
+ |
+import org.chromium.base.annotations.SuppressFBWarnings; |
+import org.chromium.base.test.util.Feature; |
+import org.chromium.chrome.browser.preferences.privacy.CrashReportingPermissionManager; |
+import org.chromium.chrome.browser.util.HttpURLConnectionFactory; |
+ |
+import java.io.BufferedReader; |
+import java.io.ByteArrayInputStream; |
+import java.io.ByteArrayOutputStream; |
+import java.io.File; |
+import java.io.FileOutputStream; |
+import java.io.FileReader; |
+import java.io.IOException; |
+import java.io.InputStream; |
+import java.io.OutputStream; |
+import java.net.HttpURLConnection; |
+import java.net.URL; |
+ |
+/** |
+ * Unittests for {@link MinidumpUploadCallable}. |
+ */ |
+public class MinidumpUploadCallableTest extends CrashTestCase { |
+ private static final String BOUNDARY = "TESTBOUNDARY"; |
+ private static final String CRASH_ID = "IMACRASHID"; |
+ private static final int CURRENT_DAY = 14; |
+ private static final String LOG_FILE_NAME = "chromium_renderer-123_log.dmp224"; |
+ private File mTestUpload; |
+ private File mUploadLog; |
+ private File mExpectedFileAfterUpload; |
+ |
+ private static class TestHttpURLConnection extends HttpURLConnection { |
+ private static final String EXPECTED_CONTENT_TYPE_VALUE = |
+ String.format(MinidumpUploadCallable.CONTENT_TYPE_TMPL, BOUNDARY); |
+ |
+ /** |
+ * The value of the "Content-Type" property if the property has been set. |
+ */ |
+ private String mContentTypePropertyValue = ""; |
+ |
+ TestHttpURLConnection(URL url) { |
+ super(url); |
+ assertEquals(MinidumpUploadCallable.CRASH_URL_STRING, url.toString()); |
+ } |
+ |
+ @Override |
+ public void disconnect() { |
+ // Check that the "Content-Type" property has been set and the property's value. |
+ assertEquals(EXPECTED_CONTENT_TYPE_VALUE, mContentTypePropertyValue); |
+ } |
+ |
+ @Override |
+ public InputStream getInputStream() { |
+ return new ByteArrayInputStream(CRASH_ID.getBytes()); |
+ } |
+ |
+ @Override |
+ public OutputStream getOutputStream() { |
+ return new ByteArrayOutputStream(); |
+ } |
+ |
+ @Override |
+ public int getResponseCode() { |
+ return 200; |
+ } |
+ |
+ @Override |
+ public String getResponseMessage() { |
+ return null; |
+ } |
+ |
+ @Override |
+ public boolean usingProxy() { |
+ return false; |
+ } |
+ |
+ @Override |
+ public void connect() { |
+ } |
+ |
+ @Override |
+ public void setRequestProperty(String key, String value) { |
+ if (key.equals("Content-Type")) { |
+ mContentTypePropertyValue = value; |
+ } |
+ } |
+ } |
+ |
+ private static class TestHttpURLConnectionFactory implements HttpURLConnectionFactory { |
+ @Override |
+ public HttpURLConnection createHttpURLConnection(String url) { |
+ try { |
+ return new TestHttpURLConnection(new URL(url)); |
+ } catch (IOException e) { |
+ return null; |
+ } |
+ } |
+ } |
+ |
+ private static class FailHttpURLConnectionFactory implements HttpURLConnectionFactory { |
+ @Override |
+ public HttpURLConnection createHttpURLConnection(String url) { |
+ fail(); |
+ return null; |
+ } |
+ } |
+ |
+ private static class MockCrashReportingPermissionManager |
+ implements CrashReportingPermissionManager { |
+ private final boolean mIsPermitted; |
+ private final boolean mIsLimitted; |
+ |
+ MockCrashReportingPermissionManager(boolean isPermitted, boolean isLimitted) { |
+ mIsPermitted = isPermitted; |
+ mIsLimitted = isLimitted; |
+ } |
+ |
+ @Override |
+ public boolean isUploadPermitted() { |
+ return mIsPermitted; |
+ } |
+ |
+ @Override |
+ public boolean isUploadLimited() { |
+ return mIsLimitted; |
+ } |
+ } |
+ |
+ /** |
+ * This class accesses member fields of |MinidumpUploadCallableTest| class and calls |
+ * |getInstrumentation| which cannot be done in a static context. |
+ */ |
+ private class MockMinidumpUploadCallable extends MinidumpUploadCallable { |
+ MockMinidumpUploadCallable( |
+ HttpURLConnectionFactory httpURLConnectionFactory, |
+ CrashReportingPermissionManager permManager) { |
+ super(mTestUpload, mUploadLog, httpURLConnectionFactory, permManager, |
+ PreferenceManager.getDefaultSharedPreferences( |
+ getInstrumentation().getTargetContext())); |
+ } |
+ |
+ @Override |
+ protected int getCurrentDay() { |
+ return CURRENT_DAY; |
+ } |
+ } |
+ |
+ private void createMinidumpFile() throws Exception { |
+ mTestUpload = new File(mCrashDir, LOG_FILE_NAME); |
+ setUpMinidumpFile(mTestUpload, BOUNDARY); |
+ } |
+ |
+ @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") |
+ @Override |
+ protected void setUp() throws Exception { |
+ super.setUp(); |
+ mUploadLog = new File(mCacheDir, CrashFileManager.CRASH_DUMP_LOGFILE); |
+ // Delete all logs from previous runs if possible. |
+ mUploadLog.delete(); |
+ |
+ createMinidumpFile(); |
+ mExpectedFileAfterUpload = new File( |
+ mCrashDir, |
+ mTestUpload.getName().replaceFirst("\\.dmp", ".up")); |
+ } |
+ |
+ @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") |
+ @Override |
+ protected void tearDown() throws Exception { |
+ if (mTestUpload.exists()) mTestUpload.delete(); |
+ super.tearDown(); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Android-AppBase"}) |
+ public void testCallWhenCurrentlyPermitted() throws Exception { |
+ CrashReportingPermissionManager testPermManager = |
+ new MockCrashReportingPermissionManager(true, false); |
+ |
+ HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory(); |
+ |
+ MinidumpUploadCallable minidumpUploadCallable = |
+ new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager); |
+ assertTrue(minidumpUploadCallable.call()); |
+ assertTrue(mExpectedFileAfterUpload.exists()); |
+ assertValidUploadLogEntry(); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Android-AppBase"}) |
+ public void testCallPermittedButNotUnderCurrentCircumstances() throws Exception { |
+ CrashReportingPermissionManager testPermManager = |
+ new MockCrashReportingPermissionManager(false, false); |
+ |
+ HttpURLConnectionFactory httpURLConnectionFactory = new FailHttpURLConnectionFactory(); |
+ |
+ MinidumpUploadCallable minidumpUploadCallable = |
+ new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager); |
+ assertFalse(minidumpUploadCallable.call()); |
+ assertFalse(mExpectedFileAfterUpload.exists()); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Android-AppBase"}) |
+ public void testCrashUploadSizeConstraints() throws Exception { |
+ CrashReportingPermissionManager testPermManager = |
+ new MockCrashReportingPermissionManager(true, true); |
+ |
+ HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory(); |
+ |
+ FileOutputStream stream = null; |
+ try { |
+ stream = new FileOutputStream(mTestUpload, true); |
+ byte[] buf = new byte[MinidumpUploadCallable.LOG_SIZE_LIMIT_BYTES]; |
+ stream.write(buf); |
+ stream.flush(); |
+ } finally { |
+ if (stream != null) stream.close(); |
+ } |
+ |
+ MinidumpUploadCallable minidumpUploadCallable = |
+ new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager); |
+ setUpCrashPreferences(CURRENT_DAY, MinidumpUploadCallable.LOG_UPLOAD_LIMIT_PER_DAY - 1); |
+ assertFalse(minidumpUploadCallable.call()); |
+ assertFalse(mExpectedFileAfterUpload.exists()); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Android-AppBase"}) |
+ public void testCrashUploadSizeNotLimited() throws Exception { |
+ CrashReportingPermissionManager testPermManager = |
+ new MockCrashReportingPermissionManager(true, false); |
+ |
+ HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory(); |
+ |
+ FileOutputStream stream = null; |
+ try { |
+ stream = new FileOutputStream(mTestUpload, true); |
+ byte[] buf = new byte[MinidumpUploadCallable.LOG_SIZE_LIMIT_BYTES]; |
+ stream.write(buf); |
+ stream.flush(); |
+ } finally { |
+ if (stream != null) stream.close(); |
+ } |
+ |
+ MinidumpUploadCallable minidumpUploadCallable = |
+ new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager); |
+ setUpCrashPreferences(CURRENT_DAY, MinidumpUploadCallable.LOG_UPLOAD_LIMIT_PER_DAY - 1); |
+ assertTrue(minidumpUploadCallable.call()); |
+ assertTrue(mExpectedFileAfterUpload.exists()); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Android-AppBase"}) |
+ public void testCrashUploadFrequencyConstraints() throws Exception { |
+ CrashReportingPermissionManager testPermManager = |
+ new MockCrashReportingPermissionManager(true, true); |
+ |
+ HttpURLConnectionFactory httpURLConnectionFactory = new TestHttpURLConnectionFactory(); |
+ |
+ MinidumpUploadCallable minidumpUploadCallable = |
+ new MockMinidumpUploadCallable(httpURLConnectionFactory, testPermManager); |
+ setUpCrashPreferences(CURRENT_DAY, MinidumpUploadCallable.LOG_UPLOAD_LIMIT_PER_DAY); |
+ assertFalse(minidumpUploadCallable.call()); |
+ assertFalse(mExpectedFileAfterUpload.exists()); |
+ |
+ setUpCrashPreferences(CURRENT_DAY, MinidumpUploadCallable.LOG_UPLOAD_LIMIT_PER_DAY - 1); |
+ assertTrue(minidumpUploadCallable.call()); |
+ assertTrue(mExpectedFileAfterUpload.exists()); |
+ |
+ createMinidumpFile(); |
+ |
+ setUpCrashPreferences(CURRENT_DAY - 1, MinidumpUploadCallable.LOG_UPLOAD_LIMIT_PER_DAY); |
+ assertTrue(minidumpUploadCallable.call()); |
+ assertTrue(mExpectedFileAfterUpload.exists()); |
+ } |
+ |
+ private void setUpCrashPreferences(int lastDay, int count) { |
+ SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences( |
+ getInstrumentation().getTargetContext()); |
+ pref.edit() |
+ .putInt(MinidumpUploadCallable.PREF_LAST_UPLOAD_DAY, lastDay) |
+ .putInt(MinidumpUploadCallable.PREF_UPLOAD_COUNT, count) |
+ .apply(); |
+ } |
+ |
+ private void assertValidUploadLogEntry() throws IOException { |
+ File logfile = new File(mCacheDir, CrashFileManager.CRASH_DUMP_LOGFILE); |
+ BufferedReader input = new BufferedReader(new FileReader(logfile)); |
+ String line = null; |
+ String lastEntry = null; |
+ while ((line = input.readLine()) != null) { |
+ lastEntry = line; |
+ } |
+ input.close(); |
+ |
+ assertNotNull("We do not have a single entry in uploads.log", lastEntry); |
+ int seperator = lastEntry.indexOf(','); |
+ |
+ long time = Long.parseLong(lastEntry.substring(0, seperator)); |
+ long now = System.currentTimeMillis() / 1000; // Timestamp was in seconds. |
+ |
+ // Sanity check on the time stamp (within an hour). |
+ // Chances are the write and the check should have less than 1 second in between. |
+ assertTrue(time <= now); |
+ assertTrue(time > now - 60 * 60); |
+ |
+ String id = lastEntry.substring(seperator + 1, lastEntry.length()); |
+ assertEquals(id, CRASH_ID); |
+ } |
+} |