Files
pargar/backend/internal/api/account_freeze_test.go
T

103 lines
3.7 KiB
Go
Raw Normal View History

package api_test
import (
"context"
"net/http"
"strings"
"testing"
"time"
)
func TestAccountFreeze(t *testing.T) {
e := setup(t)
token, uid := register(t, e, "Freeze", "freeze@test.dev")
code, missing := e.do(t, "POST", "/api/me/freeze", token, map[string]any{})
missingMsg, _ := missing["error"].(string)
if code == http.StatusOK || !strings.Contains(missingMsg, "گذرواژه") {
t.Fatalf("freeze without password: %d %q", code, missingMsg)
}
code, wrong := e.do(t, "POST", "/api/me/freeze", token, map[string]any{"currentPassword": "not-the-password"})
wrongMsg, _ := wrong["error"].(string)
if code != http.StatusForbidden || !strings.Contains(wrongMsg, "گذرواژه") || !strings.Contains(wrongMsg, "نادرست") {
t.Fatalf("freeze with wrong password: %d %q", code, wrongMsg)
}
var untouched *time.Time
if err := e.pool.QueryRow(context.Background(), `SELECT frozen_at FROM users WHERE id=$1`, uid).Scan(&untouched); err != nil {
t.Fatal(err)
}
if untouched != nil {
t.Fatal("failed freeze wrote frozen_at")
}
code, body := e.do(t, "POST", "/api/me/freeze", token, map[string]any{"currentPassword": "password123"})
if code != http.StatusOK {
t.Fatalf("freeze: %d %v", code, body["error"])
}
user := body["user"].(map[string]any)
frozenAt, _ := user["frozenAt"].(string)
if frozenAt == "" || user["isFrozen"] != true || user["isClosed"] == true {
t.Fatalf("freeze state: frozenAt=%v isFrozen=%v isClosed=%v", user["frozenAt"], user["isFrozen"], user["isClosed"])
}
if user["isLocked"] == true {
t.Fatal("freeze reused the admin lock flag")
}
var stored *time.Time
if err := e.pool.QueryRow(context.Background(), `SELECT frozen_at FROM users WHERE id=$1`, uid).Scan(&stored); err != nil {
t.Fatal(err)
}
if stored == nil || stored.IsZero() {
t.Fatal("frozen_at was not stored")
}
code, profile := e.do(t, "GET", "/api/users/"+itoa(uid), token, nil)
if code != http.StatusOK {
t.Fatalf("profile: %d %v", code, profile["error"])
}
pub := profile["user"].(map[string]any)
if pub["isFrozen"] != true {
t.Fatalf("public profile missing freeze flag: %v", pub["isFrozen"])
}
if _, ok := pub["email"]; ok {
t.Fatalf("public profile leaked email: %v", pub["email"])
}
_ = login(t, e, "freeze@test.dev")
code, body = e.do(t, "POST", "/api/me/unfreeze", token, map[string]any{})
if code != http.StatusOK {
t.Fatalf("unfreeze: %d %v", code, body["error"])
}
cleared := body["user"].(map[string]any)
if cleared["isFrozen"] == true || cleared["frozenAt"] != nil {
t.Fatalf("unfreeze left a timestamp: %v", cleared["frozenAt"])
}
var after *time.Time
if err := e.pool.QueryRow(context.Background(), `SELECT frozen_at FROM users WHERE id=$1`, uid).Scan(&after); err != nil {
t.Fatal(err)
}
if after != nil {
t.Fatalf("frozen_at still set: %s", after.Format(time.RFC3339))
}
if _, err := e.pool.Exec(context.Background(), `UPDATE users SET closed_at = now() WHERE id=$1`, uid); err != nil {
t.Fatal(err)
}
code, denied := e.do(t, "POST", "/api/auth/login", "", loginBody(t, e, "freeze@test.dev", "password123"))
errMsg, _ := denied["error"].(string)
if code != http.StatusForbidden || !strings.Contains(errMsg, "بسته") || !strings.Contains(errMsg, "ورود") {
t.Fatalf("closed login: %d %q", code, errMsg)
}
code, undo := e.do(t, "POST", "/api/me/unfreeze", token, map[string]any{})
undoMsg, _ := undo["error"].(string)
if code != http.StatusConflict || !strings.Contains(undoMsg, "لغو فریز") {
t.Fatalf("unfreeze after close: %d %q", code, undoMsg)
}
code, forbidden := e.do(t, "DELETE", "/api/admin/users/"+itoa(uid), token, nil)
if code != http.StatusForbidden {
t.Fatalf("student permanent delete: %d %v", code, forbidden["error"])
}
}