Keep certificate-directory problems on the station window and leave a hand-edit untouched until Save.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-11 19:29:32 +02:00
co-authored by Cursor
parent 775d1b5c82
commit d21e7051d7
8 changed files with 165 additions and 40 deletions
+110 -4
View File
@@ -211,6 +211,107 @@ func TestConfigStaysClosedWhilePushToTalkIsHeld(t *testing.T) {
}
}
func TestCertificateProblemStaysOnTheStation(t *testing.T) {
path := filepath.Join(t.TempDir(), "funknetz.json")
body := []byte("{\"host\":\"127.0.0.1\",\"port\":5308,\"callsign\":\"DL1ABC\",\"authKey\":\"key\",\"talkGroup\":20,\"certificateDir\":\"\",\"enableLogging\":false,\"logFile\":\"/tmp/funknetz.log\"}\n")
if err := os.WriteFile(path, body, 0o600); err != nil {
t.Fatal(err)
}
st, err := station.New(station.Options{ConfigPath: path})
if err != nil {
t.Fatal(err)
}
t.Cleanup(st.Close)
got := st.State()
if got.ConfigOpen || got.NeedsConfig || got.Detail != "certificateDir is empty" || got.Connection != "Disconnected" {
t.Fatalf("State = %+v, want the station window with the certificate detail", got)
}
if st.Cancel() {
t.Fatal("Cancel() quit after a certificate-directory problem")
}
}
func TestOpenConfigDoesNotRewriteAHandEdit(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "funknetz.json")
body := []byte(fullConfig("127.0.0.1", 5308, "DL1ABC", "key", 20, filepath.Join(dir, "funknetz.log")))
if err := os.WriteFile(path, body, 0o600); err != nil {
t.Fatal(err)
}
st, err := station.New(station.Options{ConfigPath: path})
if err != nil {
t.Fatal(err)
}
t.Cleanup(st.Close)
edited := []byte("{\"host\":\"127.0.0.1\",\"port\":5308,\"callsign\":\"DL1ABC\",\"authKey\":\"key\",\"talkGroup\":20,\"enableLogging\":false,\"logFile\":\"" + filepath.Join(dir, "funknetz.log") + "\"}\n")
if err := os.WriteFile(path, edited, 0o600); err != nil {
t.Fatal(err)
}
st.OpenConfig()
if st.Cancel() {
t.Fatal("Cancel() quit")
}
got, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
if string(got) != string(edited) {
t.Fatalf("file = %s, want the hand-edit left unchanged", got)
}
if st.State().Callsign != "DL1ABC" || st.State().ConfigOpen {
t.Fatalf("State = %+v, want the loaded session and a closed Config window", st.State())
}
}
func TestSaveEmptyCertificateDirDoesNotConnect(t *testing.T) {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer ln.Close()
port := ln.Addr().(*net.TCPAddr).Port
path := filepath.Join(t.TempDir(), "funknetz.json")
st, err := station.New(station.Options{ConfigPath: path})
if err != nil {
t.Fatal(err)
}
t.Cleanup(st.Close)
ctx, cancel := context.WithCancel(t.Context())
defer cancel()
go func() {
// Run's error is observed through State, which is the station seam.
_ = st.Run(ctx)
}()
err = st.Save(station.ConfigForm{
Host: "127.0.0.1",
Port: port,
Callsign: "DL1ABC",
AuthKey: "key",
TalkGroup: 20,
CertificateDir: "",
LogFile: "/tmp/funknetz.log",
})
if err != nil {
t.Fatal(err)
}
got := st.State()
if got.ConfigOpen || got.Detail != "certificateDir is empty" || got.Connection != "Disconnected" {
t.Fatalf("State = %+v, want the window closed and the certificate detail", got)
}
info, err := os.Stat(path)
if err != nil {
t.Fatal(err)
}
if info.Mode().Perm() != 0o600 {
t.Fatalf("mode = %o, want 600", info.Mode().Perm())
}
ln.(*net.TCPListener).SetDeadline(time.Now().Add(200 * time.Millisecond))
if conn, err := ln.Accept(); err == nil {
conn.Close()
t.Fatal("opened a socket")
}
}
func TestLoggingOnlySaveKeepsTheSession(t *testing.T) {
in := login(t, "DL1ABC", "key", 20, 7, []string{"OPUS"})
logPath := filepath.Join(t.TempDir(), "station.log")
@@ -253,7 +354,10 @@ func TestLoggingSaveDoesNotClearAFatalStop(t *testing.T) {
st.Fail("could not open the audio device")
ctx, cancel := context.WithCancel(t.Context())
defer cancel()
go func() { _ = st.Run(ctx) }()
go func() {
// Run's error is observed through State, which is the station seam.
_ = st.Run(ctx)
}()
st.OpenConfig()
form := st.Config().Form
@@ -297,7 +401,10 @@ func TestSaveWriteFailureKeepsTheSession(t *testing.T) {
if err := os.Chmod(dir, 0o555); err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = os.Chmod(dir, 0o755) })
t.Cleanup(func() {
// Restore the directory so the test temp dir can be removed.
_ = os.Chmod(dir, 0o755)
})
in.st.OpenConfig()
form := in.st.Config().Form
form.TalkGroup = 21
@@ -393,8 +500,7 @@ func connStillOpen(conn net.Conn) error {
if err == nil {
return nil
}
var ne net.Error
if errors.As(err, &ne) && ne.Timeout() {
if ne, ok := errors.AsType[net.Error](err); ok && ne.Timeout() {
return nil
}
return err