A setting changed through mesh-controller.settings rewrote dunstrc, but the running dunst kept the old font and width until the next login. Declare the package's dunst.service in the account's manager, without a state, with reload-on the configuration, so the node-engine runs its ExecReload (dunstctl reload) and what is on screen stays. Add dunst_reload to do the same on demand and say the font and width the files set.
97 lines
3.4 KiB
Go
97 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// The running dunst reads its file again when the file changes (novox/hq ADR 0262: a setting the
|
|
// operator changes shows at the next notification, not at the next login). The node-engine reloads
|
|
// the account's dunst.service, whose ExecReload is `dunstctl reload`; dunst_reload does the same now.
|
|
|
|
// writeConfig puts a dunstrc and drop-ins under a fake home's ~/.config/dunst.
|
|
func writeConfig(t *testing.T, home string, files map[string]string) {
|
|
t.Helper()
|
|
for name, body := range files {
|
|
path := filepath.Join(home, ".config", "dunst", name)
|
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(path, []byte(body), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTheGlobalsAreTheLastFileThatSetsThem(t *testing.T) {
|
|
home := t.TempDir()
|
|
writeConfig(t, home, map[string]string{
|
|
"dunstrc": "[global]\n width = 500\n height = (0, 300)\n font = Inter 13\n" +
|
|
"[urgency_low]\n font = Mono 99\n",
|
|
// A rule's font is the rule's, not the global one; a later [global] in a drop-in outranks dunstrc.
|
|
"dunstrc.d/10-slack.conf": "[slack]\n appname = Slack\n font = \"Comic 40\"\n",
|
|
"dunstrc.d/90-big.conf": "# a comment\n[global]\n font = \"Inter 16\"\n",
|
|
})
|
|
got := globalsOf(configFiles(filepath.Join(home, ".config", "dunst")))
|
|
if got.Font != "Inter 16" || got.FontSize != 16 || got.Width != "500" {
|
|
t.Fatalf("%+v", got)
|
|
}
|
|
if !strings.HasSuffix(got.FontFrom, "dunstrc.d/90-big.conf") || !strings.HasSuffix(got.WidthFrom, "/dunstrc") {
|
|
t.Fatalf("from: %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestReloadAsksTheRunningDunstToReadItsFilesAndSaysWhatTheySet(t *testing.T) {
|
|
root := withBus(t)
|
|
writeConfig(t, filepath.Join(root, "home"), map[string]string{
|
|
"dunstrc": "[global]\n width = 500\n font = Inter 13\n",
|
|
})
|
|
bin := fakeBinaries(t, map[string]string{"dunstctl": `echo "$*" >> "$LOG"
|
|
case "$*" in
|
|
count*) echo 0 ;;
|
|
is-paused) echo false ;;
|
|
esac`})
|
|
t.Setenv("LOG", filepath.Join(bin, "log"))
|
|
got, err := Reload()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !got.Reloaded || got.Font != "Inter 13" || got.FontSize != 13 || got.Width != "500" || len(got.Files) != 1 {
|
|
t.Fatalf("%+v", got)
|
|
}
|
|
if !strings.Contains(got.Note, "does not answer") {
|
|
t.Fatalf("the note does not say where the values come from: %q", got.Note)
|
|
}
|
|
log, _ := os.ReadFile(filepath.Join(bin, "log"))
|
|
asked := strings.Split(strings.TrimSpace(string(log)), "\n")
|
|
// reload first, with no files named (dunst reads its own search path, drop-ins included), and then
|
|
// asked something to show it still answers.
|
|
if asked[0] != "reload" || len(asked) < 2 {
|
|
t.Fatalf("dunstctl was asked: %q", asked)
|
|
}
|
|
}
|
|
|
|
func TestAReloadDunstRefusesIsAFailure(t *testing.T) {
|
|
withBus(t)
|
|
fakeBinaries(t, map[string]string{"dunstctl": `echo "Failed to communicate with dunst" >&2; exit 1`})
|
|
if _, err := Reload(); err == nil || !strings.Contains(err.Error(), "Failed to communicate") {
|
|
t.Fatalf("%v", err)
|
|
}
|
|
}
|
|
|
|
func TestTheRunningDunstIsReloadedWhenItsFileChanges(t *testing.T) {
|
|
m := readManifest(t)
|
|
s := m.resource(t, "notifier")
|
|
want := map[string]any{
|
|
"id": "notifier", "type": "service", "unit": "dunst.service",
|
|
"scope": "user", "user": "${machine:account}",
|
|
"reload-on": []any{"configuration"},
|
|
}
|
|
if !reflect.DeepEqual(s, want) {
|
|
t.Fatalf("notifier: %v\nwant %v", s, want)
|
|
}
|
|
}
|