Ctrl K
ComunidadGuías…

internal/pluginstore/registry_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package pluginstore

import (
	"strings"
	"testing"
)

func TestParseRegistryValidatesRegistry(t *testing.T) {
	t.Parallel()

	registry, errParse := ParseRegistry([]byte(`{
		"schema_version": 1,
		"plugins": [{
			"id": "sample-provider",
			"name": "Sample Provider",
			"description": "Adds sample provider support.",
			"author": "author-name",
			"version": "0.1.0",
			"repository": "https://github.com/author-name/cliproxy-sample-provider-plugin",
			"logo": "https://example.com/logo.png",
			"homepage": "https://github.com/author-name/cliproxy-sample-provider-plugin",
			"license": "MIT",
			"tags": ["provider"]
		}]
	}`))
	if errParse != nil {
		t.Fatalf("ParseRegistry() error = %v", errParse)
	}
	plugin, ok := registry.PluginByID("sample-provider")
	if !ok {
		t.Fatal("PluginByID(sample-provider) missing")
	}
	if plugin.Version != "0.1.0" {
		t.Fatalf("plugin version = %q, want 0.1.0", plugin.Version)
	}
}

func TestParseRegistryNormalizesPluginFields(t *testing.T) {
	t.Parallel()

	registry, errParse := ParseRegistry([]byte(`{
		"schema_version": 1,
		"plugins": [{
			"id": " sample-provider ",
			"name": " Sample Provider ",
			"description": " Adds sample provider support. ",
			"author": " author-name ",
			"version": " 0.1.0 ",
			"repository": " https://github.com/author-name/cliproxy-sample-provider-plugin ",
			"logo": " https://example.com/logo.png ",
			"homepage": " https://github.com/author-name/cliproxy-sample-provider-plugin ",
			"license": " MIT ",
			"tags": [" provider "]
		}]
	}`))
	if errParse != nil {
		t.Fatalf("ParseRegistry() error = %v", errParse)
	}
	plugin, ok := registry.PluginByID("sample-provider")
	if !ok {
		t.Fatal("PluginByID(sample-provider) missing")
	}
	if plugin.ID != "sample-provider" || plugin.Version != "0.1.0" || plugin.Repository != "https://github.com/author-name/cliproxy-sample-provider-plugin" {
		t.Fatalf("plugin not normalized: %#v", plugin)
	}
	if plugin.Name != "Sample Provider" || plugin.Tags[0] != "provider" {
		t.Fatalf("plugin display fields not normalized: %#v", plugin)
	}
}

func TestParseRegistryNormalizesPluginLocales(t *testing.T) {
	t.Parallel()

	registry, errParse := ParseRegistry([]byte(`{
		"schema_version": 1,
		"plugins": [{
			"id": "sample-provider",
			"name": "Sample Provider",
			"description": "Adds sample provider support.",
			"author": "author-name",
			"repository": "https://github.com/author-name/cliproxy-sample-provider-plugin",
			"locales": {
				" zh_cn ": {
					"description": " 增加示例提供商支持。 "
				},
				"ja": {
					"description": " サンプルプロバイダーを追加します。 "
				},
				"empty": {
					"description": "   "
				}
			}
		}]
	}`))
	if errParse != nil {
		t.Fatalf("ParseRegistry() error = %v", errParse)
	}
	plugin, ok := registry.PluginByID("sample-provider")
	if !ok {
		t.Fatal("PluginByID(sample-provider) missing")
	}
	if len(plugin.Locales) != 2 {
		t.Fatalf("plugin locales len = %d, want 2: %#v", len(plugin.Locales), plugin.Locales)
	}
	if plugin.Locales["zh-CN"].Description != "增加示例提供商支持。" {
		t.Fatalf("zh-CN locale = %#v, want trimmed description", plugin.Locales["zh-CN"])
	}
	if plugin.Locales["ja"].Description != "サンプルプロバイダーを追加します。" {
		t.Fatalf("ja locale = %#v, want trimmed description", plugin.Locales["ja"])
	}
}

func TestValidateRegistryAllowsMissingVersion(t *testing.T) {
	t.Parallel()

	registry := Registry{SchemaVersion: 1, Plugins: []Plugin{{
		ID:          "sample-provider",
		Name:        "Sample Provider",
		Description: "Adds sample provider support.",
		Author:      "author-name",
		Repository:  "https://github.com/author-name/cliproxy-sample-provider-plugin",
	}}}
	if errValidate := ValidateRegistry(registry); errValidate != nil {
		t.Fatalf("ValidateRegistry() error = %v, want nil for missing version", errValidate)
	}
}

