package server import ( "encoding/json" "net/http" "testing" "time" "music-server/internal/backend" "music-server/internal/db" "music-server/internal/db/repository" "github.com/labstack/echo/v5" "github.com/stretchr/testify/assert" ) // ensureSyncRan ensures that sync has been run before testing music endpoints func ensureSyncRan(t *testing.T, e *echo.Echo) { repo := repository.New(db.Dbpool) games, err := repo.FindAllGames(db.Ctx) assert.NoError(t, err) if len(games) == 0 { // Run sync t.Log("No games found, running sync first...") resp := MakeTestRequest(t, e, "GET", "/sync/full") assert.Equal(t, http.StatusOK, resp.Code) // Wait for sync to complete maxAttempts := 60 for i := 0; i < maxAttempts; i++ { progressResp := MakeTestRequest(t, e, "GET", "/sync/progress") var progress backend.ProgressResponse json.Unmarshal(progressResp.Body.Bytes(), &progress) if progress.Progress == "100" { break } if i == maxAttempts-1 { t.Error("Sync did not complete within timeout") } time.Sleep(1 * time.Second) } } } // TestGetAllGames verifies the /music/all/order endpoint func TestGetAllGames(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run ensureSyncRan(t, e) resp := MakeTestRequest(t, e, "GET", "/music/all/order") assert.Equal(t, http.StatusOK, resp.Code) var games []string err := json.Unmarshal(resp.Body.Bytes(), &games) assert.NoError(t, err) assert.NotEmpty(t, games, "Should have games after sync") t.Logf("Found %d games", len(games)) } // TestGetAllGamesRandom verifies the /music/all/random endpoint func TestGetAllGamesRandom(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run ensureSyncRan(t, e) resp := MakeTestRequest(t, e, "GET", "/music/all/random") assert.Equal(t, http.StatusOK, resp.Code) var games []string err := json.Unmarshal(resp.Body.Bytes(), &games) assert.NoError(t, err) assert.NotEmpty(t, games, "Should have games after sync") // Verify it's shuffled (not in original order) // We can't easily verify randomness, but we can check it's the same length resp2 := MakeTestRequest(t, e, "GET", "/music/all/order") var gamesOrdered []string json.Unmarshal(resp2.Body.Bytes(), &gamesOrdered) assert.Equal(t, len(games), len(gamesOrdered), "Random and ordered should have same count") } // TestGetRandomSong verifies the /music/rand endpoint func TestGetRandomSong(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run ensureSyncRan(t, e) resp := MakeTestRequest(t, e, "GET", "/music/rand") assert.Equal(t, http.StatusOK, resp.Code) var songPath string err := json.Unmarshal(resp.Body.Bytes(), &songPath) assert.NoError(t, err) assert.NotEmpty(t, songPath, "Should return a song path") assert.Contains(t, songPath, "testMusic/", "Path should be in testMusic directory") t.Logf("Random song: %s", songPath) } // TestGetRandomSongLowChance verifies the /music/rand/low endpoint func TestGetRandomSongLowChance(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run ensureSyncRan(t, e) resp := MakeTestRequest(t, e, "GET", "/music/rand/low") assert.Equal(t, http.StatusOK, resp.Code) var songPath string err := json.Unmarshal(resp.Body.Bytes(), &songPath) assert.NoError(t, err) assert.NotEmpty(t, songPath, "Should return a song path") } // TestGetRandomSongClassic verifies the /music/rand/classic endpoint func TestGetRandomSongClassic(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run ensureSyncRan(t, e) resp := MakeTestRequest(t, e, "GET", "/music/rand/classic") assert.Equal(t, http.StatusOK, resp.Code) var songPath string err := json.Unmarshal(resp.Body.Bytes(), &songPath) assert.NoError(t, err) assert.NotEmpty(t, songPath, "Should return a song path") } // TestGetSongInfo verifies the /music/info endpoint func TestGetSongInfo(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run and get a song first ensureSyncRan(t, e) MakeTestRequest(t, e, "GET", "/music/rand") resp := MakeTestRequest(t, e, "GET", "/music/info") assert.Equal(t, http.StatusOK, resp.Code) var info backend.SongInfo err := json.Unmarshal(resp.Body.Bytes(), &info) assert.NoError(t, err) assert.True(t, info.CurrentlyPlaying, "Should have a currently playing song") assert.NotEmpty(t, info.Song, "Should have song name") t.Logf("Song info: Game=%s, Song=%s", info.Game, info.Song) } // TestGetPlayedSongs verifies the /music/list endpoint func TestGetPlayedSongs(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run and add some songs to queue ensureSyncRan(t, e) MakeTestRequest(t, e, "GET", "/music/rand") MakeTestRequest(t, e, "GET", "/music/addQue") MakeTestRequest(t, e, "GET", "/music/rand") MakeTestRequest(t, e, "GET", "/music/addQue") resp := MakeTestRequest(t, e, "GET", "/music/list") assert.Equal(t, http.StatusOK, resp.Code) var songs []backend.SongInfo err := json.Unmarshal(resp.Body.Bytes(), &songs) assert.NoError(t, err) assert.NotEmpty(t, songs, "Should have played songs in queue") t.Logf("Found %d songs in queue", len(songs)) } // TestGetNextSong verifies the /music/next endpoint func TestGetNextSong(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run and add songs to queue ensureSyncRan(t, e) MakeTestRequest(t, e, "GET", "/music/rand") MakeTestRequest(t, e, "GET", "/music/addQue") MakeTestRequest(t, e, "GET", "/music/rand") MakeTestRequest(t, e, "GET", "/music/addQue") resp := MakeTestRequest(t, e, "GET", "/music/next") assert.Equal(t, http.StatusOK, resp.Code) var songPath string err := json.Unmarshal(resp.Body.Bytes(), &songPath) assert.NoError(t, err) assert.NotEmpty(t, songPath, "Should return a song path") } // TestGetPreviousSong verifies the /music/previous endpoint func TestGetPreviousSong(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run and add songs to queue ensureSyncRan(t, e) MakeTestRequest(t, e, "GET", "/music/rand") MakeTestRequest(t, e, "GET", "/music/addQue") MakeTestRequest(t, e, "GET", "/music/rand") MakeTestRequest(t, e, "GET", "/music/addQue") // Move forward MakeTestRequest(t, e, "GET", "/music/next") resp := MakeTestRequest(t, e, "GET", "/music/previous") assert.Equal(t, http.StatusOK, resp.Code) var songPath string err := json.Unmarshal(resp.Body.Bytes(), &songPath) assert.NoError(t, err) assert.NotEmpty(t, songPath, "Should return a song path") } // TestResetMusic verifies the /music/reset endpoint func TestResetMusic(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run and add songs to queue ensureSyncRan(t, e) MakeTestRequest(t, e, "GET", "/music/rand") MakeTestRequest(t, e, "GET", "/music/addQue") // Verify queue has items respBefore := MakeTestRequest(t, e, "GET", "/music/list") var songsBefore []backend.SongInfo json.Unmarshal(respBefore.Body.Bytes(), &songsBefore) assert.True(t, len(songsBefore) > 0, "Should have songs before reset") // Reset queue resp := MakeTestRequest(t, e, "GET", "/music/reset") assert.Equal(t, http.StatusOK, resp.Code) // Verify queue is empty respAfter := MakeTestRequest(t, e, "GET", "/music/list") var songsAfter []backend.SongInfo json.Unmarshal(respAfter.Body.Bytes(), &songsAfter) assert.Equal(t, 0, len(songsAfter), "Queue should be empty after reset") } // TestAddLatestToQue verifies the /music/addQue endpoint func TestAddLatestToQue(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run ensureSyncRan(t, e) // Get a random song (this sets lastFetchedNew) MakeTestRequest(t, e, "GET", "/music/rand") // Add to queue resp := MakeTestRequest(t, e, "GET", "/music/addQue") assert.Equal(t, http.StatusOK, resp.Code) // Verify it was added to queue respList := MakeTestRequest(t, e, "GET", "/music/list") var songs []backend.SongInfo json.Unmarshal(respList.Body.Bytes(), &songs) assert.True(t, len(songs) > 0, "Song should be in queue") } // TestAddLatestPlayed verifies the /music/addPlayed endpoint func TestAddLatestPlayed(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run and add song to queue ensureSyncRan(t, e) MakeTestRequest(t, e, "GET", "/music/rand") MakeTestRequest(t, e, "GET", "/music/addQue") // Mark as played resp := MakeTestRequest(t, e, "GET", "/music/addPlayed") assert.Equal(t, http.StatusOK, resp.Code) } // TestPutPlayed verifies the PUT /music/played endpoint func TestPutPlayed(t *testing.T) { db.TestSetupDB(t) defer db.TestTearDownDB(t) e := StartTestServer(t) // Ensure sync has run and add songs to queue ensureSyncRan(t, e) MakeTestRequest(t, e, "GET", "/music/rand") MakeTestRequest(t, e, "GET", "/music/addQue") // Mark song 0 as played resp := MakeTestRequestWithBody(t, e, "PUT", "/music/played?song=0", nil) assert.Equal(t, http.StatusOK, resp.Code) }