diff options
Diffstat (limited to 'server/tests/api/check-params')
-rw-r--r-- | server/tests/api/check-params/config.ts | 3 | ||||
-rw-r--r-- | server/tests/api/check-params/index.ts | 1 | ||||
-rw-r--r-- | server/tests/api/check-params/video-editor.ts | 385 |
3 files changed, 389 insertions, 0 deletions
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts index 3cccb612a..ce067a892 100644 --- a/server/tests/api/check-params/config.ts +++ b/server/tests/api/check-params/config.ts | |||
@@ -145,6 +145,9 @@ describe('Test config API validators', function () { | |||
145 | } | 145 | } |
146 | } | 146 | } |
147 | }, | 147 | }, |
148 | videoEditor: { | ||
149 | enabled: true | ||
150 | }, | ||
148 | import: { | 151 | import: { |
149 | videos: { | 152 | videos: { |
150 | concurrency: 1, | 153 | concurrency: 1, |
diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts index e052296db..c088b52cd 100644 --- a/server/tests/api/check-params/index.ts +++ b/server/tests/api/check-params/index.ts | |||
@@ -25,6 +25,7 @@ import './video-blacklist' | |||
25 | import './video-captions' | 25 | import './video-captions' |
26 | import './video-channels' | 26 | import './video-channels' |
27 | import './video-comments' | 27 | import './video-comments' |
28 | import './video-editor' | ||
28 | import './video-imports' | 29 | import './video-imports' |
29 | import './video-playlists' | 30 | import './video-playlists' |
30 | import './videos' | 31 | import './videos' |
diff --git a/server/tests/api/check-params/video-editor.ts b/server/tests/api/check-params/video-editor.ts new file mode 100644 index 000000000..db284a3cc --- /dev/null +++ b/server/tests/api/check-params/video-editor.ts | |||
@@ -0,0 +1,385 @@ | |||
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 () { | ||
125 | await server.jobs.pauseJobQueue() | ||
126 | |||
127 | const { uuid } = await server.videos.quickUpload({ name: 'transcoded video' }) | ||
128 | |||
129 | await command.createEditionTasks({ | ||
130 | videoId: uuid, | ||
131 | tasks: VideoEditorCommand.getComplexTask(), | ||
132 | expectedStatus: HttpStatusCode.CONFLICT_409 | ||
133 | }) | ||
134 | |||
135 | await server.jobs.resumeJobQueue() | ||
136 | }) | ||
137 | |||
138 | it('Should fail with a bad complex task', async function () { | ||
139 | await command.createEditionTasks({ | ||
140 | videoId: videoUUID, | ||
141 | tasks: [ | ||
142 | { | ||
143 | name: 'cut', | ||
144 | options: { | ||
145 | start: 1, | ||
146 | end: 2 | ||
147 | } | ||
148 | }, | ||
149 | { | ||
150 | name: 'hadock', | ||
151 | options: { | ||
152 | start: 1, | ||
153 | end: 2 | ||
154 | } | ||
155 | } | ||
156 | ] as any, | ||
157 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
158 | }) | ||
159 | }) | ||
160 | |||
161 | it('Should fail without task', async function () { | ||
162 | await command.createEditionTasks({ | ||
163 | videoId: videoUUID, | ||
164 | tasks: [], | ||
165 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
166 | }) | ||
167 | }) | ||
168 | |||
169 | it('Should fail with too many tasks', async function () { | ||
170 | const tasks: VideoEditorTask[] = [] | ||
171 | |||
172 | for (let i = 0; i < 110; i++) { | ||
173 | tasks.push({ | ||
174 | name: 'cut', | ||
175 | options: { | ||
176 | start: 1 | ||
177 | } | ||
178 | }) | ||
179 | } | ||
180 | |||
181 | await command.createEditionTasks({ | ||
182 | videoId: videoUUID, | ||
183 | tasks, | ||
184 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
185 | }) | ||
186 | }) | ||
187 | |||
188 | it('Should succeed with correct parameters', async function () { | ||
189 | await server.jobs.pauseJobQueue() | ||
190 | |||
191 | await command.createEditionTasks({ | ||
192 | videoId: videoUUID, | ||
193 | tasks: VideoEditorCommand.getComplexTask(), | ||
194 | expectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
195 | }) | ||
196 | }) | ||
197 | |||
198 | it('Should fail with a video that is already waiting for edition', async function () { | ||
199 | this.timeout(120000) | ||
200 | |||
201 | await command.createEditionTasks({ | ||
202 | videoId: videoUUID, | ||
203 | tasks: VideoEditorCommand.getComplexTask(), | ||
204 | expectedStatus: HttpStatusCode.CONFLICT_409 | ||
205 | }) | ||
206 | |||
207 | await server.jobs.resumeJobQueue() | ||
208 | |||
209 | await waitJobs([ server ]) | ||
210 | }) | ||
211 | }) | ||
212 | |||
213 | describe('Cut task', function () { | ||
214 | |||
215 | async function cut (start: number, end: number, expectedStatus = HttpStatusCode.BAD_REQUEST_400) { | ||
216 | await command.createEditionTasks({ | ||
217 | videoId: videoUUID, | ||
218 | tasks: [ | ||
219 | { | ||
220 | name: 'cut', | ||
221 | options: { | ||
222 | start, | ||
223 | end | ||
224 | } | ||
225 | } | ||
226 | ], | ||
227 | expectedStatus | ||
228 | }) | ||
229 | } | ||
230 | |||
231 | it('Should fail with bad start/end', async function () { | ||
232 | const invalid = [ | ||
233 | 'tintin', | ||
234 | -1, | ||
235 | undefined | ||
236 | ] | ||
237 | |||
238 | for (const value of invalid) { | ||
239 | await cut(value as any, undefined) | ||
240 | await cut(undefined, value as any) | ||
241 | } | ||
242 | }) | ||
243 | |||
244 | it('Should fail with the same start/end', async function () { | ||
245 | await cut(2, 2) | ||
246 | }) | ||
247 | |||
248 | it('Should fail with inconsistents start/end', async function () { | ||
249 | await cut(2, 1) | ||
250 | }) | ||
251 | |||
252 | it('Should fail without start and end', async function () { | ||
253 | await cut(undefined, undefined) | ||
254 | }) | ||
255 | |||
256 | it('Should succeed with the correct params', async function () { | ||
257 | this.timeout(120000) | ||
258 | |||
259 | await cut(0, 2, HttpStatusCode.NO_CONTENT_204) | ||
260 | |||
261 | await waitJobs([ server ]) | ||
262 | }) | ||
263 | }) | ||
264 | |||
265 | describe('Watermark task', function () { | ||
266 | |||
267 | async function addWatermark (file: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400) { | ||
268 | await command.createEditionTasks({ | ||
269 | videoId: videoUUID, | ||
270 | tasks: [ | ||
271 | { | ||
272 | name: 'add-watermark', | ||
273 | options: { | ||
274 | file | ||
275 | } | ||
276 | } | ||
277 | ], | ||
278 | expectedStatus | ||
279 | }) | ||
280 | } | ||
281 | |||
282 | it('Should fail without waterkmark', async function () { | ||
283 | await addWatermark(undefined) | ||
284 | }) | ||
285 | |||
286 | it('Should fail with an invalid watermark', async function () { | ||
287 | await addWatermark('video_short.mp4') | ||
288 | }) | ||
289 | |||
290 | it('Should succeed with the correct params', async function () { | ||
291 | this.timeout(120000) | ||
292 | |||
293 | await addWatermark('thumbnail.jpg', HttpStatusCode.NO_CONTENT_204) | ||
294 | |||
295 | await waitJobs([ server ]) | ||
296 | }) | ||
297 | }) | ||
298 | |||
299 | describe('Intro/Outro task', function () { | ||
300 | |||
301 | async function addIntroOutro (type: 'add-intro' | 'add-outro', file: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400) { | ||
302 | await command.createEditionTasks({ | ||
303 | videoId: videoUUID, | ||
304 | tasks: [ | ||
305 | { | ||
306 | name: type, | ||
307 | options: { | ||
308 | file | ||
309 | } | ||
310 | } | ||
311 | ], | ||
312 | expectedStatus | ||
313 | }) | ||
314 | } | ||
315 | |||
316 | it('Should fail without file', async function () { | ||
317 | await addIntroOutro('add-intro', undefined) | ||
318 | await addIntroOutro('add-outro', undefined) | ||
319 | }) | ||
320 | |||
321 | it('Should fail with an invalid file', async function () { | ||
322 | await addIntroOutro('add-intro', 'thumbnail.jpg') | ||
323 | await addIntroOutro('add-outro', 'thumbnail.jpg') | ||
324 | }) | ||
325 | |||
326 | it('Should fail with a file that does not contain video stream', async function () { | ||
327 | await addIntroOutro('add-intro', 'sample.ogg') | ||
328 | await addIntroOutro('add-outro', 'sample.ogg') | ||
329 | |||
330 | }) | ||
331 | |||
332 | it('Should succeed with the correct params', async function () { | ||
333 | this.timeout(120000) | ||
334 | |||
335 | await addIntroOutro('add-intro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204) | ||
336 | await waitJobs([ server ]) | ||
337 | |||
338 | await addIntroOutro('add-outro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204) | ||
339 | await waitJobs([ server ]) | ||
340 | }) | ||
341 | |||
342 | it('Should check total quota when creating the task', async function () { | ||
343 | this.timeout(120000) | ||
344 | |||
345 | const user = await server.users.create({ username: 'user_quota_1' }) | ||
346 | const token = await server.login.getAccessToken('user_quota_1') | ||
347 | const { uuid } = await server.videos.quickUpload({ token, name: 'video_quota_1', fixture: 'video_short.mp4' }) | ||
348 | |||
349 | const addIntroOutroByUser = (type: 'add-intro' | 'add-outro', expectedStatus: HttpStatusCode) => { | ||
350 | return command.createEditionTasks({ | ||
351 | token, | ||
352 | videoId: uuid, | ||
353 | tasks: [ | ||
354 | { | ||
355 | name: type, | ||
356 | options: { | ||
357 | file: 'video_short.mp4' | ||
358 | } | ||
359 | } | ||
360 | ], | ||
361 | expectedStatus | ||
362 | }) | ||
363 | } | ||
364 | |||
365 | await waitJobs([ server ]) | ||
366 | |||
367 | const { videoQuotaUsed } = await server.users.getMyQuotaUsed({ token }) | ||
368 | await server.users.update({ userId: user.id, videoQuota: Math.round(videoQuotaUsed * 2.5) }) | ||
369 | |||
370 | // Still valid | ||
371 | await addIntroOutroByUser('add-intro', HttpStatusCode.NO_CONTENT_204) | ||
372 | |||
373 | await waitJobs([ server ]) | ||
374 | |||
375 | // Too much quota | ||
376 | await addIntroOutroByUser('add-intro', HttpStatusCode.PAYLOAD_TOO_LARGE_413) | ||
377 | await addIntroOutroByUser('add-outro', HttpStatusCode.PAYLOAD_TOO_LARGE_413) | ||
378 | }) | ||
379 | }) | ||
380 | }) | ||
381 | |||
382 | after(async function () { | ||
383 | await cleanupTests([ server ]) | ||
384 | }) | ||
385 | }) | ||