// SPDX-License-Identifier: GPL-3.0-or-later // Copyright (C) 2021-2024 Simon Ruderich package frontend import ( "bytes" "fmt" "log" "os" "testing" "ruderich.org/simon/safcm" "ruderich.org/simon/safcm/rpc" "ruderich.org/simon/safcm/testutil" ) type TestHost struct { name string } func (th *TestHost) Name() string { return th.name } func (th *TestHost) Dial(*rpc.Conn) error { return fmt.Errorf("not implemented") } func TestLogEvent(t *testing.T) { // Restore default logger defer log.SetFlags(log.Flags()) defer log.SetOutput(os.Stderr) tests := []struct { name string event Event level safcm.LogLevel isTTY bool exp string expFailed bool }{ { "Error", Event{ Error: fmt.Errorf("fake error"), }, safcm.LogDebug3, false, "[error] [fake-host] fake error\n", true, }, { "Error (tty)", Event{ Error: fmt.Errorf("fake error"), }, safcm.LogDebug3, true, "[error] [\x1b[31mfake-host\x1b[0m] fake error\n", true, }, { "Error: escape", Event{ Error: fmt.Errorf("\x00"), }, safcm.LogDebug3, false, "[error] [fake-host] \\x00\n", true, }, { "Error: escape (tty)", Event{ Error: fmt.Errorf("\x00"), }, safcm.LogDebug3, true, "[error] [\x1b[31mfake-host\x1b[0m] \x1b[35m\\x00\x1b[0m\n", true, }, { "Log: info", Event{ Log: Log{ Level: safcm.LogInfo, Text: "info log", }, }, safcm.LogDebug3, false, "[info] [fake-host] info log\n", false, }, { "Log: info (tty)", Event{ Log: Log{ Level: safcm.LogInfo, Text: "info log", }, }, safcm.LogDebug3, true, "[info] [fake-host] info log\n", false, }, { "Log: verbose", Event{ Log: Log{ Level: safcm.LogVerbose, Text: "verbose log", }, }, safcm.LogDebug3, false, "[verbose] [fake-host] verbose log\n", false, }, { "Log: debug", Event{ Log: Log{ Level: safcm.LogDebug, Text: "debug log", }, }, safcm.LogDebug3, false, "[debug] [fake-host] debug log\n", false, }, { "Log: debug2", Event{ Log: Log{ Level: safcm.LogDebug2, Text: "debug2 log", }, }, safcm.LogDebug3, false, "[debug2] [fake-host] debug2 log\n", false, }, { "Log: debug3", Event{ Log: Log{ Level: safcm.LogDebug3, Text: "debug3 log", }, }, safcm.LogDebug3, false, fmt.Sprintf("[INVALID=%d] [fake-host] debug3 log\n", safcm.LogDebug3), false, }, { "Log: debug3 (tty)", Event{ Log: Log{ Level: safcm.LogDebug3, Text: "debug3 log", }, }, safcm.LogDebug3, true, fmt.Sprintf("[INVALID=%d] [\x1b[31mfake-host\x1b[0m] debug3 log\n", safcm.LogDebug3), false, }, { "Log: escape", Event{ Log: Log{ Level: safcm.LogInfo, Text: "\x00", }, }, safcm.LogDebug3, false, "[info] [fake-host] \\x00\n", false, }, { "Log: escape (tty)", Event{ Log: Log{ Level: safcm.LogInfo, Text: "\x00", }, }, safcm.LogDebug3, true, "[info] [fake-host] \x1b[35m\\x00\x1b[0m\n", false, }, { "ConnEvent: stderr", Event{ ConnEvent: rpc.ConnEvent{ Type: rpc.ConnEventStderr, Data: "fake stderr", }, }, safcm.LogDebug3, false, "[stderr] [fake-host] fake stderr\n", false, }, { "ConnEvent: stderr (tty)", Event{ ConnEvent: rpc.ConnEvent{ Type: rpc.ConnEventStderr, Data: "fake stderr", }, }, safcm.LogDebug3, true, "[stderr] [fake-host] fake stderr\n", false, }, { "ConnEvent: debug", Event{ ConnEvent: rpc.ConnEvent{ Type: rpc.ConnEventDebug, Data: "conn debug", }, }, safcm.LogDebug3, false, "[debug3] [fake-host] conn debug\n", false, }, { "ConnEvent: upload", Event{ ConnEvent: rpc.ConnEvent{ Type: rpc.ConnEventUpload, }, }, safcm.LogDebug3, false, "[info] [fake-host] remote helper upload in progress\n", false, }, { "ConnEvent: upload (ignored)", Event{ ConnEvent: rpc.ConnEvent{ Type: rpc.ConnEventUpload, }, }, safcm.LogError, false, "", false, }, { "ConnEvent: invalid", Event{ ConnEvent: rpc.ConnEvent{ Type: 42, Data: "invalid", }, }, safcm.LogError, false, "[INVALID=42] [fake-host] invalid\n", false, }, { "ConnEvent: invalid (tty)", Event{ ConnEvent: rpc.ConnEvent{ Type: 42, Data: "invalid", }, }, safcm.LogError, true, "[INVALID=42] [\x1b[31mfake-host\x1b[0m] invalid\n", false, }, { "ConnEvent: escape", Event{ ConnEvent: rpc.ConnEvent{ Type: rpc.ConnEventStderr, Data: "\x00", }, }, safcm.LogDebug3, false, "[stderr] [fake-host] \\x00\n", false, }, { "ConnEvent: escape (tty)", Event{ ConnEvent: rpc.ConnEvent{ Type: rpc.ConnEventDebug, Data: "\x01", }, }, safcm.LogDebug3, true, "[debug3] [fake-host] \x1b[35m\\x01\x1b[0m\n", false, }, { "Escaped", Event{ Log: Log{ Level: safcm.LogInfo, Text: "\x00", }, Escaped: true, }, safcm.LogDebug3, false, "[info] [fake-host] \x00\n", false, }, { "Escaped (tty)", Event{ Log: Log{ Level: safcm.LogInfo, Text: "\x00", }, Escaped: true, }, safcm.LogDebug3, true, "[info] [fake-host] \x00\n", false, }, { "empty (invalid)", Event{}, safcm.LogDebug3, false, "[INVALID=0] [fake-host] \n", false, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { tc.event.Host = &TestHost{ name: "fake-host", } var buf bytes.Buffer log.SetFlags(0) log.SetOutput(&buf) var failed bool LogEvent(tc.event, tc.level, tc.isTTY, &failed) testutil.AssertEqual(t, "log", buf.String(), tc.exp) testutil.AssertEqual(t, "failed", failed, tc.expFailed) }) } }