Append an optional station log and announce the software after login.
A log path that cannot be written leaves the station on the reflector, and the reflector learns which program joined. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+215
-3
@@ -44,11 +44,21 @@ func TestMissingConfigIsCreatedAndRejected(t *testing.T) {
|
||||
if got["port"] != float64(0) || got["talkGroup"] != float64(0) {
|
||||
t.Fatalf("numeric fields = %#v, want port and talkGroup at zero", got)
|
||||
}
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got["enableLogging"] != false {
|
||||
t.Fatalf("enableLogging = %#v, want false", got["enableLogging"])
|
||||
}
|
||||
if got["logFile"] != filepath.Join(home, "funknetz.log") {
|
||||
t.Fatalf("logFile = %#v, want funknetz.log in the home directory", got["logFile"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestExistingConfigIsNotRewritten(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "funknetz.json")
|
||||
original := []byte("{\"host\":\"127.0.0.1\",\"port\":5308,\"callsign\":\"DL1ABC\",\"authKey\":\"a b\",\"talkGroup\":20}\n")
|
||||
original := []byte("{\"host\":\"127.0.0.1\",\"port\":5308,\"callsign\":\"DL1ABC\",\"authKey\":\"a b\",\"talkGroup\":20,\"enableLogging\":false,\"logFile\":\"/tmp/funknetz.log\"}\n")
|
||||
if err := os.WriteFile(path, original, 0o640); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -117,8 +127,21 @@ func TestInvalidConfigNamesTheField(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(after) != string(before) {
|
||||
t.Fatalf("file = %q, want it left untouched", after)
|
||||
if strings.Contains(tt.want, "wrong type") {
|
||||
if string(after) != string(before) {
|
||||
t.Fatalf("file = %q, want it left untouched", after)
|
||||
}
|
||||
return
|
||||
}
|
||||
var got map[string]any
|
||||
if err := jsonv2.Unmarshal(after, &got); err != nil {
|
||||
t.Fatalf("rewritten file is not JSON: %v\n%s", err, after)
|
||||
}
|
||||
if got["enableLogging"] != false {
|
||||
t.Fatalf("enableLogging = %#v, want false", got["enableLogging"])
|
||||
}
|
||||
if _, ok := got["logFile"].(string); !ok {
|
||||
t.Fatalf("logFile = %#v, want a string", got["logFile"])
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -163,6 +186,179 @@ func TestCallsignIsTrimmedAndUppercased(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMissingLogKeysAreRewritten(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "funknetz.json")
|
||||
original := []byte("{\"note\":true,\"host\":\" 127.0.0.1 \",\"port\":5308,\"callsign\":\" dl1abc \",\"authKey\":\"a b\",\"talkGroup\":20}\n")
|
||||
if err := os.WriteFile(path, original, 0o640); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st, err := station.New(station.Options{ConfigPath: path})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(st.Close)
|
||||
if st.State().Callsign != "DL1ABC" {
|
||||
t.Fatalf("Callsign = %q", st.State().Callsign)
|
||||
}
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := info.Mode().Perm(), os.FileMode(0o640); got != want {
|
||||
t.Fatalf("mode = %o, want %o", got, want)
|
||||
}
|
||||
body, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var got map[string]any
|
||||
if err := jsonv2.Unmarshal(body, &got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := got["note"]; ok {
|
||||
t.Fatalf("note = %#v, want it dropped", got["note"])
|
||||
}
|
||||
if got["callsign"] != " dl1abc " || got["authKey"] != "a b" || got["host"] != " 127.0.0.1 " {
|
||||
t.Fatalf("kept fields = %#v", got)
|
||||
}
|
||||
if got["enableLogging"] != false {
|
||||
t.Fatalf("enableLogging = %#v", got["enableLogging"])
|
||||
}
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got["logFile"] != filepath.Join(home, "funknetz.log") {
|
||||
t.Fatalf("logFile = %#v", got["logFile"])
|
||||
}
|
||||
if st.State().Detail != "Idle" {
|
||||
t.Fatalf("Detail = %q, want Idle", st.State().Detail)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogSettingsDoNotStopTheStation(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
|
||||
t.Run("missing log file uses home", func(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,"enableLogging":true}`)
|
||||
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, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var fields map[string]any
|
||||
if err := jsonv2.Unmarshal(got, &fields); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantPath := filepath.Join(home, "funknetz.log")
|
||||
if fields["logFile"] != wantPath || fields["enableLogging"] != true {
|
||||
t.Fatalf("fields = %#v", fields)
|
||||
}
|
||||
if _, err := os.Stat(wantPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("logging off ignores a bad path", func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "funknetz.json")
|
||||
logPath := filepath.Join(t.TempDir(), "funknetz.log")
|
||||
body := []byte(`{"host":"127.0.0.1","port":5308,"callsign":"DL1ABC","authKey":"key","talkGroup":20,"enableLogging":false,"logFile":1}`)
|
||||
if err := os.WriteFile(path, body, 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
before, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st, err := station.New(station.Options{ConfigPath: path})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(st.Close)
|
||||
if st.State().Detail != "Idle" {
|
||||
t.Fatalf("Detail = %q, want Idle", st.State().Detail)
|
||||
}
|
||||
after, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(after) != string(before) {
|
||||
t.Fatalf("file = %s, want it left untouched", after)
|
||||
}
|
||||
if _, err := os.Stat(logPath); !os.IsNotExist(err) {
|
||||
t.Fatalf("log file err = %v, want not exist", err)
|
||||
}
|
||||
})
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
body string
|
||||
detail string
|
||||
same bool
|
||||
}{
|
||||
{name: "relative", body: `{"host":"127.0.0.1","port":5308,"callsign":"DL1ABC","authKey":"key","talkGroup":20,"enableLogging":true,"logFile":"funknetz.log"}`, detail: "Cannot write funknetz.log", same: true},
|
||||
{name: "empty", body: `{"host":"127.0.0.1","port":5308,"callsign":"DL1ABC","authKey":"key","talkGroup":20,"enableLogging":true,"logFile":" "}`, detail: "Cannot write logFile", same: true},
|
||||
{name: "tilde", body: `{"host":"127.0.0.1","port":5308,"callsign":"DL1ABC","authKey":"key","talkGroup":20,"enableLogging":true,"logFile":"~/funknetz.log"}`, detail: "Cannot write ~/funknetz.log", same: true},
|
||||
{name: "enable type", body: `{"host":"127.0.0.1","port":5308,"callsign":"DL1ABC","authKey":"key","talkGroup":20,"enableLogging":"yes","logFile":"/tmp/funknetz.log"}`, detail: "enableLogging has the wrong type", same: true},
|
||||
{name: "file type", body: `{"host":"127.0.0.1","port":5308,"callsign":"DL1ABC","authKey":"key","talkGroup":20,"enableLogging":true,"logFile":1}`, detail: "logFile has the wrong type", same: true},
|
||||
{name: "both types", body: `{"host":"127.0.0.1","port":5308,"callsign":"DL1ABC","authKey":"key","talkGroup":20,"enableLogging":"yes","logFile":1}`, detail: "enableLogging has the wrong type", same: true},
|
||||
{name: "missing enable and bad file", body: `{"host":"127.0.0.1","port":5308,"callsign":"DL1ABC","authKey":"key","talkGroup":20,"logFile":1}`, detail: "Idle", same: true},
|
||||
}
|
||||
for _, tt := range cases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "funknetz.json")
|
||||
if err := os.WriteFile(path, []byte(tt.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)
|
||||
if st.State().Detail != tt.detail {
|
||||
t.Fatalf("Detail = %q, want %q", st.State().Detail, tt.detail)
|
||||
}
|
||||
if tt.same {
|
||||
after, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(after) != tt.body {
|
||||
t.Fatalf("file = %s, want it left untouched", after)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("bad host still quits", func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "funknetz.json")
|
||||
body := []byte(`{"host":"","port":5308,"callsign":"DL1ABC","authKey":"key","talkGroup":20,"enableLogging":"yes"}`)
|
||||
if err := os.WriteFile(path, body, 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err := station.New(station.Options{ConfigPath: path})
|
||||
if err == nil || err.Error() != "host is empty" {
|
||||
t.Fatalf("New() error = %v, want host is empty", err)
|
||||
}
|
||||
after, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(after) != string(body) {
|
||||
t.Fatalf("file = %s, want it left untouched", after)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func configJSON(host string, port int, callsign, authKey string, talkGroup int) string {
|
||||
body, err := jsonv2.Marshal(map[string]any{
|
||||
"host": host,
|
||||
@@ -176,3 +372,19 @@ func configJSON(host string, port int, callsign, authKey string, talkGroup int)
|
||||
}
|
||||
return string(body)
|
||||
}
|
||||
|
||||
func configWithLog(host string, port int, callsign, authKey string, talkGroup int, logPath string) string {
|
||||
body, err := jsonv2.Marshal(map[string]any{
|
||||
"host": host,
|
||||
"port": port,
|
||||
"callsign": callsign,
|
||||
"authKey": authKey,
|
||||
"talkGroup": talkGroup,
|
||||
"enableLogging": true,
|
||||
"logFile": logPath,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(body)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user