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:
MrFastwind
2026-07-23 21:07:49 +02:00
parent 1307bc4740
commit 04882b3c80
4 changed files with 365 additions and 5 deletions
+145
View File
@@ -3,6 +3,7 @@ package services
import (
"os"
"path/filepath"
"strings"
"testing"
"time"
)
@@ -185,3 +186,147 @@ func TestSteamCmdManager_SteampathEnv(t *testing.T) {
waitForNotRunning(t, sm, 30*time.Second)
}
func TestDownloadMods_StubCreatesModDirs(t *testing.T) {
dir := t.TempDir()
streamer := NewLogStreamer()
sm := NewSteamCmdManager(dir, streamer)
stubPath, _ := filepath.Abs("testdata/steamcmd")
t.Setenv("STEAMCMD_PATH", stubPath)
modID := "999999"
err := sm.DownloadMod(modID)
if err != nil {
t.Fatalf("DownloadMod error = %v", err)
}
waitForNotRunning(t, sm, 30*time.Second)
// Stub should have created the workshop mod directory
modDir := filepath.Join(dir, "steamapps", "workshop", "content", "107410", modID)
fi, err := os.Stat(modDir)
if err != nil {
t.Fatalf("mod directory should exist after stub download: %v", err)
}
if !fi.IsDir() {
t.Errorf("mod path %q should be a directory", modDir)
}
}
func TestDownloadMods_StubCreatesMultipleModDirs(t *testing.T) {
dir := t.TempDir()
streamer := NewLogStreamer()
sm := NewSteamCmdManager(dir, streamer)
stubPath, _ := filepath.Abs("testdata/steamcmd")
t.Setenv("STEAMCMD_PATH", stubPath)
mods := []string{"111111", "222222", "333333"}
err := sm.DownloadMods(mods)
if err != nil {
t.Fatalf("DownloadMods error = %v", err)
}
waitForNotRunning(t, sm, 30*time.Second)
for _, modID := range mods {
modDir := filepath.Join(dir, "steamapps", "workshop", "content", "107410", modID)
if _, err := os.Stat(modDir); os.IsNotExist(err) {
t.Errorf("mod directory for %s should exist", modID)
}
}
}
func TestDownloadMods_StubLogsAppear(t *testing.T) {
dir := t.TempDir()
streamer := NewLogStreamer()
sm := NewSteamCmdManager(dir, streamer)
stubPath, _ := filepath.Abs("testdata/steamcmd")
t.Setenv("STEAMCMD_PATH", stubPath)
ch := streamer.Subscribe("steamcmd", "test-dl-logs")
defer streamer.Unsubscribe("steamcmd", "test-dl-logs")
err := sm.DownloadMod("444444")
if err != nil {
t.Fatalf("DownloadMod error = %v", err)
}
// Read lines with generous timeout (stub may take a moment)
lines := readSteamcmdLines(ch, 20, 5*time.Second)
foundDownloading := false
foundSuccess := false
for _, line := range lines {
if strings.Contains(line, "Downloading") && strings.Contains(line, "444444") {
foundDownloading = true
}
if strings.Contains(line, "Success") {
foundSuccess = true
}
}
if !foundDownloading {
t.Errorf("expected 'Downloading 444444' log line, got %v", lines)
}
if !foundSuccess {
t.Errorf("expected 'Success' log line, got %v", lines)
}
}
func TestDownloadMods_StubSteamcmdArgsLogged(t *testing.T) {
dir := t.TempDir()
streamer := NewLogStreamer()
sm := NewSteamCmdManager(dir, streamer)
stubPath, _ := filepath.Abs("testdata/steamcmd")
t.Setenv("STEAMCMD_PATH", stubPath)
ch := streamer.Subscribe("steamcmd", "test-args-logs")
defer streamer.Unsubscribe("steamcmd", "test-args-logs")
err := sm.DownloadMod("555555")
if err != nil {
t.Fatalf("DownloadMod error = %v", err)
}
lines := readSteamcmdLines(ch, 20, 5*time.Second)
foundArgsLog := false
for _, line := range lines {
if strings.Contains(line, "[STUB]") && strings.Contains(line, "install_dir=") {
foundArgsLog = true
break
}
}
if !foundArgsLog {
t.Errorf("expected [STUB] install_dir= log line, got %v", lines)
}
}
// readSteamcmdLines reads lines from a steamcmd log channel
func readSteamcmdLines(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
}