All checks were successful
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
228 lines
6.3 KiB
Go
228 lines
6.3 KiB
Go
package handlers
|
|
|
|
import (
|
|
"archive/zip"
|
|
"context"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"armature/database"
|
|
"armature/store"
|
|
postgres "armature/store/postgres"
|
|
sqlite "armature/store/sqlite"
|
|
)
|
|
|
|
// ── Test helpers ──────────────────────────────
|
|
|
|
func newTestStores(t *testing.T) store.Stores {
|
|
t.Helper()
|
|
database.RequireTestDB(t)
|
|
database.TruncateAll(t)
|
|
|
|
if database.IsSQLite() {
|
|
return sqlite.NewStores(database.TestDB)
|
|
}
|
|
return postgres.NewStores(database.TestDB)
|
|
}
|
|
|
|
// buildTestPkg creates a minimal .pkg archive in dir with the given manifest.
|
|
func buildTestPkg(t *testing.T, dir string, manifest map[string]any) string {
|
|
t.Helper()
|
|
|
|
pkgID, _ := manifest["id"].(string)
|
|
if pkgID == "" {
|
|
t.Fatal("manifest must have 'id'")
|
|
}
|
|
|
|
data, err := json.Marshal(manifest)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
pkgPath := filepath.Join(dir, pkgID+".pkg")
|
|
f, err := os.Create(pkgPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
zw := zip.NewWriter(f)
|
|
w, err := zw.Create("manifest.json")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := w.Write(data); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := zw.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
return pkgPath
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════
|
|
// Tests
|
|
// ═══════════════════════════════════════════════
|
|
|
|
// TestBundledInstall_FreshDB verifies that bundled packages are installed
|
|
// into an empty database on first run.
|
|
func TestBundledInstall_FreshDB(t *testing.T) {
|
|
stores := newTestStores(t)
|
|
ctx := context.Background()
|
|
|
|
bundledDir := t.TempDir()
|
|
packagesDir := t.TempDir()
|
|
|
|
buildTestPkg(t, bundledDir, map[string]any{
|
|
"id": "test-surface-a",
|
|
"title": "Test Surface A",
|
|
"type": "surface",
|
|
})
|
|
buildTestPkg(t, bundledDir, map[string]any{
|
|
"id": "test-surface-b",
|
|
"title": "Test Surface B",
|
|
"type": "surface",
|
|
"route": "/s/test-b",
|
|
})
|
|
|
|
InstallBundledPackages(bundledDir, packagesDir, "*", stores, nil)
|
|
|
|
// Both packages should be installed and enabled
|
|
for _, id := range []string{"test-surface-a", "test-surface-b"} {
|
|
pkg, err := stores.Packages.Get(ctx, id)
|
|
if err != nil || pkg == nil {
|
|
t.Fatalf("package %s not found after install", id)
|
|
}
|
|
if !pkg.Enabled {
|
|
t.Errorf("package %s should be enabled", id)
|
|
}
|
|
if pkg.Source != "bundled" {
|
|
t.Errorf("package %s source = %q, want %q", id, pkg.Source, "bundled")
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestBundledInstall_SkipsExisting verifies that already-installed packages
|
|
// are not re-installed (preserves admin uninstall/reconfigure).
|
|
func TestBundledInstall_SkipsExisting(t *testing.T) {
|
|
stores := newTestStores(t)
|
|
ctx := context.Background()
|
|
|
|
bundledDir := t.TempDir()
|
|
packagesDir := t.TempDir()
|
|
|
|
// Pre-seed a package with same ID but different title (simulating existing install)
|
|
manifest := map[string]any{"id": "pre-existing", "title": "Original Title", "type": "surface"}
|
|
if err := stores.Packages.Seed(ctx, "pre-existing", "Original Title", "extension", manifest); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Bundled package has same ID but different title
|
|
buildTestPkg(t, bundledDir, map[string]any{
|
|
"id": "pre-existing",
|
|
"title": "Bundled Title",
|
|
"type": "surface",
|
|
})
|
|
|
|
InstallBundledPackages(bundledDir, packagesDir, "*", stores, nil)
|
|
|
|
// Package should retain original title (not overwritten)
|
|
pkg, err := stores.Packages.Get(ctx, "pre-existing")
|
|
if err != nil || pkg == nil {
|
|
t.Fatal("pre-existing package not found")
|
|
}
|
|
if pkg.Title != "Original Title" {
|
|
t.Errorf("title = %q, want %q (should not overwrite existing)", pkg.Title, "Original Title")
|
|
}
|
|
}
|
|
|
|
// TestBundledInstall_MissingDir verifies graceful handling when bundled
|
|
// packages directory doesn't exist.
|
|
func TestBundledInstall_MissingDir(t *testing.T) {
|
|
stores := newTestStores(t)
|
|
|
|
// Should not panic or error — just log and return
|
|
InstallBundledPackages("/nonexistent/path", "", "", stores, nil)
|
|
}
|
|
|
|
// TestBundledInstall_EmptyDir verifies no-op when directory exists but is empty.
|
|
func TestBundledInstall_EmptyDir(t *testing.T) {
|
|
stores := newTestStores(t)
|
|
|
|
bundledDir := t.TempDir()
|
|
|
|
// Should not panic or error
|
|
InstallBundledPackages(bundledDir, "", "", stores, nil)
|
|
}
|
|
|
|
// TestBundledInstall_DormantPackage verifies that bundled packages with
|
|
// unmet requires are marked dormant.
|
|
func TestBundledInstall_DormantPackage(t *testing.T) {
|
|
stores := newTestStores(t)
|
|
ctx := context.Background()
|
|
|
|
bundledDir := t.TempDir()
|
|
packagesDir := t.TempDir()
|
|
|
|
buildTestPkg(t, bundledDir, map[string]any{
|
|
"id": "dormant-pkg",
|
|
"title": "Dormant Package",
|
|
"type": "extension",
|
|
"hooks": []string{"on_install"},
|
|
"requires": []string{"chat"},
|
|
})
|
|
|
|
InstallBundledPackages(bundledDir, packagesDir, "*", stores, nil)
|
|
|
|
pkg, err := stores.Packages.Get(ctx, "dormant-pkg")
|
|
if err != nil || pkg == nil {
|
|
t.Fatal("dormant package not found after install")
|
|
}
|
|
if pkg.Status != "dormant" {
|
|
t.Errorf("status = %q, want %q", pkg.Status, "dormant")
|
|
}
|
|
if pkg.Enabled {
|
|
t.Error("dormant package should not be enabled")
|
|
}
|
|
}
|
|
|
|
// TestBundledInstall_Allowlist verifies that BUNDLED_PACKAGES allowlist
|
|
// filters which packages are installed.
|
|
func TestBundledInstall_Allowlist(t *testing.T) {
|
|
stores := newTestStores(t)
|
|
ctx := context.Background()
|
|
|
|
bundledDir := t.TempDir()
|
|
packagesDir := t.TempDir()
|
|
|
|
buildTestPkg(t, bundledDir, map[string]any{
|
|
"id": "pkg-alpha", "title": "Alpha", "type": "surface",
|
|
})
|
|
buildTestPkg(t, bundledDir, map[string]any{
|
|
"id": "pkg-beta", "title": "Beta", "type": "surface",
|
|
})
|
|
buildTestPkg(t, bundledDir, map[string]any{
|
|
"id": "pkg-gamma", "title": "Gamma", "type": "surface",
|
|
})
|
|
|
|
// Only allow alpha and gamma
|
|
InstallBundledPackages(bundledDir, packagesDir, "pkg-alpha,pkg-gamma", stores, nil)
|
|
|
|
// Alpha and gamma should be installed
|
|
for _, id := range []string{"pkg-alpha", "pkg-gamma"} {
|
|
pkg, err := stores.Packages.Get(ctx, id)
|
|
if err != nil || pkg == nil {
|
|
t.Fatalf("package %s should have been installed (in allowlist)", id)
|
|
}
|
|
}
|
|
|
|
// Beta should NOT be installed
|
|
pkg, _ := stores.Packages.Get(ctx, "pkg-beta")
|
|
if pkg != nil {
|
|
t.Fatal("pkg-beta should NOT have been installed (not in allowlist)")
|
|
}
|
|
}
|