package admin import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "github.com/go-chi/chi/v5" "ds2api/internal/account" "ds2api/internal/config" adminshared "ds2api/internal/httpapi/admin/shared" ) func newHTTPAdminHarness(t *testing.T, rawConfig string, ds adminshared.DeepSeekCaller) http.Handler { t.Helper() t.Setenv("DS2API_CONFIG_JSON", rawConfig) store := config.LoadStore() h := &Handler{ Store: store, Pool: account.NewPool(store), DS: ds, } r := chi.NewRouter() RegisterRoutes(r, h) return r } func adminReq(method, path string, body []byte) *http.Request { req := httptest.NewRequest(method, path, bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer admin") req.Header.Set("Content-Type", "application/json") return req } func TestConfigImportIgnoresTokenFieldInPayload(t *testing.T) { ds := &testingDSMock{} router := newHTTPAdminHarness(t, `{"accounts":[]}`, ds) payload := []byte(`{ "mode":"replace", "config":{ "accounts":[{"email":"u@example.com","password":"pwd","token":"expired-token"}] } }`) rec := httptest.NewRecorder() router.ServeHTTP(rec, adminReq(http.MethodPost, "/config/import", payload)) if rec.Code != http.StatusOK { t.Fatalf("import status=%d body=%s", rec.Code, rec.Body.String()) } readRec := httptest.NewRecorder() router.ServeHTTP(readRec, adminReq(http.MethodGet, "/config", nil)) if readRec.Code != http.StatusOK { t.Fatalf("get config status=%d body=%s", readRec.Code, readRec.Body.String()) } var data map[string]any if err := json.Unmarshal(readRec.Body.Bytes(), &data); err != nil { t.Fatalf("decode config response: %v", err) } accounts, _ := data["accounts"].([]any) if len(accounts) != 1 { t.Fatalf("expected one account, got %d", len(accounts)) } accountMap, _ := accounts[0].(map[string]any) if hasToken, _ := accountMap["has_token"].(bool); hasToken { t.Fatalf("expected imported token to be ignored, account=%#v", accountMap) } } func TestAccountTestRefreshesRuntimeTokenButExportOmitsToken(t *testing.T) { ds := &testingDSMock{} router := newHTTPAdminHarness(t, `{ "accounts":[{"email":"batch@example.com","password":"pwd","token":"stale-token"}] }`, ds) rec := httptest.NewRecorder() router.ServeHTTP(rec, adminReq(http.MethodPost, "/accounts/test", []byte(`{"identifier":"batch@example.com"}`))) if rec.Code != http.StatusOK { t.Fatalf("test account status=%d body=%s", rec.Code, rec.Body.String()) } var testResp map[string]any if err := json.Unmarshal(rec.Body.Bytes(), &testResp); err != nil { t.Fatalf("decode test response: %v", err) } if ok, _ := testResp["success"].(bool); !ok { t.Fatalf("expected test success, got %#v", testResp) } if ds.loginCalls < 1 { t.Fatalf("expected login to be called at least once, got %d", ds.loginCalls) } exportRec := httptest.NewRecorder() router.ServeHTTP(exportRec, adminReq(http.MethodGet, "/config/export", nil)) if exportRec.Code != http.StatusOK { t.Fatalf("export status=%d body=%s", exportRec.Code, exportRec.Body.String()) } var exportResp map[string]any if err := json.Unmarshal(exportRec.Body.Bytes(), &exportResp); err != nil { t.Fatalf("decode export response: %v", err) } exportJSON, _ := exportResp["json"].(string) if strings.Contains(exportJSON, `"token"`) { t.Fatalf("expected export json to omit tokens, got %s", exportJSON) } }