1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
3 import { HttpStatusCode, VideoStudioTask } from '@shared/models'
8 setAccessTokensToServers,
11 } from '@shared/server-commands'
13 describe('Test video studio API validator', function () {
14 let server: PeerTubeServer
15 let command: VideoStudioCommand
16 let userAccessToken: string
19 // ---------------------------------------------------------------
21 before(async function () {
24 server = await createSingleServer(1)
26 await setAccessTokensToServers([ server ])
27 userAccessToken = await server.users.generateUserAndToken('user1')
29 await server.config.enableMinimumTranscoding()
31 const { uuid } = await server.videos.quickUpload({ name: 'video' })
34 command = server.videoStudio
36 await waitJobs([ server ])
39 describe('Task creation', function () {
41 describe('Config settings', function () {
43 it('Should fail if studio is disabled', async function () {
44 await server.config.updateExistingSubConfig({
52 await command.createEditionTasks({
54 tasks: VideoStudioCommand.getComplexTask(),
55 expectedStatus: HttpStatusCode.BAD_REQUEST_400
59 it('Should fail to enable studio if transcoding is disabled', async function () {
60 await server.config.updateExistingSubConfig({
69 expectedStatus: HttpStatusCode.BAD_REQUEST_400
73 it('Should succeed to enable video studio', async function () {
74 await server.config.updateExistingSubConfig({
87 describe('Common tasks', function () {
89 it('Should fail without token', async function () {
90 await command.createEditionTasks({
93 tasks: VideoStudioCommand.getComplexTask(),
94 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
98 it('Should fail with another user token', async function () {
99 await command.createEditionTasks({
100 token: userAccessToken,
102 tasks: VideoStudioCommand.getComplexTask(),
103 expectedStatus: HttpStatusCode.FORBIDDEN_403
107 it('Should fail with an invalid video', async function () {
108 await command.createEditionTasks({
110 tasks: VideoStudioCommand.getComplexTask(),
111 expectedStatus: HttpStatusCode.BAD_REQUEST_400
115 it('Should fail with an unknown video', async function () {
116 await command.createEditionTasks({
118 tasks: VideoStudioCommand.getComplexTask(),
119 expectedStatus: HttpStatusCode.NOT_FOUND_404
123 it('Should fail with an already in transcoding state video', async function () {
126 const { uuid } = await server.videos.quickUpload({ name: 'transcoded video' })
127 await waitJobs([ server ])
129 await server.jobs.pauseJobQueue()
130 await server.videos.runTranscoding({ videoId: uuid, transcodingType: 'hls' })
132 await command.createEditionTasks({
134 tasks: VideoStudioCommand.getComplexTask(),
135 expectedStatus: HttpStatusCode.CONFLICT_409
138 await server.jobs.resumeJobQueue()
141 it('Should fail with a bad complex task', async function () {
142 await command.createEditionTasks({
160 expectedStatus: HttpStatusCode.BAD_REQUEST_400
164 it('Should fail without task', async function () {
165 await command.createEditionTasks({
168 expectedStatus: HttpStatusCode.BAD_REQUEST_400
172 it('Should fail with too many tasks', async function () {
173 const tasks: VideoStudioTask[] = []
175 for (let i = 0; i < 110; i++) {
184 await command.createEditionTasks({
187 expectedStatus: HttpStatusCode.BAD_REQUEST_400
191 it('Should succeed with correct parameters', async function () {
192 await server.jobs.pauseJobQueue()
194 await command.createEditionTasks({
196 tasks: VideoStudioCommand.getComplexTask(),
197 expectedStatus: HttpStatusCode.NO_CONTENT_204
201 it('Should fail with a video that is already waiting for edition', async function () {
204 await command.createEditionTasks({
206 tasks: VideoStudioCommand.getComplexTask(),
207 expectedStatus: HttpStatusCode.CONFLICT_409
210 await server.jobs.resumeJobQueue()
212 await waitJobs([ server ])
216 describe('Cut task', function () {
218 async function cut (start: number, end: number, expectedStatus = HttpStatusCode.BAD_REQUEST_400) {
219 await command.createEditionTasks({
234 it('Should fail with bad start/end', async function () {
241 for (const value of invalid) {
242 await cut(value as any, undefined)
243 await cut(undefined, value as any)
247 it('Should fail with the same start/end', async function () {
251 it('Should fail with inconsistents start/end', async function () {
255 it('Should fail without start and end', async function () {
256 await cut(undefined, undefined)
259 it('Should succeed with the correct params', async function () {
262 await cut(0, 2, HttpStatusCode.NO_CONTENT_204)
264 await waitJobs([ server ])
268 describe('Watermark task', function () {
270 async function addWatermark (file: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400) {
271 await command.createEditionTasks({
275 name: 'add-watermark',
285 it('Should fail without waterkmark', async function () {
286 await addWatermark(undefined)
289 it('Should fail with an invalid watermark', async function () {
290 await addWatermark('video_short.mp4')
293 it('Should succeed with the correct params', async function () {
296 await addWatermark('thumbnail.jpg', HttpStatusCode.NO_CONTENT_204)
298 await waitJobs([ server ])
302 describe('Intro/Outro task', function () {
304 async function addIntroOutro (type: 'add-intro' | 'add-outro', file: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400) {
305 await command.createEditionTasks({
319 it('Should fail without file', async function () {
320 await addIntroOutro('add-intro', undefined)
321 await addIntroOutro('add-outro', undefined)
324 it('Should fail with an invalid file', async function () {
325 await addIntroOutro('add-intro', 'thumbnail.jpg')
326 await addIntroOutro('add-outro', 'thumbnail.jpg')
329 it('Should fail with a file that does not contain video stream', async function () {
330 await addIntroOutro('add-intro', 'sample.ogg')
331 await addIntroOutro('add-outro', 'sample.ogg')
335 it('Should succeed with the correct params', async function () {
338 await addIntroOutro('add-intro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204)
339 await waitJobs([ server ])
341 await addIntroOutro('add-outro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204)
342 await waitJobs([ server ])
345 it('Should check total quota when creating the task', async function () {
348 const user = await server.users.create({ username: 'user_quota_1' })
349 const token = await server.login.getAccessToken('user_quota_1')
350 const { uuid } = await server.videos.quickUpload({ token, name: 'video_quota_1', fixture: 'video_short.mp4' })
352 const addIntroOutroByUser = (type: 'add-intro' | 'add-outro', expectedStatus: HttpStatusCode) => {
353 return command.createEditionTasks({
360 file: 'video_short.mp4'
368 await waitJobs([ server ])
370 const { videoQuotaUsed } = await server.users.getMyQuotaUsed({ token })
371 await server.users.update({ userId: user.id, videoQuota: Math.round(videoQuotaUsed * 2.5) })
374 await addIntroOutroByUser('add-intro', HttpStatusCode.NO_CONTENT_204)
376 await waitJobs([ server ])
379 await addIntroOutroByUser('add-intro', HttpStatusCode.PAYLOAD_TOO_LARGE_413)
380 await addIntroOutroByUser('add-outro', HttpStatusCode.PAYLOAD_TOO_LARGE_413)
385 after(async function () {
386 await cleanupTests([ server ])