mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
test: audit 2026-08-19 — fix stale tests, close coverage gaps (#1397)
* test(server): admin/handlers/channels — test-audit 2026-08-19 fixes * test(server): api/constants — test-audit 2026-08-19 fixes * test(server): api/middleware — test-audit 2026-08-19 fixes * test(server): api/waf — test-audit 2026-08-19 fixes * test(server): auth/totp/encrypt — test-audit 2026-08-19 fixes * test(server): db/session/expiry/test — test-audit 2026-08-19 fixes * test(server): migrations/030/attachments/unlink/on/message/delete — test-audit 2026-08-19 fixes * test(server): updater/download — test-audit 2026-08-19 fixes * test(server): ws/handlers_command — test-audit 2026-08-19 fixes * test(server): ws/hub/broadcast — test-audit 2026-08-19 fixes * test(server): ws/hub/events — test-audit 2026-08-19 fixes * test(server): ws/livekit/webhook — test-audit 2026-08-19 fixes * test(server): ws/voice/controls — test-audit 2026-08-19 fixes * test(server): ws/voice/join — test-audit 2026-08-19 fixes * test(server): ws/voice/moderation — test-audit 2026-08-19 fixes * test(rust): src-tauri/src/commands.rs — test-audit 2026-08-19 fixes * test(rust): src-tauri/src/secret_store.rs — test-audit 2026-08-19 fixes * test(rust): src-tauri/src/update_commands.rs — test-audit 2026-08-19 fixes * test(client): src/components/ChannelSidebar.ts — test-audit 2026-08-19 fixes * test(client): src/lib/ws.ts — test-audit 2026-08-19 fixes * test(rust): src-tauri/src/credentials.rs — test-audit 2026-08-19 fixes * test(rust): src-tauri/src/tofu.rs — test-audit 2026-08-19 fixes * test(client): src/lib/hostValidation.ts — test-audit 2026-08-19 fixes * test(client): src/lib/rate-limiter.ts — test-audit 2026-08-19 fixes * test(client): src/pages/connect-page/LoginForm.ts — test-audit 2026-08-19 fixes * test(client): src/pages/main-page/SidebarArea.ts — test-audit 2026-08-19 fixes * test(client): src/stores/voice.store.ts — test-audit 2026-08-19 fixes * test(client): tests/browser/smoke.test.ts — test-audit 2026-08-19 fixes * test(client): tests/unit/media.test.ts — test-audit 2026-08-19 fixes * test(client): tests/unit/renderers.test.ts — test-audit 2026-08-19 fixes * test(client): src/components/UserProfilePopup.ts — test-audit 2026-08-19 fixes * test(client): src/lib/e2eeCrypto.ts — test-audit 2026-08-19 fixes * test(client): tests/unit/log-persistence.test.ts — test-audit 2026-08-19 fixes * test(client): keep tests/browser out of the jsdom suite and run it in CI * test(server): ws/hub_broadcast_test.go — bytes.Equal payload compare (gocritic) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(client): src/lib/credentials.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/dispatcher.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/permissions.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/rate-limiter.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/hostValidation.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/stores/messages.store.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/e2eeCrypto.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/ws.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/identity.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/lib/livekitE2EE.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/stores/auth.store.ts — test-audit 2026-08-19 round 2 (Stryker) * test(client): src/stores/voice.store.ts — test-audit 2026-08-19 round 2 (Stryker) * docs: test audit 2026-08-19 — findings, fixes, measured baselines Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(graph): refresh the knowledge graph after the 2026-08-19 test audit Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -127,3 +127,41 @@ func TestAdminAPI_PatchChannel_ArchiveSurvivesContextCancelAfterCommit(t *testin
|
||||
t.Errorf("RefreshChannelVisibility calls = %d, want 1", len(hub.visibilityRefreshes))
|
||||
}
|
||||
}
|
||||
|
||||
// OC-0158, create side: handleCreateChannel commits AdminCreateChannel and
|
||||
// only afterwards re-reads the row to broadcast it. A caller cancellation
|
||||
// landing in that window (tab close, network blip) failed the re-read and
|
||||
// 500ed the request, leaving a durably created channel no connected client
|
||||
// was ever told about — the same shape already fixed in the PATCH and DELETE
|
||||
// siblings. The hook fires synchronously right after the commit so the window
|
||||
// is hit deterministically instead of by wall-clock timing.
|
||||
func TestAdminAPI_CreateChannel_SurvivesContextCancelAfterCommit(t *testing.T) {
|
||||
database := openAdminTestDB(t)
|
||||
hub := &mockHub{}
|
||||
handler := admin.NewAdminAPI(database, "1.0.0", hub, nil, nil, nil, nil, newTestModService(database), newTestRoleService(database))
|
||||
token := createAdminUser(t, database)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
restore := admin.SetCreateChannelPostCommitHook(func() {
|
||||
cancel()
|
||||
})
|
||||
defer restore()
|
||||
|
||||
body, _ := json.Marshal(map[string]any{"name": "create-cancel-race", "type": "text"})
|
||||
req := httptest.NewRequest(http.MethodPost, "/channels", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
req = req.WithContext(ctx)
|
||||
w := httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusCreated {
|
||||
t.Fatalf("status = %d, want 201 (create must survive a caller cancellation that arrives after the row already committed); body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
if len(hub.channelCreates) != 1 {
|
||||
t.Fatalf("BroadcastChannelCreate called %d times, want 1 — the row committed, so connected clients must be told", len(hub.channelCreates))
|
||||
}
|
||||
if hub.channelCreates[0].Name != "create-cancel-race" {
|
||||
t.Errorf("broadcast channel name = %q, want create-cancel-race", hub.channelCreates[0].Name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,16 @@ func SetPatchChannelPostCommitHook(h func()) (restore func()) {
|
||||
return func() { patchChannelPostCommitHook = prev }
|
||||
}
|
||||
|
||||
// SetCreateChannelPostCommitHook installs h to run synchronously right after
|
||||
// handleCreateChannel's AdminCreateChannel commit, before the post-commit
|
||||
// re-read and hub fan-out — the create-side twin of
|
||||
// SetPatchChannelPostCommitHook (OC-0158).
|
||||
func SetCreateChannelPostCommitHook(h func()) (restore func()) {
|
||||
prev := createChannelPostCommitHook
|
||||
createChannelPostCommitHook = h
|
||||
return func() { createChannelPostCommitHook = prev }
|
||||
}
|
||||
|
||||
// StubCopyBackup swaps the restore path's file-copy hook so tests can inject
|
||||
// mid-copy failures that pass the pre-copy integrity gate. CopyBackupForTest
|
||||
// is the real implementation, for stubs that only want to fail once.
|
||||
|
||||
@@ -93,6 +93,13 @@ type createChannelRequest struct {
|
||||
Position int `json:"position"`
|
||||
}
|
||||
|
||||
// createChannelPostCommitHook, when non-nil, runs synchronously right after
|
||||
// handleCreateChannel's AdminCreateChannel commit, before the post-commit
|
||||
// re-read and hub fan-out — the create-side twin of
|
||||
// patchChannelPostCommitHook, so tests can land a caller cancellation in that
|
||||
// exact window (OC-0158) instead of relying on wall-clock timing.
|
||||
var createChannelPostCommitHook func()
|
||||
|
||||
func handleCreateChannel(database *db.DB, hub HubBroadcaster) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req createChannelRequest
|
||||
@@ -120,14 +127,28 @@ func handleCreateChannel(database *db.DB, hub HubBroadcaster) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
ch, err := database.GetChannel(r.Context(), id)
|
||||
// From here on the row has already committed. If the admin's browser
|
||||
// goes away in this window (tab close, navigation, network blip),
|
||||
// r.Context() cancels, and a GetChannel re-read that still used it
|
||||
// would fail with context.Canceled — 500ing while leaving a durably
|
||||
// created channel unbroadcast, so no connected client learns about it
|
||||
// until it reconnects (OC-0158). Run the rest of the handler on an
|
||||
// uncancellable tail, matching handlePatchChannel and
|
||||
// handleDeleteChannel.
|
||||
tail := context.WithoutCancel(r.Context())
|
||||
|
||||
if createChannelPostCommitHook != nil {
|
||||
createChannelPostCommitHook()
|
||||
}
|
||||
|
||||
ch, err := database.GetChannel(tail, id)
|
||||
if err != nil || ch == nil {
|
||||
writeErr(w, http.StatusInternalServerError, "INTERNAL_ERROR", "failed to fetch created channel")
|
||||
return
|
||||
}
|
||||
actor := actorFromContext(r)
|
||||
slog.Info("channel created", "actor_id", actor, "channel", req.Name, "type", req.Type)
|
||||
db.WriteAudit(context.WithoutCancel(r.Context()), database, actor, "channel_create", "channel", id,
|
||||
db.WriteAudit(tail, database, actor, "channel_create", "channel", id,
|
||||
fmt.Sprintf("created #%s (%s)", req.Name, req.Type))
|
||||
if hub != nil {
|
||||
hub.BroadcastChannelCreate(ch)
|
||||
|
||||
Reference in New Issue
Block a user