Phase 2 of the Wine/Proton stage (decisions 3, 4, 16, 17, 19 in docs/testing/wine-proton.md): replace the Wine manager's startup snapshot with a live settings source read once per poll, so accepted global settings take effect with no reader restart. The source publishes only the active/global profile's Wine values; per-application profile switching never changes the governing list. A newly listed running program restarts its helper once in the same mode; removals and clearing the global switch never downgrade a running helper.
104 lines
3.3 KiB
Go
104 lines
3.3 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package wine
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// The manager must read its settings source at each poll and helper spawn,
|
|
// never a snapshot taken when it was constructed. A live addition for a
|
|
// currently discovered program restarts the running helper once in the same
|
|
// mode, and removals never downgrade a running helper.
|
|
func TestManagerReadsSettingsSourceAtEachPoll(t *testing.T) {
|
|
t.Setenv("WINE_ACCESS_NO_DIALOG_READER", "")
|
|
root := t.TempDir()
|
|
procRoot := filepath.Join(root, "proc")
|
|
loader := filepath.Join(root, "wine")
|
|
write_helper_file(t, loader, "loader")
|
|
base := filepath.Join(procRoot, "101")
|
|
write_helper_file(t, filepath.Join(base, "cmdline"), "launcher.exe\x00")
|
|
write_helper_file(t, filepath.Join(base, "environ"), "WINEPREFIX="+root+"\x00")
|
|
if err := os.Symlink(loader, filepath.Join(base, "exe")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
helper := filepath.Join(root, "helper")
|
|
write_helper_file(t, helper, "#!/bin/sh\nexec sleep 30\n")
|
|
|
|
current := Settings{}
|
|
reads := 0
|
|
manager := New(nil)
|
|
manager.helper, manager.procRoot = helper, procRoot
|
|
manager.SettingsSource = func() Settings {
|
|
reads++
|
|
return current
|
|
}
|
|
active := map[string]*process{}
|
|
defer func() {
|
|
for _, child := range active {
|
|
stop(child)
|
|
}
|
|
}()
|
|
|
|
manager.poll(active)
|
|
child := active[root]
|
|
if child == nil || child.cmd == nil || child.controllerOnly {
|
|
t.Fatal("helper did not start normally")
|
|
}
|
|
if len(child.exclusions) != 0 {
|
|
t.Fatalf("initial exclusions = %v", child.exclusions)
|
|
}
|
|
if reads == 0 {
|
|
t.Fatal("poll did not read the settings source")
|
|
}
|
|
pid := child.cmd.Process.Pid
|
|
|
|
// A live addition naming a currently discovered program reaches the
|
|
// running helper at the next poll: one restart, same mode, flag added.
|
|
readsBefore := reads
|
|
current = Settings{ExcludedPrograms: []string{"Launcher.exe"}}
|
|
manager.poll(active)
|
|
if reads <= readsBefore {
|
|
t.Fatal("later poll did not re-read the settings source")
|
|
}
|
|
if child.controllerOnly || child.cmd == nil || child.cmd.Process.Pid == pid {
|
|
t.Fatal("live addition did not restart the helper in the same mode")
|
|
}
|
|
if !child.exclusions["launcher.exe"] {
|
|
t.Fatal("restarted helper lacks the live exclusion flag")
|
|
}
|
|
if got := strings.Join(child.cmd.Args[1:], " "); got != "--exclude-hook-program launcher.exe" {
|
|
t.Fatalf("restarted helper arguments = %q", got)
|
|
}
|
|
pid = child.cmd.Process.Pid
|
|
manager.poll(active)
|
|
if child.cmd.Process.Pid != pid {
|
|
t.Fatal("helper restarted more than once for one live addition")
|
|
}
|
|
|
|
// Removing the listing never restarts or downgrades the running helper.
|
|
current = Settings{}
|
|
manager.poll(active)
|
|
if child.cmd.Process.Pid != pid {
|
|
t.Fatal("helper restarted when a live listing was removed")
|
|
}
|
|
|
|
// Turning the global switch on live upgrades the helper wholesale;
|
|
// clearing it live never downgrades the running helper.
|
|
current = Settings{ControllerOnly: true}
|
|
manager.poll(active)
|
|
if !child.controllerOnly || child.cmd == nil || child.cmd.Process.Pid == pid {
|
|
t.Fatal("live global switch did not upgrade the helper wholesale")
|
|
}
|
|
pid = child.cmd.Process.Pid
|
|
current = Settings{}
|
|
manager.poll(active)
|
|
if !child.controllerOnly || child.cmd.Process.Pid != pid {
|
|
t.Fatal("wholesale helper downgraded after the live switch was cleared")
|
|
}
|
|
}
|