6b80fd0c0f
Add a 'scope' TEXT column (default 'homelab') to the tools table so tools can be namespaced by scope (e.g. "homelab:restart", "datacenter:reboot"). Backward-compat: bare name defaults to "homelab" scope. Changes: - Migration #1: ALTER TABLE tools ADD COLUMN scope - store.Tool: add Scope field, update all SQL and scanTool() - ipc.Tool DTO and request types: add Scope field - CoreAPI interface: pass scope in ProposeTool/EnableTool - storeAPI adapters: forward scope - cmd/mavend/voice: pass scope (empty → homelab) - cmd/mavweb/tools: show scope column in UI tables, hidden fields - All tests updated for scope field - Migration test made dynamic (startVer = len(migrations))
50 lines
1.5 KiB
Go
50 lines
1.5 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
func userVersion(t *testing.T, s *Store) int {
|
|
t.Helper()
|
|
var v int
|
|
if err := s.db.QueryRowContext(context.Background(), "PRAGMA user_version").Scan(&v); err != nil {
|
|
t.Fatalf("read user_version: %v", err)
|
|
}
|
|
return v
|
|
}
|
|
|
|
func TestMigrateAppliesOnceAndIsIdempotent(t *testing.T) {
|
|
ctx := context.Background()
|
|
s := newTestStore(t)
|
|
|
|
// The 1 migration in the built-in slice (tools scope) was applied on Open.
|
|
startVer := len(migrations)
|
|
if v := userVersion(t, s); v != startVer {
|
|
t.Fatalf("fresh DB user_version = %d, want %d", v, startVer)
|
|
}
|
|
|
|
// Append a fake migration and run it: creates a throwaway table, bumps by 1.
|
|
migrations = append(migrations, `CREATE TABLE migrate_probe (id INTEGER PRIMARY KEY)`)
|
|
t.Cleanup(func() { migrations = migrations[:len(migrations)-1] })
|
|
|
|
if err := migrate(ctx, s.db); err != nil {
|
|
t.Fatalf("migrate: %v", err)
|
|
}
|
|
want := startVer + 1
|
|
if v := userVersion(t, s); v != want {
|
|
t.Fatalf("after migrate user_version = %d, want %d", v, want)
|
|
}
|
|
if _, err := s.db.ExecContext(ctx, "INSERT INTO migrate_probe DEFAULT VALUES"); err != nil {
|
|
t.Fatalf("probe table not created: %v", err)
|
|
}
|
|
|
|
// Second run is a no-op — re-running the CREATE would error (no IF NOT EXISTS).
|
|
if err := migrate(ctx, s.db); err != nil {
|
|
t.Fatalf("migrate second run not idempotent: %v", err)
|
|
}
|
|
if v := userVersion(t, s); v != want {
|
|
t.Fatalf("after re-migrate user_version = %d, want %d", v, want)
|
|
}
|
|
}
|