mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-06 09:25:27 +08:00
- replace legacy DeepSeek ids with the new deepseek-v4 model family\n- move thinking control to request parameters and preserve assistant reasoning content\n- switch history split to IGNORE transcript injection and map upload auth failures to 401\n- update admin defaults, API docs, samples, and tests for the new model scheme
177 lines
5.6 KiB
Go
177 lines
5.6 KiB
Go
package admin
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"ds2api/internal/chathistory"
|
|
"ds2api/internal/config"
|
|
)
|
|
|
|
func newChatHistoryAdminHarness(t *testing.T) (*Handler, *chathistory.Store) {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
configPath := filepath.Join(dir, "config.json")
|
|
if err := os.WriteFile(configPath, []byte(`{}`), 0o644); err != nil {
|
|
t.Fatalf("write config failed: %v", err)
|
|
}
|
|
t.Setenv("DS2API_CONFIG_PATH", configPath)
|
|
t.Setenv("DS2API_ADMIN_KEY", "admin")
|
|
t.Setenv("DS2API_CONFIG_JSON", "")
|
|
store, err := config.LoadStoreWithError()
|
|
if err != nil {
|
|
t.Fatalf("load config store failed: %v", err)
|
|
}
|
|
historyStore := chathistory.New(filepath.Join(dir, "chat_history.json"))
|
|
return &Handler{Store: store, ChatHistory: historyStore}, historyStore
|
|
}
|
|
|
|
func TestGetChatHistoryAndUpdateSettings(t *testing.T) {
|
|
h, historyStore := newChatHistoryAdminHarness(t)
|
|
entry, err := historyStore.Start(chathistory.StartParams{
|
|
CallerID: "caller:test",
|
|
AccountID: "user@example.com",
|
|
Model: "deepseek-v4-flash",
|
|
UserInput: "hello",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("start history failed: %v", err)
|
|
}
|
|
if _, err := historyStore.Update(entry.ID, chathistory.UpdateParams{
|
|
Status: "success",
|
|
Content: "world",
|
|
Completed: true,
|
|
}); err != nil {
|
|
t.Fatalf("update history failed: %v", err)
|
|
}
|
|
|
|
r := chi.NewRouter()
|
|
RegisterRoutes(r, h)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/chat-history", nil)
|
|
req.Header.Set("Authorization", "Bearer admin")
|
|
rec := httptest.NewRecorder()
|
|
r.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d body=%s", rec.Code, rec.Body.String())
|
|
}
|
|
var payload map[string]any
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil {
|
|
t.Fatalf("decode payload failed: %v", err)
|
|
}
|
|
items, _ := payload["items"].([]any)
|
|
if len(items) != 1 {
|
|
t.Fatalf("expected one history item, got %#v", payload)
|
|
}
|
|
if rec.Header().Get("ETag") == "" {
|
|
t.Fatalf("expected list etag header")
|
|
}
|
|
|
|
notModifiedReq := httptest.NewRequest(http.MethodGet, "/chat-history", nil)
|
|
notModifiedReq.Header.Set("Authorization", "Bearer admin")
|
|
notModifiedReq.Header.Set("If-None-Match", rec.Header().Get("ETag"))
|
|
notModifiedRec := httptest.NewRecorder()
|
|
r.ServeHTTP(notModifiedRec, notModifiedReq)
|
|
if notModifiedRec.Code != http.StatusNotModified {
|
|
t.Fatalf("expected 304, got %d body=%s", notModifiedRec.Code, notModifiedRec.Body.String())
|
|
}
|
|
|
|
itemReq := httptest.NewRequest(http.MethodGet, "/chat-history/"+entry.ID, nil)
|
|
itemReq.Header.Set("Authorization", "Bearer admin")
|
|
itemRec := httptest.NewRecorder()
|
|
r.ServeHTTP(itemRec, itemReq)
|
|
if itemRec.Code != http.StatusOK {
|
|
t.Fatalf("expected item 200, got %d body=%s", itemRec.Code, itemRec.Body.String())
|
|
}
|
|
if itemRec.Header().Get("ETag") == "" {
|
|
t.Fatalf("expected detail etag header")
|
|
}
|
|
|
|
updateReq := httptest.NewRequest(http.MethodPut, "/chat-history/settings", bytes.NewReader([]byte(`{"limit":10}`)))
|
|
updateReq.Header.Set("Authorization", "Bearer admin")
|
|
updateRec := httptest.NewRecorder()
|
|
r.ServeHTTP(updateRec, updateReq)
|
|
if updateRec.Code != http.StatusOK {
|
|
t.Fatalf("expected 200 from settings update, got %d body=%s", updateRec.Code, updateRec.Body.String())
|
|
}
|
|
snapshot, err := historyStore.Snapshot()
|
|
if err != nil {
|
|
t.Fatalf("snapshot failed: %v", err)
|
|
}
|
|
if snapshot.Limit != 10 {
|
|
t.Fatalf("expected limit=10, got %d", snapshot.Limit)
|
|
}
|
|
|
|
disableReq := httptest.NewRequest(http.MethodPut, "/chat-history/settings", bytes.NewReader([]byte(`{"limit":0}`)))
|
|
disableReq.Header.Set("Authorization", "Bearer admin")
|
|
disableRec := httptest.NewRecorder()
|
|
r.ServeHTTP(disableRec, disableReq)
|
|
if disableRec.Code != http.StatusOK {
|
|
t.Fatalf("expected 200 from disable update, got %d body=%s", disableRec.Code, disableRec.Body.String())
|
|
}
|
|
snapshot, err = historyStore.Snapshot()
|
|
if err != nil {
|
|
t.Fatalf("snapshot after disable failed: %v", err)
|
|
}
|
|
if snapshot.Limit != chathistory.DisabledLimit {
|
|
t.Fatalf("expected limit=0, got %d", snapshot.Limit)
|
|
}
|
|
if len(snapshot.Items) != 1 {
|
|
t.Fatalf("expected history preserved when disabled, got %d", len(snapshot.Items))
|
|
}
|
|
}
|
|
|
|
func TestDeleteAndClearChatHistory(t *testing.T) {
|
|
h, historyStore := newChatHistoryAdminHarness(t)
|
|
entryA, err := historyStore.Start(chathistory.StartParams{UserInput: "a"})
|
|
if err != nil {
|
|
t.Fatalf("start A failed: %v", err)
|
|
}
|
|
if _, err := historyStore.Start(chathistory.StartParams{UserInput: "b"}); err != nil {
|
|
t.Fatalf("start B failed: %v", err)
|
|
}
|
|
|
|
r := chi.NewRouter()
|
|
RegisterRoutes(r, h)
|
|
|
|
deleteReq := httptest.NewRequest(http.MethodDelete, "/chat-history/"+entryA.ID, nil)
|
|
deleteReq.Header.Set("Authorization", "Bearer admin")
|
|
deleteRec := httptest.NewRecorder()
|
|
r.ServeHTTP(deleteRec, deleteReq)
|
|
if deleteRec.Code != http.StatusOK {
|
|
t.Fatalf("expected delete 200, got %d body=%s", deleteRec.Code, deleteRec.Body.String())
|
|
}
|
|
|
|
snapshot, err := historyStore.Snapshot()
|
|
if err != nil {
|
|
t.Fatalf("snapshot failed: %v", err)
|
|
}
|
|
if len(snapshot.Items) != 1 {
|
|
t.Fatalf("expected one item after delete, got %d", len(snapshot.Items))
|
|
}
|
|
|
|
clearReq := httptest.NewRequest(http.MethodDelete, "/chat-history", nil)
|
|
clearReq.Header.Set("Authorization", "Bearer admin")
|
|
clearRec := httptest.NewRecorder()
|
|
r.ServeHTTP(clearRec, clearReq)
|
|
if clearRec.Code != http.StatusOK {
|
|
t.Fatalf("expected clear 200, got %d body=%s", clearRec.Code, clearRec.Body.String())
|
|
}
|
|
|
|
snapshot, err = historyStore.Snapshot()
|
|
if err != nil {
|
|
t.Fatalf("snapshot failed: %v", err)
|
|
}
|
|
if len(snapshot.Items) != 0 {
|
|
t.Fatalf("expected empty items after clear, got %d", len(snapshot.Items))
|
|
}
|
|
}
|