Skip to main content
Glama
mjmorales

simple-mcp-runner

by mjmorales
discovery_test.go8.22 kB
package discovery import ( "context" "os" "path/filepath" "runtime" "testing" "github.com/mjmorales/simple-mcp-runner/pkg/config" "github.com/mjmorales/simple-mcp-runner/internal/logger" "github.com/mjmorales/simple-mcp-runner/pkg/types" ) func TestDiscoverer_Discover(t *testing.T) { cfg := config.Default() log, _ := logger.New(logger.DefaultOptions()) disc := New(cfg, log) tests := []struct { name string req *types.CommandDiscoveryRequest wantErr bool check func(t *testing.T, result *types.CommandDiscoveryResult) }{ { name: "discover with wildcard pattern", req: &types.CommandDiscoveryRequest{ Pattern: "*", }, wantErr: false, check: func(t *testing.T, result *types.CommandDiscoveryResult) { if runtime.GOOS == "windows" { t.Skip("Skipping Unix command discovery test on Windows") } if len(result.Commands) == 0 { t.Error("expected to find at least one command") } // Should find common commands like echo, ls, etc. found := false for _, cmd := range result.Commands { if cmd.Name == "echo" || cmd.Name == "ls" { found = true break } } if !found { t.Error("expected to find common commands like echo or ls") } }, }, { name: "discover with specific pattern", req: &types.CommandDiscoveryRequest{ Pattern: "echo", }, wantErr: false, check: func(t *testing.T, result *types.CommandDiscoveryResult) { if runtime.GOOS == "windows" { t.Skip("Skipping Unix command discovery test on Windows") } found := false for _, cmd := range result.Commands { if cmd.Name == "echo" { found = true if cmd.Path == "" { t.Error("expected path to be set for echo command") } break } } if !found { t.Error("expected to find echo command") } }, }, { name: "discover with max results", req: &types.CommandDiscoveryRequest{ Pattern: "*", MaxResults: 5, }, wantErr: false, check: func(t *testing.T, result *types.CommandDiscoveryResult) { if len(result.Commands) > 5 { t.Errorf("expected at most 5 commands, got %d", len(result.Commands)) } if result.TotalFound <= 5 { if result.Truncated { t.Error("should not be truncated when total <= max") } } }, }, { name: "discover with descriptions", req: &types.CommandDiscoveryRequest{ Pattern: "ls", IncludeDesc: true, }, wantErr: false, check: func(t *testing.T, result *types.CommandDiscoveryResult) { if runtime.GOOS == "windows" { t.Skip("Skipping Unix command discovery test on Windows") } for _, cmd := range result.Commands { if cmd.Name == "ls" && cmd.Description == "" { t.Error("expected description for ls command") } } }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() result, err := disc.Discover(ctx, tt.req) if tt.wantErr { if err == nil { t.Error("expected error but got none") } return } if err != nil { t.Errorf("unexpected error: %v", err) return } if tt.check != nil { tt.check(t, result) } }) } } func TestDiscoverer_matchesPattern(t *testing.T) { cfg := config.Default() log, _ := logger.New(logger.DefaultOptions()) disc := New(cfg, log) tests := []struct { name string cmdName string pattern string expected bool }{ { name: "wildcard pattern with common command", cmdName: "echo", pattern: "*", expected: true, }, { name: "wildcard pattern with uncommon command", cmdName: "uncommon-cmd", pattern: "*", expected: false, }, { name: "exact match", cmdName: "echo", pattern: "echo", expected: true, }, { name: "glob pattern", cmdName: "git-status", pattern: "git*", expected: true, }, { name: "substring match", cmdName: "kubectl", pattern: "kube", expected: true, }, { name: "no match", cmdName: "echo", pattern: "cat", expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := disc.matchesPattern(tt.cmdName, tt.pattern) if result != tt.expected { t.Errorf("matchesPattern(%s, %s) = %v, want %v", tt.cmdName, tt.pattern, result, tt.expected) } }) } } func TestDiscoverer_isExecutable(t *testing.T) { cfg := config.Default() log, _ := logger.New(logger.DefaultOptions()) disc := New(cfg, log) // Create temp directory with test files tmpDir := t.TempDir() // Create executable file execFile := filepath.Join(tmpDir, "executable") if err := os.WriteFile(execFile, []byte("#!/bin/sh\necho test"), 0755); err != nil { t.Fatal(err) } // Create non-executable file nonExecFile := filepath.Join(tmpDir, "nonexecutable") if err := os.WriteFile(nonExecFile, []byte("test"), 0644); err != nil { t.Fatal(err) } tests := []struct { name string file string expected bool }{ { name: "executable file", file: execFile, expected: runtime.GOOS != "windows", // On Windows, we check extensions }, { name: "non-executable file", file: nonExecFile, expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { info, err := os.Stat(tt.file) if err != nil { t.Fatal(err) } result := disc.isExecutable(info) if result != tt.expected { t.Errorf("isExecutable(%s) = %v, want %v", tt.file, result, tt.expected) } }) } } func TestDiscoverer_getCommandDescription(t *testing.T) { cfg := config.Default() log, _ := logger.New(logger.DefaultOptions()) disc := New(cfg, log) tests := []struct { name string cmdName string expected string }{ { name: "known command", cmdName: "ls", expected: "List directory contents", }, { name: "known command with extension", cmdName: "ls.exe", expected: "List directory contents", }, { name: "git subcommand", cmdName: "git-status", expected: "Git subcommand", }, { name: "unknown command", cmdName: "unknowncmd", expected: "System command", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := disc.getCommandDescription(tt.cmdName) if result != tt.expected { t.Errorf("getCommandDescription(%s) = %v, want %v", tt.cmdName, result, tt.expected) } }) } } func TestDiscoverer_Cache(t *testing.T) { cfg := config.Default() log, _ := logger.New(logger.DefaultOptions()) disc := New(cfg, log) ctx := context.Background() req := &types.CommandDiscoveryRequest{ Pattern: "echo", } // First call should populate cache result1, err := disc.Discover(ctx, req) if err != nil { t.Fatal(err) } // Second call should use cache result2, err := disc.Discover(ctx, req) if err != nil { t.Fatal(err) } // Results should be identical if len(result1.Commands) != len(result2.Commands) { t.Error("cached result differs from original") } // Clear cache disc.ClearCache() // Next call should not use cache result3, err := disc.Discover(ctx, req) if err != nil { t.Fatal(err) } // Should still find same commands (but fresh discovery) if len(result1.Commands) != len(result3.Commands) { t.Error("fresh discovery differs from original") } } func TestDeduplicateCommands(t *testing.T) { cfg := config.Default() log, _ := logger.New(logger.DefaultOptions()) disc := New(cfg, log) commands := []types.CommandInfo{ {Name: "echo", Path: "/bin/echo"}, {Name: "ls", Path: "/bin/ls"}, {Name: "echo", Path: "/usr/bin/echo"}, // Duplicate {Name: "cat", Path: "/bin/cat"}, {Name: "ls", Path: "/usr/bin/ls"}, // Duplicate } result := disc.deduplicateCommands(commands) if len(result) != 3 { t.Errorf("expected 3 unique commands, got %d", len(result)) } // Check that we kept the first occurrence for _, cmd := range result { if cmd.Name == "echo" && cmd.Path != "/bin/echo" { t.Error("deduplication should keep first occurrence") } if cmd.Name == "ls" && cmd.Path != "/bin/ls" { t.Error("deduplication should keep first occurrence") } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mjmorales/simple-mcp-runner'

If you have feedback or need assistance with the MCP directory API, please join our Discord server