213 lines
6.7 KiB
Go
213 lines
6.7 KiB
Go
package webdemo
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestServerServesSplitUIAndFakeInput(t *testing.T) {
|
|
server := httptest.NewServer(NewServer(NewFakeInput()))
|
|
defer server.Close()
|
|
|
|
for _, path := range []string{"/ui", "/ui-config.js", "/styles/base.css", "/styles/keys.css", "/styles/usage.css", "/styles/pricing.css", "/app/main.js", "/app/core/runtime.js", "/app/features/keys.js", "/app/features/usage.js", "/app/features/pricing.js", "/v0/resource/plugins/billing/ui-config.js", "/v0/resource/plugins/billing/styles/base.css", "/v0/resource/plugins/billing/app/main.js"} {
|
|
response, err := http.Get(server.URL + path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if response.StatusCode != http.StatusOK {
|
|
response.Body.Close()
|
|
t.Fatalf("GET %s status = %d", path, response.StatusCode)
|
|
}
|
|
response.Body.Close()
|
|
}
|
|
|
|
configResponse, err := http.Get(server.URL + "/ui-config.js")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer configResponse.Body.Close()
|
|
configBody, err := io.ReadAll(configResponse.Body)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(string(configBody), "demoPerspectives:true") || !strings.Contains(string(configBody), `readOnlyBase:"/v0/resource/plugins/billing/ui"`) {
|
|
t.Fatalf("demo config does not enable perspective switch: %s", configBody)
|
|
}
|
|
|
|
response, err := http.Get(server.URL + managementBase + "/usage?page=2&page_size=100&model=deepseek")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer response.Body.Close()
|
|
var usage struct {
|
|
Records []fakeUsage `json:"records"`
|
|
Page map[string]any `json:"pagination"`
|
|
}
|
|
if err := json.NewDecoder(response.Body).Decode(&usage); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if response.StatusCode != http.StatusOK || len(usage.Records) == 0 || usage.Page["page"] != float64(2) {
|
|
t.Fatalf("unexpected fake usage response: status=%d records=%d page=%v", response.StatusCode, len(usage.Records), usage.Page)
|
|
}
|
|
for _, record := range usage.Records {
|
|
if !strings.Contains(record.Model, "deepseek") {
|
|
t.Fatalf("unexpected filtered model %q", record.Model)
|
|
}
|
|
}
|
|
|
|
response, err = http.Get(server.URL + resourceUI + "?view=usage&page=8&page_size=100")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer response.Body.Close()
|
|
var readOnlyUsage struct {
|
|
Records []fakeUsage `json:"records"`
|
|
Page struct {
|
|
Page int `json:"page"`
|
|
PageSize int `json:"page_size"`
|
|
} `json:"pagination"`
|
|
}
|
|
if err := json.NewDecoder(response.Body).Decode(&readOnlyUsage); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(readOnlyUsage.Records) != 50 || readOnlyUsage.Page.Page != 1 || readOnlyUsage.Page.PageSize != 50 {
|
|
t.Fatalf("unexpected read-only usage: records=%d page=%+v", len(readOnlyUsage.Records), readOnlyUsage.Page)
|
|
}
|
|
|
|
response, err = http.Get(server.URL + managementBase + "/usage?page=1&page_size=1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer response.Body.Close()
|
|
var allUsage struct {
|
|
Page struct {
|
|
Total int `json:"total"`
|
|
} `json:"pagination"`
|
|
}
|
|
if err := json.NewDecoder(response.Body).Decode(&allUsage); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if allUsage.Page.Total != fakeUsageCount {
|
|
t.Fatalf("fake usage total = %d, want %d", allUsage.Page.Total, fakeUsageCount)
|
|
}
|
|
}
|
|
|
|
func TestFakeInputSupportsKeyMutation(t *testing.T) {
|
|
server := httptest.NewServer(NewServer(NewFakeInput()))
|
|
defer server.Close()
|
|
|
|
body := `{"name":"Demo User","route_mode":"auto","all_models":true,"billing":{"quota_usd":"25","reset_period":"none","max_concurrency":4}}`
|
|
request, err := http.NewRequest(http.MethodPost, server.URL+managementBase+"/keys", strings.NewReader(body))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
request.Header.Set("Content-Type", "application/json")
|
|
response, err := http.DefaultClient.Do(request)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer response.Body.Close()
|
|
var key fakeKey
|
|
if err := json.NewDecoder(response.Body).Decode(&key); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if response.StatusCode != http.StatusOK || key.Name != "Demo User" || key.Billing["balance_usd"] != "25.000000" {
|
|
t.Fatalf("unexpected created key: status=%d key=%+v", response.StatusCode, key)
|
|
}
|
|
}
|
|
|
|
func TestFakeDashboardIncludesSevenDailyCosts(t *testing.T) {
|
|
server := httptest.NewServer(NewServer(NewFakeInput()))
|
|
defer server.Close()
|
|
|
|
response, err := http.Get(server.URL + managementBase + "/usage-summary")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer response.Body.Close()
|
|
var dashboard struct {
|
|
Days []struct {
|
|
Date string `json:"date"`
|
|
CostUSD float64 `json:"cost_usd"`
|
|
} `json:"days"`
|
|
Users []struct {
|
|
Days []struct {
|
|
CostUSD float64 `json:"cost_usd"`
|
|
} `json:"days"`
|
|
} `json:"users"`
|
|
}
|
|
if err := json.NewDecoder(response.Body).Decode(&dashboard); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(dashboard.Days) != 7 || dashboard.Days[6].CostUSD <= 0 || len(dashboard.Users) == 0 || len(dashboard.Users[0].Days) != 7 {
|
|
t.Fatalf("unexpected daily costs: %+v", dashboard.Days)
|
|
}
|
|
}
|
|
|
|
func TestFakeDashboardHidesArchivedUsers(t *testing.T) {
|
|
input := NewFakeInput().(*fakeInput)
|
|
archivedID := input.keys[0].ID
|
|
input.keys[0].Status = "archived"
|
|
dashboard := input.dashboard()
|
|
users := dashboard["users"].([]map[string]any)
|
|
if len(users) != len(input.keys)-1 {
|
|
t.Fatalf("dashboard users = %d, want %d", len(users), len(input.keys)-1)
|
|
}
|
|
for _, user := range users {
|
|
if user["key_id"] == archivedID {
|
|
t.Fatalf("archived user %q remains in dashboard", archivedID)
|
|
}
|
|
}
|
|
if dashboard["today"].(map[string]any)["requests"].(int) == 0 {
|
|
t.Fatal("archived user usage should remain in overall totals")
|
|
}
|
|
}
|
|
|
|
func TestFakeDashboardHidesOptedOutUsers(t *testing.T) {
|
|
input := NewFakeInput().(*fakeInput)
|
|
hiddenID := input.keys[0].ID
|
|
input.keys[0].ShowInStats = false
|
|
dashboard := input.dashboard()
|
|
users := dashboard["users"].([]map[string]any)
|
|
if len(users) != len(input.keys)-1 {
|
|
t.Fatalf("dashboard users = %d, want %d", len(users), len(input.keys)-1)
|
|
}
|
|
for _, user := range users {
|
|
if user["key_id"] == hiddenID {
|
|
t.Fatalf("opted-out user %q remains in dashboard", hiddenID)
|
|
}
|
|
}
|
|
if dashboard["today"].(map[string]any)["requests"].(int) == 0 {
|
|
t.Fatal("opted-out user usage should remain in overall totals")
|
|
}
|
|
}
|
|
|
|
func TestDatabaseInputServesStandaloneBillingDatabase(t *testing.T) {
|
|
input, err := NewDatabaseInput(t.TempDir() + "/billing.db")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer input.Close()
|
|
server := httptest.NewServer(NewServer(input))
|
|
defer server.Close()
|
|
|
|
response, err := http.Get(server.URL + managementBase + "/keys")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer response.Body.Close()
|
|
var payload struct {
|
|
Keys []fakeKey `json:"keys"`
|
|
}
|
|
if err := json.NewDecoder(response.Body).Decode(&payload); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if response.StatusCode != http.StatusOK || len(payload.Keys) != 1 {
|
|
t.Fatalf("database input keys: status=%d keys=%d", response.StatusCode, len(payload.Keys))
|
|
}
|
|
}
|