packer: RemoteCommand.StdoutChan works + tests
This commit is contained in:
parent
ace53450b9
commit
810d17c0ef
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue