OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.crash; | 5 package org.chromium.chrome.browser.crash; |
6 | 6 |
| 7 import android.annotation.TargetApi; |
| 8 import android.app.job.JobInfo; |
| 9 import android.app.job.JobScheduler; |
7 import android.content.ComponentName; | 10 import android.content.ComponentName; |
8 import android.content.Context; | 11 import android.content.Context; |
9 import android.content.Intent; | 12 import android.content.Intent; |
| 13 import android.os.Build; |
10 import android.support.test.filters.MediumTest; | 14 import android.support.test.filters.MediumTest; |
11 | 15 |
12 import org.chromium.base.StreamUtil; | 16 import org.chromium.base.StreamUtil; |
13 import org.chromium.base.test.util.AdvancedMockContext; | 17 import org.chromium.base.test.util.AdvancedMockContext; |
| 18 import org.chromium.chrome.browser.ChromeFeatureList; |
| 19 import org.chromium.components.background_task_scheduler.TaskIds; |
14 import org.chromium.components.minidump_uploader.CrashFileManager; | 20 import org.chromium.components.minidump_uploader.CrashFileManager; |
15 import org.chromium.components.minidump_uploader.CrashTestCase; | 21 import org.chromium.components.minidump_uploader.CrashTestCase; |
16 | 22 |
17 import java.io.BufferedReader; | 23 import java.io.BufferedReader; |
18 import java.io.File; | 24 import java.io.File; |
19 import java.io.FileReader; | 25 import java.io.FileReader; |
20 import java.io.FileWriter; | 26 import java.io.FileWriter; |
21 import java.io.IOException; | 27 import java.io.IOException; |
22 import java.util.ArrayList; | 28 import java.util.Arrays; |
| 29 import java.util.HashMap; |
23 import java.util.List; | 30 import java.util.List; |
24 import java.util.concurrent.atomic.AtomicInteger; | 31 import java.util.Map; |
25 | 32 |
26 /** | 33 /** |
27 * Unittests for {@link LogcatExtractionRunnable}. | 34 * Unittests for {@link LogcatExtractionRunnable}. |
28 */ | 35 */ |
29 public class LogcatExtractionRunnableTest extends CrashTestCase { | 36 public class LogcatExtractionRunnableTest extends CrashTestCase { |
30 private File mCrashDir; | 37 private File mCrashDir; |
31 | 38 |
| 39 private static final String BOUNDARY = "boundary"; |
| 40 private static final String MINIDUMP_CONTENTS = "important minidump contents
"; |
| 41 private static final List<String> LOGCAT = |
| 42 Arrays.asList("some random log content", "some more deterministic lo
g content"); |
| 43 |
| 44 private static class TestLogcatExtractionRunnable extends LogcatExtractionRu
nnable { |
| 45 TestLogcatExtractionRunnable(Context context, File minidump) { |
| 46 super(context, minidump); |
| 47 } |
| 48 |
| 49 @Override |
| 50 protected List<String> getLogcat() { |
| 51 return LOGCAT; |
| 52 } |
| 53 }; |
| 54 |
| 55 @TargetApi(Build.VERSION_CODES.M) |
| 56 private static class TestJobScheduler extends JobScheduler { |
| 57 TestJobScheduler() {} |
| 58 |
| 59 @Override |
| 60 public void cancel(int jobId) {} |
| 61 |
| 62 @Override |
| 63 public void cancelAll() {} |
| 64 |
| 65 @Override |
| 66 public List<JobInfo> getAllPendingJobs() { |
| 67 return null; |
| 68 } |
| 69 |
| 70 @Override |
| 71 public JobInfo getPendingJob(int jobId) { |
| 72 return null; |
| 73 } |
| 74 |
| 75 @Override |
| 76 public int schedule(JobInfo job) { |
| 77 assertEquals(TaskIds.CHROME_MINIDUMP_UPLOADING_JOB_ID, job.getId()); |
| 78 assertEquals(ChromeMinidumpUploadJobService.class.getName(), |
| 79 job.getService().getClassName()); |
| 80 return 0; |
| 81 } |
| 82 }; |
| 83 |
| 84 // Responsible for verifying that the correct intent is fired after the logc
at is extracted. |
| 85 private class TestContext extends AdvancedMockContext { |
| 86 int mNumServiceStarts; |
| 87 |
| 88 TestContext(Context realContext) { |
| 89 super(realContext); |
| 90 } |
| 91 |
| 92 @Override |
| 93 public ComponentName startService(Intent intent) { |
| 94 assertFalse("Should only start a service directly when the job sched
uler is disabled.", |
| 95 ChromeFeatureList.isEnabled( |
| 96 ChromeFeatureList.UPLOAD_CRASH_REPORTS_USING_JOB_SCH
EDULER)); |
| 97 ++mNumServiceStarts; |
| 98 assertEquals(1, mNumServiceStarts); |
| 99 assertEquals( |
| 100 MinidumpUploadService.class.getName(), intent.getComponent()
.getClassName()); |
| 101 assertEquals(MinidumpUploadService.ACTION_UPLOAD, intent.getAction()
); |
| 102 assertEquals(new File(mCrashDir, "test.dmp.try0").getAbsolutePath(), |
| 103 intent.getStringExtra(MinidumpUploadService.FILE_TO_UPLOAD_K
EY)); |
| 104 return super.startService(intent); |
| 105 } |
| 106 |
| 107 @Override |
| 108 public Object getSystemService(String name) { |
| 109 if (Context.JOB_SCHEDULER_SERVICE.equals(name)) { |
| 110 assertTrue("Should only access the JobScheduler when it is enabl
ed.", |
| 111 ChromeFeatureList.isEnabled( |
| 112 ChromeFeatureList.UPLOAD_CRASH_REPORTS_USING_JOB
_SCHEDULER)); |
| 113 return new TestJobScheduler(); |
| 114 } |
| 115 |
| 116 return super.getSystemService(name); |
| 117 } |
| 118 }; |
| 119 |
32 @Override | 120 @Override |
33 protected void setUp() throws Exception { | 121 protected void setUp() throws Exception { |
34 super.setUp(); | 122 super.setUp(); |
35 mCrashDir = new CrashFileManager(mCacheDir).getCrashDirectory(); | 123 mCrashDir = new CrashFileManager(mCacheDir).getCrashDirectory(); |
36 } | 124 } |
37 | 125 |
38 @MediumTest | 126 @Override |
39 public void testSimpleExtraction() { | 127 protected void tearDown() throws Exception { |
40 // Set up the test. | 128 ChromeFeatureList.setTestFeatures(null); |
41 final List<String> logcat = new ArrayList<String>(); | 129 super.tearDown(); |
42 logcat.add("some random log content"); | 130 } |
43 logcat.add("some more deterministic log content"); | |
44 | 131 |
45 final File minidump = new File(mCrashDir, "test.dmp"); | 132 /** |
46 final String boundary = "boundary"; | 133 * Sets whether to upload minidumps using the JobScheduler API. Minidumps ca
n either be uploaded |
47 final String minidumpContents = "important minidump contents"; | 134 * via a JobScheduler, or via a direct Intent service. |
| 135 * @param enable Whether to enable the JobScheduler API. |
| 136 */ |
| 137 private void setJobSchedulerEnabled(boolean enable) { |
| 138 Map<String, Boolean> features = new HashMap<>(); |
| 139 features.put(ChromeFeatureList.UPLOAD_CRASH_REPORTS_USING_JOB_SCHEDULER,
enable); |
| 140 ChromeFeatureList.setTestFeatures(features); |
| 141 } |
| 142 |
| 143 /** |
| 144 * Creates a simple fake minidump file for testing. |
| 145 * @param filename The name of the file to create. |
| 146 */ |
| 147 private File createMinidump(String filename) throws IOException { |
| 148 File minidump = new File(mCrashDir, filename); |
48 FileWriter writer = null; | 149 FileWriter writer = null; |
49 try { | 150 try { |
50 writer = new FileWriter(minidump); | 151 writer = new FileWriter(minidump); |
51 writer.write(boundary + "\n"); | 152 writer.write(BOUNDARY + "\n"); |
52 writer.write(minidumpContents + "\n"); | 153 writer.write(MINIDUMP_CONTENTS + "\n"); |
53 } catch (IOException e) { | |
54 fail(e.toString()); | |
55 } finally { | 154 } finally { |
56 StreamUtil.closeQuietly(writer); | 155 StreamUtil.closeQuietly(writer); |
57 } | 156 } |
| 157 return minidump; |
| 158 } |
58 | 159 |
59 // The testContext is responsible for verifying that the correct intent
is fired after the | 160 /** |
60 // logcat is extracted. | 161 * Verifies that the contents of the {@param filename} are the expected ones
. |
61 final AtomicInteger numServiceStarts = new AtomicInteger(0); | 162 * @param filename The name of the file containing the concatenated logcat a
nd minidump output. |
62 Context testContext = new AdvancedMockContext(getInstrumentation().getTa
rgetContext()) { | 163 */ |
63 @Override | 164 private void verifyMinidumpWithLogcat(String filename) throws IOException { |
64 public ComponentName startService(Intent intent) { | |
65 assertEquals(1, numServiceStarts.incrementAndGet()); | |
66 assertEquals(MinidumpUploadService.class.getName(), | |
67 intent.getComponent().getClassName()); | |
68 assertEquals(MinidumpUploadService.ACTION_UPLOAD, intent.getActi
on()); | |
69 assertEquals(new File(mCrashDir, "test.dmp.try0").getAbsolutePat
h(), | |
70 intent.getStringExtra(MinidumpUploadService.FILE_TO_UPLO
AD_KEY)); | |
71 return super.startService(intent); | |
72 } | |
73 }; | |
74 | |
75 // Extract the logcat! | |
76 LogcatExtractionRunnable runnable = new LogcatExtractionRunnable(testCon
text, minidump) { | |
77 @Override | |
78 protected List<String> getLogcat() { | |
79 return logcat; | |
80 } | |
81 }; | |
82 runnable.run(); | |
83 | |
84 // Verify the file contents. | |
85 BufferedReader input = null; | 165 BufferedReader input = null; |
86 try { | 166 try { |
87 File logfile = new File(mCrashDir, "test.dmp.try0"); | 167 File minidumpWithLogcat = new File(mCrashDir, filename); |
88 assertTrue("Logfile should exist!", logfile.exists()); | 168 assertTrue("Should have created a file containing the logcat and min
idump contents", |
| 169 minidumpWithLogcat.exists()); |
89 | 170 |
90 input = new BufferedReader(new FileReader(logfile)); | 171 input = new BufferedReader(new FileReader(minidumpWithLogcat)); |
91 assertEquals("The first line should be the boundary line.", boundary
, input.readLine()); | 172 assertEquals("The first line should be the boundary line.", BOUNDARY
, input.readLine()); |
92 assertEquals("The second line should be the content dispoistion.", | 173 assertEquals("The second line should be the content dispoistion.", |
93 MinidumpLogcatPrepender.LOGCAT_CONTENT_DISPOSITION, input.re
adLine()); | 174 MinidumpLogcatPrepender.LOGCAT_CONTENT_DISPOSITION, input.re
adLine()); |
94 assertEquals("The third line should be the content type.", | 175 assertEquals("The third line should be the content type.", |
95 MinidumpLogcatPrepender.LOGCAT_CONTENT_TYPE, input.readLine(
)); | 176 MinidumpLogcatPrepender.LOGCAT_CONTENT_TYPE, input.readLine(
)); |
96 assertEquals("The fourth line should be blank, for padding.", "", in
put.readLine()); | 177 assertEquals("The fourth line should be blank, for padding.", "", in
put.readLine()); |
97 for (String expected : logcat) { | 178 for (String expected : LOGCAT) { |
98 assertEquals(expected, input.readLine()); | 179 assertEquals("The logcat contents should match", expected, input
.readLine()); |
99 } | 180 } |
100 assertEquals("The logcat should be followed by the boundary line.",
boundary, | 181 assertEquals("The logcat should be followed by the boundary line.",
BOUNDARY, |
101 input.readLine()); | 182 input.readLine()); |
102 assertEquals( | 183 assertEquals( |
103 "The minidump contents should follow.", minidumpContents, in
put.readLine()); | 184 "The minidump contents should follow.", MINIDUMP_CONTENTS, i
nput.readLine()); |
104 assertNull("There should be nothing else in the file", input.readLin
e()); | 185 assertNull("There should be nothing else in the file", input.readLin
e()); |
105 } catch (IOException e) { | |
106 fail(e.toString()); | |
107 } finally { | 186 } finally { |
108 StreamUtil.closeQuietly(input); | 187 StreamUtil.closeQuietly(input); |
109 } | 188 } |
110 } | 189 } |
| 190 |
| 191 @MediumTest |
| 192 public void testSimpleExtraction_SansJobScheduler() throws IOException { |
| 193 setJobSchedulerEnabled(false); |
| 194 final File minidump = createMinidump("test.dmp"); |
| 195 Context testContext = new TestContext(getInstrumentation().getTargetCont
ext()); |
| 196 |
| 197 LogcatExtractionRunnable runnable = new TestLogcatExtractionRunnable(tes
tContext, minidump); |
| 198 runnable.run(); |
| 199 |
| 200 verifyMinidumpWithLogcat("test.dmp.try0"); |
| 201 } |
| 202 |
| 203 @MediumTest |
| 204 public void testSimpleExtraction_WithJobScheduler() throws IOException { |
| 205 // The JobScheduler API is only available as of Android M. |
| 206 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return; |
| 207 |
| 208 setJobSchedulerEnabled(true); |
| 209 final File minidump = createMinidump("test.dmp"); |
| 210 Context testContext = new TestContext(getInstrumentation().getTargetCont
ext()); |
| 211 |
| 212 LogcatExtractionRunnable runnable = new TestLogcatExtractionRunnable(tes
tContext, minidump); |
| 213 runnable.run(); |
| 214 |
| 215 verifyMinidumpWithLogcat("test.dmp.try0"); |
| 216 } |
111 } | 217 } |
OLD | NEW |