mirror of
https://github.com/prymitive/karma
synced 2026-05-07 03:26:52 +00:00
httptest.newRequest is suppose to be used for testing request handing, http.newRequest is for preparing outgoing requests, this allows to fix cache key selection and increase test coverage
227 lines
6.9 KiB
Go
227 lines
6.9 KiB
Go
package main
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/prymitive/unsee/internal/alertmanager"
|
|
|
|
httpmock "gopkg.in/jarcoal/httpmock.v1"
|
|
)
|
|
|
|
// httptest.NewRecorder() doesn't implement http.CloseNotifier
|
|
type closeNotifyingRecorder struct {
|
|
*httptest.ResponseRecorder
|
|
closed chan bool
|
|
}
|
|
|
|
func newCloseNotifyingRecorder() *closeNotifyingRecorder {
|
|
return &closeNotifyingRecorder{
|
|
httptest.NewRecorder(),
|
|
make(chan bool, 1),
|
|
}
|
|
}
|
|
|
|
func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
|
|
return c.closed
|
|
}
|
|
|
|
type proxyTest struct {
|
|
method string
|
|
localPath string
|
|
upstreamURI string
|
|
code int
|
|
response string
|
|
}
|
|
|
|
var proxyTests = []proxyTest{
|
|
// valid alertmanager and methods
|
|
{
|
|
method: "POST",
|
|
localPath: "/proxy/alertmanager/dummy/api/v1/silences",
|
|
upstreamURI: "http://localhost:9093/api/v1/silences",
|
|
code: 200,
|
|
response: "{\"status\":\"success\",\"data\":{\"silenceId\":\"d8a61ca8-ee2e-4076-999f-276f1e986bf3\"}}",
|
|
},
|
|
{
|
|
method: "DELETE",
|
|
localPath: "/proxy/alertmanager/dummy/api/v1/silence/d8a61ca8-ee2e-4076-999f-276f1e986bf3",
|
|
upstreamURI: "http://localhost:9093/api/v1/silence/d8a61ca8-ee2e-4076-999f-276f1e986bf3",
|
|
code: 200,
|
|
response: "{\"status\":\"success\"}",
|
|
},
|
|
// invalid alertmanager name
|
|
{
|
|
method: "POST",
|
|
localPath: "/proxy/alertmanager/INVALID/api/v1/silences",
|
|
upstreamURI: "",
|
|
code: 404,
|
|
response: "404 page not found",
|
|
},
|
|
{
|
|
method: "DELETE",
|
|
localPath: "/proxy/alertmanager/INVALID/api/v1/silence/d8a61ca8-ee2e-4076-999f-276f1e986bf3",
|
|
upstreamURI: "http://localhost:9093/api/v1/silence/d8a61ca8-ee2e-4076-999f-276f1e986bf3",
|
|
code: 404,
|
|
response: "404 page not found",
|
|
},
|
|
// valid alertmanager name, but invalid method
|
|
{
|
|
method: "GET",
|
|
localPath: "/proxy/alertmanager/dummy/api/v1/silences",
|
|
upstreamURI: "",
|
|
code: 404,
|
|
response: "404 page not found",
|
|
},
|
|
{
|
|
method: "GET",
|
|
localPath: "/proxy/alertmanager/dummy/api/v1/silence/d8a61ca8-ee2e-4076-999f-276f1e986bf3",
|
|
upstreamURI: "http://localhost:9093/api/v1/silence/d8a61ca8-ee2e-4076-999f-276f1e986bf3",
|
|
code: 404,
|
|
response: "404 page not found",
|
|
},
|
|
}
|
|
|
|
func TestProxy(t *testing.T) {
|
|
r := ginTestEngine()
|
|
am, err := alertmanager.NewAlertmanager(
|
|
"dummy",
|
|
"http://localhost:9093",
|
|
alertmanager.WithRequestTimeout(time.Second*5),
|
|
alertmanager.WithProxy(true),
|
|
)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = setupRouterProxyHandlers(r, am)
|
|
if err != nil {
|
|
t.Errorf("Failed to setup proxy for Alertmanager %s: %s", am.Name, err)
|
|
}
|
|
|
|
httpmock.Activate()
|
|
defer httpmock.DeactivateAndReset()
|
|
|
|
for _, testCase := range proxyTests {
|
|
httpmock.Reset()
|
|
if testCase.upstreamURI != "" {
|
|
httpmock.RegisterResponder(testCase.method, testCase.upstreamURI, httpmock.NewStringResponder(testCase.code, testCase.response))
|
|
}
|
|
req := httptest.NewRequest(testCase.method, testCase.localPath, nil)
|
|
resp := newCloseNotifyingRecorder()
|
|
r.ServeHTTP(resp, req)
|
|
if resp.Code != testCase.code {
|
|
t.Errorf("%s %s proxied to %s returned status %d while %d was expected",
|
|
testCase.method, testCase.localPath, testCase.upstreamURI, resp.Code, testCase.code)
|
|
}
|
|
body := resp.Body.String()
|
|
if body != testCase.response {
|
|
t.Errorf("%s %s proxied to %s returned content '%s' while '%s' was expected",
|
|
testCase.method, testCase.localPath, testCase.upstreamURI, body, testCase.response)
|
|
}
|
|
}
|
|
}
|
|
|
|
type proxyHeaderTest struct {
|
|
method string
|
|
localPath string
|
|
upstreamURI string
|
|
code int
|
|
alertmanagerURI string
|
|
alertmanagerHost string
|
|
authUser string
|
|
authPass string
|
|
}
|
|
|
|
var proxyHeaderTests = []proxyHeaderTest{
|
|
{
|
|
method: "POST",
|
|
localPath: "/proxy/alertmanager/dummy/api/v1/silences",
|
|
upstreamURI: "http://localhost:9093/api/v1/silences",
|
|
code: 200,
|
|
alertmanagerURI: "http://localhost:9093",
|
|
alertmanagerHost: "localhost:9093",
|
|
},
|
|
{
|
|
method: "POST",
|
|
localPath: "/proxy/alertmanager/dummy/api/v1/silences",
|
|
upstreamURI: "http://alertmanager.example.com/api/v1/silences",
|
|
code: 200,
|
|
alertmanagerURI: "http://alertmanager.example.com",
|
|
alertmanagerHost: "alertmanager.example.com",
|
|
},
|
|
{
|
|
method: "POST",
|
|
localPath: "/proxy/alertmanager/dummy/api/v1/silences",
|
|
upstreamURI: "http://alertmanager.example.com/api/v1/silences",
|
|
code: 200,
|
|
alertmanagerURI: "http://foo:bar@alertmanager.example.com",
|
|
alertmanagerHost: "alertmanager.example.com",
|
|
authUser: "foo",
|
|
authPass: "bar",
|
|
},
|
|
{
|
|
method: "POST",
|
|
localPath: "/proxy/alertmanager/dummy/api/v1/silences",
|
|
upstreamURI: "http://alertmanager.example.com/api/v1/silences",
|
|
code: 200,
|
|
alertmanagerURI: "http://foo@alertmanager.example.com",
|
|
alertmanagerHost: "alertmanager.example.com",
|
|
authUser: "foo",
|
|
authPass: "",
|
|
},
|
|
}
|
|
|
|
func TestProxyHeaders(t *testing.T) {
|
|
httpmock.Activate()
|
|
defer httpmock.DeactivateAndReset()
|
|
|
|
for _, testCase := range proxyHeaderTests {
|
|
r := ginTestEngine()
|
|
am, err := alertmanager.NewAlertmanager(
|
|
"dummy",
|
|
testCase.alertmanagerURI,
|
|
alertmanager.WithRequestTimeout(time.Second*5),
|
|
alertmanager.WithProxy(true),
|
|
)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
err = setupRouterProxyHandlers(r, am)
|
|
if err != nil {
|
|
t.Errorf("Failed to setup proxy for Alertmanager %s: %s", am.Name, err)
|
|
}
|
|
|
|
httpmock.Reset()
|
|
httpmock.RegisterResponder(testCase.method, testCase.upstreamURI, func(req *http.Request) (*http.Response, error) {
|
|
if req.Host != testCase.alertmanagerHost {
|
|
t.Errorf("req.Host is '%s' while '%s' was expected", req.Host, testCase.alertmanagerHost)
|
|
}
|
|
if req.Header.Get("Host") != "" {
|
|
t.Errorf("req.Header.Host is '%s' while '%s' was expected", req.Header.Get("Host"), testCase.alertmanagerHost)
|
|
}
|
|
if testCase.authUser != "" || testCase.authPass != "" {
|
|
user, password, _ := req.BasicAuth()
|
|
if testCase.authUser != "" && testCase.authUser != user {
|
|
t.Errorf("%s %s proxied to %s was expected to have Basic Auth user '%s', got '%s'",
|
|
testCase.method, testCase.localPath, testCase.upstreamURI, testCase.authUser, user)
|
|
}
|
|
if testCase.authPass != "" && testCase.authPass != password {
|
|
t.Errorf("%s %s proxied to %s was expected to have Basic Auth password '%s', got '%s'",
|
|
testCase.method, testCase.localPath, testCase.upstreamURI, testCase.authPass, password)
|
|
}
|
|
}
|
|
return httpmock.NewStringResponse(testCase.code, "ok"), nil
|
|
})
|
|
|
|
req := httptest.NewRequest(testCase.method, testCase.localPath, nil)
|
|
resp := newCloseNotifyingRecorder()
|
|
r.ServeHTTP(resp, req)
|
|
if resp.Code != testCase.code {
|
|
t.Errorf("%s %s proxied to %s returned status %d while %d was expected",
|
|
testCase.method, testCase.localPath, testCase.upstreamURI, resp.Code, testCase.code)
|
|
}
|
|
}
|
|
}
|