package services import ( "os" "path/filepath" "testing" "time" ) func TestCheckWorkshopMod(t *testing.T) { dir := t.TempDir() // Existing workshop mod modDir := filepath.Join(dir, "steamapps", "workshop", "content", "107410", "123456") os.MkdirAll(modDir, 0755) if !CheckWorkshopMod(dir, "123456") { t.Error("CheckWorkshopMod should return true for existing mod") } // Non-existing mod if CheckWorkshopMod(dir, "999999") { t.Error("CheckWorkshopMod should return false for non-existing mod") } // Empty mod ID if CheckWorkshopMod(dir, "") { t.Error("CheckWorkshopMod should return false for empty mod ID") } } func TestCheckWorkshopMod_IsFile(t *testing.T) { dir := t.TempDir() // Create a file instead of directory at the expected path workshopDir := filepath.Join(dir, "steamapps", "workshop", "content", "107410") os.MkdirAll(workshopDir, 0755) os.WriteFile(filepath.Join(workshopDir, "111111"), []byte("not a dir"), 0644) if CheckWorkshopMod(dir, "111111") { t.Error("CheckWorkshopMod should return false for file (not directory)") } } func TestSteamCmdManager_IsRunning(t *testing.T) { dir := t.TempDir() streamer := NewLogStreamer() sm := NewSteamCmdManager(dir, streamer) if sm.IsRunning() { t.Error("IsRunning() should be false initially") } } func TestSteamCmdManager_DoubleStart(t *testing.T) { dir := t.TempDir() streamer := NewLogStreamer() sm := NewSteamCmdManager(dir, streamer) // First DownloadMods sets running=true. If the binary exists, the goroutine // handles cleanup. If it doesn't, running is reset synchronously. sm.DownloadMods([]string{"123456"}) // Second call while running should get "already running" err2 := sm.DownloadMods([]string{"789012"}) if err2 == nil || err2.Error() != "steamcmd already running" { t.Logf("second DownloadMods: %v (may vary based on timing)", err2) } waitForNotRunning(t, sm, 30*time.Second) } func waitForNotRunning(t *testing.T, sm *SteamCmdManager, timeout time.Duration) { t.Helper() deadline := time.Now().Add(timeout) for time.Now().Before(deadline) { if !sm.IsRunning() { return } time.Sleep(20 * time.Millisecond) } t.Errorf("IsRunning() still true after %v", timeout) } func TestSteamCmdManager_StopResetsFlag(t *testing.T) { dir := t.TempDir() streamer := NewLogStreamer() sm := NewSteamCmdManager(dir, streamer) // After run completes (success or failure), running flag should be reset sm.DownloadMods([]string{"123"}) waitForNotRunning(t, sm, 30*time.Second) } func TestSteamCmdManager_UpdateGameArgs(t *testing.T) { dir := t.TempDir() streamer := NewLogStreamer() sm := NewSteamCmdManager(dir, streamer) err := sm.UpdateGame("stable", "anonymous") if err != nil { t.Logf("UpdateGame returned (expected): %v", err) } waitForNotRunning(t, sm, 30*time.Second) } func TestSteamCmdManager_UpdateGameBeta(t *testing.T) { dir := t.TempDir() streamer := NewLogStreamer() sm := NewSteamCmdManager(dir, streamer) // Test with a beta branch err := sm.UpdateGame("creatordlc", "anonymous") if err != nil { t.Logf("UpdateGame(creatordlc) returned (expected): %v", err) } waitForNotRunning(t, sm, 30*time.Second) } func TestSteamCmdManager_DownloadModEmpty(t *testing.T) { dir := t.TempDir() streamer := NewLogStreamer() sm := NewSteamCmdManager(dir, streamer) err := sm.DownloadMods([]string{}) if err == nil { t.Error("DownloadMods with empty list should return error") } } func TestSteamCmdManager_DownloadModSingle(t *testing.T) { dir := t.TempDir() streamer := NewLogStreamer() sm := NewSteamCmdManager(dir, streamer) err := sm.DownloadMod("123456") // steamcmd may or may not exist; either way the call should complete if err != nil { t.Logf("DownloadMod returned (expected): %v", err) } waitForNotRunning(t, sm, 30*time.Second) } func TestNewSteamCmdManager(t *testing.T) { dir := t.TempDir() streamer := NewLogStreamer() sm := NewSteamCmdManager(dir, streamer) if sm.serverfileDir != dir { t.Errorf("serverfileDir = %q, want %q", sm.serverfileDir, dir) } if sm.streamer != streamer { t.Error("streamer should be set") } if sm.IsRunning() { t.Error("new manager should not be running") } }