|
1 | 1 | import { JSONBlobStringify, PieceLifespan, StatusCode } from '@sofie-automation/blueprints-integration' |
2 | 2 | import { AdLibPiece } from '@sofie-automation/corelib/dist/dataModel/AdLibPiece' |
3 | | -import { PartInstanceId, RundownId, RundownPlaylistId } from '@sofie-automation/corelib/dist/dataModel/Ids' |
| 3 | +import { |
| 4 | + PartInstanceId, |
| 5 | + PeripheralDeviceId, |
| 6 | + RundownId, |
| 7 | + RundownPlaylistId, |
| 8 | +} from '@sofie-automation/corelib/dist/dataModel/Ids' |
4 | 9 | import { DBPart } from '@sofie-automation/corelib/dist/dataModel/Part' |
5 | 10 | import { DBPartInstance } from '@sofie-automation/corelib/dist/dataModel/PartInstance' |
6 | 11 | import { |
@@ -29,6 +34,12 @@ import { ProcessedShowStyleCompound } from '../../../../jobs/index.js' |
29 | 34 | import { runWithPlaylistLock } from '../../../../playout/lock.js' |
30 | 35 | import { PlayoutModelImpl } from '../PlayoutModelImpl.js' |
31 | 36 | import { PlayoutRundownModelImpl } from '../PlayoutRundownModelImpl.js' |
| 37 | +import { PlayoutSegmentModelImpl } from '../PlayoutSegmentModelImpl.js' |
| 38 | +import _ from 'underscore' |
| 39 | + |
| 40 | +const TIME_FAR_PAST = 1000 |
| 41 | +const TIME_CONNECTED = 2000 |
| 42 | +const TIME_PING = 3000 |
32 | 43 |
|
33 | 44 | describe('PlayoutModelImpl', () => { |
34 | 45 | let context: MockJobContext |
@@ -60,71 +71,67 @@ describe('PlayoutModelImpl', () => { |
60 | 71 | ) |
61 | 72 |
|
62 | 73 | it('returns the current time', async () => { |
63 | | - const { playlistId: playlistId0 } = await setupRundownWithAutoplayPart0( |
| 74 | + const { playlistId: playlistId0, rundownId: rundownId0 } = await setupRundownWithAutoplayPart0( |
64 | 75 | context, |
65 | 76 | protectString('rundown00'), |
66 | 77 | showStyleCompound |
67 | 78 | ) |
68 | 79 |
|
69 | 80 | const playlist = await context.mockCollections.RundownPlaylists.findOne(playlistId0) |
70 | 81 |
|
71 | | - const TIME_FAR_PAST = 1000 |
72 | | - const TIME_CONNECTED = 2000 |
73 | | - const TIME_PING = 3000 |
| 82 | + const TIME_NOW = 5000 |
| 83 | + |
| 84 | + const peripheralDevices = [setupMockPlayoutGateway(protectString('playoutGateway0'))] |
| 85 | + |
| 86 | + const { partInstances, groupedPieceInstances, rundowns } = await getPlayoutModelImplArugments( |
| 87 | + context, |
| 88 | + playlistId0, |
| 89 | + rundownId0 |
| 90 | + ) |
| 91 | + |
| 92 | + if (!playlist) throw new Error('Playlist not found!') |
| 93 | + |
| 94 | + jest.setSystemTime(TIME_NOW) |
| 95 | + |
| 96 | + await runWithPlaylistLock(context, playlistId0, async (lock) => { |
| 97 | + const model = new PlayoutModelImpl( |
| 98 | + context, |
| 99 | + lock, |
| 100 | + playlistId0, |
| 101 | + peripheralDevices, |
| 102 | + playlist, |
| 103 | + partInstances, |
| 104 | + groupedPieceInstances, |
| 105 | + rundowns, |
| 106 | + undefined |
| 107 | + ) |
| 108 | + |
| 109 | + const now = model.getNowInPlayout() |
| 110 | + expect(now).toBeGreaterThanOrEqual(TIME_NOW) |
| 111 | + expect(now - TIME_NOW).toBeLessThan(100) |
| 112 | + }) |
| 113 | + }) |
74 | 114 |
|
| 115 | + it('never returns a smaller value', async () => { |
| 116 | + const { playlistId: playlistId0, rundownId: rundownId0 } = await setupRundownWithAutoplayPart0( |
| 117 | + context, |
| 118 | + protectString('rundown00'), |
| 119 | + showStyleCompound |
| 120 | + ) |
| 121 | + |
| 122 | + const playlist = await context.mockCollections.RundownPlaylists.findOne(playlistId0) |
75 | 123 | const TIME_NOW = 5000 |
76 | 124 |
|
77 | | - const peripheralDevices: PeripheralDevice[] = [ |
78 | | - { |
79 | | - _id: protectString('playoutGateway0'), |
80 | | - category: PeripheralDeviceCategory.PLAYOUT, |
81 | | - type: PeripheralDeviceType.PLAYOUT, |
82 | | - subType: '', |
83 | | - connected: true, |
84 | | - configManifest: { |
85 | | - deviceConfigSchema: JSONBlobStringify({}), |
86 | | - subdeviceManifest: {}, |
87 | | - }, |
88 | | - connectionId: 'connectionId0', |
89 | | - created: TIME_FAR_PAST, |
90 | | - deviceName: 'Dummy Playout Gateway 1', |
91 | | - lastConnected: TIME_CONNECTED, |
92 | | - lastSeen: TIME_PING, |
93 | | - name: 'Dummy Playout Gateway 1', |
94 | | - organizationId: null, |
95 | | - status: { |
96 | | - statusCode: StatusCode.GOOD, |
97 | | - messages: [], |
98 | | - }, |
99 | | - token: '', |
100 | | - }, |
101 | | - { |
102 | | - _id: protectString('playoutGateway1'), |
103 | | - category: PeripheralDeviceCategory.PLAYOUT, |
104 | | - type: PeripheralDeviceType.PLAYOUT, |
105 | | - subType: '', |
106 | | - connected: true, |
107 | | - configManifest: { |
108 | | - deviceConfigSchema: JSONBlobStringify({}), |
109 | | - subdeviceManifest: {}, |
110 | | - }, |
111 | | - connectionId: 'connectionId1', |
112 | | - created: TIME_FAR_PAST, |
113 | | - deviceName: 'Dummy Playout Gateway 2', |
114 | | - lastConnected: TIME_CONNECTED, |
115 | | - lastSeen: TIME_PING, |
116 | | - name: 'Dummy Playout Gateway 2', |
117 | | - organizationId: null, |
118 | | - status: { |
119 | | - statusCode: StatusCode.GOOD, |
120 | | - messages: [], |
121 | | - }, |
122 | | - token: '', |
123 | | - }, |
| 125 | + const peripheralDevices = [ |
| 126 | + setupMockPlayoutGateway(protectString('playoutGateway0')), |
| 127 | + setupMockPlayoutGateway(protectString('playoutGateway1')), |
124 | 128 | ] |
125 | | - const partInstances: DBPartInstance[] = [] |
126 | | - const groupedPieceInstances: Map<PartInstanceId, PieceInstance[]> = new Map() |
127 | | - const rundowns: PlayoutRundownModelImpl[] = [] |
| 129 | + |
| 130 | + const { partInstances, groupedPieceInstances, rundowns } = await getPlayoutModelImplArugments( |
| 131 | + context, |
| 132 | + playlistId0, |
| 133 | + rundownId0 |
| 134 | + ) |
128 | 135 |
|
129 | 136 | if (!playlist) throw new Error('Playlist not found!') |
130 | 137 |
|
@@ -174,6 +181,77 @@ describe('PlayoutModelImpl', () => { |
174 | 181 | }) |
175 | 182 | }) |
176 | 183 |
|
| 184 | +async function getPlayoutModelImplArugments( |
| 185 | + context: MockJobContext, |
| 186 | + playlistId: RundownPlaylistId, |
| 187 | + rundownId: RundownId |
| 188 | +) { |
| 189 | + const partInstances = await context.mockCollections.PartInstances.findFetch({ |
| 190 | + rundownId, |
| 191 | + }) |
| 192 | + const pieceInstances = await context.mockCollections.PieceInstances.findFetch({ |
| 193 | + rundownId, |
| 194 | + }) |
| 195 | + const groupedPieceInstances: Map<PartInstanceId, PieceInstance[]> = new Map( |
| 196 | + Object.entries<PieceInstance[]>( |
| 197 | + _.groupBy(pieceInstances, (pieceInstance) => unprotectString(pieceInstance.partInstanceId)) |
| 198 | + ) |
| 199 | + ) as any |
| 200 | + const rundowns: PlayoutRundownModelImpl[] = await Promise.all( |
| 201 | + ( |
| 202 | + await context.mockCollections.Rundowns.findFetch({ |
| 203 | + playlistId, |
| 204 | + }) |
| 205 | + ).map(async (rundown) => { |
| 206 | + const segments = await context.mockCollections.Segments.findFetch({ |
| 207 | + rundownId: rundown._id, |
| 208 | + }) |
| 209 | + |
| 210 | + const allSegmentModelImpl = await Promise.all( |
| 211 | + segments.map(async (segment) => { |
| 212 | + const parts = await context.mockCollections.Parts.findFetch({ |
| 213 | + rundownId: rundown._id, |
| 214 | + }) |
| 215 | + return new PlayoutSegmentModelImpl(segment, parts) |
| 216 | + }) |
| 217 | + ) |
| 218 | + return new PlayoutRundownModelImpl(rundown, allSegmentModelImpl, []) |
| 219 | + }) |
| 220 | + ) |
| 221 | + |
| 222 | + return { |
| 223 | + partInstances, |
| 224 | + groupedPieceInstances, |
| 225 | + rundowns, |
| 226 | + } |
| 227 | +} |
| 228 | + |
| 229 | +function setupMockPlayoutGateway(id: PeripheralDeviceId): PeripheralDevice { |
| 230 | + return { |
| 231 | + _id: id, |
| 232 | + category: PeripheralDeviceCategory.PLAYOUT, |
| 233 | + type: PeripheralDeviceType.PLAYOUT, |
| 234 | + subType: '', |
| 235 | + connected: true, |
| 236 | + configManifest: { |
| 237 | + deviceConfigSchema: JSONBlobStringify({}), |
| 238 | + subdeviceManifest: {}, |
| 239 | + }, |
| 240 | + connectionId: '', |
| 241 | + created: TIME_FAR_PAST, |
| 242 | + deviceName: `Dummy ${id}`, |
| 243 | + lastConnected: TIME_CONNECTED, |
| 244 | + lastSeen: TIME_PING, |
| 245 | + name: `Dummy ${id}`, |
| 246 | + organizationId: null, |
| 247 | + status: { |
| 248 | + statusCode: StatusCode.GOOD, |
| 249 | + messages: [], |
| 250 | + }, |
| 251 | + token: '', |
| 252 | + } |
| 253 | +} |
| 254 | + |
177 | 255 | async function setupRundownWithAutoplayPart0( |
178 | 256 | context: MockJobContext, |
179 | 257 | rundownId: RundownId, |
|
0 commit comments