Skip to content

Commit

Permalink
Improve test coverage for proxy.go
Browse files Browse the repository at this point in the history
  • Loading branch information
adiclepcea committed Oct 20, 2017
1 parent ecf7ba8 commit d95c0c3
Show file tree
Hide file tree
Showing 2 changed files with 307 additions and 9 deletions.
26 changes: 17 additions & 9 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,8 @@ func NewErgoProxy(config *Config) *httputil.ReverseProxy {
}
}

//ServeProxy listens & serves the HTTP proxy.
func ServeProxy(config *Config) error {

pollConfigChange(config)

http.HandleFunc("/proxy.pac", func(w http.ResponseWriter, r *http.Request) {
func proxy(config *Config) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
content := `
function FindProxyForURL (url, host) {
if (dnsDomainIs(host, '` + config.Domain + `')) {
Expand All @@ -138,14 +134,26 @@ func ServeProxy(config *Config) error {
`
w.Header().Set("Content-Type", "application/x-ns-proxy-autoconfig")
w.Write([]byte(content))
})
}
}

http.HandleFunc("/_ergo/list", func(w http.ResponseWriter, r *http.Request) {
func list(config *Config) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
for _, s := range config.Services {
localURL := `http://` + s.Name + config.Domain
fmt.Fprintf(w, "- %s -> %s \n", localURL, s.URL)
}
})
}
}

//ServeProxy listens & serves the HTTP proxy.
func ServeProxy(config *Config) error {

pollConfigChange(config)

http.HandleFunc("/proxy.pac", proxy(config))

http.HandleFunc("/_ergo/list", list(config))

http.Handle("/", NewErgoProxy(config))

Expand Down
290 changes: 290 additions & 0 deletions proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ package proxy

import (
// "io/ioutil"
"bytes"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"time"
// "net/http/httptest"
// "strings"
"net/url"
Expand Down Expand Up @@ -130,3 +137,286 @@ func TestWhenHasCollectionFile(t *testing.T) {
})
})
}

func TestPollConfigChangeShouldNotFindFile(t *testing.T) {

config := Config{}
config.ConfigFile = ".notexistent"

logbuf := new(bytes.Buffer)

log.SetOutput(logbuf)

pollConfigChange(&config)

stop := struct{}{}

time.Sleep(2 * time.Second)

quit <- stop

if len(logbuf.String()) == 0 {
t.Fatalf("Expected to get a read from the log. Got none")
} else if !strings.Contains(logbuf.String(), "The system cannot find the file specified") &&
!strings.Contains(logbuf.String(), "no such file or directory") {
t.Fatalf("Expected the log to report a missing file. Got %s", logbuf.String())
}
}

func TestPollConfigChangeWithInvalidConfigFile(t *testing.T) {
tmpfile, err := ioutil.TempFile("", "example")
if err != nil {
t.Fatalf("No error expected while creating a temporary file. Got %s.", err.Error())
}

defer os.Remove(tmpfile.Name())

if _, err = tmpfile.Write([]byte("test.dev localhost:9999")); err != nil {
t.Fatalf("No error expected while writing initial config to a temporary file. Got %s.", err.Error())
}

if err = tmpfile.Close(); err != nil {
t.Fatalf("No error expected while closing the temporary file. Got %s.", err.Error())
}

config := Config{}
config.ConfigFile = tmpfile.Name()

pollConfigChange(&config)

stop := struct{}{}

time.Sleep(2 * time.Second)
logbuf := new(bytes.Buffer)

log.SetOutput(logbuf)

err = ioutil.WriteFile(tmpfile.Name(), []byte("test.devlocalhost:9900"), 0644)

if err != nil {
t.Fatalf("Expected no error while rewriting the temporary config file. Got %s", err.Error())
}

time.Sleep(2 * time.Second)

quit <- stop

if len(logbuf.String()) == 0 {
t.Fatalf("Expected to get a read from the log. Got none")
} else if !strings.Contains(logbuf.String(), "Error reading the modified config file") {
t.Fatalf("Expected the log to report an error reading an invalid config file. Got %s", logbuf.String())
}
}

func TestPollConfigChangeWithValidConfigFile(t *testing.T) {
tmpfile, err := ioutil.TempFile("", "example")
if err != nil {
t.Fatalf("No error expected while creating a temporary file. Got %s.", err.Error())
}

defer os.Remove(tmpfile.Name())

if _, err = tmpfile.Write([]byte("test.dev localhost:9999")); err != nil {
t.Fatalf("No error expected while writing initial config to a temporary file. Got %s.", err.Error())
}

if err = tmpfile.Close(); err != nil {
t.Fatalf("No error expected while closing the temporary file. Got %s.", err.Error())
}

config := Config{}
config.ConfigFile = tmpfile.Name()

pollConfigChange(&config)

stop := struct{}{}

time.Sleep(2 * time.Second)

err = ioutil.WriteFile(tmpfile.Name(), []byte("test.dev http://localhost:9900"), 0644)

if err != nil {
t.Fatalf("Expected no error while rewriting the temporary config file. Got %s", err.Error())
}

time.Sleep(2 * time.Second)

var srv []Service

select {
case srv = <-configChan:
if len(srv) != 1 {
t.Fatalf("Expected to get 1 service Got %d", len(srv))
}
if srv[0].URL != "http://localhost:9900" || srv[0].Name != "test.dev" {
t.Fatalf("Expected to get 1 service with the URL http://localhost:9900 and the name test.dev. Got the URL: %s and the name: %s", srv[0].URL, srv[0].Name)
}
default:
quit <- stop
t.Fatalf("Expected to get the changed services. Got nothing")
}
quit <- stop
}

