Files
cthulhu/internal/app/tentacle_repositories_test.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)
}
}