// 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(); });