1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.chromium.content.browser;
7 import android.content.Context;
8 import android.content.pm.PackageManager;
9 import android.media.MediaMetadataRetriever;
10 import android.net.ConnectivityManager;
11 import android.test.InstrumentationTestCase;
12 import android.test.mock.MockContext;
13 import android.test.suitebuilder.annotation.SmallTest;
14 import android.util.SparseArray;
16 import org.chromium.content.browser.MediaResourceGetter.MediaMetadata;
19 import java.util.Collections;
20 import java.util.HashMap;
24 * Tests for MediaResourceGetter.
26 public class MediaResourceGetterTest extends InstrumentationTestCase {
27 private static final String TEST_HTTP_URL = "http://example.com";
28 private static final String TEST_USER_AGENT = // Anyhting, really
29 "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 " +
30 "(KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36";
31 private static final String TEST_FILE_PATH = "/mnt/sdcard/test";
32 private static final String TEST_FILE_URL = "file://" + TEST_FILE_PATH;
33 private static final String TEST_COOKIES = "yum yum yum!";
34 private static final MediaMetadata sEmptyMetadata = new MediaMetadata(0, 0, 0, false);
35 private static final String sExternalStorageDirectory = "/test_external_storage";
37 private static final Map<String,String> sHeadersCookieOnly;
38 private static final Map<String,String> sHeadersCookieAndUA;
39 private static final Map<String,String> sHeadersUAOnly;
41 Map<String,String> headers = new HashMap<String, String>();
42 headers.put("Cookie", TEST_COOKIES);
43 sHeadersCookieOnly = Collections.unmodifiableMap(headers);
45 headers = new HashMap<String, String>();
46 headers.put("User-Agent", TEST_USER_AGENT);
47 sHeadersUAOnly = Collections.unmodifiableMap(headers);
49 headers = new HashMap<String, String>();
50 headers.putAll(sHeadersCookieOnly);
51 headers.putAll(sHeadersUAOnly);
52 sHeadersCookieAndUA = Collections.unmodifiableMap(headers);
55 private static class FakeFile extends File {
56 final boolean mExists;
58 public FakeFile(String path, boolean exists) {
64 public int hashCode() {
66 int result = super.hashCode();
67 result = prime * result + (mExists ? 1231 : 1237);
72 public boolean equals(Object obj) {
75 if (!super.equals(obj))
77 if (getClass() != obj.getClass())
79 FakeFile other = (FakeFile) obj;
80 if (mExists != other.mExists)
86 public boolean exists() {
92 * Helper class that fakes functionality we cannot perform without real
93 * media resources. The class being faked here has been architected
94 * carefully to allow most of the functionality to be tested. What remains
95 * here is overrides of trivial functionality.
97 private static class FakeMediaResourceGetter extends MediaResourceGetter {
98 // Read these back in tests to ensure proper values passed through
100 Map<String,String> mHeaders = null;
103 // Write these before tests to configure functionality
104 SparseArray<String> mMetadata = null;
105 Integer mNetworkType = null;
106 boolean mThrowExceptionInConfigure = false;
107 boolean mThrowExceptionInExtract = false;
108 boolean mFileExists = false;
110 // Can't use a real MediaMetadataRetriever as we have no media
112 public void configure(String uri, Map<String, String> headers) {
113 if (mThrowExceptionInConfigure) {
114 throw new RuntimeException("test exception");
120 // Can't use a real MediaMetadataRetriever as we have no media
122 public void configure(String path) {
123 if (mThrowExceptionInConfigure) {
124 throw new RuntimeException("test exception");
129 // Can't use a real MediaMetadataRetriever as we have no media
131 public String extractMetadata(int key) {
132 if (mThrowExceptionInExtract) {
133 throw new RuntimeException("test exception");
135 if (mMetadata == null) {
138 return mMetadata.get(key);
141 // Can't use a real NetworkInfo object because there is no way to
142 // mock the ConnectivityManager in Android.
144 Integer getNetworkType(Context context) {
148 // Can't use Environment.getExternalStorageDirectory because it could
149 // be inconsistent depending upon the state of the real or emulated
150 // device upon which we are testing.
152 String getExternalStorageDirectory() {
153 return sExternalStorageDirectory;
156 // Can't use regular File because we need to control the return from
157 // File.exists() on arbitrary paths.
159 File uriToFile(String path) {
160 FakeFile result = new FakeFile(path, mFileExists);
165 * Convenience method to bind a metadata value to a key.
167 * @param value the value
169 void bind(int key, String value) {
170 if (mMetadata == null) {
171 mMetadata = new SparseArray<String>();
173 mMetadata.put(key, value);
179 * Helper class to control the result of permission checks.
181 private static class InternalMockContext extends MockContext {
182 boolean allowPermission = false;
184 public int checkCallingOrSelfPermission(String permission) {
185 assertEquals(android.Manifest.permission.ACCESS_NETWORK_STATE,
187 return allowPermission ? PackageManager.PERMISSION_GRANTED :
188 PackageManager.PERMISSION_DENIED;
193 private FakeMediaResourceGetter mFakeMRG;
194 private InternalMockContext mMockContext;
197 protected void setUp() throws Exception {
199 mFakeMRG = new FakeMediaResourceGetter();
200 mMockContext = new InternalMockContext();
204 public void testMediaMetadataEquals() {
205 assertEquals(sEmptyMetadata, sEmptyMetadata);
206 assertEquals(sEmptyMetadata, new MediaMetadata(0, 0, 0, false));
207 assertFalse(sEmptyMetadata.equals(null));
208 assertFalse(sEmptyMetadata.equals("test"));
209 assertFalse(sEmptyMetadata.equals(new MediaMetadata(1, 0, 0, false)));
210 assertFalse(sEmptyMetadata.equals(new MediaMetadata(0, 1, 0, false)));
211 assertFalse(sEmptyMetadata.equals(new MediaMetadata(0, 0, 1, false)));
212 assertFalse(sEmptyMetadata.equals(new MediaMetadata(0, 0, 0, true)));
216 public void testMediaMetadataHashCode() {
217 assertEquals(sEmptyMetadata.hashCode(), sEmptyMetadata.hashCode());
218 assertEquals(sEmptyMetadata.hashCode(), new MediaMetadata(0, 0, 0, false).hashCode());
219 assertFalse(sEmptyMetadata.hashCode() == new MediaMetadata(1, 0, 0, false).hashCode());
220 assertFalse(sEmptyMetadata.hashCode() == new MediaMetadata(0, 1, 0, false).hashCode());
221 assertFalse(sEmptyMetadata.hashCode() == new MediaMetadata(0, 0, 1, false).hashCode());
222 assertFalse(sEmptyMetadata.hashCode() == new MediaMetadata(0, 0, 0, true).hashCode());
226 public void testMediaMetadataGetters() {
227 MediaMetadata data = new MediaMetadata(1, 2, 3, true);
228 assertEquals(1, data.getDurationInMilliseconds());
229 assertEquals(2, data.getWidth());
230 assertEquals(3, data.getHeight());
231 assertTrue(data.isSuccess());
233 // Validate no overlap of test values with defaults
234 data = new MediaMetadata(4, 5, 6, false);
235 assertEquals(4, data.getDurationInMilliseconds());
236 assertEquals(5, data.getWidth());
237 assertEquals(6, data.getHeight());
238 assertFalse(data.isSuccess());
242 public void testConfigure_Net_NoPermissions() {
243 mMockContext.allowPermission = false;
244 assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
245 TEST_COOKIES, TEST_USER_AGENT));
249 public void testConfigure_Net_NoActiveNetwork() {
250 mMockContext.allowPermission = true;
251 mFakeMRG.mNetworkType = null;
252 assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
253 TEST_COOKIES, TEST_USER_AGENT));
257 public void testConfigure_Net_Disallowed_Mobile() {
258 mMockContext.allowPermission = true;
259 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_MOBILE;
260 assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
261 TEST_COOKIES, TEST_USER_AGENT));
265 public void testConfigure_Net_Disallowed_Wimax() {
266 mMockContext.allowPermission = true;
267 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_WIMAX;
268 assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
269 TEST_COOKIES, TEST_USER_AGENT));
273 public void testConfigure_Net_Allowed_Ethernet_Cookies_NoUA() {
274 mMockContext.allowPermission = true;
275 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
276 assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
277 TEST_COOKIES, null));
278 assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
279 assertEquals(sHeadersCookieOnly, mFakeMRG.mHeaders);
280 assertNull(mFakeMRG.mPath);
284 public void testConfigure_Net_Allowed_Wifi_Cookies_NoUA() {
285 mMockContext.allowPermission = true;
286 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_WIFI;
287 assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
288 TEST_COOKIES, null));
289 assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
290 assertEquals(sHeadersCookieOnly, mFakeMRG.mHeaders);
291 assertNull(mFakeMRG.mPath);
295 public void testConfigure_Net_Allowed_Ethernet_NoCookies_NoUA() {
296 mMockContext.allowPermission = true;
297 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
298 assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
300 assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
301 assertEquals(Collections.emptyMap(), mFakeMRG.mHeaders);
302 assertNull(mFakeMRG.mPath);
306 public void testConfigure_Net_Allowed_Ethernet_Cookies_WithUA() {
307 mMockContext.allowPermission = true;
308 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
309 assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
310 TEST_COOKIES, TEST_USER_AGENT));
311 assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
312 assertEquals(sHeadersCookieAndUA, mFakeMRG.mHeaders);
313 assertNull(mFakeMRG.mPath);
317 public void testConfigure_Net_Allowed_Ethernet_NoCookies_WithUA() {
318 mMockContext.allowPermission = true;
319 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
320 assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
321 "", TEST_USER_AGENT));
322 assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
323 assertEquals(sHeadersUAOnly, mFakeMRG.mHeaders);
324 assertNull(mFakeMRG.mPath);
328 public void testConfigure_Net_Allowed_Ethernet_Exception() {
329 mMockContext.allowPermission = true;
330 mFakeMRG.mThrowExceptionInConfigure = true;
331 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
332 assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
333 "", TEST_USER_AGENT));
334 assertNull(mFakeMRG.mUri);
335 assertNull(mFakeMRG.mHeaders);
339 public void testConfigure_File_Allowed_MntSdcard() {
340 final String path = "/mnt/sdcard/test";
341 final String url = "file://" + path;
342 mFakeMRG.mFileExists = true;
343 assertTrue(mFakeMRG.configure(mMockContext, url, "", null));
344 assertEquals(path, mFakeMRG.mPath);
345 assertNull(mFakeMRG.mUri);
346 assertNull(mFakeMRG.mHeaders);
350 public void testConfigure_File_Allowed_Sdcard() {
351 final String path = "/sdcard/test";
352 final String url = "file://" + path;
353 mFakeMRG.mFileExists = true;
354 assertTrue(mFakeMRG.configure(mMockContext, url, "", null));
355 assertEquals(path, mFakeMRG.mPath);
356 assertNull(mFakeMRG.mUri);
357 assertNull(mFakeMRG.mHeaders);
361 public void testConfigure_File_Allowed_Sdcard_DoesntExist() {
362 final String path = "/sdcard/test";
363 final String url = "file://" + path;
364 mFakeMRG.mFileExists = false;
365 assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
366 assertNull(mFakeMRG.mPath);
370 public void testConfigure_File_Allowed_ExternalStorage() {
371 final String path = sExternalStorageDirectory + "/test";
372 final String url = "file://" + path;
373 mFakeMRG.mFileExists = true;
374 assertTrue(mFakeMRG.configure(mMockContext, url, "", null));
375 assertEquals(path, mFakeMRG.mPath);
376 assertNull(mFakeMRG.mUri);
377 assertNull(mFakeMRG.mHeaders);
381 public void testConfigure_File_Disallowed_Innocent() {
382 final String path = "/malicious/path";
383 final String url = "file://" + path;
384 mFakeMRG.mFileExists = true;
385 assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
386 assertNull(mFakeMRG.mPath);
390 public void testConfigure_File_Disallowed_Malicious() {
391 final String path = "/mnt/sdcard/../../data";
392 final String url = "file://" + path;
393 mFakeMRG.mFileExists = true;
394 assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
395 assertNull(mFakeMRG.mPath);
399 public void testConfigure_File_Allowed_Exception() {
400 final String path = "/mnt/sdcard/test";
401 final String url = "file://" + path;
402 mFakeMRG.mFileExists = true;
403 mFakeMRG.mThrowExceptionInConfigure = true;
404 assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
405 assertNull(mFakeMRG.mPath);
409 public void testExtract_NoMetadata() {
410 mFakeMRG.mFileExists = true;
411 assertEquals(sEmptyMetadata, mFakeMRG.extract(
412 mMockContext, TEST_FILE_URL, null, null));
413 assertEquals("configured successfully when we shouldn't have",
414 TEST_FILE_PATH, mFakeMRG.mPath); // tricky
418 public void testExtract_WithMetadata_ValidDuration() {
419 mFakeMRG.mFileExists = true;
420 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
421 final MediaMetadata expected = new MediaMetadata(1, 0, 0, true);
422 assertEquals(expected, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
426 public void testExtract_WithMetadata_InvalidDuration() {
427 mFakeMRG.mFileExists = true;
428 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "i am not an integer");
429 assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
433 public void testExtract_WithMetadata_ValidDuration_HasVideo_NoWidth_NoHeight() {
434 mFakeMRG.mFileExists = true;
435 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
436 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
437 assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
441 public void testExtract_WithMetadata_ValidDuration_HasVideo_ValidWidth_NoHeight() {
442 mFakeMRG.mFileExists = true;
443 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
444 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
445 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH, "1");
446 assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
450 public void testExtract_WithMetadata_ValidDuration_HasVideo_InvalidWidth_NoHeight() {
451 mFakeMRG.mFileExists = true;
452 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
453 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
454 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH, "i am not an integer");
455 assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
459 public void testExtract_WithMetadata_ValidDuration_HasVideo_ValidWidth_ValidHeight() {
460 mFakeMRG.mFileExists = true;
461 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
462 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
463 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH, "2");
464 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT, "3");
465 final MediaMetadata expected = new MediaMetadata(1, 2, 3, true);
466 assertEquals(expected, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
470 public void testExtract_WithMetadata_ValidDuration_HasVideo_ValidWidth_InvalidHeight() {
471 mFakeMRG.mFileExists = true;
472 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
473 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
474 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH, "1");
475 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT, "i am not an integer");
476 assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
480 public void testExtract_WithMetadata_ValidDuration_ExceptionInExtract() {
481 mFakeMRG.mFileExists = true;
482 mFakeMRG.mThrowExceptionInExtract = true;
483 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
484 assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
488 public void testAndroidDeviceOk_BadModel_BadVersion() {
489 assertFalse(MediaResourceGetter.androidDeviceOk(
490 "GT-I9100", android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1));
494 public void testAndroidDeviceOk_BadModel_GoodVersion() {
495 assertTrue(MediaResourceGetter.androidDeviceOk(
496 "GT-I9100", android.os.Build.VERSION_CODES.JELLY_BEAN));
500 public void testAndroidDeviceOk_GoodModel_AnyVersion() {
501 assertTrue(MediaResourceGetter.androidDeviceOk(
502 "Happy Device", android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH));