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