110 lines
4.0 KiB
Go
110 lines
4.0 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
package app
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"git.stormux.org/storm/cthulhu/internal/tentacle"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestManagedRepositoryDiscoveryRefreshRemoveAndRestart(t *testing.T) {
|
|
registryPath := filepath.Join(t.TempDir(), "tentacles.toml")
|
|
runtime, _ := managed_tentacle_fixture(t, registryPath, false)
|
|
origin := "https://example.org/team/tentacles"
|
|
repository := tentacle.Repository{URL: origin, ID: "example.tentacles", Name: "Example", Revision: strings.Repeat("a", 40), Tentacles: []tentacle.Manifest{{FormatVersion: 1, ID: "echo", Name: "Echo", Version: "0.1"}}}
|
|
fail := false
|
|
runtime.fetchRepository = func(context.Context, string) (tentacle.Repository, error) {
|
|
if fail {
|
|
return tentacle.Repository{}, errors.New("invalid metadata")
|
|
}
|
|
return repository, nil
|
|
}
|
|
runtime.newManager = func() (*tentacle.Manager, error) {
|
|
t.Error("repository discovery started host")
|
|
return nil, tentacle.ErrUnavailable
|
|
}
|
|
if err := runtime.Start(context.Background()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
manage := func(action string) error {
|
|
return runtime.Manage(context.Background(), tentacle.ManagementRequest{Action: action, URL: origin})
|
|
}
|
|
if err := manage("repository-add"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(runtime.Snapshot().Repositories) != 1 || len(runtime.Snapshot().Entries) != 0 {
|
|
t.Fatal(runtime.Snapshot())
|
|
}
|
|
if err := manage("repository-add"); err == nil {
|
|
t.Fatal("duplicate accepted")
|
|
}
|
|
fail = true
|
|
if err := manage("repository-refresh"); err == nil {
|
|
t.Fatal("invalid refresh accepted")
|
|
}
|
|
if runtime.Snapshot().Repositories[0].Revision != repository.Revision {
|
|
t.Fatal("lost last good catalog")
|
|
}
|
|
fail = false
|
|
repository.Revision = strings.Repeat("b", 40)
|
|
if err := manage("repository-refresh"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
repository.ID = "different"
|
|
if err := manage("repository-refresh"); err == nil {
|
|
t.Fatal("changed identity accepted")
|
|
}
|
|
disk := &tentacle.Registry{Path: registryPath}
|
|
if _, err := disk.Load(); err != nil || len(disk.Repositories()) != 1 || disk.Repositories()[0].ID != "example.tentacles" || disk.Repositories()[0].Revision != strings.Repeat("b", 40) {
|
|
t.Fatalf("persisted repository: %+v %v", disk.Repositories(), err)
|
|
}
|
|
// Cached catalogs load at startup without invoking any fetch function.
|
|
restarted, _ := managed_tentacle_fixture(t, registryPath, false)
|
|
restarted.fetchRepository = func(context.Context, string) (tentacle.Repository, error) {
|
|
t.Error("startup fetched repository")
|
|
return repository, nil
|
|
}
|
|
if err := restarted.Start(context.Background()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
waitTentacle(t, func() bool { return len(restarted.Snapshot().Repositories) == 1 })
|
|
if err := manage("repository-remove"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(runtime.Snapshot().Repositories) != 0 {
|
|
t.Fatal("source not removed")
|
|
}
|
|
}
|
|
|
|
func TestRepositoryRemovalRetainsInstalledEntries(t *testing.T) {
|
|
registryPath := filepath.Join(t.TempDir(), "tentacles.toml")
|
|
origin := "https://example.org/team/tentacles"
|
|
registry := &tentacle.Registry{Path: registryPath}
|
|
if _, err := registry.Load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
entry := probe_entry(t, "installed", "called")
|
|
entry.Repository = origin
|
|
entry.RepositoryID = "example.tentacles"
|
|
entry.LocalID = "echo"
|
|
repository := tentacle.Repository{URL: origin, ID: "example.tentacles", Name: "Example", Revision: strings.Repeat("a", 40)}
|
|
if err := registry.SaveState([]tentacle.Entry{entry}, []tentacle.Repository{repository}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
runtime, _ := managed_tentacle_fixture(t, registryPath, false)
|
|
if err := runtime.Start(context.Background()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := runtime.Manage(context.Background(), tentacle.ManagementRequest{Action: "repository-remove", URL: origin}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
snapshot := runtime.Snapshot()
|
|
if len(snapshot.Repositories) != 0 || len(snapshot.Entries) != 1 || snapshot.Entries[0].Entry.ID != entry.ID {
|
|
t.Fatal(snapshot)
|
|
}
|
|
}
|