Changeset 166040 in webkit


Ignore:
Timestamp:
Mar 20, 2014 9:45:14 PM (10 years ago)
Author:
BJ Burg
Message:

Web Inspector: add frontend controller and models for replay sessions
https://bugs.webkit.org/show_bug.cgi?id=130145

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

  • inspector/scripts/CodeGeneratorInspector.py: Add the conditional Replay domain.

Source/WebInspectorUI:

Upstream the frontend models and controller for web replay. The replay manager
syncs with the backend controller's replay state and replay sessions by using
the same state machines and transitions.

Session and segment models update their data asynchronously using promises.

  • UserInterface/Base/Main.js:

(WebInspector.loaded): Add the replay manager.

  • UserInterface/Base/Test.js:

(WebInspector.loaded): Add the replay manager.
(InspectorTest.debugLog): Fix a bug in the unescape/escape trick.
(InspectorTest.addResult): Don't try to add results until the test page has loaded.
(InspectorTest.testPageDidLoad): Clear the isReloading flag.
(InspectorTest.reloadPage): Reimplement using promises. Return a promise.

  • UserInterface/Base/Utilities.js: Implement Map.take in the obvious way.
  • UserInterface/Controllers/ReplayManager.js: Added.

(WebInspector.ReplayManager):
(WebInspector):
(WebInspector.ReplayManager.prototype.get sessionState):
(WebInspector.ReplayManager.prototype.get segmentState):
(WebInspector.ReplayManager.prototype.get activeSessionIdentifier):
(WebInspector.ReplayManager.prototype.get activeSegmentIdentifier):
(WebInspector.ReplayManager.prototype.get playbackSpeed):
(WebInspector.ReplayManager.prototype.set playbackSpeed):
(WebInspector.ReplayManager.prototype.get currentPosition):
(WebInspector.ReplayManager.prototype.getSession.get var):
(WebInspector.ReplayManager.prototype.getSegment.get var):
(WebInspector.ReplayManager.prototype.captureStarted):
(WebInspector.ReplayManager.prototype.captureStopped):
(WebInspector.ReplayManager.prototype.playbackStarted):
(WebInspector.ReplayManager.prototype.playbackHitPosition):
(WebInspector.ReplayManager.prototype.playbackPaused):
(WebInspector.ReplayManager.prototype.playbackFinished):
(WebInspector.ReplayManager.prototype.sessionCreated.set catch):
(WebInspector.ReplayManager.prototype.sessionCreated.this):
(WebInspector.ReplayManager.prototype.sessionCreated):
(WebInspector.ReplayManager.prototype.sessionModified):
(WebInspector.ReplayManager.prototype.sessionRemoved.then):
(WebInspector.ReplayManager.prototype.sessionRemoved):
(WebInspector.ReplayManager.prototype.segmentCreated.set this):
(WebInspector.ReplayManager.prototype.segmentCompleted.set catch):
(WebInspector.ReplayManager.prototype.segmentCompleted):
(WebInspector.ReplayManager.prototype.segmentRemoved.then):
(WebInspector.ReplayManager.prototype.segmentRemoved):
(WebInspector.ReplayManager.prototype.segmentLoaded):
(WebInspector.ReplayManager.prototype.segmentUnloaded):
(WebInspector.ReplayManager.prototype.startCapturing):
(WebInspector.ReplayManager.prototype.stopCapturing):
(WebInspector.ReplayManager.prototype.replayToMarkIndex):
(WebInspector.ReplayManager.prototype.replayToCompletion):
(WebInspector.ReplayManager.prototype.pausePlayback):
(WebInspector.ReplayManager.prototype.stopPlayback):
(WebInspector.ReplayManager.prototype._changeSessionState):
(WebInspector.ReplayManager.prototype._changeSegmentState):

  • UserInterface/Main.html:
  • UserInterface/Models/ReplaySession.js: Added.

(WebInspector.ReplaySession):
(WebInspector.ReplaySession.fromPayload):
(WebInspector.ReplaySession.prototype.get segments):
(WebInspector.ReplaySession.prototype.segmentsChanged):
(WebInspector.ReplaySession.prototype._updateFromPayload):

  • UserInterface/Models/ReplaySessionSegment.js: Added.

(WebInspector.IncompleteSessionSegment):
(WebInspector.IncompleteSessionSegment.prototype.get isComplete):
(WebInspector.ReplaySessionSegment):
(WebInspector.ReplaySessionSegment.prototype.get isComplete):

  • UserInterface/Protocol/InspectorBackend.js:

(InspectorBackendClass.prototype.registerCommand):
(InspectorBackendClass.prototype._promise): Add a promise-returning method for
invoking backend commands that return a result asynchronously.

  • UserInterface/Protocol/ReplayObserver.js: Added.

(WebInspector.ReplayPosition):
(WebInspector.ReplayPosition.fromProtocol):
(WebInspector.ReplayObserver):
(WebInspector.ReplayObserver.prototype.captureStarted):
(WebInspector.ReplayObserver.prototype.captureStopped):
(WebInspector.ReplayObserver.prototype.playbackStarted):
(WebInspector.ReplayObserver.prototype.playbackHitPosition):
(WebInspector.ReplayObserver.prototype.playbackPaused):
(WebInspector.ReplayObserver.prototype.playbackFinished):
(WebInspector.ReplayObserver.prototype.inputSuppressionChanged):
(WebInspector.ReplayObserver.prototype.sessionCreated):
(WebInspector.ReplayObserver.prototype.sessionModified):
(WebInspector.ReplayObserver.prototype.sessionRemoved):
(WebInspector.ReplayObserver.prototype.sessionLoaded):
(WebInspector.ReplayObserver.prototype.segmentCreated):
(WebInspector.ReplayObserver.prototype.segmentRemoved):
(WebInspector.ReplayObserver.prototype.segmentCompleted):
(WebInspector.ReplayObserver.prototype.segmentLoaded):
(WebInspector.ReplayObserver.prototype.segmentUnloaded):

  • UserInterface/Test.html:

LayoutTests:

Add tests for existing nondeterministic inputs handled in JSC.
They are skipped for all platforms until WEB_REPLAY is enabled.

The new mechanism here is the single-segment replay reftest. It will
load the test page once to inject test code into the inspector. Then,
the reftest will reload the test page and start capturing. The test
page performs some nondeterministic computation before the load event.
Then, the inspector test dumps the computed nondeterministic state.
Capturing is stopped, and the session is replayed once. When the load
event fires on the replayed page execution, the nondeterministic states
from capturing and replaying are compared. They should be the same.

  • inspector/replay/javascript-random-seed-expected.txt: Added.
  • inspector/replay/javascript-random-seed.html: Added.
  • inspector/replay/replay-test.js: Added. This contains the bulk of

the replay-specific testing logic for the added tests.

(InspectorTestProxy.registerInitializer.):
(InspectorTestProxy.registerInitializer):

Location:
trunk
Files:
10 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r166022 r166040  
     12014-03-20  Brian Burg  <bburg@apple.com>
     2
     3        Web Inspector: add frontend controller and models for replay sessions
     4        https://bugs.webkit.org/show_bug.cgi?id=130145
     5
     6        Reviewed by Joseph Pecoraro.
     7
     8        Add tests for existing nondeterministic inputs handled in JSC.
     9        They are skipped for all platforms until WEB_REPLAY is enabled.
     10
     11        The new mechanism here is the single-segment replay reftest. It will
     12        load the test page once to inject test code into the inspector. Then,
     13        the reftest will reload the test page and start capturing. The test
     14        page performs some nondeterministic computation before the load event.
     15        Then, the inspector test dumps the computed nondeterministic state.
     16        Capturing is stopped, and the session is replayed once. When the load
     17        event fires on the replayed page execution, the nondeterministic states
     18        from capturing and replaying are compared. They should be the same.
     19
     20        * inspector/replay/javascript-random-seed-expected.txt: Added.
     21        * inspector/replay/javascript-random-seed.html: Added.
     22        * inspector/replay/replay-test.js: Added. This contains the bulk of
     23        the replay-specific testing logic for the added tests.
     24
     25        (InspectorTestProxy.registerInitializer.):
     26        (InspectorTestProxy.registerInitializer):
     27
    1282014-03-20  Brent Fulgham  <bfulgham@apple.com>
    229
  • trunk/LayoutTests/inspector/inspector-test.js

    r165545 r166040  
    5656    function runInitializationMethodsInFrontend(initializersArray)
    5757    {
    58         if (InspectorTest.didInjectTestCode) {
    59             // If the test page reloaded but we started running the test in a previous
    60             // navigation, then don't initialize the inspector frontend again.
    61             InspectorTest.testPageDidLoad();
     58        InspectorTest.testPageDidLoad();
     59
     60        // If the test page reloaded but we started running the test in a previous
     61        // navigation, then don't initialize the inspector frontend again.
     62        if (InspectorTest.didInjectTestCode)
    6263            return;
    63         }
    6464
    6565        for (var initializer of initializersArray) {
  • trunk/Source/JavaScriptCore/ChangeLog

    r166030 r166040  
     12014-03-20  Brian Burg  <bburg@apple.com>
     2
     3        Web Inspector: add frontend controller and models for replay sessions
     4        https://bugs.webkit.org/show_bug.cgi?id=130145
     5
     6        Reviewed by Joseph Pecoraro.
     7
     8        * inspector/scripts/CodeGeneratorInspector.py: Add the conditional Replay domain.
     9
    1102014-03-20  Filip Pizlo  <fpizlo@apple.com>
    211
  • trunk/Source/JavaScriptCore/inspector/scripts/CodeGeneratorInspector.py

    r163024 r166040  
    4646    "Database": "SQL_DATABASE",
    4747    "IndexedDB": "INDEXED_DATABASE",
     48    "Replay": "WEB_REPLAY",
    4849}
    4950
  • trunk/Source/WebInspectorUI/ChangeLog

    r165988 r166040  
     12014-03-20  Brian Burg  <bburg@apple.com>
     2
     3        Web Inspector: add frontend controller and models for replay sessions
     4        https://bugs.webkit.org/show_bug.cgi?id=130145
     5
     6        Reviewed by Joseph Pecoraro.
     7
     8        Upstream the frontend models and controller for web replay. The replay manager
     9        syncs with the backend controller's replay state and replay sessions by using
     10        the same state machines and transitions.
     11
     12        Session and segment models update their data asynchronously using promises.
     13
     14        * UserInterface/Base/Main.js:
     15        (WebInspector.loaded): Add the replay manager.
     16        * UserInterface/Base/Test.js:
     17        (WebInspector.loaded): Add the replay manager.
     18        (InspectorTest.debugLog): Fix a bug in the unescape/escape trick.
     19        (InspectorTest.addResult): Don't try to add results until the test page has loaded.
     20        (InspectorTest.testPageDidLoad): Clear the isReloading flag.
     21        (InspectorTest.reloadPage): Reimplement using promises. Return a promise.
     22        * UserInterface/Base/Utilities.js: Implement Map.take in the obvious way.
     23        * UserInterface/Controllers/ReplayManager.js: Added.
     24        (WebInspector.ReplayManager):
     25        (WebInspector):
     26        (WebInspector.ReplayManager.prototype.get sessionState):
     27        (WebInspector.ReplayManager.prototype.get segmentState):
     28        (WebInspector.ReplayManager.prototype.get activeSessionIdentifier):
     29        (WebInspector.ReplayManager.prototype.get activeSegmentIdentifier):
     30        (WebInspector.ReplayManager.prototype.get playbackSpeed):
     31        (WebInspector.ReplayManager.prototype.set playbackSpeed):
     32        (WebInspector.ReplayManager.prototype.get currentPosition):
     33        (WebInspector.ReplayManager.prototype.getSession.get var):
     34        (WebInspector.ReplayManager.prototype.getSegment.get var):
     35        (WebInspector.ReplayManager.prototype.captureStarted):
     36        (WebInspector.ReplayManager.prototype.captureStopped):
     37        (WebInspector.ReplayManager.prototype.playbackStarted):
     38        (WebInspector.ReplayManager.prototype.playbackHitPosition):
     39        (WebInspector.ReplayManager.prototype.playbackPaused):
     40        (WebInspector.ReplayManager.prototype.playbackFinished):
     41        (WebInspector.ReplayManager.prototype.sessionCreated.set catch):
     42        (WebInspector.ReplayManager.prototype.sessionCreated.this):
     43        (WebInspector.ReplayManager.prototype.sessionCreated):
     44        (WebInspector.ReplayManager.prototype.sessionModified):
     45        (WebInspector.ReplayManager.prototype.sessionRemoved.then):
     46        (WebInspector.ReplayManager.prototype.sessionRemoved):
     47        (WebInspector.ReplayManager.prototype.segmentCreated.set this):
     48        (WebInspector.ReplayManager.prototype.segmentCompleted.set catch):
     49        (WebInspector.ReplayManager.prototype.segmentCompleted):
     50        (WebInspector.ReplayManager.prototype.segmentRemoved.then):
     51        (WebInspector.ReplayManager.prototype.segmentRemoved):
     52        (WebInspector.ReplayManager.prototype.segmentLoaded):
     53        (WebInspector.ReplayManager.prototype.segmentUnloaded):
     54        (WebInspector.ReplayManager.prototype.startCapturing):
     55        (WebInspector.ReplayManager.prototype.stopCapturing):
     56        (WebInspector.ReplayManager.prototype.replayToMarkIndex):
     57        (WebInspector.ReplayManager.prototype.replayToCompletion):
     58        (WebInspector.ReplayManager.prototype.pausePlayback):
     59        (WebInspector.ReplayManager.prototype.stopPlayback):
     60        (WebInspector.ReplayManager.prototype._changeSessionState):
     61        (WebInspector.ReplayManager.prototype._changeSegmentState):
     62        * UserInterface/Main.html:
     63        * UserInterface/Models/ReplaySession.js: Added.
     64        (WebInspector.ReplaySession):
     65        (WebInspector.ReplaySession.fromPayload):
     66        (WebInspector.ReplaySession.prototype.get segments):
     67        (WebInspector.ReplaySession.prototype.segmentsChanged):
     68        (WebInspector.ReplaySession.prototype._updateFromPayload):
     69        * UserInterface/Models/ReplaySessionSegment.js: Added.
     70        (WebInspector.IncompleteSessionSegment):
     71        (WebInspector.IncompleteSessionSegment.prototype.get isComplete):
     72        (WebInspector.ReplaySessionSegment):
     73        (WebInspector.ReplaySessionSegment.prototype.get isComplete):
     74        * UserInterface/Protocol/InspectorBackend.js:
     75        (InspectorBackendClass.prototype.registerCommand):
     76        (InspectorBackendClass.prototype._promise): Add a promise-returning method for
     77        invoking backend commands that return a result asynchronously.
     78        * UserInterface/Protocol/ReplayObserver.js: Added.
     79        (WebInspector.ReplayPosition):
     80        (WebInspector.ReplayPosition.fromProtocol):
     81        (WebInspector.ReplayObserver):
     82        (WebInspector.ReplayObserver.prototype.captureStarted):
     83        (WebInspector.ReplayObserver.prototype.captureStopped):
     84        (WebInspector.ReplayObserver.prototype.playbackStarted):
     85        (WebInspector.ReplayObserver.prototype.playbackHitPosition):
     86        (WebInspector.ReplayObserver.prototype.playbackPaused):
     87        (WebInspector.ReplayObserver.prototype.playbackFinished):
     88        (WebInspector.ReplayObserver.prototype.inputSuppressionChanged):
     89        (WebInspector.ReplayObserver.prototype.sessionCreated):
     90        (WebInspector.ReplayObserver.prototype.sessionModified):
     91        (WebInspector.ReplayObserver.prototype.sessionRemoved):
     92        (WebInspector.ReplayObserver.prototype.sessionLoaded):
     93        (WebInspector.ReplayObserver.prototype.segmentCreated):
     94        (WebInspector.ReplayObserver.prototype.segmentRemoved):
     95        (WebInspector.ReplayObserver.prototype.segmentCompleted):
     96        (WebInspector.ReplayObserver.prototype.segmentLoaded):
     97        (WebInspector.ReplayObserver.prototype.segmentUnloaded):
     98        * UserInterface/Test.html:
     99
    11002014-03-20  Joseph Pecoraro  <pecoraro@apple.com>
    2101
  • trunk/Source/WebInspectorUI/UserInterface/Base/Main.js

    r165383 r166040  
    8585    if (InspectorBackend.registerRuntimeDispatcher)
    8686        InspectorBackend.registerRuntimeDispatcher(new WebInspector.RuntimeObserver);
     87    if (InspectorBackend.registerReplayDispatcher)
     88        InspectorBackend.registerReplayDispatcher(new WebInspector.ReplayObserver);
    8789
    8890    // Enable agents.
     
    116118    this.dashboardManager = new WebInspector.DashboardManager;
    117119    this.probeManager = new WebInspector.ProbeManager;
     120    this.replayManager = new WebInspector.ReplayManager;
    118121
    119122    // Enable the Console Agent after creating the singleton managers.
  • trunk/Source/WebInspectorUI/UserInterface/Base/Test.js

    r165501 r166040  
    3636    InspectorBackend.registerCSSDispatcher(new WebInspector.CSSObserver);
    3737    InspectorBackend.registerRuntimeDispatcher(new WebInspector.RuntimeObserver);
     38    if (InspectorBackend.registerReplayDispatcher)
     39        InspectorBackend.registerReplayDispatcher(new WebInspector.ReplayObserver);
    3840
    3941    // Instantiate controllers used by tests.
     
    4547    this.debuggerManager = new WebInspector.DebuggerManager;
    4648    this.probeManager = new WebInspector.ProbeManager;
     49    this.replayManager = new WebInspector.ReplayManager;
    4750
    4851    document.addEventListener("DOMContentLoaded", this.contentLoaded.bind(this));
     
    7073InspectorTest = {};
    7174
     75// This is a workaround for the fact that it would be hard to set up a constructor,
     76// prototype, and prototype chain for the singleton InspectorTest.
     77InspectorTest.EventDispatcher = function()
     78{
     79    WebInspector.Object.call(this);
     80};
     81
     82InspectorTest.EventDispatcher.Event = {
     83    TestPageDidLoad: "inspector-test-test-page-did-load"
     84};
     85
     86InspectorTest.EventDispatcher.prototype = {
     87    __proto__: WebInspector.Object.prototype,
     88    constructor: InspectorTest.EventDispatcher,
     89
     90    dispatchEvent: function(event)
     91    {
     92        this.dispatchEventToListeners(event);
     93    }
     94};
     95
     96InspectorTest.eventDispatcher = new InspectorTest.EventDispatcher;
     97
    7298// Note: Additional InspectorTest methods are included on a per-test basis from
    7399// files like `debugger-test.js`.
     
    101127InspectorTest.debugLog = function(message)
    102128{
    103     this.evaluateInPage("InspectorTestProxy.debugLog(unescape(" + escape(JSON.stringify(message)) + "))");
     129    this.evaluateInPage("InspectorTestProxy.debugLog(unescape('" + escape(JSON.stringify(message)) + "'))");
    104130}
    105131
     
    133159{
    134160    this._results.push(text);
    135     this.evaluateInPage("InspectorTestProxy.addResult(unescape('" + escape(text) + "'))");
     161
     162    if (!this._testPageIsReloading)
     163        this.evaluateInPage("InspectorTestProxy.addResult(unescape('" + escape(text) + "'))");
    136164}
    137165
     
    155183InspectorTest.testPageDidLoad = function()
    156184{
    157     this._shouldResendResults = true;
     185    this._testPageIsReloading = false;
    158186    this._resendResults();
     187
     188    this.eventDispatcher.dispatchEvent(InspectorTest.EventDispatcher.Event.TestPageDidLoad);
    159189}
    160190
    161191InspectorTest.reloadPage = function(shouldIgnoreCache)
    162192{
    163     PageAgent.reload.invoke({ignoreCache: !!shouldIgnoreCache});
     193    return PageAgent.reload.promise(!!shouldIgnoreCache)
     194        .then(function() {
     195            this._shouldResendResults = true;
     196            this._testPageIsReloading = true;
     197
     198            return Promise.resolve(null);
     199        });
    164200}
    165201
  • trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js

    r164604 r166040  
    9191});
    9292
     93Object.defineProperty(Map.prototype, "take",
     94{
     95    value: function(key)
     96    {
     97        var deletedValue = this.get(key);
     98        this.delete(key);
     99        return deletedValue;
     100    }
     101});
     102
    93103Object.defineProperty(Node.prototype, "enclosingNodeOrSelfWithClass",
    94104{
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r165487 r166040  
    191191    <script src="Protocol/PageObserver.js"></script>
    192192    <script src="Protocol/RemoteObject.js"></script>
     193    <script src="Protocol/ReplayObserver.js"></script>
    193194    <script src="Protocol/RuntimeObserver.js"></script>
    194195    <script src="Protocol/TimelineObserver.js"></script>
     
    244245    <script src="Models/ProfileNode.js"></script>
    245246    <script src="Models/ProfileNodeCall.js"></script>
     247    <script src="Models/ReplaySession.js"></script>
     248    <script src="Models/ReplaySessionSegment.js"></script>
    246249    <script src="Models/Resource.js"></script>
    247250    <script src="Models/ResourceCollection.js"></script>
     
    477480    <script src="Controllers/LogManager.js"></script>
    478481    <script src="Controllers/ProbeManager.js"></script>
     482    <script src="Controllers/ReplayManager.js"></script>
    479483    <script src="Controllers/RuntimeManager.js"></script>
    480484    <script src="Controllers/SourceMapManager.js"></script>
  • trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorBackend.js

    r165501 r166040  
    7777        agent[domainAndMethod[1]] = this._sendMessageToBackend.bind(this, method, signature);
    7878        agent[domainAndMethod[1]]["invoke"] = this._invoke.bind(this, method, signature);
     79        agent[domainAndMethod[1]]["promise"] = this._promise.bind(this, method, signature);
    7980        agent[domainAndMethod[1]]["supports"] = this._supports.bind(this, method, signature);
    8081        this._replyArgs[method] = replyArgs;
     
    9798    {
    9899        this._wrapCallbackAndSendMessageObject(method, args, callback);
     100    },
     101
     102    _promise: function(method, signature)
     103    {
     104        var backend = this;
     105        var promiseArguments = Array.prototype.slice.call(arguments);
     106        return new Promise(function(resolve, reject) {
     107            function convertToPromiseCallback(error, payload) {
     108                if (error)
     109                    reject(error);
     110                else
     111                    resolve(payload);
     112            }
     113            promiseArguments.push(convertToPromiseCallback);
     114            backend._sendMessageToBackend.apply(backend, promiseArguments);
     115        });
    99116    },
    100117
  • trunk/Source/WebInspectorUI/UserInterface/Test.html

    r165501 r166040  
    3131    -->
    3232    <script src="Base/WebInspector.js"></script>
     33    <script src="Base/Object.js"></script>
     34
    3335    <script src="Base/Test.js"></script>
    3436
    35     <script src="Base/Object.js"></script>
    3637    <script src="Base/DOMUtilities.js"></script>
    3738    <script src="Base/URLUtilities.js"></script>
     
    5253    <script src="Protocol/PageObserver.js"></script>
    5354    <script src="Protocol/RemoteObject.js"></script>
     55    <script src="Protocol/ReplayObserver.js"></script>
    5456    <script src="Protocol/RuntimeObserver.js"></script>
    5557    <script src="Protocol/TimelineObserver.js"></script>
     
    8385    <script src="Models/ProfileNode.js"></script>
    8486    <script src="Models/ProfileNodeCall.js"></script>
     87    <script src="Models/ReplaySession.js"></script>
     88    <script src="Models/ReplaySessionSegment.js"></script>
    8589    <script src="Models/Resource.js"></script>
    8690    <script src="Models/ResourceCollection.js"></script>
     
    8993    <script src="Models/Script.js"></script>
    9094    <script src="Models/ScriptTimelineRecord.js"></script>
     95    <script src="Models/Setting.js"></script>
    9196    <script src="Models/SourceCodeLocation.js"></script>
    9297    <script src="Models/SourceCodeRevision.js"></script>
     
    102107    <script src="Controllers/FrameResourceManager.js"></script>
    103108    <script src="Controllers/ProbeManager.js"></script>
     109    <script src="Controllers/ReplayManager.js"></script>
    104110    <script src="Controllers/RuntimeManager.js"></script>
    105111    <script src="Controllers/StorageManager.js"></script>
Note: See TracChangeset for help on using the changeset viewer.