packer: RemoteCommand.StdoutChan works + tests

This commit is contained in:
Mitchell Hashimoto 2013-06-01 18:21:27 -07:00
parent ace53450b9
commit 810d17c0ef
2 changed files with 69 additions and 1 deletions

View File

@ -1,6 +1,7 @@
package packer package packer
import ( import (
"bufio"
"io" "io"
"log" "log"
"sync" "sync"
@ -39,13 +40,56 @@ type RemoteCommand struct {
exitChans []chan<- int exitChans []chan<- int
exitChanLock sync.Mutex exitChanLock sync.Mutex
outChans []chan<- string
outChanLock sync.Mutex
} }
// StdoutStream returns a channel that will be sent all the output // StdoutStream returns a channel that will be sent all the output
// of stdout as it comes. The output isn't guaranteed to be a full line. // of stdout as it comes. The output isn't guaranteed to be a full line.
// When the channel is closed, the process is exited. // When the channel is closed, the process is exited.
func (r *RemoteCommand) StdoutChan() <-chan string { func (r *RemoteCommand) StdoutChan() <-chan string {
return nil r.outChanLock.Lock()
defer r.outChanLock.Unlock()
// If no output channels have been made yet, then make that slice
// and start the goroutine to read and send to them.
if r.outChans == nil {
r.outChans = make([]chan<- string, 0, 5)
go func() {
buf := bufio.NewReader(r.Stdout)
var err error
for err != io.EOF {
var data []byte
data, err = buf.ReadSlice('\n')
if len(data) > 0 {
for _, ch := range r.outChans {
// Note: this blocks if the channel is full (they
// are buffered by default). What to do?
ch <- string(data)
}
}
}
// Clean up the channels by closing them and setting the
// list to nil.
r.outChanLock.Lock()
defer r.outChanLock.Unlock()
for _, ch := range r.outChans {
close(ch)
}
r.outChans = nil
}()
}
// Create the channel, append it to the channels we care about
outChan := make(chan string, 10)
r.outChans = append(r.outChans, outChan)
return outChan
} }
// ExitChan returns a channel that will be sent the exit status once // ExitChan returns a channel that will be sent the exit status once

View File

@ -1,6 +1,7 @@
package packer package packer
import ( import (
"bytes"
"testing" "testing"
"time" "time"
) )
@ -30,6 +31,29 @@ func TestRemoteCommand_ExitChan(t *testing.T) {
} }
} }
func TestRemoteCommand_StdoutChan(t *testing.T) {
expected := "DATA!!!"
stdoutBuf := new(bytes.Buffer)
stdoutBuf.WriteString(expected)
rc := &RemoteCommand{}
rc.Stdout = stdoutBuf
outChan := rc.StdoutChan()
results := new(bytes.Buffer)
for data := range outChan {
results.WriteString(data)
}
if results.String() != expected {
t.Fatalf(
"outputs didn't match:\ngot:\n%s\nexpected:\n%s",
results.String(), stdoutBuf.String())
}
}
func TestRemoteCommand_WaitBlocks(t *testing.T) { func TestRemoteCommand_WaitBlocks(t *testing.T) {
t.Parallel() t.Parallel()