Some integration testing

main
Drew Bednar 2 months ago
parent a667f14ace
commit 41e31f763b

@ -1,9 +1,23 @@
SQL_DATABASE?=./ratchet.db
# TODO maybe only use -race in an ARG for CI
FLAGS := -race -v
# `make <target> ARGS=no-cache` will avoid using cached results in go test.
ifeq ($(ARGS), no-cache)
FLAGS += -count=1
endif
# make test ARGS=no-cache
test:
go test -v ./...
go test $(FLAGS) ./...
PHONEY: test
# make test-int ARGS=no-cache
test-int:
go test $(FLAGS) ./cmd/...
.PHONY: test-int
serve:
go run ./cmd/ratchetd/main.go
PHONEY: serve

@ -1 +1,58 @@
package main
import (
"net/http"
"testing"
"git.runcible.io/learning/ratchet/internal/assert"
)
// func testingLogger() *slog.Logger {
// return slog.New(slog.NewTextHandler(io.Discard, nil))
// }
// WITHOUT testutils_test.go helpers
// func TestPingIntegration(t *testing.T) {
// rs := server.NewRatchetApp(testingLogger(), nil, nil, nil)
// // We then use the httptest.NewTLSServer() function to create a new test
// // server, passing in the value returned by our app.routes() method as the
// // handler for the server. This starts up a HTTPS server which listens on a
// // randomly-chosen port of your local machine for the duration of the test.
// // Notice that we defer a call to ts.Close() so that the server is shutdown
// // when the test finishes.
// ts := httptest.NewTLSServer(rs)
// defer ts.Close()
// resp, err := ts.Client().Get(ts.URL + "/ping")
// if err != nil {
// t.Fatal(err)
// }
// assert.Equal(t, resp.StatusCode, http.StatusOK)
// defer resp.Body.Close()
// body, err := io.ReadAll(resp.Body)
// if err != nil {
// t.Fatal(err)
// }
// body = bytes.TrimSpace(body)
// assert.Equal(t, string(body), "OK")
// }
func TestPingIntegration(t *testing.T) {
// Tests marked using t.Parallel() will be run in parallel with — and only with — other parallel tests.
// By default, the maximum number of tests that will be run simultaneously is the current value of
// GOMAXPROCS. You can override this by setting a specific value via the -parallel flag.
t.Parallel()
app := newTestApplication(t)
ts := newTestServer(t, app)
defer ts.Close()
code, _, body := ts.get(t, "/ping")
assert.Equal(t, code, http.StatusOK)
assert.Equal(t, body, "OK")
}

@ -0,0 +1,62 @@
package main
import (
"io"
"log/slog"
"net/http"
"net/http/cookiejar"
"net/http/httptest"
"testing"
"git.runcible.io/learning/ratchet/internal/server"
)
// Create a newTestApplication helper which returns an instance of our
// application struct containing mocked dependencies.
func newTestApplication(t *testing.T) *server.RatchetApp {
rs := server.NewRatchetApp(slog.New(slog.NewTextHandler(io.Discard, nil)), nil, nil, nil)
return rs
}
// create out own test server with additional receiver functions for ease of testing
type testServer struct {
*httptest.Server
}
func newTestServer(t *testing.T, h http.Handler) *testServer {
ts := httptest.NewTLSServer(h)
jar, err := cookiejar.New(nil)
if err != nil {
t.Fatal(err)
}
// Any response cookies will be stored and sent on subsequent requests
ts.Client().Jar = jar
// Disable redirect-following for test server client by setting custom
// CheckRedirect function. Called whenever 3xx response. By returning a
// http.ErrUseLastResponse error it forces the client to immediately return
// the received response
ts.Client().CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
return &testServer{ts}
}
func (ts *testServer) get(t *testing.T, urlPath string) (int, http.Header, string) {
resp, err := ts.Client().Get(ts.URL + urlPath)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
return resp.StatusCode, resp.Header, string(body)
}

@ -19,6 +19,8 @@ func addRoutes(mux *http.ServeMux,
userService *model.UserService,
snippetService *model.SnippetService) http.Handler {
mux.Handle("GET /ping", PingHandler())
// /{$} is used to prevent subtree path patterns from acting like a wildcard
// resulting in this route requiring an exact match on "/" only
// You can only include one HTTP method in a route pattern if you choose

Loading…
Cancel
Save