Bug 1459301 - 1. Wait on sessions opened through onNewSession response; r?snorp draft
authorJim Chen <nchen@mozilla.com>
Fri, 11 May 2018 14:59:49 -0400
changeset 794345 628e26129539ce07e55a437dbb41736ef3763d05
parent 794344 64e1ba4d4895b0771a12d9094ce7e8a3b9e12ce6
child 794346 1147bfdba62ecd991c99c07e5ba78edd13a0c9a3
push id109648
push userbmo:nchen@mozilla.com
push dateFri, 11 May 2018 19:00:34 +0000
reviewerssnorp
bugs1459301
milestone62.0a1
Bug 1459301 - 1. Wait on sessions opened through onNewSession response; r?snorp The session returned through the onNewSession response is opened internally by GV. GeckoSessionTestRule should trap that and wait on the newly opened session, just like we do for any other session, so that this internal open operation is transparent to the test. MozReview-Commit-ID: HOvEsSVZufS
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.geckoview.test.rule;
 
 import org.mozilla.gecko.gfx.GeckoDisplay;
 import org.mozilla.geckoview.BuildConfig;
+import org.mozilla.geckoview.GeckoResponse;
 import org.mozilla.geckoview.GeckoRuntime;
 import org.mozilla.geckoview.GeckoRuntimeSettings;
 import org.mozilla.geckoview.GeckoSession;
 import org.mozilla.geckoview.GeckoSessionSettings;
 import org.mozilla.geckoview.test.rdp.Actor;
 import org.mozilla.geckoview.test.rdp.RDPConnection;
 import org.mozilla.geckoview.test.rdp.Tab;
 import org.mozilla.geckoview.test.util.Callbacks;
@@ -86,25 +87,25 @@ public class GeckoSessionTestRule extend
     private static final long DEFAULT_ARM_DEVICE_TIMEOUT_MILLIS = 30000;
     private static final long DEFAULT_ARM_EMULATOR_TIMEOUT_MILLIS = 120000;
     private static final long DEFAULT_X86_DEVICE_TIMEOUT_MILLIS = 30000;
     private static final long DEFAULT_X86_EMULATOR_TIMEOUT_MILLIS = 5000;
     private static final long DEFAULT_IDE_DEBUG_TIMEOUT_MILLIS = 86400000;
 
     public static final String APK_URI_PREFIX = "resource://android/";
 
-    private static final Method sOnLocationChange;
     private static final Method sOnPageStop;
+    private static final Method sOnNewSession;
 
     static {
         try {
-            sOnLocationChange = GeckoSession.NavigationDelegate.class.getMethod(
-                    "onLocationChange", GeckoSession.class, String.class);
             sOnPageStop = GeckoSession.ProgressDelegate.class.getMethod(
                     "onPageStop", GeckoSession.class, boolean.class);
+            sOnNewSession = GeckoSession.NavigationDelegate.class.getMethod(
+                    "onNewSession", GeckoSession.class, String.class, GeckoResponse.class);
         } catch (final NoSuchMethodException e) {
             throw new RuntimeException(e);
         }
     }
 
     /**
      * Specify the timeout for any of the wait methods, in milliseconds, relative to
      * {@link #DEFAULT_TIMEOUT_MILLIS}. When the default timeout scales to account
@@ -901,16 +902,35 @@ public class GeckoSessionTestRule extend
                     records.add(new CallRecord(session, method, args));
 
                     call = waitDelegates.prepareMethodCall(session, method);
                     if (call == null) {
                         call = testDelegates.prepareMethodCall(session, method);
                     }
                 }
 
+                if (call != null && sOnNewSession.equals(method)) {
+                    // We're delegating an onNewSession call.
+                    // Make sure we wait on the newly opened session, if any.
+                    final GeckoSession oldSession = (GeckoSession) args[0];
+                    @SuppressWarnings("unchecked")
+                    final GeckoResponse<GeckoSession> realResponse =
+                            (GeckoResponse<GeckoSession>) args[2];
+                    args[2] = new GeckoResponse<GeckoSession>() {
+                        @Override
+                        public void respond(final GeckoSession newSession) {
+                            realResponse.respond(newSession);
+                            // `realResponse` has opened the session at this point, so wait on it.
+                            if (oldSession.isOpen() && newSession != null) {
+                                GeckoSessionTestRule.this.waitForOpenSession(newSession);
+                            }
+                        }
+                    };
+                }
+
                 try {
                     mCurrentMethodCall = call;
                     return method.invoke((call != null) ? call.target
                                                         : Callbacks.Default.INSTANCE, args);
                 } catch (final IllegalAccessException | InvocationTargetException e) {
                     throw unwrapRuntimeException(e);
                 } finally {
                     mCurrentMethodCall = null;
@@ -960,16 +980,20 @@ public class GeckoSessionTestRule extend
     /**
      * Call open() on a session, and ensure it's ready for use by the test. In particular,
      * remove any extra calls recorded as part of opening the session.
      *
      * @param session Session to open.
      */
     public void openSession(final GeckoSession session) {
         session.open(sRuntime);
+        waitForOpenSession(session);
+    }
+
+    /* package */ void waitForOpenSession(final GeckoSession session) {
         waitForInitialLoad(session);
 
         if (mWithDevTools) {
             if (sRDPConnection == null) {
                 final String dataDir = InstrumentationRegistry.getTargetContext()
                                                               .getApplicationInfo().dataDir;
                 final LocalSocketAddress address = new LocalSocketAddress(
                         dataDir + "/firefox-debugger-socket",
@@ -979,47 +1003,33 @@ public class GeckoSessionTestRule extend
             }
             final Tab tab = sRDPConnection.getMostRecentTab();
             tab.attach();
             mRDPTabs.put(session, tab);
         }
     }
 
     private void waitForInitialLoad(final GeckoSession session) {
-        // We receive an initial about:blank load; don't expose that to the test.
-        // The about:blank load is bounded by onLocationChange and onPageStop calls,
-        // so find the first about:blank onLocationChange, then the next onPageStop,
-        // and ignore everything in-between from that session.
+        // We receive an initial about:blank load; don't expose that to the test. The initial
+        // load ends with the first onPageStop call, so ignore everything from the session
+        // until the first onPageStop call.
 
         try {
             // We cannot detect initial page load without progress delegate.
             assertThat("ProgressDelegate cannot be null-delegate when opening session",
                        GeckoSession.ProgressDelegate.class, not(isIn(mNullDelegates)));
 
-            // If navigation delegate is a null-delegate, instead of looking for
-            // onLocationChange(), start with the first call that targets this session.
-            final boolean nullNavigation = mNullDelegates.contains(
-                    GeckoSession.NavigationDelegate.class);
-
             mCallRecordHandler = new CallRecordHandler() {
-                private boolean mFoundStart = false;
-
                 @Override
                 public boolean handleCall(final Method method, final Object[] args) {
-                    if (!mFoundStart && session.equals(args[0]) && (nullNavigation ||
-                            (sOnLocationChange.equals(method) && "about:blank".equals(args[1])))) {
-                        mFoundStart = true;
-                        return true;
-                    } else if (mFoundStart && session.equals(args[0])) {
-                        if (sOnPageStop.equals(method)) {
-                            mCallRecordHandler = null;
-                        }
-                        return true;
+                    final boolean matching = session.equals(args[0]);
+                    if (matching && sOnPageStop.equals(method)) {
+                        mCallRecordHandler = null;
                     }
-                    return false;
+                    return matching;
                 }
             };
 
             do {
                 loopUntilIdle(getDefaultTimeoutMillis());
             } while (mCallRecordHandler != null);
 
         } finally {