gochan/test/go/doubleselect.js
2021-07-18 14:56:44 +09:00

77 lines
2.1 KiB
JavaScript

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test the situation in which two cases of a select can
// both end up running. See http://codereview.appspot.com/180068.
"use strict";
const Channel = require(`../../lib`);
it(`doubleselect`, async function() {
this.timeout(10 * 1000);
const iterations = 100000; // number of iterations
// sender sends a counter to one of four different channels. If two cases both
// end up running in the same iteration, the same value will be sent to two
// different channels.
const sender = async (n, c1, c2, c3, c4) => {
for (let i = 0; i < n; i++) {
await Channel.select([c1.push(i), c2.push(i), c3.push(i), c4.push(i)]);
}
c1.close();
c2.close();
c3.close();
c4.close();
};
// mux receives the values from sender and forwards them onto another channel.
// It would be simpler to just have sender's four cases all be the same
// channel, but this doesn't actually trigger the bug.
const mux = async (output, input, done) => {
await input.forEach(async value => {
await output.push(value);
});
await done.push(true);
};
// recver gets a steam of values from the four mux's and checks for
// duplicates.
const recver = input => {
const seen = new Map();
input.forEach(v => {
if (seen.has(v)) {
throw new Error(`got duplicate value: ${v}`);
}
seen.set(v, true);
});
};
const c1 = Channel();
const c2 = Channel();
const c3 = Channel();
const c4 = Channel();
const done = Channel();
const cmux = Channel();
sender(iterations, c1, c2, c3, c4);
mux(cmux, c1, done);
mux(cmux, c2, done);
mux(cmux, c3, done);
mux(cmux, c4, done);
// We keep the recver because it might catch more bugs in the future.
// However, the result of the bug linked to at the top is that we'll
// end up panicking with: "throw: bad g->status in ready".
recver(cmux);
await done.shift();
await done.shift();
await done.shift();
await done.shift();
cmux.close();
});