picoclaw/pkg/skills/github_registry_test.go

218 lines
6.9 KiB
Go

package skills
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/sipeed/picoclaw/pkg/config"
)
func TestGitHubRegistrySearch(t *testing.T) {
var server *httptest.Server
server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/api/v3/search/code", r.URL.Path)
assert.Equal(t, "Bearer test-token", r.Header.Get("Authorization"))
assert.Equal(t, "skill search filename:SKILL.md", r.URL.Query().Get("q"))
assert.Equal(t, "2", r.URL.Query().Get("per_page"))
w.Header().Set("Content-Type", "application/json")
require.NoError(t, json.NewEncoder(w).Encode(gitHubCodeSearchResponse{
Items: []gitHubCodeSearchItem{
{
Path: "skills/pr-review/SKILL.md",
Score: 10,
HTMLURL: server.URL + "/foo/bar/blob/main/skills/pr-review/SKILL.md",
Repository: struct {
FullName string `json:"full_name"`
Name string `json:"name"`
Description string `json:"description"`
DefaultBranch string `json:"default_branch"`
}{
FullName: "foo/bar",
Name: "bar",
Description: "Review pull requests",
DefaultBranch: "main",
},
},
{
Path: "SKILL.md",
Score: 5,
HTMLURL: server.URL + "/foo/root/blob/main/SKILL.md",
Repository: struct {
FullName string `json:"full_name"`
Name string `json:"name"`
Description string `json:"description"`
DefaultBranch string `json:"default_branch"`
}{
FullName: "foo/root",
Name: "root",
Description: "Root skill",
DefaultBranch: "master",
},
},
},
}))
}))
defer server.Close()
provider := GitHubRegistryConfig{
Enabled: true,
BaseURL: server.URL,
AuthToken: "test-token",
}
registry := provider.BuildRegistry()
require.NotNil(t, registry)
results, err := registry.Search(context.Background(), "skill search", 2)
require.NoError(t, err)
require.Len(t, results, 2)
assert.Equal(t, "foo/bar/skills/pr-review", results[0].Slug)
assert.Equal(t, "pr-review", results[0].DisplayName)
assert.Equal(t, "Review pull requests", results[0].Summary)
assert.Equal(t, "main", results[0].Version)
assert.Equal(t, "github", results[0].RegistryName)
assert.Equal(t, "foo/root", results[1].Slug)
assert.Equal(t, "root", results[1].DisplayName)
assert.Equal(t, "master", results[1].Version)
}
func TestGitHubRegistryProviderDecodesProxyParam(t *testing.T) {
builder := buildRegistryProvider("github", config.SkillRegistryConfig{
Name: "github",
Enabled: true,
BaseURL: "https://github.com",
AuthToken: *config.NewSecureString("test-token"),
Param: map[string]any{
"proxy": "http://127.0.0.1:7890",
},
})
require.NotNil(t, builder)
registry := builder.BuildRegistry()
require.NotNil(t, registry)
ghRegistry, ok := registry.(*GitHubRegistry)
require.True(t, ok)
assert.Equal(t, "http://127.0.0.1:7890", ghRegistry.installer.proxy)
}
func TestGitHubRegistrySearchReturnsNoResultsOnUnauthenticatedRateLimit(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Empty(t, r.Header.Get("Authorization"))
w.WriteHeader(http.StatusForbidden)
_, _ = w.Write([]byte(`{"message":"API rate limit exceeded for 1.2.3.4"}`))
}))
defer server.Close()
registry := GitHubRegistryConfig{Enabled: true, BaseURL: server.URL}.BuildRegistry()
require.NotNil(t, registry)
results, err := registry.Search(context.Background(), "pr review", 5)
require.NoError(t, err)
assert.Empty(t, results)
}
func TestGitHubRegistrySearchReturnsNoResultsOnUnauthenticatedAuthRequired(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Empty(t, r.Header.Get("Authorization"))
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte(
`{"message":"Requires authentication","errors":[{"message":"Must be authenticated to access the code search API"}]}`,
))
}))
defer server.Close()
registry := GitHubRegistryConfig{Enabled: true, BaseURL: server.URL}.BuildRegistry()
require.NotNil(t, registry)
results, err := registry.Search(context.Background(), "pr review", 5)
require.NoError(t, err)
assert.Empty(t, results)
}
func TestGitHubRegistryGetSkillMetaCanonicalizesURLSlug(t *testing.T) {
registry := GitHubRegistryConfig{
Enabled: true,
BaseURL: "https://ghe.example.com/git",
}.BuildRegistry()
require.NotNil(t, registry)
meta, err := registry.GetSkillMeta(
context.Background(),
"https://ghe.example.com/git/org/repo/tree/dev/skills/pr-review",
)
require.NoError(t, err)
require.NotNil(t, meta)
assert.Equal(t, "org/repo/skills/pr-review", meta.Slug)
assert.Equal(t, "dev", meta.LatestVersion)
}
func TestGitHubRegistrySkillURLUsesProvidedVersionAndBasePath(t *testing.T) {
registry := GitHubRegistryConfig{
Enabled: true,
BaseURL: "https://ghe.example.com/git",
}.BuildRegistry()
require.NotNil(t, registry)
assert.Equal(
t,
"https://ghe.example.com/git/org/repo/tree/master/skills/pr-review",
registry.SkillURL("org/repo/skills/pr-review", "master"),
)
assert.Equal(
t,
"https://ghe.example.com/git/org/repo/tree/dev/skills/pr-review",
registry.SkillURL("https://ghe.example.com/git/org/repo/tree/dev/skills/pr-review", ""),
)
assert.Equal(
t,
"https://ghe.example.com/git/org/repo/tree/feature/skills-registry/skills/pr-review",
registry.SkillURL("org/repo/skills/pr-review", "feature/skills-registry"),
)
assert.Equal(
t,
"https://ghe.example.com/git/org/repo/blob/main/.agents/skills/pr-review/SKILL.md",
registry.SkillURL("https://ghe.example.com/git/org/repo/blob/main/.agents/skills/pr-review/SKILL.md", ""),
)
assert.Equal(
t,
"https://github.com/org/repo/tree/main/.agents/skills/pr-review",
registry.SkillURL("https://github.com/org/repo/tree/main/.agents/skills/pr-review", ""),
)
assert.Empty(t, registry.SkillURL("org/repo/.agents/skills/pr-review", ""))
}
func TestGitHubRegistryResolveInstallDirNameSupportsFullURLs(t *testing.T) {
registry := GitHubRegistryConfig{
Enabled: true,
BaseURL: "https://ghe.example.com/git",
}.BuildRegistry()
require.NotNil(t, registry)
dirName, err := registry.ResolveInstallDirName("https://ghe.example.com/git/org/repo/tree/dev/skills/pr-review")
require.NoError(t, err)
assert.Equal(t, "pr-review", dirName)
dirName, err = registry.ResolveInstallDirName("https://github.com/org/repo/tree/main/skills/release-checklist")
require.NoError(t, err)
assert.Equal(t, "release-checklist", dirName)
dirName, err = registry.ResolveInstallDirName(
"https://ghe.example.com/git/org/repo/blob/dev/skills/pr-review/SKILL.md",
)
require.NoError(t, err)
assert.Equal(t, "pr-review", dirName)
dirName, err = registry.ResolveInstallDirName(
"https://ghe.example.com/git/org/repo/blob/dev/SKILL.md",
)
require.NoError(t, err)
assert.Equal(t, "repo", dirName)
}