General API와 Coding Plan이 서로 다른 엔드포인트와 사용량 경계를 유지하도록 프로필, credential route, provider mapping, full-cycle 검증을 함께 반영한다.
458 lines
17 KiB
Go
458 lines
17 KiB
Go
package credentialstore
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"iop/packages/go/config"
|
|
)
|
|
|
|
func setupRouteTestFixture(t *testing.T) (*Store, *IssuedPrincipal, *CredentialSlotRecord, *CredentialSlotRecord) {
|
|
t.Helper()
|
|
dbPath := filepath.Join(t.TempDir(), "test_routes.db")
|
|
ctx := context.Background()
|
|
|
|
reg := newFakeKeyRegistry()
|
|
reg.RegisterKey("k1", 1)
|
|
|
|
store, err := Open(ctx, dbPath, WithEnvelopeKeyRegistry(reg))
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() { _ = store.Close() })
|
|
|
|
p, err := store.CreatePrincipalWithToken(ctx, CreatePrincipalInput{Alias: "route-principal"})
|
|
require.NoError(t, err)
|
|
|
|
env := SecretEnvelope{
|
|
Algorithm: "AES-256-GCM",
|
|
KeyID: "k1",
|
|
KeyVersion: 1,
|
|
Nonce: []byte("123456789012"),
|
|
Ciphertext: []byte("cipher1"),
|
|
}
|
|
|
|
openaiSlot, err := store.CreateSlot(ctx, CreateSlotInput{
|
|
PrincipalID: p.Principal.ID,
|
|
Vendor: "openai",
|
|
CredentialKind: CredentialKindBearer,
|
|
Alias: "openai-slot-1",
|
|
Envelope: env,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
anthropicSlot, err := store.CreateSlot(ctx, CreateSlotInput{
|
|
PrincipalID: p.Principal.ID,
|
|
Vendor: "anthropic",
|
|
CredentialKind: CredentialKindAPIKey,
|
|
Alias: "anthropic-slot-1",
|
|
Envelope: env,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
return store, p, openaiSlot, anthropicSlot
|
|
}
|
|
|
|
func TestRoutesDisambiguateSameUpstreamModelBySlot(t *testing.T) {
|
|
reg := newFakeKeyRegistry()
|
|
reg.RegisterKey("k1", 1)
|
|
dbPath := filepath.Join(t.TempDir(), "disambig.db")
|
|
ctx := context.Background()
|
|
|
|
store, err := Open(ctx, dbPath, WithEnvelopeKeyRegistry(reg))
|
|
require.NoError(t, err)
|
|
defer store.Close()
|
|
|
|
p, err := store.CreatePrincipalWithToken(ctx, CreatePrincipalInput{Alias: "p-disambig"})
|
|
require.NoError(t, err)
|
|
|
|
env := SecretEnvelope{
|
|
Algorithm: "AES-256-GCM",
|
|
KeyID: "k1",
|
|
KeyVersion: 1,
|
|
Nonce: []byte("123456789012"),
|
|
Ciphertext: []byte("cipher1"),
|
|
}
|
|
|
|
slotA, err := store.CreateSlot(ctx, CreateSlotInput{
|
|
PrincipalID: p.Principal.ID,
|
|
Vendor: "openai",
|
|
CredentialKind: CredentialKindBearer,
|
|
Alias: "slot-a",
|
|
Envelope: env,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
slotB, err := store.CreateSlot(ctx, CreateSlotInput{
|
|
PrincipalID: p.Principal.ID,
|
|
Vendor: "openai",
|
|
CredentialKind: CredentialKindBearer,
|
|
Alias: "slot-b",
|
|
Envelope: env,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Create Route 1 referencing slotA for gpt-4o
|
|
route1, err := store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p.Principal.ID,
|
|
SlotID: slotA.ID,
|
|
Alias: "route-gpt4o-a",
|
|
ProfileID: "openai",
|
|
UpstreamModel: "gpt-4o",
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, slotA.ID, route1.SlotID)
|
|
|
|
// Create Route 2 referencing slotB for gpt-4o
|
|
route2, err := store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p.Principal.ID,
|
|
SlotID: slotB.ID,
|
|
Alias: "route-gpt4o-b",
|
|
ProfileID: "openai",
|
|
UpstreamModel: "gpt-4o",
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, slotB.ID, route2.SlotID)
|
|
|
|
routes, err := store.ListRoutes(ctx, p.Principal.ID)
|
|
require.NoError(t, err)
|
|
require.Len(t, routes, 2)
|
|
}
|
|
|
|
func TestSlotSupportsMultipleCompatibleRoutes(t *testing.T) {
|
|
store, p, openaiSlot, _ := setupRouteTestFixture(t)
|
|
ctx := context.Background()
|
|
|
|
r1, err := store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p.Principal.ID,
|
|
SlotID: openaiSlot.ID,
|
|
Alias: "route-gpt4o",
|
|
ProfileID: "openai",
|
|
UpstreamModel: "gpt-4o",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
r2, err := store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p.Principal.ID,
|
|
SlotID: openaiSlot.ID,
|
|
Alias: "route-gpt4o-mini",
|
|
ProfileID: "openai",
|
|
UpstreamModel: "gpt-4o-mini",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
slotRoutes, err := store.ListRoutesBySlot(ctx, p.Principal.ID, openaiSlot.ID)
|
|
require.NoError(t, err)
|
|
require.Len(t, slotRoutes, 2)
|
|
require.Equal(t, r1.ID, slotRoutes[0].ID)
|
|
require.Equal(t, r2.ID, slotRoutes[1].ID)
|
|
}
|
|
|
|
func TestRouteRejectsCrossPrincipalSlot(t *testing.T) {
|
|
store, _, openaiSlotP1, _ := setupRouteTestFixture(t)
|
|
ctx := context.Background()
|
|
|
|
p2, err := store.CreatePrincipalWithToken(ctx, CreatePrincipalInput{Alias: "principal-2"})
|
|
require.NoError(t, err)
|
|
|
|
// Attempting to create a route for P2 using P1's slot must fail
|
|
_, err = store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p2.Principal.ID,
|
|
SlotID: openaiSlotP1.ID,
|
|
Alias: "p2-route",
|
|
ProfileID: "openai",
|
|
UpstreamModel: "gpt-4o",
|
|
})
|
|
require.Error(t, err)
|
|
require.ErrorIs(t, err, ErrCrossPrincipalSlot)
|
|
}
|
|
|
|
func TestRouteRejectsIncompatibleProfile(t *testing.T) {
|
|
store, p, openaiSlot, anthropicSlot := setupRouteTestFixture(t)
|
|
ctx := context.Background()
|
|
|
|
// OpenAI slot with Anthropic profile should fail
|
|
_, err := store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p.Principal.ID,
|
|
SlotID: openaiSlot.ID,
|
|
Alias: "bad-route-1",
|
|
ProfileID: "anthropic",
|
|
UpstreamModel: "claude-3-5-sonnet",
|
|
})
|
|
require.Error(t, err)
|
|
require.ErrorIs(t, err, ErrIncompatibleProfile)
|
|
|
|
// Anthropic slot with OpenAI profile should fail
|
|
_, err = store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p.Principal.ID,
|
|
SlotID: anthropicSlot.ID,
|
|
Alias: "bad-route-2",
|
|
ProfileID: "openai",
|
|
UpstreamModel: "gpt-4o",
|
|
})
|
|
require.Error(t, err)
|
|
require.ErrorIs(t, err, ErrIncompatibleProfile)
|
|
}
|
|
|
|
func TestRouteAliasCollisionFailsClosed(t *testing.T) {
|
|
store, p, openaiSlot, _ := setupRouteTestFixture(t)
|
|
ctx := context.Background()
|
|
|
|
_, err := store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p.Principal.ID,
|
|
SlotID: openaiSlot.ID,
|
|
Alias: "my-route-alias",
|
|
ProfileID: "openai",
|
|
UpstreamModel: "gpt-4o",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
_, err = store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p.Principal.ID,
|
|
SlotID: openaiSlot.ID,
|
|
Alias: "my-route-alias",
|
|
ProfileID: "openai",
|
|
UpstreamModel: "gpt-4o-mini",
|
|
})
|
|
require.Error(t, err)
|
|
require.ErrorIs(t, err, ErrRouteAliasAlreadyExists)
|
|
}
|
|
|
|
func TestSlotSupportsCompatibleChatAndMessagesProfiles(t *testing.T) {
|
|
reg := newFakeKeyRegistry()
|
|
reg.RegisterKey("k1", 1)
|
|
store, p := setupTestStoreWithRegistry(t, reg)
|
|
ctx := context.Background()
|
|
slot, err := store.CreateSlot(ctx, CreateSlotInput{
|
|
PrincipalID: p.Principal.ID, Vendor: "minimax", CredentialKind: CredentialKindBearer, Alias: "minimax",
|
|
Envelope: SecretEnvelope{Algorithm: "AES-256-GCM", KeyID: "k1", KeyVersion: 1, Nonce: []byte("123456789012"), Ciphertext: []byte("opaque")},
|
|
})
|
|
require.NoError(t, err)
|
|
chat, err := store.CreateRoute(ctx, CreateRouteInput{PrincipalID: p.Principal.ID, SlotID: slot.ID, Alias: "mini-chat", ProfileID: "minimax_chat", UpstreamModel: "MiniMax-M2"})
|
|
require.NoError(t, err)
|
|
messages, err := store.CreateRoute(ctx, CreateRouteInput{PrincipalID: p.Principal.ID, SlotID: slot.ID, Alias: "mini-messages", ProfileID: "minimax_messages", UpstreamModel: "MiniMax-M2"})
|
|
require.NoError(t, err)
|
|
require.NotEqual(t, chat.ProfileID, messages.ProfileID)
|
|
routes, err := store.ListRoutesBySlot(ctx, p.Principal.ID, slot.ID)
|
|
require.NoError(t, err)
|
|
require.Len(t, routes, 2)
|
|
}
|
|
|
|
// TestGLMSlotSupportsGeneralAndCodingProfiles verifies that a single
|
|
// glm/bearer credential slot can bind two distinct routes — one for General
|
|
// API and one for Coding Plan — each with its own alias, profile, and
|
|
// resource selector, while a different vendor slot rejects glm_coding.
|
|
// Official endpoint distinction rechecked on 2026-08-02:
|
|
// https://docs.z.ai/api-reference/introduction
|
|
// https://docs.z.ai/scenario-example/develop-tools/others
|
|
func TestGLMSlotSupportsGeneralAndCodingProfiles(t *testing.T) {
|
|
reg := newFakeKeyRegistry()
|
|
reg.RegisterKey("k1", 1)
|
|
store, p := setupTestStoreWithRegistry(t, reg)
|
|
ctx := context.Background()
|
|
|
|
env := SecretEnvelope{
|
|
Algorithm: "AES-256-GCM",
|
|
KeyID: "k1",
|
|
KeyVersion: 1,
|
|
Nonce: []byte("123456789012"),
|
|
Ciphertext: []byte("opaque-glm"),
|
|
}
|
|
|
|
slot, err := store.CreateSlot(ctx, CreateSlotInput{
|
|
PrincipalID: p.Principal.ID,
|
|
Vendor: "glm",
|
|
CredentialKind: CredentialKindBearer,
|
|
Alias: "glm-slot",
|
|
Envelope: env,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
apiRoute, err := store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p.Principal.ID,
|
|
SlotID: slot.ID,
|
|
Alias: "glm-5.1-api",
|
|
ProfileID: "glm",
|
|
UpstreamModel: "glm-5.1",
|
|
ResourceSelector: "glm-api",
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, "glm", apiRoute.ProfileID)
|
|
require.Equal(t, "glm-5.1-api", apiRoute.Alias)
|
|
require.Equal(t, "glm-api", apiRoute.ResourceSelector)
|
|
|
|
codingRoute, err := store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p.Principal.ID,
|
|
SlotID: slot.ID,
|
|
Alias: "glm-5.1-coding",
|
|
ProfileID: "glm_coding",
|
|
UpstreamModel: "glm-5.1",
|
|
ResourceSelector: "glm-coding",
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, "glm_coding", codingRoute.ProfileID)
|
|
require.Equal(t, "glm-5.1-coding", codingRoute.Alias)
|
|
require.Equal(t, "glm-coding", codingRoute.ResourceSelector)
|
|
|
|
require.NotEqual(t, apiRoute.ID, codingRoute.ID, "two routes must have distinct IDs")
|
|
|
|
routes, err := store.ListRoutes(ctx, p.Principal.ID)
|
|
require.NoError(t, err)
|
|
require.Len(t, routes, 2)
|
|
|
|
routesBySlot, err := store.ListRoutesBySlot(ctx, p.Principal.ID, slot.ID)
|
|
require.NoError(t, err)
|
|
require.Len(t, routesBySlot, 2)
|
|
|
|
// A different-vendor slot must reject glm_coding.
|
|
otherSlot, err := store.CreateSlot(ctx, CreateSlotInput{
|
|
PrincipalID: p.Principal.ID,
|
|
Vendor: "openai",
|
|
CredentialKind: CredentialKindBearer,
|
|
Alias: "openai-slot",
|
|
Envelope: env,
|
|
})
|
|
require.NoError(t, err)
|
|
_, err = store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p.Principal.ID,
|
|
SlotID: otherSlot.ID,
|
|
Alias: "openai-glm-coding",
|
|
ProfileID: "glm_coding",
|
|
UpstreamModel: "glm-5.1",
|
|
})
|
|
require.ErrorIs(t, err, ErrIncompatibleProfile)
|
|
}
|
|
|
|
func TestRouteRejectsUnknownVendorCredentialTuple(t *testing.T) {
|
|
reg := newFakeKeyRegistry()
|
|
reg.RegisterKey("k1", 1)
|
|
store, p := setupTestStoreWithRegistry(t, reg)
|
|
slot, err := store.CreateSlot(context.Background(), CreateSlotInput{
|
|
PrincipalID: p.Principal.ID, Vendor: "unknown-provider", CredentialKind: CredentialKindBearer, Alias: "unknown",
|
|
Envelope: SecretEnvelope{Algorithm: "AES-256-GCM", KeyID: "k1", KeyVersion: 1, Nonce: []byte("123456789012"), Ciphertext: []byte("opaque")},
|
|
})
|
|
require.NoError(t, err)
|
|
_, err = store.CreateRoute(context.Background(), CreateRouteInput{PrincipalID: p.Principal.ID, SlotID: slot.ID, ProfileID: "openai", UpstreamModel: "model"})
|
|
require.ErrorIs(t, err, ErrIncompatibleProfile)
|
|
|
|
mismatched, err := store.CreateSlot(context.Background(), CreateSlotInput{
|
|
PrincipalID: p.Principal.ID, Vendor: "openai", CredentialKind: CredentialKindAPIKey, Alias: "mismatched",
|
|
Envelope: SecretEnvelope{Algorithm: "AES-256-GCM", KeyID: "k1", KeyVersion: 1, Nonce: []byte("123456789012"), Ciphertext: []byte("opaque-2")},
|
|
})
|
|
require.NoError(t, err)
|
|
_, err = store.CreateRoute(context.Background(), CreateRouteInput{PrincipalID: p.Principal.ID, SlotID: mismatched.ID, ProfileID: "openai", UpstreamModel: "model"})
|
|
require.ErrorIs(t, err, ErrIncompatibleProfile)
|
|
}
|
|
|
|
func TestRouteResolutionUsesImmutableProfileCatalog(t *testing.T) {
|
|
store, p, slot, _ := setupRouteTestFixture(t)
|
|
ctx := context.Background()
|
|
|
|
original, ok := config.BuiltInProtocolProfiles["openai"]
|
|
require.True(t, ok)
|
|
delete(config.BuiltInProtocolProfiles, "openai")
|
|
t.Cleanup(func() { config.BuiltInProtocolProfiles["openai"] = original })
|
|
|
|
route, err := store.CreateRoute(ctx, CreateRouteInput{
|
|
PrincipalID: p.Principal.ID,
|
|
SlotID: slot.ID,
|
|
ProfileID: "openai",
|
|
UpstreamModel: "gpt-4o",
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, "openai", route.ProfileID)
|
|
}
|
|
|
|
func TestRouteRejectsInactiveSlot(t *testing.T) {
|
|
store, p, slot, _ := setupRouteTestFixture(t)
|
|
ctx := context.Background()
|
|
first, err := store.CreateRoute(ctx, CreateRouteInput{PrincipalID: p.Principal.ID, SlotID: slot.ID, ProfileID: "openai", UpstreamModel: "gpt-4o"})
|
|
require.NoError(t, err)
|
|
loaded, err := store.GetSlot(ctx, p.Principal.ID, slot.ID)
|
|
require.NoError(t, err)
|
|
disabled, err := store.DisableSlot(ctx, p.Principal.ID, slot.ID, loaded.Revision)
|
|
require.NoError(t, err)
|
|
_, err = store.CreateRoute(ctx, CreateRouteInput{PrincipalID: p.Principal.ID, SlotID: slot.ID, ProfileID: "openai", UpstreamModel: "gpt-4o-mini"})
|
|
require.ErrorIs(t, err, ErrSlotNotActive)
|
|
revoked, err := store.RevokeSlot(ctx, p.Principal.ID, slot.ID, disabled.Revision)
|
|
require.NoError(t, err)
|
|
_, err = store.CreateRoute(ctx, CreateRouteInput{PrincipalID: p.Principal.ID, SlotID: slot.ID, ProfileID: "openai", UpstreamModel: "gpt-4.1"})
|
|
require.ErrorIs(t, err, ErrSlotRevoked)
|
|
require.NotEmpty(t, first.ID)
|
|
require.Equal(t, StatusRevoked, revoked.Status)
|
|
}
|
|
|
|
func TestEnableRouteRejectsInactiveSlot(t *testing.T) {
|
|
store, p, slot, _ := setupRouteTestFixture(t)
|
|
ctx := context.Background()
|
|
route, err := store.CreateRoute(ctx, CreateRouteInput{PrincipalID: p.Principal.ID, SlotID: slot.ID, ProfileID: "openai", UpstreamModel: "gpt-4o"})
|
|
require.NoError(t, err)
|
|
disabledRoute, err := store.DisableRoute(ctx, p.Principal.ID, route.ID, route.Revision)
|
|
require.NoError(t, err)
|
|
loaded, err := store.GetSlot(ctx, p.Principal.ID, slot.ID)
|
|
require.NoError(t, err)
|
|
disabledSlot, err := store.DisableSlot(ctx, p.Principal.ID, slot.ID, loaded.Revision)
|
|
require.NoError(t, err)
|
|
_, err = store.EnableRoute(ctx, p.Principal.ID, route.ID, disabledRoute.Revision)
|
|
require.ErrorIs(t, err, ErrSlotNotActive)
|
|
_, err = store.EnableSlot(ctx, p.Principal.ID, slot.ID, disabledSlot.Revision)
|
|
require.NoError(t, err)
|
|
enabledRoute, err := store.EnableRoute(ctx, p.Principal.ID, route.ID, disabledRoute.Revision)
|
|
require.NoError(t, err)
|
|
require.Equal(t, StatusActive, enabledRoute.Status)
|
|
}
|
|
|
|
func TestUpdateRouteUsesRevisionCAS(t *testing.T) {
|
|
store, p, slot, _ := setupRouteTestFixture(t)
|
|
ctx := context.Background()
|
|
route, err := store.CreateRoute(ctx, CreateRouteInput{PrincipalID: p.Principal.ID, SlotID: slot.ID, Alias: "before", ProfileID: "openai", UpstreamModel: "gpt-4o"})
|
|
require.NoError(t, err)
|
|
updated, err := store.UpdateRoute(ctx, UpdateRouteInput{PrincipalID: p.Principal.ID, RouteID: route.ID, CurrentRevision: route.Revision, SlotID: slot.ID, Alias: " after ", ProfileID: "openai", UpstreamModel: "gpt-4.1", ResourceSelector: "preferred"})
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(1), updated.Revision)
|
|
require.Equal(t, "after", updated.Alias)
|
|
require.Equal(t, "gpt-4.1", updated.UpstreamModel)
|
|
require.Equal(t, "preferred", updated.ResourceSelector)
|
|
_, err = store.UpdateRoute(ctx, UpdateRouteInput{PrincipalID: p.Principal.ID, RouteID: route.ID, CurrentRevision: route.Revision, SlotID: slot.ID, Alias: "stale", ProfileID: "openai", UpstreamModel: "gpt-4o"})
|
|
require.ErrorIs(t, err, ErrRevisionMismatch)
|
|
}
|
|
|
|
func TestRouteAliasCannotShadowRouteID(t *testing.T) {
|
|
store, p, slot, _ := setupRouteTestFixture(t)
|
|
first, err := store.CreateRoute(context.Background(), CreateRouteInput{PrincipalID: p.Principal.ID, SlotID: slot.ID, Alias: "first", ProfileID: "openai", UpstreamModel: "gpt-4o"})
|
|
require.NoError(t, err)
|
|
_, err = store.CreateRoute(context.Background(), CreateRouteInput{PrincipalID: p.Principal.ID, SlotID: slot.ID, Alias: first.ID, ProfileID: "openai", UpstreamModel: "gpt-4.1"})
|
|
require.ErrorIs(t, err, ErrRouteAliasAlreadyExists)
|
|
}
|
|
|
|
func TestRouteLifecyclePersistsAcrossReopen(t *testing.T) {
|
|
ctx := context.Background()
|
|
dbPath := filepath.Join(t.TempDir(), "route-lifecycle.db")
|
|
reg := newFakeKeyRegistry()
|
|
reg.RegisterKey("k1", 1)
|
|
store, err := Open(ctx, dbPath, WithEnvelopeKeyRegistry(reg))
|
|
require.NoError(t, err)
|
|
p, err := store.CreatePrincipalWithToken(ctx, CreatePrincipalInput{Alias: "route-reopen"})
|
|
require.NoError(t, err)
|
|
slot, err := store.CreateSlot(ctx, CreateSlotInput{
|
|
PrincipalID: p.Principal.ID, Vendor: "openai", CredentialKind: CredentialKindBearer, Alias: "reopen-slot",
|
|
Envelope: SecretEnvelope{Algorithm: "AES-256-GCM", KeyID: "k1", KeyVersion: 1, Nonce: []byte("123456789012"), Ciphertext: []byte("opaque")},
|
|
})
|
|
require.NoError(t, err)
|
|
route, err := store.CreateRoute(ctx, CreateRouteInput{PrincipalID: p.Principal.ID, SlotID: slot.ID, Alias: "reopen-route", ProfileID: "openai", UpstreamModel: "gpt-4o", ResourceSelector: "primary"})
|
|
require.NoError(t, err)
|
|
disabled, err := store.DisableRoute(ctx, p.Principal.ID, route.ID, route.Revision)
|
|
require.NoError(t, err)
|
|
require.NoError(t, store.Close())
|
|
|
|
reopened, err := Open(ctx, dbPath, WithEnvelopeKeyRegistry(reg))
|
|
require.NoError(t, err)
|
|
defer reopened.Close()
|
|
loaded, err := reopened.GetRoute(ctx, p.Principal.ID, route.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, StatusDisabled, loaded.Status)
|
|
require.Equal(t, disabled.Revision, loaded.Revision)
|
|
require.Equal(t, "reopen-route", loaded.Alias)
|
|
require.Equal(t, "primary", loaded.ResourceSelector)
|
|
}
|