1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
4 import { HttpStatusCode, VideoStudioTask } from '@shared/models'
9 setAccessTokensToServers,
12 } from '@shared/server-commands'
14 describe('Test video studio API validator', function () {
15 let server: PeerTubeServer
16 let command: VideoStudioCommand
17 let userAccessToken: string
20 // ---------------------------------------------------------------
22 before(async function () {
25 server = await createSingleServer(1)
27 await setAccessTokensToServers([ server ])
28 userAccessToken = await server.users.generateUserAndToken('user1')
30 await server.config.enableMinimumTranscoding()
32 const { uuid } = await server.videos.quickUpload({ name: 'video' })
35 command = server.videoStudio
37 await waitJobs([ server ])
40 describe('Task creation', function () {
42 describe('Config settings', function () {
44 it('Should fail if studio is disabled', async function () {
45 await server.config.updateExistingSubConfig({
53 await command.createEditionTasks({
55 tasks: VideoStudioCommand.getComplexTask(),
56 expectedStatus: HttpStatusCode.BAD_REQUEST_400
60 it('Should fail to enable studio if transcoding is disabled', async function () {
61 await server.config.updateExistingSubConfig({
70 expectedStatus: HttpStatusCode.BAD_REQUEST_400
74 it('Should succeed to enable video studio', async function () {
75 await server.config.updateExistingSubConfig({
88 describe('Common tasks', function () {
90 it('Should fail without token', async function () {
91 await command.createEditionTasks({
94 tasks: VideoStudioCommand.getComplexTask(),
95 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
99 it('Should fail with another user token', async function () {
100 await command.createEditionTasks({
101 token: userAccessToken,
103 tasks: VideoStudioCommand.getComplexTask(),
104 expectedStatus: HttpStatusCode.FORBIDDEN_403
108 it('Should fail with an invalid video', async function () {
109 await command.createEditionTasks({
111 tasks: VideoStudioCommand.getComplexTask(),
112 expectedStatus: HttpStatusCode.BAD_REQUEST_400
116 it('Should fail with an unknown video', async function () {
117 await command.createEditionTasks({
119 tasks: VideoStudioCommand.getComplexTask(),
120 expectedStatus: HttpStatusCode.NOT_FOUND_404
124 it('Should fail with an already in transcoding state video', async function () {
127 const { uuid } = await server.videos.quickUpload({ name: 'transcoded video' })
128 await waitJobs([ server ])
130 await server.jobs.pauseJobQueue()
131 await server.videos.runTranscoding({ videoId: uuid, transcodingType: 'hls' })
133 await command.createEditionTasks({
135 tasks: VideoStudioCommand.getComplexTask(),
136 expectedStatus: HttpStatusCode.CONFLICT_409
139 await server.jobs.resumeJobQueue()
142 it('Should fail with a bad complex task', async function () {
143 await command.createEditionTasks({
161 expectedStatus: HttpStatusCode.BAD_REQUEST_400
165 it('Should fail without task', async function () {
166 await command.createEditionTasks({
169 expectedStatus: HttpStatusCode.BAD_REQUEST_400
173 it('Should fail with too many tasks', async function () {
174 const tasks: VideoStudioTask[] = []
176 for (let i = 0; i < 110; i++) {
185 await command.createEditionTasks({
188 expectedStatus: HttpStatusCode.BAD_REQUEST_400
192 it('Should succeed with correct parameters', async function () {
193 await server.jobs.pauseJobQueue()
195 await command.createEditionTasks({
197 tasks: VideoStudioCommand.getComplexTask(),
198 expectedStatus: HttpStatusCode.NO_CONTENT_204
202 it('Should fail with a video that is already waiting for edition', async function () {
205 await command.createEditionTasks({
207 tasks: VideoStudioCommand.getComplexTask(),
208 expectedStatus: HttpStatusCode.CONFLICT_409
211 await server.jobs.resumeJobQueue()
213 await waitJobs([ server ])
217 describe('Cut task', function () {
219 async function cut (start: number, end: number, expectedStatus = HttpStatusCode.BAD_REQUEST_400) {
220 await command.createEditionTasks({
235 it('Should fail with bad start/end', async function () {
242 for (const value of invalid) {
243 await cut(value as any, undefined)
244 await cut(undefined, value as any)
248 it('Should fail with the same start/end', async function () {
252 it('Should fail with inconsistents start/end', async function () {
256 it('Should fail without start and end', async function () {
257 await cut(undefined, undefined)
260 it('Should succeed with the correct params', async function () {
263 await cut(0, 2, HttpStatusCode.NO_CONTENT_204)
265 await waitJobs([ server ])
269 describe('Watermark task', function () {
271 async function addWatermark (file: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400) {
272 await command.createEditionTasks({
276 name: 'add-watermark',
286 it('Should fail without waterkmark', async function () {
287 await addWatermark(undefined)
290 it('Should fail with an invalid watermark', async function () {
291 await addWatermark('video_short.mp4')
294 it('Should succeed with the correct params', async function () {
297 await addWatermark('thumbnail.jpg', HttpStatusCode.NO_CONTENT_204)
299 await waitJobs([ server ])
303 describe('Intro/Outro task', function () {
305 async function addIntroOutro (type: 'add-intro' | 'add-outro', file: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400) {
306 await command.createEditionTasks({
320 it('Should fail without file', async function () {
321 await addIntroOutro('add-intro', undefined)
322 await addIntroOutro('add-outro', undefined)
325 it('Should fail with an invalid file', async function () {
326 await addIntroOutro('add-intro', 'thumbnail.jpg')
327 await addIntroOutro('add-outro', 'thumbnail.jpg')
330 it('Should fail with a file that does not contain video stream', async function () {
331 await addIntroOutro('add-intro', 'sample.ogg')
332 await addIntroOutro('add-outro', 'sample.ogg')
336 it('Should succeed with the correct params', async function () {
339 await addIntroOutro('add-intro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204)
340 await waitJobs([ server ])
342 await addIntroOutro('add-outro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204)
343 await waitJobs([ server ])
346 it('Should check total quota when creating the task', async function () {
349 const user = await server.users.create({ username: 'user_quota_1' })
350 const token = await server.login.getAccessToken('user_quota_1')
351 const { uuid } = await server.videos.quickUpload({ token, name: 'video_quota_1', fixture: 'video_short.mp4' })
353 const addIntroOutroByUser = (type: 'add-intro' | 'add-outro', expectedStatus: HttpStatusCode) => {
354 return command.createEditionTasks({
361 file: 'video_short.mp4'
369 await waitJobs([ server ])
371 const { videoQuotaUsed } = await server.users.getMyQuotaUsed({ token })
372 await server.users.update({ userId: user.id, videoQuota: Math.round(videoQuotaUsed * 2.5) })
375 await addIntroOutroByUser('add-intro', HttpStatusCode.NO_CONTENT_204)
377 await waitJobs([ server ])
380 await addIntroOutroByUser('add-intro', HttpStatusCode.PAYLOAD_TOO_LARGE_413)
381 await addIntroOutroByUser('add-outro', HttpStatusCode.PAYLOAD_TOO_LARGE_413)
386 after(async function () {
387 await cleanupTests([ server ])