297 lines
8.5 KiB
Go
297 lines
8.5 KiB
Go
package manifest
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"slices"
|
|
"testing"
|
|
)
|
|
|
|
func TestFindWalksParents(t *testing.T) {
|
|
root := t.TempDir()
|
|
manifestPath := filepath.Join(root, DefaultFile)
|
|
if err := os.WriteFile(manifestPath, []byte("[update]\n"), 0o600); err != nil {
|
|
t.Fatalf("WriteFile manifest: %v", err)
|
|
}
|
|
|
|
startDir := filepath.Join(root, "cmd", "graylog")
|
|
if err := os.MkdirAll(startDir, 0o755); err != nil {
|
|
t.Fatalf("MkdirAll startDir: %v", err)
|
|
}
|
|
|
|
got, err := Find(startDir)
|
|
if err != nil {
|
|
t.Fatalf("Find returned error: %v", err)
|
|
}
|
|
if got != manifestPath {
|
|
t.Fatalf("Find = %q, want %q", got, manifestPath)
|
|
}
|
|
}
|
|
|
|
func TestFindReturnsNotExistWhenMissing(t *testing.T) {
|
|
_, err := Find(t.TempDir())
|
|
if err == nil {
|
|
t.Fatal("expected error")
|
|
}
|
|
if !errors.Is(err, os.ErrNotExist) {
|
|
t.Fatalf("error = %v, want os.ErrNotExist", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadParsesUpdateConfig(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, DefaultFile)
|
|
|
|
const content = `
|
|
[update]
|
|
source_name = " Gitea releases "
|
|
driver = " Gitea "
|
|
repository = " org/repo "
|
|
base_url = "https://gitea.example.com/"
|
|
latest_release_url = "https://gitea.example.com/api/releases/latest"
|
|
asset_name_template = "{binary}_{os}_{arch}{ext}"
|
|
checksum_asset_name = "{asset}.sha256"
|
|
checksum_required = true
|
|
signature_asset_name = "{asset}.sig"
|
|
signature_required = true
|
|
signature_public_key = " 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef "
|
|
signature_public_key_env_names = [" MCP_PUBKEY ", "", "MCP_RELEASE_PUBKEY"]
|
|
token_header = " Authorization "
|
|
token_prefix = " token "
|
|
token_env_names = [" GITEA_TOKEN ", "", "GITEA_RELEASE_TOKEN"]
|
|
`
|
|
|
|
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
|
|
t.Fatalf("WriteFile manifest: %v", err)
|
|
}
|
|
|
|
file, err := Load(path)
|
|
if err != nil {
|
|
t.Fatalf("Load returned error: %v", err)
|
|
}
|
|
|
|
source := file.Update.ReleaseSource()
|
|
if source.Name != "Gitea releases" {
|
|
t.Fatalf("source name = %q", source.Name)
|
|
}
|
|
if source.Driver != "gitea" {
|
|
t.Fatalf("driver = %q", source.Driver)
|
|
}
|
|
if source.Repository != "org/repo" {
|
|
t.Fatalf("repository = %q", source.Repository)
|
|
}
|
|
if source.BaseURL != "https://gitea.example.com" {
|
|
t.Fatalf("base URL = %q", source.BaseURL)
|
|
}
|
|
if source.LatestReleaseURL != "https://gitea.example.com/api/releases/latest" {
|
|
t.Fatalf("latest release URL = %q", source.LatestReleaseURL)
|
|
}
|
|
if source.AssetNameTemplate != "{binary}_{os}_{arch}{ext}" {
|
|
t.Fatalf("asset name template = %q", source.AssetNameTemplate)
|
|
}
|
|
if source.ChecksumAssetName != "{asset}.sha256" {
|
|
t.Fatalf("checksum asset name = %q", source.ChecksumAssetName)
|
|
}
|
|
if !source.ChecksumRequired {
|
|
t.Fatal("checksum required should be true")
|
|
}
|
|
if source.SignatureAssetName != "{asset}.sig" {
|
|
t.Fatalf("signature asset name = %q", source.SignatureAssetName)
|
|
}
|
|
if !source.SignatureRequired {
|
|
t.Fatal("signature required should be true")
|
|
}
|
|
if source.SignaturePublicKey == "" {
|
|
t.Fatal("signature public key should be set")
|
|
}
|
|
if len(source.SignaturePublicKeyEnvNames) != 2 {
|
|
t.Fatalf("signature env names = %v", source.SignaturePublicKeyEnvNames)
|
|
}
|
|
if source.TokenHeader != "Authorization" {
|
|
t.Fatalf("token header = %q", source.TokenHeader)
|
|
}
|
|
if source.TokenPrefix != "token" {
|
|
t.Fatalf("token prefix = %q", source.TokenPrefix)
|
|
}
|
|
if len(source.TokenEnvNames) != 2 {
|
|
t.Fatalf("token env names = %v", source.TokenEnvNames)
|
|
}
|
|
}
|
|
|
|
func TestLoadDefaultFindsManifest(t *testing.T) {
|
|
root := t.TempDir()
|
|
path := filepath.Join(root, DefaultFile)
|
|
if err := os.WriteFile(path, []byte("[update]\nlatest_release_url = \"https://example.com/latest\"\n"), 0o600); err != nil {
|
|
t.Fatalf("WriteFile manifest: %v", err)
|
|
}
|
|
|
|
startDir := filepath.Join(root, "cmd", "tool")
|
|
if err := os.MkdirAll(startDir, 0o755); err != nil {
|
|
t.Fatalf("MkdirAll startDir: %v", err)
|
|
}
|
|
|
|
file, gotPath, err := LoadDefault(startDir)
|
|
if err != nil {
|
|
t.Fatalf("LoadDefault returned error: %v", err)
|
|
}
|
|
if gotPath != path {
|
|
t.Fatalf("path = %q, want %q", gotPath, path)
|
|
}
|
|
if file.Update.LatestReleaseURL != "https://example.com/latest" {
|
|
t.Fatalf("latest release URL = %q", file.Update.LatestReleaseURL)
|
|
}
|
|
}
|
|
|
|
func TestLoadReturnsParseError(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, DefaultFile)
|
|
if err := os.WriteFile(path, []byte("[update\n"), 0o600); err != nil {
|
|
t.Fatalf("WriteFile manifest: %v", err)
|
|
}
|
|
|
|
_, err := Load(path)
|
|
if err == nil {
|
|
t.Fatal("expected error")
|
|
}
|
|
}
|
|
|
|
func TestLoadParsesExtendedManifestMetadata(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, DefaultFile)
|
|
|
|
const content = `
|
|
binary_name = " my-mcp "
|
|
docs_url = " https://docs.example.com/mcp "
|
|
|
|
[update]
|
|
latest_release_url = "https://example.com/latest"
|
|
|
|
[environment]
|
|
known = [" MCP_PROFILE ", "", "MCP_TOKEN"]
|
|
|
|
[secret_store]
|
|
backend_policy = " auto "
|
|
|
|
[profiles]
|
|
default = " prod "
|
|
known = [" default ", "", "prod"]
|
|
|
|
[bootstrap]
|
|
description = " Client MCP interne "
|
|
`
|
|
|
|
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
|
|
t.Fatalf("WriteFile manifest: %v", err)
|
|
}
|
|
|
|
file, err := Load(path)
|
|
if err != nil {
|
|
t.Fatalf("Load returned error: %v", err)
|
|
}
|
|
|
|
if file.BinaryName != "my-mcp" {
|
|
t.Fatalf("binary name = %q", file.BinaryName)
|
|
}
|
|
if file.DocsURL != "https://docs.example.com/mcp" {
|
|
t.Fatalf("docs URL = %q", file.DocsURL)
|
|
}
|
|
if !slices.Equal(file.Environment.Known, []string{"MCP_PROFILE", "MCP_TOKEN"}) {
|
|
t.Fatalf("environment known = %v", file.Environment.Known)
|
|
}
|
|
if file.SecretStore.BackendPolicy != "auto" {
|
|
t.Fatalf("secret store policy = %q", file.SecretStore.BackendPolicy)
|
|
}
|
|
if file.Profiles.Default != "prod" {
|
|
t.Fatalf("default profile = %q", file.Profiles.Default)
|
|
}
|
|
if !slices.Equal(file.Profiles.Known, []string{"default", "prod"}) {
|
|
t.Fatalf("profiles known = %v", file.Profiles.Known)
|
|
}
|
|
if file.Bootstrap.Description != "Client MCP interne" {
|
|
t.Fatalf("bootstrap description = %q", file.Bootstrap.Description)
|
|
}
|
|
|
|
bootstrap := file.BootstrapInfo()
|
|
if bootstrap.BinaryName != "my-mcp" {
|
|
t.Fatalf("bootstrap binary name = %q", bootstrap.BinaryName)
|
|
}
|
|
if bootstrap.DocsURL != "https://docs.example.com/mcp" {
|
|
t.Fatalf("bootstrap docs URL = %q", bootstrap.DocsURL)
|
|
}
|
|
if bootstrap.DefaultProfile != "prod" {
|
|
t.Fatalf("bootstrap default profile = %q", bootstrap.DefaultProfile)
|
|
}
|
|
if !slices.Equal(bootstrap.Profiles, []string{"default", "prod"}) {
|
|
t.Fatalf("bootstrap profiles = %v", bootstrap.Profiles)
|
|
}
|
|
|
|
scaffold := file.ScaffoldInfo()
|
|
if scaffold.SecretStorePolicy != "auto" {
|
|
t.Fatalf("scaffold secret store policy = %q", scaffold.SecretStorePolicy)
|
|
}
|
|
if !slices.Equal(scaffold.KnownEnvironmentVariables, []string{"MCP_PROFILE", "MCP_TOKEN"}) {
|
|
t.Fatalf("scaffold known environment variables = %v", scaffold.KnownEnvironmentVariables)
|
|
}
|
|
}
|
|
|
|
func TestLoadEmbeddedParsesContent(t *testing.T) {
|
|
file, source, err := LoadEmbedded(`
|
|
[update]
|
|
latest_release_url = "https://example.com/latest"
|
|
`)
|
|
if err != nil {
|
|
t.Fatalf("LoadEmbedded returned error: %v", err)
|
|
}
|
|
if source != EmbeddedSource {
|
|
t.Fatalf("source = %q, want %q", source, EmbeddedSource)
|
|
}
|
|
if file.Update.LatestReleaseURL != "https://example.com/latest" {
|
|
t.Fatalf("latest release URL = %q", file.Update.LatestReleaseURL)
|
|
}
|
|
}
|
|
|
|
func TestLoadEmbeddedReturnsNotExistWhenEmpty(t *testing.T) {
|
|
_, _, err := LoadEmbedded(" ")
|
|
if !errors.Is(err, os.ErrNotExist) {
|
|
t.Fatalf("error = %v, want os.ErrNotExist", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadDefaultOrEmbeddedPrefersManifestFile(t *testing.T) {
|
|
root := t.TempDir()
|
|
path := filepath.Join(root, DefaultFile)
|
|
if err := os.WriteFile(path, []byte("[update]\nlatest_release_url = \"https://example.com/from-file\"\n"), 0o600); err != nil {
|
|
t.Fatalf("WriteFile manifest: %v", err)
|
|
}
|
|
|
|
file, source, err := LoadDefaultOrEmbedded(root, `
|
|
[update]
|
|
latest_release_url = "https://example.com/from-embedded"
|
|
`)
|
|
if err != nil {
|
|
t.Fatalf("LoadDefaultOrEmbedded returned error: %v", err)
|
|
}
|
|
if source != path {
|
|
t.Fatalf("source = %q, want %q", source, path)
|
|
}
|
|
if file.Update.LatestReleaseURL != "https://example.com/from-file" {
|
|
t.Fatalf("latest release URL = %q", file.Update.LatestReleaseURL)
|
|
}
|
|
}
|
|
|
|
func TestLoadDefaultOrEmbeddedUsesEmbeddedWhenFileMissing(t *testing.T) {
|
|
file, source, err := LoadDefaultOrEmbedded(t.TempDir(), `
|
|
[update]
|
|
latest_release_url = "https://example.com/from-embedded"
|
|
`)
|
|
if err != nil {
|
|
t.Fatalf("LoadDefaultOrEmbedded returned error: %v", err)
|
|
}
|
|
if source != EmbeddedSource {
|
|
t.Fatalf("source = %q, want %q", source, EmbeddedSource)
|
|
}
|
|
if file.Update.LatestReleaseURL != "https://example.com/from-embedded" {
|
|
t.Fatalf("latest release URL = %q", file.Update.LatestReleaseURL)
|
|
}
|
|
}
|