Files

132 lines
3.7 KiB
Go

package store
import (
"context"
"errors"
"testing"
"time"
)
func int64ptr(v int64) *int64 { return &v }
func boolptr(v bool) *bool { return &v }
func TestHostRepoStatsRoundTrip(t *testing.T) {
t.Parallel()
s := openTestStore(t)
ctx := context.Background()
const hostID = "h-stats-test"
seedHost(t, s, hostID)
// 1. Initial upsert: set TotalSizeBytes only.
if err := s.UpsertHostRepoStats(ctx, hostID, HostRepoStats{
TotalSizeBytes: int64ptr(100),
}); err != nil {
t.Fatalf("upsert 1: %v", err)
}
got, err := s.GetHostRepoStats(ctx, hostID)
if err != nil {
t.Fatalf("get after upsert 1: %v", err)
}
if got.TotalSizeBytes == nil || *got.TotalSizeBytes != 100 {
t.Errorf("TotalSizeBytes: want 100, got %v", got.TotalSizeBytes)
}
if got.LastCheckStatus != "" {
t.Errorf("LastCheckStatus should be empty after first upsert, got %q", got.LastCheckStatus)
}
// 2. Upsert with LastCheckStatus; TotalSizeBytes must be preserved.
if err := s.UpsertHostRepoStats(ctx, hostID, HostRepoStats{
LastCheckStatus: "ok",
}); err != nil {
t.Fatalf("upsert 2: %v", err)
}
got, err = s.GetHostRepoStats(ctx, hostID)
if err != nil {
t.Fatalf("get after upsert 2: %v", err)
}
if got.TotalSizeBytes == nil || *got.TotalSizeBytes != 100 {
t.Errorf("TotalSizeBytes should still be 100 after second upsert, got %v", got.TotalSizeBytes)
}
if got.LastCheckStatus != "ok" {
t.Errorf("LastCheckStatus: want %q, got %q", "ok", got.LastCheckStatus)
}
// 3. Upsert with LockPresent=true; all other fields preserved.
now := time.Now().UTC().Truncate(time.Second)
if err := s.UpsertHostRepoStats(ctx, hostID, HostRepoStats{
LockPresent: boolptr(true),
LastCheckAt: &now,
}); err != nil {
t.Fatalf("upsert 3: %v", err)
}
got, err = s.GetHostRepoStats(ctx, hostID)
if err != nil {
t.Fatalf("get after upsert 3: %v", err)
}
if got.LockPresent == nil || !*got.LockPresent {
t.Error("LockPresent should be true after upsert 3")
}
if got.TotalSizeBytes == nil || *got.TotalSizeBytes != 100 {
t.Errorf("TotalSizeBytes still 100 expected, got %v", got.TotalSizeBytes)
}
if got.LastCheckStatus != "ok" {
t.Errorf("LastCheckStatus still 'ok' expected, got %q", got.LastCheckStatus)
}
if got.LastCheckAt == nil {
t.Error("LastCheckAt should be set")
} else if !got.LastCheckAt.UTC().Truncate(time.Second).Equal(now) {
t.Errorf("LastCheckAt: got %v, want %v", got.LastCheckAt.UTC().Truncate(time.Second), now)
}
// 4. Clear lock (set to false).
if err := s.UpsertHostRepoStats(ctx, hostID, HostRepoStats{
LockPresent: boolptr(false),
}); err != nil {
t.Fatalf("upsert 4: %v", err)
}
got, err = s.GetHostRepoStats(ctx, hostID)
if err != nil {
t.Fatalf("get after upsert 4: %v", err)
}
if got.LockPresent == nil || *got.LockPresent {
t.Error("LockPresent should be false after upsert 4")
}
}
func TestHostRepoStatsNotFound(t *testing.T) {
t.Parallel()
s := openTestStore(t)
ctx := context.Background()
_, err := s.GetHostRepoStats(ctx, "no-such-host")
if !errors.Is(err, ErrNotFound) {
t.Errorf("expected ErrNotFound, got %v", err)
}
}
func TestHostRepoStatsCascadeDelete(t *testing.T) {
t.Parallel()
s := openTestStore(t)
ctx := context.Background()
const hostID = "h-cascade-test"
seedHost(t, s, hostID)
if err := s.UpsertHostRepoStats(ctx, hostID, HostRepoStats{
TotalSizeBytes: int64ptr(999),
}); err != nil {
t.Fatalf("upsert: %v", err)
}
// Delete the host; stats row should cascade-delete.
if _, err := s.DB().ExecContext(ctx,
`DELETE FROM hosts WHERE id = ?`, hostID); err != nil {
t.Fatalf("delete host: %v", err)
}
_, err := s.GetHostRepoStats(ctx, hostID)
if !errors.Is(err, ErrNotFound) {
t.Errorf("after host delete, expected ErrNotFound for stats; got %v", err)
}
}