blob: fb49c568eda20cc7e971d7d67326e1618e6d32cb [file] [log] [blame]
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script type="module">
import {Counter, CounterObserverReceiver, CounterRemote} from '/gen/content/test/data/mojo_bindings_web_test.test-mojom.m.js';
class ObserverImpl {
constructor() {
this.count_ = null;
this.disconnectResolvers_ = [];
}
get count() {
return this.count_;
}
async nextCloneDisconnect() {
return new Promise(r => this.disconnectResolvers_.push(r));
}
onCountChanged(count) {
this.count_ = count;
}
onCloneDisconnected() {
let resolvers = [];
[resolvers, this.disconnectResolvers_] =
[this.disconnectResolvers_, resolvers];
resolvers.forEach(r => r());
}
}
function getCounterRemote() {
const {handle0, handle1} = Mojo.createMessagePipe();
const remote = new CounterRemote(handle1);
Mojo.bindInterface(Counter.$interfaceName, handle0, 'process');
return remote;
}
async function waitForDisconnect(receiver) {
return new Promise(r => receiver.onConnectionError.addListener(r));
}
promise_test(async () => {
const counter = getCounterRemote();
counter.increment();
counter.increment();
const {count} = await counter.increment();
assert_equals(count, 3);
}, 'basic validity check for browser-side support of these tests');
promise_test(async () => {
const counter = getCounterRemote();
const observerA = new ObserverImpl;
const receiverA = new CounterObserverReceiver(observerA);
const observerB = new ObserverImpl;
const receiverB = new CounterObserverReceiver(observerB);
counter.addObserver(receiverA.$.associateAndPassRemote());
counter.addObserver(receiverB.$.associateAndPassRemote());
counter.increment();
const {count} = await counter.increment();
assert_equals(count, 2);
// The observers should always observe changes before the caller of increment
// gets a reply, so the above await should guarantee that the observers' count
// values are up-to-date.
assert_equals(observerA.count, 2);
assert_equals(observerB.count, 2);
}, 'associated remotes can be created and passed');
promise_test(async () => {
const counter = getCounterRemote();
const observerA = new ObserverImpl;
const receiverA = new CounterObserverReceiver(observerA);
const observerB = new ObserverImpl;
const receiverB = new CounterObserverReceiver(observerB);
receiverA.$.bindHandle((await counter.addNewObserver()).receiver.handle);
receiverB.$.bindHandle((await counter.addNewObserver()).receiver.handle);
counter.increment();
const {count} = await counter.increment();
assert_equals(count, 2);
assert_equals(observerA.count, 2);
assert_equals(observerB.count, 2);
}, 'associated receivers can be deserialized and receive messages');
promise_test(async () => {
const counterA = getCounterRemote();
const counterB = new CounterRemote;
const counterC = new CounterRemote;
const counterD = new CounterRemote;
counterA.clone(counterB.$.associateAndPassReceiver());
counterA.clone(counterC.$.associateAndPassReceiver());
counterB.clone(counterD.$.associateAndPassReceiver());
// Increment operations among the three interfaces should be strictly ordered.
const increments = [
counterA.increment(),
counterB.increment(),
counterC.increment(),
counterD.increment(),
counterA.increment(),
counterB.increment(),
counterC.increment(),
counterD.increment(),
];
const replies = await Promise.all(increments);
const results = replies.map(reply => reply.count);
assert_array_equals([1, 2, 3, 4, 5, 6, 7, 8], results);
}, 'associated receivers can be created and passed, and message ordering is preserved among endpoints');
promise_test(async () => {
const counterA = getCounterRemote();
const {remote: counterB} = await counterA.cloneToNewRemote();
const {remote: counterC} = await counterA.cloneToNewRemote();
const {remote: counterD} = await counterC.cloneToNewRemote();
const increments = [
counterA.increment(),
counterB.increment(),
counterC.increment(),
counterD.increment(),
counterA.increment(),
counterB.increment(),
counterC.increment(),
counterD.increment(),
];
const replies = await Promise.all(increments);
const results = replies.map(reply => reply.count);
assert_array_equals([1, 2, 3, 4, 5, 6, 7, 8], results);
}, 'associated remotes can be deserialized and used to send messages, and message ordering is preserved among endpoints');
promise_test(async () => {
const counter = getCounterRemote();
const observer = new ObserverImpl;
const receiver = new CounterObserverReceiver(observer);
counter.addObserver(receiver.$.associateAndPassRemote());
counter.increment();
counter.increment();
counter.increment();
await counter.$.flushForTesting();
assert_equals(observer.count, 3);
}, 'associated endpoints can use flushForTesting');
promise_test(async () => {
const counter = getCounterRemote();
const {remote: clone} = await counter.cloneToNewRemote();
const observer = new ObserverImpl;
const receiver = new CounterObserverReceiver(observer);
counter.addObserver(receiver.$.associateAndPassRemote());
clone.$.close();
observer.nextCloneDisconnect();
}, 'closing an associated endpoint from JavaScript will signal its peer');
promise_test(async () => {
const counter = getCounterRemote();
const observer = new ObserverImpl;
const receiver = new CounterObserverReceiver(observer);
counter.addObserver(receiver.$.associateAndPassRemote());
counter.removeAllObservers();
await waitForDisconnect(receiver);
}, 'JavaScript associated endpoints are notified when their peers close');
</script>