/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ // Functions that are automatically loaded as frame scripts for // timeline tests. var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; var { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); var { Promise } = Cu.import('resource://gre/modules/Promise.jsm', {}); Cu.import("resource://gre/modules/Timer.jsm"); // Functions that look like mochitest functions but forward to the // browser process. this.ok = function(value, message) { sendAsyncMessage("browser:test:ok", { value: !!value, message: message}); } this.is = function(v1, v2, message) { ok(v1 == v2, message); } this.info = function(message) { sendAsyncMessage("browser:test:info", {message: message}); } this.finish = function() { sendAsyncMessage("browser:test:finish"); } /* Start a task that runs some timeline tests in the ordinary way. * * @param array tests * The tests to run. This is an array where each element * is of the form { desc, searchFor, setup, check }. * * desc is the test description, a string. * searchFor is a string or a function * If a string, then when a marker with this name is * found, marker-reading is stopped. * If a function, then the accumulated marker array is * passed to it, and marker reading stops when it returns * true. * setup is a function that takes the docshell as an argument. * It should start the test. * check is a function that takes an array of markers * as an argument and checks the results of the test. */ this.timelineContentTest = function(tests) { Task.spawn(function*() { let docShell = content.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); info("Start recording"); docShell.recordProfileTimelineMarkers = true; for (let {desc, searchFor, setup, check} of tests) { info("Running test: " + desc); info("Flushing the previous markers if any"); docShell.popProfileTimelineMarkers(); info("Running the test setup function"); let onMarkers = timelineWaitForMarkers(docShell, searchFor); setup(docShell); info("Waiting for new markers on the docShell"); let markers = yield onMarkers; // Cycle collection markers are non-deterministic, and none of these tests // expect them to show up. markers = markers.filter(m => m.name.indexOf("nsCycleCollector") === -1); info("Running the test check function"); check(markers); } info("Stop recording"); docShell.recordProfileTimelineMarkers = false; finish(); }); } function timelineWaitForMarkers(docshell, searchFor) { if (typeof(searchFor) == "string") { let searchForString = searchFor; let f = function (markers) { return markers.some(m => m.name == searchForString); }; searchFor = f; } return new Promise(function(resolve, reject) { let waitIterationCount = 0; let maxWaitIterationCount = 10; // Wait for 2sec maximum let markers = []; setTimeout(function timeoutHandler() { let newMarkers = docshell.popProfileTimelineMarkers(); markers = [...markers, ...newMarkers]; if (searchFor(markers) || waitIterationCount > maxWaitIterationCount) { resolve(markers); } else { setTimeout(timeoutHandler, 200); waitIterationCount++; } }, 200); }); }