File
Blob: worker/src/server/publisher-metadata.test.ts
| 1 | import assert from 'node:assert/strict'; |
| 2 | import { test } from 'node:test'; |
| 3 | import { checkStartupMetadata, heartbeatMetadata, startupMetadata } from './publisher-metadata.ts'; |
| 4 | import type { Publisher } from './room-state.ts'; |
| 5 | |
| 6 | const track = { title: 'First', artist: '', durationMs: 2000 }; |
| 7 | const nowPlaying = { revision: 0, trackIndex: 0, trackCount: 2, track }; |
| 8 | const offer = { type: 'offer' as const, sdp: 'v=0' }; |
| 9 | const publisher: Publisher = { |
| 10 | sessionId: 'test', |
| 11 | generation: 'test', |
| 12 | ready: true, |
| 13 | seen: 0, |
| 14 | channels: [], |
| 15 | track, |
| 16 | nowPlaying, |
| 17 | initialNowPlaying: nowPlaying, |
| 18 | }; |
| 19 | |
| 20 | test('startup normalization supports legacy, playlist-only and agreeing dual metadata', () => { |
| 21 | for (const fields of [{ nowPlaying }, { nowPlaying, track }]) { |
| 22 | const normalized = startupMetadata({ sessionDescription: offer, ...fields }); |
| 23 | checkStartupMetadata(publisher, normalized); |
| 24 | assert.equal(normalized.track, track); |
| 25 | } |
| 26 | const legacy = { ...publisher, nowPlaying: undefined, initialNowPlaying: undefined }; |
| 27 | checkStartupMetadata(legacy, startupMetadata({ sessionDescription: offer, track })); |
| 28 | assert.throws(() => startupMetadata({ sessionDescription: offer, nowPlaying, track: null })); |
| 29 | assert.throws(() => |
| 30 | startupMetadata({ sessionDescription: offer, nowPlaying, track: { ...track, title: 'Other' } }), |
| 31 | ); |
| 32 | assert.equal( |
| 33 | startupMetadata({ sessionDescription: offer, nowPlaying: { ...nowPlaying, track: null } }) |
| 34 | .track, |
| 35 | undefined, |
| 36 | ); |
| 37 | }); |
| 38 | |
| 39 | test('heartbeat accepts wrapping revisions but rejects conflicts and playlist resizing', () => { |
| 40 | const wrapped = { ...nowPlaying, revision: 0xffff_ffff }; |
| 41 | assert.equal(heartbeatMetadata(wrapped, nowPlaying), nowPlaying); |
| 42 | assert.equal(heartbeatMetadata(nowPlaying, wrapped), nowPlaying); |
| 43 | assert.throws(() => heartbeatMetadata(nowPlaying, { ...nowPlaying, trackIndex: 1 })); |
| 44 | assert.throws(() => heartbeatMetadata(nowPlaying, { ...nowPlaying, revision: 1, trackCount: 3 })); |
| 45 | const playing = { |
| 46 | ...publisher, |
| 47 | track: { ...track, title: 'Second' }, |
| 48 | nowPlaying: { ...nowPlaying, revision: 1 }, |
| 49 | }; |
| 50 | checkStartupMetadata(playing, startupMetadata({ sessionDescription: offer, nowPlaying })); |
| 51 | }); |