drls2738 2015-07-31 15:39
浏览 49
已采纳

如何告诉我的测试等待goroutine中的回调?

I am using the dockerclient https://github.com/samalba/dockerclient which has a channel-based API to listen for events client.MonitorEvents() and a convenient callback method client.StartMonitorEvents(callbackHandler).

I want to test that the handler gets called. Of course, the dockerclient handles the events in a goroutine.

For now, my handler just spits out a log. If I wait in my test, everything is handled. If I do not, it exits before it handles anything:

func eventCallback(event *dockerclient.Event, ec chan error, args ...interface{}) {
  log.Printf("Received event: %#v
", *event)
}

My test seems straightforward:

func TestReceiveEvent(t *testing.T) {
   createAndMonitorEvents(server.URL)
   <- eventReady
   eventWriter.Write([]byte(someEvent))
   // test for something here
}

Of course, it doesn't work unless I put in a time.Sleep() because of the goroutine.

How do I tell my test, "wait for the other routine to do its work before running the test", other than putting in some arbitrary sleep? I am looking to test that the event is processed correctly by my handler.

The alternate interface, client.MonitorEvents() returns a channel, which gives me greater control, but the receive off the channel spits out infinite nil events.

UPDATE:

As requested, createAndMonitorEvents is:

func createAndMonitorEvents(url string) {
  // Init the client
  docker, _ := dockerclient.NewDockerClient(url, nil)

  // Listen to events
  stopchan := make(chan struct{})

  go func() {
    eventErrChan, err := docker.MonitorEvents(nil, stopchan)
    if err != nil {
        return
    }

    for e := range eventErrChan {
        if e.Error != nil {
            return
        }
        eventCallback(&e.Event, nil)
    }
    fmt.Println("monitor in place")
  }()
}
  • 写回答

3条回答 默认 最新

  • dongpin6941 2015-07-31 16:16
    关注

    I think when you get nils with MonitorEvents, you're just seeing that the event channel is closed (the source of MonitorEvents includes a close(eventOrErrorChan), supporting this). evt, ok := <-c lets you directly check if that (ok will be false when it's closed), and for evt := range c will stop after it's closed. In general, receiving from a closed channel is specified to "[yield] the element type's zero value after any previously sent values have been received"

    On the question about waiting on a callback: the callback can close a channel. (Or send to it.) Then your test can wait up to a specified length of time with a select:

    select {
    case <-c:
            /* ...success... */
    case <-time.After(5 * time.Second):
            /* timed out */
    }
    

    If you know some error conditions cause the handler not to finish, or not to run, it could signal those situations on a different channel, or by sending a different value to c.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了