145 lines
3.4 KiB
Go
145 lines
3.4 KiB
Go
package cli
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"forge.lclr.dev/AI/mcp-framework/secretstore"
|
|
)
|
|
|
|
type testSecretStore struct {
|
|
values map[string]string
|
|
errs map[string]error
|
|
}
|
|
|
|
func (s testSecretStore) SetSecret(name, label, secret string) error {
|
|
return nil
|
|
}
|
|
|
|
func (s testSecretStore) GetSecret(name string) (string, error) {
|
|
if err, ok := s.errs[name]; ok {
|
|
return "", err
|
|
}
|
|
value, ok := s.values[name]
|
|
if !ok {
|
|
return "", secretstore.ErrNotFound
|
|
}
|
|
return value, nil
|
|
}
|
|
|
|
func (s testSecretStore) DeleteSecret(name string) error {
|
|
return nil
|
|
}
|
|
|
|
func TestResolveLookupWithStandardProviders(t *testing.T) {
|
|
t.Setenv("MCP_PASSWORD", "")
|
|
|
|
lookup := ResolveLookup(ResolveLookupOptions{
|
|
Flag: MapLookup(map[string]string{"host": "https://flag.example.com"}),
|
|
Env: EnvLookup(nil),
|
|
Config: ConfigMap(map[string]string{"username": "config-user"}),
|
|
Secret: SecretStore(testSecretStore{
|
|
values: map[string]string{"smtp-password": "secret-password"},
|
|
}),
|
|
})
|
|
|
|
resolution, err := ResolveFields(ResolveOptions{
|
|
Fields: []FieldSpec{
|
|
{
|
|
Name: "host",
|
|
Required: true,
|
|
FlagKey: "host",
|
|
},
|
|
{
|
|
Name: "username",
|
|
Required: true,
|
|
EnvKey: "MCP_USERNAME",
|
|
ConfigKey: "username",
|
|
},
|
|
{
|
|
Name: "password",
|
|
Required: true,
|
|
EnvKey: "MCP_PASSWORD",
|
|
SecretKey: "smtp-password",
|
|
},
|
|
},
|
|
Lookup: lookup,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("ResolveFields returned error: %v", err)
|
|
}
|
|
|
|
host, _ := resolution.Get("host")
|
|
if host.Source != SourceFlag || host.Value != "https://flag.example.com" {
|
|
t.Fatalf("host = %+v", host)
|
|
}
|
|
|
|
username, _ := resolution.Get("username")
|
|
if username.Source != SourceConfig || username.Value != "config-user" {
|
|
t.Fatalf("username = %+v", username)
|
|
}
|
|
|
|
password, _ := resolution.Get("password")
|
|
if password.Source != SourceSecret || password.Value != "secret-password" {
|
|
t.Fatalf("password = %+v", password)
|
|
}
|
|
}
|
|
|
|
func TestSecretStoreProviderTreatsErrNotFoundAsMissing(t *testing.T) {
|
|
lookup := ResolveLookup(ResolveLookupOptions{
|
|
Secret: SecretStore(testSecretStore{
|
|
errs: map[string]error{"smtp-password": secretstore.ErrNotFound},
|
|
}),
|
|
})
|
|
|
|
resolution, err := ResolveFields(ResolveOptions{
|
|
Fields: []FieldSpec{
|
|
{
|
|
Name: "password",
|
|
Required: true,
|
|
SecretKey: "smtp-password",
|
|
DefaultValue: "fallback-password",
|
|
},
|
|
},
|
|
Lookup: lookup,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("ResolveFields returned error: %v", err)
|
|
}
|
|
|
|
password, _ := resolution.Get("password")
|
|
if password.Source != SourceDefault || password.Value != "fallback-password" {
|
|
t.Fatalf("password = %+v", password)
|
|
}
|
|
}
|
|
|
|
func TestSecretStoreProviderPropagatesBackendErrors(t *testing.T) {
|
|
backendErr := errors.New("backend unavailable")
|
|
lookup := ResolveLookup(ResolveLookupOptions{
|
|
Secret: SecretStore(testSecretStore{
|
|
errs: map[string]error{"smtp-password": backendErr},
|
|
}),
|
|
})
|
|
|
|
_, err := ResolveFields(ResolveOptions{
|
|
Fields: []FieldSpec{
|
|
{
|
|
Name: "password",
|
|
Required: true,
|
|
SecretKey: "smtp-password",
|
|
},
|
|
},
|
|
Lookup: lookup,
|
|
})
|
|
|
|
var sourceErr *SourceLookupError
|
|
if !errors.As(err, &sourceErr) {
|
|
t.Fatalf("ResolveFields error = %v, want SourceLookupError", err)
|
|
}
|
|
if sourceErr.Source != SourceSecret {
|
|
t.Fatalf("sourceErr.Source = %q, want %q", sourceErr.Source, SourceSecret)
|
|
}
|
|
if !errors.Is(err, backendErr) {
|
|
t.Fatalf("ResolveFields error should wrap backend error")
|
|
}
|
|
}
|