mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #5687 from shykes/pr_out_engine_fix_a_timeout_bug_in_sender_receiver
This commit is contained in:
commit
a7e61a21c0
6 changed files with 137 additions and 13 deletions
|
@ -90,19 +90,21 @@ func (rcv *Receiver) Run() error {
|
||||||
f.Close()
|
f.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
f.Close()
|
||||||
|
defer peer.Close()
|
||||||
cmd := data.Message(p).Get("cmd")
|
cmd := data.Message(p).Get("cmd")
|
||||||
job := rcv.Engine.Job(cmd[0], cmd[1:]...)
|
job := rcv.Engine.Job(cmd[0], cmd[1:]...)
|
||||||
stdout, err := beam.SendPipe(peer, data.Empty().Set("cmd", "log", "stdout").Bytes())
|
stdout, err := beam.SendRPipe(peer, data.Empty().Set("cmd", "log", "stdout").Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
job.Stdout.Add(stdout)
|
job.Stdout.Add(stdout)
|
||||||
stderr, err := beam.SendPipe(peer, data.Empty().Set("cmd", "log", "stderr").Bytes())
|
stderr, err := beam.SendRPipe(peer, data.Empty().Set("cmd", "log", "stderr").Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
job.Stderr.Add(stderr)
|
job.Stderr.Add(stderr)
|
||||||
stdin, err := beam.SendPipe(peer, data.Empty().Set("cmd", "log", "stdin").Bytes())
|
stdin, err := beam.SendWPipe(peer, data.Empty().Set("cmd", "log", "stdin").Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,94 @@
|
||||||
package engine
|
package engine
|
||||||
|
|
||||||
import ()
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"github.com/dotcloud/docker/pkg/beam"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHelloWorld(t *testing.T) {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
testRemote(t,
|
||||||
|
|
||||||
|
// Sender side
|
||||||
|
func(eng *Engine) {
|
||||||
|
job := eng.Job("echo", "hello", "world")
|
||||||
|
out := &bytes.Buffer{}
|
||||||
|
job.Stdout.Add(out)
|
||||||
|
job.Run()
|
||||||
|
if job.status != StatusOK {
|
||||||
|
t.Fatalf("#%v", job.StatusCode())
|
||||||
|
}
|
||||||
|
lines := bufio.NewScanner(out)
|
||||||
|
var i int
|
||||||
|
for lines.Scan() {
|
||||||
|
if lines.Text() != "hello world" {
|
||||||
|
t.Fatalf("%#v", lines.Text())
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i != 1000 {
|
||||||
|
t.Fatalf("%#v", i)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Receiver side
|
||||||
|
func(eng *Engine) {
|
||||||
|
eng.Register("echo", func(job *Job) Status {
|
||||||
|
// Simulate more output with a delay in the middle
|
||||||
|
for i := 0; i < 500; i++ {
|
||||||
|
fmt.Fprintf(job.Stdout, "%s\n", strings.Join(job.Args, " "))
|
||||||
|
}
|
||||||
|
time.Sleep(5 * time.Millisecond)
|
||||||
|
for i := 0; i < 500; i++ {
|
||||||
|
fmt.Fprintf(job.Stdout, "%s\n", strings.Join(job.Args, " "))
|
||||||
|
}
|
||||||
|
return StatusOK
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
func testRemote(t *testing.T, senderSide, receiverSide func(*Engine)) {
|
||||||
|
sndConn, rcvConn, err := beam.USocketPair()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer sndConn.Close()
|
||||||
|
defer rcvConn.Close()
|
||||||
|
sender := NewSender(sndConn)
|
||||||
|
receiver := NewReceiver(rcvConn)
|
||||||
|
|
||||||
|
// Setup the sender side
|
||||||
|
eng := New()
|
||||||
|
sender.Install(eng)
|
||||||
|
|
||||||
|
// Setup the receiver side
|
||||||
|
receiverSide(receiver.Engine)
|
||||||
|
go receiver.Run()
|
||||||
|
|
||||||
|
timeout(t, func() {
|
||||||
|
senderSide(eng)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func timeout(t *testing.T, f func()) {
|
||||||
|
onTimeout := time.After(100 * time.Millisecond)
|
||||||
|
onDone := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
f()
|
||||||
|
close(onDone)
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-onTimeout:
|
||||||
|
t.Fatalf("timeout")
|
||||||
|
case <-onDone:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,17 +29,48 @@ type ReceiveSender interface {
|
||||||
Sender
|
Sender
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendPipe(dst Sender, data []byte) (*os.File, error) {
|
const (
|
||||||
|
R int = 1 << (32 - 1 - iota)
|
||||||
|
W
|
||||||
|
)
|
||||||
|
|
||||||
|
func sendPipe(dst Sender, data []byte, mode int) (*os.File, error) {
|
||||||
r, w, err := os.Pipe()
|
r, w, err := os.Pipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := dst.Send(data, r); err != nil {
|
var (
|
||||||
r.Close()
|
remote *os.File
|
||||||
w.Close()
|
local *os.File
|
||||||
|
)
|
||||||
|
if mode == R {
|
||||||
|
remote = r
|
||||||
|
local = w
|
||||||
|
} else if mode == W {
|
||||||
|
remote = w
|
||||||
|
local = r
|
||||||
|
}
|
||||||
|
if err := dst.Send(data, remote); err != nil {
|
||||||
|
local.Close()
|
||||||
|
remote.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return w, nil
|
return local, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendRPipe create a pipe and sends its *read* end attached in a beam message
|
||||||
|
// to `dst`, with `data` as the message payload.
|
||||||
|
// It returns the *write* end of the pipe, or an error.
|
||||||
|
func SendRPipe(dst Sender, data []byte) (*os.File, error) {
|
||||||
|
return sendPipe(dst, data, R)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendWPipe create a pipe and sends its *read* end attached in a beam message
|
||||||
|
// to `dst`, with `data` as the message payload.
|
||||||
|
// It returns the *write* end of the pipe, or an error.
|
||||||
|
func SendWPipe(dst Sender, data []byte) (*os.File, error) {
|
||||||
|
return sendPipe(dst, data, W)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendConn(dst Sender, data []byte) (conn *UnixConn, err error) {
|
func SendConn(dst Sender, data []byte) (conn *UnixConn, err error) {
|
||||||
|
|
|
@ -257,12 +257,12 @@ func Handlers(sink beam.Sender) (*beam.UnixConn, error) {
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
stdout, err := beam.SendPipe(conn, data.Empty().Set("cmd", "log", "stdout").Set("fromcmd", cmd...).Bytes())
|
stdout, err := beam.SendRPipe(conn, data.Empty().Set("cmd", "log", "stdout").Set("fromcmd", cmd...).Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer stdout.Close()
|
defer stdout.Close()
|
||||||
stderr, err := beam.SendPipe(conn, data.Empty().Set("cmd", "log", "stderr").Set("fromcmd", cmd...).Bytes())
|
stderr, err := beam.SendRPipe(conn, data.Empty().Set("cmd", "log", "stderr").Set("fromcmd", cmd...).Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,7 +272,7 @@ func CmdPrint(args []string, stdout, stderr io.Writer, in beam.Receiver, out bea
|
||||||
}
|
}
|
||||||
// Skip commands
|
// Skip commands
|
||||||
if a != nil && data.Message(payload).Get("cmd") == nil {
|
if a != nil && data.Message(payload).Get("cmd") == nil {
|
||||||
dup, err := beam.SendPipe(out, payload)
|
dup, err := beam.SendRPipe(out, payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.Close()
|
a.Close()
|
||||||
return
|
return
|
||||||
|
|
|
@ -78,7 +78,7 @@ func (route *Route) Tee(dst Sender) *Route {
|
||||||
return inner(payload, attachment)
|
return inner(payload, attachment)
|
||||||
}
|
}
|
||||||
// Setup the tee
|
// Setup the tee
|
||||||
w, err := SendPipe(dst, payload)
|
w, err := SendRPipe(dst, payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue