feat: change email, export my data, delete account (with data anonymization)
This commit is contained in:
1 parent
bb191c389a
commit
10a66cd979
123 files changed
+10789
-76
No files matched your search
@@ -0,0 +1,100 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"RenewCMS/api/middleware"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestAccountExportDataEmptyCollectionsAreArrays(t *testing.T) {
|
||||
f := newExportFixture(t)
|
||||
for index := range f.events.events {
|
||||
f.events.events[index].Params = nil
|
||||
}
|
||||
|
||||
rec := f.export(t, exportMartaID)
|
||||
files := openExportArchive(t, rec)
|
||||
|
||||
for _, item := range exportList(t, exportJSON(t, files, "authored-content.json"), "articles") {
|
||||
authors, ok := item.(map[string]any)["authors"].([]any)
|
||||
if !ok || len(authors) != 0 {
|
||||
t.Errorf("uncredited article authors = %v, want empty list", item.(map[string]any)["authors"])
|
||||
}
|
||||
}
|
||||
events := exportList(t, exportJSON(t, files, "account-activity.json"), "events")
|
||||
if len(events) == 0 {
|
||||
t.Fatal("expected activity events")
|
||||
}
|
||||
for _, item := range events {
|
||||
params, ok := item.(map[string]any)["params"].(map[string]any)
|
||||
if !ok || len(params) != 0 {
|
||||
t.Errorf("event params = %v, want empty object", item.(map[string]any)["params"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func successLimiterStatus(t *testing.T, handler http.Handler) *httptest.ResponseRecorder {
|
||||
t.Helper()
|
||||
rec := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/", nil))
|
||||
return rec
|
||||
}
|
||||
|
||||
func newSuccessLimiterHandler(clock *exportClock, status *int) http.Handler {
|
||||
limited := middleware.NewUserSuccessLimiterAt(time.Minute, clock.now)
|
||||
return limited(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(*status)
|
||||
}))
|
||||
}
|
||||
|
||||
func TestUserSuccessLimiterStatusBoundary(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
status int
|
||||
blocked bool
|
||||
}{
|
||||
"399 keeps the slot": {399, true},
|
||||
"400 releases the slot": {400, false},
|
||||
"500 releases the slot": {500, false},
|
||||
"200 keeps the slot": {200, true},
|
||||
"302 keeps the slot": {302, true},
|
||||
"429 releases the slot": {429, false},
|
||||
"401 releases the slot": {401, false},
|
||||
"204 keeps the slot too": {204, true},
|
||||
}
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
clock := &exportClock{current: time.Date(2026, time.October, 29, 9, 0, 0, 0, time.UTC)}
|
||||
status := tc.status
|
||||
handler := newSuccessLimiterHandler(clock, &status)
|
||||
|
||||
successLimiterStatus(t, handler)
|
||||
second := successLimiterStatus(t, handler)
|
||||
|
||||
if tc.blocked && second.Code != http.StatusTooManyRequests {
|
||||
t.Errorf("second call = %d, want 429", second.Code)
|
||||
}
|
||||
if !tc.blocked && second.Code != tc.status {
|
||||
t.Errorf("second call = %d, want handler status %d", second.Code, tc.status)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserSuccessLimiterWindowEdge(t *testing.T) {
|
||||
clock := &exportClock{current: time.Date(2026, time.October, 29, 9, 0, 0, 0, time.UTC)}
|
||||
status := http.StatusOK
|
||||
handler := newSuccessLimiterHandler(clock, &status)
|
||||
|
||||
successLimiterStatus(t, handler)
|
||||
clock.advance(time.Minute - time.Second)
|
||||
blocked := successLimiterStatus(t, handler)
|
||||
if blocked.Code != http.StatusTooManyRequests || blocked.Header().Get("Retry-After") != "1" {
|
||||
t.Errorf("just inside the window = %d retry-after %q, want 429 and 1", blocked.Code, blocked.Header().Get("Retry-After"))
|
||||
}
|
||||
clock.advance(time.Second)
|
||||
if edge := successLimiterStatus(t, handler); edge.Code != http.StatusOK {
|
||||
t.Errorf("exactly at the window = %d, want 200", edge.Code)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user