]>
Commit | Line | Data |
---|---|---|
af4ae64f C |
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | ||
3 | import 'mocha' | |
4 | import * as chai from 'chai' | |
97969c4e | 5 | import { LiveVideo, LiveVideoCreate, User, VideoDetails, VideoPrivacy } from '@shared/models' |
af4ae64f | 6 | import { |
af4ae64f C |
7 | cleanupTests, |
8 | createLive, | |
97969c4e | 9 | createUser, |
af4ae64f C |
10 | doubleFollow, |
11 | flushAndRunMultipleServers, | |
12 | getLive, | |
97969c4e | 13 | getMyUserInformation, |
af4ae64f C |
14 | getVideo, |
15 | getVideosList, | |
16 | makeRawRequest, | |
17 | removeVideo, | |
18 | ServerInfo, | |
19 | setAccessTokensToServers, | |
20 | setDefaultVideoChannel, | |
97969c4e | 21 | testFfmpegStreamError, |
af4ae64f C |
22 | testImage, |
23 | updateCustomSubConfig, | |
24 | updateLive, | |
97969c4e C |
25 | updateUser, |
26 | userLogin, | |
27 | wait, | |
af4ae64f C |
28 | waitJobs |
29 | } from '../../../../shared/extra-utils' | |
30 | ||
31 | const expect = chai.expect | |
32 | ||
33 | describe('Test live', function () { | |
34 | let servers: ServerInfo[] = [] | |
35 | let liveVideoUUID: string | |
97969c4e C |
36 | let userId: number |
37 | let userAccessToken: string | |
38 | let userChannelId: number | |
af4ae64f C |
39 | |
40 | before(async function () { | |
41 | this.timeout(120000) | |
42 | ||
43 | servers = await flushAndRunMultipleServers(2) | |
44 | ||
45 | // Get the access tokens | |
46 | await setAccessTokensToServers(servers) | |
47 | await setDefaultVideoChannel(servers) | |
48 | ||
49 | await updateCustomSubConfig(servers[0].url, servers[0].accessToken, { | |
50 | live: { | |
51 | enabled: true, | |
52 | allowReplay: true | |
53 | } | |
54 | }) | |
55 | ||
97969c4e C |
56 | { |
57 | const user = { username: 'user1', password: 'superpassword' } | |
58 | const res = await createUser({ | |
59 | url: servers[0].url, | |
60 | accessToken: servers[0].accessToken, | |
61 | username: user.username, | |
62 | password: user.password | |
63 | }) | |
64 | userId = res.body.user.id | |
65 | ||
66 | userAccessToken = await userLogin(servers[0], user) | |
67 | ||
68 | const resMe = await getMyUserInformation(servers[0].url, userAccessToken) | |
69 | userChannelId = (resMe.body as User).videoChannels[0].id | |
70 | } | |
71 | ||
af4ae64f C |
72 | // Server 1 and server 2 follow each other |
73 | await doubleFollow(servers[0], servers[1]) | |
74 | }) | |
75 | ||
76 | describe('Live creation, update and delete', function () { | |
77 | ||
78 | it('Should create a live with the appropriate parameters', async function () { | |
79 | this.timeout(20000) | |
80 | ||
81 | const attributes: LiveVideoCreate = { | |
82 | category: 1, | |
83 | licence: 2, | |
84 | language: 'fr', | |
85 | description: 'super live description', | |
86 | support: 'support field', | |
87 | channelId: servers[0].videoChannel.id, | |
88 | nsfw: false, | |
89 | waitTranscoding: false, | |
90 | name: 'my super live', | |
91 | tags: [ 'tag1', 'tag2' ], | |
92 | commentsEnabled: false, | |
93 | downloadEnabled: false, | |
94 | saveReplay: true, | |
95 | privacy: VideoPrivacy.PUBLIC, | |
96 | previewfile: 'video_short1-preview.webm.jpg', | |
97 | thumbnailfile: 'video_short1.webm.jpg' | |
98 | } | |
99 | ||
100 | const res = await createLive(servers[0].url, servers[0].accessToken, attributes) | |
101 | liveVideoUUID = res.body.video.uuid | |
102 | ||
103 | await waitJobs(servers) | |
104 | ||
105 | for (const server of servers) { | |
106 | const resVideo = await getVideo(server.url, liveVideoUUID) | |
107 | const video: VideoDetails = resVideo.body | |
108 | ||
109 | expect(video.category.id).to.equal(1) | |
110 | expect(video.licence.id).to.equal(2) | |
111 | expect(video.language.id).to.equal('fr') | |
112 | expect(video.description).to.equal('super live description') | |
113 | expect(video.support).to.equal('support field') | |
114 | ||
115 | expect(video.channel.name).to.equal(servers[0].videoChannel.name) | |
116 | expect(video.channel.host).to.equal(servers[0].videoChannel.host) | |
117 | ||
118 | expect(video.nsfw).to.be.false | |
119 | expect(video.waitTranscoding).to.be.false | |
120 | expect(video.name).to.equal('my super live') | |
121 | expect(video.tags).to.deep.equal([ 'tag1', 'tag2' ]) | |
122 | expect(video.commentsEnabled).to.be.false | |
123 | expect(video.downloadEnabled).to.be.false | |
124 | expect(video.privacy.id).to.equal(VideoPrivacy.PUBLIC) | |
125 | ||
126 | await testImage(server.url, 'video_short1-preview.webm', video.previewPath) | |
127 | await testImage(server.url, 'video_short1.webm', video.thumbnailPath) | |
128 | ||
129 | const resLive = await getLive(server.url, server.accessToken, liveVideoUUID) | |
130 | const live: LiveVideo = resLive.body | |
131 | ||
132 | if (server.url === servers[0].url) { | |
133 | expect(live.rtmpUrl).to.equal('rtmp://' + server.hostname + ':1936/live') | |
134 | expect(live.streamKey).to.not.be.empty | |
135 | } else { | |
136 | expect(live.rtmpUrl).to.be.null | |
137 | expect(live.streamKey).to.be.null | |
138 | } | |
139 | ||
140 | expect(live.saveReplay).to.be.true | |
141 | } | |
142 | }) | |
143 | ||
144 | it('Should have a default preview and thumbnail', async function () { | |
145 | this.timeout(20000) | |
146 | ||
147 | const attributes: LiveVideoCreate = { | |
148 | name: 'default live thumbnail', | |
149 | channelId: servers[0].videoChannel.id, | |
150 | privacy: VideoPrivacy.UNLISTED, | |
151 | nsfw: true | |
152 | } | |
153 | ||
154 | const res = await createLive(servers[0].url, servers[0].accessToken, attributes) | |
155 | const videoId = res.body.video.uuid | |
156 | ||
157 | await waitJobs(servers) | |
158 | ||
159 | for (const server of servers) { | |
160 | const resVideo = await getVideo(server.url, videoId) | |
161 | const video: VideoDetails = resVideo.body | |
162 | ||
163 | expect(video.privacy.id).to.equal(VideoPrivacy.UNLISTED) | |
164 | expect(video.nsfw).to.be.true | |
165 | ||
166 | await makeRawRequest(server.url + video.thumbnailPath, 200) | |
167 | await makeRawRequest(server.url + video.previewPath, 200) | |
168 | } | |
169 | }) | |
170 | ||
171 | it('Should not have the live listed since nobody streams into', async function () { | |
172 | for (const server of servers) { | |
173 | const res = await getVideosList(server.url) | |
174 | ||
175 | expect(res.body.total).to.equal(0) | |
176 | expect(res.body.data).to.have.lengthOf(0) | |
177 | } | |
178 | }) | |
179 | ||
180 | it('Should not be able to update a live of another server', async function () { | |
181 | await updateLive(servers[1].url, servers[1].accessToken, liveVideoUUID, { saveReplay: false }, 403) | |
182 | }) | |
183 | ||
184 | it('Should update the live', async function () { | |
185 | this.timeout(10000) | |
186 | ||
187 | await updateLive(servers[0].url, servers[0].accessToken, liveVideoUUID, { saveReplay: false }) | |
188 | await waitJobs(servers) | |
189 | }) | |
190 | ||
191 | it('Have the live updated', async function () { | |
192 | for (const server of servers) { | |
193 | const res = await getLive(server.url, server.accessToken, liveVideoUUID) | |
194 | const live: LiveVideo = res.body | |
195 | ||
196 | if (server.url === servers[0].url) { | |
197 | expect(live.rtmpUrl).to.equal('rtmp://' + server.hostname + ':1936/live') | |
198 | expect(live.streamKey).to.not.be.empty | |
199 | } else { | |
200 | expect(live.rtmpUrl).to.be.null | |
201 | expect(live.streamKey).to.be.null | |
202 | } | |
203 | ||
204 | expect(live.saveReplay).to.be.false | |
205 | } | |
206 | }) | |
207 | ||
208 | it('Delete the live', async function () { | |
209 | this.timeout(10000) | |
210 | ||
211 | await removeVideo(servers[0].url, servers[0].accessToken, liveVideoUUID) | |
212 | await waitJobs(servers) | |
213 | }) | |
214 | ||
215 | it('Should have the live deleted', async function () { | |
216 | for (const server of servers) { | |
217 | await getVideo(server.url, liveVideoUUID, 404) | |
218 | await getLive(server.url, server.accessToken, liveVideoUUID, 404) | |
219 | } | |
220 | }) | |
221 | }) | |
222 | ||
223 | describe('Test live constraints', function () { | |
224 | ||
97969c4e C |
225 | async function createLiveWrapper (saveReplay: boolean) { |
226 | const liveAttributes = { | |
227 | name: 'user live', | |
228 | channelId: userChannelId, | |
229 | privacy: VideoPrivacy.PUBLIC, | |
230 | saveReplay | |
231 | } | |
232 | ||
233 | const res = await createLive(servers[0].url, userAccessToken, liveAttributes) | |
234 | return res.body.video.uuid as string | |
235 | } | |
236 | ||
237 | before(async function () { | |
238 | await updateCustomSubConfig(servers[0].url, servers[0].accessToken, { | |
239 | live: { | |
240 | enabled: true, | |
241 | allowReplay: true | |
242 | } | |
243 | }) | |
244 | ||
245 | await updateUser({ | |
246 | url: servers[0].url, | |
247 | userId, | |
248 | accessToken: servers[0].accessToken, | |
249 | videoQuota: 1, | |
250 | videoQuotaDaily: -1 | |
251 | }) | |
252 | }) | |
253 | ||
af4ae64f | 254 | it('Should not have size limit if save replay is disabled', async function () { |
97969c4e C |
255 | this.timeout(30000) |
256 | ||
257 | const userVideoLiveoId = await createLiveWrapper(false) | |
258 | await testFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, false) | |
259 | }) | |
260 | ||
261 | it('Should have size limit depending on user global quota if save replay is enabled', async function () { | |
262 | this.timeout(30000) | |
263 | ||
264 | const userVideoLiveoId = await createLiveWrapper(true) | |
265 | await testFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, true) | |
266 | ||
267 | await waitJobs(servers) | |
268 | ||
269 | for (const server of servers) { | |
270 | const res = await getVideo(server.url, userVideoLiveoId) | |
271 | ||
272 | const video: VideoDetails = res.body | |
273 | expect(video.isLive).to.be.false | |
274 | expect(video.duration).to.be.greaterThan(0) | |
275 | } | |
af4ae64f | 276 | |
97969c4e | 277 | // TODO: check stream correctly saved + cleaned |
af4ae64f C |
278 | }) |
279 | ||
97969c4e C |
280 | it('Should have size limit depending on user daily quota if save replay is enabled', async function () { |
281 | this.timeout(30000) | |
282 | ||
283 | await updateUser({ | |
284 | url: servers[0].url, | |
285 | userId, | |
286 | accessToken: servers[0].accessToken, | |
287 | videoQuota: -1, | |
288 | videoQuotaDaily: 1 | |
289 | }) | |
af4ae64f | 290 | |
97969c4e C |
291 | const userVideoLiveoId = await createLiveWrapper(true) |
292 | await testFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, true) | |
293 | ||
294 | // TODO: check stream correctly saved + cleaned | |
295 | }) | |
296 | ||
297 | it('Should succeed without quota limit', async function () { | |
298 | this.timeout(30000) | |
299 | ||
300 | // Wait for user quota memoize cache invalidation | |
301 | await wait(5000) | |
302 | ||
303 | await updateUser({ | |
304 | url: servers[0].url, | |
305 | userId, | |
306 | accessToken: servers[0].accessToken, | |
307 | videoQuota: 10 * 1000 * 1000, | |
308 | videoQuotaDaily: -1 | |
309 | }) | |
310 | ||
311 | const userVideoLiveoId = await createLiveWrapper(true) | |
312 | await testFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, false) | |
af4ae64f C |
313 | }) |
314 | ||
315 | it('Should have max duration limit', async function () { | |
97969c4e C |
316 | this.timeout(30000) |
317 | ||
318 | await updateCustomSubConfig(servers[0].url, servers[0].accessToken, { | |
319 | live: { | |
320 | enabled: true, | |
321 | allowReplay: true, | |
322 | maxDuration: 1 | |
323 | } | |
324 | }) | |
325 | ||
326 | const userVideoLiveoId = await createLiveWrapper(true) | |
327 | await testFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, true) | |
af4ae64f | 328 | |
97969c4e | 329 | // TODO: check stream correctly saved + cleaned |
af4ae64f C |
330 | }) |
331 | }) | |
332 | ||
333 | describe('With save replay disabled', function () { | |
334 | ||
335 | it('Should correctly create and federate the "waiting for stream" live', async function () { | |
336 | ||
337 | }) | |
338 | ||
339 | it('Should correctly have updated the live and federated it when streaming in the live', async function () { | |
340 | ||
341 | }) | |
342 | ||
343 | it('Should correctly delete the video and the live after the stream ended', async function () { | |
344 | // Wait 10 seconds | |
345 | // get video 404 | |
346 | // get video federation 404 | |
347 | ||
348 | // check cleanup | |
349 | }) | |
350 | ||
351 | it('Should correctly terminate the stream on blacklist and delete the live', async function () { | |
352 | // Wait 10 seconds | |
353 | // get video 404 | |
354 | // get video federation 404 | |
355 | ||
356 | // check cleanup | |
357 | }) | |
358 | ||
359 | it('Should correctly terminate the stream on delete and delete the video', async function () { | |
360 | // Wait 10 seconds | |
361 | // get video 404 | |
362 | // get video federation 404 | |
363 | ||
364 | // check cleanup | |
365 | }) | |
366 | }) | |
367 | ||
368 | describe('With save replay enabled', function () { | |
369 | ||
370 | it('Should correctly create and federate the "waiting for stream" live', async function () { | |
371 | ||
372 | }) | |
373 | ||
374 | it('Should correctly have updated the live and federated it when streaming in the live', async function () { | |
375 | ||
376 | }) | |
377 | ||
378 | it('Should correctly have saved the live and federated it after the streaming', async function () { | |
379 | ||
380 | }) | |
381 | ||
382 | it('Should update the saved live and correctly federate the updated attributes', async function () { | |
383 | ||
384 | }) | |
385 | ||
386 | it('Should have cleaned up the live files', async function () { | |
387 | ||
388 | }) | |
389 | ||
390 | it('Should correctly terminate the stream on blacklist and blacklist the saved replay video', async function () { | |
391 | // Wait 10 seconds | |
392 | // get video -> blacklisted | |
393 | // get video federation -> blacklisted | |
394 | ||
395 | // check cleanup live files quand meme | |
396 | }) | |
397 | ||
398 | it('Should correctly terminate the stream on delete and delete the video', async function () { | |
399 | // Wait 10 seconds | |
400 | // get video 404 | |
401 | // get video federation 404 | |
402 | ||
403 | // check cleanup | |
404 | }) | |
405 | }) | |
406 | ||
407 | describe('Stream checks', function () { | |
408 | ||
409 | it('Should not allow a stream without the appropriate path', async function () { | |
410 | ||
411 | }) | |
412 | ||
413 | it('Should not allow a stream without the appropriate stream key', async function () { | |
414 | ||
415 | }) | |
416 | ||
417 | it('Should not allow a stream on a live that was blacklisted', async function () { | |
418 | ||
419 | }) | |
420 | ||
421 | it('Should not allow a stream on a live that was deleted', async function () { | |
422 | ||
423 | }) | |
424 | }) | |
425 | ||
426 | describe('Live transcoding', function () { | |
427 | ||
428 | it('Should enable transcoding without additional resolutions', async function () { | |
429 | // enable | |
430 | // stream | |
431 | // wait federation + test | |
432 | ||
433 | }) | |
434 | ||
435 | it('Should enable transcoding with some resolutions', async function () { | |
436 | // enable | |
437 | // stream | |
438 | // wait federation + test | |
439 | }) | |
440 | ||
441 | it('Should enable transcoding with some resolutions and correctly save them', async function () { | |
442 | // enable | |
443 | // stream | |
444 | // end stream | |
445 | // wait federation + test | |
446 | }) | |
447 | ||
448 | it('Should correctly have cleaned up the live files', async function () { | |
449 | // check files | |
450 | }) | |
451 | }) | |
452 | ||
453 | describe('Live socket messages', function () { | |
454 | ||
455 | it('Should correctly send a message when the live starts', async function () { | |
456 | // local | |
457 | // federation | |
458 | }) | |
459 | ||
460 | it('Should correctly send a message when the live ends', async function () { | |
461 | // local | |
462 | // federation | |
463 | }) | |
464 | }) | |
465 | ||
466 | after(async function () { | |
467 | await cleanupTests(servers) | |
468 | }) | |
469 | }) |