| package model |
|
|
| import ( |
| "encoding/json" |
| "math" |
| "testing" |
| ) |
|
|
| func TestAuthToken_IsModelAllowed(t *testing.T) { |
| t.Parallel() |
|
|
| tests := []struct { |
| name string |
| allowed []string |
| model string |
| expectedBool bool |
| }{ |
| {name: "empty_allowed_models_allows_any", allowed: nil, model: "gpt-4", expectedBool: true}, |
| {name: "case_insensitive_match", allowed: []string{"GPT-4", "claude"}, model: "gpt-4", expectedBool: true}, |
| {name: "no_match", allowed: []string{"gpt-4", "claude"}, model: "gemini", expectedBool: false}, |
| } |
|
|
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| token := &AuthToken{AllowedModels: tt.allowed} |
| if got := token.IsModelAllowed(tt.model); got != tt.expectedBool { |
| t.Fatalf("IsModelAllowed(%q) = %v, want %v", tt.model, got, tt.expectedBool) |
| } |
| }) |
| } |
| } |
|
|
| func TestAuthToken_IsChannelAllowed(t *testing.T) { |
| t.Parallel() |
|
|
| tests := []struct { |
| name string |
| allowed []int64 |
| channelID int64 |
| expectedBool bool |
| }{ |
| {name: "nil_allowed_channels_allows_any", allowed: nil, channelID: 42, expectedBool: true}, |
| {name: "empty_allowed_channels_allows_any", allowed: []int64{}, channelID: 42, expectedBool: true}, |
| {name: "listed_channel_is_allowed", allowed: []int64{2, 42}, channelID: 42, expectedBool: true}, |
| {name: "missing_channel_is_rejected", allowed: []int64{2, 7}, channelID: 42, expectedBool: false}, |
| } |
|
|
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| token := &AuthToken{AllowedChannelIDs: tt.allowed} |
| if got := token.IsChannelAllowed(tt.channelID); got != tt.expectedBool { |
| t.Fatalf("IsChannelAllowed(%d) = %v, want %v", tt.channelID, got, tt.expectedBool) |
| } |
| }) |
| } |
| } |
|
|
| func TestAuthToken_CostConversions(t *testing.T) { |
| t.Parallel() |
|
|
| token := &AuthToken{ |
| CostUsedMicroUSD: 1_230_000, |
| CostLimitMicroUSD: 4_500_000, |
| } |
| if got := token.CostUsedUSD(); math.Abs(got-1.23) > 1e-9 { |
| t.Fatalf("CostUsedUSD() = %v, want 1.23", got) |
| } |
| if got := token.CostLimitUSD(); math.Abs(got-4.5) > 1e-9 { |
| t.Fatalf("CostLimitUSD() = %v, want 4.5", got) |
| } |
|
|
| token.SetCostLimitUSD(0) |
| if token.CostLimitMicroUSD != 0 { |
| t.Fatalf("SetCostLimitUSD(0) should reset to 0 microUSD, got %d", token.CostLimitMicroUSD) |
| } |
|
|
| token.SetCostLimitUSD(1.5) |
| if token.CostLimitMicroUSD != 1_500_000 { |
| t.Fatalf("SetCostLimitUSD(1.5) microUSD = %d, want 1500000", token.CostLimitMicroUSD) |
| } |
| } |
|
|
| func TestAuthToken_MarshalJSON_ExposesCostFields(t *testing.T) { |
| t.Parallel() |
|
|
| token := AuthToken{ |
| ID: 123, |
| Token: "hash", |
| IsActive: true, |
| CostUsedMicroUSD: 250_000, |
| CostLimitMicroUSD: 2_000_000, |
| AllowedModels: []string{"gpt-4"}, |
| AllowedChannelIDs: []int64{11, 22}, |
| MaxConcurrency: 3, |
| } |
|
|
| b, err := json.Marshal(token) |
| if err != nil { |
| t.Fatalf("MarshalJSON failed: %v", err) |
| } |
|
|
| var got struct { |
| CostUsedUSD float64 `json:"cost_used_usd"` |
| CostLimitUSD float64 `json:"cost_limit_usd"` |
| AllowedChannelID []int64 `json:"allowed_channel_ids"` |
| MaxConcurrency int `json:"max_concurrency"` |
| } |
| if err := json.Unmarshal(b, &got); err != nil { |
| t.Fatalf("Unmarshal failed: %v", err) |
| } |
|
|
| if math.Abs(got.CostUsedUSD-0.25) > 1e-9 { |
| t.Fatalf("cost_used_usd = %#v, want 0.25", got.CostUsedUSD) |
| } |
| if math.Abs(got.CostLimitUSD-2.0) > 1e-9 { |
| t.Fatalf("cost_limit_usd = %#v, want 2.0", got.CostLimitUSD) |
| } |
| if len(got.AllowedChannelID) != 2 || got.AllowedChannelID[0] != 11 || got.AllowedChannelID[1] != 22 { |
| t.Fatalf("allowed_channel_ids = %#v, want [11 22]", got.AllowedChannelID) |
| } |
| if got.MaxConcurrency != 3 { |
| t.Fatalf("max_concurrency = %#v, want 3", got.MaxConcurrency) |
| } |
| } |
|
|