Files
AetherForge/server/internal/db/builds_test.go

211 lines
5.3 KiB
Go

package db
import (
"database/sql"
"errors"
"strings"
"testing"
"time"
"crypto-miner-server/internal/models"
)
func insertBuild(t *testing.T, d *Database, b *models.BuildRecord) {
t.Helper()
if err := d.InsertBuild(b); err != nil {
t.Fatal(err)
}
}
func TestBuildCRUDAndList(t *testing.T) {
d := openTestDB(t)
created := time.Now().UTC().Truncate(time.Second)
build := &models.BuildRecord{
ID: "build-001",
WorkerName: "rig1",
ServerURL: "http://localhost:8080",
Wallet: "48xyz",
Threads: 4,
FileSize: 1024,
BundleSize: 2048,
FilePath: "/data/builds/build-001.zip",
FileName: "agent.zip",
DownloadURL: "/api/v1/builds/build-001/download",
Platform: "windows",
CreatedAt: created,
PoolHost: "pool.example.com",
PoolPort: 443,
PoolTLS: true,
PoolPass: "x",
}
insertBuild(t, d, build)
got, err := d.GetBuild("build-001")
if err != nil {
t.Fatal(err)
}
if got.WorkerName != "rig1" || got.Platform != "windows" || got.BundleSize != 2048 {
t.Fatalf("build mismatch: %+v", got)
}
if got.Pinned {
t.Fatal("new build should not be pinned")
}
list, err := d.ListBuilds(10)
if err != nil {
t.Fatal(err)
}
if len(list) != 1 || list[0].ID != "build-001" {
t.Fatalf("list builds: %+v", list)
}
}
func TestGetBuildNotFound(t *testing.T) {
d := openTestDB(t)
_, err := d.GetBuild("missing")
if !errors.Is(err, sql.ErrNoRows) {
t.Fatalf("expected sql.ErrNoRows, got %v", err)
}
}
func TestSetPinnedBuild(t *testing.T) {
d := openTestDB(t)
now := time.Now()
insertBuild(t, d, &models.BuildRecord{ID: "b1", WorkerName: "w", ServerURL: "u", Wallet: "w", CreatedAt: now})
insertBuild(t, d, &models.BuildRecord{ID: "b2", WorkerName: "w", ServerURL: "u", Wallet: "w", CreatedAt: now.Add(time.Second)})
if err := d.SetPinnedBuild("b1"); err != nil {
t.Fatal(err)
}
b1, _ := d.GetBuild("b1")
b2, _ := d.GetBuild("b2")
if !b1.Pinned || b2.Pinned {
t.Fatalf("pin state wrong: b1=%v b2=%v", b1.Pinned, b2.Pinned)
}
if err := d.SetPinnedBuild(""); err != nil {
t.Fatal(err)
}
b1, _ = d.GetBuild("b1")
if b1.Pinned {
t.Fatal("empty id should unpin all builds")
}
}
func TestSetPinnedBuildUnknownID(t *testing.T) {
d := openTestDB(t)
now := time.Now()
insertBuild(t, d, &models.BuildRecord{ID: "b1", WorkerName: "w", ServerURL: "u", Wallet: "w", CreatedAt: now, Pinned: true})
err := d.SetPinnedBuild("missing")
if err == nil {
t.Fatal("expected error for unknown build id")
}
if !strings.Contains(err.Error(), "not found") {
t.Fatalf("unexpected error: %v", err)
}
b1, _ := d.GetBuild("b1")
if b1.Pinned {
t.Fatal("unknown id should leave builds unpinned, not keep prior pin")
}
}
func TestGetLatestBuildForPlatform(t *testing.T) {
d := openTestDB(t)
base := time.Now().UTC().Truncate(time.Second)
insertBuild(t, d, &models.BuildRecord{
ID: "old-linux", WorkerName: "w", ServerURL: "u", Wallet: "w",
Platform: "linux", CreatedAt: base,
})
insertBuild(t, d, &models.BuildRecord{
ID: "new-linux", WorkerName: "w", ServerURL: "u", Wallet: "w",
Platform: "linux", CreatedAt: base.Add(time.Minute),
})
insertBuild(t, d, &models.BuildRecord{
ID: "new-windows", WorkerName: "w", ServerURL: "u", Wallet: "w",
Platform: "windows", CreatedAt: base.Add(2 * time.Minute),
})
latestLinux, err := d.GetLatestBuildForPlatform("linux")
if err != nil {
t.Fatal(err)
}
if latestLinux.ID != "new-linux" {
t.Fatalf("latest linux: got %q", latestLinux.ID)
}
if err := d.SetPinnedBuild("old-linux"); err != nil {
t.Fatal(err)
}
pinnedLinux, err := d.GetLatestBuildForPlatform("linux")
if err != nil {
t.Fatal(err)
}
if pinnedLinux.ID != "old-linux" {
t.Fatalf("pinned linux: got %q", pinnedLinux.ID)
}
anyLatest, err := d.GetLatestBuildForPlatform("any")
if err != nil {
t.Fatal(err)
}
if anyLatest.ID != "old-linux" {
t.Fatalf("any with pinned: got %q want old-linux", anyLatest.ID)
}
if err := d.SetPinnedBuild(""); err != nil {
t.Fatal(err)
}
emptyPlatform, err := d.GetLatestBuildForPlatform("")
if err != nil {
t.Fatal(err)
}
if emptyPlatform.ID != "new-windows" {
t.Fatalf("empty platform latest: got %q", emptyPlatform.ID)
}
}
func TestGetLatestBuildForPlatformEmpty(t *testing.T) {
d := openTestDB(t)
_, err := d.GetLatestBuildForPlatform("linux")
if !errors.Is(err, sql.ErrNoRows) {
t.Fatalf("expected sql.ErrNoRows on empty db, got %v", err)
}
}
func TestListBuildsOlderThanAndDeleteBuild(t *testing.T) {
d := openTestDB(t)
cutoff := time.Now().UTC().Truncate(time.Second)
oldTime := cutoff.Add(-time.Hour)
newTime := cutoff.Add(time.Hour)
insertBuild(t, d, &models.BuildRecord{
ID: "old-build", WorkerName: "w", ServerURL: "u", Wallet: "w", CreatedAt: oldTime,
})
insertBuild(t, d, &models.BuildRecord{
ID: "new-build", WorkerName: "w", ServerURL: "u", Wallet: "w", CreatedAt: newTime,
})
older, err := d.ListBuildsOlderThan(cutoff)
if err != nil {
t.Fatal(err)
}
if len(older) != 1 || older[0].ID != "old-build" {
t.Fatalf("ListBuildsOlderThan: %+v", older)
}
if err := d.DeleteBuild("old-build"); err != nil {
t.Fatal(err)
}
_, err = d.GetBuild("old-build")
if !errors.Is(err, sql.ErrNoRows) {
t.Fatalf("expected deleted build missing, got %v", err)
}
if err := d.DeleteBuild("never-existed"); err != nil {
t.Fatal(err)
}
}