Refactor: split monolith into cmd/palette + internal/{store,api,web,lang} (#35)
CI / test (push) Successful in 19s
CI / docker (push) Failing after 2m7s

This commit is contained in:
2026-09-09 01:33:39 -05:00
parent a3349b4a98
commit 4f1e901f04
43 changed files with 1251 additions and 1203 deletions
+100
View File
@@ -0,0 +1,100 @@
package api
import (
"net/http/httptest"
"strings"
"testing"
)
// #33 sweep: the create API must enforce the same expiry window as the UI
// (1 minute .. 1 year). Previously -1h, 0s, 1ns and 30000h were all accepted,
// producing pastes that were born expired or effectively permanent.
func TestCreatePasteExpiryBounds(t *testing.T) {
s := testServer(t)
h := s.routes()
cases := []struct {
expiresIn string
wantCode int
}{
{"-1h", 400},
{"-0s", 400},
{"0s", 400},
{"1ns", 400},
{"59s", 400},
{"1m", 201},
{"90s", 201},
{"8760h", 201}, // exactly 1 year
{"8785h", 400}, // 1 year + 1 day: over the max
{"30000h", 400}, // ~3.4 years, over the max
}
globalLimiter = newLimiter() // one fresh bucket for the whole table
for _, c := range cases {
globalLimiter = newLimiter() // avoid create rate limit between cases
req := httptest.NewRequest("POST", "/api/pastes",
strings.NewReader(`{"content":"x","expires_in":"`+c.expiresIn+`"}`))
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != c.wantCode {
t.Errorf("expires_in %q: got %d want %d (%s)",
c.expiresIn, rec.Code, c.wantCode, rec.Body.String())
}
}
}
// #33 sweep: HTML paste views must increment view_count. The increment was
// missing from handlePasteView, so the counter only moved on /raw.
func TestPasteViewIncrementsViewCount(t *testing.T) {
s := testServer(t)
h := s.routes()
req := httptest.NewRequest("POST", "/api/pastes", strings.NewReader(`{"content":"vc"}`))
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
id := jsonField(t, rec.Body.String(), "id")
// first render counts (no ?created=1 here: that's the just-created banner case)
req = httptest.NewRequest("GET", "/"+id, nil)
rec = httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != 200 {
t.Fatalf("view: got %d", rec.Code)
}
req = httptest.NewRequest("GET", "/"+id, nil)
rec = httptest.NewRecorder()
h.ServeHTTP(rec, req)
req = httptest.NewRequest("GET", "/api/pastes/"+id, nil)
rec = httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != 200 {
t.Fatalf("api get: got %d", rec.Code)
}
body := rec.Body.String()
if !strings.Contains(body, `"view_count":2`) {
t.Fatalf("expected view_count 2 after two HTML views, got: %s", body)
}
}
// #33 sweep: the just-created banner render (?created=1) must NOT count as a
// view for the creator.
func TestJustCreatedViewDoesNotCount(t *testing.T) {
s := testServer(t)
h := s.routes()
req := httptest.NewRequest("POST", "/api/pastes", strings.NewReader(`{"content":"jc"}`))
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
id := jsonField(t, rec.Body.String(), "id")
req = httptest.NewRequest("GET", "/"+id+"?created=1&token=t", nil)
rec = httptest.NewRecorder()
h.ServeHTTP(rec, req)
req = httptest.NewRequest("GET", "/api/pastes/"+id, nil)
rec = httptest.NewRecorder()
h.ServeHTTP(rec, req)
if strings.Contains(rec.Body.String(), `"view_count":1`) {
t.Fatalf("just-created render counted as a view: %s", rec.Body.String())
}
}