func TestParseRegistrySupportsDirectInstall(t *testing.T) {
	t.Parallel()

	registry, errParse := ParseRegistry([]byte(`{
		"schema_version": 2,
		"plugins": [{
			"id": "sample-provider",
			"name": "Sample Provider",
			"description": "Adds sample provider support.",
			"author": "author-name",
			"version": "0.2.0",
			"auth_required": true,
			"install": {
				"type": "direct",
				"artifacts": [{
					"goos": "windows",
					"goarch": "x64",
					"url": "https://downloads.example/sample-provider.zip",
					"sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
				}]
			},
			"versions": [{
				"version": "0.1.0",
				"install": {
					"type": "direct",
					"artifacts": [{
						"goos": "linux",
						"goarch": "aarch64",
						"url": "https://downloads.example/sample-provider-0.1.0.zip",
						"sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
					}]
				}
			}]
		}]
	}`))
	if errParse != nil {
		t.Fatalf("ParseRegistry() error = %v", errParse)
	}
	plugin, ok := registry.PluginByID("sample-provider")
	if !ok {
		t.Fatal("PluginByID(sample-provider) missing")
	}
	if PluginInstallType(plugin) != InstallTypeDirect {
		t.Fatalf("install type = %q, want direct", PluginInstallType(plugin))
	}
	if !plugin.AuthRequired {
		t.Fatal("AuthRequired = false, want true")
	}
	if len(plugin.Versions) != 1 || plugin.Versions[0].Version != "0.1.0" {
		t.Fatalf("versions = %#v, want normalized 0.1.0 entry", plugin.Versions)
	}
	platforms := PluginPlatforms(plugin)
	if len(platforms) != 2 ||
		platforms[0].GOOS != "windows" || platforms[0].GOARCH != "amd64" ||
		platforms[1].GOOS != "linux" || platforms[1].GOARCH != "arm64" {
		t.Fatalf("platforms = %#v, want normalized windows/amd64 and linux/arm64", platforms)
	}
	artifacts := PluginArtifacts(plugin)
	if len(artifacts) != 2 ||
		artifacts[0].GOOS != "windows" || artifacts[0].GOARCH != "amd64" ||
		artifacts[1].GOOS != "linux" || artifacts[1].GOARCH != "arm64" {
		t.Fatalf("artifacts = %#v, want normalized top-level and version artifacts", artifacts)
	}
}

func TestValidateRegistryRejectsInvalidDirectInstall(t *testing.T) {
	t.Parallel()

	registry := Registry{SchemaVersion: SchemaVersionV2, Plugins: []Plugin{{
		ID:          "sample-provider",
		Name:        "Sample Provider",
		Description: "Adds sample provider support.",
		Author:      "author-name",
		Version:     "0.2.0",
		Install: InstallPlan{
			Type: InstallTypeDirect,
			Artifacts: []Artifact{{
				GOOS:   "linux",
				GOARCH: "amd64",
				URL:    "https://downloads.example/sample.zip?token=secret",
				SHA256: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
			}},
		},
	}}}
	errValidate := ValidateRegistry(registry)
	if errValidate == nil {
		t.Fatal("ValidateRegistry() error = nil")
	}
	if !strings.Contains(errValidate.Error(), "sensitive query") {
		t.Fatalf("ValidateRegistry() error = %v, want sensitive query", errValidate)
	}
}

func TestValidateRegistryRejectsDirectInstallInSchemaV1(t *testing.T) {
	t.Parallel()

	registry := Registry{SchemaVersion: SchemaVersion, Plugins: []Plugin{{
		ID:          "sample-provider",
		Name:        "Sample Provider",
		Description: "Adds sample provider support.",
		Author:      "author-name",
		Version:     "0.2.0",
		Install: InstallPlan{
			Type: InstallTypeDirect,
			Artifacts: []Artifact{{
				GOOS:   "linux",
				GOARCH: "amd64",
				URL:    "https://downloads.example/sample.zip",
				SHA256: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
			}},
		},
	}}}
	errValidate := ValidateRegistry(registry)
	if errValidate == nil {
		t.Fatal("ValidateRegistry() error = nil")
	}
	if !strings.Contains(errValidate.Error(), "schema_version 2") {
		t.Fatalf("ValidateRegistry() error = %v, want schema_version 2", errValidate)
	}
}

