feat(notifications): library health reaches admins, coalesced (#5341)
release / govulncheck (push) Successful in 18s
release / web (push) Successful in 1m22s
release / go (push) Successful in 1m43s
release / integration (push) Successful in 4m56s
release / android (push) Successful in 5m16s
release / Build signed APK (releases and dev) (push) Successful in 5m27s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 15s
release / Verify release artifacts (tag releases only) (push) Skipped
release / govulncheck (push) Successful in 18s
release / web (push) Successful in 1m22s
release / go (push) Successful in 1m43s
release / integration (push) Successful in 4m56s
release / android (push) Successful in 5m16s
release / Build signed APK (releases and dev) (push) Successful in 5m27s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 15s
release / Verify release artifacts (tag releases only) (push) Skipped
- A failed scan run sends scan_failed. Each failure adds to the count and the notice shows the latest error. A scan cut short by shutdown says nothing. - Marking tracks missing sends tracks_missing with a running count. - A duplicate sweep that proposes a group it had not proposed before sends duplicates_found, counting everything awaiting review. A sweep that only re-finds known groups stays quiet, so a read notice isn't repeated every sweep (CountDuplicateGroupsDetectedSince). - A playback-error report sends playback_errors, counting the unresolved errors (CountUnresolvedPlaybackErrors). The library package gets its notifier as a package-level SetNotifier beside SetEventBus, for the same reason the bus is package-level. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -210,3 +210,29 @@ func TestQuarantineReasonLabel(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotify_PlaybackErrorsCoalesceIntoOneCount(t *testing.T) {
|
||||
h, pool := testHandlers(t)
|
||||
truncateLibrary(t, pool)
|
||||
|
||||
alice := seedUser(t, pool, "np-play-alice", "pw", false)
|
||||
admin := seedUser(t, pool, "np-play-admin", "pw", true)
|
||||
track := seedQuarantineTrack(t, h, "play")
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
body := fmt.Sprintf(`{"track_id":%q,"kind":"load_failed","client_id":"web-%d"}`, uuidToString(track.ID), i)
|
||||
req := withUser(httptest.NewRequest(http.MethodPost, "/api/playback-errors", strings.NewReader(body)), alice)
|
||||
w := httptest.NewRecorder()
|
||||
h.handleReportPlaybackError(w, req)
|
||||
if w.Code != http.StatusCreated {
|
||||
t.Fatalf("report %d: status = %d; body = %s", i, w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
got := inboxOf(t, pool, admin)
|
||||
wantInbox(t, "admin", got, notifications.KindPlaybackErrors)
|
||||
if got[0].Payload.Count != 2 {
|
||||
t.Errorf("count = %d, want 2 unresolved", got[0].Payload.Count)
|
||||
}
|
||||
wantInbox(t, "reporter", inboxOf(t, pool, alice))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user