156 lines
4.6 KiB
Go
156 lines
4.6 KiB
Go
|
|
package bootstrap
|
||
|
|
|
||
|
|
import (
|
||
|
|
"bytes"
|
||
|
|
"context"
|
||
|
|
"errors"
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
fwcli "forge.lclr.dev/AI/mcp-framework/cli"
|
||
|
|
"forge.lclr.dev/AI/mcp-framework/secretstore"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestStandardConfigTestHandlerRendersChecks(t *testing.T) {
|
||
|
|
var stdout bytes.Buffer
|
||
|
|
|
||
|
|
handler := StandardConfigTestHandler(StandardConfigTestOptions{
|
||
|
|
ConfigCheck: func(context.Context) fwcli.DoctorResult {
|
||
|
|
return fwcli.DoctorResult{Name: "config", Status: fwcli.DoctorStatusOK, Summary: "config ok"}
|
||
|
|
},
|
||
|
|
ConnectivityCheck: func(context.Context) fwcli.DoctorResult {
|
||
|
|
return fwcli.DoctorResult{Name: "connectivity", Status: fwcli.DoctorStatusOK, Summary: "reachable"}
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
err := handler(context.Background(), Invocation{Command: CommandConfig, Stdout: &stdout})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("handler returned error: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
out := stdout.String()
|
||
|
|
if !strings.Contains(out, "[OK] config") {
|
||
|
|
t.Fatalf("stdout = %q, want [OK] config", out)
|
||
|
|
}
|
||
|
|
if !strings.Contains(out, "[OK] connectivity") {
|
||
|
|
t.Fatalf("stdout = %q, want [OK] connectivity", out)
|
||
|
|
}
|
||
|
|
if strings.Contains(out, "manifest") {
|
||
|
|
t.Fatalf("stdout should not contain manifest check, got:\n%s", out)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestStandardConfigTestHandlerIncludesSecretStoreCheck(t *testing.T) {
|
||
|
|
var stdout bytes.Buffer
|
||
|
|
|
||
|
|
handler := StandardConfigTestHandler(StandardConfigTestOptions{
|
||
|
|
OpenStore: func() (secretstore.Store, error) {
|
||
|
|
return secretstore.Open(secretstore.Options{
|
||
|
|
BackendPolicy: secretstore.BackendEnvOnly,
|
||
|
|
LookupEnv: func(string) (string, bool) { return "", false },
|
||
|
|
})
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
err := handler(context.Background(), Invocation{Command: CommandConfig, Stdout: &stdout})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("handler returned error: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if !strings.Contains(stdout.String(), "secret-store") {
|
||
|
|
t.Fatalf("stdout = %q, want secret-store check", stdout.String())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestStandardConfigTestHandlerReturnsErrorOnFailure(t *testing.T) {
|
||
|
|
var stdout bytes.Buffer
|
||
|
|
|
||
|
|
handler := StandardConfigTestHandler(StandardConfigTestOptions{
|
||
|
|
ConnectivityCheck: func(context.Context) fwcli.DoctorResult {
|
||
|
|
return fwcli.DoctorResult{Name: "connectivity", Status: fwcli.DoctorStatusFail, Summary: "unreachable"}
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
err := handler(context.Background(), Invocation{Command: CommandConfig, Stdout: &stdout})
|
||
|
|
if err == nil {
|
||
|
|
t.Fatal("handler should return error when checks fail")
|
||
|
|
}
|
||
|
|
if !strings.Contains(err.Error(), "config checks failed") {
|
||
|
|
t.Fatalf("err = %q, want 'config checks failed'", err.Error())
|
||
|
|
}
|
||
|
|
if !strings.Contains(stdout.String(), "[FAIL] connectivity") {
|
||
|
|
t.Fatalf("stdout = %q, want [FAIL] connectivity", stdout.String())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestStandardConfigTestHandlerOmitsManifestCheck(t *testing.T) {
|
||
|
|
var stdout bytes.Buffer
|
||
|
|
|
||
|
|
handler := StandardConfigTestHandler(StandardConfigTestOptions{
|
||
|
|
ExtraChecks: []fwcli.DoctorCheck{
|
||
|
|
func(context.Context) fwcli.DoctorResult {
|
||
|
|
return fwcli.DoctorResult{Name: "custom", Status: fwcli.DoctorStatusOK, Summary: "ok"}
|
||
|
|
},
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
err := handler(context.Background(), Invocation{Command: CommandConfig, Stdout: &stdout})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("handler returned error: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if strings.Contains(stdout.String(), "manifest") {
|
||
|
|
t.Fatalf("manifest check should not appear, got:\n%s", stdout.String())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestStandardConfigTestHandlerRunsViaBootstrap(t *testing.T) {
|
||
|
|
var stdout bytes.Buffer
|
||
|
|
openCalled := false
|
||
|
|
|
||
|
|
err := Run(context.Background(), Options{
|
||
|
|
BinaryName: "my-mcp",
|
||
|
|
Args: []string{"config", "test"},
|
||
|
|
Stdout: &stdout,
|
||
|
|
Hooks: Hooks{
|
||
|
|
ConfigTest: StandardConfigTestHandler(StandardConfigTestOptions{
|
||
|
|
OpenStore: func() (secretstore.Store, error) {
|
||
|
|
openCalled = true
|
||
|
|
return secretstore.Open(secretstore.Options{
|
||
|
|
BackendPolicy: secretstore.BackendEnvOnly,
|
||
|
|
LookupEnv: func(string) (string, bool) { return "", false },
|
||
|
|
})
|
||
|
|
},
|
||
|
|
}),
|
||
|
|
},
|
||
|
|
})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("Run error = %v", err)
|
||
|
|
}
|
||
|
|
if !openCalled {
|
||
|
|
t.Fatal("OpenStore should have been called")
|
||
|
|
}
|
||
|
|
if !strings.Contains(stdout.String(), "secret-store") {
|
||
|
|
t.Fatalf("stdout = %q, want secret-store in output", stdout.String())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestStandardConfigTestHandlerSecretStoreFailurePropagates(t *testing.T) {
|
||
|
|
var stdout bytes.Buffer
|
||
|
|
storeErr := errors.New("bitwarden unavailable")
|
||
|
|
|
||
|
|
handler := StandardConfigTestHandler(StandardConfigTestOptions{
|
||
|
|
OpenStore: func() (secretstore.Store, error) {
|
||
|
|
return nil, storeErr
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
err := handler(context.Background(), Invocation{Command: CommandConfig, Stdout: &stdout})
|
||
|
|
if err == nil {
|
||
|
|
t.Fatal("handler should return error when store fails")
|
||
|
|
}
|
||
|
|
if !strings.Contains(stdout.String(), "[FAIL] secret-store") {
|
||
|
|
t.Fatalf("stdout = %q, want [FAIL] secret-store", stdout.String())
|
||
|
|
}
|
||
|
|
}
|