After commit c018f5fd29 Fenrir is being switched over to go. If you do not want to be part of the testing process, please switch to master.
This commit is contained in:
1 parent
c018f5fd29
commit
0e50de4c76
1047 files changed
+58364
-63747
No files matched your search
@@ -0,0 +1,138 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"git.stormux.org/storm/fenrir/internal/config"
|
||||
"git.stormux.org/storm/fenrir/internal/control"
|
||||
"git.stormux.org/storm/fenrir/internal/input"
|
||||
"git.stormux.org/storm/fenrir/internal/screen"
|
||||
)
|
||||
|
||||
// Model the console's policy boundary independently of the shared application.
|
||||
type policySource struct {
|
||||
fakeSource
|
||||
ignoredVTs []int
|
||||
}
|
||||
|
||||
func (s *policySource) Configure_ignored_vts(numbers []int) {
|
||||
s.ignoredVTs = append([]int(nil), numbers...)
|
||||
}
|
||||
|
||||
func (s *policySource) Read() (screen.Snapshot, error) {
|
||||
for _, number := range s.ignoredVTs {
|
||||
if number == s.snapshot.Terminal {
|
||||
return screen.Snapshot{Terminal: number}, nil
|
||||
}
|
||||
}
|
||||
return s.fakeSource.Read()
|
||||
}
|
||||
|
||||
func (s *policySource) State() (int, bool, bool, error) {
|
||||
snapshot, err := s.Read()
|
||||
return snapshot.Terminal, snapshot.Active, snapshot.NumLock, err
|
||||
}
|
||||
|
||||
func TestRemoteIgnoredVTListsAreAtomic(t *testing.T) {
|
||||
base := config.Defaults()
|
||||
base.Screen.IgnoredVTs = []int{2, 3}
|
||||
for _, text := range []string{
|
||||
"SET screen#ignore_screen=7, 8,10;speech#enabled=False",
|
||||
"SET screen#ignore_screen=7, 8,10,speech#enabled=False",
|
||||
} {
|
||||
updated, err := remote_settings(base, text)
|
||||
if err != nil || !reflect.DeepEqual(updated.Screen.IgnoredVTs, []int{7, 8, 10}) || updated.Presentation.Speech.Enabled {
|
||||
t.Fatal("lost list or following assignment", updated, err)
|
||||
}
|
||||
}
|
||||
for _, value := range []string{"0", "64", "-1", "7,7", "7,", "7,,8", "tty7", "7;unknown#setting=True"} {
|
||||
failed, err := remote_settings(base, "SET speech#enabled=False;screen#ignore_screen="+value)
|
||||
if err == nil || !reflect.DeepEqual(failed, base) || !reflect.DeepEqual(base.Screen.IgnoredVTs, []int{2, 3}) {
|
||||
t.Fatal("invalid list partially applied", value, failed, base, err)
|
||||
}
|
||||
}
|
||||
updated, err := remote_settings(base, "SET screen#ignore_screen=")
|
||||
if err != nil || len(updated.Screen.IgnoredVTs) != 0 {
|
||||
t.Fatal("empty list did not clear policy", updated.Screen, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIgnoredVTStartupRemoteReleaseRecoveryAndTerminalIsolation(t *testing.T) {
|
||||
for _, terminalMode := range []bool{false, true} {
|
||||
settings := config.Defaults()
|
||||
settings.Screen.IgnoredVTs = []int{2, 7, 8, 10}
|
||||
source := &policySource{fakeSource: fakeSource{snapshot: screen.Snapshot{Terminal: 2, Active: true, Rows: 1, Cols: 5, Cells: []rune("alpha")}}}
|
||||
voice := &fakeVoice{}
|
||||
var modes []bool
|
||||
keys := &fakeKeys{poll: func(active bool, _ func(input.Decision)) error {
|
||||
modes = append(modes, active)
|
||||
return nil
|
||||
}}
|
||||
a, err := new_application(context.Background(), source, keys, voice, RunOptions{Settings: settings, TerminalMode: terminalMode})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(a.ui.close)
|
||||
if err := a.read_screen(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := a.poll_input(true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if a.lastActive != terminalMode || (!terminalMode && len(voice.messages) != 0) {
|
||||
t.Fatal("wrong startup policy", terminalMode, a.lastActive, voice.messages)
|
||||
}
|
||||
request := func(uid int, text string) string {
|
||||
t.Helper()
|
||||
replies := make(chan string, 1)
|
||||
a.remote_request(control.Request{UID: uid, Text: "SETTING " + text, Reply: replies})
|
||||
return <-replies
|
||||
}
|
||||
if reply := request(os.Geteuid()+1, "SET screen#ignore_screen="); reply == "" || !reflect.DeepEqual(a.settings.live.Screen, settings.Screen) {
|
||||
t.Fatal("unauthorized policy change", reply, a.settings.live.Screen)
|
||||
}
|
||||
if reply := request(os.Geteuid(), "SET screen#ignore_screen="); reply != "" {
|
||||
t.Fatal(reply)
|
||||
}
|
||||
if err := a.poll_input(true); err != nil || !a.lastActive {
|
||||
t.Fatal("did not recover after remote clear", err)
|
||||
}
|
||||
a.ui.open_tutorial(nil, nil, nil)
|
||||
interrupts := voice.interrupts
|
||||
if reply := request(os.Geteuid(), "SET screen#ignore_screen=2,7,8,10"); reply != "" {
|
||||
t.Fatal(reply)
|
||||
}
|
||||
if err := a.poll_input(false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !terminalMode && (a.lastActive || a.ui.active || voice.interrupts <= interrupts || !reflect.DeepEqual(keys.captures, []bool{true, false})) {
|
||||
t.Fatal("handoff retained modal capture or speech", a.lastActive, a.ui.active, keys.captures, voice.interrupts)
|
||||
}
|
||||
if terminalMode && (!a.lastActive || !a.ui.active) {
|
||||
t.Fatal("console policy affected X11 session")
|
||||
}
|
||||
source.snapshot.Terminal = 3
|
||||
if err := a.poll_input(false); err != nil || !a.lastActive {
|
||||
t.Fatal("allowed VT did not resume", err)
|
||||
}
|
||||
if !terminalMode && !reflect.DeepEqual(modes, []bool{false, true, false, true}) {
|
||||
t.Fatal("wrong handoff order", modes)
|
||||
}
|
||||
// Applying a saved draft uses the same policy; quick-save must retain it.
|
||||
saved := settings
|
||||
saved.Screen.IgnoredVTs = []int{3}
|
||||
a.apply_saved_settings(saved, false)
|
||||
if err := a.poll_input(false); err != nil || a.lastActive != terminalMode {
|
||||
t.Fatal("saved policy was not applied", err, a.lastActive)
|
||||
}
|
||||
if !reflect.DeepEqual(a.settings.saveDraft.Screen.IgnoredVTs, []int{3}) {
|
||||
t.Fatal("lost saved policy")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user