fetch_ml/tests/unit/api/helpers/db_helpers_test.go
Jeremie Fraeys 7305e2bc21
test: add comprehensive test coverage and command improvements
- 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
2026-02-16 20:38:15 -05:00

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])
}
}
})
}
}