The laptop model's hardware module and a memory-pressure module for any machine (hq research 027/03, 026/05, to-be 42 phase 3). The predecessor's polling auto-profile and mem-guard user scripts become each module's own Go code launched by the node runtime (ADR 0198): a profile switcher woken by the kernel's power-supply uevents, and a guard that warns on RAM, swap or PSI before systemd-oomd acts, on the desktop over the account's bus and always as an event. supergfxctl and triggerhappy are kept as found (research 027 Q1).
92 lines
2.9 KiB
Go
92 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// backlight makes a backlight the way sysfs does: a link from /sys/class/backlight into the device
|
|
// tree, which is where the eDP connector shows.
|
|
func (f *fake) backlight(name, device string, raw, max string) {
|
|
dev := "/sys/devices/" + device + "/" + name
|
|
f.file(dev+"/brightness", raw)
|
|
f.file(dev+"/max_brightness", max)
|
|
f.file(dev+"/type", "raw")
|
|
link := filepath.Join(f.root, "/sys/class/backlight", name)
|
|
os.MkdirAll(filepath.Dir(link), 0o755)
|
|
if err := os.Symlink(filepath.Join(f.root, dev), link); err != nil {
|
|
f.t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestThePanelIsTheBacklightUnderTheEDPConnectorNotTheDiscreteGPUs(t *testing.T) {
|
|
f := newFake(t)
|
|
f.backlight("amdgpu_bl1", "pci0000:00/0000:65:00.0/drm/card1/card1-eDP-1", "199500", "399000")
|
|
f.backlight("nvidia_0", "pci0000:00/0000:01:00.0/backlight", "100", "100")
|
|
p, err := f.machine().PanelBrightness()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if p.Device != "amdgpu_bl1" || p.Percent != 50 || len(p.Others) != 1 || p.Others[0] != "nvidia_0" {
|
|
t.Fatalf("%+v", p)
|
|
}
|
|
}
|
|
|
|
func TestAPanelRequestIsAPercentageOrAStepAndNeverGoesDark(t *testing.T) {
|
|
for _, c := range []struct {
|
|
cur float64
|
|
req string
|
|
want float64
|
|
}{{50, "40", 40}, {50, "40%", 40}, {50, "+5", 55}, {50, "-10", 40}, {3, "-10", 1}, {98, "+5", 100}, {50, "0", 1}} {
|
|
got, err := PanelTarget(c.cur, c.req)
|
|
if err != nil || got != c.want {
|
|
t.Errorf("%v %q: %v %v, want %v", c.cur, c.req, got, err, c.want)
|
|
}
|
|
}
|
|
for _, bad := range []string{"", "bright", "NaN"} {
|
|
if _, err := PanelTarget(50, bad); err == nil {
|
|
t.Errorf("%q was accepted", bad)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSettingThePanelWritesTheRawValue(t *testing.T) {
|
|
f := newFake(t)
|
|
f.backlight("amdgpu_bl1", "card1-eDP-1", "399000", "399000")
|
|
p, err := f.machine().SetPanel(context.Background(), "25")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
raw, _ := os.ReadFile(filepath.Join(f.root, "/sys/devices/card1-eDP-1/amdgpu_bl1/brightness"))
|
|
if strings.TrimSpace(string(raw)) != "99750" || p.Percent != 25 {
|
|
t.Fatalf("wrote %q, read back %+v", raw, p)
|
|
}
|
|
}
|
|
|
|
func TestTheKeyboardIsSetThroughAsusdByLevel(t *testing.T) {
|
|
f := newFake(t)
|
|
f.file("/sys/class/leds/asus::kbd_backlight/brightness", "1")
|
|
f.file("/sys/class/leds/asus::kbd_backlight/max_brightness", "3")
|
|
k, err := f.machine().KeyboardBrightness()
|
|
if err != nil || k.Level != "low" {
|
|
t.Fatalf("%+v %v", k, err)
|
|
}
|
|
if _, err := f.machine().SetKeyboard(context.Background(), "+"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !f.called("asusctl leds set med") {
|
|
t.Fatalf("calls: %v", f.calls)
|
|
}
|
|
for req, want := range map[string]string{"high": "high", "0": "off", "medium": "med", "-": "off"} {
|
|
if got, err := KeyboardTarget(1, req); err != nil || got != want {
|
|
t.Errorf("%q: %q %v", req, got, err)
|
|
}
|
|
}
|
|
if _, err := KeyboardTarget(1, "7"); err == nil {
|
|
t.Error("level 7 was accepted")
|
|
}
|
|
}
|