gochan/test/go/doubleselect.js
2017-10-06 21:01:34 -04: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()
})