Skip to content

Commit

Permalink
Include running a client command in the functional test
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-stripe committed Jun 30, 2016
1 parent 11a6365 commit e9dfba6
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -11,6 +11,6 @@ install:
- make dev_bootstrap
- make rubygem/lib/zeus/version.rb
script:
- make test-go
- RAILS_ENV="" make test-go
- make build-linux
- make rubygem/lib/zeus/version.rb && cd rubygem && bundle install --without development && bin/rspec spec
2 changes: 1 addition & 1 deletion go/cmd/zeus/zeus.go
Expand Up @@ -86,7 +86,7 @@ func main() {
if args[0] == name {
// Don't confuse the master by sending *full* args to
// it; just those that are not zeus-specific.
os.Exit(zeusclient.Run(args))
os.Exit(zeusclient.Run(args, os.Stdin, os.Stdout))
}
}

Expand Down
24 changes: 14 additions & 10 deletions go/zeusclient/zeusclient.go
@@ -1,6 +1,7 @@
package zeusclient

import (
"io"
"net"
"os"
"os/signal"
Expand All @@ -25,15 +26,15 @@ const (
// man signal | grep 'terminate process' | awk '{print $2}' | xargs -I '{}' echo -n "syscall.{}, "
var terminatingSignals = []os.Signal{syscall.SIGHUP, syscall.SIGINT, syscall.SIGKILL, syscall.SIGPIPE, syscall.SIGALRM, syscall.SIGTERM, syscall.SIGXCPU, syscall.SIGXFSZ, syscall.SIGVTALRM, syscall.SIGPROF, syscall.SIGUSR1, syscall.SIGUSR2}

func Run(args []string) int {
func Run(args []string, input io.Reader, output *os.File) int {
if os.Getenv("RAILS_ENV") != "" {
println("Warning: Specifying a Rails environment via RAILS_ENV has no effect for commands run with zeus.")
println("As a safety precaution to protect you from nuking your development database,")
println("Zeus will now cowardly refuse to proceed. Please unset RAILS_ENV and try again.")
return 1
}

isTerminal := ttyutils.IsTerminal(os.Stdout.Fd())
isTerminal := ttyutils.IsTerminal(output.Fd())

var master, slave *os.File
var err error
Expand All @@ -50,16 +51,16 @@ func Run(args []string) int {
defer master.Close()
var oldState *ttyutils.Termios
if isTerminal {
oldState, err = ttyutils.MakeTerminalRaw(os.Stdout.Fd())
oldState, err = ttyutils.MakeTerminalRaw(output.Fd())
if err != nil {
slog.ErrorString(err.Error() + "\r")
return 1
}
defer ttyutils.RestoreTerminalState(os.Stdout.Fd(), oldState)
defer ttyutils.RestoreTerminalState(output.Fd(), oldState)
}

// should this happen if we're running over a pipe? I think maybe not?
ttyutils.MirrorWinsize(os.Stdout, master)
ttyutils.MirrorWinsize(output, master)

addr, err := net.ResolveUnixAddr("unixgram", unixsocket.ZeusSockName())
if err != nil {
Expand Down Expand Up @@ -114,10 +115,10 @@ func Run(args []string) int {
if sig == syscall.SIGCONT {
syscall.Kill(commandPid, syscall.SIGCONT)
} else if sig == syscall.SIGWINCH {
ttyutils.MirrorWinsize(os.Stdout, master)
ttyutils.MirrorWinsize(output, master)
syscall.Kill(commandPid, syscall.SIGWINCH)
} else { // member of terminatingSignals
ttyutils.RestoreTerminalState(os.Stdout.Fd(), oldState)
ttyutils.RestoreTerminalState(output.Fd(), oldState)
print("\r")
syscall.Kill(commandPid, sig.(syscall.Signal))
os.Exit(1)
Expand All @@ -140,18 +141,21 @@ func Run(args []string) int {
for {
buf := make([]byte, 1024)
n, err := master.Read(buf)
if err != nil {

if err == nil || (err == io.EOF && n > 0) {
output.Write(buf[:n])
} else {
eof <- true
break
}
os.Stdout.Write(buf[:n])

}
}()

go func() {
buf := make([]byte, 8192)
for {
n, err := os.Stdin.Read(buf)
n, err := input.Read(buf)
if err != nil {
eof <- true
break
Expand Down
46 changes: 41 additions & 5 deletions go/zeusmaster/zeusmaster_test.go
Expand Up @@ -3,6 +3,7 @@ package zeusmaster_test
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net"
"os"
Expand All @@ -14,6 +15,7 @@ import (
"github.com/burke/zeus/go/filemonitor"
slog "github.com/burke/zeus/go/shinylog"
"github.com/burke/zeus/go/unixsocket"
"github.com/burke/zeus/go/zeusclient"
"github.com/burke/zeus/go/zeusmaster"
)

Expand All @@ -29,7 +31,7 @@ var testFiles = map[string]string{
"code": {
"code_srv": {}
},
"cmd_srv": []
"cmd": []
}
}
}
Expand All @@ -41,7 +43,6 @@ require 'zeus'
class CustomPlan < Zeus::Plan
def self.command(name, &block)
define_method(name) do
redirect_log(name)
begin
self.instance_eval(&block)
rescue => e
Expand All @@ -66,9 +67,8 @@ class CustomPlan < Zeus::Plan
require_relative 'code'
end
command :cmd_srv do
redirect_log('cmd_srv')
serve('cmd.sock')
command :cmd do
puts "bijagua"
end
command :data_srv do
Expand Down Expand Up @@ -185,6 +185,7 @@ func TestZeusBoots(t *testing.T) {
if err != nil {
t.Fatal(err)
}
defer me.Signal(os.Interrupt)

if err := os.Chdir(dir); err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -233,6 +234,32 @@ func TestZeusBoots(t *testing.T) {
}
}

readCloser := make(chan struct{})
defer func() { close(readCloser) }()

cmdReader, cmdWriter, err := os.Pipe()
if err != nil {
t.Fatal(err)
}

cexit := make(chan int, 1)
go func() {
cexit <- zeusclient.Run([]string{"cmd"}, hangingReader{readCloser}, cmdWriter)
time.Sleep(100 * time.Millisecond)
cmdWriter.Close()
}()

have, err := ioutil.ReadAll(cmdReader)
if err != nil {
t.Fatal(err)
}
if want := "bijagua\n"; string(have) != want {
t.Errorf("expected %q, got %q", want, have)
}
if code := <-cexit; code != 0 {
t.Errorf("cmd exited with %d", code)
}

// The zeusmaster catches the interrupt and exits gracefully
me.Signal(os.Interrupt)
if code := <-zexit; code != 0 {
Expand All @@ -255,3 +282,12 @@ func readAndCompare(conn *net.UnixConn, want string) error {

return nil
}

type hangingReader struct {
close chan struct{}
}

func (r hangingReader) Read([]byte) (int, error) {
<-r.close
return 0, io.EOF
}

0 comments on commit e9dfba6

Please sign in to comment.