One registry line — `"openai": StaticKey`. The generic static-key adapter
already serves any vendor (accept is the vendor-independent seal, deliver is the
value unchanged, and refresh/identity/usage are not implemented), so a second
static-key vendor is data, not code. The shape-selection test now asserts
For("openai") reports static-key.
Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
121 lines
3.9 KiB
Go
121 lines
3.9 KiB
Go
package adapters
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestTheTwoShapesAreSelectedByVendor(t *testing.T) {
|
|
static, err := For("anthropic-api-key")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if static.Shape() != StaticKey {
|
|
t.Fatalf("anthropic-api-key is %q, expected static-key", static.Shape())
|
|
}
|
|
|
|
grant, err := For("anthropic")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if grant.Shape() != RefreshableGrant {
|
|
t.Fatalf("anthropic is %q, expected refreshable-grant", grant.Shape())
|
|
}
|
|
|
|
// openai is a second static-key vendor, served by the same generic adapter — the registry line is
|
|
// the whole of its integration, and it reports the static-key shape like any other.
|
|
openai, err := For("openai")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if openai.Shape() != StaticKey {
|
|
t.Fatalf("openai is %q, expected static-key", openai.Shape())
|
|
}
|
|
}
|
|
|
|
// The type assertion is what gates the carve-out: a static key is not a Refresher, so it can never
|
|
// reach the machinery that holds a token readably. A refreshable grant is one.
|
|
func TestOnlyARefreshableGrantIsARefresher(t *testing.T) {
|
|
static, _ := For("anthropic-api-key")
|
|
if _, ok := static.(Refresher); ok {
|
|
t.Fatal("a static-key adapter is a Refresher, so the carve-out is not gated by shape")
|
|
}
|
|
grant, _ := For("anthropic")
|
|
if _, ok := grant.(Refresher); !ok {
|
|
t.Fatal("a refreshable-grant adapter is not a Refresher, so it cannot be refreshed")
|
|
}
|
|
}
|
|
|
|
// With nothing plugged in, a refresh is refused in a way that names why — not answered with a
|
|
// silent no-op that would look like a refresh that changed nothing.
|
|
func TestARefreshWithNoRefresherPluggedInIsRefused(t *testing.T) {
|
|
grant, _ := For("anthropic")
|
|
r := grant.(Refresher)
|
|
_, err := r.Refresh(context.Background(), RefreshInput{Licence: "personal"})
|
|
if err == nil {
|
|
t.Fatal("a refresh succeeded with no vendor refresher plugged in")
|
|
}
|
|
if !strings.Contains(err.Error(), "Phase C") {
|
|
t.Fatalf("the refusal does not point at the missing plug-in: %v", err)
|
|
}
|
|
}
|
|
|
|
type fakeVendor struct {
|
|
result RefreshResult
|
|
got RefreshInput
|
|
}
|
|
|
|
func (f *fakeVendor) Refresh(_ context.Context, in RefreshInput) (RefreshResult, error) {
|
|
f.got = in
|
|
return f.result, nil
|
|
}
|
|
|
|
// A plugged-in refresher is dispatched to, and is handed the sealed refresh token (never a plaintext
|
|
// one) plus which node is the manager.
|
|
func TestAPluggedInRefresherIsDispatchedTo(t *testing.T) {
|
|
fake := &fakeVendor{result: RefreshResult{AccessToken: "at-new"}}
|
|
RegisterRefresher("anthropic", fake)
|
|
defer RegisterRefresher("anthropic", nil)
|
|
|
|
grant, _ := For("anthropic")
|
|
r := grant.(Refresher)
|
|
in := RefreshInput{
|
|
Licence: "personal", Manager: "workstation",
|
|
Sealed: "sealed-box", ManagerKey: "mk",
|
|
}
|
|
out, err := r.Refresh(context.Background(), in)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if out.AccessToken != "at-new" {
|
|
t.Fatalf("the dispatched result did not come back: %q", out.AccessToken)
|
|
}
|
|
if fake.got.Manager != "workstation" || fake.got.Sealed != "sealed-box" {
|
|
t.Fatalf("the refresher was handed the wrong input: %+v", fake.got)
|
|
}
|
|
}
|
|
|
|
// A vendor this build has no adapter for is refused, and the refusal lists what it does know so a
|
|
// typo and an unsupported vendor are told apart.
|
|
func TestAnUnknownVendorIsRefusedWithTheList(t *testing.T) {
|
|
_, err := For("acme-models")
|
|
if err == nil {
|
|
t.Fatal("an unknown vendor returned an adapter")
|
|
}
|
|
if !strings.Contains(err.Error(), "anthropic") {
|
|
t.Fatalf("the refusal does not list the known vendors: %v", err)
|
|
}
|
|
}
|
|
|
|
// Both shapes deliver their stored blob unchanged: a static key has no vendor step, and a
|
|
// refreshable grant's holder row holds an access token with no refresh token to strip.
|
|
func TestBothShapesDeliverTheStoredBlobUnchanged(t *testing.T) {
|
|
for _, vendor := range []string{"anthropic", "anthropic-api-key"} {
|
|
a, _ := For(vendor)
|
|
if got := a.Deliver("sealed-blob"); got != "sealed-blob" {
|
|
t.Fatalf("%s changed the delivered blob to %q", vendor, got)
|
|
}
|
|
}
|
|
}
|