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.annotation.SuppressLint;
8 import android.content.Context;
9 import android.content.pm.PackageManager;
10 import android.media.MediaMetadataRetriever;
11 import android.net.ConnectivityManager;
12 import android.test.InstrumentationTestCase;
13 import android.test.mock.MockContext;
14 import android.test.suitebuilder.annotation.SmallTest;
15 import android.util.SparseArray;
17 import org.chromium.content.browser.MediaResourceGetter.MediaMetadata;
20 import java.util.Collections;
21 import java.util.HashMap;
25 * Tests for MediaResourceGetter.
27 @SuppressLint("SdCardPath")
28 public class MediaResourceGetterTest extends InstrumentationTestCase {
29 private static final String TEST_HTTP_URL = "http://example.com";
30 private static final String TEST_USER_AGENT = // Anyhting, really
31 "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 " +
32 "(KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36";
33 private static final String TEST_FILE_PATH = "/mnt/sdcard/test";
34 private static final String TEST_FILE_URL = "file://" + TEST_FILE_PATH;
35 private static final String TEST_COOKIES = "yum yum yum!";
36 private static final MediaMetadata sEmptyMetadata = new MediaMetadata(0, 0, 0, false);
37 private static final String sExternalStorageDirectory = "/test_external_storage";
39 private static final Map<String,String> sHeadersCookieOnly;
40 private static final Map<String,String> sHeadersCookieAndUA;
41 private static final Map<String,String> sHeadersUAOnly;
43 Map<String,String> headers = new HashMap<String, String>();
44 headers.put("Cookie", TEST_COOKIES);
45 sHeadersCookieOnly = Collections.unmodifiableMap(headers);
47 headers = new HashMap<String, String>();
48 headers.put("User-Agent", TEST_USER_AGENT);
49 sHeadersUAOnly = Collections.unmodifiableMap(headers);
51 headers = new HashMap<String, String>();
52 headers.putAll(sHeadersCookieOnly);
53 headers.putAll(sHeadersUAOnly);
54 sHeadersCookieAndUA = Collections.unmodifiableMap(headers);
57 private static class FakeFile extends File {
58 final boolean mExists;
60 public FakeFile(String path, boolean exists) {
66 public int hashCode() {
68 int result = super.hashCode();
69 result = prime * result + (mExists ? 1231 : 1237);
74 public boolean equals(Object obj) {
77 if (!super.equals(obj))
79 if (getClass() != obj.getClass())
81 FakeFile other = (FakeFile) obj;
82 if (mExists != other.mExists)
88 public boolean exists() {
94 * Helper class that fakes functionality we cannot perform without real
95 * media resources. The class being faked here has been architected
96 * carefully to allow most of the functionality to be tested. What remains
97 * here is overrides of trivial functionality.
99 private static class FakeMediaResourceGetter extends MediaResourceGetter {
100 // Read these back in tests to ensure proper values passed through
102 Map<String,String> mHeaders = null;
105 // Write these before tests to configure functionality
106 SparseArray<String> mMetadata = null;
107 Integer mNetworkType = null;
108 boolean mThrowExceptionInConfigure = false;
109 boolean mThrowExceptionInExtract = false;
110 boolean mFileExists = false;
112 // Can't use a real MediaMetadataRetriever as we have no media
114 public void configure(String uri, Map<String, String> headers) {
115 if (mThrowExceptionInConfigure) {
116 throw new RuntimeException("test exception");
122 // Can't use a real MediaMetadataRetriever as we have no media
124 public void configure(String path) {
125 if (mThrowExceptionInConfigure) {
126 throw new RuntimeException("test exception");
131 // Can't use a real MediaMetadataRetriever as we have no media
133 public String extractMetadata(int key) {
134 if (mThrowExceptionInExtract) {
135 throw new RuntimeException("test exception");
137 if (mMetadata == null) {
140 return mMetadata.get(key);
143 // Can't use a real NetworkInfo object because there is no way to
144 // mock the ConnectivityManager in Android.
146 Integer getNetworkType(Context context) {
150 // Can't use Environment.getExternalStorageDirectory because it could
151 // be inconsistent depending upon the state of the real or emulated
152 // device upon which we are testing.
154 String getExternalStorageDirectory() {
155 return sExternalStorageDirectory;
158 // Can't use regular File because we need to control the return from
159 // File.exists() on arbitrary paths.
161 File uriToFile(String path) {
162 FakeFile result = new FakeFile(path, mFileExists);
167 * Convenience method to bind a metadata value to a key.
169 * @param value the value
171 void bind(int key, String value) {
172 if (mMetadata == null) {
173 mMetadata = new SparseArray<String>();
175 mMetadata.put(key, value);
181 * Helper class to control the result of permission checks.
183 private static class InternalMockContext extends MockContext {
184 boolean allowPermission = false;
186 public int checkCallingOrSelfPermission(String permission) {
187 assertEquals(android.Manifest.permission.ACCESS_NETWORK_STATE,
189 return allowPermission ? PackageManager.PERMISSION_GRANTED :
190 PackageManager.PERMISSION_DENIED;
195 private FakeMediaResourceGetter mFakeMRG;
196 private InternalMockContext mMockContext;
199 protected void setUp() throws Exception {
201 mFakeMRG = new FakeMediaResourceGetter();
202 mMockContext = new InternalMockContext();
206 public void testMediaMetadataEquals() {
207 assertEquals(sEmptyMetadata, sEmptyMetadata);
208 assertEquals(sEmptyMetadata, new MediaMetadata(0, 0, 0, false));
209 assertFalse(sEmptyMetadata.equals(null));
210 assertFalse(sEmptyMetadata.equals("test"));
211 assertFalse(sEmptyMetadata.equals(new MediaMetadata(1, 0, 0, false)));
212 assertFalse(sEmptyMetadata.equals(new MediaMetadata(0, 1, 0, false)));
213 assertFalse(sEmptyMetadata.equals(new MediaMetadata(0, 0, 1, false)));
214 assertFalse(sEmptyMetadata.equals(new MediaMetadata(0, 0, 0, true)));
218 public void testMediaMetadataHashCode() {
219 assertEquals(sEmptyMetadata.hashCode(), sEmptyMetadata.hashCode());
220 assertEquals(sEmptyMetadata.hashCode(), new MediaMetadata(0, 0, 0, false).hashCode());
221 assertFalse(sEmptyMetadata.hashCode() == new MediaMetadata(1, 0, 0, false).hashCode());
222 assertFalse(sEmptyMetadata.hashCode() == new MediaMetadata(0, 1, 0, false).hashCode());
223 assertFalse(sEmptyMetadata.hashCode() == new MediaMetadata(0, 0, 1, false).hashCode());
224 assertFalse(sEmptyMetadata.hashCode() == new MediaMetadata(0, 0, 0, true).hashCode());
228 public void testMediaMetadataGetters() {
229 MediaMetadata data = new MediaMetadata(1, 2, 3, true);
230 assertEquals(1, data.getDurationInMilliseconds());
231 assertEquals(2, data.getWidth());
232 assertEquals(3, data.getHeight());
233 assertTrue(data.isSuccess());
235 // Validate no overlap of test values with defaults
236 data = new MediaMetadata(4, 5, 6, false);
237 assertEquals(4, data.getDurationInMilliseconds());
238 assertEquals(5, data.getWidth());
239 assertEquals(6, data.getHeight());
240 assertFalse(data.isSuccess());
244 public void testConfigure_Net_NoPermissions() {
245 mMockContext.allowPermission = false;
246 assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
247 TEST_COOKIES, TEST_USER_AGENT));
251 public void testConfigure_Net_NoActiveNetwork() {
252 mMockContext.allowPermission = true;
253 mFakeMRG.mNetworkType = null;
254 assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
255 TEST_COOKIES, TEST_USER_AGENT));
259 public void testConfigure_Net_Disallowed_Mobile() {
260 mMockContext.allowPermission = true;
261 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_MOBILE;
262 assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
263 TEST_COOKIES, TEST_USER_AGENT));
267 public void testConfigure_Net_Disallowed_Wimax() {
268 mMockContext.allowPermission = true;
269 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_WIMAX;
270 assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
271 TEST_COOKIES, TEST_USER_AGENT));
275 public void testConfigure_Net_Allowed_Ethernet_Cookies_NoUA() {
276 mMockContext.allowPermission = true;
277 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
278 assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
279 TEST_COOKIES, null));
280 assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
281 assertEquals(sHeadersCookieOnly, mFakeMRG.mHeaders);
282 assertNull(mFakeMRG.mPath);
286 public void testConfigure_Net_Allowed_Wifi_Cookies_NoUA() {
287 mMockContext.allowPermission = true;
288 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_WIFI;
289 assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
290 TEST_COOKIES, null));
291 assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
292 assertEquals(sHeadersCookieOnly, mFakeMRG.mHeaders);
293 assertNull(mFakeMRG.mPath);
297 public void testConfigure_Net_Allowed_Ethernet_NoCookies_NoUA() {
298 mMockContext.allowPermission = true;
299 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
300 assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
302 assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
303 assertEquals(Collections.emptyMap(), mFakeMRG.mHeaders);
304 assertNull(mFakeMRG.mPath);
308 public void testConfigure_Net_Allowed_Ethernet_Cookies_WithUA() {
309 mMockContext.allowPermission = true;
310 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
311 assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
312 TEST_COOKIES, TEST_USER_AGENT));
313 assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
314 assertEquals(sHeadersCookieAndUA, mFakeMRG.mHeaders);
315 assertNull(mFakeMRG.mPath);
319 public void testConfigure_Net_Allowed_Ethernet_NoCookies_WithUA() {
320 mMockContext.allowPermission = true;
321 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
322 assertTrue(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
323 "", TEST_USER_AGENT));
324 assertEquals(TEST_HTTP_URL, mFakeMRG.mUri);
325 assertEquals(sHeadersUAOnly, mFakeMRG.mHeaders);
326 assertNull(mFakeMRG.mPath);
330 public void testConfigure_Net_Allowed_Ethernet_Exception() {
331 mMockContext.allowPermission = true;
332 mFakeMRG.mThrowExceptionInConfigure = true;
333 mFakeMRG.mNetworkType = ConnectivityManager.TYPE_ETHERNET;
334 assertFalse(mFakeMRG.configure(mMockContext, TEST_HTTP_URL,
335 "", TEST_USER_AGENT));
336 assertNull(mFakeMRG.mUri);
337 assertNull(mFakeMRG.mHeaders);
341 public void testConfigure_Net_Allowed_LocalHost_WithNoNetwork() {
342 String[] localHostUrls = {
344 "https://127.0.0.1/",
345 "http://[::1]:8888/",
347 mMockContext.allowPermission = true;
348 mFakeMRG.mNetworkType = null;
349 for (String localHostUrl : localHostUrls) {
350 assertTrue(mFakeMRG.configure(mMockContext, localHostUrl,
351 TEST_COOKIES, TEST_USER_AGENT));
352 assertEquals(localHostUrl, mFakeMRG.mUri);
353 assertEquals(sHeadersCookieAndUA, mFakeMRG.mHeaders);
354 assertNull(mFakeMRG.mPath);
359 public void testConfigure_File_Allowed_MntSdcard() {
360 final String path = "/mnt/sdcard/test";
361 final String url = "file://" + path;
362 mFakeMRG.mFileExists = true;
363 assertTrue(mFakeMRG.configure(mMockContext, url, "", null));
364 assertEquals(path, mFakeMRG.mPath);
365 assertNull(mFakeMRG.mUri);
366 assertNull(mFakeMRG.mHeaders);
370 public void testConfigure_File_Allowed_Sdcard() {
371 final String path = "/sdcard/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_Allowed_Sdcard_DoesntExist() {
382 final String path = "/sdcard/test";
383 final String url = "file://" + path;
384 mFakeMRG.mFileExists = false;
385 assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
386 assertNull(mFakeMRG.mPath);
390 public void testConfigure_File_Allowed_ExternalStorage() {
391 final String path = sExternalStorageDirectory + "/test";
392 final String url = "file://" + path;
393 mFakeMRG.mFileExists = true;
394 assertTrue(mFakeMRG.configure(mMockContext, url, "", null));
395 assertEquals(path, mFakeMRG.mPath);
396 assertNull(mFakeMRG.mUri);
397 assertNull(mFakeMRG.mHeaders);
401 public void testConfigure_File_Disallowed_Innocent() {
402 final String path = "/malicious/path";
403 final String url = "file://" + path;
404 mFakeMRG.mFileExists = true;
405 assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
406 assertNull(mFakeMRG.mPath);
410 public void testConfigure_File_Disallowed_Malicious() {
411 final String path = "/mnt/sdcard/../../data";
412 final String url = "file://" + path;
413 mFakeMRG.mFileExists = true;
414 assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
415 assertNull(mFakeMRG.mPath);
419 public void testConfigure_File_Allowed_Exception() {
420 final String path = "/mnt/sdcard/test";
421 final String url = "file://" + path;
422 mFakeMRG.mFileExists = true;
423 mFakeMRG.mThrowExceptionInConfigure = true;
424 assertFalse(mFakeMRG.configure(mMockContext, url, "", null));
425 assertNull(mFakeMRG.mPath);
429 public void testExtract_NoMetadata() {
430 mFakeMRG.mFileExists = true;
431 assertEquals(sEmptyMetadata, mFakeMRG.extract(
432 mMockContext, TEST_FILE_URL, null, null));
433 assertEquals("configured successfully when we shouldn't have",
434 TEST_FILE_PATH, mFakeMRG.mPath); // tricky
438 public void testExtract_WithMetadata_ValidDuration() {
439 mFakeMRG.mFileExists = true;
440 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
441 final MediaMetadata expected = new MediaMetadata(1, 0, 0, true);
442 assertEquals(expected, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
446 public void testExtract_WithMetadata_InvalidDuration() {
447 mFakeMRG.mFileExists = true;
448 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "i am not an integer");
449 assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
453 public void testExtract_WithMetadata_ValidDuration_HasVideo_NoWidth_NoHeight() {
454 mFakeMRG.mFileExists = true;
455 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
456 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
457 assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
461 public void testExtract_WithMetadata_ValidDuration_HasVideo_ValidWidth_NoHeight() {
462 mFakeMRG.mFileExists = true;
463 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
464 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
465 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH, "1");
466 assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
470 public void testExtract_WithMetadata_ValidDuration_HasVideo_InvalidWidth_NoHeight() {
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, "i am not an integer");
475 assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
479 public void testExtract_WithMetadata_ValidDuration_HasVideo_ValidWidth_ValidHeight() {
480 mFakeMRG.mFileExists = true;
481 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
482 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
483 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH, "2");
484 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT, "3");
485 final MediaMetadata expected = new MediaMetadata(1, 2, 3, true);
486 assertEquals(expected, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
490 public void testExtract_WithMetadata_ValidDuration_HasVideo_ValidWidth_InvalidHeight() {
491 mFakeMRG.mFileExists = true;
492 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
493 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO, "yes");
494 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH, "1");
495 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT, "i am not an integer");
496 assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
500 public void testExtract_WithMetadata_ValidDuration_ExceptionInExtract() {
501 mFakeMRG.mFileExists = true;
502 mFakeMRG.mThrowExceptionInExtract = true;
503 mFakeMRG.bind(MediaMetadataRetriever.METADATA_KEY_DURATION, "1");
504 assertEquals(sEmptyMetadata, mFakeMRG.extract(mMockContext, TEST_FILE_URL, null, null));
508 public void testAndroidDeviceOk_BadModel_BadVersion() {
509 assertFalse(MediaResourceGetter.androidDeviceOk(
510 "GT-I9100", android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1));
514 public void testAndroidDeviceOk_BadModel_GoodVersion() {
515 assertTrue(MediaResourceGetter.androidDeviceOk(
516 "GT-I9100", android.os.Build.VERSION_CODES.JELLY_BEAN));
520 public void testAndroidDeviceOk_GoodModel_AnyVersion() {
521 assertTrue(MediaResourceGetter.androidDeviceOk(
522 "Happy Device", android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH));