Better notification organization.
This commit is contained in:
1 parent
81cc630319
commit
2c02a79655
14 files changed
+1276
-40
No files matched your search
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func shared_notification_application(t *testing.T, namespace string) (*application, *fakeVoice, *fakeSounds) {
|
||||
t.Helper()
|
||||
a, voice := persistence_application(t, true)
|
||||
voice.messages = nil
|
||||
sounds := &fakeSounds{}
|
||||
a.cues = sounds
|
||||
a.options.SharedNotifications = true
|
||||
a.options.NotificationNamespace = namespace
|
||||
a.share_notification_history(1, true)
|
||||
t.Cleanup(func() {
|
||||
a.notificationHistory.Close()
|
||||
a.notificationClosers.Wait()
|
||||
})
|
||||
return a, voice, sounds
|
||||
}
|
||||
|
||||
func wait_shared_notifications(t *testing.T, a *application, count int) {
|
||||
t.Helper()
|
||||
deadline := time.NewTimer(3 * time.Second)
|
||||
defer deadline.Stop()
|
||||
for {
|
||||
a.refresh_notification_history()
|
||||
if len(a.notifications) == count {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-a.notificationHistory.Updates():
|
||||
case <-deadline.C:
|
||||
t.Fatalf("notification history has %d entries, want %d", len(a.notifications), count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedNotificationHistoryNeverSpeaksOrPlaysOnOtherReaders(t *testing.T) {
|
||||
namespace := fmt.Sprintf(".app.%d.%d", os.Getpid(), time.Now().UnixNano())
|
||||
var readers []*application
|
||||
var voices []*fakeVoice
|
||||
var sounds []*fakeSounds
|
||||
for range 4 {
|
||||
a, voice, cues := shared_notification_application(t, namespace)
|
||||
readers, voices, sounds = append(readers, a), append(voices, voice), append(sounds, cues)
|
||||
}
|
||||
if response := runtime_request(readers[0], "command notify First target"); response != "" {
|
||||
t.Fatal(response)
|
||||
}
|
||||
for index, a := range readers {
|
||||
wait_shared_notifications(t, a, 1)
|
||||
wantSpeech, wantCues := 0, 0
|
||||
if index == 0 {
|
||||
wantSpeech, wantCues = 1, 1
|
||||
}
|
||||
if len(voices[index].messages) != wantSpeech || len(sounds[index].cues) != wantCues {
|
||||
t.Fatal("silent history update triggered speech or sound", index, voices[index].messages, sounds[index].cues)
|
||||
}
|
||||
}
|
||||
runtime_request(readers[1], "command notify Second target")
|
||||
for index, a := range readers {
|
||||
wait_shared_notifications(t, a, 2)
|
||||
if !reflect.DeepEqual(a.notifications, readers[0].notifications) {
|
||||
t.Fatal("readers disagree about history", index)
|
||||
}
|
||||
}
|
||||
if !reflect.DeepEqual(voices[0].messages, []string{"First target"}) || !reflect.DeepEqual(voices[1].messages, []string{"Second target"}) {
|
||||
t.Fatal("targeted speech was duplicated", voices[0].messages, voices[1].messages)
|
||||
}
|
||||
for index := 1; index < len(readers); index++ {
|
||||
if len(sounds[index].cues) != 0 {
|
||||
t.Fatal("target switch reset the shared sound cooldown", index, sounds[index].cues)
|
||||
}
|
||||
}
|
||||
// History recall is an explicit user action and still belongs to that reader.
|
||||
readers[2].last_notification()
|
||||
if !reflect.DeepEqual(voices[2].messages, []string{"Second target"}) || len(sounds[2].cues) != 0 {
|
||||
t.Fatal("history recall was missing or replayed the cue")
|
||||
}
|
||||
readers[2].muted, voices[2].muted = true, true
|
||||
runtime_request(readers[2], "command notify Muted target")
|
||||
readers[3].temporarySilence = true
|
||||
runtime_request(readers[3], "command notify Silenced target")
|
||||
for index, a := range readers {
|
||||
wait_shared_notifications(t, a, 4)
|
||||
if index >= 2 && len(sounds[index].cues) != 0 {
|
||||
t.Fatal("muted or silenced target replayed the cue")
|
||||
}
|
||||
}
|
||||
joining, voice, cues := shared_notification_application(t, namespace)
|
||||
wait_shared_notifications(t, joining, 4)
|
||||
if len(voice.messages) != 0 || len(cues.cues) != 0 || !reflect.DeepEqual(joining.notifications, readers[0].notifications) {
|
||||
t.Fatal("joining reader announced existing history or loaded different messages")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotificationUserSwitchClearsHistoryAndClosesOldDialog(t *testing.T) {
|
||||
namespace := fmt.Sprintf(".app.%d.%d", os.Getpid(), time.Now().UnixNano())
|
||||
a, voice, _ := shared_notification_application(t, namespace)
|
||||
peer, _, _ := shared_notification_application(t, namespace)
|
||||
a.notify("Original account", time.Now())
|
||||
wait_shared_notifications(t, peer, 1)
|
||||
a.open_notifications()
|
||||
if !a.ui.active {
|
||||
t.Fatal("notification dialog did not open")
|
||||
}
|
||||
a.select_notification_user(os.Geteuid() + 1)
|
||||
voice.messages = nil
|
||||
a.refresh_notification_history()
|
||||
if len(a.notifications) != 0 || a.ui.active {
|
||||
t.Fatal("switching accounts exposed the previous history or dialog")
|
||||
}
|
||||
a.select_notification_user(os.Geteuid())
|
||||
wait_shared_notifications(t, a, 1)
|
||||
if len(voice.messages) != 0 {
|
||||
t.Fatal("restoring an account spoke its history", voice.messages)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user