Release v0.2.34

This commit is contained in:
ponzischeme89
2026-08-09 08:25:50 +12:00
parent b1128bcce2
commit fdd9e6cab2
116 changed files with 11418 additions and 879 deletions
+69
View File
@@ -1,6 +1,7 @@
package api
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
@@ -277,6 +278,74 @@ func TestSearchHistoryResponseEncodesEmptyQueriesAsArray(t *testing.T) {
}
}
// Both routes that write search_history apply one rule, so a query /v1/search records is
// exactly one /v1/search/history would have accepted. The length is counted in runes:
// bytes would reject a Japanese title at a third of an English one's length.
func TestSearchQueryRecordable(t *testing.T) {
long := strings.Repeat("a", maxSearchQueryRunes)
for _, tc := range []struct {
name string
term string
want bool
}{
{"ordinary", "titanic", true},
{"at the floor", "up", true},
{"one letter", "u", false},
{"blank", " ", false},
{"padded is measured trimmed", " up ", true},
{"at the ceiling", long, true},
{"past the ceiling", long + "a", false},
{"multibyte counted as runes", strings.Repeat("あ", maxSearchQueryRunes), true},
} {
t.Run(tc.name, func(t *testing.T) {
if got := searchQueryRecordable(tc.term); got != tc.want {
t.Fatalf("searchQueryRecordable(%q) = %v, want %v", tc.term, got, tc.want)
}
})
}
}
// A search whose viewer no longer has a session keeps its row: the query is what the page
// is for, and an id still tells one searcher from another.
func TestNameSearchEventsKeepsUnattributedRows(t *testing.T) {
events := []store.SearchEvent{
{Query: "severance", UserID: "u-1"},
{Query: "dune", UserID: "gone"},
}
users := []store.KnownUser{
{ID: "u-1", Username: "matt"},
{ID: "u-2", Username: "sam"},
}
got := nameSearchEvents(events, users)
if len(got) != 2 {
t.Fatalf("event count = %d, want 2", len(got))
}
if got[0].Username != "matt" {
t.Fatalf("username = %q, want matt", got[0].Username)
}
if got[1].Username != "" || got[1].Query != "dune" {
t.Fatalf("unattributed event = %+v, want an empty name and its query", got[1])
}
}
// The page must not offer a window the table cannot fill: RecordSearch prunes to the
// retention period, so a wider one would draw a flat line for the difference.
func TestSearchWindowMatchesRetention(t *testing.T) {
if searchWindowDays != 30 {
t.Fatalf("search window = %d days, want 30 to match store.SearchRetention", searchWindowDays)
}
}
// Recording must never be what stops a search being answered. A gateway with no database
// reaches this on every keystroke, so the guard comes before anything that could panic on
// a half-built server.
func TestRecordSearchQueryWithoutStoreIsSilent(t *testing.T) {
s := &Server{}
s.recordSearchQuery(context.Background(), store.Session{EmbyUserID: "u1"}, "titanic")
}
// The fixed rows must keep their order, ids and kinds: the client maps kinds onto
// card shapes and uses ids as Compose keys.
func TestBaseRowsShape(t *testing.T) {