98c1948eff
- Add Database struct in internal/db/database.go with Pool, Ctx, and RunMigrations() - Update server.go to use Database struct with NewServerInstance() - Add backend.go with InitBackend(), BackendRepo(), BackendCtx(), BackendPool() - Update music.go and sync.go to use BackendRepo() and BackendCtx() instead of db.Dbpool/db.Ctx - Update token_handler.go to accept pool parameter - Update routes.go to use s.db.Pool for middleware - Update cmd/main.go to use NewServerInstance() and HTTPServer() - Update test_helpers.go to initialize backend with test database - Update test files to use backend.BackendPool() and backend.BackendCtx() Benefits: - Easier to mock database for unit tests - Follows Go best practices (dependency injection) - Better architecture with explicit dependencies - RunMigrations() replaces old Migrate_db() function Note: Global db.Dbpool and db.Ctx still exist in dbHelper.go for backward compatibility with test_helpers.go, but production code no longer uses them. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
313 lines
8.9 KiB
Go
313 lines
8.9 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"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(backend.BackendPool())
|
|
games, err := repo.FindAllGames(backend.BackendCtx())
|
|
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 using shared helper
|
|
if !waitForSyncCompletion(t, e, 60) {
|
|
t.Error("Sync did not complete within timeout")
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestGetAllGames verifies the /music/all/order endpoint
|
|
func TestZGetAllGames(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 TestZGetAllGamesRandom(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 TestZGetRandomSong(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)
|
|
|
|
// The endpoint returns a file stream, not JSON
|
|
// Just verify we got a response with content
|
|
assert.NotEmpty(t, resp.Body.Bytes(), "Should return song file content")
|
|
t.Logf("Random song returned %d bytes", len(resp.Body.Bytes()))
|
|
}
|
|
|
|
// TestGetRandomSongLowChance verifies the /music/rand/low endpoint
|
|
func TestZGetRandomSongLowChance(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)
|
|
|
|
// The endpoint returns a file stream, not JSON
|
|
assert.NotEmpty(t, resp.Body.Bytes(), "Should return song file content")
|
|
}
|
|
|
|
// TestGetRandomSongClassic verifies the /music/rand/classic endpoint
|
|
func TestZGetRandomSongClassic(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)
|
|
|
|
// The endpoint returns a file stream, not JSON
|
|
assert.NotEmpty(t, resp.Body.Bytes(), "Should return song file content")
|
|
}
|
|
|
|
// TestGetSongInfo verifies the /music/info endpoint
|
|
func TestZGetSongInfo(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")
|
|
// Add to queue and mark as played
|
|
MakeTestRequest(t, e, "GET", "/music/addQue")
|
|
MakeTestRequest(t, e, "GET", "/music/addPlayed")
|
|
|
|
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)
|
|
// Note: CurrentlyPlaying might be false if no song is currently set
|
|
// Just verify we got a valid response
|
|
t.Logf("Song info: Game=%s, Song=%s", info.Game, info.Song)
|
|
}
|
|
|
|
// TestGetPlayedSongs verifies the /music/list endpoint
|
|
func TestZGetPlayedSongs(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 TestZGetNextSong(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)
|
|
|
|
// The endpoint returns a file stream, not JSON
|
|
assert.NotEmpty(t, resp.Body.Bytes(), "Should return song file content")
|
|
}
|
|
|
|
// TestGetPreviousSong verifies the /music/previous endpoint
|
|
func TestZGetPreviousSong(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)
|
|
|
|
// The endpoint returns a file stream, not JSON
|
|
assert.NotEmpty(t, resp.Body.Bytes(), "Should return song file content")
|
|
}
|
|
|
|
// TestResetMusic verifies the /music/reset endpoint
|
|
func TestZResetMusic(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 TestZAddLatestToQue(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 TestZAddLatestPlayed(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 TestZPutPlayed(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)
|
|
}
|