abacd4c115
This adds support for injecting binding into contexts other than main based on the context name (AKA isolated world name in Blink terms). This would simplify a common use case for addBinding in Puppeteer and other automation tools that use addBinding to expose a back-channel for extension code running in an isolated world by making bindings available to such code at an early stage and in a race-free manner (currently, we can only inject a binding into specific context after the creation of the context has been reported to the client, which typically introduces a race with other evals the client may be running in the context). Change-Id: I66454954491a47a0c9aa4864f0aace4da2e67d3a Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2440984 Reviewed-by: Simon Zünd <szuend@chromium.org> Reviewed-by: Pavel Feldman <pfeldman@chromium.org> Commit-Queue: Andrey Kosyakov <caseq@chromium.org> Cr-Commit-Position: refs/heads/master@{#70266}
151 lines
6.7 KiB
JavaScript
151 lines
6.7 KiB
JavaScript
// Copyright 2018 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
InspectorTest.log('Test for Runtime.addBinding.');
|
|
|
|
InspectorTest.runAsyncTestSuite([
|
|
async function testBasic() {
|
|
const {contextGroup, sessions: [session1, session2]} = setupSessions(2);
|
|
|
|
InspectorTest.log('\nAdd binding inside session1..');
|
|
session1.Protocol.Runtime.addBinding({name: 'send'});
|
|
InspectorTest.log('Call binding..');
|
|
await session1.Protocol.Runtime.evaluate({expression: `send('payload')`});
|
|
|
|
InspectorTest.log('\nAdd binding inside session2..');
|
|
session2.Protocol.Runtime.addBinding({name: 'send'});
|
|
InspectorTest.log('Call binding..');
|
|
await session2.Protocol.Runtime.evaluate({expression: `send('payload')`});
|
|
|
|
InspectorTest.log('\nDisable agent inside session1..');
|
|
session1.Protocol.Runtime.disable();
|
|
InspectorTest.log('Call binding..');
|
|
await session2.Protocol.Runtime.evaluate({expression: `send('payload')`});
|
|
|
|
InspectorTest.log('\nDisable agent inside session2..');
|
|
session2.Protocol.Runtime.disable();
|
|
InspectorTest.log('Call binding..');
|
|
await session2.Protocol.Runtime.evaluate({expression: `send('payload')`});
|
|
|
|
InspectorTest.log('\nEnable agent inside session1..');
|
|
session1.Protocol.Runtime.enable();
|
|
InspectorTest.log('Call binding..');
|
|
await session2.Protocol.Runtime.evaluate({expression: `send('payload')`});
|
|
},
|
|
|
|
async function testReconnect() {
|
|
const {contextGroup, sessions: [session]} = setupSessions(1);
|
|
InspectorTest.log('\nAdd binding inside session..');
|
|
await session.Protocol.Runtime.addBinding({name: 'send'});
|
|
InspectorTest.log('Reconnect..');
|
|
session.reconnect();
|
|
await session.Protocol.Runtime.evaluate({expression: `send('payload')`});
|
|
},
|
|
|
|
async function testBindingOverrides() {
|
|
const {contextGroup, sessions: [session]} = setupSessions(1);
|
|
InspectorTest.log('\nAdd send function on global object..');
|
|
session.Protocol.Runtime.evaluate({expression: 'send = () => 42'});
|
|
InspectorTest.log('Add binding inside session..');
|
|
session.Protocol.Runtime.addBinding({name: 'send'});
|
|
InspectorTest.log('Call binding..');
|
|
await session.Protocol.Runtime.evaluate({expression: `send('payload')`});
|
|
},
|
|
|
|
async function testRemoveBinding() {
|
|
const {contextGroup, sessions: [session]} = setupSessions(1);
|
|
InspectorTest.log('\nAdd binding inside session..');
|
|
session.Protocol.Runtime.addBinding({name: 'send'});
|
|
InspectorTest.log('Call binding..');
|
|
await session.Protocol.Runtime.evaluate({expression: `send('payload')`});
|
|
InspectorTest.log('Remove binding inside session..');
|
|
session.Protocol.Runtime.removeBinding({name: 'send'});
|
|
InspectorTest.log('Call binding..');
|
|
await session.Protocol.Runtime.evaluate({expression: `send('payload')`});
|
|
},
|
|
|
|
async function testAddBindingToContextById() {
|
|
const {contextGroup, sessions: [session]} = setupSessions(1);
|
|
const contextId1 = (await session.Protocol.Runtime.onceExecutionContextCreated()).params.context.id;
|
|
|
|
contextGroup.createContext();
|
|
const contextId2 = (await session.Protocol.Runtime.onceExecutionContextCreated()).params.context.id;
|
|
|
|
await session.Protocol.Runtime.addBinding({name: 'frobnicate', executionContextId: contextId2});
|
|
const expression = `frobnicate('message')`;
|
|
|
|
InspectorTest.log('Call binding in default context (binding should NOT be exposed)');
|
|
await session.Protocol.Runtime.evaluate({expression});
|
|
|
|
InspectorTest.log('Call binding in target context (binding should be exposed)');
|
|
await session.Protocol.Runtime.evaluate({expression, contextId: contextId2});
|
|
|
|
InspectorTest.log('Call binding in newly created context (binding should NOT be exposed)');
|
|
contextGroup.createContext();
|
|
const contextId3 = (await session.Protocol.Runtime.onceExecutionContextCreated()).params.context.id;
|
|
await session.Protocol.Runtime.evaluate({expression, contextId: contextId3});
|
|
},
|
|
|
|
async function testAddBindingToContextByName() {
|
|
const {contextGroup, sessions: [session]} = setupSessions(1);
|
|
const defaultContext = (await session.Protocol.Runtime.onceExecutionContextCreated()).params.context.id;
|
|
|
|
contextGroup.createContext("foo");
|
|
const contextFoo = (await session.Protocol.Runtime.onceExecutionContextCreated()).params.context.id;
|
|
|
|
contextGroup.createContext("bar");
|
|
const contextBar = (await session.Protocol.Runtime.onceExecutionContextCreated()).params.context.id;
|
|
|
|
await session.Protocol.Runtime.addBinding({name: 'frobnicate', executionContextName: 'foo'});
|
|
const expression = `frobnicate('message')`;
|
|
|
|
InspectorTest.log('Call binding in default context (binding should NOT be exposed)');
|
|
await session.Protocol.Runtime.evaluate({expression});
|
|
|
|
InspectorTest.log('Call binding in Foo (binding should be exposed)');
|
|
await session.Protocol.Runtime.evaluate({expression, contextId: contextFoo});
|
|
|
|
InspectorTest.log('Call binding in Bar (binding should NOT be exposed)');
|
|
await session.Protocol.Runtime.evaluate({expression, contextId: contextBar});
|
|
|
|
contextGroup.createContext("foo");
|
|
const contextFoo2 = (await session.Protocol.Runtime.onceExecutionContextCreated()).params.context.id;
|
|
|
|
InspectorTest.log('Call binding in newly-created Foo (binding should be exposed)');
|
|
await session.Protocol.Runtime.evaluate({expression, contextId: contextFoo2});
|
|
|
|
contextGroup.createContext("bazz");
|
|
const contextBazz = (await session.Protocol.Runtime.onceExecutionContextCreated()).params.context.id;
|
|
|
|
InspectorTest.log('Call binding in newly-created Bazz (binding should NOT be exposed)');
|
|
await session.Protocol.Runtime.evaluate({expression, contextId: contextBazz});
|
|
},
|
|
|
|
async function testErrors() {
|
|
const {contextGroup, sessions: [session]} = setupSessions(1);
|
|
let err = await session.Protocol.Runtime.addBinding({name: 'frobnicate', executionContextName: ''});
|
|
InspectorTest.logMessage(err);
|
|
err = await session.Protocol.Runtime.addBinding({name: 'frobnicate', executionContextName: 'foo', executionContextId: 1});
|
|
InspectorTest.logMessage(err);
|
|
err = await session.Protocol.Runtime.addBinding({name: 'frobnicate', executionContextId: 2128506});
|
|
InspectorTest.logMessage(err);
|
|
}
|
|
|
|
]);
|
|
|
|
function setupSessions(num) {
|
|
const contextGroup = new InspectorTest.ContextGroup();
|
|
const sessions = [];
|
|
for (let i = 0; i < num; ++i) {
|
|
const session = contextGroup.connect();
|
|
sessions.push(session);
|
|
session.Protocol.Runtime.enable();
|
|
session.Protocol.Runtime.onBindingCalled(msg => {
|
|
InspectorTest.log(`binding called in session${i + 1}`);
|
|
InspectorTest.logMessage(msg);
|
|
});
|
|
}
|
|
return {contextGroup, sessions};
|
|
}
|