Bug 1532641 - Skip Pausing should persist across reloads and reopens. r=bhackett
authorJason Laster <jlaster@mozilla.com>
Tue, 05 Mar 2019 23:28:25 +0000
changeset 520390 c57bc49cdb13a66e16ca34aec71629d3d316be37
parent 520389 ec0a441cb8f91ba7dd0ccb91abb295c2515d20dd
child 520391 dd4c4ce4a78d10470bd2e3f89a643e7f42fd09d2
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs1532641
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 1532641 - Skip Pausing should persist across reloads and reopens. r=bhackett Differential Revision: https://phabricator.services.mozilla.com/D22091
devtools/client/debugger/new/src/actions/pause/skipPausing.js
devtools/client/debugger/new/src/client/firefox/commands.js
devtools/client/debugger/new/src/client/firefox/types.js
devtools/client/debugger/new/src/reducers/pause.js
devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoint-skipping.js
--- a/devtools/client/debugger/new/src/actions/pause/skipPausing.js
+++ b/devtools/client/debugger/new/src/actions/pause/skipPausing.js
@@ -1,21 +1,20 @@
 /* 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/>. */
 
 // @flow
 
 import type { ThunkArgs } from "../types";
-import { getSkipPausing, getCurrentThread } from "../../selectors";
+import { getSkipPausing } from "../../selectors";
 
 /**
  * @memberof actions/pause
  * @static
  */
 export function toggleSkipPausing() {
   return async ({ dispatch, client, getState, sourceMaps }: ThunkArgs) => {
-    const thread = getCurrentThread(getState());
     const skipPausing = !getSkipPausing(getState());
-    await client.setSkipPausing(thread, skipPausing);
-    dispatch({ type: "TOGGLE_SKIP_PAUSING", thread, skipPausing });
+    await client.setSkipPausing(skipPausing);
+    dispatch({ type: "TOGGLE_SKIP_PAUSING", skipPausing });
   };
 }
--- a/devtools/client/debugger/new/src/client/firefox/commands.js
+++ b/devtools/client/debugger/new/src/client/firefox/commands.js
@@ -90,16 +90,24 @@ function lookupConsoleClient(thread: str
   }
   return workerClients[thread].console;
 }
 
 function listWorkerThreadClients() {
   return (Object.values(workerClients): any).map(({ thread }) => thread);
 }
 
+function forEachWorkerThread(iteratee) {
+  const promises = listWorkerThreadClients().map(thread => iteratee(thread));
+
+  if (shouldWaitForWorkers) {
+    return Promise.all(promises);
+  }
+}
+
 function resume(thread: string): Promise<*> {
   return new Promise(resolve => {
     lookupThreadClient(thread).resume(resolve);
   });
 }
 
 function stepIn(thread: string): Promise<*> {
   return new Promise(resolve => {
@@ -184,42 +192,26 @@ async function setBreakpoint(
   await threadClient.setBreakpoint(location, options);
 
   // Set breakpoints in other threads as well, but do not wait for the requests
   // to complete, so that we don't get hung up if one of the threads stops
   // responding. We don't strictly need to wait for the main thread to finish
   // setting its breakpoint, but this leads to more consistent behavior if the
   // user sets a breakpoint and immediately starts interacting with the page.
   // If the main thread stops responding then we're toast regardless.
-  if (shouldWaitForWorkers) {
-    for (const thread of listWorkerThreadClients()) {
-      await thread.setBreakpoint(location, options);
-    }
-  } else {
-    for (const thread of listWorkerThreadClients()) {
-      thread.setBreakpoint(location, options);
-    }
-  }
+  await forEachWorkerThread(thread => thread.setBreakpoint(location, options));
 }
 
 async function removeBreakpoint(location: BreakpointLocation) {
   delete breakpoints[locationKey(location)];
   await threadClient.removeBreakpoint(location);
 
   // Remove breakpoints without waiting for the thread to respond, for the same
   // reason as in setBreakpoint.
-  if (shouldWaitForWorkers) {
-    for (const thread of listWorkerThreadClients()) {
-      await thread.removeBreakpoint(location);
-    }
-  } else {
-    for (const thread of listWorkerThreadClients()) {
-      thread.removeBreakpoint(location);
-    }
-  }
+  await forEachWorkerThread(thread => thread.removeBreakpoint(location));
 }
 
 async function evaluateInFrame(script: Script, options: EvaluateParam) {
   return evaluate(script, options);
 }
 
 async function evaluateExpressions(scripts: Script[], options: EvaluateParam) {
   return Promise.all(scripts.map(script => evaluate(script, options)));
@@ -315,23 +307,19 @@ async function blackBox(
   const sourceClient = threadClient.source({ actor: sourceActor.actor });
   if (isBlackBoxed) {
     await sourceClient.unblackBox(range);
   } else {
     await sourceClient.blackBox(range);
   }
 }
 
-async function setSkipPausing(thread: string, shouldSkip: boolean) {
-  const client = lookupThreadClient(thread);
-  return client.request({
-    skip: shouldSkip,
-    to: client.actor,
-    type: "skipBreakpoints"
-  });
+async function setSkipPausing(shouldSkip: boolean) {
+  await threadClient.skipBreakpoints(shouldSkip);
+  await forEachWorkerThread(thread => thread.skipBreakpoints(shouldSkip));
 }
 
 function interrupt(thread: string): Promise<*> {
   return lookupThreadClient(thread).interrupt();
 }
 
 function setEventListenerBreakpoints(eventTypes: EventListenerBreakpoints) {
   // TODO: Figure out what sendpoint we want to hit
--- a/devtools/client/debugger/new/src/client/firefox/types.js
+++ b/devtools/client/debugger/new/src/client/firefox/types.js
@@ -353,17 +353,18 @@ export type ThreadClient = {
   addListener: (string, Function) => void,
   getSources: () => Promise<SourcesPacket>,
   reconfigure: ({ observeAsmJS: boolean }) => Promise<*>,
   getLastPausePacket: () => ?PausedPacket,
   _parent: TabClient,
   actor: ActorId,
   request: (payload: Object) => Promise<*>,
   url: string,
-  setEventListenerBreakpoints: (string[]) => void
+  setEventListenerBreakpoints: (string[]) => void,
+  skipBreakpoints: boolean => Promise<{| skip: boolean |}>
 };
 
 export type FirefoxClientConnection = {
   getTabTarget: () => TabTarget,
   getThreadClient: () => ThreadClient,
   setTabTarget: (target: TabTarget) => void,
   setThreadClient: (client: ThreadClient) => void
 };
--- a/devtools/client/debugger/new/src/reducers/pause.js
+++ b/devtools/client/debugger/new/src/reducers/pause.js
@@ -65,31 +65,32 @@ type ThreadPauseState = {
   },
   selectedFrameId: ?string,
   loadedObjects: Object,
   shouldPauseOnExceptions: boolean,
   shouldPauseOnCaughtExceptions: boolean,
   command: Command,
   lastCommand: Command,
   wasStepping: boolean,
-  previousLocation: ?MappedLocation,
-  skipPausing: boolean
+  previousLocation: ?MappedLocation
 };
 
 // Pause state describing all threads.
 export type PauseState = {
   currentThread: string,
   canRewind: boolean,
-  threads: { [string]: ThreadPauseState }
+  threads: { [string]: ThreadPauseState },
+  skipPausing: boolean
 };
 
 export const createPauseState = (): PauseState => ({
   currentThread: "UnknownThread",
   threads: {},
-  canRewind: false
+  canRewind: false,
+  skipPausing: prefs.skipPausing
 });
 
 const resumedPauseState = {
   frames: null,
   frameScopes: {
     generated: {},
     original: {},
     mappings: {}
@@ -102,18 +103,17 @@ const resumedPauseState = {
 const createInitialPauseState = () => ({
   ...resumedPauseState,
   isWaitingOnBreak: false,
   shouldPauseOnExceptions: prefs.pauseOnExceptions,
   shouldPauseOnCaughtExceptions: prefs.pauseOnCaughtExceptions,
   canRewind: false,
   command: null,
   lastCommand: null,
-  previousLocation: null,
-  skipPausing: prefs.skipPausing
+  previousLocation: null
 });
 
 function getThreadPauseState(state: PauseState, thread: string) {
   // Thread state is lazily initialized so that we don't have to keep track of
   // the current set of worker threads.
   return state.threads[thread] || createInitialPauseState();
 }
 
@@ -299,17 +299,17 @@ function update(
           }
         }
       };
 
     case "TOGGLE_SKIP_PAUSING": {
       const { skipPausing } = action;
       prefs.skipPausing = skipPausing;
 
-      return updateThreadState({ skipPausing });
+      return { ...state, skipPausing };
     }
   }
 
   return state;
 }
 
 function getPauseLocation(state, action) {
   const { frames, previousLocation } = state;
@@ -548,17 +548,17 @@ export const getSelectedFrame: Selector<
       return null;
     }
 
     return frames.find(frame => frame.id == selectedFrameId);
   }
 );
 
 export function getSkipPausing(state: OuterState) {
-  return getCurrentPauseState(state).skipPausing;
+  return state.pause.skipPausing;
 }
 
 // NOTE: currently only used for chrome
 export function getChromeScopes(state: OuterState) {
   const frame: ?ChromeFrame = (getSelectedFrame(state): any);
   return frame ? frame.scopeChain : undefined;
 }
 
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoint-skipping.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoint-skipping.js
@@ -1,16 +1,26 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function skipPausing(dbg) {
   clickElementWithSelector(dbg, ".command-bar-skip-pausing");
   return waitForState(dbg, state => dbg.selectors.getSkipPausing(state))
 }
 
+/*
+ * Tests toggling the skip pausing button and 
+ * invoking functions without pausing.
+ */
+
 add_task(async function() {
   let dbg = await initDebugger("doc-scripts.html");
   await addBreakpoint(dbg, "simple3", 2);
 
   await skipPausing(dbg);
-  const res = await invokeInTab("simple")
-  is(res, 3, "simple() successfully completed")
+  let res = await invokeInTab("simple");
+  is(res, 3, "simple() successfully completed");
+
+  info("Reload and invoke again");
+  reload(dbg, "simple3");
+  res = await invokeInTab("simple");
+  is(res, 3, "simple() successfully completed");
 });