Metrics are served on METRICS_PORT (default 2112, "off" to disable), never on the public port. Besides the Go runtime and process metrics this adds: - http_requests_total and http_request_duration_seconds per route pattern, from an Echo middleware. - musicserver_songs_requested_total and musicserver_songs_played_total by pick mode (random, low, classic). The mode is now stored with each queued song (migration 000006, not released yet). - Library size, sync duration, last successful sync, broken songs from the last full sync, and the database connection pool. Refs #35, #36, #37 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
114 lines
3.6 KiB
Go
114 lines
3.6 KiB
Go
//go:build integration
|
|
|
|
package backend
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"music-server/internal/db/repository"
|
|
"music-server/internal/testutil/pgtest"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestQueueWithPostgres checks the queue queries against a real database.
|
|
func TestQueueWithPostgres(t *testing.T) {
|
|
ctx := context.Background()
|
|
database := pgtest.NewMigratedDatabase(t)
|
|
q := repository.New(database.Pool)
|
|
s := NewSyncService(q, copyTestMusic(t), nil)
|
|
require.True(t, s.Start(false))
|
|
s.Wait()
|
|
|
|
m := NewMusicService(q, t.TempDir())
|
|
queueID, err := m.ResolveQueue(ctx, "")
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, m.AddLatestToQueue(ctx, queueID), "nothing fetched yet")
|
|
var paths []string
|
|
for range 3 {
|
|
path, err := m.RandomSong(ctx, queueID)
|
|
require.NoError(t, err)
|
|
require.NoError(t, m.AddLatestToQueue(ctx, queueID))
|
|
paths = append(paths, path)
|
|
}
|
|
require.NoError(t, m.AddLatestToQueue(ctx, queueID), "a fetched song is only added once")
|
|
|
|
played, err := m.PlayedSongs(ctx, queueID)
|
|
require.NoError(t, err)
|
|
require.Len(t, played, 3)
|
|
for i, song := range played {
|
|
assert.Equal(t, i, song.SongNo)
|
|
assert.Equal(t, i == 2, song.CurrentlyPlaying, "the last added song is current")
|
|
assert.NotEmpty(t, song.Soundtrack)
|
|
assert.NotEqual(t, uuid.Nil, song.SoundtrackUuid)
|
|
}
|
|
|
|
var modes []string
|
|
rows, err := database.Pool.Query(ctx, "SELECT mode FROM queue_song WHERE queue_uuid = $1 ORDER BY song_no", queueID)
|
|
require.NoError(t, err)
|
|
for rows.Next() {
|
|
var mode string
|
|
require.NoError(t, rows.Scan(&mode))
|
|
modes = append(modes, mode)
|
|
}
|
|
require.NoError(t, rows.Err())
|
|
assert.Equal(t, []string{"random", "random", "random"}, modes)
|
|
|
|
_, err = m.RandomSongClassic(ctx, queueID)
|
|
require.NoError(t, err)
|
|
require.NoError(t, m.AddLatestToQueue(ctx, queueID))
|
|
var classic string
|
|
require.NoError(t, database.Pool.QueryRow(ctx, "SELECT mode FROM queue_song WHERE queue_uuid = $1 AND song_no = 3", queueID).Scan(&classic))
|
|
assert.Equal(t, "classic", classic)
|
|
played, err = m.PlayedSongs(ctx, queueID)
|
|
require.NoError(t, err)
|
|
require.Len(t, played, 4)
|
|
|
|
path, err := m.Song(ctx, queueID, 2)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, paths[2], path)
|
|
path, err = m.PreviousSong(ctx, queueID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, paths[1], path)
|
|
require.NoError(t, m.AddLatestPlayed(ctx, queueID))
|
|
info, err := m.SongInfo(ctx, queueID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, info.SongNo)
|
|
assert.Equal(t, int32(1), info.SongPlayed)
|
|
|
|
// A new service, as after a restart, sees the same queue.
|
|
restarted := NewMusicService(q, t.TempDir())
|
|
same, err := restarted.ResolveQueue(ctx, queueID.String())
|
|
require.NoError(t, err)
|
|
assert.Equal(t, queueID, same)
|
|
|
|
newID, err := m.NewQueue(ctx, queueID)
|
|
require.NoError(t, err)
|
|
assert.NotEqual(t, queueID, newID)
|
|
resolved, err := m.ResolveQueue(ctx, queueID.String())
|
|
require.NoError(t, err)
|
|
assert.NotEqual(t, queueID, resolved, "an ended queue is not used again")
|
|
|
|
other, err := m.ResolveQueue(ctx, "")
|
|
require.NoError(t, err)
|
|
require.NoError(t, m.EndAllQueues(ctx))
|
|
var active int
|
|
require.NoError(t, database.Pool.QueryRow(ctx, "SELECT COUNT(*) FROM queue WHERE ended_at IS NULL").Scan(&active))
|
|
assert.Zero(t, active)
|
|
_, err = m.ResolveQueue(ctx, other.String())
|
|
require.NoError(t, err)
|
|
|
|
// Ended queues keep their songs, also after the songs are removed from the library.
|
|
require.NoError(t, q.ClearSongs(ctx))
|
|
played, err = m.PlayedSongs(ctx, queueID)
|
|
require.NoError(t, err)
|
|
require.Len(t, played, 4)
|
|
assert.NotEmpty(t, played[0].Song)
|
|
_, err = m.Song(ctx, queueID, 0)
|
|
assert.ErrorIs(t, err, ErrNotFound)
|
|
}
|