mesh/merge-gate fail: builds dunst → g14, shanks; no bus step; 2 problem(s) the change brings; the first: a machine (f35): nothing could be sent to it with…
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery superseded: a newer head of the same pull request
The actions sat on the middle click, which the operator's touchpads cannot give, and the context menu named dmenu, which dunst's PATH does not hold. The left click is now do_action, close_current (one action runs, several open the menu, none closes), the menu is rofi, declared as a package, Super+N opens it from the keyboard through i3's contribution, and send refuses the token default, which dunst would run at a tap without the menu.
112 lines
3.6 KiB
Go
112 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// **A notification offers answers, and the chosen one is said as an event** (novox/hq ADR 0253): the id
|
|
// is answered at once, the answer comes when the operator chooses, and nothing is said for a
|
|
// notification closed without one.
|
|
func TestANotificationsChosenAnswerIsSaidAsAnEvent(t *testing.T) {
|
|
withBus(t)
|
|
bin := fakeBinaries(t, map[string]string{"notify-send": `for a in "$@"; do printf '[%s]' "$a"; done > "$LOG"; echo 42; sleep 0.2; echo "$CHOSEN"`})
|
|
t.Setenv("LOG", filepath.Join(bin, "log"))
|
|
t.Setenv("MESH_NODE", "g14")
|
|
var mu sync.Mutex
|
|
var said []map[string]any
|
|
before := emit
|
|
emit = func(event string, body any) error {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
if event != ChosenEvent {
|
|
t.Errorf("event %q", event)
|
|
}
|
|
said = append(said, body.(map[string]any))
|
|
return nil
|
|
}
|
|
t.Cleanup(func() { emit = before })
|
|
|
|
n, err := notificationOf(map[string]any{"summary": "Delivery of hq held for 36 hours", "body": "Needs you: release it, or stop it.",
|
|
"actions": []any{map[string]any{"token": "a1b2", "label": "Release"}, map[string]any{"token": "c3d4", "label": "Stop"}}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Setenv("CHOSEN", "c3d4")
|
|
start := time.Now()
|
|
got, err := Send(n)
|
|
if err != nil || got.ID != 42 || time.Since(start) > 150*time.Millisecond {
|
|
t.Fatalf("%+v, %v, after %s: the id is answered before the answer", got, err, time.Since(start))
|
|
}
|
|
asked, _ := os.ReadFile(filepath.Join(bin, "log"))
|
|
if !strings.Contains(string(asked), "[--expire-time=0][--wait][--action=a1b2=Release][--action=c3d4=Stop][--]") {
|
|
t.Fatalf("notify-send was asked %s", asked)
|
|
}
|
|
deadline := time.Now().Add(3 * time.Second)
|
|
for {
|
|
mu.Lock()
|
|
n := len(said)
|
|
mu.Unlock()
|
|
if n > 0 || time.Now().After(deadline) {
|
|
break
|
|
}
|
|
time.Sleep(20 * time.Millisecond)
|
|
}
|
|
mu.Lock()
|
|
if len(said) != 1 || said[0]["token"] != "c3d4" || said[0]["id"] != 42 || said[0]["machine"] != "g14" {
|
|
t.Fatalf("said %v", said)
|
|
}
|
|
said = nil
|
|
mu.Unlock()
|
|
|
|
// Closed without an answer, or an answer nobody offered: nothing is said.
|
|
for _, chosen := range []string{"", "zzzz"} {
|
|
t.Setenv("CHOSEN", chosen)
|
|
if _, err := Send(n); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
time.Sleep(600 * time.Millisecond)
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
if len(said) != 0 {
|
|
t.Fatalf("an answer was invented: %v", said)
|
|
}
|
|
}
|
|
|
|
func TestActionsAreRefusedForWhatTheyCannotBe(t *testing.T) {
|
|
for _, bad := range []any{"x", []any{"x"}, []any{map[string]any{"token": "a b", "label": "x"}},
|
|
[]any{map[string]any{"token": "a", "label": ""}}, []any{map[string]any{"token": "a", "label": "x=y"}},
|
|
[]any{map[string]any{"token": "a", "label": "x"}, map[string]any{"token": "a", "label": "y"}},
|
|
[]any{map[string]any{"token": "default", "label": "x"}, map[string]any{"token": "b", "label": "y"}},
|
|
[]any{map[string]any{"token": "a", "label": "1"}, map[string]any{"token": "b", "label": "2"},
|
|
map[string]any{"token": "c", "label": "3"}, map[string]any{"token": "d", "label": "4"},
|
|
map[string]any{"token": "e", "label": "5"}}} {
|
|
if _, err := notificationOf(map[string]any{"summary": "x", "actions": bad}); err == nil {
|
|
t.Errorf("accepted %v", bad)
|
|
}
|
|
}
|
|
}
|
|
|
|
// **A bundle that started says so**, so the operator channel shows again the answers lost with the one
|
|
// before.
|
|
func TestABundleThatStartedSaysSo(t *testing.T) {
|
|
t.Setenv("MESH_NODE", "g14")
|
|
var said []string
|
|
before := emit
|
|
emit = func(event string, body any) error {
|
|
said = append(said, fmt.Sprintf("%s %v", event, body))
|
|
return nil
|
|
}
|
|
t.Cleanup(func() { emit = before })
|
|
sayStarted()
|
|
if len(said) != 1 || said[0] != "started map[machine:g14]" {
|
|
t.Fatalf("%v", said)
|
|
}
|
|
}
|