74 lines
2.9 KiB
Go
74 lines
2.9 KiB
Go
package http
|
|
|
|
import (
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// Review PERF-2: page search treats % and _ literally and is backed by the
|
|
// trigram indexes introduced alongside the escaping change.
|
|
func TestPageSearchEscapesWildcards(t *testing.T) {
|
|
srv, d := testServerDB(t)
|
|
alice, _ := accountClient(t, srv.URL, "pagesearch@computer.test")
|
|
other, _ := accountClient(t, srv.URL, "pagesearch-other@computer.test")
|
|
|
|
alice.request("POST", "/api/pages", map[string]any{"title": "100% done", "content": "literal percent"}, 201)
|
|
alice.request("POST", "/api/pages", map[string]any{"title": "100x done", "content": "not a percent"}, 201)
|
|
alice.request("POST", "/api/pages", map[string]any{"title": "snake_case", "content": "underscore"}, 201)
|
|
alice.request("POST", "/api/pages", map[string]any{"title": "snakeXcase", "content": "not an underscore"}, 201)
|
|
other.request("POST", "/api/pages", map[string]any{"title": "100% private", "content": "someone else"}, 201)
|
|
|
|
search := func(term string) []map[string]any {
|
|
return alice.getJSON("/api/pages?search="+url.QueryEscape(term), 200)
|
|
}
|
|
if got := search("100%"); len(got) != 1 || got[0]["title"] != "100% done" {
|
|
t.Fatalf("literal %% search returned %v", got)
|
|
}
|
|
if got := search("snake_"); len(got) != 1 || got[0]["title"] != "snake_case" {
|
|
t.Fatalf("literal _ search returned %v", got)
|
|
}
|
|
if got := search("100x"); len(got) != 1 || got[0]["title"] != "100x done" {
|
|
t.Fatalf("plain substring search returned %v", got)
|
|
}
|
|
|
|
for _, idx := range []string{"Page_title_trgm_idx", "Page_content_trgm_idx"} {
|
|
var n int
|
|
if e := d.QueryRow(`SELECT count(*) FROM pg_indexes WHERE schemaname=current_schema() AND indexname=$1`, idx).Scan(&n); e != nil || n != 1 {
|
|
t.Fatalf("missing page search index %s: n=%d err=%v", idx, n, e)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Review "cap input sizes": per-field limits reject absurd values with a 400
|
|
// instead of persisting them (the 1 MiB body cap alone is too coarse).
|
|
func TestTextFieldSizeLimits(t *testing.T) {
|
|
srv := testServer(t)
|
|
alice, _ := accountClient(t, srv.URL, "limits@computer.test")
|
|
|
|
const (
|
|
urlLimit = 2048
|
|
titleLimit = 500
|
|
tagNameLimit = 80
|
|
contentLimit = 512 << 10
|
|
)
|
|
alice.request("POST", "/api/bookmarks", map[string]any{
|
|
"url": "https://example.org/" + strings.Repeat("u", urlLimit),
|
|
"title": "too long",
|
|
}, 400)
|
|
alice.request("POST", "/api/bookmarks", map[string]any{
|
|
"url": "https://example.org/ok",
|
|
"title": strings.Repeat("t", titleLimit+1),
|
|
}, 400)
|
|
alice.request("POST", "/api/tags", map[string]any{"name": strings.Repeat("n", tagNameLimit+1)}, 400)
|
|
alice.request("POST", "/api/pages", map[string]any{
|
|
"title": "huge",
|
|
"content": strings.Repeat("x", contentLimit+1),
|
|
}, 400)
|
|
|
|
// The boundary itself remains accepted.
|
|
if got := alice.request("POST", "/api/tags", map[string]any{"name": strings.Repeat("n", tagNameLimit)}, 201); got["name"] != strings.Repeat("n", tagNameLimit) {
|
|
t.Fatal("boundary-length tag rejected or altered")
|
|
}
|
|
}
|