package main import ( "os" "path/filepath" "strings" "testing" "time" ) // A notification carrying something shown once — a link's code — is sent transient and in the category // mesh.secret, whatever category the caller names (the review of 2026-10-09, H4): the dunstrc's rules keep // both out of dunst's history, and the history verb leaves out any that got there anyway, so no agent reads // the code back through node-notifier.history. func TestASecretNotificationIsTransientAndKeptOutOfTheHistory(t *testing.T) { withBus(t) bin := fakeBinaries(t, map[string]string{"notify-send": `for a in "$@"; do printf '[%s]' "$a"; done > "$LOG"; echo 42`}) t.Setenv("LOG", filepath.Join(bin, "log")) n, err := notificationOf(map[string]any{"summary": "Link code", "body": "123 456", "secret": true, "category": "email"}) if err != nil { t.Fatal(err) } if _, err := Send(n); err != nil { t.Fatal(err) } asked, _ := os.ReadFile(filepath.Join(bin, "log")) for _, want := range []string{"[--transient]", "[--category=" + SecretCategory + "]"} { if !strings.Contains(string(asked), want) { t.Errorf("notify-send was not asked %s: %s", want, asked) } } if strings.Contains(string(asked), "--category=email") { t.Error("a secret notification kept the caller's category") } if n, err := notificationOf(map[string]any{"summary": "x", "transient": true}); err != nil || !n.Transient || n.Secret { t.Errorf("transient alone: %+v %v", n, err) } // The history leaves a secret one out, and says how many it left out. withSecret := strings.Replace(history, `"category":{"type":"s","data":"device"}`, `"category":{"type":"s","data":"`+SecretCategory+`"}`, 1) got, err := parseHistory(withSecret, 200_000_000, 20) if err != nil { t.Fatal(err) } if len(got.Notifications) != 1 || got.Notifications[0].ID != 7 || got.Total != 1 || got.Withheld != 1 { t.Fatalf("the history showed a secret notification: %+v", got) } // The decided file holds the rules that keep them out of dunst's own history. rc, err := os.ReadFile(filepath.Join("..", "..", "files", "dunstrc")) if err != nil { t.Fatal(err) } for _, want := range []string{"category = \"" + SecretCategory + "\"", "match_transient = yes", "history_ignore = yes"} { if !strings.Contains(string(rc), want) { t.Errorf("dunstrc does not say %q", want) } } } // Whether notifications are paused is said as the event `paused` {paused, machine}: at once, on every change, // and again every PausedEvery, so the desk knows a link's code would not be seen (C4); nothing is said while // dunst cannot be asked. func TestWhetherPausedIsSaidOnChangeAndEveryFewMinutes(t *testing.T) { var said []bool paused, fails := false, false w := pauseWatch{ isPaused: func() (bool, error) { if fails { return false, os.ErrNotExist } return paused, nil }, say: func(p bool) error { said = append(said, p); return nil }, } at := time.Date(2026, 10, 9, 12, 0, 0, 0, time.UTC) w.step(at) w.step(at.Add(5 * time.Second)) paused = true w.step(at.Add(10 * time.Second)) w.step(at.Add(10*time.Second + PausedEvery)) fails = true w.step(at.Add(10*time.Second + 3*PausedEvery)) if len(said) != 3 || said[0] || !said[1] || !said[2] { t.Fatalf("said %v", said) } }