Git Repository
Stackyard
Stackyard scannt lokale Entwicklungsordner und bündelt Projekte, Git-Status, TODOs, Toolchains, Docker-Compose-Setups, Datei- und Launcher-Funktionen sowie Operations-Informationen in einer lokalen WebUI.
HTTPS
https://zanvex.de/git/stackyard.gitinternal/storage/sqlite_test.go
Zum Verzeichnispackage storage
import (
"context"
"path/filepath"
"testing"
"time"
"stackyard/internal/project"
)
func TestStoreRoundTripProjects(t *testing.T) {
store, err := Open(filepath.Join(t.TempDir(), "stackyard.db"))
if err != nil {
t.Fatalf("open store: %v", err)
}
defer store.Close()
input := []project.Project{
{
ID: "p1",
Name: "api",
RootName: "DEV",
Path: "/tmp/api",
PrimaryType: "go",
State: project.StateActive,
MiseTools: []string{"go 1.24.0"},
Ports: []int{3000, 8080},
ComposeFiles: []string{"docker-compose.yml"},
TodoPath: "/tmp/api/.stackyard/todo.md",
Markers: []string{"go.mod", ".git"},
LastModified: time.Date(2026, 5, 27, 12, 0, 0, 0, time.UTC),
LastScannedAt: time.Date(2026, 5, 27, 13, 0, 0, 0, time.UTC),
Git: project.GitInfo{
IsRepo: true,
Branch: "main",
Dirty: true,
Ahead: 2,
Behind: 1,
LastCommitHash: "abc",
LastCommitSubject: "Initial",
LastCommitAt: time.Date(2026, 5, 27, 11, 0, 0, 0, time.UTC),
},
},
}
if err := store.UpsertProjects(context.Background(), input); err != nil {
t.Fatalf("upsert projects: %v", err)
}
got, err := store.ListProjects(context.Background())
if err != nil {
t.Fatalf("list projects: %v", err)
}
if len(got) != 1 {
t.Fatalf("expected 1 project, got %d", len(got))
}
if got[0].Git.Branch != "main" || got[0].Markers[0] != "go.mod" || got[0].MiseTools[0] != "go 1.24.0" || got[0].Ports[0] != 3000 {
t.Fatalf("unexpected project: %+v", got[0])
}
}
func TestStorePrunesMissingProjects(t *testing.T) {
store, err := Open(filepath.Join(t.TempDir(), "stackyard.db"))
if err != nil {
t.Fatalf("open store: %v", err)
}
defer store.Close()
ctx := context.Background()
if err := store.UpsertProjects(ctx, []project.Project{{ID: "one", Name: "one", RootName: "DEV", Path: "/tmp/one", State: project.StateActive}}); err != nil {
t.Fatalf("first upsert: %v", err)
}
if err := store.UpsertProjects(ctx, []project.Project{{ID: "two", Name: "two", RootName: "DEV", Path: "/tmp/two", State: project.StateActive}}); err != nil {
t.Fatalf("second upsert: %v", err)
}
got, err := store.ListProjects(ctx)
if err != nil {
t.Fatalf("list projects: %v", err)
}
if len(got) != 1 || got[0].ID != "two" {
t.Fatalf("expected only pruned project 'two', got %+v", got)
}
}
func TestStoreSetFavoriteAndState(t *testing.T) {
store, err := Open(filepath.Join(t.TempDir(), "stackyard.db"))
if err != nil {
t.Fatalf("open store: %v", err)
}
defer store.Close()
ctx := context.Background()
if err := store.UpsertProjects(ctx, []project.Project{{ID: "one", Name: "one", RootName: "DEV", Path: "/tmp/one", State: project.StateActive}}); err != nil {
t.Fatalf("upsert: %v", err)
}
if err := store.SetFavorite(ctx, "one", true); err != nil {
t.Fatalf("set favorite: %v", err)
}
if err := store.SetState(ctx, "one", project.StatePaused); err != nil {
t.Fatalf("set state: %v", err)
}
p, ok, err := store.GetProject(ctx, "one")
if err != nil || !ok {
t.Fatalf("get project: ok=%v err=%v", ok, err)
}
if !p.Favorite || p.State != project.StatePaused {
t.Fatalf("unexpected project state: %+v", p)
}
}
func TestStoreProjectCollections(t *testing.T) {
store, err := Open(filepath.Join(t.TempDir(), "stackyard.db"))
if err != nil {
t.Fatalf("open store: %v", err)
}
defer store.Close()
ctx := context.Background()
if err := store.UpsertProjects(ctx, []project.Project{{ID: "one", Name: "one", RootName: "DEV", Path: "/tmp/one", State: project.StateActive}}); err != nil {
t.Fatalf("upsert project: %v", err)
}
if err := store.CreateCollection(ctx, "Kundenprojekte"); err != nil {
t.Fatalf("create collection: %v", err)
}
collections, err := store.ListCollections(ctx)
if err != nil || len(collections) != 1 {
t.Fatalf("list collections: collections=%+v err=%v", collections, err)
}
if err := store.AssignProjectCollection(ctx, "one", collections[0].ID); err != nil {
t.Fatalf("assign collection: %v", err)
}
collections, err = store.ListCollections(ctx)
if err != nil || len(collections[0].ProjectIDs) != 1 || collections[0].ProjectIDs[0] != "one" {
t.Fatalf("unexpected assignment: collections=%+v err=%v", collections, err)
}
if err := store.DeleteCollection(ctx, collections[0].ID); err != nil {
t.Fatalf("delete collection: %v", err)
}
collections, err = store.ListCollections(ctx)
if err != nil || len(collections) != 0 {
t.Fatalf("expected collection deletion, got %+v err=%v", collections, err)
}
if _, ok, err := store.GetProject(ctx, "one"); err != nil || !ok {
t.Fatalf("project must survive collection deletion: ok=%v err=%v", ok, err)
}
}
func TestStoreProjectMetadata(t *testing.T) {
store, err := Open(filepath.Join(t.TempDir(), "stackyard.db"))
if err != nil {
t.Fatal(err)
}
defer store.Close()
ctx := context.Background()
if err := store.UpsertProjects(ctx, []project.Project{{ID: "one", Name: "one", RootName: "DEV", Path: "/tmp/one", State: project.StateActive}}); err != nil {
t.Fatal(err)
}
if err := store.SetProjectMetadata(ctx, "one", "Beschreibung", "Notiz", "Go, wichtig, go"); err != nil {
t.Fatal(err)
}
got, ok, err := store.GetProject(ctx, "one")
if err != nil || !ok {
t.Fatalf("get metadata: ok=%v err=%v", ok, err)
}
if got.Description != "Beschreibung" || got.Notes != "Notiz" || len(got.Labels) != 2 {
t.Fatalf("unexpected metadata: %+v", got)
}
}
func TestStoreOperationsMetadata(t *testing.T) {
store, err := Open(filepath.Join(t.TempDir(), "stackyard.db"))
if err != nil {
t.Fatal(err)
}
defer store.Close()
ctx := context.Background()
if err := store.CreateSnapshot(ctx, "Workspace", []string{"one", "two"}); err != nil {
t.Fatal(err)
}
snapshots, err := store.ListSnapshots(ctx)
if err != nil || len(snapshots) != 1 || len(snapshots[0].ProjectIDs) != 2 {
t.Fatalf("unexpected snapshots: %+v err=%v", snapshots, err)
}
if err := store.SetScannerRule(ctx, "/tmp/manual", "manual"); err != nil {
t.Fatal(err)
}
if rules, err := store.ListScannerRules(ctx); err != nil || len(rules) != 1 {
t.Fatalf("unexpected scanner rules: %+v err=%v", rules, err)
}
if err := store.SetDependency(ctx, "one", "two"); err != nil {
t.Fatal(err)
}
if dependencies, err := store.ListDependencies(ctx); err != nil || len(dependencies) != 1 {
t.Fatalf("unexpected dependencies: %+v err=%v", dependencies, err)
}
if err := store.AddEvent(ctx, "warning", "test event"); err != nil {
t.Fatal(err)
}
if events, err := store.ListEvents(ctx, 10); err != nil || len(events) != 1 || events[0].Level != "warning" {
t.Fatalf("unexpected events: %+v err=%v", events, err)
}
}