Bug 1522451 - Add asset support to HttpBin r=geckoview-reviewers,agi
☠☠ backed out by 0ffd90627891 ☠ ☠
authorJames Willcox <snorp@snorp.net>
Mon, 11 Mar 2019 19:15:55 +0000
changeset 521890 6fbcde5da1c1
parent 521889 767ee8714acf
child 521891 d291cd16ef76
push id10870
push usernbeleuzu@mozilla.com
push dateFri, 15 Mar 2019 20:00:07 +0000
treeherdermozilla-beta@c594aee5b7a4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgeckoview-reviewers, agi
bugs1522451
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1522451 - Add asset support to HttpBin r=geckoview-reviewers,agi This lets us request, e.g. '/assets/www/hello.html'. Differential Revision: https://phabricator.services.mozilla.com/D22611
mobile/android/geckoview/src/androidTest/assets/www/manifest.webmanifest
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExecutorTest.kt
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/HttpBin.java
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/HttpBinHandler.java
new file mode 100644
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExecutorTest.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExecutorTest.kt
@@ -3,16 +3,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.geckoview.test
 
 import android.os.Build
 import android.os.Handler
 import android.os.Looper
 import android.os.SystemClock
+import android.support.test.InstrumentationRegistry
 
 import android.support.test.filters.MediumTest
 import android.support.test.filters.SdkSuppress
 import android.support.test.runner.AndroidJUnit4
 
 import java.math.BigInteger
 
 import java.net.URI
@@ -61,17 +62,17 @@ class WebExecutorTest {
     fun setup() {
         // Using @UiThreadTest here does not seem to block
         // the tests which are not using @UiThreadTest, so we do that
         // ourselves here as GeckoRuntime needs to be initialized
         // on the UI thread.
         val latch = CountDownLatch(1)
         Handler(Looper.getMainLooper()).post {
             executor = GeckoWebExecutor(RuntimeCreator.getRuntime())
-            server = HttpBin(URI.create(TEST_ENDPOINT))
+            server = HttpBin(InstrumentationRegistry.getTargetContext(), URI.create(TEST_ENDPOINT))
             server.start()
             latch.countDown()
         }
 
         latch.await()
     }
 
     @After
@@ -90,19 +91,24 @@ class WebExecutorTest {
     fun String.toDirectByteBuffer(): ByteBuffer {
         val chars = CharBuffer.wrap(this)
         val buffer = ByteBuffer.allocateDirect(this.length)
         Charset.forName("UTF-8").newEncoder().encode(chars, buffer, true)
 
         return buffer
     }
 
+    fun WebResponse.getBodyBytes(): ByteBuffer {
+        return ByteBuffer.wrap(body!!.readBytes())
+    }
+
     fun WebResponse.getJSONBody(): JSONObject {
-        val bytes = ByteBuffer.wrap(body!!.readBytes())
-        return JSONObject(Charset.forName("UTF-8").decode(bytes).toString())
+        val bytes = this.getBodyBytes()
+        val bodyString = Charset.forName("UTF-8").decode(bytes).toString()
+        return JSONObject(bodyString)
     }
 
     @Test
     fun smoke() {
         val uri = "$TEST_ENDPOINT/anything"
         val bodyString = "This is the POST data"
         val referrer = "http://foo/bar"
 
@@ -129,16 +135,23 @@ class WebExecutorTest {
         assertThat("Headers should match", body.getJSONObject("headers").getString("Header1"), equalTo("Value"))
         assertThat("Headers should match", body.getJSONObject("headers").getString("Header2"), equalTo("Value1, Value2"))
         assertThat("Headers should match", body.getJSONObject("headers").getString("Content-Type"), equalTo("text/plain"))
         assertThat("Referrer should match", body.getJSONObject("headers").getString("Referer"), equalTo(referrer))
         assertThat("Data should match", body.getString("data"), equalTo(bodyString));
     }
 
     @Test
+    fun testFetchAsset() {
+        val response = fetch(WebRequest("$TEST_ENDPOINT/assets/www/hello.html"))
+        assertThat("Status should match", response.statusCode, equalTo(200))
+        assertThat("Body should have bytes", response.getBodyBytes().remaining(), greaterThan(0))
+    }
+
+    @Test
     fun test404() {
         val response = fetch(WebRequest("$TEST_ENDPOINT/status/404"))
         assertThat("Status code should match", response.statusCode, equalTo(404))
     }
 
     @Test
     fun testRedirect() {
         val response = fetch(WebRequest("$TEST_ENDPOINT/redirect-to?url=/status/200"))
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/HttpBin.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/HttpBin.java
@@ -11,16 +11,17 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package org.mozilla.geckoview.test.util;
 
+import android.content.Context;
 import android.os.StrictMode;
 
 import android.support.annotation.NonNull;
 
 import android.util.Log;
 
 import java.net.URI;
 
@@ -37,18 +38,18 @@ import org.eclipse.jetty.util.thread.Exe
 public final class HttpBin {
     private static final String LOGTAG = "HttpBin";
     private final Server mServer;
 
     static {
         org.eclipse.jetty.util.log.Log.setLog(new AndroidLogger());
     }
 
-    public HttpBin(@NonNull URI endpoint) {
-        this(endpoint, new HttpBinHandler());
+    public HttpBin(@NonNull Context context, @NonNull URI endpoint) {
+        this(endpoint, new HttpBinHandler(context));
     }
 
     public HttpBin(@NonNull URI endpoint, @NonNull HttpBinHandler handler) {
         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(
                 StrictMode.getThreadPolicy())
                 .permitNetwork()
                 .build());
 
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/HttpBinHandler.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/HttpBinHandler.java
@@ -11,16 +11,18 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package org.mozilla.geckoview.test.util;
 
+import android.content.Context;
+import android.content.res.AssetManager;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
 import android.util.Log;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -41,16 +43,24 @@ import org.eclipse.jetty.server.handler.
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 class HttpBinHandler extends AbstractHandler {
     private static final String LOGTAG = "HttpBinHandler";
     private static final int BUFSIZE = 4096;
 
+    private AssetManager mAssets;
+
+    public HttpBinHandler(@NonNull Context context) {
+        super();
+
+        mAssets = context.getResources().getAssets();
+    }
+
     private static void pipe(final @NonNull InputStream is) throws IOException {
         pipe(is, null);
     }
 
     private static void pipe(final @NonNull InputStream is, final @Nullable OutputStream os)
         throws IOException {
         final byte[] buf = new byte[BUFSIZE];
         int count = 0;
@@ -183,25 +193,34 @@ class HttpBinHandler extends AbstractHan
                 final byte[] digest = MessageDigest.getInstance("SHA-256").digest(payload);
                 servletResponse.addHeader("X-SHA-256",
                         String.format("%064x", new BigInteger(1, digest)));
 
                 os.write(payload);
                 os.flush();
 
                 baseRequest.setHandled(true);
+            } else if (uri.startsWith("/assets")) {
+                pipe(is);
+                pipe(mAssets.open(uri.substring("/assets/".length())), os);
+                os.flush();
+                baseRequest.setHandled(true);
             }
 
             if (!baseRequest.isHandled()) {
                 servletResponse.setStatus(501);
                 baseRequest.setHandled(true);
             }
         } catch (JSONException e) {
             Log.e(LOGTAG, "JSON error while handling response", e);
             servletResponse.setStatus(500);
             baseRequest.setHandled(true);
         } catch (NoSuchAlgorithmException e) {
             Log.e(LOGTAG, "Failed to generate digest", e);
             servletResponse.setStatus(500);
             baseRequest.setHandled(true);
+        } catch (IOException e) {
+            Log.e(LOGTAG, "Failed to respond", e);
+            servletResponse.setStatus(500);
+            baseRequest.setHandled(true);
         }
     }
 }