chore: switch from memfs to fstest.MapFS (#327)

* Switch from memfs to built-in fstest.MapFS
* Ensure httptest servers are closed during test cleanup
* Swap ordering of expected/actual values in assertion functions
* Use http.StatusOK constants for status codes
* Add a 1-second context timeout for each request
* Use the test httptest.Server.Client() so that we can handle
  TLS server certificates if desired
This commit is contained in:
Jonathan Yu
2022-02-18 13:03:32 -08:00
committed by GitHub
parent 37bcfeb398
commit 5ef59e7b64
3 changed files with 178 additions and 115 deletions
-1
View File
@@ -41,7 +41,6 @@ require (
github.com/pion/transport v0.13.0
github.com/pion/webrtc/v3 v3.1.23
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef
github.com/quasilyte/go-ruleguard/dsl v0.3.17
github.com/spf13/cobra v1.3.0
github.com/stretchr/testify v1.7.0
-2
View File
@@ -1104,8 +1104,6 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef h1:NKxTG6GVGbfMXc2mIk+KphcH6hagbVXhcFkbTgYleTI=
github.com/psanford/memfs v0.0.0-20210214183328-a001468d78ef/go.mod h1:tcaRap0jS3eifrEEllL6ZMd9dg8IlDpi2S1oARrQ+NI=
github.com/quasilyte/go-ruleguard/dsl v0.3.17 h1:L5xf3nifnRIdYe9vyMuY2sDnZHIgQol/fDq74FQz7ZY=
github.com/quasilyte/go-ruleguard/dsl v0.3.17/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
+178 -112
View File
@@ -6,8 +6,9 @@ import (
"net/http"
"net/http/httptest"
"testing"
"testing/fstest"
"time"
"github.com/psanford/memfs"
"github.com/stretchr/testify/require"
"cdr.dev/slog"
@@ -20,311 +21,369 @@ func TestNextRouter(t *testing.T) {
t.Run("Serves file at root", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.WriteFile("test.html", []byte("test123"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"test.html": &fstest.MapFile{
Data: []byte("test123"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/test.html")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, string(body), "test123")
require.Equal(t, res.StatusCode, 200)
require.NoError(t, res.Body.Close())
require.EqualValues(t, "test123", body)
require.Equal(t, http.StatusOK, res.StatusCode)
})
// This is a test case for the issue we hit in V1 w/ NextJS migration
t.Run("Prefer file over folder w/ trailing slash", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.MkdirAll("folder", 0777)
require.NoError(t, err)
err = rootFS.WriteFile("folder.html", []byte("folderFile"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"folder/test.html": &fstest.MapFile{},
"folder.html": &fstest.MapFile{
Data: []byte("folderFile"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/folder/")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, string(body), "folderFile")
require.Equal(t, res.StatusCode, 200)
require.NoError(t, res.Body.Close())
require.EqualValues(t, "folderFile", body)
require.Equal(t, http.StatusOK, res.StatusCode)
})
t.Run("Serves non-html files at root", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.WriteFile("test.png", []byte("png-bytes"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"test.png": &fstest.MapFile{
Data: []byte("png-bytes"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/test.png")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, res.Header.Get("Content-Type"), "image/png")
require.Equal(t, string(body), "png-bytes")
require.Equal(t, res.StatusCode, 200)
require.NoError(t, res.Body.Close())
require.Equal(t, "image/png", res.Header.Get("Content-Type"))
require.EqualValues(t, "png-bytes", body)
require.Equal(t, http.StatusOK, res.StatusCode)
})
t.Run("Serves html file without extension", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.WriteFile("test.html", []byte("test-no-extension"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"test.html": &fstest.MapFile{
Data: []byte("test-no-extension"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/test")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, string(body), "test-no-extension")
require.Equal(t, res.StatusCode, 200)
require.NoError(t, res.Body.Close())
require.EqualValues(t, "test-no-extension", body)
require.Equal(t, http.StatusOK, res.StatusCode)
})
t.Run("Defaults to index.html at root", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.WriteFile("index.html", []byte("test-root-index"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"index.html": &fstest.MapFile{
Data: []byte("test-root-index"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, res.Header.Get("Content-Type"), "text/html; charset=utf-8")
require.Equal(t, string(body), "test-root-index")
require.Equal(t, res.StatusCode, 200)
require.NoError(t, res.Body.Close())
require.Equal(t, "text/html; charset=utf-8", res.Header.Get("Content-Type"))
require.EqualValues(t, "test-root-index", body)
require.Equal(t, http.StatusOK, res.StatusCode)
})
t.Run("Serves nested file", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.MkdirAll("test/a/b", 0777)
require.NoError(t, err)
rootFS.WriteFile("test/a/b/c.html", []byte("test123"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"test/a/b/c.html": &fstest.MapFile{
Data: []byte("test123"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/test/a/b/c.html")
require.NoError(t, err)
defer res.Body.Close()
require.NoError(t, res.Body.Close())
res, err = request(server, "/test/a/b/c.html")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, string(body), "test123")
require.Equal(t, res.StatusCode, 200)
require.NoError(t, res.Body.Close())
require.EqualValues(t, "test123", body)
require.Equal(t, http.StatusOK, res.StatusCode)
})
t.Run("Uses index.html in nested path", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.MkdirAll("test/a/b/c", 0777)
require.NoError(t, err)
rootFS.WriteFile("test/a/b/c/index.html", []byte("test-abc-index"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"test/a/b/c/index.html": &fstest.MapFile{
Data: []byte("test-abc-index"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/test/a/b/c")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, string(body), "test-abc-index")
require.Equal(t, res.StatusCode, 200)
require.NoError(t, res.Body.Close())
require.EqualValues(t, "test-abc-index", body)
require.Equal(t, http.StatusOK, res.StatusCode)
})
t.Run("404 if file at root is not found", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.WriteFile("test.html", []byte("test123"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"test.html": &fstest.MapFile{
Data: []byte("test123"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/test-non-existent.html")
require.NoError(t, err)
defer res.Body.Close()
require.Equal(t, res.StatusCode, 404)
require.NoError(t, res.Body.Close())
require.Equal(t, http.StatusNotFound, res.StatusCode)
})
t.Run("404 if file at root is not found", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.WriteFile("test.html", []byte("test123"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"test.html": &fstest.MapFile{
Data: []byte("test123"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/test-non-existent.html")
require.NoError(t, err)
defer res.Body.Close()
require.Equal(t, res.StatusCode, 404)
require.NoError(t, res.Body.Close())
require.Equal(t, http.StatusNotFound, res.StatusCode)
})
t.Run("Serve custom 404.html if available", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.WriteFile("404.html", []byte("404 custom content"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"404.html": &fstest.MapFile{
Data: []byte("404 custom content"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/test-non-existent.html")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, res.StatusCode, 404)
require.Equal(t, string(body), "404 custom content")
require.NoError(t, res.Body.Close())
require.Equal(t, http.StatusNotFound, res.StatusCode)
require.EqualValues(t, "404 custom content", body)
})
t.Run("Serves dynamic-routed file", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.MkdirAll("folder", 0777)
require.NoError(t, err)
err = rootFS.WriteFile("folder/[orgs].html", []byte("test-dynamic-path"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"folder/[orgs].html": &fstest.MapFile{
Data: []byte("test-dynamic-path"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/folder/org-1")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, string(body), "test-dynamic-path")
require.Equal(t, res.StatusCode, 200)
require.NoError(t, res.Body.Close())
require.Equal(t, http.StatusOK, res.StatusCode)
require.EqualValues(t, "test-dynamic-path", body)
})
t.Run("Handles dynamic-routed folders", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.MkdirAll("folder/[org]/[project]", 0777)
require.NoError(t, err)
err = rootFS.WriteFile("folder/[org]/[project]/create.html", []byte("test-create"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"folder/[org]/[project]/create.html": &fstest.MapFile{
Data: []byte("test-create"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/folder/org-1/project-1/create")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, string(body), "test-create")
require.Equal(t, res.StatusCode, 200)
require.NoError(t, res.Body.Close())
require.Equal(t, http.StatusOK, res.StatusCode)
require.EqualValues(t, "test-create", body)
})
t.Run("Handles catch-all routes", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.MkdirAll("folder", 0777)
require.NoError(t, err)
err = rootFS.WriteFile("folder/[[...any]].html", []byte("test-catch-all"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"folder/[[...any]].html": &fstest.MapFile{
Data: []byte("test-catch-all"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/folder/org-1/project-1/random")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, string(body), "test-catch-all")
require.Equal(t, res.StatusCode, 200)
require.NoError(t, res.Body.Close())
require.Equal(t, http.StatusOK, res.StatusCode)
require.EqualValues(t, "test-catch-all", body)
})
t.Run("Static routes should be preferred to dynamic routes", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.MkdirAll("folder", 0777)
require.NoError(t, err)
err = rootFS.WriteFile("folder/[orgs].html", []byte("test-dynamic-path"), 0755)
require.NoError(t, err)
err = rootFS.WriteFile("folder/create.html", []byte("test-create"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"folder/[orgs].html": &fstest.MapFile{
Data: []byte("test-dynamic-path"),
},
"folder/create.html": &fstest.MapFile{
Data: []byte("test-create"),
},
}
router, err := nextrouter.Handler(rootFS, nil)
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/folder/create")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, string(body), "test-create")
require.Equal(t, res.StatusCode, 200)
require.NoError(t, res.Body.Close())
require.Equal(t, http.StatusOK, res.StatusCode)
require.EqualValues(t, "test-create", body)
})
t.Run("Injects template parameters", func(t *testing.T) {
t.Parallel()
rootFS := memfs.New()
err := rootFS.WriteFile("test.html", []byte("{{ .CSRF.Token }}"), 0755)
require.NoError(t, err)
rootFS := fstest.MapFS{
"test.html": &fstest.MapFile{
Data: []byte("{{ .CSRF.Token }}"),
},
}
type csrfState struct {
Token string
@@ -348,25 +407,32 @@ func TestNextRouter(t *testing.T) {
TemplateDataFunc: templateFunc,
})
require.NoError(t, err)
server := httptest.NewServer(router)
t.Cleanup(server.Close)
res, err := request(server, "/test.html")
require.NoError(t, err)
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
require.NoError(t, err)
require.Equal(t, string(body), "hello-csrf")
require.Equal(t, res.StatusCode, 200)
require.NoError(t, res.Body.Close())
require.Equal(t, http.StatusOK, res.StatusCode)
require.EqualValues(t, "hello-csrf", body)
})
}
func request(server *httptest.Server, path string) (*http.Response, error) {
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, server.URL+path, nil)
ctx, cancelFunc := context.WithTimeout(context.Background(), 1*time.Second)
defer cancelFunc()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, server.URL+path, nil)
if err != nil {
return nil, err
}
res, err := http.DefaultClient.Do(req)
res, err := server.Client().Do(req)
if err != nil {
return nil, err
}