chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
package github
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/github/github-mcp-server/pkg/inventory"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// stubTranslation is a simple translation function for testing
|
||||
func stubTranslation(_, fallback string) string {
|
||||
return fallback
|
||||
}
|
||||
|
||||
// TestAllToolsHaveRequiredMetadata validates that all tools have mandatory metadata:
|
||||
// - Toolset must be set (non-empty ID)
|
||||
// - ReadOnlyHint annotation must be explicitly set (not nil)
|
||||
func TestAllToolsHaveRequiredMetadata(t *testing.T) {
|
||||
tools := AllTools(stubTranslation)
|
||||
|
||||
require.NotEmpty(t, tools, "AllTools should return at least one tool")
|
||||
|
||||
for _, tool := range tools {
|
||||
t.Run(tool.Tool.Name, func(t *testing.T) {
|
||||
// Toolset ID must be set
|
||||
assert.NotEmpty(t, tool.Toolset.ID,
|
||||
"Tool %q must have a Toolset.ID", tool.Tool.Name)
|
||||
|
||||
// Toolset description should be set for documentation
|
||||
assert.NotEmpty(t, tool.Toolset.Description,
|
||||
"Tool %q should have a Toolset.Description", tool.Tool.Name)
|
||||
|
||||
// Annotations must exist and have ReadOnlyHint explicitly set
|
||||
require.NotNil(t, tool.Tool.Annotations,
|
||||
"Tool %q must have Annotations set (for ReadOnlyHint)", tool.Tool.Name)
|
||||
|
||||
// We can't distinguish between "not set" and "set to false" for a bool,
|
||||
// but having Annotations non-nil confirms the developer thought about it.
|
||||
// The ReadOnlyHint value itself is validated by ensuring Annotations exist.
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestAllResourcesHaveRequiredMetadata validates that all resources have mandatory metadata
|
||||
func TestAllResourcesHaveRequiredMetadata(t *testing.T) {
|
||||
// Resources are now stateless - no client functions needed
|
||||
resources := AllResources(stubTranslation)
|
||||
|
||||
require.NotEmpty(t, resources, "AllResources should return at least one resource")
|
||||
|
||||
for _, res := range resources {
|
||||
t.Run(res.Template.Name, func(t *testing.T) {
|
||||
// Toolset ID must be set
|
||||
assert.NotEmpty(t, res.Toolset.ID,
|
||||
"Resource %q must have a Toolset.ID", res.Template.Name)
|
||||
|
||||
// HandlerFunc must be set
|
||||
assert.True(t, res.HasHandler(),
|
||||
"Resource %q must have a HandlerFunc", res.Template.Name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestAllPromptsHaveRequiredMetadata validates that all prompts have mandatory metadata
|
||||
func TestAllPromptsHaveRequiredMetadata(t *testing.T) {
|
||||
prompts := AllPrompts(stubTranslation)
|
||||
|
||||
require.NotEmpty(t, prompts, "AllPrompts should return at least one prompt")
|
||||
|
||||
for _, prompt := range prompts {
|
||||
t.Run(prompt.Prompt.Name, func(t *testing.T) {
|
||||
// Toolset ID must be set
|
||||
assert.NotEmpty(t, prompt.Toolset.ID,
|
||||
"Prompt %q must have a Toolset.ID", prompt.Prompt.Name)
|
||||
|
||||
// Handler must be set
|
||||
assert.NotNil(t, prompt.Handler,
|
||||
"Prompt %q must have a Handler", prompt.Prompt.Name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestToolReadOnlyHintConsistency validates that read-only tools are correctly annotated
|
||||
func TestToolReadOnlyHintConsistency(t *testing.T) {
|
||||
tools := AllTools(stubTranslation)
|
||||
|
||||
for _, tool := range tools {
|
||||
t.Run(tool.Tool.Name, func(t *testing.T) {
|
||||
require.NotNil(t, tool.Tool.Annotations,
|
||||
"Tool %q must have Annotations", tool.Tool.Name)
|
||||
|
||||
// Verify IsReadOnly() method matches the annotation
|
||||
assert.Equal(t, tool.Tool.Annotations.ReadOnlyHint, tool.IsReadOnly(),
|
||||
"Tool %q: IsReadOnly() should match Annotations.ReadOnlyHint", tool.Tool.Name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestNoDuplicateToolNames ensures all tools have unique names
|
||||
func TestNoDuplicateToolNames(t *testing.T) {
|
||||
tools := AllTools(stubTranslation)
|
||||
seen := make(map[string]bool)
|
||||
featureFlagged := make(map[string]bool)
|
||||
|
||||
// get_label is intentionally in both issues and labels toolsets for conformance
|
||||
// with original behavior where it was registered in both
|
||||
allowedDuplicates := map[string]bool{
|
||||
"get_label": true,
|
||||
}
|
||||
|
||||
// First pass: identify tools that have feature flags (mutually exclusive at runtime)
|
||||
for _, tool := range tools {
|
||||
if tool.FeatureFlagEnable != "" || len(tool.FeatureFlagDisable) > 0 {
|
||||
featureFlagged[tool.Tool.Name] = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, tool := range tools {
|
||||
name := tool.Tool.Name
|
||||
// Allow duplicates for explicitly allowed tools and feature-flagged tools
|
||||
if !allowedDuplicates[name] && !featureFlagged[name] {
|
||||
assert.False(t, seen[name],
|
||||
"Duplicate tool name found: %q", name)
|
||||
}
|
||||
seen[name] = true
|
||||
}
|
||||
}
|
||||
|
||||
// TestNoDuplicateResourceNames ensures all resources have unique names
|
||||
func TestNoDuplicateResourceNames(t *testing.T) {
|
||||
resources := AllResources(stubTranslation)
|
||||
seen := make(map[string]bool)
|
||||
|
||||
for _, res := range resources {
|
||||
name := res.Template.Name
|
||||
assert.False(t, seen[name],
|
||||
"Duplicate resource name found: %q", name)
|
||||
seen[name] = true
|
||||
}
|
||||
}
|
||||
|
||||
// TestNoDuplicatePromptNames ensures all prompts have unique names
|
||||
func TestNoDuplicatePromptNames(t *testing.T) {
|
||||
prompts := AllPrompts(stubTranslation)
|
||||
seen := make(map[string]bool)
|
||||
|
||||
for _, prompt := range prompts {
|
||||
name := prompt.Prompt.Name
|
||||
assert.False(t, seen[name],
|
||||
"Duplicate prompt name found: %q", name)
|
||||
seen[name] = true
|
||||
}
|
||||
}
|
||||
|
||||
// TestAllToolsHaveHandlerFunc ensures all tools have a handler function
|
||||
func TestAllToolsHaveHandlerFunc(t *testing.T) {
|
||||
tools := AllTools(stubTranslation)
|
||||
|
||||
for _, tool := range tools {
|
||||
t.Run(tool.Tool.Name, func(t *testing.T) {
|
||||
assert.NotNil(t, tool.HandlerFunc,
|
||||
"Tool %q must have a HandlerFunc", tool.Tool.Name)
|
||||
assert.True(t, tool.HasHandler(),
|
||||
"Tool %q HasHandler() should return true", tool.Tool.Name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestToolsetMetadataConsistency ensures tools in the same toolset have consistent descriptions
|
||||
func TestToolsetMetadataConsistency(t *testing.T) {
|
||||
tools := AllTools(stubTranslation)
|
||||
toolsetDescriptions := make(map[inventory.ToolsetID]string)
|
||||
|
||||
for _, tool := range tools {
|
||||
id := tool.Toolset.ID
|
||||
desc := tool.Toolset.Description
|
||||
|
||||
if existing, ok := toolsetDescriptions[id]; ok {
|
||||
assert.Equal(t, existing, desc,
|
||||
"Toolset %q has inconsistent descriptions across tools", id)
|
||||
} else {
|
||||
toolsetDescriptions[id] = desc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitHubPackageDoesNotReadInsidersMode(t *testing.T) {
|
||||
files, err := filepath.Glob("*.go")
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, file := range files {
|
||||
if strings.HasSuffix(file, "_test.go") {
|
||||
continue
|
||||
}
|
||||
|
||||
fset := token.NewFileSet()
|
||||
node, err := parser.ParseFile(fset, file, nil, 0)
|
||||
require.NoError(t, err, "failed to parse %s", file)
|
||||
|
||||
ast.Inspect(node, func(n ast.Node) bool {
|
||||
selector, ok := n.(*ast.SelectorExpr)
|
||||
if !ok || selector.Sel.Name != "InsidersMode" {
|
||||
return true
|
||||
}
|
||||
|
||||
position := fset.Position(selector.Sel.Pos())
|
||||
t.Errorf("%s reads InsidersMode directly; gate behavior on concrete feature flags instead", position)
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user