- Add logs and debug end-to-end tests - Add test helper utilities - Improve test fixtures and templates - Update API server and config lint commands - Add multi-user database initialization
225 lines
4.6 KiB
Go
225 lines
4.6 KiB
Go
package helpers
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/jfraeys/fetch_ml/internal/api/helpers"
|
|
)
|
|
|
|
func TestDBContext(t *testing.T) {
|
|
ctx, cancel := helpers.DBContext(3 * time.Second)
|
|
defer cancel()
|
|
|
|
deadline, ok := ctx.Deadline()
|
|
if !ok {
|
|
t.Error("expected deadline to be set")
|
|
}
|
|
|
|
// Deadline should be within a reasonable time window
|
|
now := time.Now()
|
|
if deadline.Before(now) {
|
|
t.Error("deadline is in the past")
|
|
}
|
|
if deadline.After(now.Add(4 * time.Second)) {
|
|
t.Error("deadline is too far in the future")
|
|
}
|
|
|
|
// Context should not be cancelled
|
|
select {
|
|
case <-ctx.Done():
|
|
t.Error("context should not be cancelled yet")
|
|
default:
|
|
// Good
|
|
}
|
|
}
|
|
|
|
func TestDBContextShort(t *testing.T) {
|
|
ctx, cancel := helpers.DBContextShort()
|
|
defer cancel()
|
|
|
|
deadline, ok := ctx.Deadline()
|
|
if !ok {
|
|
t.Error("expected deadline to be set")
|
|
}
|
|
|
|
now := time.Now()
|
|
diff := deadline.Sub(now)
|
|
|
|
// Should be around 3 seconds
|
|
if diff < 2*time.Second || diff > 4*time.Second {
|
|
t.Errorf("expected deadline ~3s, got %v", diff)
|
|
}
|
|
}
|
|
|
|
func TestDBContextMedium(t *testing.T) {
|
|
ctx, cancel := helpers.DBContextMedium()
|
|
defer cancel()
|
|
|
|
deadline, ok := ctx.Deadline()
|
|
if !ok {
|
|
t.Error("expected deadline to be set")
|
|
}
|
|
|
|
now := time.Now()
|
|
diff := deadline.Sub(now)
|
|
|
|
// Should be around 5 seconds
|
|
if diff < 4*time.Second || diff > 6*time.Second {
|
|
t.Errorf("expected deadline ~5s, got %v", diff)
|
|
}
|
|
}
|
|
|
|
func TestDBContextLong(t *testing.T) {
|
|
ctx, cancel := helpers.DBContextLong()
|
|
defer cancel()
|
|
|
|
deadline, ok := ctx.Deadline()
|
|
if !ok {
|
|
t.Error("expected deadline to be set")
|
|
}
|
|
|
|
now := time.Now()
|
|
diff := deadline.Sub(now)
|
|
|
|
// Should be around 10 seconds
|
|
if diff < 9*time.Second || diff > 11*time.Second {
|
|
t.Errorf("expected deadline ~10s, got %v", diff)
|
|
}
|
|
}
|
|
|
|
func TestDBContextCancellation(t *testing.T) {
|
|
ctx, cancel := helpers.DBContextShort()
|
|
|
|
// Cancel immediately
|
|
cancel()
|
|
|
|
// Context should be cancelled
|
|
select {
|
|
case <-ctx.Done():
|
|
// Good - context was cancelled
|
|
default:
|
|
t.Error("context should be cancelled after calling cancel()")
|
|
}
|
|
|
|
// Check error
|
|
if ctx.Err() == nil {
|
|
t.Error("expected non-nil error after cancellation")
|
|
}
|
|
}
|
|
|
|
func TestStringSliceContains(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
slice []string
|
|
item string
|
|
want bool
|
|
}{
|
|
{
|
|
name: "contains",
|
|
slice: []string{"a", "b", "c"},
|
|
item: "b",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "not contains",
|
|
slice: []string{"a", "b", "c"},
|
|
item: "d",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "empty slice",
|
|
slice: []string{},
|
|
item: "a",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "nil slice",
|
|
slice: nil,
|
|
item: "a",
|
|
want: false,
|
|
},
|
|
{
|
|
name: "empty string item",
|
|
slice: []string{"a", "", "c"},
|
|
item: "",
|
|
want: true,
|
|
},
|
|
{
|
|
name: "case sensitive",
|
|
slice: []string{"Apple", "Banana"},
|
|
item: "apple",
|
|
want: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := helpers.StringSliceContains(tt.slice, tt.item)
|
|
if got != tt.want {
|
|
t.Errorf("StringSliceContains() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStringSliceFilter(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
slice []string
|
|
predicate func(string) bool
|
|
want []string
|
|
}{
|
|
{
|
|
name: "filter by prefix",
|
|
slice: []string{"apple", "banana", "apricot", "cherry"},
|
|
predicate: func(s string) bool { return len(s) > 0 && s[0] == 'a' },
|
|
want: []string{"apple", "apricot"},
|
|
},
|
|
{
|
|
name: "filter empty strings",
|
|
slice: []string{"a", "", "b", "", "c"},
|
|
predicate: func(s string) bool { return s != "" },
|
|
want: []string{"a", "b", "c"},
|
|
},
|
|
{
|
|
name: "all match",
|
|
slice: []string{"a", "b", "c"},
|
|
predicate: func(s string) bool { return true },
|
|
want: []string{"a", "b", "c"},
|
|
},
|
|
{
|
|
name: "none match",
|
|
slice: []string{"a", "b", "c"},
|
|
predicate: func(s string) bool { return false },
|
|
want: []string{},
|
|
},
|
|
{
|
|
name: "empty slice",
|
|
slice: []string{},
|
|
predicate: func(s string) bool { return true },
|
|
want: []string{},
|
|
},
|
|
{
|
|
name: "nil slice",
|
|
slice: nil,
|
|
predicate: func(s string) bool { return true },
|
|
want: []string{},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := helpers.StringSliceFilter(tt.slice, tt.predicate)
|
|
if len(got) != len(tt.want) {
|
|
t.Errorf("StringSliceFilter() returned %d items, want %d", len(got), len(tt.want))
|
|
return
|
|
}
|
|
for i := range got {
|
|
if got[i] != tt.want[i] {
|
|
t.Errorf("StringSliceFilter()[%d] = %q, want %q", i, got[i], tt.want[i])
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|