| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| (class TracingHelper { |
| constructor(testRunner, session) { |
| this._testRunner = testRunner; |
| this._session = session; |
| } |
| |
| startTracing() { |
| return this.startTracingWithArguments({ "categories": "-*,disabled-by-default-devtools.timeline,devtools.timeline", "type": "", "options": "" }); |
| } |
| |
| startTracingAndSaveAsStream() { |
| var args = { |
| "categories": "-*,disabled-by-default-devtools.timeline,devtools.timeline", |
| "type": "", |
| "options": "", |
| "transferMode": "ReturnAsStream" |
| }; |
| return this.startTracingWithArguments(args); |
| } |
| |
| async startTracingWithArguments(args) { |
| await this._session.protocol.Tracing.start(args); |
| this._testRunner.log("Recording started"); |
| } |
| |
| async stopTracing() { |
| var devtoolsEvents = []; |
| |
| function dataCollected(reply) { |
| var allEvents = reply.params.value; |
| var filteredEvents = allEvents.filter(e => /devtools.timeline/.test(e.cat)); |
| devtoolsEvents = devtoolsEvents.concat(filteredEvents); |
| }; |
| |
| this._session.protocol.Tracing.onDataCollected(dataCollected); |
| this._session.protocol.Tracing.end(); |
| await this._session.protocol.Tracing.onceTracingComplete(); |
| this._testRunner.log("Tracing complete"); |
| this._session.protocol.Tracing.offDataCollected(dataCollected); |
| this._devtoolsEvents = devtoolsEvents; |
| return devtoolsEvents; |
| } |
| |
| async stopTracingAndReturnStream() { |
| function dataCollected() { |
| this._testRunner.log("FAIL: dataCollected event should not be fired when returning trace as stream."); |
| } |
| |
| this._session.protocol.Tracing.onDataCollected(dataCollected); |
| this._session.protocol.Tracing.end(); |
| var event = await this._session.protocol.Tracing.onceTracingComplete(); |
| this._testRunner.log("Tracing complete"); |
| this._session.protocol.Tracing.offDataCollected(dataCollected); |
| return event.params.stream; |
| } |
| |
| retrieveStream(streamHandle, offset, chunkSize) { |
| var callback; |
| var promise = new Promise(f => callback = f); |
| var result = ""; |
| var had_eof = false; |
| |
| var readArguments = { handle: streamHandle }; |
| if (typeof chunkSize === "number") |
| readArguments.size = chunkSize; |
| var firstReadArguments = JSON.parse(JSON.stringify(readArguments)); |
| if (typeof offset === "number") |
| firstReadArguments.offset = offset; |
| this._session.protocol.IO.read(firstReadArguments).then(message => onChunkRead.call(this, message.result)); |
| // Assure multiple in-flight reads are fine (also, save on latencies). |
| this._session.protocol.IO.read(readArguments).then(message => onChunkRead.call(this, message.result)); |
| return promise; |
| |
| function onChunkRead(response) { |
| if (had_eof) |
| return; |
| result += response.data; |
| if (response.eof) { |
| // Ignore stray callbacks from proactive read requests. |
| had_eof = true; |
| if (response.base64Encoded) |
| result = atob(result); |
| callback(result); |
| return; |
| } |
| this._session.protocol.IO.read(readArguments).then(message => onChunkRead.call(this, message.result)); |
| } |
| } |
| |
| findEvents(name, ph, condition) { |
| return this._devtoolsEvents.filter(e => e.name === name && e.ph === ph && (!condition || condition(e))); |
| } |
| |
| findEvent(name, ph, condition) { |
| var events = this.findEvents(name, ph, condition); |
| if (events.length) |
| return events[0]; |
| throw new Error("Couldn't find event " + name + " / " + ph + "\n\n in " + JSON.stringify(this._devtoolsEvents, null, 2)); |
| } |
| |
| filterEvents(callback) { |
| return this._devtoolsEvents.filter(callback); |
| } |
| |
| async invokeAsyncWithTracing(performActions) { |
| await this.startTracing(); |
| var data = await this._session.evaluateAsync(`(${performActions.toString()})()`); |
| await this.stopTracing(); |
| return data; |
| } |
| |
| formattedEvents() { |
| var formattedEvents = this._devtoolsEvents.map(e => e.name + (e.args.data ? '(' + e.args.data.type + ')' : '')); |
| return JSON.stringify(formattedEvents, null, 2); |
| } |
| }) |