//structure to mock a http ResponseWriter
type mockHTTPResponse struct {
WrittenData []byte
WrittenHeader int
MyHeader http.Header
}

func (mr *mockHTTPResponse) Header() http.Header {
return mr.MyHeader
}

func (mr *mockHTTPResponse) Write(data []byte) (int, error) {
mr.WrittenData = data
return len(data), nil
}

func (mr *mockHTTPResponse) WriteHeader(header int) {
mr.WrittenHeader = header
}

func TestProxyFunction(t *testing.T) {
tmpfile, err := ioutil.TempFile("", "example")
if err != nil {
t.Fatalf("No error expected while creating a temporary file. Got %s.", err.Error())
}

defer os.Remove(tmpfile.Name())

if _, err = tmpfile.Write([]byte("test.dev localhost:9999")); err != nil {
t.Fatalf("No error expected while writing initial config to a temporary file. Got %s.", err.Error())
}

if err = tmpfile.Close(); err != nil {
t.Fatalf("No error expected while closing the temporary file. Got %s.", err.Error())
}

config := Config{}
config.ConfigFile = tmpfile.Name()
config.Domain = "dev"
config.Port = "2000"

fncProxy := proxy(&config)
m := &mockHTTPResponse{}
m.MyHeader = make(http.Header)
r := http.Request{}

fncProxy(m, &r)

if len(m.MyHeader) != 1 {
t.Fatalf("Expected to get 1 header. Got %d", len(m.MyHeader))
}
if m.MyHeader["Content-Type"] == nil {
t.Fatal("Expected to get a \"Content-Type\" header. Got none")
}
if m.MyHeader["Content-Type"][0] != "application/x-ns-proxy-autoconfig" {
t.Fatalf("Expected to get a \"Content-Type\" header of \"application/x-ns-proxy-autoconfig\". Got %s", m.MyHeader["Content-Type"][0])
}

content := `
function FindProxyForURL (url, host) {
if (dnsDomainIs(host, '` + config.Domain + `')) {
return 'PROXY 127.0.0.1:` + config.Port + `';
}
return 'DIRECT';
}
`

content = strings.Replace(content, "\t", "", -1)

response := strings.Replace(string(m.WrittenData), "\t", "", -1)

if !strings.Contains(response, content) {
t.Fatalf("Expected to get an response of %s. Got %s", content, response)
}

}

func TestListFunction(t *testing.T) {
tmpfile, err := ioutil.TempFile("", "example")
if err != nil {
t.Fatalf("No error expected while creating a temporary file. Got %s.", err.Error())
}

defer os.Remove(tmpfile.Name())

if _, err = tmpfile.Write([]byte("test.dev localhost:9999")); err != nil {
t.Fatalf("No error expected while writing initial config to a temporary file. Got %s.", err.Error())
}

if err = tmpfile.Close(); err != nil {
t.Fatalf("No error expected while closing the temporary file. Got %s.", err.Error())
}

config := Config{}
config.ConfigFile = tmpfile.Name()
config.Domain = "dev"
config.Port = "2000"
config.Services, err = LoadServices(tmpfile.Name())
if err != nil {
t.Fatalf("Expected no error while loading services from temp file. Got %s", err.Error())
}

fncList := list(&config)
m := &mockHTTPResponse{}
m.MyHeader = make(http.Header)
r := http.Request{}

fncList(m, &r)

content := fmt.Sprintf("- %s -> %s \n", "http:\\test.dev", "localhost:9999")

if !strings.Contains(string(m.WrittenData), content) {
t.Fatalf("Expected to get an response of %s. Got %s", content, m.WrittenData)
}

}

func TestFormatRequest(t *testing.T) {

r := http.Request{}
r.Header = make(http.Header)
r.Header.Add("test-header", "test-header-value")
r.Host = "test-host"

expected := `Host: test-host Test-Header: test-header-value`
formated := formatRequest(&r)

if strings.Replace(formated, "\n", " ", -1) != expected {
t.Fatalf("Expected to get a formated string of \"%s\". Got \"%s\"", strings.Trim(expected, "\n"), strings.Trim(formated, "\n"))
}
}

func TestSingleJoiningSlash(t *testing.T) {
a1 := "path/"
a2 := "path"
b1 := "/anotherpath"
b2 := "anotherpath"

rez11 := singleJoiningSlash(a1, b1)
rez12 := singleJoiningSlash(a1, b2)
rez21 := singleJoiningSlash(a2, b1)
rez22 := singleJoiningSlash(a2, b2)

expected := "path/anotherpath"

if rez11 != expected {
t.Fatalf("Expected to get %s as the joining of %s and %s. Got %s", expected, a1, b1, rez11)
}

if rez12 != expected {
t.Fatalf("Expected to get %s as the joining of %s and %s. Got %s", expected, a1, b2, rez12)
}

if rez21 != expected {
t.Fatalf("Expected to get %s as the joining of %s and %s. Got %s", expected, a2, b1, rez21)
}

if rez22 != expected {
t.Fatalf("Expected to get %s as the joining of %s and %s. Got %s", expected, a2, b2, rez22)
}
}

0 comments on commit d95c0c3

Please sign in to comment.