Files
new-api-custom/middleware/frontend_static_test.go

107 lines
3.8 KiB
Go

package middleware
import (
"bytes"
"compress/gzip"
"io"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"sync/atomic"
"testing"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type countingFrontendFS struct {
static.ServeFileSystem
opens atomic.Int32
}
func (f *countingFrontendFS) Open(name string) (http.File, error) {
f.opens.Add(1)
return f.ServeFileSystem.Open(name)
}
func performFrontendRequest(router http.Handler, method, target, acceptEncoding string) *httptest.ResponseRecorder {
recorder := httptest.NewRecorder()
request := httptest.NewRequest(method, target, nil)
if acceptEncoding != "" {
request.Header.Set("Accept-Encoding", acceptEncoding)
}
router.ServeHTTP(recorder, request)
return recorder
}
func TestServeFrontendFilesCompressesEachFileOnce(t *testing.T) {
gin.SetMode(gin.TestMode)
frontendDir := t.TempDir()
script := []byte(strings.Repeat("export const answer = 42;\n", 400))
image := []byte("\x89PNG\r\n\x1a\nnot-really-an-image")
require.NoError(t, os.MkdirAll(filepath.Join(frontendDir, "static", "js"), 0o755))
require.NoError(t, os.WriteFile(filepath.Join(frontendDir, "static", "js", "app.js"), script, 0o644))
require.NoError(t, os.WriteFile(filepath.Join(frontendDir, "logo.png"), image, 0o644))
require.NoError(t, os.WriteFile(filepath.Join(frontendDir, "index.html"), []byte("<html></html>"), 0o644))
frontendFS := &countingFrontendFS{ServeFileSystem: static.LocalFile(frontendDir, false)}
router := gin.New()
router.NoRoute(ServeFrontendFiles(frontendFS), func(c *gin.Context) {
c.String(http.StatusTeapot, "fallback")
})
plain := performFrontendRequest(router, http.MethodGet, "/static/js/app.js", "")
require.Equal(t, http.StatusOK, plain.Code)
assert.Empty(t, plain.Header().Get("Content-Encoding"))
assert.Equal(t, script, plain.Body.Bytes())
frontendFS.opens.Store(0)
responses := make([]*httptest.ResponseRecorder, 8)
var wg sync.WaitGroup
for i := range responses {
wg.Go(func() {
responses[i] = performFrontendRequest(router, http.MethodGet, "/static/js/app.js", "gzip, deflate, br")
})
}
wg.Wait()
for _, response := range responses {
require.Equal(t, http.StatusOK, response.Code)
assert.Equal(t, "gzip", response.Header().Get("Content-Encoding"))
assert.Equal(t, "Accept-Encoding", response.Header().Get("Vary"))
assert.Equal(t, plain.Header().Get("Content-Type"), response.Header().Get("Content-Type"))
assert.Equal(t, strconv.Itoa(response.Body.Len()), response.Header().Get("Content-Length"))
assert.Equal(t, responses[0].Body.Bytes(), response.Body.Bytes())
}
reader, err := gzip.NewReader(bytes.NewReader(responses[0].Body.Bytes()))
require.NoError(t, err)
decoded, err := io.ReadAll(reader)
require.NoError(t, err)
assert.Equal(t, script, decoded)
head := performFrontendRequest(router, http.MethodHead, "/static/js/app.js", "gzip")
assert.Equal(t, http.StatusOK, head.Code)
assert.Equal(t, "gzip", head.Header().Get("Content-Encoding"))
assert.Equal(t, strconv.Itoa(responses[0].Body.Len()), head.Header().Get("Content-Length"))
assert.Empty(t, head.Body.Bytes())
assert.Equal(t, int32(1), frontendFS.opens.Load(), "the file must be read and compressed once")
png := performFrontendRequest(router, http.MethodGet, "/logo.png", "gzip")
assert.Equal(t, http.StatusOK, png.Code)
assert.Empty(t, png.Header().Get("Content-Encoding"))
assert.Equal(t, image, png.Body.Bytes())
index := performFrontendRequest(router, http.MethodGet, "/index.html", "gzip")
assert.Equal(t, http.StatusMovedPermanently, index.Code)
assert.Equal(t, "./", index.Header().Get("Location"))
missing := performFrontendRequest(router, http.MethodGet, "/static/js/missing.js", "gzip")
assert.Equal(t, http.StatusTeapot, missing.Code)
assert.Equal(t, "fallback", missing.Body.String())
}