From 92184e3d560c94ffe9404aed753cd60dcfb82c40 Mon Sep 17 00:00:00 2001 From: joeybloggs Date: Fri, 30 Oct 2015 10:47:14 -0400 Subject: [PATCH] Added WebHook Test Converage + reduces server complexity --- README.md | 2 +- github/github.go | 3 - webhooks.go | 46 +++-------- webhooks_test.go | 206 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 216 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 2985277..1fa3cac 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,6 @@ Library webhooks [![GoDoc](https://godoc.org/github.com/joeybloggs/webhooks?status.svg)](https://godoc.org/github.com/joeybloggs/webhooks) -Source control webhook reciever for GitHub +Source control webhook reciever for GitHub, others to come, with complete event payload parsing ### In Development \ No newline at end of file diff --git a/github/github.go b/github/github.go index 7d5de90..7f817b1 100644 --- a/github/github.go +++ b/github/github.go @@ -225,9 +225,6 @@ func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) { func (hook Webhook) runProcessPayloadFunc(fn webhooks.ProcessPayloadFunc, results interface{}) { go func(fn webhooks.ProcessPayloadFunc, results interface{}) { - - // put in recovery here! - fn(results) }(fn, results) } diff --git a/webhooks.go b/webhooks.go index b96c2be..bc91b07 100644 --- a/webhooks.go +++ b/webhooks.go @@ -1,10 +1,6 @@ package webhooks -import ( - "errors" - "fmt" - "net/http" -) +import "net/http" // Provider defines the type of webhook type Provider int @@ -46,23 +42,11 @@ func Run(hook Webhook, addr string, path string) error { s := &http.Server{Addr: addr, Handler: srv} - return run(s) -} - -// RunTLS runs a server with TLS configuration. -func RunTLS(hook Webhook, addr string, path string, certFile string, keyFile string) error { - srv := &server{ - hook: hook, - path: path, - } - - s := &http.Server{Addr: addr, Handler: srv} - - return run(s, certFile, keyFile) + return s.ListenAndServe() } // RunServer runs a custom server. -func RunServer(s *http.Server, hook Webhook, addr string, path string) error { +func RunServer(s *http.Server, hook Webhook, path string) error { srv := &server{ hook: hook, @@ -71,12 +55,16 @@ func RunServer(s *http.Server, hook Webhook, addr string, path string) error { s.Handler = srv - return run(s) + return s.ListenAndServe() } // RunTLSServer runs a custom server with TLS configuration. -// NOTE: http.Server Handler will be overridden by this library, just set it to nil -func RunTLSServer(s *http.Server, hook Webhook, addr string, path string, certFile string, keyFile string) error { +// NOTE: http.Server Handler will be overridden by this library, just set it to nil. +// Setting the Certificates can be done in the http.Server.TLSConfig.Certificates +// see example here: +func RunTLSServer(s *http.Server, hook Webhook, path string) error { + + // var err error srv := &server{ hook: hook, @@ -85,24 +73,12 @@ func RunTLSServer(s *http.Server, hook Webhook, addr string, path string, certFi s.Handler = srv - return run(s, certFile, keyFile) -} - -func run(s *http.Server, files ...string) error { - if len(files) == 0 { - return s.ListenAndServe() - } else if len(files) == 2 { - return s.ListenAndServeTLS(files[0], files[1]) - } - - return errors.New("invalid server configuration") + return s.ListenAndServeTLS("", "") } func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() - fmt.Println("GOT HERE!") - if r.Method != "POST" { http.Error(w, "405 Method not allowed", http.StatusMethodNotAllowed) return diff --git a/webhooks_test.go b/webhooks_test.go index f74aee8..0b3f0c2 100644 --- a/webhooks_test.go +++ b/webhooks_test.go @@ -1,6 +1,9 @@ package webhooks import ( + "bytes" + "crypto/tls" + "net/http" "os" "testing" @@ -18,16 +21,215 @@ import ( // go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html // +type FakeWebhook struct { + provider Provider +} + +func (fhook FakeWebhook) Provider() Provider { + return fhook.provider +} + +func (fhook FakeWebhook) ParsePayload(w http.ResponseWriter, r *http.Request) { +} + +var fakeHook Webhook + func TestMain(m *testing.M) { // setup + fakeHook = &FakeWebhook{ + provider: GitHub, + } os.Exit(m.Run()) // teardown } -func TestHooks(t *testing.T) { +func TestRun(t *testing.T) { - Equal(t, true, true) + go Run(fakeHook, ":3006", "/webhooks") + + payload := "{}" + + req, err := http.NewRequest("POST", "http://localhost:3006/webhooks", bytes.NewBuffer([]byte(payload))) + req.Header.Set("Content-Type", "application/json") + + Equal(t, err, nil) + + client := &http.Client{} + resp, err := client.Do(req) + Equal(t, err, nil) + + defer resp.Body.Close() + + Equal(t, resp.StatusCode, http.StatusOK) + + // While HTTP Server is running test some bad input + + // Test BAD URL + req, err = http.NewRequest("POST", "http://localhost:3006", bytes.NewBuffer([]byte(payload))) + req.Header.Set("Content-Type", "application/json") + + Equal(t, err, nil) + + resp, err = client.Do(req) + Equal(t, err, nil) + + defer resp.Body.Close() + + Equal(t, resp.StatusCode, http.StatusNotFound) + + // Test BAD METHOD + req, err = http.NewRequest("GET", "http://localhost:3006/webhooks", bytes.NewBuffer([]byte(payload))) + req.Header.Set("Content-Type", "application/json") + + Equal(t, err, nil) + + resp, err = client.Do(req) + Equal(t, err, nil) + + defer resp.Body.Close() + + Equal(t, resp.StatusCode, http.StatusMethodNotAllowed) +} + +func TestRunServer(t *testing.T) { + + server := &http.Server{Addr: ":3007", Handler: nil} + go RunServer(server, fakeHook, "/webhooks") + + payload := "{}" + + req, err := http.NewRequest("POST", "http://localhost:3007/webhooks", bytes.NewBuffer([]byte(payload))) + req.Header.Set("Content-Type", "application/json") + + Equal(t, err, nil) + + client := &http.Client{} + resp, err := client.Do(req) + Equal(t, err, nil) + + defer resp.Body.Close() + + Equal(t, resp.StatusCode, http.StatusOK) + + // While HTTP Server is running test some bad input + + // Test BAD URL + req, err = http.NewRequest("POST", "http://localhost:3007", bytes.NewBuffer([]byte(payload))) + req.Header.Set("Content-Type", "application/json") + + Equal(t, err, nil) + + resp, err = client.Do(req) + Equal(t, err, nil) + + defer resp.Body.Close() + + Equal(t, resp.StatusCode, http.StatusNotFound) + + // Test BAD METHOD + req, err = http.NewRequest("GET", "http://localhost:3007/webhooks", bytes.NewBuffer([]byte(payload))) + req.Header.Set("Content-Type", "application/json") + + Equal(t, err, nil) + + resp, err = client.Do(req) + Equal(t, err, nil) + + defer resp.Body.Close() + + Equal(t, resp.StatusCode, http.StatusMethodNotAllowed) +} + +func TestRunTLSServer(t *testing.T) { + + var err error + + // can have certificates in static variables or load from disk + cert := `-----BEGIN CERTIFICATE----- +MIIB0zCCAX2gAwIBAgIJAI/M7BYjwB+uMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTIwOTEyMjE1MjAyWhcNMTUwOTEyMjE1MjAyWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANLJ +hPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wok/4xIA+ui35/MmNa +rtNuC+BdZ1tMuVCPFZcCAwEAAaNQME4wHQYDVR0OBBYEFJvKs8RfJaXTH08W+SGv +zQyKn0H8MB8GA1UdIwQYMBaAFJvKs8RfJaXTH08W+SGvzQyKn0H8MAwGA1UdEwQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADQQBJlffJHybjDGxRMqaRmDhX0+6v02TUKZsW +r5QuVbpQhH6u+0UgcW0jp9QwpxoPTLTWGXEWBBBurxFwiCBhkQ+V +-----END CERTIFICATE----- + ` + key := `-----BEGIN RSA PRIVATE KEY----- +MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo +k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G +6OB1M1WO+k+ztnX/1SvNeWu8D6GImtupLTYgjZcHufykj09jiHmjHx8u8ZZB/o1N +MQIhAPW+eyZo7ay3lMz1V01WVjNKK9QSn1MJlb06h/LuYv9FAiEA25WPedKgVyCW +SmUwbPw8fnTcpqDWE3yTO3vKcebqMSsCIBF3UmVue8YU3jybC3NxuXq3wNm34R8T +xVLHwDXh/6NJAiEAl2oHGGLz64BuAfjKrqwz7qMYr9HCLIe/YsoWq/olzScCIQDi +D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g== +-----END RSA PRIVATE KEY----- +` + + server := &http.Server{Addr: ":3008", Handler: nil, TLSConfig: &tls.Config{}} + server.TLSConfig.Certificates = make([]tls.Certificate, 1) + + server.TLSConfig.Certificates[0], err = tls.X509KeyPair([]byte(cert), []byte(key)) + Equal(t, err, nil) + + go RunTLSServer(server, fakeHook, "/webhooks") + + payload := "{}" + + req, err := http.NewRequest("POST", "https://localhost:3008/webhooks", bytes.NewBuffer([]byte(payload))) + req.Header.Set("Content-Type", "application/json") + + Equal(t, err, nil) + + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + + client := &http.Client{Transport: tr} + resp, err := client.Do(req) + Equal(t, err, nil) + + defer resp.Body.Close() + + Equal(t, resp.StatusCode, http.StatusOK) + + // While HTTP Server is running test some bad input + + // Test BAD URL + req, err = http.NewRequest("POST", "https://localhost:3008", bytes.NewBuffer([]byte(payload))) + req.Header.Set("Content-Type", "application/json") + + Equal(t, err, nil) + + resp, err = client.Do(req) + Equal(t, err, nil) + + defer resp.Body.Close() + + Equal(t, resp.StatusCode, http.StatusNotFound) + + // Test BAD METHOD + req, err = http.NewRequest("GET", "https://localhost:3008/webhooks", bytes.NewBuffer([]byte(payload))) + req.Header.Set("Content-Type", "application/json") + + Equal(t, err, nil) + + resp, err = client.Do(req) + Equal(t, err, nil) + + defer resp.Body.Close() + + Equal(t, resp.StatusCode, http.StatusMethodNotAllowed) +} + +func TestProviderString(t *testing.T) { + + Equal(t, GitHub.String(), "GitHub") + Equal(t, Provider(999999).String(), "Unknown") }