func TestValidateRegistryRejectsInvalidEntries(t *testing.T) {
	t.Parallel()

	valid := Plugin{
		ID:          "sample-provider",
		Name:        "Sample Provider",
		Description: "Adds sample provider support.",
		Author:      "author-name",
		Version:     "0.1.0",
		Repository:  "https://github.com/author-name/cliproxy-sample-provider-plugin",
	}
	tests := []struct {
		name    string
		mutate  func(*Registry)
		wantErr string
	}{
		{
			name: "schema version",
			mutate: func(registry *Registry) {
				registry.SchemaVersion = 3
			},
			wantErr: "unsupported schema_version",
		},
		{
			name: "missing required field",
			mutate: func(registry *Registry) {
				registry.Plugins[0].Name = ""
			},
			wantErr: "missing required field name",
		},
		{
			name: "duplicate id",
			mutate: func(registry *Registry) {
				registry.Plugins = append(registry.Plugins, valid)
			},
			wantErr: "duplicate plugin id",
		},
		{
			name: "invalid id",
			mutate: func(registry *Registry) {
				registry.Plugins[0].ID = "../sample-provider"
			},
			wantErr: "invalid plugin id",
		},
		{
			name: "v-prefixed version",
			mutate: func(registry *Registry) {
				registry.Plugins[0].Version = "v0.1.0"
			},
			wantErr: "invalid plugin version",
		},
		{
			name: "invalid repository",
			mutate: func(registry *Registry) {
				registry.Plugins[0].Repository = "https://example.com/author/repo"
			},
			wantErr: "repository must be",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()

			registry := Registry{SchemaVersion: 1, Plugins: []Plugin{valid}}
			tt.mutate(&registry)
			errValidate := ValidateRegistry(registry)
			if errValidate == nil {
				t.Fatal("ValidateRegistry() error = nil")
			}
			if !strings.Contains(errValidate.Error(), tt.wantErr) {
				t.Fatalf("ValidateRegistry() error = %v, want substring %q", errValidate, tt.wantErr)
			}
		})
	}
}

func TestNormalizeSourcesAppendsURLsToDefaultSource(t *testing.T) {
	t.Parallel()

	sources, errNormalize := NormalizeSources([]string{" https://community.example/registry.json "})
	if errNormalize != nil {
		t.Fatalf("NormalizeSources() error = %v", errNormalize)
	}
	if len(sources) != 2 {
		t.Fatalf("sources len = %d, want 2", len(sources))
	}
	if sources[0].ID != DefaultSourceID || sources[0].URL != DefaultRegistryURL {
		t.Fatalf("default source = %#v", sources[0])
	}
	if sources[1].ID != SourceID("https://community.example/registry.json") ||
		sources[1].Name != "community.example" ||
		sources[1].URL != "https://community.example/registry.json" {
		t.Fatalf("third-party source = %#v", sources[1])
	}
}

func TestNormalizeSourcesSkipsDuplicates(t *testing.T) {
	t.Parallel()

	sources, errNormalize := NormalizeSources([]string{
		DefaultRegistryURL,
		"https://community.example/registry.json",
		"https://community.example/registry.json",
	})
	if errNormalize != nil {
		t.Fatalf("NormalizeSources() error = %v", errNormalize)
	}
	if len(sources) != 2 {
		t.Fatalf("sources len = %d, want 2: %#v", len(sources), sources)
	}
}

func TestGitHubRepositoryPartsRejectsNonRepositoryURLs(t *testing.T) {
	t.Parallel()

	tests := []string{
		"http://github.com/owner/repo",
		"https://github.com/owner",
		"https://github.com/owner/repo/issues",
		"https://github.com/owner/repo.git",
		"https://github.com/owner/repo?tab=readme",
	}
	for _, repository := range tests {
		t.Run(repository, func(t *testing.T) {
			t.Parallel()

			if _, _, errParse := GitHubRepositoryParts(repository); errParse == nil {
				t.Fatalf("GitHubRepositoryParts(%q) error = nil", repository)
			}
		})
	}
}