test(backend): enhance stubs with logging, heartbeat, timed exit, and fake downloads
arma3server_x64 stub: - Logs binary path and all arguments ([STUB] binary=... args=...) - Prints heartbeat every 5 seconds - Accepts -t N flag to exit after N seconds (for auto-exit tests) steamcmd stub: - Parses +force_install_dir and +workshop_download_item args - Creates fake mod directories at the expected workshop content path - Prints fake download progress and success logs New tests: - TestStart_StubLogsArgsAndPath: verifies arg logging via log streamer - TestStart_StubLogsBinaryPath: verifies binary path logging - TestStart_StubHeartbeatLogs: verifies heartbeat lines appear within timeout - TestStart_StubAutoExit: verifies -t flag causes server to auto-exit - TestDownloadMods_StubCreatesModDirs: verifies single mod dir creation - TestDownloadMods_StubCreatesMultipleModDirs: verifies multi-mod dir creation - TestDownloadMods_StubLogsAppear: verifies fake download logs on channel - TestDownloadMods_StubSteamcmdArgsLogged: verifies install_dir logging
This commit is contained in:
@@ -610,3 +610,166 @@ func TestServerParamsEnvOverridesSettings(t *testing.T) {
|
||||
pm.Stop()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
// helper: sets up a ProcessManager with the stub and optional server params
|
||||
func setupStubPM(t *testing.T, serverParams string) (*ProcessManager, *LogStreamer) {
|
||||
t.Helper()
|
||||
dir := t.TempDir()
|
||||
serverfileDir := filepath.Join(dir, "server")
|
||||
os.MkdirAll(serverfileDir, 0755)
|
||||
|
||||
stubSrc, _ := os.ReadFile("testdata/arma3server_x64")
|
||||
os.WriteFile(filepath.Join(serverfileDir, "arma3server_x64"), stubSrc, 0755)
|
||||
|
||||
sm := NewSettingsManager(dir)
|
||||
mm := NewModlistManager(filepath.Join(dir, "modlists"))
|
||||
cm := NewConfigManager(filepath.Join(dir, "cfg"))
|
||||
streamer := NewLogStreamer()
|
||||
|
||||
pm := NewProcessManager(serverfileDir, filepath.Join(dir, "mods"), filepath.Join(dir, "cfg"), filepath.Join(dir, "profiles"), sm, mm, cm, streamer)
|
||||
|
||||
if serverParams != "" {
|
||||
s, _ := sm.Load()
|
||||
s.ServerParameters = serverParams
|
||||
sm.Save(s)
|
||||
}
|
||||
|
||||
return pm, streamer
|
||||
}
|
||||
|
||||
// readLines reads up to n lines from ch within timeout
|
||||
func readLines(ch chan string, n int, timeout time.Duration) []string {
|
||||
var lines []string
|
||||
deadline := time.Now().Add(timeout)
|
||||
for len(lines) < n {
|
||||
remaining := time.Until(deadline)
|
||||
if remaining <= 0 {
|
||||
break
|
||||
}
|
||||
select {
|
||||
case line, ok := <-ch:
|
||||
if !ok {
|
||||
return lines
|
||||
}
|
||||
lines = append(lines, line)
|
||||
case <-time.After(remaining):
|
||||
return lines
|
||||
}
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
func containsAny(s string, substrs ...string) bool {
|
||||
for _, sub := range substrs {
|
||||
if strings.Contains(s, sub) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestStart_StubLogsArgsAndPath(t *testing.T) {
|
||||
pm, streamer := setupStubPM(t, "-server -port=2402")
|
||||
ch := streamer.Subscribe("server", "test-args")
|
||||
defer streamer.Unsubscribe("server", "test-args")
|
||||
|
||||
if err := pm.Start(); err != nil {
|
||||
t.Fatalf("Start() error = %v", err)
|
||||
}
|
||||
|
||||
lines := readLines(ch, 10, 3*time.Second)
|
||||
|
||||
foundArgsLog := false
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "[STUB]") && strings.Contains(line, "args=") {
|
||||
foundArgsLog = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundArgsLog {
|
||||
t.Errorf("expected [STUB] args= log line, got %v", lines)
|
||||
}
|
||||
|
||||
pm.Stop()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
func TestStart_StubLogsBinaryPath(t *testing.T) {
|
||||
pm, streamer := setupStubPM(t, "-server -world=empty")
|
||||
ch := streamer.Subscribe("server", "test-path")
|
||||
defer streamer.Unsubscribe("server", "test-path")
|
||||
|
||||
if err := pm.Start(); err != nil {
|
||||
t.Fatalf("Start() error = %v", err)
|
||||
}
|
||||
|
||||
lines := readLines(ch, 10, 3*time.Second)
|
||||
|
||||
foundBinaryLog := false
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "[STUB]") && strings.Contains(line, "binary=") {
|
||||
foundBinaryLog = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundBinaryLog {
|
||||
t.Errorf("expected [STUB] binary= log line, got %v", lines)
|
||||
}
|
||||
|
||||
pm.Stop()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
func TestStart_StubHeartbeatLogs(t *testing.T) {
|
||||
pm, streamer := setupStubPM(t, "-t 12")
|
||||
ch := streamer.Subscribe("server", "test-heartbeat")
|
||||
defer streamer.Unsubscribe("server", "test-heartbeat")
|
||||
|
||||
if err := pm.Start(); err != nil {
|
||||
t.Fatalf("Start() error = %v", err)
|
||||
}
|
||||
|
||||
// Collect lines for up to 10s, looking for a heartbeat
|
||||
lines := readLines(ch, 50, 10*time.Second)
|
||||
|
||||
foundHeartbeat := false
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "[STUB]") && strings.Contains(line, "heartbeat") {
|
||||
foundHeartbeat = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundHeartbeat {
|
||||
t.Errorf("expected [STUB] heartbeat log line within 10s, got %v", lines)
|
||||
}
|
||||
|
||||
pm.Stop()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
func TestStart_StubAutoExit(t *testing.T) {
|
||||
pm, streamer := setupStubPM(t, "-t 2")
|
||||
streamer.Subscribe("server", "test-autoexit")
|
||||
defer streamer.Unsubscribe("server", "test-autoexit")
|
||||
|
||||
if err := pm.Start(); err != nil {
|
||||
t.Fatalf("Start() error = %v", err)
|
||||
}
|
||||
|
||||
if !pm.IsRunning() {
|
||||
t.Fatal("IsRunning() should be true immediately after Start()")
|
||||
}
|
||||
|
||||
// Wait for stub to exit (2s + margin)
|
||||
deadline := time.Now().Add(5 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
if !pm.IsRunning() {
|
||||
break
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
|
||||
if pm.IsRunning() {
|
||||
t.Error("IsRunning() should be false after stub auto-exited (timeout 2s)")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user