如何强制goroutine排序进行测试

时间:2017-03-06 04:17:58

标签: go concurrency

我有一个并发实用程序,它本质上是一个无缓冲的包装器 渠道 - 提供SendReceive功能以及可选的超时时间 context.Context。因此,函数内部的外观为select 大致如此(简化为博览会):

func Send(ctx context.Context, ch chan interface{}, item interface{}) error {
    select {
    case <-ctx.Done():
        return ctx.Err()
    case ch <- item:
        return nil
    }
}

此代码已经过测试并正常运行,但是如果有的话,则存在不良行为 上下文已被取消可以写入通道,发送 将以非确定性成功或失败。这是预期的行为 select,所以我在主select之前添加了一个非阻止发送 预期的行为,如果陈,这第一个select应该总是成功 是可用的。

func Send(ctx context.Context, ch chan interface{}, item interface{}) error {
    select {
    case ch <- item:
        return nil
    default:
    }
    select {
    case <-ctx.Done():
        return ctx.Err()
    case ch <- item:
        return nil
    }
}

合理地确信这是一个正确的实现,但我愿意 喜欢写一个试图运行事件排序的测试用例。 但是,由于处理多重问题所固有的非确定性 goroutines,我无法弄清楚如何正确地对事件进行排序。

以下是我想测试的内容:

func TestReceiveThenSend(t *testing.T) {
    ch := make(chan interface{})
    go Receive(context.Background(), ch)

    // Somehow, wait until the above `Receive` is blocked reading from `ch`.

    // Immediately expired context.
    ctx, cancel := context.WithTimeout(context.Background(), 0)
    defer cancel()

    if err := Send(ctx, ch, "foo"); err != nil {
        t.Fatal("expected Send to succeed because Receive is already called.")
    }
}

显然,由于没有订购,我不能指望上述测试能够正常工作 在go ReceiveSend之间。我尝试过各种各样的黑客攻击 runtime.Goschedtime.Sleep或实施知道的自定义Context 何时使用Done成员。这些都不能强迫我订购 我想。

我被卡住了,我正在寻找任何方式,非常或丑陋,以强制这种行为。 有没有人有解决这个问题的技巧?

0 个答案:

没有答案