]>
Commit | Line | Data |
---|---|---|
c729caf6 C |
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | ||
3 | import 'mocha' | |
4 | import { HttpStatusCode, VideoEditorTask } from '@shared/models' | |
5 | import { | |
6 | cleanupTests, | |
7 | createSingleServer, | |
8 | PeerTubeServer, | |
9 | setAccessTokensToServers, | |
10 | VideoEditorCommand, | |
11 | waitJobs | |
12 | } from '@shared/server-commands' | |
13 | ||
14 | describe('Test video editor API validator', function () { | |
15 | let server: PeerTubeServer | |
16 | let command: VideoEditorCommand | |
17 | let userAccessToken: string | |
18 | let videoUUID: string | |
19 | ||
20 | // --------------------------------------------------------------- | |
21 | ||
22 | before(async function () { | |
23 | this.timeout(120_000) | |
24 | ||
25 | server = await createSingleServer(1) | |
26 | ||
27 | await setAccessTokensToServers([ server ]) | |
28 | userAccessToken = await server.users.generateUserAndToken('user1') | |
29 | ||
30 | await server.config.enableMinimumTranscoding() | |
31 | ||
32 | const { uuid } = await server.videos.quickUpload({ name: 'video' }) | |
33 | videoUUID = uuid | |
34 | ||
35 | command = server.videoEditor | |
36 | ||
37 | await waitJobs([ server ]) | |
38 | }) | |
39 | ||
40 | describe('Task creation', function () { | |
41 | ||
42 | describe('Config settings', function () { | |
43 | ||
44 | it('Should fail if editor is disabled', async function () { | |
45 | await server.config.updateExistingSubConfig({ | |
46 | newConfig: { | |
47 | videoEditor: { | |
48 | enabled: false | |
49 | } | |
50 | } | |
51 | }) | |
52 | ||
53 | await command.createEditionTasks({ | |
54 | videoId: videoUUID, | |
55 | tasks: VideoEditorCommand.getComplexTask(), | |
56 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | |
57 | }) | |
58 | }) | |
59 | ||
60 | it('Should fail to enable editor if transcoding is disabled', async function () { | |
61 | await server.config.updateExistingSubConfig({ | |
62 | newConfig: { | |
63 | videoEditor: { | |
64 | enabled: true | |
65 | }, | |
66 | transcoding: { | |
67 | enabled: false | |
68 | } | |
69 | }, | |
70 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | |
71 | }) | |
72 | }) | |
73 | ||
74 | it('Should succeed to enable video editor', async function () { | |
75 | await server.config.updateExistingSubConfig({ | |
76 | newConfig: { | |
77 | videoEditor: { | |
78 | enabled: true | |
79 | }, | |
80 | transcoding: { | |
81 | enabled: true | |
82 | } | |
83 | } | |
84 | }) | |
85 | }) | |
86 | }) | |
87 | ||
88 | describe('Common tasks', function () { | |
89 | ||
90 | it('Should fail without token', async function () { | |
91 | await command.createEditionTasks({ | |
92 | token: null, | |
93 | videoId: videoUUID, | |
94 | tasks: VideoEditorCommand.getComplexTask(), | |
95 | expectedStatus: HttpStatusCode.UNAUTHORIZED_401 | |
96 | }) | |
97 | }) | |
98 | ||
99 | it('Should fail with another user token', async function () { | |
100 | await command.createEditionTasks({ | |
101 | token: userAccessToken, | |
102 | videoId: videoUUID, | |
103 | tasks: VideoEditorCommand.getComplexTask(), | |
104 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | |
105 | }) | |
106 | }) | |
107 | ||
108 | it('Should fail with an invalid video', async function () { | |
109 | await command.createEditionTasks({ | |
110 | videoId: 'tintin', | |
111 | tasks: VideoEditorCommand.getComplexTask(), | |
112 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | |
113 | }) | |
114 | }) | |
115 | ||
116 | it('Should fail with an unknown video', async function () { | |
117 | await command.createEditionTasks({ | |
118 | videoId: 42, | |
119 | tasks: VideoEditorCommand.getComplexTask(), | |
120 | expectedStatus: HttpStatusCode.NOT_FOUND_404 | |
121 | }) | |
122 | }) | |
123 | ||
124 | it('Should fail with an already in transcoding state video', async function () { | |
c729caf6 C |
125 | const { uuid } = await server.videos.quickUpload({ name: 'transcoded video' }) |
126 | ||
52fe4b67 C |
127 | await server.jobs.pauseJobQueue() |
128 | await server.videos.runTranscoding({ videoId: uuid, transcodingType: 'hls' }) | |
129 | ||
c729caf6 C |
130 | await command.createEditionTasks({ |
131 | videoId: uuid, | |
132 | tasks: VideoEditorCommand.getComplexTask(), | |
133 | expectedStatus: HttpStatusCode.CONFLICT_409 | |
134 | }) | |
135 | ||
136 | await server.jobs.resumeJobQueue() | |
137 | }) | |
138 | ||
139 | it('Should fail with a bad complex task', async function () { | |
140 | await command.createEditionTasks({ | |
141 | videoId: videoUUID, | |
142 | tasks: [ | |
143 | { | |
144 | name: 'cut', | |
145 | options: { | |
146 | start: 1, | |
147 | end: 2 | |
148 | } | |
149 | }, | |
150 | { | |
151 | name: 'hadock', | |
152 | options: { | |
153 | start: 1, | |
154 | end: 2 | |
155 | } | |
156 | } | |
157 | ] as any, | |
158 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | |
159 | }) | |
160 | }) | |
161 | ||
162 | it('Should fail without task', async function () { | |
163 | await command.createEditionTasks({ | |
164 | videoId: videoUUID, | |
165 | tasks: [], | |
166 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | |
167 | }) | |
168 | }) | |
169 | ||
170 | it('Should fail with too many tasks', async function () { | |
171 | const tasks: VideoEditorTask[] = [] | |
172 | ||
173 | for (let i = 0; i < 110; i++) { | |
174 | tasks.push({ | |
175 | name: 'cut', | |
176 | options: { | |
177 | start: 1 | |
178 | } | |
179 | }) | |
180 | } | |
181 | ||
182 | await command.createEditionTasks({ | |
183 | videoId: videoUUID, | |
184 | tasks, | |
185 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | |
186 | }) | |
187 | }) | |
188 | ||
189 | it('Should succeed with correct parameters', async function () { | |
190 | await server.jobs.pauseJobQueue() | |
191 | ||
192 | await command.createEditionTasks({ | |
193 | videoId: videoUUID, | |
194 | tasks: VideoEditorCommand.getComplexTask(), | |
195 | expectedStatus: HttpStatusCode.NO_CONTENT_204 | |
196 | }) | |
197 | }) | |
198 | ||
199 | it('Should fail with a video that is already waiting for edition', async function () { | |
200 | this.timeout(120000) | |
201 | ||
202 | await command.createEditionTasks({ | |
203 | videoId: videoUUID, | |
204 | tasks: VideoEditorCommand.getComplexTask(), | |
205 | expectedStatus: HttpStatusCode.CONFLICT_409 | |
206 | }) | |
207 | ||
208 | await server.jobs.resumeJobQueue() | |
209 | ||
210 | await waitJobs([ server ]) | |
211 | }) | |
212 | }) | |
213 | ||
214 | describe('Cut task', function () { | |
215 | ||
216 | async function cut (start: number, end: number, expectedStatus = HttpStatusCode.BAD_REQUEST_400) { | |
217 | await command.createEditionTasks({ | |
218 | videoId: videoUUID, | |
219 | tasks: [ | |
220 | { | |
221 | name: 'cut', | |
222 | options: { | |
223 | start, | |
224 | end | |
225 | } | |
226 | } | |
227 | ], | |
228 | expectedStatus | |
229 | }) | |
230 | } | |
231 | ||
232 | it('Should fail with bad start/end', async function () { | |
233 | const invalid = [ | |
234 | 'tintin', | |
235 | -1, | |
236 | undefined | |
237 | ] | |
238 | ||
239 | for (const value of invalid) { | |
240 | await cut(value as any, undefined) | |
241 | await cut(undefined, value as any) | |
242 | } | |
243 | }) | |
244 | ||
245 | it('Should fail with the same start/end', async function () { | |
246 | await cut(2, 2) | |
247 | }) | |
248 | ||
249 | it('Should fail with inconsistents start/end', async function () { | |
250 | await cut(2, 1) | |
251 | }) | |
252 | ||
253 | it('Should fail without start and end', async function () { | |
254 | await cut(undefined, undefined) | |
255 | }) | |
256 | ||
257 | it('Should succeed with the correct params', async function () { | |
258 | this.timeout(120000) | |
259 | ||
260 | await cut(0, 2, HttpStatusCode.NO_CONTENT_204) | |
261 | ||
262 | await waitJobs([ server ]) | |
263 | }) | |
264 | }) | |
265 | ||
266 | describe('Watermark task', function () { | |
267 | ||
268 | async function addWatermark (file: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400) { | |
269 | await command.createEditionTasks({ | |
270 | videoId: videoUUID, | |
271 | tasks: [ | |
272 | { | |
273 | name: 'add-watermark', | |
274 | options: { | |
275 | file | |
276 | } | |
277 | } | |
278 | ], | |
279 | expectedStatus | |
280 | }) | |
281 | } | |
282 | ||
283 | it('Should fail without waterkmark', async function () { | |
284 | await addWatermark(undefined) | |
285 | }) | |
286 | ||
287 | it('Should fail with an invalid watermark', async function () { | |
288 | await addWatermark('video_short.mp4') | |
289 | }) | |
290 | ||
291 | it('Should succeed with the correct params', async function () { | |
292 | this.timeout(120000) | |
293 | ||
294 | await addWatermark('thumbnail.jpg', HttpStatusCode.NO_CONTENT_204) | |
295 | ||
296 | await waitJobs([ server ]) | |
297 | }) | |
298 | }) | |
299 | ||
300 | describe('Intro/Outro task', function () { | |
301 | ||
302 | async function addIntroOutro (type: 'add-intro' | 'add-outro', file: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400) { | |
303 | await command.createEditionTasks({ | |
304 | videoId: videoUUID, | |
305 | tasks: [ | |
306 | { | |
307 | name: type, | |
308 | options: { | |
309 | file | |
310 | } | |
311 | } | |
312 | ], | |
313 | expectedStatus | |
314 | }) | |
315 | } | |
316 | ||
317 | it('Should fail without file', async function () { | |
318 | await addIntroOutro('add-intro', undefined) | |
319 | await addIntroOutro('add-outro', undefined) | |
320 | }) | |
321 | ||
322 | it('Should fail with an invalid file', async function () { | |
323 | await addIntroOutro('add-intro', 'thumbnail.jpg') | |
324 | await addIntroOutro('add-outro', 'thumbnail.jpg') | |
325 | }) | |
326 | ||
327 | it('Should fail with a file that does not contain video stream', async function () { | |
328 | await addIntroOutro('add-intro', 'sample.ogg') | |
329 | await addIntroOutro('add-outro', 'sample.ogg') | |
330 | ||
331 | }) | |
332 | ||
333 | it('Should succeed with the correct params', async function () { | |
334 | this.timeout(120000) | |
335 | ||
336 | await addIntroOutro('add-intro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204) | |
337 | await waitJobs([ server ]) | |
338 | ||
339 | await addIntroOutro('add-outro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204) | |
340 | await waitJobs([ server ]) | |
341 | }) | |
342 | ||
343 | it('Should check total quota when creating the task', async function () { | |
344 | this.timeout(120000) | |
345 | ||
346 | const user = await server.users.create({ username: 'user_quota_1' }) | |
347 | const token = await server.login.getAccessToken('user_quota_1') | |
348 | const { uuid } = await server.videos.quickUpload({ token, name: 'video_quota_1', fixture: 'video_short.mp4' }) | |
349 | ||
350 | const addIntroOutroByUser = (type: 'add-intro' | 'add-outro', expectedStatus: HttpStatusCode) => { | |
351 | return command.createEditionTasks({ | |
352 | token, | |
353 | videoId: uuid, | |
354 | tasks: [ | |
355 | { | |
356 | name: type, | |
357 | options: { | |
358 | file: 'video_short.mp4' | |
359 | } | |
360 | } | |
361 | ], | |
362 | expectedStatus | |
363 | }) | |
364 | } | |
365 | ||
366 | await waitJobs([ server ]) | |
367 | ||
368 | const { videoQuotaUsed } = await server.users.getMyQuotaUsed({ token }) | |
369 | await server.users.update({ userId: user.id, videoQuota: Math.round(videoQuotaUsed * 2.5) }) | |
370 | ||
371 | // Still valid | |
372 | await addIntroOutroByUser('add-intro', HttpStatusCode.NO_CONTENT_204) | |
373 | ||
374 | await waitJobs([ server ]) | |
375 | ||
376 | // Too much quota | |
377 | await addIntroOutroByUser('add-intro', HttpStatusCode.PAYLOAD_TOO_LARGE_413) | |
378 | await addIntroOutroByUser('add-outro', HttpStatusCode.PAYLOAD_TOO_LARGE_413) | |
379 | }) | |
380 | }) | |
381 | }) | |
382 | ||
383 | after(async function () { | |
384 | await cleanupTests([ server ]) | |
385 | }) | |
386 | }) |