Feat v0.3.8 distribution (#21)
All checks were successful
CI/CD / detect-changes (pull_request) Successful in 19s
CI/CD / test-frontend (pull_request) Successful in 5s
CI/CD / test-go-pg (pull_request) Successful in 2m50s
CI/CD / test-sqlite (pull_request) Successful in 3m1s
CI/CD / build-and-deploy (pull_request) Successful in 1m31s
All checks were successful
CI/CD / detect-changes (pull_request) Successful in 19s
CI/CD / test-frontend (pull_request) Successful in 5s
CI/CD / test-go-pg (pull_request) Successful in 2m50s
CI/CD / test-sqlite (pull_request) Successful in 3m1s
CI/CD / build-and-deploy (pull_request) Successful in 1m31s
Bundled packages auto-install on first boot for zero-config first run. Builder image for faster custom builds. Per-environment allowlists for K8s/Helm (dev=all, test=all, prod=skip). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
226
server/handlers/packages_bundled_test.go
Normal file
226
server/handlers/packages_bundled_test.go
Normal file
@@ -0,0 +1,226 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/store"
|
||||
postgres "switchboard-core/store/postgres"
|
||||
sqlite "switchboard-core/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",
|
||||
"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)")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user