mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-22 03:02:35 +00:00
186 lines
6 KiB
Go
186 lines
6 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"crypto/ed25519"
|
|
"encoding/base64"
|
|
"testing"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/ai/chat"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/config"
|
|
pkglicensing "github.com/rcourtman/pulse-go-rewrite/pkg/licensing"
|
|
)
|
|
|
|
func TestLoadHostedAwareAIConfig_DoesNotAutoBootstrapHostedQuickstart(t *testing.T) {
|
|
baseDir := t.TempDir()
|
|
mtp := config.NewMultiTenantPersistence(baseDir)
|
|
persistence, err := mtp.GetPersistence("default")
|
|
if err != nil {
|
|
t.Fatalf("GetPersistence(default): %v", err)
|
|
}
|
|
|
|
seedHostedAIBillingState(t, mtp, "default")
|
|
|
|
loaded, err := loadHostedAwareAIConfig(true, mtp.BaseDataDir(), "default", persistence)
|
|
if err != nil {
|
|
t.Fatalf("loadHostedAwareAIConfig(): %v", err)
|
|
}
|
|
if loaded == nil {
|
|
t.Fatal("expected default Pulse Assistant config")
|
|
}
|
|
if loaded.Enabled {
|
|
t.Fatal("expected hosted Pulse Assistant config to stay disabled until BYOK/local setup")
|
|
}
|
|
if loaded.Model != "" || loaded.ChatModel != "" || loaded.PatrolModel != "" {
|
|
t.Fatalf("expected no quickstart models, got model=%q chat=%q patrol=%q", loaded.Model, loaded.ChatModel, loaded.PatrolModel)
|
|
}
|
|
if persistence.HasAIConfig() {
|
|
t.Fatal("expected hosted AI loader not to persist an implicit quickstart config")
|
|
}
|
|
|
|
billingStore := config.NewFileBillingStore(mtp.BaseDataDir())
|
|
state, err := billingStore.GetBillingState("default")
|
|
if err != nil {
|
|
t.Fatalf("GetBillingState(default): %v", err)
|
|
}
|
|
if state == nil {
|
|
t.Fatal("expected hosted billing state to remain readable")
|
|
}
|
|
if state.QuickstartCreditsGranted {
|
|
t.Fatal("expected hosted AI loader not to grant quickstart credits")
|
|
}
|
|
}
|
|
|
|
func TestLoadHostedAwareAIConfig_DoesNotOverrideExplicitAIConfig(t *testing.T) {
|
|
baseDir := t.TempDir()
|
|
mtp := config.NewMultiTenantPersistence(baseDir)
|
|
persistence, err := mtp.GetPersistence("default")
|
|
if err != nil {
|
|
t.Fatalf("GetPersistence(default): %v", err)
|
|
}
|
|
|
|
seedHostedAIBillingState(t, mtp, "default")
|
|
|
|
explicit := config.NewDefaultAIConfig()
|
|
explicit.Enabled = false
|
|
explicit.Model = "anthropic:existing-explicit-model"
|
|
if err := persistence.SaveAIConfig(*explicit); err != nil {
|
|
t.Fatalf("SaveAIConfig(): %v", err)
|
|
}
|
|
|
|
loaded, err := loadHostedAwareAIConfig(true, mtp.BaseDataDir(), "default", persistence)
|
|
if err != nil {
|
|
t.Fatalf("loadHostedAwareAIConfig(): %v", err)
|
|
}
|
|
if loaded == nil {
|
|
t.Fatal("expected explicit Pulse Assistant config")
|
|
}
|
|
if loaded.Enabled {
|
|
t.Fatal("expected explicit disabled Pulse Assistant config to remain disabled")
|
|
}
|
|
if loaded.Model != explicit.Model {
|
|
t.Fatalf("model=%q, want %q", loaded.Model, explicit.Model)
|
|
}
|
|
}
|
|
|
|
func TestLoadHostedAwareAIConfig_HostedTenantFallsBackToDefaultBillingState(t *testing.T) {
|
|
baseDir := t.TempDir()
|
|
mtp := config.NewMultiTenantPersistence(baseDir)
|
|
persistence, err := mtp.GetPersistence("t-tenant")
|
|
if err != nil {
|
|
t.Fatalf("GetPersistence(t-tenant): %v", err)
|
|
}
|
|
|
|
seedHostedAIBillingState(t, mtp, "default")
|
|
|
|
loaded, err := loadHostedAwareAIConfig(true, mtp.BaseDataDir(), "t-tenant", persistence)
|
|
if err != nil {
|
|
t.Fatalf("loadHostedAwareAIConfig(): %v", err)
|
|
}
|
|
if loaded == nil {
|
|
t.Fatal("expected default tenant AI config")
|
|
}
|
|
if loaded.Enabled {
|
|
t.Fatalf("expected hosted tenant AI config to stay disabled until BYOK/local setup, got %#v", loaded)
|
|
}
|
|
if persistence.HasAIConfig() {
|
|
t.Fatal("expected hosted tenant AI loader not to persist an implicit quickstart config")
|
|
}
|
|
|
|
billingStore := config.NewFileBillingStore(mtp.BaseDataDir())
|
|
defaultState, err := billingStore.GetBillingState("default")
|
|
if err != nil {
|
|
t.Fatalf("GetBillingState(default): %v", err)
|
|
}
|
|
if defaultState == nil {
|
|
t.Fatal("expected hosted tenant AI loader to keep default hosted billing state readable")
|
|
}
|
|
if defaultState.QuickstartCreditsGranted {
|
|
t.Fatal("expected hosted tenant AI loader not to grant quickstart credits")
|
|
}
|
|
tenantState, err := billingStore.GetBillingState("t-tenant")
|
|
if err != nil {
|
|
t.Fatalf("GetBillingState(t-tenant): %v", err)
|
|
}
|
|
if tenantState != nil && tenantState.SubscriptionState != "" {
|
|
t.Fatalf("expected tenant org to avoid shadow billing state, got %#v", tenantState)
|
|
}
|
|
}
|
|
|
|
func TestAIHandlerStart_DoesNotAutoBootstrapHostedQuickstartService(t *testing.T) {
|
|
oldNewService := newChatService
|
|
defer func() { newChatService = oldNewService }()
|
|
|
|
newChatService = func(chat.Config) AIService {
|
|
t.Fatal("newChatService must not be called without explicit BYOK/local AI config")
|
|
return nil
|
|
}
|
|
|
|
baseDir := t.TempDir()
|
|
mtp := config.NewMultiTenantPersistence(baseDir)
|
|
persistence, err := mtp.GetPersistence("default")
|
|
if err != nil {
|
|
t.Fatalf("GetPersistence(default): %v", err)
|
|
}
|
|
seedHostedAIBillingState(t, mtp, "default")
|
|
|
|
handler := NewAIHandler(mtp, nil, nil)
|
|
handler.defaultPersistence = persistence
|
|
handler.hostedMode = true
|
|
|
|
if err := handler.Start(context.Background(), nil); err != nil {
|
|
t.Fatalf("Start(): %v", err)
|
|
}
|
|
if handler.defaultService != nil {
|
|
t.Fatal("expected hosted start not to create a quickstart-backed service")
|
|
}
|
|
}
|
|
|
|
func seedHostedAIBillingState(t *testing.T, mtp *config.MultiTenantPersistence, orgID string) {
|
|
t.Helper()
|
|
|
|
pub, priv, err := ed25519.GenerateKey(nil)
|
|
if err != nil {
|
|
t.Fatalf("generate entitlement keypair: %v", err)
|
|
}
|
|
t.Setenv(pkglicensing.TrialActivationPublicKeyEnvVar, base64.StdEncoding.EncodeToString(pub))
|
|
|
|
entitlementJWT, err := pkglicensing.SignEntitlementLeaseToken(priv, pkglicensing.EntitlementLeaseClaims{
|
|
OrgID: orgID,
|
|
InstanceHost: "t-hostedai.cloud.pulserelay.pro",
|
|
PlanVersion: "msp_starter",
|
|
SubscriptionState: pkglicensing.SubStateActive,
|
|
Capabilities: []string{pkglicensing.FeatureAIPatrol, pkglicensing.FeatureAIAutoFix},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("SignEntitlementLeaseToken(): %v", err)
|
|
}
|
|
|
|
billingStore := config.NewFileBillingStore(mtp.BaseDataDir())
|
|
if err := billingStore.SaveBillingState(orgID, &billingState{
|
|
EntitlementJWT: entitlementJWT,
|
|
EntitlementRefreshToken: "etr_hosted_test_bootstrap",
|
|
}); err != nil {
|
|
t.Fatalf("SaveBillingState(): %v", err)
|
|
}
|
|
}
|