1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
4 import { omit } from 'lodash'
5 import { HttpStatusCode } from '@shared/core-utils'
7 buildAbsoluteFixturePath,
15 setAccessTokensToServers,
18 } from '@shared/extra-utils'
19 import { VideoCreateResult, VideoPrivacy } from '@shared/models'
21 describe('Test video lives API validator', function () {
22 const path = '/api/v1/videos/live'
23 let server: ServerInfo
24 let userAccessToken = ''
26 let video: VideoCreateResult
27 let videoIdNotLive: number
28 let command: LiveCommand
30 // ---------------------------------------------------------------
32 before(async function () {
35 server = await flushAndRunServer(1)
37 await setAccessTokensToServers([ server ])
39 await server.configCommand.updateCustomSubConfig({
50 const username = 'user1'
51 const password = 'my super password'
52 await server.usersCommand.create({ username: username, password: password })
53 userAccessToken = await server.loginCommand.getAccessToken({ username, password })
56 const { videoChannels } = await server.usersCommand.getMyInfo()
57 channelId = videoChannels[0].id
61 videoIdNotLive = (await uploadVideoAndGetId({ server, videoName: 'not live' })).id
64 command = server.liveCommand
67 describe('When creating a live', function () {
72 name: 'my super name',
77 commentsEnabled: true,
78 downloadEnabled: true,
79 waitTranscoding: true,
80 description: 'my super description',
81 support: 'my super support text',
82 tags: [ 'tag1', 'tag2' ],
83 privacy: VideoPrivacy.PUBLIC,
90 it('Should fail with nothing', async function () {
92 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
95 it('Should fail with a long name', async function () {
96 const fields = { ...baseCorrectParams, name: 'super'.repeat(65) }
98 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
101 it('Should fail with a bad category', async function () {
102 const fields = { ...baseCorrectParams, category: 125 }
104 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
107 it('Should fail with a bad licence', async function () {
108 const fields = { ...baseCorrectParams, licence: 125 }
110 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
113 it('Should fail with a bad language', async function () {
114 const fields = { ...baseCorrectParams, language: 'a'.repeat(15) }
116 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
119 it('Should fail with a long description', async function () {
120 const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) }
122 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
125 it('Should fail with a long support text', async function () {
126 const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
128 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
131 it('Should fail without a channel', async function () {
132 const fields = omit(baseCorrectParams, 'channelId')
134 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
137 it('Should fail with a bad channel', async function () {
138 const fields = { ...baseCorrectParams, channelId: 545454 }
140 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
143 it('Should fail with another user channel', async function () {
146 password: 'fake_password'
148 await server.usersCommand.create({ username: user.username, password: user.password })
150 const accessTokenUser = await server.loginCommand.getAccessToken(user)
151 const { videoChannels } = await server.usersCommand.getMyInfo({ token: accessTokenUser })
152 const customChannelId = videoChannels[0].id
154 const fields = { ...baseCorrectParams, channelId: customChannelId }
156 await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields })
159 it('Should fail with too many tags', async function () {
160 const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }
162 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
165 it('Should fail with a tag length too low', async function () {
166 const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] }
168 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
171 it('Should fail with a tag length too big', async function () {
172 const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }
174 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
177 it('Should fail with an incorrect thumbnail file', async function () {
178 const fields = baseCorrectParams
180 thumbnailfile: buildAbsoluteFixturePath('video_short.mp4')
183 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
186 it('Should fail with a big thumbnail file', async function () {
187 const fields = baseCorrectParams
189 thumbnailfile: buildAbsoluteFixturePath('preview-big.png')
192 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
195 it('Should fail with an incorrect preview file', async function () {
196 const fields = baseCorrectParams
198 previewfile: buildAbsoluteFixturePath('video_short.mp4')
201 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
204 it('Should fail with a big preview file', async function () {
205 const fields = baseCorrectParams
207 previewfile: buildAbsoluteFixturePath('preview-big.png')
210 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
213 it('Should fail with save replay and permanent live set to true', async function () {
214 const fields = { ...baseCorrectParams, saveReplay: true, permanentLive: true }
216 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
219 it('Should succeed with the correct parameters', async function () {
222 const res = await makePostBodyRequest({
225 token: server.accessToken,
226 fields: baseCorrectParams,
227 statusCodeExpected: HttpStatusCode.OK_200
230 video = res.body.video
233 it('Should forbid if live is disabled', async function () {
234 await server.configCommand.updateCustomSubConfig({
242 await makePostBodyRequest({
245 token: server.accessToken,
246 fields: baseCorrectParams,
247 statusCodeExpected: HttpStatusCode.FORBIDDEN_403
251 it('Should forbid to save replay if not enabled by the admin', async function () {
252 const fields = { ...baseCorrectParams, saveReplay: true }
254 await server.configCommand.updateCustomSubConfig({
263 await makePostBodyRequest({
266 token: server.accessToken,
268 statusCodeExpected: HttpStatusCode.FORBIDDEN_403
272 it('Should allow to save replay if enabled by the admin', async function () {
273 const fields = { ...baseCorrectParams, saveReplay: true }
275 await server.configCommand.updateCustomSubConfig({
284 await makePostBodyRequest({
287 token: server.accessToken,
289 statusCodeExpected: HttpStatusCode.OK_200
293 it('Should not allow live if max instance lives is reached', async function () {
294 await server.configCommand.updateCustomSubConfig({
303 await makePostBodyRequest({
306 token: server.accessToken,
307 fields: baseCorrectParams,
308 statusCodeExpected: HttpStatusCode.FORBIDDEN_403
312 it('Should not allow live if max user lives is reached', async function () {
313 await server.configCommand.updateCustomSubConfig({
317 maxInstanceLives: 20,
323 await makePostBodyRequest({
326 token: server.accessToken,
327 fields: baseCorrectParams,
328 statusCodeExpected: HttpStatusCode.FORBIDDEN_403
333 describe('When getting live information', function () {
335 it('Should fail without access token', async function () {
336 await command.get({ token: '', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
339 it('Should fail with a bad access token', async function () {
340 await command.get({ token: 'toto', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
343 it('Should fail with access token of another user', async function () {
344 await command.get({ token: userAccessToken, videoId: video.id, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
347 it('Should fail with a bad video id', async function () {
348 await command.get({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
351 it('Should fail with an unknown video id', async function () {
352 await command.get({ videoId: 454555, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
355 it('Should fail with a non live video', async function () {
356 await command.get({ videoId: videoIdNotLive, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
359 it('Should succeed with the correct params', async function () {
360 await command.get({ videoId: video.id })
361 await command.get({ videoId: video.uuid })
362 await command.get({ videoId: video.shortUUID })
366 describe('When updating live information', async function () {
368 it('Should fail without access token', async function () {
369 await command.update({ token: '', videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
372 it('Should fail with a bad access token', async function () {
373 await command.update({ token: 'toto', videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
376 it('Should fail with access token of another user', async function () {
377 await command.update({ token: userAccessToken, videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
380 it('Should fail with a bad video id', async function () {
381 await command.update({ videoId: 'toto', fields: {}, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
384 it('Should fail with an unknown video id', async function () {
385 await command.update({ videoId: 454555, fields: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
388 it('Should fail with a non live video', async function () {
389 await command.update({ videoId: videoIdNotLive, fields: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
392 it('Should fail with save replay and permanent live set to true', async function () {
393 const fields = { saveReplay: true, permanentLive: true }
395 await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
398 it('Should succeed with the correct params', async function () {
399 await command.update({ videoId: video.id, fields: { saveReplay: false } })
400 await command.update({ videoId: video.uuid, fields: { saveReplay: false } })
401 await command.update({ videoId: video.shortUUID, fields: { saveReplay: false } })
404 it('Should fail to update replay status if replay is not allowed on the instance', async function () {
405 await server.configCommand.updateCustomSubConfig({
414 await command.update({ videoId: video.id, fields: { saveReplay: true }, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
417 it('Should fail to update a live if it has already started', async function () {
420 const live = await command.get({ videoId: video.id })
422 const ffmpegCommand = sendRTMPStream(live.rtmpUrl, live.streamKey)
424 await command.waitUntilPublished({ videoId: video.id })
425 await command.update({ videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
427 await stopFfmpeg(ffmpegCommand)
430 it('Should fail to stream twice in the save live', async function () {
433 const live = await command.get({ videoId: video.id })
435 const ffmpegCommand = sendRTMPStream(live.rtmpUrl, live.streamKey)
437 await command.waitUntilPublished({ videoId: video.id })
439 await command.runAndTestStreamError({ videoId: video.id, shouldHaveError: true })
441 await stopFfmpeg(ffmpegCommand)
445 after(async function () {
446 await cleanupTests([ server ])