0.1.38 gateway
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The filter predicate is the one piece of this feature worth pinning without a database:
|
||||
// it is built by string concatenation with hand-numbered placeholders, and the failure it
|
||||
// can produce is not a compile error or a crash but a *wrong answer* — a page of somebody
|
||||
// else's sign-ins, or a total that does not match the rows above it.
|
||||
|
||||
func TestLoginWhereIsEmptyForAnEmptyFilter(t *testing.T) {
|
||||
where, args := loginWhere(LoginFilter{})
|
||||
if where != "TRUE" {
|
||||
t.Fatalf("an unfiltered history should match everything, got %q", where)
|
||||
}
|
||||
if len(args) != 0 {
|
||||
t.Fatalf("no filter means no arguments, got %v", args)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoginWhereNumbersPlaceholdersInOrder(t *testing.T) {
|
||||
// Every argument must be referenced exactly once, by its own position. A duplicated or
|
||||
// skipped number is how one filter silently applies another's value.
|
||||
where, args := loginWhere(LoginFilter{
|
||||
EmbyUserID: "user-1",
|
||||
DeviceID: "device-1",
|
||||
IPAddress: "10.0.0.9",
|
||||
From: time.Now().Add(-time.Hour),
|
||||
To: time.Now(),
|
||||
Method: LoginMethodPassword,
|
||||
})
|
||||
if len(args) != 6 {
|
||||
t.Fatalf("expected six bound values, got %d (%v)", len(args), args)
|
||||
}
|
||||
for position := 1; position <= len(args); position++ {
|
||||
placeholder := "$" + itoa(position)
|
||||
if strings.Count(where, placeholder) != 1 {
|
||||
t.Fatalf("placeholder %s appears %d times in %q",
|
||||
placeholder, strings.Count(where, placeholder), where)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoginWhereQueryReusesOneArgumentAcrossThreeColumns(t *testing.T) {
|
||||
// The free-text control searches three columns from a single bound value. If it ever
|
||||
// bound three, every later placeholder would be numbered wrongly.
|
||||
where, args := loginWhere(LoginFilter{Query: "lounge"})
|
||||
if len(args) != 1 {
|
||||
t.Fatalf("free text should bind one value, got %d", len(args))
|
||||
}
|
||||
if strings.Count(where, "$1") != 3 {
|
||||
t.Fatalf("free text should search three columns, got %q", where)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoginWhereOutcomeBindsNothing(t *testing.T) {
|
||||
// Outcome is a literal predicate rather than a bound value; if it ever consumed an
|
||||
// argument slot without appending to args, the numbering after it would be wrong.
|
||||
for _, outcome := range []string{"success", "failure"} {
|
||||
where, args := loginWhere(LoginFilter{Outcome: outcome, DeviceID: "device-1"})
|
||||
if len(args) != 1 {
|
||||
t.Fatalf("%s: expected one bound value, got %d", outcome, len(args))
|
||||
}
|
||||
if !strings.Contains(where, "$1") {
|
||||
t.Fatalf("%s: the device filter lost its placeholder: %q", outcome, where)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoginWhereIgnoresBlankAndWhitespaceFilters(t *testing.T) {
|
||||
// The console sends empty controls as empty strings. A blank that reached the query
|
||||
// would match no rows at all rather than every row, which reads as "this television
|
||||
// has never connected".
|
||||
where, args := loginWhere(LoginFilter{EmbyUserID: " ", DeviceID: "", IPAddress: "\t"})
|
||||
if where != "TRUE" || len(args) != 0 {
|
||||
t.Fatalf("blank filters should not narrow anything, got %q %v", where, args)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoginWhereUnknownOutcomeMatchesBoth(t *testing.T) {
|
||||
// An outcome the server does not recognise must mean "any", not "none": the filter is
|
||||
// a convenience, and a typo in a bookmarked URL should not empty the page.
|
||||
where, _ := loginWhere(LoginFilter{Outcome: "maybe"})
|
||||
if strings.Contains(where, "success") {
|
||||
t.Fatalf("an unrecognised outcome should not filter, got %q", where)
|
||||
}
|
||||
}
|
||||
|
||||
func itoa(value int) string {
|
||||
if value == 0 {
|
||||
return "0"
|
||||
}
|
||||
digits := ""
|
||||
for value > 0 {
|
||||
digits = string(rune('0'+value%10)) + digits
|
||||
value /= 10
|
||||
}
|
||||
return digits
|
||||
}
|
||||
Reference in New Issue
Block a user