diff --git a/client.go b/client.go index 2d660a7..f41224a 100644 --- a/client.go +++ b/client.go @@ -20,6 +20,10 @@ type HAProxyClient struct { conn net.Conn } +type HAProxy interface { + RunCommand(cmd string) (*bytes.Buffer, error) +} + // RunCommand is the entrypoint to the client. Sends an arbitray command string to HAProxy. func (h *HAProxyClient) RunCommand(cmd string) (*bytes.Buffer, error) { err := h.dial() diff --git a/client_test.go b/client_test.go index eb8f6e9..7a44f3a 100644 --- a/client_test.go +++ b/client_test.go @@ -1,52 +1,25 @@ -package haproxy_test +package haproxy import ( - "fmt" - - "github.com/bcicen/go-haproxy" + "testing" ) -func ExampleHAProxyClient_Stats() { - client := &haproxy.HAProxyClient{ - Addr: "unix:///var/run/haproxy.sock", - } - stats, err := client.Stats() - if err != nil { - fmt.Println(err) - return - } - for _, s := range stats { - fmt.Printf("%s: %s\n", s.SvName, s.Status) - } - // Output: - //static: DOWN - //app1: UP - //app2: UP - //... -} +// TestSchemaValidation ensures that the schema() method correctly parses Addr strings. +func TestSchemaValidation(t *testing.T) { + ha := &HAProxyClient{Addr: "tcp://sys49152/"} -func ExampleHAProxyClient_Info() { - client := &haproxy.HAProxyClient{ - Addr: "unix:///var/run/haproxy.sock", + if ha.schema() != "tcp" { + t.Errorf("Expected 'tcp', received '%s'", ha) } - info, err := client.Info() - if err != nil { - fmt.Println(err) - return - } - fmt.Printf("%s version %s\n", info.Name, info.Version) - // Output: - //HAProxy version 1.6.3 -} -func ExampleHAProxyClient_RunCommand() { - client := &haproxy.HAProxyClient{ - Addr: "unix:///var/run/haproxy.sock", + ha = &HAProxyClient{Addr: "unix://sys2064/"} + if ha.schema() != "socket" { + t.Errorf("Expected 'socket', received '%s'", ha) } - result, err := client.RunCommand("show info") - if err != nil { - fmt.Println(err) - return + + ha = &HAProxyClient{Addr: "unknown://RUN/"} + if ha.schema() != "" { + t.Errorf("Expected '', received '%s'", ha) } - fmt.Println(result.String()) + } diff --git a/info.go b/info.go index f64e63d..02793e9 100644 --- a/info.go +++ b/info.go @@ -7,7 +7,7 @@ import ( ) // Response from HAProxy "show info" command. -type Info struct { +type InfoResponse struct { Name string `kv:"Name"` Version string `kv:"Version"` ReleaseDate string `kv:"Release_date"` @@ -59,12 +59,12 @@ type Info struct { } // Equivalent to HAProxy "show info" command. -func (h *HAProxyClient) Info() (*Info, error) { +func Info(h HAProxy) (*InfoResponse, error) { res, err := h.RunCommand("show info") if err != nil { return nil, err } - info := &Info{} + info := &InfoResponse{} err = kvcodec.Unmarshal(res, info) if err != nil { return nil, fmt.Errorf("error decoding response: %s", err) diff --git a/info_test.go b/info_test.go new file mode 100644 index 0000000..d73189a --- /dev/null +++ b/info_test.go @@ -0,0 +1,48 @@ +package haproxy + +import ( + "bytes" + "testing" +) + +type InfoTestHAProxyClient struct{} + +// RunCommand stubs the HAProxyClient returning our expected bytes.Buffer containing the response from a 'show info' command. +func (ha *InfoTestHAProxyClient) RunCommand(cmd string) (*bytes.Buffer, error) { + var buf bytes.Buffer + buf.WriteString("Name: HAProxy\n") + buf.WriteString("Version: 1.5.4\n") + buf.WriteString("node: SYS64738\n") + buf.WriteString("description: go-haproxy stub tests.\n") + return &buf, nil +} + +// TestCommandInfo validates the structure of the "show info" command is handled appropriately. +func TestCommandInfo(t *testing.T) { + ha := new(InfoTestHAProxyClient) + info, err := Info(ha) + + if err != nil { + t.Fatalf("Unable to execute 'show info' Info()") + } + + expect := "HAProxy" + if info.Name != expect { + t.Errorf("Expected Name of '%s', but received '%s' instead", expect, info.Name) + } + + expect = "1.5.4" + if info.Version != expect { + t.Errorf("Expected Version of '%s', but received '%s' instead", expect, info.Version) + } + + expect = "SYS64738" + if info.Node != expect { + t.Errorf("Expected Node of '%s', but received '%s' instead", expect, info.Node) + } + + expect = "go-haproxy stub tests." + if info.Description != expect { + t.Errorf("Expected Description of '%s', but received '%s' instead", expect, info.Description) + } +} diff --git a/stat.go b/stat.go index 3928646..23b429c 100644 --- a/stat.go +++ b/stat.go @@ -8,7 +8,7 @@ import ( ) // Response from HAProxy "show stat" command. -type Stat struct { +type StatResponse struct { PxName string `csv:"# pxname"` SvName string `csv:"svname"` Qcur uint64 `csv:"qcur"` @@ -74,7 +74,7 @@ type Stat struct { } // Equivalent to HAProxy "show stat" command. -func (h *HAProxyClient) Stats() (stats []*Stat, err error) { +func Stats(h HAProxy) (stats []*StatResponse, err error) { res, err := h.RunCommand("show stat") if err != nil { return nil, err diff --git a/stat_test.go b/stat_test.go new file mode 100644 index 0000000..02b9107 --- /dev/null +++ b/stat_test.go @@ -0,0 +1,40 @@ +package haproxy + +import ( + "bytes" + "testing" +) + +type StatsTestHAProxyClient struct{} + +// RunCommand stubs the HAProxyClient returning our expected bytes.Buffer containing the response from a 'show stats' command. +func (ha *StatsTestHAProxyClient) RunCommand(cmd string) (*bytes.Buffer, error) { + var buf bytes.Buffer + buf.WriteString("# pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq,dresp,ereq,econ,eresp,wretr,wredis,status,weight,act,bck,chkfail,chkdown,lastchg,downtime,qlimit,pid,iid,sid,throttle,lbtot,tracked,type,rate,rate_lim,rate_max,check_status,check_code,check_duration,hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,req_rate,req_rate_max,req_tot,cli_abrt,srv_abrt,comp_in,comp_out,comp_byp,comp_rsp,lastsess,last_chk,last_agt,qtime,ctime,rtime,ttime,\n") + buf.WriteString("main,FRONTEND,,,0,0,3000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,2,0,,,,0,0,0,0,,,,0,0,0,0,0,0,,0,0,0,,,0,0,0,0,,,,,,,,") + return &buf, nil +} + +// TestCommandStats validates the structure of the "show stats" command is handled appropriately. +func TestCommandStats(t *testing.T) { + ha := new(StatsTestHAProxyClient) + stats, err := Stats(ha) + + if err != nil { + t.Fatalf("Unable to execute 'show stats' Stats()") + } + + if len(stats) != 1 { + t.Errorf("Expected 1 'show stats' record, found %d", len(stats)) + } + + expect := "main" + if stats[0].PxName != expect { + t.Errorf("Expected PxName of '%s', but received '%s' instead", expect, stats[0].PxName) + } + + expect = "FRONTEND" + if stats[0].SvName != expect { + t.Errorf("Expected SvName of '%s', but received '%s' instead", expect, stats[0].SvName) + } +}