From 3b859cf52ade7079f155b88006bb48c885737ec7 Mon Sep 17 00:00:00 2001 From: Matt Fellows Date: Sat, 4 Jun 2016 09:38:58 +1000 Subject: [PATCH] test(daemon): RPC Client error tests --- command/pact_mock_service_cmd.go | 2 +- command/pact_mock_service_cmd_test.go | 7 -- daemon/daemon.go | 3 +- daemon/pact_mock_service.go | 3 +- daemon/pact_mock_service_test.go | 2 +- daemon/service.go | 2 +- daemon/service_mock.go | 2 +- dsl/client.go | 58 ++++++++++++----- dsl/client_test.go | 94 ++++++++++++++++++++++----- 9 files changed, 127 insertions(+), 46 deletions(-) diff --git a/command/pact_mock_service_cmd.go b/command/pact_mock_service_cmd.go index b9c8fb8f8..5791426ed 100644 --- a/command/pact_mock_service_cmd.go +++ b/command/pact_mock_service_cmd.go @@ -19,7 +19,7 @@ var mockServiceCmd = &cobra.Command{ // Start the service svcManager := &daemon.PactMockService{} svcManager.Setup() - _, svc := svcManager.NewService() + _, svc := svcManager.NewService([]string{}) svc.Start() // Block until a signal is received. diff --git a/command/pact_mock_service_cmd_test.go b/command/pact_mock_service_cmd_test.go index a45b9d3cc..7a14b2e58 100644 --- a/command/pact_mock_service_cmd_test.go +++ b/command/pact_mock_service_cmd_test.go @@ -2,16 +2,9 @@ package command import "testing" -func init() { - // os.Args = append(os.Args, "mock") - // os.Args = append(os.Args, "--help") -} - func Test_PactMockServiceCommand(t *testing.T) { err := mockServiceCmd.Help() if err != nil { t.Fatalf("Error: %v", err) } - - // mockServiceCmd.Run(nil, os.Args) } diff --git a/daemon/daemon.go b/daemon/daemon.go index 1a6e30742..473250d4a 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -16,6 +16,7 @@ type PactMockServer struct { Pid int Port int Status int + Args []string } // PublishRequest contains the details required to Publish Pacts to a broker. @@ -121,7 +122,7 @@ func (d *Daemon) Shutdown() { // struct. func (d *Daemon) StartServer(request *PactMockServer, reply *PactMockServer) error { server := &PactMockServer{} - port, svc := d.pactMockSvcManager.NewService() + port, svc := d.pactMockSvcManager.NewService(request.Args) server.Port = port cmd := svc.Start() server.Pid = cmd.Process.Pid diff --git a/daemon/pact_mock_service.go b/daemon/pact_mock_service.go index b0593bf75..3204b8697 100644 --- a/daemon/pact_mock_service.go +++ b/daemon/pact_mock_service.go @@ -15,7 +15,7 @@ type PactMockService struct { } // NewService creates a new PactMockService with default settings. -func (m *PactMockService) NewService() (int, Service) { +func (m *PactMockService) NewService(args []string) (int, Service) { port, _ := utils.GetFreePort() // version := 2 // dir, _ := os.Getwd() @@ -30,6 +30,7 @@ func (m *PactMockService) NewService() (int, Service) { // fmt.Sprintf("--log-dir %s", logDir), // fmt.Sprintf("--ssl"), } + m.Args = append(m.Args, args...) m.Command = getCommandPath() return port, m } diff --git a/daemon/pact_mock_service_test.go b/daemon/pact_mock_service_test.go index 54ccbe4ad..a31345a93 100644 --- a/daemon/pact_mock_service_test.go +++ b/daemon/pact_mock_service_test.go @@ -4,7 +4,7 @@ import "testing" func TestNewService(t *testing.T) { s := &PactMockService{} - port, svc := s.NewService() + port, svc := s.NewService([]string{}) if port <= 0 { t.Fatalf("Expected non-zero port but got: %d", port) diff --git a/daemon/service.go b/daemon/service.go index 2b8f2e819..f64be1fc7 100644 --- a/daemon/service.go +++ b/daemon/service.go @@ -14,7 +14,7 @@ type Service interface { Stop(pid int) (bool, error) List() map[int]*exec.Cmd Start() *exec.Cmd - NewService() (int, Service) + NewService(args []string) (int, Service) } // ServiceManager is the default implementation of the Service interface. diff --git a/daemon/service_mock.go b/daemon/service_mock.go index bb12d234b..0767583d3 100644 --- a/daemon/service_mock.go +++ b/daemon/service_mock.go @@ -47,6 +47,6 @@ func (s *ServiceMock) Start() *exec.Cmd { } // NewService creates a new MockService with default settings. -func (s *ServiceMock) NewService() (int, Service) { +func (s *ServiceMock) NewService(args []string) (int, Service) { return s.ServicePort, s } diff --git a/dsl/client.go b/dsl/client.go index 707a749d8..5340ebc6a 100644 --- a/dsl/client.go +++ b/dsl/client.go @@ -10,6 +10,8 @@ import ( "github.com/mefellows/pact-go/daemon" ) +var timeoutDuration = 1 * time.Second + // Client is the simplified remote interface to the Pact Daemon type Client interface { StartServer() *daemon.PactMockServer @@ -22,24 +24,28 @@ type PactClient struct { } func getHTTPClient(port int) (*rpc.Client, error) { - waitForPort(port) + err := waitForPort(port) + if err != nil { + return nil, err + } return rpc.DialHTTP("tcp", fmt.Sprintf(":%d", port)) } // Use this to wait for a daemon to be running prior // to running tests -func waitForPort(port int) { +func waitForPort(port int) error { fmt.Printf("client - Waiting for daemon port: %d", port) - timeout := time.After(10 * time.Second) + timeout := time.After(timeoutDuration) for { select { case <-timeout: - log.Fatalf("Expected server to start < 1s.") + log.Printf("Expected server to start < %s", timeoutDuration) + return fmt.Errorf("Expected server to start < %s", timeoutDuration) case <-time.After(50 * time.Millisecond): _, err := net.Dial("tcp", fmt.Sprintf(":%d", port)) if err == nil { - return + return nil } } } @@ -49,12 +55,11 @@ func waitForPort(port int) { func (p *PactClient) StartServer() *daemon.PactMockServer { var res daemon.PactMockServer client, err := getHTTPClient(p.Port) - if err != nil { - log.Fatal("rpc error:", err) - } - err = client.Call("Daemon.StartServer", daemon.PactMockServer{}, &res) - if err != nil { - log.Fatal("rpc error:", err) + if err == nil { + err = client.Call("Daemon.StartServer", daemon.PactMockServer{}, &res) + if err != nil { + log.Fatal("rpc error:", err) + } } return &res } @@ -63,20 +68,37 @@ func (p *PactClient) StartServer() *daemon.PactMockServer { func (p *PactClient) ListServers() *daemon.PactListResponse { var res daemon.PactListResponse client, err := getHTTPClient(p.Port) - err = client.Call("Daemon.ListServers", daemon.PactMockServer{}, &res) - if err != nil { - log.Fatal("rpc error:", err) + if err == nil { + err = client.Call("Daemon.ListServers", daemon.PactMockServer{}, &res) + if err != nil { + log.Fatal("rpc error:", err) + } } return &res } // StopServer stops a remote Pact Mock Server. func (p *PactClient) StopServer(server *daemon.PactMockServer) *daemon.PactMockServer { - client, err := getHTTPClient(p.Port) var res daemon.PactMockServer - err = client.Call("Daemon.StopServer", server, &res) - if err != nil { - log.Fatal("rpc error:", err) + client, err := getHTTPClient(p.Port) + if err == nil { + err = client.Call("Daemon.StopServer", server, &res) + if err != nil { + log.Fatal("rpc error:", err) + } } return &res } + +// StopDaemon remotely shuts down the Pact Daemon. +func (p *PactClient) StopDaemon() error { + var req, res string + client, err := getHTTPClient(p.Port) + if err == nil { + err = client.Call("Daemon.StopDaemon", &req, &res) + if err != nil { + log.Fatal("rpc error:", err) + } + } + return err +} diff --git a/dsl/client_test.go b/dsl/client_test.go index db20d87a0..af965be8a 100644 --- a/dsl/client_test.go +++ b/dsl/client_test.go @@ -7,6 +7,7 @@ import ( "net/rpc" "os" "os/exec" + "reflect" "testing" "time" @@ -35,7 +36,6 @@ func waitForPortInTest(port int, t *testing.T) { func waitForDaemonToShutdown(port int, t *testing.T) { req := "" res := "" - // var req interface{} waitForPortInTest(port, t) @@ -43,11 +43,9 @@ func waitForDaemonToShutdown(port int, t *testing.T) { client, err := rpc.DialHTTP("tcp", fmt.Sprintf(":%d", port)) err = client.Call("Daemon.StopDaemon", &req, &res) - // err = client.Call("Daemon.StopDaemon", req, &res) if err != nil { log.Fatal("rpc error:", err) } - fmt.Println(res) t.Logf("Waiting for deamon to shutdown before next test") timeout := time.After(1 * time.Second) @@ -72,7 +70,8 @@ func waitForDaemonToShutdown(port int, t *testing.T) { } // This guy mocks out the underlying Service provider in the Daemon, -// but executes actual Daemon code. +// but executes actual Daemon code. This means we don't spin up the real +// mock service but execute our code in isolation. // // Stubbing the exec.Cmd interface is hard, see fakeExec* functions for // the magic. @@ -108,21 +107,14 @@ func createDaemon(port int) (*daemon.Daemon, *daemon.ServiceMock) { return d, svc } -// func TestClient_Fail(t *testing.T) { -// client := NewPactClient{ /* don't supply port */ } -// -// } - // Integration style test: Can a client hit each endpoint? -func TestRPCClient_List(t *testing.T) { +func TestClient_List(t *testing.T) { port, _ := utils.GetFreePort() createDaemon(port) waitForPortInTest(port, t) defer waitForDaemonToShutdown(port, t) client := &PactClient{Port: port} - waitForPortInTest(port, t) - s := client.ListServers() if len(s.Servers) != 3 { @@ -130,22 +122,94 @@ func TestRPCClient_List(t *testing.T) { } } +func TestClient_ListFail(t *testing.T) { + timeoutDuration = 50 * time.Millisecond + client := &PactClient{ /* don't supply port */ } + client.StartServer() + list := client.ListServers() + + if len(list.Servers) != 0 { + t.Fatalf("Expected 0 servers, got %d", len(list.Servers)) + } + timeoutDuration = oldTimeoutDuration +} + // Integration style test: Can a client hit each endpoint? -func TestRPCClient_StartServer(t *testing.T) { +func TestClient_StartServer(t *testing.T) { port, _ := utils.GetFreePort() _, svc := createDaemon(port) waitForPortInTest(port, t) defer waitForDaemonToShutdown(port, t) client := &PactClient{Port: port} - waitForPortInTest(port, t) - client.StartServer() if svc.ServiceStartCount != 1 { t.Fatalf("Expected 1 server to have been started, got %d", svc.ServiceStartCount) } } +var oldTimeoutDuration = timeoutDuration + +func TestClient_StartServerFail(t *testing.T) { + timeoutDuration = 50 * time.Millisecond + + client := &PactClient{ /* don't supply port */ } + server := client.StartServer() + if server.Port != 0 { + t.Fatalf("Expected server to be empty %v", server) + } + timeoutDuration = oldTimeoutDuration +} + +// Integration style test: Can a client hit each endpoint? +func TestClient_StopServer(t *testing.T) { + port, _ := utils.GetFreePort() + _, svc := createDaemon(port) + waitForPortInTest(port, t) + defer waitForDaemonToShutdown(port, t) + client := &PactClient{Port: port} + + client.StopServer(&daemon.PactMockServer{}) + if svc.ServiceStopCount != 1 { + t.Fatalf("Expected 1 server to have been stopped, got %d", svc.ServiceStartCount) + } +} + +func TestClient_StopServerFail(t *testing.T) { + timeoutDuration = 50 * time.Millisecond + client := &PactClient{ /* don't supply port */ } + res := client.StopServer(&daemon.PactMockServer{}) + should := &daemon.PactMockServer{} + if !reflect.DeepEqual(res, should) { + t.Fatalf("Expected nil object but got a difference: %v != %v", res, should) + } + timeoutDuration = oldTimeoutDuration +} + +// Integration style test: Can a client hit each endpoint? +func TestClient_StopDaemon(t *testing.T) { + port, _ := utils.GetFreePort() + createDaemon(port) + waitForPortInTest(port, t) + client := &PactClient{Port: port} + + err := client.StopDaemon() + if err != nil { + t.Fatalf("Err: %v", err) + } + waitForDaemonToShutdown(port, t) +} + +func TestClient_StopDaemonFail(t *testing.T) { + timeoutDuration = 50 * time.Millisecond + client := &PactClient{ /* don't supply port */ } + err := client.StopDaemon() + if err == nil { + t.Fatalf("Expected error but got none") + } + timeoutDuration = oldTimeoutDuration +} + // Adapted from http://npf.io/2015/06/testing-exec-command/ var fakeExecSuccessCommand = func() *exec.Cmd { return fakeExecCommand("", true, "")