Commit 90914b5f authored by Johannes Henkel's avatar Johannes Henkel Committed by Commit Bot

[DevTools] Rework the console-worker.js test for flatten=true.

In my rework, I think there could be some race conditions
in the order of the output. I'll do the dry-run for now
and see whether anything manifests. Perhaps it's worth
doing some sorting of the logs, e.g. we could make the
test insensitive to the order of some of the events in
the golden file, by keeping two or three separate logging
streams for each section.

Bug: 991325
Change-Id: Ib9b8fb0732f5efbf9ad619ff12d5a36bccb02a16
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1762823
Commit-Queue: Johannes Henkel <johannes@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#690125}
parent 39753803
Tests how console messages from worker get into page's console once worker is destroyed. Tests how console messages from worker get into page's console once worker is destroyed.
=== console.log event won't get lost despite worker.terminate. ===
Starting worker Starting worker
Logging in worker: message0 -> Posting to worker: message0 (posted after starting worker)
Got log message from page: message0 <- Log from page: message0 (posted after starting worker)
Stopping worker Terminating worker
=== Scenario with autoattach enabled and stopped. ===
Starting worker Starting worker
Logging in worker: message1 -> Posting to worker: message1
Got log message from page: message1 <- Log from page: message1
Starting autoattach Starting autoattach
Worker.created child session for worker created
Sending Runtime.enable to worker Sending Runtime.enable to worker
Got console API call from worker: message1 -> Posting to worker: message2 (posted after runtime enabled)
Logging in worker: message2 <-- Console API from worker: message1
Got console API call from worker: message2 <-- Console API from worker: message2 (posted after runtime enabled)
Got log message from page: message2 <- Log from page: message2 (posted after runtime enabled)
Logging in worker: throw1 -> Posting to worker: throw1 (posted after runtime enabled; yields exception in worker)
Got log message from page: Uncaught (in promise) throw1
Stopping autoattach Stopping autoattach
Logging in worker: message3 <- Log from page: Uncaught (in promise) throw1 (posted after runtime enabled; yields exception in worker)
Got log message from page: message3 -> Posting to worker: message3 (posted after auto-attach)
Stopping worker <- Log from page: message3 (posted after auto-attach)
Terminating worker
=== Scenario with autoattach from the get-go. ===
Starting autoattach Starting autoattach
Starting worker Starting worker
Worker.created child session for worker created
Logging in worker: message4 -> Posting to worker: message4 (posted before worker's runtime agent enabled)
Sending Runtime.enable to worker Sending Runtime.enable to worker
Got console API call from worker: message4 -> Posting to worker: message5 (posted after worker's runtime agent enabled)
Got log message from page: message4 <- Log from page: message4 (posted before worker's runtime agent enabled)
Logging in worker: message5 <-- Console API from worker: message4 (posted before worker's runtime agent enabled)
Got console API call from worker: message5 <-- Console API from worker: message5 (posted after worker's runtime agent enabled)
Got log message from page: message5 <- Log from page: message5 (posted after worker's runtime agent enabled)
Stopping worker Terminating worker
=== New worker, with auto-attach still enabled. ===
Starting worker Starting worker
Worker.created child session for worker created
Logging in worker: message6 -> Posting to worker: message6 (posted just before worker termination)
Got log message from page: message6 Terminating worker
Stopping worker <- Log from page: message6 (posted just before worker termination)
Stopping autoattach Stopping autoattach
(async function(testRunner) { (async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank(`Tests how console messages from worker get into page's console once worker is destroyed.`); var {page, session, dp} = await testRunner.startBlank(
`Tests how console messages from worker get into page's console once worker is destroyed.`);
await session.evaluate(` await session.evaluate(`
var worker = null; let worker;
var onMessageCallbacks = {};
// This function returns a promise, which, if awaited (e.g. with
// await session.evaluateAsync("startWorker()") ensures that the
// worker has been created. This works by worker-console-worker.js posting
// a message upon which worker.onmessage resolves the promise.
function startWorker() { function startWorker() {
var callback; return new Promise(resolve => {
var promise = new Promise((fulfill) => callback = fulfill); worker = new Worker(
worker = new Worker('${testRunner.url('../resources/worker-console-worker.js')}'); '${testRunner.url('../resources/worker-console-worker.js')}');
worker.onmessage = function(event) { worker.onmessage = () => { resolve(); }
worker.onmessage = onMessageFromWorker; });
callback();
};
return promise;
} }
function logInWorkerFromPage(message, callback) { // Similar to the above method, this method returns a promise such that
onMessageCallbacks[message] = callback; // awaiting it ensures that the worker has posted a message back to the
// page. In this way, we know that worker-console-worker.js gets a chance
// to call console.log.
// We can terminate the worker after awaiting the promise returned by this
// method, and then observe that the console.log events were registered
// anyway. This is much of the point of this test.
function postToWorker(message) {
return new Promise(resolve => {
worker.onmessage = () => { resolve(); };
worker.postMessage(message); worker.postMessage(message);
} });
function onMessageFromWorker(event) {
var callback = onMessageCallbacks[event.data];
delete onMessageCallbacks[event.data];
if (callback)
callback();
}
function stopWorker() {
worker.terminate();
worker = null;
} }
`); `);
var workerEventHandler = {}; await dp.Log.enable();
dp.Target.onAttachedToTarget(onWorkerCreated); dp.Log.onEntryAdded((event) => {
dp.Target.onReceivedMessageFromTarget(onWorkerMessage); testRunner.log('<- Log from page: ' + event.params.entry.text);
workerEventHandler['Runtime.consoleAPICalled'] = onConsoleAPICalledFromWorker;
var workerId;
var workerCreateCallback;
function onWorkerCreated(payload) {
testRunner.log('Worker.created');
workerId = payload.params.targetInfo.targetId;
if (workerCreateCallback) {
var tmp = workerCreateCallback;
workerCreateCallback = null;
tmp();
}
}
function waitForWorkerCreated(next) {
workerCreateCallback = next;
}
var requestId = 0;
var dispatchTable = [];
function sendCommandToWorker(method, params, callback) {
dispatchTable[++requestId] = callback;
var messageObject = {
'method': method,
'params': params,
'id': requestId
};
dp.Target.sendMessageToTarget({
targetId: workerId,
message: JSON.stringify(messageObject)
}); });
}
function onWorkerMessage(payload) {
if (payload.params.targetId !== workerId)
testRunner.log('targetId mismatch');
var messageObject = JSON.parse(payload.params.message);
var messageId = messageObject['id'];
if (typeof messageId === 'number') {
var handler = dispatchTable[messageId];
dispatchTable[messageId] = null;
if (handler && typeof handler === 'function')
handler(messageObject);
} else {
var eventName = messageObject['method'];
var eventHandler = workerEventHandler[eventName];
if (eventHandler)
eventHandler(messageObject);
}
}
var lastPageLog = '';
function logInWorker(message, next) {
lastPageLog = '';
testRunner.log('Logging in worker: ' + message);
dp.Log.onEntryAdded(onLogEntry);
session.evaluate('logInWorkerFromPage(\'' + message + '\')');
function onLogEntry(payload) {
lastPageLog = payload.params.entry.text;
dp.Log.offEntryAdded(onLogEntry);
next();
}
}
var gotMessages = [];
var waitingForMessage;
var waitingForMessageCallback;
function onConsoleAPICalledFromWorker(payload) {
var message = payload.params.args[0].value;
testRunner.log('Got console API call from worker: ' + message);
gotMessages.push(message);
if (message === waitingForMessage)
waitingForMessageCallback();
}
function waitForMessage(message, next) { function postToWorker(message) {
if (gotMessages.indexOf(message) !== -1) { testRunner.log('-> Posting to worker: ' + message);
next(); return session.evaluateAsync('postToWorker("' + message + '")');
return;
}
waitingForMessage = message;
waitingForMessageCallback = next;
} }
var steps = [ {
function listenToConsole(next) { testRunner.log(
dp.Log.enable().then(next); "\n=== console.log event won't get lost despite worker.terminate. ===");
},
function start0(next) {
testRunner.log('Starting worker'); testRunner.log('Starting worker');
session.evaluateAsync('startWorker()').then(next); await session.evaluateAsync('startWorker()');
}, await postToWorker('message0 (posted after starting worker)');
testRunner.log('Terminating worker');
function log0(next) { await session.evaluate('worker.terminate()');
logInWorker('message0', next); // The key part of this test is that its expectation contains
}, // "<- Log from page: message1", even though we terminated the
// worker without awaiting the log event (postToWorker only ensures
function stop0(next) { // that the message was echoed back to the page).
testRunner.log('Got log message from page: ' + lastPageLog); }
testRunner.log('Stopping worker');
session.evaluate('stopWorker()').then(next); {
}, testRunner.log(
'\n=== Scenario with autoattach enabled and stopped. ===');
function start1(next) {
testRunner.log('Starting worker'); testRunner.log('Starting worker');
session.evaluateAsync('startWorker()').then(next); await session.evaluateAsync('startWorker()');
}, await postToWorker('message1');
function log1(next) { // Now we call Target.setAutoAttach, which will immediately generate
logInWorker('message1', next); // an event that we're attached; which we receive below to create the
}, // childSession instance.
function enable1(next) {
testRunner.log('Got log message from page: ' + lastPageLog);
testRunner.log('Starting autoattach'); testRunner.log('Starting autoattach');
dp.Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: false}); dp.Target.setAutoAttach({
waitForWorkerCreated(next); autoAttach: true, waitForDebuggerOnStart: false, flatten: true});
}, const childSession = session.createChild(
(await dp.Target.onceAttachedToTarget()).params.sessionId);
childSession.protocol.Runtime.onConsoleAPICalled((event) => {
testRunner.log('<-- Console API from worker: ' +
event.params.args[0].value);
});
testRunner.log('child session for worker created');
function consoleEnable1(next) {
testRunner.log('Sending Runtime.enable to worker'); testRunner.log('Sending Runtime.enable to worker');
waitForMessage('message1', next); childSession.protocol.Runtime.enable();
sendCommandToWorker('Runtime.enable', {});
},
function log2(next) {
logInWorker('message2', next);
},
function waitForMessage2(next) { await postToWorker('message2 (posted after runtime enabled)');
waitForMessage('message2', next); await postToWorker('throw1 (posted after runtime enabled; ' +
}, 'yields exception in worker)');
function throw1(next) { // This unregisters the child session, so we stop getting the console API
testRunner.log('Got log message from page: ' + lastPageLog); // calls, but still receive the log messages for the page.
logInWorker('throw1', next);
},
function disable1(next) {
testRunner.log('Got log message from page: ' + lastPageLog);
testRunner.log('Stopping autoattach'); testRunner.log('Stopping autoattach');
dp.Target.setAutoAttach({autoAttach: false, waitForDebuggerOnStart: false}).then(next); await dp.Target.setAutoAttach({autoAttach: false,
}, waitForDebuggerOnStart: false});
await postToWorker('message3 (posted after auto-attach)');
function log3(next) { testRunner.log('Terminating worker');
logInWorker('message3', next); await session.evaluate('worker.terminate()');
}, }
function stop1(next) { {
testRunner.log('Got log message from page: ' + lastPageLog); testRunner.log(
testRunner.log('Stopping worker'); '\n=== Scenario with autoattach from the get-go. ===');
session.evaluate('stopWorker()').then(next); // This time we start the worker only after Target.setAutoAttach, so
}, // we may await the autoattach response.
function enable2(next) {
testRunner.log('Starting autoattach'); testRunner.log('Starting autoattach');
dp.Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: false}).then(next); await dp.Target.setAutoAttach({
}, autoAttach: true, waitForDebuggerOnStart: false, flatten: true});
function start2(next) {
testRunner.log('Starting worker'); testRunner.log('Starting worker');
session.evaluateAsync('startWorker()'); session.evaluate('startWorker()');
waitForWorkerCreated(next); const childSession = session.createChild(
}, (await dp.Target.onceAttachedToTarget()).params.sessionId);
childSession.protocol.Runtime.onConsoleAPICalled((event) => {
function log4(next) { testRunner.log('<-- Console API from worker: ' +
logInWorker('message4', next); event.params.args[0].value);
}, });
testRunner.log('child session for worker created');
function consoleEnable2(next) { // Here, we test the behavior of posting before / after Runtime.enable.
await postToWorker(
"message4 (posted before worker's runtime agent enabled)");
testRunner.log('Sending Runtime.enable to worker'); testRunner.log('Sending Runtime.enable to worker');
waitForMessage('message4', next); childSession.protocol.Runtime.enable();
sendCommandToWorker('Runtime.enable', {}); await postToWorker(
}, "message5 (posted after worker's runtime agent enabled)");
testRunner.log('Terminating worker');
function log5(next) { await session.evaluate('worker.terminate()');
testRunner.log('Got log message from page: ' + lastPageLog); }
logInWorker('message5', next);
},
function waitForMessage5(next) {
waitForMessage('message5', next);
},
function stop2(next) {
testRunner.log('Got log message from page: ' + lastPageLog);
testRunner.log('Stopping worker');
session.evaluate('stopWorker()').then(next);
},
function start3(next) { {
testRunner.log(
'\n=== New worker, with auto-attach still enabled. ===');
testRunner.log('Starting worker'); testRunner.log('Starting worker');
session.evaluateAsync('startWorker()'); session.evaluate('startWorker()');
waitForWorkerCreated(next); const childSession = session.createChild(
}, (await dp.Target.onceAttachedToTarget()).params.sessionId);
childSession.protocol.Runtime.onConsoleAPICalled((event) => {
testRunner.log('<-- Console API from worker: ' +
event.params.args[0].value);
});
testRunner.log('child session for worker created');
function log6(next) { await postToWorker('message6 (posted just before worker termination)');
logInWorker('message6', next);
},
function stop3(next) { testRunner.log('Terminating worker');
testRunner.log('Got log message from page: ' + lastPageLog); await session.evaluate('worker.terminate()');
testRunner.log('Stopping worker');
session.evaluate('stopWorker()').then(next);
},
function disable2(next) {
testRunner.log('Stopping autoattach'); testRunner.log('Stopping autoattach');
dp.Target.setAutoAttach({autoAttach: false, waitForDebuggerOnStart: false}).then(next); await dp.Target.setAutoAttach({autoAttach: false,
waitForDebuggerOnStart: false});
} }
];
function runNextStep() {
if (!steps.length) {
testRunner.completeTest(); testRunner.completeTest();
return;
}
var nextStep = steps.shift();
nextStep(runNextStep);
}
runNextStep();
}) })
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment