diff --git a/internal/api/cast_token_test.go b/internal/api/cast_token_test.go index 0687b57d..526f50ed 100644 --- a/internal/api/cast_token_test.go +++ b/internal/api/cast_token_test.go @@ -10,15 +10,21 @@ import ( "time" ) -const testTrackUUID = "11111111-1111-1111-1111-111111111111" +// nonExistentTrackUUID is used by tests that exercise paths which don't +// require the track to actually exist (auth/UUID-shape rejection). +const nonExistentTrackUUID = "11111111-1111-1111-1111-111111111111" func TestCastStreamToken_HappyPath(t *testing.T) { h, pool := testHandlers(t) user := seedUser(t, pool, "alice", "hunter2", false) + artist := seedArtist(t, pool, "Artist") + album := seedAlbum(t, pool, artist.ID, "Album", 0) + track := seedTrack(t, pool, album.ID, artist.ID, "Song", 1, 180_000) + trackID := uuidToString(track.ID) h.streamSecret = []byte("cast-token-test-secret") body, err := json.Marshal(castTokenRequest{ - TrackID: testTrackUUID, + TrackID: trackID, ExpSeconds: 3600, }) if err != nil { @@ -44,10 +50,16 @@ func TestCastStreamToken_HappyPath(t *testing.T) { if !strings.Contains(resp.URL, "token="+resp.Token) { t.Fatalf("URL missing token query: %s", resp.URL) } - if !strings.Contains(resp.URL, "/api/tracks/"+testTrackUUID+"/stream") { + if !strings.Contains(resp.URL, "/api/tracks/"+trackID+"/stream") { t.Fatalf("URL missing stream path: %s", resp.URL) } - if !VerifyStreamToken(h.streamSecret, testTrackUUID, resp.Exp, resp.Token) { + // Stream URL must carry a file extension so Sonos's URL probe can + // identify the audio format (see task #610). Track seeded above is + // .flac via seedTrack's default file_format. + if !strings.Contains(resp.URL, "/stream.flac?") { + t.Fatalf("URL missing file-extension segment: %s", resp.URL) + } + if !VerifyStreamToken(h.streamSecret, trackID, resp.Exp, resp.Token) { t.Fatal("returned token does not verify") } } @@ -77,7 +89,7 @@ func TestCastStreamToken_RejectsUnauthenticated(t *testing.T) { h, _ := testHandlers(t) h.streamSecret = []byte("cast-token-test-secret") - body, err := json.Marshal(castTokenRequest{TrackID: testTrackUUID}) + body, err := json.Marshal(castTokenRequest{TrackID: nonExistentTrackUUID}) if err != nil { t.Fatalf("marshal: %v", err) } @@ -96,11 +108,15 @@ func TestCastStreamToken_RejectsUnauthenticated(t *testing.T) { func TestCastStreamToken_ClampsExpSeconds(t *testing.T) { h, pool := testHandlers(t) user := seedUser(t, pool, "alice", "hunter2", false) + artist := seedArtist(t, pool, "Artist") + album := seedAlbum(t, pool, artist.ID, "Album", 0) + track := seedTrack(t, pool, album.ID, artist.ID, "Song", 1, 180_000) + trackID := uuidToString(track.ID) h.streamSecret = []byte("cast-token-test-secret") // Request 1 second (below min 60), expect clamp to 60s. body, err := json.Marshal(castTokenRequest{ - TrackID: testTrackUUID, + TrackID: trackID, ExpSeconds: 1, }) if err != nil {