]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tests/api/live/live-save-replay.ts
add support for 1440p (Quad HD/QHD/WQHD) videos
[github/Chocobozzz/PeerTube.git] / server / tests / api / live / live-save-replay.ts
1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3 import 'mocha'
4 import * as chai from 'chai'
5 import { FfmpegCommand } from 'fluent-ffmpeg'
6 import { LiveVideoCreate, VideoDetails, VideoPrivacy, VideoState } from '@shared/models'
7 import {
8 addVideoToBlacklist,
9 checkLiveCleanup,
10 cleanupTests,
11 createLive,
12 doubleFollow,
13 flushAndRunMultipleServers,
14 getVideo,
15 getVideosList,
16 removeVideo,
17 sendRTMPStreamInVideo,
18 ServerInfo,
19 setAccessTokensToServers,
20 setDefaultVideoChannel,
21 stopFfmpeg,
22 testFfmpegStreamError,
23 updateCustomSubConfig,
24 updateVideo,
25 waitJobs,
26 waitUntilLivePublished
27 } from '../../../../shared/extra-utils'
28 import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
29
30 const expect = chai.expect
31
32 describe('Save replay setting', function () {
33 let servers: ServerInfo[] = []
34 let liveVideoUUID: string
35 let ffmpegCommand: FfmpegCommand
36
37 async function createLiveWrapper (saveReplay: boolean) {
38 if (liveVideoUUID) {
39 try {
40 await removeVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
41 await waitJobs(servers)
42 } catch {}
43 }
44
45 const attributes: LiveVideoCreate = {
46 channelId: servers[0].videoChannel.id,
47 privacy: VideoPrivacy.PUBLIC,
48 name: 'my super live',
49 saveReplay
50 }
51
52 const res = await createLive(servers[0].url, servers[0].accessToken, attributes)
53 return res.body.video.uuid
54 }
55
56 async function checkVideosExist (videoId: string, existsInList: boolean, getStatus?: number) {
57 for (const server of servers) {
58 const length = existsInList ? 1 : 0
59
60 const resVideos = await getVideosList(server.url)
61 expect(resVideos.body.data).to.have.lengthOf(length)
62 expect(resVideos.body.total).to.equal(length)
63
64 if (getStatus) {
65 await getVideo(server.url, videoId, getStatus)
66 }
67 }
68 }
69
70 async function checkVideoState (videoId: string, state: VideoState) {
71 for (const server of servers) {
72 const res = await getVideo(server.url, videoId)
73 expect((res.body as VideoDetails).state.id).to.equal(state)
74 }
75 }
76
77 before(async function () {
78 this.timeout(120000)
79
80 servers = await flushAndRunMultipleServers(2)
81
82 // Get the access tokens
83 await setAccessTokensToServers(servers)
84 await setDefaultVideoChannel(servers)
85
86 // Server 1 and server 2 follow each other
87 await doubleFollow(servers[0], servers[1])
88
89 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
90 live: {
91 enabled: true,
92 allowReplay: true,
93 maxDuration: -1,
94 transcoding: {
95 enabled: false,
96 resolutions: {
97 '240p': true,
98 '360p': true,
99 '480p': true,
100 '720p': true,
101 '1080p': true,
102 '1440p': true,
103 '2160p': true
104 }
105 }
106 }
107 })
108 })
109
110 describe('With save replay disabled', function () {
111
112 before(async function () {
113 this.timeout(10000)
114 })
115
116 it('Should correctly create and federate the "waiting for stream" live', async function () {
117 this.timeout(20000)
118
119 liveVideoUUID = await createLiveWrapper(false)
120
121 await waitJobs(servers)
122
123 await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200)
124 await checkVideoState(liveVideoUUID, VideoState.WAITING_FOR_LIVE)
125 })
126
127 it('Should correctly have updated the live and federated it when streaming in the live', async function () {
128 this.timeout(20000)
129
130 ffmpegCommand = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
131 await waitUntilLivePublished(servers[0].url, servers[0].accessToken, liveVideoUUID)
132
133 await waitJobs(servers)
134
135 await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200)
136 await checkVideoState(liveVideoUUID, VideoState.PUBLISHED)
137 })
138
139 it('Should correctly delete the video files after the stream ended', async function () {
140 this.timeout(40000)
141
142 await stopFfmpeg(ffmpegCommand)
143
144 await waitJobs(servers)
145
146 // Live still exist, but cannot be played anymore
147 await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200)
148 await checkVideoState(liveVideoUUID, VideoState.LIVE_ENDED)
149
150 await waitJobs(servers)
151
152 // No resolutions saved since we did not save replay
153 await checkLiveCleanup(servers[0], liveVideoUUID, [])
154 })
155
156 it('Should correctly terminate the stream on blacklist and delete the live', async function () {
157 this.timeout(40000)
158
159 liveVideoUUID = await createLiveWrapper(false)
160
161 ffmpegCommand = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
162 await waitUntilLivePublished(servers[0].url, servers[0].accessToken, liveVideoUUID)
163
164 await waitJobs(servers)
165 await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200)
166
167 await Promise.all([
168 addVideoToBlacklist(servers[0].url, servers[0].accessToken, liveVideoUUID, 'bad live', true),
169 testFfmpegStreamError(ffmpegCommand, true)
170 ])
171
172 await waitJobs(servers)
173
174 await checkVideosExist(liveVideoUUID, false)
175
176 await getVideo(servers[0].url, liveVideoUUID, HttpStatusCode.UNAUTHORIZED_401)
177 await getVideo(servers[1].url, liveVideoUUID, HttpStatusCode.NOT_FOUND_404)
178
179 await checkLiveCleanup(servers[0], liveVideoUUID, [])
180 })
181
182 it('Should correctly terminate the stream on delete and delete the video', async function () {
183 this.timeout(40000)
184
185 liveVideoUUID = await createLiveWrapper(false)
186
187 ffmpegCommand = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
188 await waitUntilLivePublished(servers[0].url, servers[0].accessToken, liveVideoUUID)
189
190 await waitJobs(servers)
191 await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200)
192
193 await Promise.all([
194 testFfmpegStreamError(ffmpegCommand, true),
195 removeVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
196 ])
197
198 await waitJobs(servers)
199
200 await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404)
201 await checkLiveCleanup(servers[0], liveVideoUUID, [])
202 })
203 })
204
205 describe('With save replay enabled', function () {
206
207 it('Should correctly create and federate the "waiting for stream" live', async function () {
208 this.timeout(20000)
209
210 liveVideoUUID = await createLiveWrapper(true)
211
212 await waitJobs(servers)
213
214 await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200)
215 await checkVideoState(liveVideoUUID, VideoState.WAITING_FOR_LIVE)
216 })
217
218 it('Should correctly have updated the live and federated it when streaming in the live', async function () {
219 this.timeout(20000)
220
221 ffmpegCommand = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
222 await waitUntilLivePublished(servers[0].url, servers[0].accessToken, liveVideoUUID)
223
224 await waitJobs(servers)
225
226 await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200)
227 await checkVideoState(liveVideoUUID, VideoState.PUBLISHED)
228 })
229
230 it('Should correctly have saved the live and federated it after the streaming', async function () {
231 this.timeout(30000)
232
233 await stopFfmpeg(ffmpegCommand)
234
235 await waitJobs(servers)
236
237 // Live has been transcoded
238 await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200)
239 await checkVideoState(liveVideoUUID, VideoState.PUBLISHED)
240 })
241
242 it('Should update the saved live and correctly federate the updated attributes', async function () {
243 this.timeout(30000)
244
245 await updateVideo(servers[0].url, servers[0].accessToken, liveVideoUUID, { name: 'video updated' })
246 await waitJobs(servers)
247
248 for (const server of servers) {
249 const res = await getVideo(server.url, liveVideoUUID)
250 expect(res.body.name).to.equal('video updated')
251 expect(res.body.isLive).to.be.false
252 }
253 })
254
255 it('Should have cleaned up the live files', async function () {
256 await checkLiveCleanup(servers[0], liveVideoUUID, [ 720 ])
257 })
258
259 it('Should correctly terminate the stream on blacklist and blacklist the saved replay video', async function () {
260 this.timeout(40000)
261
262 liveVideoUUID = await createLiveWrapper(true)
263
264 ffmpegCommand = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
265 await waitUntilLivePublished(servers[0].url, servers[0].accessToken, liveVideoUUID)
266
267 await waitJobs(servers)
268 await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200)
269
270 await Promise.all([
271 addVideoToBlacklist(servers[0].url, servers[0].accessToken, liveVideoUUID, 'bad live', true),
272 testFfmpegStreamError(ffmpegCommand, true)
273 ])
274
275 await waitJobs(servers)
276
277 await checkVideosExist(liveVideoUUID, false)
278
279 await getVideo(servers[0].url, liveVideoUUID, HttpStatusCode.UNAUTHORIZED_401)
280 await getVideo(servers[1].url, liveVideoUUID, HttpStatusCode.NOT_FOUND_404)
281
282 await checkLiveCleanup(servers[0], liveVideoUUID, [ 720 ])
283 })
284
285 it('Should correctly terminate the stream on delete and delete the video', async function () {
286 this.timeout(40000)
287
288 liveVideoUUID = await createLiveWrapper(true)
289
290 ffmpegCommand = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
291 await waitUntilLivePublished(servers[0].url, servers[0].accessToken, liveVideoUUID)
292
293 await waitJobs(servers)
294 await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200)
295
296 await Promise.all([
297 removeVideo(servers[0].url, servers[0].accessToken, liveVideoUUID),
298 testFfmpegStreamError(ffmpegCommand, true)
299 ])
300
301 await waitJobs(servers)
302
303 await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404)
304 await checkLiveCleanup(servers[0], liveVideoUUID, [])
305 })
306 })
307
308 after(async function () {
309 await cleanupTests(servers)
310 })
311 })