App v0.2.26 and gateway 0.1.20
Client: seek controls, Bazarr subtitle download and cast panel in the player; MDBList ratings strip; episode and schedule detail pages; series pace estimate; what's new panel; install-permission onboarding step; synced per-profile preferences; Emby outage banner. Gateway: rebuilt admin console (one fragment per page), preference history and restore, merged Continue Watching, Emby health probe, subtitle selection and Bazarr download, structured request logging with per-request identity, and embedded build version. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2675e6d82b
commit
4a4df7a73c
@@ -7,24 +7,96 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewWritesReadableStructuredText(t *testing.T) {
|
||||
func TestConsoleLineLeadsWithTimeLevelAndMessage(t *testing.T) {
|
||||
var output bytes.Buffer
|
||||
New(&output, slog.LevelInfo).Info("server ready", "listen", ":8080")
|
||||
New(&output, slog.LevelInfo).Info("gateway ready", "listen", ":8080")
|
||||
|
||||
line := strings.TrimRight(output.String(), "\n")
|
||||
if strings.HasPrefix(line, "{") {
|
||||
t.Fatalf("expected console output, got JSON: %s", line)
|
||||
}
|
||||
// The timestamp is a column, not a field: nothing labelled `time=` may appear in
|
||||
// front of — or anywhere in — the readable part of the line.
|
||||
if strings.Contains(line, "time=") || strings.Contains(line, "msg=") {
|
||||
t.Fatalf("console line still carries slog's own keys: %s", line)
|
||||
}
|
||||
if !strings.Contains(line, "INFO") || !strings.Contains(line, "gateway ready") {
|
||||
t.Fatalf("line is missing its level or message: %s", line)
|
||||
}
|
||||
if !strings.Contains(line, "listen=:8080") {
|
||||
t.Fatalf("line is missing its fields: %s", line)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConsoleLineOrdersIdentityFirstAndErrorLast(t *testing.T) {
|
||||
var output bytes.Buffer
|
||||
New(&output, slog.LevelInfo).Info("playback requested",
|
||||
"error", "nope", "title", "Dune", "user", "matt", "component", "playback",
|
||||
)
|
||||
|
||||
line := output.String()
|
||||
if strings.HasPrefix(strings.TrimSpace(line), "{") {
|
||||
t.Fatalf("expected text output, got JSON: %s", line)
|
||||
}
|
||||
for _, want := range []string{`level=INFO`, `msg="server ready"`, `listen=:8080`} {
|
||||
if !strings.Contains(line, want) {
|
||||
t.Errorf("output %q does not contain %q", line, want)
|
||||
order := []string{"component=playback", "user=matt", "title=Dune", "error=nope"}
|
||||
previous := -1
|
||||
for _, want := range order {
|
||||
at := strings.Index(line, want)
|
||||
if at < 0 {
|
||||
t.Fatalf("output %q does not contain %q", line, want)
|
||||
}
|
||||
if at < previous {
|
||||
t.Fatalf("field %q is out of order in %q", want, line)
|
||||
}
|
||||
previous = at
|
||||
}
|
||||
}
|
||||
|
||||
func TestConsoleQuotesOnlyAmbiguousValues(t *testing.T) {
|
||||
var output bytes.Buffer
|
||||
New(&output, slog.LevelInfo).Info("signed in", "device", "Living Room", "user", "matt")
|
||||
|
||||
line := output.String()
|
||||
if !strings.Contains(line, `device="Living Room"`) {
|
||||
t.Errorf("a value containing a space was not quoted: %s", line)
|
||||
}
|
||||
if !strings.Contains(line, `user=matt`) {
|
||||
t.Errorf("an unambiguous value was quoted: %s", line)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseFormat(t *testing.T) {
|
||||
tests := map[string]Format{
|
||||
"": FormatConsole,
|
||||
"console": FormatConsole,
|
||||
"nonsense": FormatConsole,
|
||||
"json": FormatJSON,
|
||||
" LOGFMT": FormatLogfmt,
|
||||
"text": FormatLogfmt,
|
||||
}
|
||||
for input, want := range tests {
|
||||
if got := ParseFormat(input); got != want {
|
||||
t.Errorf("ParseFormat(%q) = %v, want %v", input, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectedFormatIsWhatGetsWritten(t *testing.T) {
|
||||
var output bytes.Buffer
|
||||
logger, _ := NewBuffered(&output, slog.LevelInfo, 0, FormatJSON)
|
||||
logger.Info("gateway ready")
|
||||
if !strings.HasPrefix(strings.TrimSpace(output.String()), "{") {
|
||||
t.Fatalf("JSON format did not produce JSON: %s", output.String())
|
||||
}
|
||||
|
||||
output.Reset()
|
||||
logger, _ = NewBuffered(&output, slog.LevelInfo, 0, FormatLogfmt)
|
||||
logger.Info("gateway ready")
|
||||
if !strings.Contains(output.String(), `msg="gateway ready"`) {
|
||||
t.Fatalf("logfmt format did not produce logfmt: %s", output.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferedLoggerRetainsStructuredEventsWithCursorPagination(t *testing.T) {
|
||||
var output bytes.Buffer
|
||||
logger, buffer := NewBuffered(&output, slog.LevelDebug, 3)
|
||||
logger, buffer := NewBuffered(&output, slog.LevelDebug, 3, FormatConsole)
|
||||
for i := 1; i <= 5; i++ {
|
||||
logger.Info("request complete", "number", i)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user