feat: add tray control, priority restoration and session logging
This commit is contained in:
1 parent
4f8f6218ad
commit
4880aa46dc
25 files changed
+3072
-676
No files matched your search
@@ -0,0 +1,146 @@
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNativeProcessHelper(t *testing.T) {
|
||||
if os.Getenv("AP_OWNED_HELPER") != "1" {
|
||||
t.Skip("helper child only")
|
||||
}
|
||||
fmt.Fprintln(os.Stdout, "READY")
|
||||
io.Copy(io.Discard, os.Stdin)
|
||||
os.Exit(0)
|
||||
}
|
||||
func startOwnedHelper(t *testing.T) (uint32, func()) {
|
||||
t.Helper()
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
cmd := exec.CommandContext(ctx, exe, "-test.run=^TestNativeProcessHelper$")
|
||||
cmd.Env = append(os.Environ(), "AP_OWNED_HELPER=1")
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000}
|
||||
input, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
cancel()
|
||||
t.Fatal(err)
|
||||
}
|
||||
output, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
input.Close()
|
||||
cancel()
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = cmd.Start(); err != nil {
|
||||
input.Close()
|
||||
cancel()
|
||||
t.Fatal(err)
|
||||
}
|
||||
var once sync.Once
|
||||
stop := func() { once.Do(func() { input.Close(); cmd.Wait(); cancel() }) }
|
||||
t.Cleanup(stop)
|
||||
line, err := bufio.NewReader(output).ReadString('\n')
|
||||
if err != nil || line != "READY\n" {
|
||||
t.Fatalf("owned helper did not start: %v", err)
|
||||
}
|
||||
return uint32(cmd.Process.Pid), stop
|
||||
}
|
||||
func requireNativeProcesses(t *testing.T) {
|
||||
t.Helper()
|
||||
if os.Getenv("AP_NATIVE_PROCESSES") != "1" {
|
||||
t.Skip("opt-in, test-owned children only; never enumerates other processes")
|
||||
}
|
||||
}
|
||||
func TestNativeOwnedProcessRightsIdentityAndLifetime(t *testing.T) {
|
||||
requireNativeProcesses(t)
|
||||
pid, stop := startOwnedHelper(t)
|
||||
backend := newWindowsBackend()
|
||||
// The system-wide enumerator is intentionally NEVER called in native tests.
|
||||
backend.list = func() ([]procInfo, error) { return []procInfo{{PID: pid, Name: "OwnedHelper.exe"}}, nil }
|
||||
snap, err := backend.Snapshot()
|
||||
if err != nil || len(snap.Processes) != 1 {
|
||||
t.Fatalf("owned snapshot failed: %v", err)
|
||||
}
|
||||
p := snap.Processes[0]
|
||||
defer backend.Close(&p)
|
||||
if p.Key.Created == 0 || p.RSS == 0 || p.Name == "" || !p.Waitable {
|
||||
t.Fatal("incomplete owned-process metadata")
|
||||
}
|
||||
alive, err := backend.Alive(&p)
|
||||
if err != nil || !alive {
|
||||
t.Fatal("live helper not recognized", err)
|
||||
}
|
||||
if err = setPrio(p.Handle, p.PID, p.Prio); err == nil {
|
||||
t.Fatal("snapshot handle unexpectedly grants SET_INFORMATION")
|
||||
}
|
||||
original := p.Prio
|
||||
bad := p
|
||||
bad.Key.Created++
|
||||
if err = backend.SetPriority(&bad, PriorityClassHigh); err == nil {
|
||||
t.Fatal("identity mismatch did not prevent write")
|
||||
}
|
||||
now, err := backend.Priority(&p)
|
||||
if err != nil || now != original {
|
||||
t.Fatal("identity check changed priority")
|
||||
}
|
||||
if err = backend.SetPriority(&p, PriorityClassBelowNormal); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
now, err = backend.Priority(&p)
|
||||
if err != nil || now != PriorityClassBelowNormal {
|
||||
t.Fatal("owned priority write not observed", err)
|
||||
}
|
||||
// Do not request REALTIME in native tests. The child is about to terminate.
|
||||
stop()
|
||||
alive, err = backend.Alive(&p)
|
||||
if err != nil || alive {
|
||||
t.Fatal("signaled process handle not recognized as exited", err)
|
||||
}
|
||||
}
|
||||
func TestNativeControllerRestoresOwnedChild(t *testing.T) {
|
||||
requireNativeProcesses(t)
|
||||
pid, _ := startOwnedHelper(t)
|
||||
backend := newWindowsBackend()
|
||||
backend.list = func() ([]procInfo, error) { return []procInfo{{PID: pid, Name: "OwnedHelper.exe"}}, nil }
|
||||
initial, err := backend.inspect(procInfo{PID: pid})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer backend.Close(&initial)
|
||||
// Establish a known, non-realtime baseline on this test-owned child.
|
||||
if err = backend.SetPriority(&initial, PriorityClassBelowNormal); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c := newController(backend, 1, 0, false, time.Minute)
|
||||
r := c.Step()
|
||||
if len(r.Errors) != 0 {
|
||||
c.Shutdown()
|
||||
t.Fatal(r.Errors)
|
||||
}
|
||||
actual, err := backend.Priority(&initial)
|
||||
if err != nil || actual != PriorityClassHigh {
|
||||
c.Shutdown()
|
||||
t.Fatal("promotion failed", err)
|
||||
}
|
||||
r = c.Shutdown()
|
||||
if r.Unrestored != 0 || len(r.Errors) != 0 {
|
||||
t.Fatal(r)
|
||||
}
|
||||
actual, err = backend.Priority(&initial)
|
||||
if err != nil || actual != PriorityClassBelowNormal {
|
||||
t.Fatal("baseline not restored", err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user