File size: 5,258 Bytes
6bc074c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | package handler
import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"aurora/internal/accounts"
"aurora/internal/config"
officialtypes "aurora/typings/official"
"github.com/gin-gonic/gin"
)
// βββ Test: writeChatCompletionStreamDone βββββββββββββββββββββββββ
func TestWriteChatCompletionStreamDoneAddsStopBeforeDone(t *testing.T) {
gin.SetMode(gin.TestMode)
writer := httptest.NewRecorder()
c, _ := gin.CreateTestContext(writer)
writeChatCompletionStreamDone(c, false, "auto", "conv-xxx")
lines := sseDataLines(writer.Body.String())
if len(lines) != 2 {
t.Fatalf("data line count = %d, want 2; output: %s", len(lines), writer.Body.String())
}
var stopChunk map[string]interface{}
if err := json.Unmarshal([]byte(lines[0]), &stopChunk); err != nil {
t.Fatalf("invalid stop chunk: %v", err)
}
if stopChunk["conversation_id"] != "conv-xxx" {
t.Fatalf("conversation_id = %#v, want conv-xxx", stopChunk["conversation_id"])
}
choices := stopChunk["choices"].([]interface{})
if choices[0].(map[string]interface{})["finish_reason"] != "stop" {
t.Fatalf("finish_reason = %#v, want stop", choices[0].(map[string]interface{})["finish_reason"])
}
if lines[1] != "[DONE]" {
t.Fatalf("last data line = %q, want [DONE]", lines[1])
}
}
func TestWriteChatCompletionStreamDoneSkipsDuplicateStop(t *testing.T) {
gin.SetMode(gin.TestMode)
writer := httptest.NewRecorder()
c, _ := gin.CreateTestContext(writer)
writeChatCompletionStreamDone(c, true, "auto", "conv-xxx")
lines := sseDataLines(writer.Body.String())
if len(lines) != 1 || lines[0] != "[DONE]" {
t.Fatalf("data lines = %#v, want only [DONE]", lines)
}
}
// βββ Test: toolCallingEnabled ββββββββββββββββββββββββββββββββββββ
func TestToolCallingEnabledFromConfig(t *testing.T) {
okCfg := &config.Config{ToolCallingEnabled: true}
disabledCfg := &config.Config{ToolCallingEnabled: false}
if toolCallingEnabled(nil, okCfg) {
t.Error("toolCallingEnabled(nil, true) should be false (len(nil)==0)")
}
if toolCallingEnabled(nil, disabledCfg) {
t.Error("toolCallingEnabled(nil, false) should be false")
}
// empty tools slice with config enabled β false
if toolCallingEnabled([]officialtypes.Tool{}, okCfg) {
t.Error("toolCallingEnabled([], true) should be false")
}
// with actual tools and config enabled β true
tools := []officialtypes.Tool{{Type: "function", Function: officialtypes.ToolFunction{Name: "test"}}}
if !toolCallingEnabled(tools, okCfg) {
t.Error("toolCallingEnabled([tool], true) should be true")
}
}
// βββ Test: original_requestHasFiles ββββββββββββββββββββββββββββββ
func TestOriginalRequestHasFiles(t *testing.T) {
req := officialtypes.APIRequest{
Messages: []officialtypes.APIMessage{
{
Role: "user",
Content: officialtypes.MessageContent{TextValue: "hello"},
},
},
}
if original_requestHasFiles(req) {
t.Error("should be false when no files")
}
}
// βββ Test: countMessagesTokens βββββββββββββββββββββββββββββββββββ
func TestCountMessagesTokens(t *testing.T) {
zero := countMessagesTokens(nil)
if zero != 0 {
t.Errorf("nil messages should return 0, got %d", zero)
}
}
// βββ Test: resolveAccount ββββββββββββββββββββββββββββββββββββββββ
func TestResolveAccountEmptyPool(t *testing.T) {
gin.SetMode(gin.TestMode)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest(http.MethodPost, "/", nil)
pool := accounts.NewPool(nil)
cfg := &config.Config{}
acct, _, err := resolveAccount(c, pool, cfg, false)
if err == nil {
t.Fatal("expected error with empty pool")
}
if acct != nil {
t.Fatal("expected nil account")
}
}
func TestResolveAccountWithGlobalKey(t *testing.T) {
gin.SetMode(gin.TestMode)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest(http.MethodPost, "/", nil)
c.Request.Header.Set("Authorization", "Bearer my-global-key")
pool := accounts.NewPool(nil)
acct := accounts.NewAccount("test", accounts.TypeFree, "test-token")
acct.Status = accounts.StatusActive
pool.AddAccount(acct)
cfg := &config.Config{Authorization: "my-global-key"}
result, _, err := resolveAccount(c, pool, cfg, false)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result == nil {
t.Fatal("expected account, got nil")
}
if result.Token != "test-token" {
t.Errorf("got token %q, want test-token", result.Token)
}
}
// βββ helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββ
func sseDataLines(output string) []string {
var lines []string
for _, line := range strings.Split(output, "\n") {
line = strings.TrimSpace(line)
if !strings.HasPrefix(line, "data: ") {
continue
}
lines = append(lines, strings.TrimPrefix(line, "data: "))
}
return lines
}
|