add test for the wall app
Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
parent
c4776d81dd
commit
9e287e4e6a
15 changed files with 3022 additions and 1 deletions
131
internal/store/blocked_test.go
Normal file
131
internal/store/blocked_test.go
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
package store_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/syonad/clonepack/internal/store"
|
||||
)
|
||||
|
||||
func newBlockedStore(t *testing.T) (*store.SQLiteBlockedPackageStore, int64) {
|
||||
t.Helper()
|
||||
db := newTestDB(t)
|
||||
repoID := insertTestRepo(t, db)
|
||||
return store.NewBlockedPackageStore(db), repoID
|
||||
}
|
||||
|
||||
func TestBlockAndListPackages(t *testing.T) {
|
||||
s, repoID := newBlockedStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
pkgs := []store.BlockedPackage{
|
||||
{Name: "curl", Location: "Packages/curl-7.88.rpm"},
|
||||
{Name: "wget", Location: "Packages/wget-1.21.rpm"},
|
||||
}
|
||||
if err := s.BlockPackages(ctx, repoID, pkgs); err != nil {
|
||||
t.Fatalf("BlockPackages: %v", err)
|
||||
}
|
||||
|
||||
listed, err := s.ListBlocked(ctx, repoID)
|
||||
if err != nil {
|
||||
t.Fatalf("ListBlocked: %v", err)
|
||||
}
|
||||
if len(listed) != 2 {
|
||||
t.Fatalf("expected 2 blocked, got %d", len(listed))
|
||||
}
|
||||
if listed[0].Name != "curl" {
|
||||
t.Errorf("expected curl first, got %q", listed[0].Name)
|
||||
}
|
||||
if listed[0].RepoID != repoID {
|
||||
t.Errorf("RepoID: got %d, want %d", listed[0].RepoID, repoID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockPackages_idempotent(t *testing.T) {
|
||||
s, repoID := newBlockedStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
pkg := []store.BlockedPackage{{Name: "curl", Location: "Packages/curl.rpm"}}
|
||||
s.BlockPackages(ctx, repoID, pkg)
|
||||
// INSERT OR IGNORE — should not duplicate.
|
||||
s.BlockPackages(ctx, repoID, pkg)
|
||||
|
||||
listed, _ := s.ListBlocked(ctx, repoID)
|
||||
if len(listed) != 1 {
|
||||
t.Errorf("expected 1 after double block, got %d", len(listed))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnblockPackages(t *testing.T) {
|
||||
s, repoID := newBlockedStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
s.BlockPackages(ctx, repoID, []store.BlockedPackage{
|
||||
{Name: "curl", Location: "Packages/curl.rpm"},
|
||||
{Name: "wget", Location: "Packages/wget.rpm"},
|
||||
})
|
||||
|
||||
listed, _ := s.ListBlocked(ctx, repoID)
|
||||
if len(listed) != 2 {
|
||||
t.Fatalf("setup: expected 2, got %d", len(listed))
|
||||
}
|
||||
|
||||
// Unblock only the first.
|
||||
if err := s.UnblockPackages(ctx, repoID, []int64{listed[0].ID}); err != nil {
|
||||
t.Fatalf("UnblockPackages: %v", err)
|
||||
}
|
||||
|
||||
remaining, _ := s.ListBlocked(ctx, repoID)
|
||||
if len(remaining) != 1 {
|
||||
t.Fatalf("expected 1 remaining, got %d", len(remaining))
|
||||
}
|
||||
if remaining[0].Name != "wget" {
|
||||
t.Errorf("expected wget remaining, got %q", remaining[0].Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnblockPackages_empty(t *testing.T) {
|
||||
s, repoID := newBlockedStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
if err := s.UnblockPackages(ctx, repoID, nil); err != nil {
|
||||
t.Errorf("UnblockPackages(nil): %v", err)
|
||||
}
|
||||
if err := s.UnblockPackages(ctx, repoID, []int64{}); err != nil {
|
||||
t.Errorf("UnblockPackages([]): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListBlocked_empty(t *testing.T) {
|
||||
s, repoID := newBlockedStore(t)
|
||||
listed, err := s.ListBlocked(context.Background(), repoID)
|
||||
if err != nil {
|
||||
t.Fatalf("ListBlocked: %v", err)
|
||||
}
|
||||
if len(listed) != 0 {
|
||||
t.Errorf("expected 0, got %d", len(listed))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockPackages_isolation(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
repoStore := store.NewRepoStore(db)
|
||||
ctx := context.Background()
|
||||
|
||||
id1, _ := repoStore.CreateRepo(ctx, &store.Repo{Name: "repo-1", Type: "rpm", SourceURL: "https://a.com", SyncMode: "auto"})
|
||||
id2, _ := repoStore.CreateRepo(ctx, &store.Repo{Name: "repo-2", Type: "rpm", SourceURL: "https://b.com", SyncMode: "auto"})
|
||||
|
||||
bs := store.NewBlockedPackageStore(db)
|
||||
bs.BlockPackages(ctx, id1, []store.BlockedPackage{{Name: "curl", Location: "pkg/curl.rpm"}})
|
||||
bs.BlockPackages(ctx, id2, []store.BlockedPackage{{Name: "vim", Location: "pkg/vim.rpm"}})
|
||||
|
||||
list1, _ := bs.ListBlocked(ctx, id1)
|
||||
list2, _ := bs.ListBlocked(ctx, id2)
|
||||
|
||||
if len(list1) != 1 || list1[0].Name != "curl" {
|
||||
t.Errorf("repo-1: expected [curl], got %v", list1)
|
||||
}
|
||||
if len(list2) != 1 || list2[0].Name != "vim" {
|
||||
t.Errorf("repo-2: expected [vim], got %v", list2)
|
||||
}
|
||||
}
|
||||
|
|
@ -59,7 +59,7 @@ func (s *SQLiteCloneJobStore) GetCloneJob(ctx context.Context, id int64) (*Clone
|
|||
|
||||
func (s *SQLiteCloneJobStore) GetLatestCloneJob(ctx context.Context, repoID int64) (*CloneJob, error) {
|
||||
row := s.db.QueryRowContext(ctx,
|
||||
`SELECT id, repo_id, status, started_at, finished_at, error, created_at FROM clone_jobs WHERE repo_id = ? ORDER BY created_at DESC LIMIT 1`, repoID)
|
||||
`SELECT id, repo_id, status, started_at, finished_at, error, created_at FROM clone_jobs WHERE repo_id = ? ORDER BY created_at DESC, id DESC LIMIT 1`, repoID)
|
||||
return scanCloneJob(row)
|
||||
}
|
||||
|
||||
|
|
|
|||
165
internal/store/clone_job_test.go
Normal file
165
internal/store/clone_job_test.go
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
package store_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/syonad/clonepack/internal/store"
|
||||
)
|
||||
|
||||
func newCloneJobStore(t *testing.T) (*store.SQLiteCloneJobStore, int64) {
|
||||
t.Helper()
|
||||
db := newTestDB(t)
|
||||
repoID := insertTestRepo(t, db)
|
||||
return store.NewCloneJobStore(db), repoID
|
||||
}
|
||||
|
||||
func TestCreateAndGetCloneJob(t *testing.T) {
|
||||
s, repoID := newCloneJobStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
jobID, err := s.CreateCloneJob(ctx, repoID)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateCloneJob: %v", err)
|
||||
}
|
||||
|
||||
job, err := s.GetCloneJob(ctx, jobID)
|
||||
if err != nil {
|
||||
t.Fatalf("GetCloneJob: %v", err)
|
||||
}
|
||||
if job.RepoID != repoID {
|
||||
t.Errorf("RepoID: got %d, want %d", job.RepoID, repoID)
|
||||
}
|
||||
if job.Status != store.CloneJobPending {
|
||||
t.Errorf("Status: got %q, want pending", job.Status)
|
||||
}
|
||||
if job.StartedAt != nil {
|
||||
t.Errorf("StartedAt should be nil initially")
|
||||
}
|
||||
if job.FinishedAt != nil {
|
||||
t.Errorf("FinishedAt should be nil initially")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCloneJob_notFound(t *testing.T) {
|
||||
s, _ := newCloneJobStore(t)
|
||||
_, err := s.GetCloneJob(context.Background(), 9999)
|
||||
if err != store.ErrNotFound {
|
||||
t.Errorf("expected ErrNotFound, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLatestCloneJob(t *testing.T) {
|
||||
s, repoID := newCloneJobStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
s.CreateCloneJob(ctx, repoID)
|
||||
id2, _ := s.CreateCloneJob(ctx, repoID)
|
||||
|
||||
job, err := s.GetLatestCloneJob(ctx, repoID)
|
||||
if err != nil {
|
||||
t.Fatalf("GetLatestCloneJob: %v", err)
|
||||
}
|
||||
if job.ID != id2 {
|
||||
t.Errorf("expected latest job ID %d, got %d", id2, job.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLatestCloneJob_notFound(t *testing.T) {
|
||||
s, repoID := newCloneJobStore(t)
|
||||
_, err := s.GetLatestCloneJob(context.Background(), repoID)
|
||||
if err != store.ErrNotFound {
|
||||
t.Errorf("expected ErrNotFound, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarkCloneJobStarted(t *testing.T) {
|
||||
s, repoID := newCloneJobStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
jobID, _ := s.CreateCloneJob(ctx, repoID)
|
||||
if err := s.MarkCloneJobStarted(ctx, jobID); err != nil {
|
||||
t.Fatalf("MarkCloneJobStarted: %v", err)
|
||||
}
|
||||
|
||||
job, _ := s.GetCloneJob(ctx, jobID)
|
||||
if job.Status != store.CloneJobRunning {
|
||||
t.Errorf("Status: got %q, want running", job.Status)
|
||||
}
|
||||
if job.StartedAt == nil {
|
||||
t.Error("StartedAt should be set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarkCloneJobFinished_completed(t *testing.T) {
|
||||
s, repoID := newCloneJobStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
jobID, _ := s.CreateCloneJob(ctx, repoID)
|
||||
s.MarkCloneJobStarted(ctx, jobID)
|
||||
if err := s.MarkCloneJobFinished(ctx, jobID, store.CloneJobCompleted, nil); err != nil {
|
||||
t.Fatalf("MarkCloneJobFinished: %v", err)
|
||||
}
|
||||
|
||||
job, _ := s.GetCloneJob(ctx, jobID)
|
||||
if job.Status != store.CloneJobCompleted {
|
||||
t.Errorf("Status: got %q, want completed", job.Status)
|
||||
}
|
||||
if job.FinishedAt == nil {
|
||||
t.Error("FinishedAt should be set")
|
||||
}
|
||||
if job.Error != nil {
|
||||
t.Errorf("Error should be nil, got %q", *job.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarkCloneJobFinished_failed(t *testing.T) {
|
||||
s, repoID := newCloneJobStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
jobID, _ := s.CreateCloneJob(ctx, repoID)
|
||||
s.MarkCloneJobStarted(ctx, jobID)
|
||||
errMsg := "connection refused"
|
||||
if err := s.MarkCloneJobFinished(ctx, jobID, store.CloneJobFailed, &errMsg); err != nil {
|
||||
t.Fatalf("MarkCloneJobFinished: %v", err)
|
||||
}
|
||||
|
||||
job, _ := s.GetCloneJob(ctx, jobID)
|
||||
if job.Status != store.CloneJobFailed {
|
||||
t.Errorf("Status: got %q, want failed", job.Status)
|
||||
}
|
||||
if job.Error == nil || *job.Error != errMsg {
|
||||
t.Errorf("Error: got %v, want %q", job.Error, errMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasRunningCloneJob(t *testing.T) {
|
||||
s, repoID := newCloneJobStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
running, err := s.HasRunningCloneJob(ctx, repoID)
|
||||
if err != nil {
|
||||
t.Fatalf("HasRunningCloneJob: %v", err)
|
||||
}
|
||||
if running {
|
||||
t.Error("expected no running job initially")
|
||||
}
|
||||
|
||||
jobID, _ := s.CreateCloneJob(ctx, repoID)
|
||||
running, _ = s.HasRunningCloneJob(ctx, repoID)
|
||||
if !running {
|
||||
t.Error("expected running job after create (status=pending)")
|
||||
}
|
||||
|
||||
s.MarkCloneJobStarted(ctx, jobID)
|
||||
running, _ = s.HasRunningCloneJob(ctx, repoID)
|
||||
if !running {
|
||||
t.Error("expected running job after start")
|
||||
}
|
||||
|
||||
s.MarkCloneJobFinished(ctx, jobID, store.CloneJobCompleted, nil)
|
||||
running, _ = s.HasRunningCloneJob(ctx, repoID)
|
||||
if running {
|
||||
t.Error("expected no running job after completion")
|
||||
}
|
||||
}
|
||||
139
internal/store/pending_test.go
Normal file
139
internal/store/pending_test.go
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
package store_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/syonad/clonepack/internal/store"
|
||||
)
|
||||
|
||||
func newPendingStore(t *testing.T) (*store.SQLitePendingPackageStore, int64) {
|
||||
t.Helper()
|
||||
db := newTestDB(t)
|
||||
repoID := insertTestRepo(t, db)
|
||||
return store.NewPendingPackageStore(db), repoID
|
||||
}
|
||||
|
||||
func makePending(repoID int64, name, version, location string) store.PendingPackage {
|
||||
return store.PendingPackage{
|
||||
RepoID: repoID,
|
||||
Name: name,
|
||||
Version: version,
|
||||
Arch: "amd64",
|
||||
Location: location,
|
||||
Checksum: "abc123",
|
||||
ChecksumType: "sha256",
|
||||
Size: 1024,
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpsertAndListPending(t *testing.T) {
|
||||
s, repoID := newPendingStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
pkgs := []store.PendingPackage{
|
||||
makePending(repoID, "curl", "7.88", "Packages/curl.rpm"),
|
||||
makePending(repoID, "wget", "1.21", "Packages/wget.rpm"),
|
||||
}
|
||||
if err := s.UpsertPending(ctx, pkgs); err != nil {
|
||||
t.Fatalf("UpsertPending: %v", err)
|
||||
}
|
||||
|
||||
listed, err := s.ListPending(ctx, repoID)
|
||||
if err != nil {
|
||||
t.Fatalf("ListPending: %v", err)
|
||||
}
|
||||
if len(listed) != 2 {
|
||||
t.Fatalf("expected 2 pending, got %d", len(listed))
|
||||
}
|
||||
if listed[0].Name != "curl" {
|
||||
t.Errorf("expected curl first, got %q", listed[0].Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpsertPending_idempotent(t *testing.T) {
|
||||
s, repoID := newPendingStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
pkg := makePending(repoID, "curl", "7.88", "Packages/curl.rpm")
|
||||
s.UpsertPending(ctx, []store.PendingPackage{pkg})
|
||||
// Insert same package again — INSERT OR IGNORE, should not duplicate.
|
||||
s.UpsertPending(ctx, []store.PendingPackage{pkg})
|
||||
|
||||
listed, _ := s.ListPending(ctx, repoID)
|
||||
if len(listed) != 1 {
|
||||
t.Errorf("expected 1 after double upsert, got %d", len(listed))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeletePending_byIDs(t *testing.T) {
|
||||
s, repoID := newPendingStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
pkgs := []store.PendingPackage{
|
||||
makePending(repoID, "curl", "7.88", "Packages/curl.rpm"),
|
||||
makePending(repoID, "wget", "1.21", "Packages/wget.rpm"),
|
||||
makePending(repoID, "vim", "9.0", "Packages/vim.rpm"),
|
||||
}
|
||||
s.UpsertPending(ctx, pkgs)
|
||||
|
||||
listed, _ := s.ListPending(ctx, repoID)
|
||||
if len(listed) != 3 {
|
||||
t.Fatalf("setup: expected 3, got %d", len(listed))
|
||||
}
|
||||
|
||||
// Delete first two.
|
||||
ids := []int64{listed[0].ID, listed[1].ID}
|
||||
if err := s.DeletePending(ctx, ids); err != nil {
|
||||
t.Fatalf("DeletePending: %v", err)
|
||||
}
|
||||
|
||||
remaining, _ := s.ListPending(ctx, repoID)
|
||||
if len(remaining) != 1 {
|
||||
t.Fatalf("expected 1 remaining, got %d", len(remaining))
|
||||
}
|
||||
if remaining[0].Name != "vim" {
|
||||
t.Errorf("expected vim remaining, got %q", remaining[0].Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeletePending_empty(t *testing.T) {
|
||||
s, _ := newPendingStore(t)
|
||||
// Should not error on empty slice.
|
||||
if err := s.DeletePending(context.Background(), nil); err != nil {
|
||||
t.Errorf("DeletePending(nil): %v", err)
|
||||
}
|
||||
if err := s.DeletePending(context.Background(), []int64{}); err != nil {
|
||||
t.Errorf("DeletePending([]): %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteAllPending(t *testing.T) {
|
||||
s, repoID := newPendingStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
s.UpsertPending(ctx, []store.PendingPackage{
|
||||
makePending(repoID, "curl", "7.88", "Packages/curl.rpm"),
|
||||
makePending(repoID, "wget", "1.21", "Packages/wget.rpm"),
|
||||
})
|
||||
|
||||
if err := s.DeleteAllPending(ctx, repoID); err != nil {
|
||||
t.Fatalf("DeleteAllPending: %v", err)
|
||||
}
|
||||
|
||||
remaining, _ := s.ListPending(ctx, repoID)
|
||||
if len(remaining) != 0 {
|
||||
t.Errorf("expected 0 after DeleteAll, got %d", len(remaining))
|
||||
}
|
||||
}
|
||||
|
||||
func TestListPending_empty(t *testing.T) {
|
||||
s, repoID := newPendingStore(t)
|
||||
listed, err := s.ListPending(context.Background(), repoID)
|
||||
if err != nil {
|
||||
t.Fatalf("ListPending: %v", err)
|
||||
}
|
||||
if len(listed) != 0 {
|
||||
t.Errorf("expected 0, got %d", len(listed))
|
||||
}
|
||||
}
|
||||
188
internal/store/repo_test.go
Normal file
188
internal/store/repo_test.go
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
package store_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/syonad/clonepack/internal/store"
|
||||
)
|
||||
|
||||
func newTestStore(t *testing.T) *store.SQLiteRepoStore {
|
||||
t.Helper()
|
||||
return store.NewRepoStore(newTestDB(t))
|
||||
}
|
||||
|
||||
func TestCreateAndGetRepo(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
r := &store.Repo{Name: "test-repo", Type: "rpm", SourceURL: "https://example.com", SyncMode: "auto"}
|
||||
id, err := s.CreateRepo(ctx, r)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateRepo: %v", err)
|
||||
}
|
||||
if id <= 0 {
|
||||
t.Errorf("expected positive id, got %d", id)
|
||||
}
|
||||
|
||||
got, err := s.GetRepo(ctx, id)
|
||||
if err != nil {
|
||||
t.Fatalf("GetRepo: %v", err)
|
||||
}
|
||||
if got.Name != "test-repo" {
|
||||
t.Errorf("Name: got %q, want %q", got.Name, "test-repo")
|
||||
}
|
||||
if got.Type != "rpm" {
|
||||
t.Errorf("Type: got %q, want %q", got.Type, "rpm")
|
||||
}
|
||||
if got.SourceURL != "https://example.com" {
|
||||
t.Errorf("SourceURL: got %q", got.SourceURL)
|
||||
}
|
||||
if got.SyncMode != "auto" {
|
||||
t.Errorf("SyncMode: got %q, want auto", got.SyncMode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRepo_notFound(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
_, err := s.GetRepo(ctx, 9999)
|
||||
if err != store.ErrNotFound {
|
||||
t.Errorf("expected ErrNotFound, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRepoByName(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
r := &store.Repo{Name: "debian-bookworm", Type: "apt", SourceURL: "https://deb.debian.org/debian", SyncMode: "manual", Config: `{"suite":"bookworm"}`}
|
||||
id, err := s.CreateRepo(ctx, r)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateRepo: %v", err)
|
||||
}
|
||||
|
||||
got, err := s.GetRepoByName(ctx, "debian-bookworm")
|
||||
if err != nil {
|
||||
t.Fatalf("GetRepoByName: %v", err)
|
||||
}
|
||||
if got.ID != id {
|
||||
t.Errorf("ID: got %d, want %d", got.ID, id)
|
||||
}
|
||||
if got.Config != `{"suite":"bookworm"}` {
|
||||
t.Errorf("Config: got %q", got.Config)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRepoByName_notFound(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
_, err := s.GetRepoByName(ctx, "does-not-exist")
|
||||
if err != store.ErrNotFound {
|
||||
t.Errorf("expected ErrNotFound, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListRepos(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
repos, err := s.ListRepos(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("ListRepos (empty): %v", err)
|
||||
}
|
||||
if len(repos) != 0 {
|
||||
t.Errorf("expected empty list, got %d repos", len(repos))
|
||||
}
|
||||
|
||||
for _, name := range []string{"repo-a", "repo-b", "repo-c"} {
|
||||
_, err := s.CreateRepo(ctx, &store.Repo{Name: name, Type: "rpm", SourceURL: "https://x.com", SyncMode: "auto"})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateRepo %q: %v", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
repos, err = s.ListRepos(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("ListRepos: %v", err)
|
||||
}
|
||||
if len(repos) != 3 {
|
||||
t.Errorf("expected 3 repos, got %d", len(repos))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteRepo(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
id, _ := s.CreateRepo(ctx, &store.Repo{Name: "to-delete", Type: "rpm", SourceURL: "https://x.com", SyncMode: "auto"})
|
||||
|
||||
if err := s.DeleteRepo(ctx, id); err != nil {
|
||||
t.Fatalf("DeleteRepo: %v", err)
|
||||
}
|
||||
_, err := s.GetRepo(ctx, id)
|
||||
if err != store.ErrNotFound {
|
||||
t.Errorf("expected ErrNotFound after delete, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteRepo_notFound(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
err := s.DeleteRepo(ctx, 9999)
|
||||
if err != store.ErrNotFound {
|
||||
t.Errorf("expected ErrNotFound, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateRepo(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
id, _ := s.CreateRepo(ctx, &store.Repo{Name: "updatable", Type: "apt", SourceURL: "https://old.example.com", SyncMode: "auto", Config: ""})
|
||||
|
||||
newConfig := `{"suite":"bookworm","components":["main"],"architectures":["amd64"]}`
|
||||
if err := s.UpdateRepo(ctx, id, "https://new.example.com", "manual", newConfig); err != nil {
|
||||
t.Fatalf("UpdateRepo: %v", err)
|
||||
}
|
||||
|
||||
got, err := s.GetRepo(ctx, id)
|
||||
if err != nil {
|
||||
t.Fatalf("GetRepo after update: %v", err)
|
||||
}
|
||||
if got.SourceURL != "https://new.example.com" {
|
||||
t.Errorf("SourceURL: got %q, want https://new.example.com", got.SourceURL)
|
||||
}
|
||||
if got.SyncMode != "manual" {
|
||||
t.Errorf("SyncMode: got %q, want manual", got.SyncMode)
|
||||
}
|
||||
if got.Config != newConfig {
|
||||
t.Errorf("Config: got %q", got.Config)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateRepo_notFound(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
err := s.UpdateRepo(ctx, 9999, "https://x.com", "auto", "")
|
||||
if err != store.ErrNotFound {
|
||||
t.Errorf("expected ErrNotFound, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateRepo_uniqueName(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
r := &store.Repo{Name: "unique", Type: "rpm", SourceURL: "https://x.com", SyncMode: "auto"}
|
||||
if _, err := s.CreateRepo(ctx, r); err != nil {
|
||||
t.Fatalf("first create: %v", err)
|
||||
}
|
||||
if _, err := s.CreateRepo(ctx, r); err == nil {
|
||||
t.Error("expected error for duplicate name, got nil")
|
||||
}
|
||||
}
|
||||
142
internal/store/snapshot_test.go
Normal file
142
internal/store/snapshot_test.go
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
package store_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/syonad/clonepack/internal/store"
|
||||
)
|
||||
|
||||
func newSnapshotStore(t *testing.T) (*store.SQLiteSnapshotStore, int64) {
|
||||
t.Helper()
|
||||
db := newTestDB(t)
|
||||
repoID := insertTestRepo(t, db)
|
||||
return store.NewSnapshotStore(db), repoID
|
||||
}
|
||||
|
||||
func TestCreateAndGetSnapshot(t *testing.T) {
|
||||
s, repoID := newSnapshotStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
id, err := s.CreateSnapshot(ctx, repoID, "v1.0")
|
||||
if err != nil {
|
||||
t.Fatalf("CreateSnapshot: %v", err)
|
||||
}
|
||||
|
||||
snap, err := s.GetSnapshot(ctx, id)
|
||||
if err != nil {
|
||||
t.Fatalf("GetSnapshot: %v", err)
|
||||
}
|
||||
if snap.RepoID != repoID {
|
||||
t.Errorf("RepoID: got %d, want %d", snap.RepoID, repoID)
|
||||
}
|
||||
if snap.Label != "v1.0" {
|
||||
t.Errorf("Label: got %q, want v1.0", snap.Label)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSnapshot_notFound(t *testing.T) {
|
||||
s, _ := newSnapshotStore(t)
|
||||
_, err := s.GetSnapshot(context.Background(), 9999)
|
||||
if err != store.ErrNotFound {
|
||||
t.Errorf("expected ErrNotFound, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListSnapshots(t *testing.T) {
|
||||
s, repoID := newSnapshotStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
snaps, err := s.ListSnapshots(ctx, repoID)
|
||||
if err != nil {
|
||||
t.Fatalf("ListSnapshots (empty): %v", err)
|
||||
}
|
||||
if len(snaps) != 0 {
|
||||
t.Errorf("expected 0 snapshots, got %d", len(snaps))
|
||||
}
|
||||
|
||||
s.CreateSnapshot(ctx, repoID, "snap-1")
|
||||
s.CreateSnapshot(ctx, repoID, "snap-2")
|
||||
|
||||
snaps, err = s.ListSnapshots(ctx, repoID)
|
||||
if err != nil {
|
||||
t.Fatalf("ListSnapshots: %v", err)
|
||||
}
|
||||
if len(snaps) != 2 {
|
||||
t.Fatalf("expected 2 snapshots, got %d", len(snaps))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAndGetSnapshotPackages(t *testing.T) {
|
||||
s, repoID := newSnapshotStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
snapID, _ := s.CreateSnapshot(ctx, repoID, "with-pkgs")
|
||||
|
||||
pkgs := []store.SnapshotPackage{
|
||||
{Name: "curl", Version: "7.88", Arch: "amd64", Location: "Packages/curl.rpm", Checksum: "abc", ChecksumType: "sha256", Size: 1000},
|
||||
{Name: "wget", Version: "1.21", Arch: "amd64", Location: "Packages/wget.rpm", Checksum: "def", ChecksumType: "sha256", Size: 2000},
|
||||
}
|
||||
if err := s.AddSnapshotPackages(ctx, snapID, pkgs); err != nil {
|
||||
t.Fatalf("AddSnapshotPackages: %v", err)
|
||||
}
|
||||
|
||||
got, err := s.GetSnapshotPackages(ctx, snapID)
|
||||
if err != nil {
|
||||
t.Fatalf("GetSnapshotPackages: %v", err)
|
||||
}
|
||||
if len(got) != 2 {
|
||||
t.Fatalf("expected 2 packages, got %d", len(got))
|
||||
}
|
||||
if got[0].Name != "curl" {
|
||||
t.Errorf("pkg[0].Name: got %q, want curl", got[0].Name)
|
||||
}
|
||||
if got[1].Size != 2000 {
|
||||
t.Errorf("pkg[1].Size: got %d, want 2000", got[1].Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddSnapshotPackages_empty(t *testing.T) {
|
||||
s, repoID := newSnapshotStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
snapID, _ := s.CreateSnapshot(ctx, repoID, "empty")
|
||||
if err := s.AddSnapshotPackages(ctx, snapID, nil); err != nil {
|
||||
t.Fatalf("AddSnapshotPackages with nil: %v", err)
|
||||
}
|
||||
pkgs, _ := s.GetSnapshotPackages(ctx, snapID)
|
||||
if len(pkgs) != 0 {
|
||||
t.Errorf("expected 0 packages, got %d", len(pkgs))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteSnapshot(t *testing.T) {
|
||||
s, repoID := newSnapshotStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
snapID, _ := s.CreateSnapshot(ctx, repoID, "to-delete")
|
||||
pkgs := []store.SnapshotPackage{
|
||||
{Name: "curl", Version: "7.88", Arch: "amd64", Location: "loc", Checksum: "abc", ChecksumType: "sha256", Size: 100},
|
||||
}
|
||||
s.AddSnapshotPackages(ctx, snapID, pkgs)
|
||||
|
||||
if err := s.DeleteSnapshot(ctx, snapID); err != nil {
|
||||
t.Fatalf("DeleteSnapshot: %v", err)
|
||||
}
|
||||
if _, err := s.GetSnapshot(ctx, snapID); err != store.ErrNotFound {
|
||||
t.Errorf("expected ErrNotFound after delete, got %v", err)
|
||||
}
|
||||
// Cascade: packages should also be gone.
|
||||
remaining, _ := s.GetSnapshotPackages(ctx, snapID)
|
||||
if len(remaining) != 0 {
|
||||
t.Errorf("expected cascade delete of packages, got %d", len(remaining))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteSnapshot_notFound(t *testing.T) {
|
||||
s, _ := newSnapshotStore(t)
|
||||
err := s.DeleteSnapshot(context.Background(), 9999)
|
||||
if err != store.ErrNotFound {
|
||||
t.Errorf("expected ErrNotFound, got %v", err)
|
||||
}
|
||||
}
|
||||
36
internal/store/testhelper_test.go
Normal file
36
internal/store/testhelper_test.go
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package store_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"testing"
|
||||
|
||||
"github.com/syonad/clonepack/config"
|
||||
"github.com/syonad/clonepack/internal/store"
|
||||
)
|
||||
|
||||
func newTestDB(t *testing.T) *sql.DB {
|
||||
t.Helper()
|
||||
db, err := store.Open(config.DBConfig{Path: ":memory:"})
|
||||
if err != nil {
|
||||
t.Fatalf("open db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { db.Close() })
|
||||
return db
|
||||
}
|
||||
|
||||
// insertTestRepo crée un repo minimal et retourne son ID.
|
||||
func insertTestRepo(t *testing.T, db *sql.DB) int64 {
|
||||
t.Helper()
|
||||
s := store.NewRepoStore(db)
|
||||
id, err := s.CreateRepo(context.Background(), &store.Repo{
|
||||
Name: "test-repo",
|
||||
Type: "rpm",
|
||||
SourceURL: "https://example.com",
|
||||
SyncMode: "auto",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("insertTestRepo: %v", err)
|
||||
}
|
||||
return id
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue