The i3 and laptop READMEs each pointed at the other for 10-asus.conf and 20-g14.conf, so nobody owned them. The module now writes both (adopted paths, so no duplicate binding breaks i3's config check), ships the scripts they call, runs the media keys with notifications again, and brings back the touchpad reset after resume as a unit the sleep services want. zephyrus_keys answers what each custom key runs; the check flags as-user, thd's account and the resume unit. xorg-xinput is the xorg module's.
107 lines
3.4 KiB
Go
107 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func put(t *testing.T, root, p, content string) {
|
|
t.Helper()
|
|
full := filepath.Join(root, p)
|
|
if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(full, []byte(content), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// The module's shipped triggers and i3 lines, read back as keys: what each runs and where.
|
|
func TestKeysListsTriggersI3LinesAndFirmwareKeys(t *testing.T) {
|
|
f := newFake(t)
|
|
m := readManifest(t)
|
|
content := map[string]string{}
|
|
for _, r := range m.Resources {
|
|
if c, ok := r["content"].(string); ok {
|
|
content[r["id"].(string)] = c
|
|
}
|
|
}
|
|
put(t, f.root, TriggerDir+"/asus-g14.conf", content["vendor-keys"])
|
|
home := "/home/operator"
|
|
t.Setenv("MESH_OPERATOR_HOME", home)
|
|
put(t, f.root, home+"/"+I3Fragments[0], content["i3-vendor-keys"])
|
|
put(t, f.root, home+"/"+I3Fragments[1], content["i3-model"])
|
|
|
|
r := f.machine().Keys()
|
|
got := map[string]Key{}
|
|
for _, k := range r.Keys {
|
|
got[k.Key+"|"+k.When] = k
|
|
}
|
|
if k := got["KEY_F21|pressed"]; !strings.Contains(k.Runs, "zephyrus-touchpad reset") || k.Physical == "" {
|
|
t.Errorf("touchpad key: %+v", k)
|
|
}
|
|
if k := got["KEY_PROG1|pressed"]; !strings.Contains(k.Runs, "zephyrus-media play-pause") {
|
|
t.Errorf("media key: %+v", k)
|
|
}
|
|
if k := got["$mod+Shift+s|released"]; !strings.Contains(k.Runs, "screenshot") || !strings.Contains(k.Physical, "Fn+F6") {
|
|
t.Errorf("screenshot key: %+v", k)
|
|
}
|
|
if k := got["$mod+p|pressed"]; !strings.Contains(k.Runs, "zephyrus-display order") {
|
|
t.Errorf("display key: %+v", k)
|
|
}
|
|
if k := got["(session start)|at login"]; k.Runs == "" {
|
|
t.Errorf("no session-start line read")
|
|
}
|
|
if k := got["Fn+F2 / Fn+F3|"]; k.From != "firmware" {
|
|
t.Errorf("firmware keys missing: %+v", r.Keys)
|
|
}
|
|
if len(r.Warnings) != 0 || len(r.NotRead) != 0 {
|
|
t.Errorf("warnings %v, not read %v", r.Warnings, r.NotRead)
|
|
}
|
|
if _, err := json.Marshal(r); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// A key bound in two trigger files fires twice, which is said.
|
|
func TestKeysWarnsAboutAKeyInTwoTriggerFiles(t *testing.T) {
|
|
f := newFake(t)
|
|
put(t, f.root, TriggerDir+"/asus-g14.conf", "KEY_F21\t1\t/x reset\n")
|
|
put(t, f.root, TriggerDir+"/old.conf", "KEY_F21\t1\t/y reset\n")
|
|
t.Setenv("MESH_OPERATOR_HOME", "")
|
|
r := f.machine().Keys()
|
|
if len(r.Warnings) != 1 || !strings.Contains(r.Warnings[0], "KEY_F21") || len(r.NotRead) != 1 {
|
|
t.Errorf("warnings %v, not read %v", r.Warnings, r.NotRead)
|
|
}
|
|
}
|
|
|
|
// The check names what still calls as-user, and whether triggerhappy runs as the account.
|
|
func TestCheckFindsAsUserAndTriggerhappysAccount(t *testing.T) {
|
|
f := newFake(t)
|
|
put(t, f.root, "/etc/udev/rules.d/91-monitor-hotplug.rules", `RUN+="/x/scripts/as-user setsid wizard"`)
|
|
put(t, f.root, "/proc/4242/comm", "thd\n")
|
|
put(t, f.root, "/proc/4242/status", "Name:\tthd\nUid:\t0\t0\t0\t0\n")
|
|
was := operatorUID
|
|
operatorUID = func() int { return 1000 }
|
|
defer func() { operatorUID = was }()
|
|
t.Setenv("MESH_OPERATOR_HOME", "")
|
|
r := f.machine().Check(context.Background(), nil)
|
|
by := map[string]Check{}
|
|
for _, c := range r.Checks {
|
|
by[c.Name] = c
|
|
}
|
|
if c := by["no as-user"]; c.OK || !strings.Contains(c.Detail, "91-monitor-hotplug.rules") {
|
|
t.Errorf("as-user: %+v", c)
|
|
}
|
|
if c := by["triggerhappy as the account"]; c.OK || !strings.Contains(c.Detail, "uid 0") {
|
|
t.Errorf("triggerhappy: %+v", c)
|
|
}
|
|
if c := by["touchpad after resume"]; c.OK {
|
|
t.Errorf("resume: %+v", c)
|
|
}
|
|
}
|