func TestSendRet(t *testing.T) { r, w := beam.Pipe() defer r.Close() defer w.Close() q := NewQueue(w, 1) defer q.Close() ret, err := q.Send(&beam.Message{Verb: beam.Log, Args: []string{"ping"}, Ret: beam.RetPipe}) if err != nil { t.Fatal(err) } go func() { ping, err := r.Receive(beam.Ret) if err != nil { t.Fatal(err) } if _, err := ping.Ret.Send(&beam.Message{Verb: beam.Log, Args: []string{"pong"}}); err != nil { t.Fatal(err) } }() pong, err := ret.Receive(0) if err != nil { t.Fatal(err) } if pong.Verb != beam.Log { t.Fatal(err) } }
func NewQueue(dst beam.Sender, size int) *Queue { r, w := beam.Pipe() q := &Queue{ PipeSender: w, dst: dst, ch: make(chan *beam.Message, size), } go func() { defer close(q.ch) for { msg, err := r.Receive(beam.Ret) if err != nil { r.Close() return } q.ch <- msg } }() go func() { for msg := range q.ch { _, err := dst.Send(msg) if err != nil { r.Close() return } } }() return q }
func TestStackWithPipe(t *testing.T) { r, w := beam.Pipe() defer r.Close() defer w.Close() s := NewStackSender() s.Add(w) testutils.Timeout(t, func() { go func() { msg, err := r.Receive(0) if err != nil { t.Fatal(err) } if msg.Verb != beam.Log { t.Fatalf("%#v", msg) } if strings.Join(msg.Args, " ") != "wonderful world" { t.Fatalf("%#v", msg) } }() _, err := s.Send(&beam.Message{Verb: beam.Log, Args: []string{"wonderful", "world"}}) if err != nil { t.Fatal(err) } }) }
// Misbehaving backends must be removed func TestStackAddBad(t *testing.T) { s := NewStackSender() buf := Buffer{} s.Add(&buf) r, w := beam.Pipe() s.Add(w) if s.Len() != 2 { t.Fatalf("%#v", s) } r.Close() if _, err := s.Send(&beam.Message{Verb: beam.Log, Args: []string{"for the buffer"}}); err != nil { t.Fatal(err) } if s.Len() != 1 { t.Fatalf("%#v") } if len(buf) != 1 { t.Fatalf("%#v", buf) } if buf[0].Args[0] != "for the buffer" { t.Fatalf("%#v", buf) } }
func Exec() beam.Sender { e := beam.NewServer() e.OnSpawn(beam.Handler(func(msg *beam.Message) error { if len(msg.Args) < 1 { return fmt.Errorf("usage: SPAWN exec|... <config>") } if msg.Args[0] != "exec" { return fmt.Errorf("invalid command: %s", msg.Args[0]) } var config struct { Path string Args []string } if err := json.Unmarshal([]byte(msg.Args[1]), &config); err != nil { config.Path = msg.Args[1] config.Args = msg.Args[2:] } cmd := &command{ Cmd: exec.Command(config.Path, config.Args...), Server: beam.NewServer(), } cmd.OnAttach(beam.Handler(func(msg *beam.Message) error { stdout, err := cmd.StdoutPipe() if err != nil { return err } stdin, err := cmd.StdinPipe() if err != nil { return err } inR, inW := beam.Pipe() if _, err := msg.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: inW}); err != nil { return err } out := beam.Obj(msg.Ret) go func() { defer stdin.Close() for { msg, err := inR.Receive(0) if err != nil { return } if msg.Verb == beam.Log && len(msg.Args) > 0 { fmt.Fprintf(stdin, "%s\n", strings.TrimRight(msg.Args[0], "\r\n")) } } }() cmd.tasks.Add(1) go func() { defer cmd.tasks.Done() scanner := bufio.NewScanner(stdout) for scanner.Scan() { if scanner.Err() != io.EOF && scanner.Err() != nil { return } if err := out.Log(scanner.Text()); err != nil { out.Error("%v", err) return } } }() cmd.tasks.Wait() return nil })) cmd.OnStart(beam.Handler(func(msg *beam.Message) error { cmd.tasks.Add(1) if err := cmd.Cmd.Start(); err != nil { return err } go func() { defer cmd.tasks.Done() if err := cmd.Cmd.Wait(); err != nil { beam.Obj(msg.Ret).Log("%s exited status=%v", cmd.Cmd.Path, err) } }() msg.Ret.Send(&beam.Message{Verb: beam.Ack}) return nil })) if _, err := msg.Ret.Send(&beam.Message{Verb: beam.Ack, Ret: cmd}); err != nil { return err } return nil })) return e }