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.LOLLIPOP) | |
56 private static class TestJobScheduler extends JobScheduler { | |
57 private final JobScheduler mRealScheduler; | |
gsennton
2017/03/15 12:57:43
I don't quite see why you have a real JobScheduler
Ilya Sherman
2017/03/16 01:36:57
Hmm, good point. Simplified.
| |
58 | |
59 TestJobScheduler(JobScheduler realScheduler) { | |
60 mRealScheduler = realScheduler; | |
61 } | |
62 | |
63 @Override | |
64 public void cancel(int jobId) { | |
65 mRealScheduler.cancel(jobId); | |
66 } | |
67 | |
68 @Override | |
69 public void cancelAll() { | |
70 mRealScheduler.cancelAll(); | |
71 } | |
72 | |
73 @Override | |
74 public List<JobInfo> getAllPendingJobs() { | |
75 return mRealScheduler.getAllPendingJobs(); | |
76 } | |
77 | |
78 @Override | |
79 public JobInfo getPendingJob(int jobId) { | |
80 return mRealScheduler.getPendingJob(jobId); | |
81 } | |
82 | |
83 @Override | |
84 public int schedule(JobInfo job) { | |
85 assertEquals(TaskIds.CHROME_MINIDUMP_UPLOADING_JOB_ID, job.getId()); | |
86 assertEquals(ChromeMinidumpUploadJobService.class.getName(), | |
87 job.getService().getClassName()); | |
88 return mRealScheduler.schedule(job); | |
89 } | |
90 }; | |
91 | |
92 // Responsible for verifying that the correct intent is fired after the logc at is extracted. | |
93 private class TestContext extends AdvancedMockContext { | |
94 int mNumServiceStarts; | |
95 | |
96 TestContext(Context realContext) { | |
97 super(realContext); | |
98 } | |
99 | |
100 @Override | |
101 public ComponentName startService(Intent intent) { | |
102 assertFalse("Should only start a service directly when the job sched uler is disabled.", | |
103 ChromeFeatureList.isEnabled( | |
104 ChromeFeatureList.UPLOAD_CRASH_REPORTS_USING_JOB_SCH EDULER)); | |
105 ++mNumServiceStarts; | |
106 assertEquals(1, mNumServiceStarts); | |
107 assertEquals( | |
108 MinidumpUploadService.class.getName(), intent.getComponent() .getClassName()); | |
109 assertEquals(MinidumpUploadService.ACTION_UPLOAD, intent.getAction() ); | |
110 assertEquals(new File(mCrashDir, "test.dmp.try0").getAbsolutePath(), | |
111 intent.getStringExtra(MinidumpUploadService.FILE_TO_UPLOAD_K EY)); | |
112 return super.startService(intent); | |
113 } | |
114 | |
115 @Override | |
116 public Object getSystemService(String name) { | |
117 if (Context.JOB_SCHEDULER_SERVICE.equals(name)) { | |
118 assertTrue("Should only access the JobScheduler when it is enabl ed.", | |
119 ChromeFeatureList.isEnabled( | |
120 ChromeFeatureList.UPLOAD_CRASH_REPORTS_USING_JOB _SCHEDULER)); | |
121 return new TestJobScheduler((JobScheduler) super.getSystemServic e(name)); | |
122 } | |
123 | |
124 return super.getSystemService(name); | |
125 } | |
126 }; | |
127 | |
32 @Override | 128 @Override |
33 protected void setUp() throws Exception { | 129 protected void setUp() throws Exception { |
34 super.setUp(); | 130 super.setUp(); |
35 mCrashDir = new CrashFileManager(mCacheDir).getCrashDirectory(); | 131 mCrashDir = new CrashFileManager(mCacheDir).getCrashDirectory(); |
36 } | 132 } |
37 | 133 |
38 @MediumTest | 134 @Override |
39 public void testSimpleExtraction() { | 135 protected void tearDown() { |
40 // Set up the test. | 136 ChromeFeatureList.setTestFeatures(null); |
41 final List<String> logcat = new ArrayList<String>(); | 137 } |
42 logcat.add("some random log content"); | |
43 logcat.add("some more deterministic log content"); | |
44 | 138 |
45 final File minidump = new File(mCrashDir, "test.dmp"); | 139 /** |
46 final String boundary = "boundary"; | 140 * Sets whether to upload minidumps using the JobScheduler API. Minidumps ca n either be uploaded |
47 final String minidumpContents = "important minidump contents"; | 141 * via a JobScheduler, or via a direct Intent service. |
142 * @param enable Whether to enable the JobScheduler API. | |
143 */ | |
144 private void setJobSchedulerEnabled(boolean enable) { | |
145 Map<String, Boolean> features = new HashMap<>(); | |
146 features.put(ChromeFeatureList.UPLOAD_CRASH_REPORTS_USING_JOB_SCHEDULER, enable); | |
147 ChromeFeatureList.setTestFeatures(features); | |
148 } | |
149 | |
150 /** | |
151 * Creates a simple fake minidump file for testing. | |
152 * @param filename The name of the file to create. | |
153 */ | |
154 private File createMinidump(String filename) throws IOException { | |
155 File minidump = new File(mCrashDir, filename); | |
48 FileWriter writer = null; | 156 FileWriter writer = null; |
49 try { | 157 try { |
50 writer = new FileWriter(minidump); | 158 writer = new FileWriter(minidump); |
51 writer.write(boundary + "\n"); | 159 writer.write(BOUNDARY + "\n"); |
52 writer.write(minidumpContents + "\n"); | 160 writer.write(MINIDUMP_CONTENTS + "\n"); |
53 } catch (IOException e) { | |
54 fail(e.toString()); | |
55 } finally { | 161 } finally { |
56 StreamUtil.closeQuietly(writer); | 162 StreamUtil.closeQuietly(writer); |
57 } | 163 } |
164 return minidump; | |
165 } | |
58 | 166 |
59 // The testContext is responsible for verifying that the correct intent is fired after the | 167 /** |
60 // logcat is extracted. | 168 * Verifies that the contents of the {@param filename} are the expected ones . |
61 final AtomicInteger numServiceStarts = new AtomicInteger(0); | 169 * @param filename The name of the file containing the concatenated logcat a nd minidump output. |
62 Context testContext = new AdvancedMockContext(getInstrumentation().getTa rgetContext()) { | 170 */ |
63 @Override | 171 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; | 172 BufferedReader input = null; |
86 try { | 173 try { |
87 File logfile = new File(mCrashDir, "test.dmp.try0"); | 174 File minidumpWithLogcat = new File(mCrashDir, filename); |
88 assertTrue("Logfile should exist!", logfile.exists()); | 175 assertTrue("Should have created a file containing the logcat and min idump contents", |
176 minidumpWithLogcat.exists()); | |
89 | 177 |
90 input = new BufferedReader(new FileReader(logfile)); | 178 input = new BufferedReader(new FileReader(minidumpWithLogcat)); |
91 assertEquals("The first line should be the boundary line.", boundary , input.readLine()); | 179 assertEquals("The first line should be the boundary line.", BOUNDARY , input.readLine()); |
92 assertEquals("The second line should be the content dispoistion.", | 180 assertEquals("The second line should be the content dispoistion.", |
93 MinidumpLogcatPrepender.LOGCAT_CONTENT_DISPOSITION, input.re adLine()); | 181 MinidumpLogcatPrepender.LOGCAT_CONTENT_DISPOSITION, input.re adLine()); |
94 assertEquals("The third line should be the content type.", | 182 assertEquals("The third line should be the content type.", |
95 MinidumpLogcatPrepender.LOGCAT_CONTENT_TYPE, input.readLine( )); | 183 MinidumpLogcatPrepender.LOGCAT_CONTENT_TYPE, input.readLine( )); |
96 assertEquals("The fourth line should be blank, for padding.", "", in put.readLine()); | 184 assertEquals("The fourth line should be blank, for padding.", "", in put.readLine()); |
97 for (String expected : logcat) { | 185 for (String expected : LOGCAT) { |
98 assertEquals(expected, input.readLine()); | 186 assertEquals("The logcat contents should match", expected, input .readLine()); |
99 } | 187 } |
100 assertEquals("The logcat should be followed by the boundary line.", boundary, | 188 assertEquals("The logcat should be followed by the boundary line.", BOUNDARY, |
101 input.readLine()); | 189 input.readLine()); |
102 assertEquals( | 190 assertEquals( |
103 "The minidump contents should follow.", minidumpContents, in put.readLine()); | 191 "The minidump contents should follow.", MINIDUMP_CONTENTS, i nput.readLine()); |
104 assertNull("There should be nothing else in the file", input.readLin e()); | 192 assertNull("There should be nothing else in the file", input.readLin e()); |
105 } catch (IOException e) { | |
106 fail(e.toString()); | |
107 } finally { | 193 } finally { |
108 StreamUtil.closeQuietly(input); | 194 StreamUtil.closeQuietly(input); |
109 } | 195 } |
110 } | 196 } |
197 | |
198 @MediumTest | |
199 public void testSimpleExtraction_SansJobScheduler() throws IOException { | |
200 setJobSchedulerEnabled(false); | |
201 final File minidump = createMinidump("test.dmp"); | |
202 Context testContext = new TestContext(getInstrumentation().getTargetCont ext()); | |
203 | |
204 LogcatExtractionRunnable runnable = new TestLogcatExtractionRunnable(tes tContext, minidump); | |
205 runnable.run(); | |
206 | |
207 verifyMinidumpWithLogcat("test.dmp.try0"); | |
208 } | |
209 | |
210 @MediumTest | |
211 public void testSimpleExtraction_WithJobScheduler() throws IOException { | |
212 // The JobScheduler API is only available as of Android L. | |
213 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return; | |
214 | |
215 setJobSchedulerEnabled(true); | |
216 final File minidump = createMinidump("test.dmp"); | |
217 Context testContext = new TestContext(getInstrumentation().getTargetCont ext()); | |
218 | |
219 LogcatExtractionRunnable runnable = new TestLogcatExtractionRunnable(tes tContext, minidump); | |
220 runnable.run(); | |
221 | |
222 verifyMinidumpWithLogcat("test.dmp.try0"); | |
223 } | |
111 } | 224 } |
OLD | NEW |