1dc96e86fc
- User blocking (with reason) now closes the auth gap immediately — a
blocked user's still-valid access token stops working on the next
request, not just on their next OTP/refresh.
- Admin-created reports (moderation notes) per user, viewable in a history
list independent of block status.
- GET /admin/users: full paginated, searchable user list with report counts.
- GET /admin/matches: all matches across the app ("friends" who mutually
liked each other), for admin visibility.
- GET/DELETE /admin/photos: paginated feed of every uploaded photo with
uploader info, so admins can review and remove content without going
user-by-user.
- Per-user activity: monitoring requests can now be filtered by user_id, so
a user's detail page can show their recent API activity.
- Batched the profile-selections query in fullProfilePayload (was 6 queries
per view, now 1) for consistency with the earlier N+1 fixes.
94 lines
2.9 KiB
Go
94 lines
2.9 KiB
Go
package monitoring
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestStore_RecordAndSummary(t *testing.T) {
|
|
s := NewStore()
|
|
|
|
s.Record(RequestRecord{Time: time.Now(), Method: "GET", Path: "/x", StatusCode: 200, DurationMs: 10})
|
|
s.Record(RequestRecord{Time: time.Now(), Method: "GET", Path: "/x", StatusCode: 500, DurationMs: 20})
|
|
|
|
sum := s.Summary()
|
|
if sum.TotalRequests != 2 {
|
|
t.Fatalf("expected 2 total requests, got %d", sum.TotalRequests)
|
|
}
|
|
if sum.TotalErrors != 1 {
|
|
t.Fatalf("expected 1 error (status>=400), got %d", sum.TotalErrors)
|
|
}
|
|
if sum.ErrorRatePct != 50 {
|
|
t.Fatalf("expected 50%% error rate, got %v", sum.ErrorRatePct)
|
|
}
|
|
if sum.AvgLatencyMs != 15 {
|
|
t.Fatalf("expected avg latency 15ms, got %v", sum.AvgLatencyMs)
|
|
}
|
|
}
|
|
|
|
func TestStore_RecentOrder(t *testing.T) {
|
|
s := NewStore()
|
|
s.Record(RequestRecord{Time: time.Now(), Path: "/1", StatusCode: 200})
|
|
s.Record(RequestRecord{Time: time.Now(), Path: "/2", StatusCode: 200})
|
|
s.Record(RequestRecord{Time: time.Now(), Path: "/3", StatusCode: 200})
|
|
|
|
recent := s.Recent(10)
|
|
if len(recent) != 3 {
|
|
t.Fatalf("expected 3 records, got %d", len(recent))
|
|
}
|
|
// جدیدترین باید اول باشه
|
|
if recent[0].Path != "/3" || recent[1].Path != "/2" || recent[2].Path != "/1" {
|
|
t.Fatalf("expected newest-first order, got %+v", recent)
|
|
}
|
|
}
|
|
|
|
func TestStore_RecentLimit(t *testing.T) {
|
|
s := NewStore()
|
|
for i := 0; i < 5; i++ {
|
|
s.Record(RequestRecord{Time: time.Now(), Path: "/x", StatusCode: 200})
|
|
}
|
|
if got := len(s.Recent(2)); got != 2 {
|
|
t.Fatalf("expected limit of 2, got %d", got)
|
|
}
|
|
if got := len(s.Recent(100)); got != 5 {
|
|
t.Fatalf("expected all 5 when limit exceeds count, got %d", got)
|
|
}
|
|
}
|
|
|
|
func TestStore_RingBufferWraparound(t *testing.T) {
|
|
s := NewStore()
|
|
// بیشتر از ظرفیت بافر ثبت میکنیم تا رفتار wraparound رو تست کنیم
|
|
for i := 0; i < bufferSize+50; i++ {
|
|
s.Record(RequestRecord{Time: time.Now(), Path: "/x", StatusCode: 200, DurationMs: 1})
|
|
}
|
|
|
|
sum := s.Summary()
|
|
if sum.TotalRequests != int64(bufferSize+50) {
|
|
t.Fatalf("expected total requests to keep counting past buffer size, got %d", sum.TotalRequests)
|
|
}
|
|
|
|
recent := s.Recent(bufferSize + 100)
|
|
if len(recent) != bufferSize {
|
|
t.Fatalf("expected Recent to be capped at bufferSize (%d), got %d", bufferSize, len(recent))
|
|
}
|
|
}
|
|
|
|
func TestStore_RecentByUser(t *testing.T) {
|
|
s := NewStore()
|
|
uidA := uint(1)
|
|
uidB := uint(2)
|
|
|
|
s.Record(RequestRecord{Time: time.Now(), Path: "/a1", UserID: &uidA})
|
|
s.Record(RequestRecord{Time: time.Now(), Path: "/b1", UserID: &uidB})
|
|
s.Record(RequestRecord{Time: time.Now(), Path: "/a2", UserID: &uidA})
|
|
s.Record(RequestRecord{Time: time.Now(), Path: "/none"}) // بدون کاربر (مثل OTP)
|
|
|
|
got := s.RecentByUser(uidA, 10)
|
|
if len(got) != 2 {
|
|
t.Fatalf("expected 2 records for user A, got %d", len(got))
|
|
}
|
|
if got[0].Path != "/a2" || got[1].Path != "/a1" {
|
|
t.Fatalf("expected newest-first order for user A, got %+v", got)
|
|
}
|
|
}
|