Index: chrome/android/junit/src/org/chromium/chrome/browser/media/remote/MediaUrlResolverTest.java |
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/remote/MediaUrlResolverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/remote/MediaUrlResolverTest.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5b4ceadb617ba9e145137b6abdac977fb12f366c |
--- /dev/null |
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/remote/MediaUrlResolverTest.java |
@@ -0,0 +1,300 @@ |
+// 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.media.remote; |
+ |
+import static org.hamcrest.CoreMatchers.equalTo; |
+import static org.hamcrest.CoreMatchers.nullValue; |
+import static org.junit.Assert.assertThat; |
+ |
+import android.net.Uri; |
+ |
+import org.chromium.base.CommandLine; |
+import org.chromium.testing.local.LocalRobolectricTestRunner; |
+import org.junit.Test; |
+import org.junit.runner.RunWith; |
+import org.robolectric.Robolectric; |
+import org.robolectric.annotation.Config; |
+ |
+import java.io.IOException; |
+import java.net.HttpURLConnection; |
+import java.net.MalformedURLException; |
+import java.net.URL; |
+import java.net.URLConnection; |
+import java.net.URLStreamHandler; |
+import java.net.URLStreamHandlerFactory; |
+import java.util.ArrayList; |
+import java.util.HashMap; |
+import java.util.List; |
+import java.util.Map; |
+ |
+/** |
+ * Unit tests (run on host) for {@link org.chromium.chrome.browser.media.remote.MediaUrlResolver}. |
+ */ |
+@RunWith(LocalRobolectricTestRunner.class) |
+@Config(manifest = Config.NONE) |
+public class MediaUrlResolverTest { |
+ |
+ // Constants copied from MediaUrlResolver. Don't use the copies in MediaUrlResolver |
+ // since we want the tests to detect if these are changed or corrupted. |
+ private static final String COOKIES_HEADER_NAME = "Cookies"; |
+ private static final String CORS_HEADER_NAME = "Access-Control-Allow-Origin"; |
+ private static final String RANGE_HEADER_NAME = "Range"; |
+ private static final String RANGE_HEADER_VALUE = "bytes: 0-65536"; |
+ |
+ private static final String USER_AGENT_HEADER_NAME = "User-Agent"; |
+ |
+ private static class TestDelegate implements MediaUrlResolver.Delegate { |
+ private final String mCookies; |
+ private final Uri mInputUri; |
+ |
+ private boolean mReturnedPlayable; |
+ private Uri mReturnedUri; |
+ |
+ TestDelegate(Uri uri, String cookies) { |
+ mInputUri = uri; |
+ mCookies = cookies; |
+ } |
+ |
+ @Override |
+ public String getCookies() { |
+ return mCookies; |
+ } |
+ |
+ @Override |
+ public Uri getUri() { |
+ return mInputUri; |
+ } |
+ |
+ @Override |
+ public void setUri(Uri uri, boolean playable) { |
+ // TODO(aberent): Auto-generated method stub |
+ mReturnedUri = uri; |
+ mReturnedPlayable = playable; |
+ } |
+ |
+ Uri getReturnedUri() { |
+ return mReturnedUri; |
+ } |
+ |
+ boolean isPlayable() { |
+ return mReturnedPlayable; |
+ } |
+ } |
+ |
+ private DummyUrlStreamHandler mHandler = new DummyUrlStreamHandler(); |
+ |
+ private Map<String, String> mRequestProperties; |
+ |
+ private Map<String, List<String>> mReturnedHeaders; |
+ |
+ private URL mReturnedUrl; |
+ |
+ /** |
+ * Dummy HttpURLConnection class that returns canned headers. Also prevents the test from going |
+ * out to the real network. |
+ */ |
+ private class DummyUrlConnection extends HttpURLConnection { |
+ |
+ private final URL mUrl; |
+ |
+ protected DummyUrlConnection(URL u) { |
+ super(u); |
+ mUrl = u; |
+ } |
+ |
+ @Override |
+ public void connect() throws IOException { |
+ } |
+ |
+ @Override |
+ public void disconnect() { |
+ } |
+ |
+ @Override |
+ public Map<String, List<String>> getHeaderFields() { |
+ return mReturnedHeaders; |
+ } |
+ |
+ @Override |
+ public URL getURL() { |
+ return mReturnedUrl == null ? mUrl : mReturnedUrl; |
+ } |
+ |
+ @Override |
+ public void setRequestProperty(String key, String value) { |
+ mRequestProperties.put(key, value); |
+ } |
+ |
+ @Override |
+ public boolean usingProxy() { |
+ return false; |
+ } |
+ |
+ } |
+ |
+ /** |
+ * Class for plugging in DummyUrlConnection |
+ */ |
+ private class DummyUrlStreamHandler extends URLStreamHandler { |
+ |
+ @Override |
+ protected URLConnection openConnection(URL u) throws IOException { |
+ return new DummyUrlConnection(u); |
+ } |
+ |
+ } |
+ /** |
+ * Class for plugging in DummyUrlStreamHandler and hence DummyUrlConnection |
+ */ |
+ private class DummyUrlStreamHandlerFactory implements URLStreamHandlerFactory { |
+ |
+ @Override |
+ public URLStreamHandler createURLStreamHandler(String protocol) { |
+ // If the test create the handler here then the test crashes with a |
+ // ClassCircularityError. |
+ // See https://github.com/robolectric/robolectric/issues/1688 |
+ // TODO(aberent) Once bug fixed, create handler here. |
+ return mHandler; |
+ } |
+ |
+ } |
+ |
+ /** |
+ * Test method for |
+ * {@link org.chromium.chrome.browser.media.remote.MediaUrlResolver#MediaUrlResolver}. |
+ * @throws MalformedURLException |
+ */ |
+ @Test |
+ public void testMediaUrlResolver() throws MalformedURLException { |
+ |
+ // Initialize the command line to avoid a crash when the code checks the logging flag. |
+ CommandLine.init(new String[0]); |
+ |
+ // Plug in the dummy networking. |
+ URL.setURLStreamHandlerFactory(new DummyUrlStreamHandlerFactory()); |
+ |
+ // An empty URL isn't playable |
+ TestDelegate delegate = resolveUri(Uri.EMPTY, null, null, null); |
+ |
+ assertThat("An empty Uri remains empty", delegate.getReturnedUri(), equalTo(Uri.EMPTY)); |
+ assertThat("An empty Uri isn't playable", delegate.isPlayable(), equalTo(false)); |
+ |
+ // A random, non parsable, URI of unknown type is treated as playable. |
+ delegate = resolveUri(Uri.parse("junk"), null, null, null); |
+ |
+ assertThat("A junk Uri of unknown type is unchanged", delegate.getReturnedUri().toString(), |
+ equalTo("junk")); |
+ assertThat("A junk Uri of unknown type is playable", delegate.isPlayable(), equalTo(true)); |
+ |
+ // A random, non parsable, mpeg4 URI is playable. |
+ delegate = resolveUri(Uri.parse("junk.mp4"), null, null, null); |
+ |
+ assertThat("A non-parsable mp4 Uri is unchanged", delegate.getReturnedUri().toString(), |
+ equalTo("junk.mp4")); |
+ assertThat("A non-parsable mp4 Uri is playable", delegate.isPlayable(), equalTo(true)); |
+ |
+ // A random, non parsable, HLS URI is not playable. |
+ delegate = resolveUri(Uri.parse("junk.m3u8"), null, null, null); |
+ |
+ assertThat("A non-parsable HLS Uri is unchanged", delegate.getReturnedUri().toString(), |
+ equalTo("junk.m3u8")); |
+ assertThat("A non-parsable HLS Uri is not playable", delegate.isPlayable(), equalTo(false)); |
+ |
+ // A random, non parsable, smoothstream URI is not playable even with CORS headers. |
+ HashMap<String, List<String>> corsHeaders = new HashMap<String, List<String>>(); |
+ corsHeaders.put(CORS_HEADER_NAME, new ArrayList<String>()); |
+ |
+ delegate = resolveUri(Uri.parse("junk.ism"), null, null, corsHeaders); |
+ |
+ assertThat("A non-parsable smoothstream Uri is unchanged", |
+ delegate.getReturnedUri().toString(), |
+ equalTo("junk.ism")); |
+ assertThat( |
+ "A non-parsable smoothstream Uri is not playable, " |
+ + "even if a CORS header is available", |
+ delegate.isPlayable(), equalTo(false)); |
+ |
+ // A valid mpeg4 URI is playable and unchanged. |
+ Uri uri = Uri.parse("http://example.com/test.mp4"); |
+ |
+ delegate = resolveUri(uri, null, null, null); |
+ |
+ assertThat("A valid mp4 Uri is unchanged", delegate.getReturnedUri(), equalTo(uri)); |
+ assertThat("A valid mp4 Uri is playable", delegate.isPlayable(), equalTo(true)); |
+ |
+ // Check that the correct message was sent |
+ assertThat("The message contained the user agent name", |
+ mRequestProperties.get(USER_AGENT_HEADER_NAME), equalTo("User agent")); |
+ assertThat("The message contained the user agent name", |
+ mRequestProperties.get(RANGE_HEADER_NAME), equalTo(RANGE_HEADER_VALUE)); |
+ assertThat("The message didn't contain any cookies", |
+ mRequestProperties.get(COOKIES_HEADER_NAME), nullValue()); |
+ |
+ // A valid DASH URI is unplayable without headers and unchanged. |
+ uri = Uri.parse("http://example.com/test.mpd"); |
+ |
+ delegate = resolveUri(uri, null, null, null); |
+ |
+ assertThat("A valid mpd Uri is unchanged", delegate.getReturnedUri(), equalTo(uri)); |
+ assertThat("A valid mpd Uri without a CORS header is unplayable", delegate.isPlayable(), |
+ equalTo(false)); |
+ |
+ // Adding a CORS header makes it playable. |
+ delegate = resolveUri(uri, null, null, corsHeaders); |
+ |
+ assertThat("A valid mpd Uri is unchanged", delegate.getReturnedUri(), equalTo(uri)); |
+ assertThat("A valid mpd Uri with a CORS header is playable", delegate.isPlayable(), |
+ equalTo(true)); |
+ |
+ // Adding a random header doesn't. |
+ HashMap<String, List<String>> randomHeaders = new HashMap<String, List<String>>(); |
+ randomHeaders.put("Random", new ArrayList<String>()); |
+ delegate = resolveUri(uri, null, null, randomHeaders); |
+ |
+ assertThat("A valid mpd Uri is unchanged", delegate.getReturnedUri(), equalTo(uri)); |
+ assertThat("A valid mpd Uri with a random header is not playable", delegate.isPlayable(), |
+ equalTo(false)); |
+ |
+ // Check that cookies are sent correctly, and that URL updates happen correctly |
+ uri = Uri.parse("http://example.com/test.xxx"); |
+ URL returnedUrl = null; |
+ |
+ returnedUrl = new URL("http://example.com/test.ism"); |
+ |
+ delegate = resolveUri(uri, "Cookies!", returnedUrl, null); |
+ |
+ assertThat("The message contained the user agent name", |
+ mRequestProperties.get(USER_AGENT_HEADER_NAME), equalTo("User agent")); |
+ assertThat("The message contained the user agent name", |
+ mRequestProperties.get(RANGE_HEADER_NAME), equalTo(RANGE_HEADER_VALUE)); |
+ assertThat("The message contained the cookies", |
+ mRequestProperties.get(COOKIES_HEADER_NAME), equalTo("Cookies!")); |
+ |
+ assertThat("The returned Url is correctly updated", delegate.getReturnedUri().toString(), |
+ equalTo("http://example.com/test.ism")); |
+ // This should not be playable since it is returned as a smoothstream URI with no CORS |
+ // header. |
+ assertThat("Whether a video is playable depends on the RETURNED URI", delegate.isPlayable(), |
+ equalTo(false)); |
+ } |
+ |
+ private TestDelegate resolveUri(final Uri uri, final String cookies, URL returnedUrl, |
+ Map<String, List<String>> returnedHeaders) { |
+ mReturnedUrl = returnedUrl; |
+ mReturnedHeaders = returnedHeaders == null ? new HashMap<String, List<String>>() |
+ : returnedHeaders; |
+ mRequestProperties = new HashMap<String, String>(); |
+ |
+ TestDelegate delegate = new TestDelegate(uri, cookies); |
+ |
+ MediaUrlResolver resolver = new MediaUrlResolver(delegate, "User agent"); |
+ resolver.execute(); |
+ |
+ Robolectric.runBackgroundTasks(); |
+ |
+ return delegate; |
+ } |
+ |
+} |