Тестирование горутины, которую мой код не ждет

У меня есть функция, которая выполняется одновременно. Его задача — запустить метод командной строки, зарегистрировав ошибку, если она есть. Мой основной поток выполнения не ждет завершения этого метода. Он просто возвращается оптимистично.

Как мне проверить свою функцию? Предполагая, что я даю ему cmdStr, например {"sleep", "1"}, который работает, но не возвращается мгновенно, как я могу заставить мой тест ждать завершения этой функции?

Я хочу убедиться, что реальная программа, которая запускает это, не должна ждать завершения.

func runCmd(cmdStr []string, errChan chan error) {
  cmd := exec.Command(cmdStr...)
  var out bytes.Buffer
  cmd.Stdout = &out
  err := cmd.Start()
  if err != nil {
    errChan <- err
    return
  }
  // Command started successfully, so our caller can continue.
  errChan <- nil
  err = cmd.Wait()
  if err != nil {
    log.Println(err)
  }
}

person dave mankoff    schedule 22.01.2015    source источник


Ответы (2)


Используйте группу ожидания

wg := sync.WaitGroup{}
errc := make(chan error)
wg.Add(1)
go func() {
    runCmd([]string{"sleep", 1}, errc)
    wg.Done()
}()
err <- errc
if err != nil {
    // handle error
}
wg.Wait()
person jmaloney    schedule 22.01.2015
comment
За исключением того, что я не жду завершения runCmd. По крайней мере, я бы предпочел этого не делать. Вызывающая функция в этом случае предназначена для недолгого существования, она используется просто для запуска потенциально более долгой работы runCmd. - person dave mankoff; 22.01.2015
comment
@davemankoff, тогда вы рискуете, что ваша программа существует без завершения всей работы. Но если вы действительно не хотите ждать, ваша основная программа может игнорировать канал done, а код тестирования может использовать канал done. - person jmaloney; 22.01.2015
comment
Если я проигнорирую готовый канал, не запустится блок Cmd, ожидая, пока он будет прочитан? golang.org/ref/spec#Channel_types. Кажется, я мог бы сделать его буферизованным, но мне неясно точное поведение там, если я никогда не читал его. - person dave mankoff; 22.01.2015
comment
Я обновил свой ответ, чтобы вместо этого использовать группу ожидания. Это будет работать, но ваша основная программа, вероятно, должна остаться, чтобы обрабатывать любые сообщения об ошибках, которые могут возникнуть из ваших команд exec. - person jmaloney; 22.01.2015

Самый простой способ узнать обо всех выполненных маршрутизациях — добавить select{} в качестве последнего оператора main.main(). Но main() никогда не вернется таким образом, и вы должны явно убить процесс. Также runtime.Goshed() мягче ждать других, но это не может дать такой надежной гарантии. И каноническим способом было бы

wg := sync.WaitGroup
...
wg.Add(1)
go runCmd(...)
...
wg.Wait()
person Uvelichitel    schedule 22.01.2015