mcp-framework/bootstrap/login_test.go
thibaud-lclr d23d79b6c1 feat(bootstrap): ajouter DefaultLoginHandler et StandardConfigTestHandler
- DefaultLoginHandler(binaryName) : handler de login Bitwarden prêt à
  l'emploi avec confirmation. Remplace les réimplémentations identiques
  dans chaque MCP.
- StandardConfigTestHandler(opts) : handler de config test standard sans
  ManifestCheck. Accepte ConfigCheck, OpenStore, ConnectivityCheck et
  ExtraChecks.
- ManifestCheck dans RunDoctor devient opt-in : inclus uniquement si
  ManifestDir est fourni (artefact de build, pas de contrainte runtime).
- Supprime le handler mort CommandLogin dans bootstrap.Run, désormais
  remplacé par l'auto-disable et DefaultLoginHandler.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 10:45:51 +02:00

103 lines
2.5 KiB
Go

package bootstrap
import (
"bytes"
"context"
"errors"
"strings"
"testing"
"forge.lclr.dev/AI/mcp-framework/secretstore"
)
func withLoginBitwarden(t *testing.T, fn func(secretstore.BitwardenLoginOptions) (string, error)) {
t.Helper()
previous := loginBitwarden
loginBitwarden = fn
t.Cleanup(func() { loginBitwarden = previous })
}
func TestDefaultLoginHandlerPrintsConfirmation(t *testing.T) {
var stdout bytes.Buffer
withLoginBitwarden(t, func(opts secretstore.BitwardenLoginOptions) (string, error) {
if opts.ServiceName != "my-mcp" {
t.Fatalf("ServiceName = %q, want %q", opts.ServiceName, "my-mcp")
}
return "session-token", nil
})
handler := DefaultLoginHandler("my-mcp")
err := handler(context.Background(), Invocation{
Command: CommandLogin,
Stdout: &stdout,
})
if err != nil {
t.Fatalf("handler returned error: %v", err)
}
out := stdout.String()
if !strings.Contains(out, `"my-mcp"`) {
t.Fatalf("stdout = %q, want mention of binary name", out)
}
if !strings.Contains(out, "persistée") {
t.Fatalf("stdout = %q, want confirmation message", out)
}
}
func TestDefaultLoginHandlerPropagatesError(t *testing.T) {
var stdout bytes.Buffer
loginErr := errors.New("vault locked")
withLoginBitwarden(t, func(_ secretstore.BitwardenLoginOptions) (string, error) {
return "", loginErr
})
handler := DefaultLoginHandler("my-mcp")
err := handler(context.Background(), Invocation{
Command: CommandLogin,
Stdout: &stdout,
})
if !errors.Is(err, loginErr) {
t.Fatalf("err = %v, want %v", err, loginErr)
}
if stdout.Len() > 0 {
t.Fatalf("stdout should be empty on error, got %q", stdout.String())
}
}
func TestRunUsesDefaultLoginHandlerWhenHookSet(t *testing.T) {
var stdout bytes.Buffer
withLoginBitwarden(t, func(_ secretstore.BitwardenLoginOptions) (string, error) {
return "tok", nil
})
err := Run(context.Background(), Options{
BinaryName: "my-mcp",
Args: []string{"login"},
Stdout: &stdout,
Hooks: Hooks{
Login: DefaultLoginHandler("my-mcp"),
},
})
if err != nil {
t.Fatalf("Run error = %v", err)
}
if !strings.Contains(stdout.String(), "persistée") {
t.Fatalf("stdout = %q, want confirmation", stdout.String())
}
}
func TestRunLoginAutoHiddenWithoutHook(t *testing.T) {
var stdout bytes.Buffer
err := Run(context.Background(), Options{
BinaryName: "my-mcp",
Args: []string{"login"},
Stdout: &stdout,
})
if !errors.Is(err, ErrUnknownCommand) {
t.Fatalf("err = %v, want ErrUnknownCommand", err)
}
}