Skip to content
quarry Artifact [952fbc9890]
Login

Artifact [952fbc9890]

Artifact 952fbc98906a9b156627cd38d7cd9466f20fbe7ff728a786057fbb3a1cb530e5:


package web

import (
	"bytes"
	"context"
	"io"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/api"
	"craftdesign.group/quarry/internal/ops"
)

// Every script quarry writes is served smaller than its source and
// parses cleanly: the minifier reporting an error here is the same
// error that would have served the source as written in production.
func TestQuarrysScriptsAreCompacted(t *testing.T) {
	if assetsRaw {
		t.Fatal("FAIL: QUARRY_ASSETS_RAW is set in a test run; the served assets would be the sources")
	}
	scripts := []struct {
		name     string
		src, out []byte
	}{
		{"composer.js", composerJS, composerOut}, {"wiki.js", wikiJS, wikiOut},
		{"draft.js", draftJS, draftOut},
		{"copy.js", copyJS, copyOut}, {"onerror.js", onerrorJS, onerrorOut},
		{"activity.js", activityJS, activityJSOut}, {"chat.js", chatJS, chatOut},
		{"settings.js", settingsJS, settingsOut},
	}
	for _, a := range scripts {
		if _, err := minifier.Bytes("text/javascript", a.src); err != nil {
			t.Errorf("FAIL: %s does not minify: %v", a.name, err)
		}
		if len(a.out) == 0 || len(a.out) >= len(a.src) {
			t.Errorf("FAIL: %s served at %d bytes from a %d-byte source", a.name, len(a.out), len(a.src))
		}
	}
	// datastar is vendored minified and passed through untouched.
	if !bytes.Equal(datastarOut, datastarJS) {
		t.Error("FAIL: the vendored datastar bundle was re-minified")
	}
	t.Logf("ok: %d scripts are served compact", len(scripts))
}

// The wire carries the compact bytes under the hashed name: the name is
// the hash of what is served, and what is served is not the source.
func TestAssetsAreServedCompactUnderTheirHash(t *testing.T) {
	r := ops.NewRegistry()
	if err := api.RegisterAll(r, api.Deps{Version: "0.1.0-test", Repos: api.NewRepos(map[string]*api.Repo{})}); err != nil {
		t.Fatal(err)
	}
	srv := httptest.NewServer(HandlerWith(r, nil, nil, nil,
		Verify(func(string, string, string, ops.Auth) api.Decision { return api.Denied })))
	t.Cleanup(srv.Close)
	for _, a := range []struct {
		url  string
		out  []byte
		name string
	}{{onerrorURL, onerrorOut, "onerror"}, {activityJSURL, activityJSOut, "activity"}} {
		if hashedAsset(a.name, a.out) != a.url {
			t.Errorf("FAIL: %s's URL is not the hash of its served bytes", a.name)
		}
		req, _ := http.NewRequestWithContext(context.Background(), "GET", srv.URL+a.url, nil)
		resp, err := srv.Client().Do(req)
		if err != nil {
			t.Fatal(err)
		}
		got, _ := io.ReadAll(resp.Body)
		resp.Body.Close()
		if resp.StatusCode != 200 || !bytes.Equal(got, a.out) {
			t.Errorf("FAIL: %s served %d bytes with status %d, want the %d compact bytes", a.name, len(got), resp.StatusCode, len(a.out))
		}
		if !strings.Contains(resp.Header.Get("Cache-Control"), "immutable") {
			t.Errorf("FAIL: %s is not immutable: %q", a.name, resp.Header.Get("Cache-Control"))
		}
	}
	t.Log("ok: hashed URLs serve the compact bytes, immutably")
}