diff options
Diffstat (limited to 'server/tests/api/check-params/runners.ts')
-rw-r--r-- | server/tests/api/check-params/runners.ts | 910 |
1 files changed, 0 insertions, 910 deletions
diff --git a/server/tests/api/check-params/runners.ts b/server/tests/api/check-params/runners.ts deleted file mode 100644 index 0e5012da5..000000000 --- a/server/tests/api/check-params/runners.ts +++ /dev/null | |||
@@ -1,910 +0,0 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | import { basename } from 'path' | ||
3 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' | ||
4 | import { | ||
5 | HttpStatusCode, | ||
6 | isVideoStudioTaskIntro, | ||
7 | RunnerJob, | ||
8 | RunnerJobState, | ||
9 | RunnerJobStudioTranscodingPayload, | ||
10 | RunnerJobSuccessPayload, | ||
11 | RunnerJobUpdatePayload, | ||
12 | VideoPrivacy, | ||
13 | VideoStudioTaskIntro | ||
14 | } from '@shared/models' | ||
15 | import { | ||
16 | cleanupTests, | ||
17 | createSingleServer, | ||
18 | makePostBodyRequest, | ||
19 | PeerTubeServer, | ||
20 | sendRTMPStream, | ||
21 | setAccessTokensToServers, | ||
22 | setDefaultVideoChannel, | ||
23 | stopFfmpeg, | ||
24 | VideoStudioCommand, | ||
25 | waitJobs | ||
26 | } from '@shared/server-commands' | ||
27 | |||
28 | const badUUID = '910ec12a-d9e6-458b-a274-0abb655f9464' | ||
29 | |||
30 | describe('Test managing runners', function () { | ||
31 | let server: PeerTubeServer | ||
32 | |||
33 | let userToken: string | ||
34 | |||
35 | let registrationTokenId: number | ||
36 | let registrationToken: string | ||
37 | |||
38 | let runnerToken: string | ||
39 | let runnerToken2: string | ||
40 | |||
41 | let completedJobToken: string | ||
42 | let completedJobUUID: string | ||
43 | |||
44 | let cancelledJobToken: string | ||
45 | let cancelledJobUUID: string | ||
46 | |||
47 | before(async function () { | ||
48 | this.timeout(120000) | ||
49 | |||
50 | const config = { | ||
51 | rates_limit: { | ||
52 | api: { | ||
53 | max: 5000 | ||
54 | } | ||
55 | } | ||
56 | } | ||
57 | |||
58 | server = await createSingleServer(1, config) | ||
59 | await setAccessTokensToServers([ server ]) | ||
60 | await setDefaultVideoChannel([ server ]) | ||
61 | |||
62 | userToken = await server.users.generateUserAndToken('user1') | ||
63 | |||
64 | const { data } = await server.runnerRegistrationTokens.list() | ||
65 | registrationToken = data[0].registrationToken | ||
66 | registrationTokenId = data[0].id | ||
67 | |||
68 | await server.config.enableTranscoding({ hls: true, webVideo: true }) | ||
69 | await server.config.enableStudio() | ||
70 | await server.config.enableRemoteTranscoding() | ||
71 | await server.config.enableRemoteStudio() | ||
72 | |||
73 | runnerToken = await server.runners.autoRegisterRunner() | ||
74 | runnerToken2 = await server.runners.autoRegisterRunner() | ||
75 | |||
76 | { | ||
77 | await server.videos.quickUpload({ name: 'video 1' }) | ||
78 | await server.videos.quickUpload({ name: 'video 2' }) | ||
79 | |||
80 | await waitJobs([ server ]) | ||
81 | |||
82 | { | ||
83 | const job = await server.runnerJobs.autoProcessWebVideoJob(runnerToken) | ||
84 | completedJobToken = job.jobToken | ||
85 | completedJobUUID = job.uuid | ||
86 | } | ||
87 | |||
88 | { | ||
89 | const { job } = await server.runnerJobs.autoAccept({ runnerToken }) | ||
90 | cancelledJobToken = job.jobToken | ||
91 | cancelledJobUUID = job.uuid | ||
92 | await server.runnerJobs.cancelByAdmin({ jobUUID: cancelledJobUUID }) | ||
93 | } | ||
94 | } | ||
95 | }) | ||
96 | |||
97 | describe('Managing runner registration tokens', function () { | ||
98 | |||
99 | describe('Common', function () { | ||
100 | |||
101 | it('Should fail to generate, list or delete runner registration token without oauth token', async function () { | ||
102 | const expectedStatus = HttpStatusCode.UNAUTHORIZED_401 | ||
103 | |||
104 | await server.runnerRegistrationTokens.generate({ token: null, expectedStatus }) | ||
105 | await server.runnerRegistrationTokens.list({ token: null, expectedStatus }) | ||
106 | await server.runnerRegistrationTokens.delete({ token: null, id: registrationTokenId, expectedStatus }) | ||
107 | }) | ||
108 | |||
109 | it('Should fail to generate, list or delete runner registration token without admin rights', async function () { | ||
110 | const expectedStatus = HttpStatusCode.FORBIDDEN_403 | ||
111 | |||
112 | await server.runnerRegistrationTokens.generate({ token: userToken, expectedStatus }) | ||
113 | await server.runnerRegistrationTokens.list({ token: userToken, expectedStatus }) | ||
114 | await server.runnerRegistrationTokens.delete({ token: userToken, id: registrationTokenId, expectedStatus }) | ||
115 | }) | ||
116 | }) | ||
117 | |||
118 | describe('Delete', function () { | ||
119 | |||
120 | it('Should fail to delete with a bad id', async function () { | ||
121 | await server.runnerRegistrationTokens.delete({ id: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
122 | }) | ||
123 | }) | ||
124 | |||
125 | describe('List', function () { | ||
126 | const path = '/api/v1/runners/registration-tokens' | ||
127 | |||
128 | it('Should fail to list with a bad start pagination', async function () { | ||
129 | await checkBadStartPagination(server.url, path, server.accessToken) | ||
130 | }) | ||
131 | |||
132 | it('Should fail to list with a bad count pagination', async function () { | ||
133 | await checkBadCountPagination(server.url, path, server.accessToken) | ||
134 | }) | ||
135 | |||
136 | it('Should fail to list with an incorrect sort', async function () { | ||
137 | await checkBadSortPagination(server.url, path, server.accessToken) | ||
138 | }) | ||
139 | |||
140 | it('Should succeed to list with the correct params', async function () { | ||
141 | await server.runnerRegistrationTokens.list({ start: 0, count: 5, sort: '-createdAt' }) | ||
142 | }) | ||
143 | }) | ||
144 | }) | ||
145 | |||
146 | describe('Managing runners', function () { | ||
147 | let toDeleteId: number | ||
148 | |||
149 | describe('Register', function () { | ||
150 | const name = 'runner name' | ||
151 | |||
152 | it('Should fail with a bad registration token', async function () { | ||
153 | const expectedStatus = HttpStatusCode.BAD_REQUEST_400 | ||
154 | |||
155 | await server.runners.register({ name, registrationToken: 'a'.repeat(4000), expectedStatus }) | ||
156 | await server.runners.register({ name, registrationToken: null, expectedStatus }) | ||
157 | }) | ||
158 | |||
159 | it('Should fail with an unknown registration token', async function () { | ||
160 | await server.runners.register({ name, registrationToken: 'aaa', expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
161 | }) | ||
162 | |||
163 | it('Should fail with a bad name', async function () { | ||
164 | const expectedStatus = HttpStatusCode.BAD_REQUEST_400 | ||
165 | |||
166 | await server.runners.register({ name: '', registrationToken, expectedStatus }) | ||
167 | await server.runners.register({ name: 'a'.repeat(200), registrationToken, expectedStatus }) | ||
168 | }) | ||
169 | |||
170 | it('Should fail with an invalid description', async function () { | ||
171 | const expectedStatus = HttpStatusCode.BAD_REQUEST_400 | ||
172 | |||
173 | await server.runners.register({ name, description: '', registrationToken, expectedStatus }) | ||
174 | await server.runners.register({ name, description: 'a'.repeat(5000), registrationToken, expectedStatus }) | ||
175 | }) | ||
176 | |||
177 | it('Should succeed with the correct params', async function () { | ||
178 | const { id } = await server.runners.register({ name, description: 'super description', registrationToken }) | ||
179 | |||
180 | toDeleteId = id | ||
181 | }) | ||
182 | |||
183 | it('Should fail with the same runner name', async function () { | ||
184 | await server.runners.register({ | ||
185 | name, | ||
186 | description: 'super description', | ||
187 | registrationToken, | ||
188 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
189 | }) | ||
190 | }) | ||
191 | }) | ||
192 | |||
193 | describe('Delete', function () { | ||
194 | |||
195 | it('Should fail without oauth token', async function () { | ||
196 | await server.runners.delete({ token: null, id: toDeleteId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) | ||
197 | }) | ||
198 | |||
199 | it('Should fail without admin rights', async function () { | ||
200 | await server.runners.delete({ token: userToken, id: toDeleteId, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
201 | }) | ||
202 | |||
203 | it('Should fail with a bad id', async function () { | ||
204 | await server.runners.delete({ id: 'hi' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
205 | }) | ||
206 | |||
207 | it('Should fail with an unknown id', async function () { | ||
208 | await server.runners.delete({ id: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
209 | }) | ||
210 | |||
211 | it('Should succeed with the correct params', async function () { | ||
212 | await server.runners.delete({ id: toDeleteId }) | ||
213 | }) | ||
214 | }) | ||
215 | |||
216 | describe('List', function () { | ||
217 | const path = '/api/v1/runners' | ||
218 | |||
219 | it('Should fail without oauth token', async function () { | ||
220 | await server.runners.list({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) | ||
221 | }) | ||
222 | |||
223 | it('Should fail without admin rights', async function () { | ||
224 | await server.runners.list({ token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
225 | }) | ||
226 | |||
227 | it('Should fail to list with a bad start pagination', async function () { | ||
228 | await checkBadStartPagination(server.url, path, server.accessToken) | ||
229 | }) | ||
230 | |||
231 | it('Should fail to list with a bad count pagination', async function () { | ||
232 | await checkBadCountPagination(server.url, path, server.accessToken) | ||
233 | }) | ||
234 | |||
235 | it('Should fail to list with an incorrect sort', async function () { | ||
236 | await checkBadSortPagination(server.url, path, server.accessToken) | ||
237 | }) | ||
238 | |||
239 | it('Should fail with an invalid state', async function () { | ||
240 | await server.runners.list({ start: 0, count: 5, sort: '-createdAt' }) | ||
241 | }) | ||
242 | |||
243 | it('Should succeed to list with the correct params', async function () { | ||
244 | await server.runners.list({ start: 0, count: 5, sort: '-createdAt' }) | ||
245 | }) | ||
246 | }) | ||
247 | |||
248 | }) | ||
249 | |||
250 | describe('Runner jobs by admin', function () { | ||
251 | |||
252 | describe('Cancel', function () { | ||
253 | let jobUUID: string | ||
254 | |||
255 | before(async function () { | ||
256 | this.timeout(60000) | ||
257 | |||
258 | await server.videos.quickUpload({ name: 'video' }) | ||
259 | await waitJobs([ server ]) | ||
260 | |||
261 | const { availableJobs } = await server.runnerJobs.request({ runnerToken }) | ||
262 | jobUUID = availableJobs[0].uuid | ||
263 | }) | ||
264 | |||
265 | it('Should fail without oauth token', async function () { | ||
266 | await server.runnerJobs.cancelByAdmin({ token: null, jobUUID, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) | ||
267 | }) | ||
268 | |||
269 | it('Should fail without admin rights', async function () { | ||
270 | await server.runnerJobs.cancelByAdmin({ token: userToken, jobUUID, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
271 | }) | ||
272 | |||
273 | it('Should fail with a bad job uuid', async function () { | ||
274 | await server.runnerJobs.cancelByAdmin({ jobUUID: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
275 | }) | ||
276 | |||
277 | it('Should fail with an unknown job uuid', async function () { | ||
278 | const jobUUID = badUUID | ||
279 | await server.runnerJobs.cancelByAdmin({ jobUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
280 | }) | ||
281 | |||
282 | it('Should fail with an already cancelled job', async function () { | ||
283 | await server.runnerJobs.cancelByAdmin({ jobUUID: cancelledJobUUID, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
284 | }) | ||
285 | |||
286 | it('Should succeed with the correct params', async function () { | ||
287 | await server.runnerJobs.cancelByAdmin({ jobUUID }) | ||
288 | }) | ||
289 | }) | ||
290 | |||
291 | describe('List', function () { | ||
292 | const path = '/api/v1/runners/jobs' | ||
293 | |||
294 | it('Should fail without oauth token', async function () { | ||
295 | await server.runnerJobs.list({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) | ||
296 | }) | ||
297 | |||
298 | it('Should fail without admin rights', async function () { | ||
299 | await server.runnerJobs.list({ token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
300 | }) | ||
301 | |||
302 | it('Should fail to list with a bad start pagination', async function () { | ||
303 | await checkBadStartPagination(server.url, path, server.accessToken) | ||
304 | }) | ||
305 | |||
306 | it('Should fail to list with a bad count pagination', async function () { | ||
307 | await checkBadCountPagination(server.url, path, server.accessToken) | ||
308 | }) | ||
309 | |||
310 | it('Should fail to list with an incorrect sort', async function () { | ||
311 | await checkBadSortPagination(server.url, path, server.accessToken) | ||
312 | }) | ||
313 | |||
314 | it('Should fail with an invalid state', async function () { | ||
315 | await server.runnerJobs.list({ start: 0, count: 5, sort: '-createdAt', stateOneOf: 42 as any }) | ||
316 | await server.runnerJobs.list({ start: 0, count: 5, sort: '-createdAt', stateOneOf: [ 42 ] as any }) | ||
317 | }) | ||
318 | |||
319 | it('Should succeed with the correct params', async function () { | ||
320 | await server.runnerJobs.list({ start: 0, count: 5, sort: '-createdAt', stateOneOf: [ RunnerJobState.COMPLETED ] }) | ||
321 | }) | ||
322 | }) | ||
323 | |||
324 | describe('Delete', function () { | ||
325 | let jobUUID: string | ||
326 | |||
327 | before(async function () { | ||
328 | this.timeout(60000) | ||
329 | |||
330 | await server.videos.quickUpload({ name: 'video' }) | ||
331 | await waitJobs([ server ]) | ||
332 | |||
333 | const { availableJobs } = await server.runnerJobs.request({ runnerToken }) | ||
334 | jobUUID = availableJobs[0].uuid | ||
335 | }) | ||
336 | |||
337 | it('Should fail without oauth token', async function () { | ||
338 | await server.runnerJobs.deleteByAdmin({ token: null, jobUUID, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) | ||
339 | }) | ||
340 | |||
341 | it('Should fail without admin rights', async function () { | ||
342 | await server.runnerJobs.deleteByAdmin({ token: userToken, jobUUID, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
343 | }) | ||
344 | |||
345 | it('Should fail with a bad job uuid', async function () { | ||
346 | await server.runnerJobs.deleteByAdmin({ jobUUID: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
347 | }) | ||
348 | |||
349 | it('Should fail with an unknown job uuid', async function () { | ||
350 | const jobUUID = badUUID | ||
351 | await server.runnerJobs.deleteByAdmin({ jobUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
352 | }) | ||
353 | |||
354 | it('Should succeed with the correct params', async function () { | ||
355 | await server.runnerJobs.deleteByAdmin({ jobUUID }) | ||
356 | }) | ||
357 | }) | ||
358 | |||
359 | }) | ||
360 | |||
361 | describe('Runner jobs by runners', function () { | ||
362 | let jobUUID: string | ||
363 | let jobToken: string | ||
364 | let videoUUID: string | ||
365 | |||
366 | let jobUUID2: string | ||
367 | let jobToken2: string | ||
368 | |||
369 | let videoUUID2: string | ||
370 | |||
371 | let pendingUUID: string | ||
372 | |||
373 | let videoStudioUUID: string | ||
374 | let studioFile: string | ||
375 | |||
376 | let liveAcceptedJob: RunnerJob & { jobToken: string } | ||
377 | let studioAcceptedJob: RunnerJob & { jobToken: string } | ||
378 | |||
379 | async function fetchVideoInputFiles (options: { | ||
380 | jobUUID: string | ||
381 | videoUUID: string | ||
382 | runnerToken: string | ||
383 | jobToken: string | ||
384 | expectedStatus: HttpStatusCode | ||
385 | }) { | ||
386 | const { jobUUID, expectedStatus, videoUUID, runnerToken, jobToken } = options | ||
387 | |||
388 | const basePath = '/api/v1/runners/jobs/' + jobUUID + '/files/videos/' + videoUUID | ||
389 | const paths = [ `${basePath}/max-quality`, `${basePath}/previews/max-quality` ] | ||
390 | |||
391 | for (const path of paths) { | ||
392 | await makePostBodyRequest({ url: server.url, path, fields: { runnerToken, jobToken }, expectedStatus }) | ||
393 | } | ||
394 | } | ||
395 | |||
396 | async function fetchStudioFiles (options: { | ||
397 | jobUUID: string | ||
398 | videoUUID: string | ||
399 | runnerToken: string | ||
400 | jobToken: string | ||
401 | studioFile?: string | ||
402 | expectedStatus: HttpStatusCode | ||
403 | }) { | ||
404 | const { jobUUID, expectedStatus, videoUUID, runnerToken, jobToken, studioFile } = options | ||
405 | |||
406 | const path = `/api/v1/runners/jobs/${jobUUID}/files/videos/${videoUUID}/studio/task-files/${studioFile}` | ||
407 | |||
408 | await makePostBodyRequest({ url: server.url, path, fields: { runnerToken, jobToken }, expectedStatus }) | ||
409 | } | ||
410 | |||
411 | before(async function () { | ||
412 | this.timeout(120000) | ||
413 | |||
414 | { | ||
415 | await server.runnerJobs.cancelAllJobs({ state: RunnerJobState.PENDING }) | ||
416 | } | ||
417 | |||
418 | { | ||
419 | const { uuid } = await server.videos.quickUpload({ name: 'video' }) | ||
420 | videoUUID = uuid | ||
421 | |||
422 | await waitJobs([ server ]) | ||
423 | |||
424 | const { job } = await server.runnerJobs.autoAccept({ runnerToken }) | ||
425 | jobUUID = job.uuid | ||
426 | jobToken = job.jobToken | ||
427 | } | ||
428 | |||
429 | { | ||
430 | const { uuid } = await server.videos.quickUpload({ name: 'video' }) | ||
431 | videoUUID2 = uuid | ||
432 | |||
433 | await waitJobs([ server ]) | ||
434 | |||
435 | const { job } = await server.runnerJobs.autoAccept({ runnerToken: runnerToken2 }) | ||
436 | jobUUID2 = job.uuid | ||
437 | jobToken2 = job.jobToken | ||
438 | } | ||
439 | |||
440 | { | ||
441 | await server.videos.quickUpload({ name: 'video' }) | ||
442 | await waitJobs([ server ]) | ||
443 | |||
444 | const { availableJobs } = await server.runnerJobs.request({ runnerToken }) | ||
445 | pendingUUID = availableJobs[0].uuid | ||
446 | } | ||
447 | |||
448 | { | ||
449 | await server.config.disableTranscoding() | ||
450 | |||
451 | const { uuid } = await server.videos.quickUpload({ name: 'video studio' }) | ||
452 | videoStudioUUID = uuid | ||
453 | |||
454 | await server.config.enableTranscoding({ hls: true, webVideo: true }) | ||
455 | await server.config.enableStudio() | ||
456 | |||
457 | await server.videoStudio.createEditionTasks({ | ||
458 | videoId: videoStudioUUID, | ||
459 | tasks: VideoStudioCommand.getComplexTask() | ||
460 | }) | ||
461 | |||
462 | const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'video-studio-transcoding' }) | ||
463 | studioAcceptedJob = job | ||
464 | |||
465 | const tasks = (job.payload as RunnerJobStudioTranscodingPayload).tasks | ||
466 | const fileUrl = (tasks.find(t => isVideoStudioTaskIntro(t)) as VideoStudioTaskIntro).options.file as string | ||
467 | studioFile = basename(fileUrl) | ||
468 | } | ||
469 | |||
470 | { | ||
471 | await server.config.enableLive({ | ||
472 | allowReplay: false, | ||
473 | resolutions: 'max', | ||
474 | transcoding: true | ||
475 | }) | ||
476 | |||
477 | const { live } = await server.live.quickCreate({ permanentLive: true, saveReplay: false, privacy: VideoPrivacy.PUBLIC }) | ||
478 | |||
479 | const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) | ||
480 | await waitJobs([ server ]) | ||
481 | |||
482 | await server.runnerJobs.requestLiveJob(runnerToken) | ||
483 | |||
484 | const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'live-rtmp-hls-transcoding' }) | ||
485 | liveAcceptedJob = job | ||
486 | |||
487 | await stopFfmpeg(ffmpegCommand) | ||
488 | } | ||
489 | }) | ||
490 | |||
491 | describe('Common runner tokens validations', function () { | ||
492 | |||
493 | async function testEndpoints (options: { | ||
494 | jobUUID: string | ||
495 | runnerToken: string | ||
496 | jobToken: string | ||
497 | expectedStatus: HttpStatusCode | ||
498 | }) { | ||
499 | await server.runnerJobs.abort({ ...options, reason: 'reason' }) | ||
500 | await server.runnerJobs.update({ ...options }) | ||
501 | await server.runnerJobs.error({ ...options, message: 'message' }) | ||
502 | await server.runnerJobs.success({ ...options, payload: { videoFile: 'video_short.mp4' } }) | ||
503 | } | ||
504 | |||
505 | it('Should fail with an invalid job uuid', async function () { | ||
506 | const options = { jobUUID: 'a', runnerToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 } | ||
507 | |||
508 | await testEndpoints({ ...options, jobToken }) | ||
509 | await fetchVideoInputFiles({ ...options, videoUUID, jobToken }) | ||
510 | await fetchStudioFiles({ ...options, videoUUID, jobToken: studioAcceptedJob.jobToken, studioFile }) | ||
511 | }) | ||
512 | |||
513 | it('Should fail with an unknown job uuid', async function () { | ||
514 | const options = { jobUUID: badUUID, runnerToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 } | ||
515 | |||
516 | await testEndpoints({ ...options, jobToken }) | ||
517 | await fetchVideoInputFiles({ ...options, videoUUID, jobToken }) | ||
518 | await fetchStudioFiles({ ...options, jobToken: studioAcceptedJob.jobToken, videoUUID, studioFile }) | ||
519 | }) | ||
520 | |||
521 | it('Should fail with an invalid runner token', async function () { | ||
522 | const options = { runnerToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 } | ||
523 | |||
524 | await testEndpoints({ ...options, jobUUID, jobToken }) | ||
525 | await fetchVideoInputFiles({ ...options, jobUUID, videoUUID, jobToken }) | ||
526 | await fetchStudioFiles({ | ||
527 | ...options, | ||
528 | jobToken: studioAcceptedJob.jobToken, | ||
529 | jobUUID: studioAcceptedJob.uuid, | ||
530 | videoUUID: videoStudioUUID, | ||
531 | studioFile | ||
532 | }) | ||
533 | }) | ||
534 | |||
535 | it('Should fail with an unknown runner token', async function () { | ||
536 | const options = { runnerToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 } | ||
537 | |||
538 | await testEndpoints({ ...options, jobUUID, jobToken }) | ||
539 | await fetchVideoInputFiles({ ...options, jobUUID, videoUUID, jobToken }) | ||
540 | await fetchStudioFiles({ | ||
541 | ...options, | ||
542 | jobToken: studioAcceptedJob.jobToken, | ||
543 | jobUUID: studioAcceptedJob.uuid, | ||
544 | videoUUID: videoStudioUUID, | ||
545 | studioFile | ||
546 | }) | ||
547 | }) | ||
548 | |||
549 | it('Should fail with an invalid job token job uuid', async function () { | ||
550 | const options = { runnerToken, jobToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 } | ||
551 | |||
552 | await testEndpoints({ ...options, jobUUID }) | ||
553 | await fetchVideoInputFiles({ ...options, jobUUID, videoUUID }) | ||
554 | await fetchStudioFiles({ ...options, jobUUID: studioAcceptedJob.uuid, videoUUID: videoStudioUUID, studioFile }) | ||
555 | }) | ||
556 | |||
557 | it('Should fail with an unknown job token job uuid', async function () { | ||
558 | const options = { runnerToken, jobToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 } | ||
559 | |||
560 | await testEndpoints({ ...options, jobUUID }) | ||
561 | await fetchVideoInputFiles({ ...options, jobUUID, videoUUID }) | ||
562 | await fetchStudioFiles({ ...options, jobUUID: studioAcceptedJob.uuid, videoUUID: videoStudioUUID, studioFile }) | ||
563 | }) | ||
564 | |||
565 | it('Should fail with a runner token not associated to this job', async function () { | ||
566 | const options = { runnerToken: runnerToken2, expectedStatus: HttpStatusCode.NOT_FOUND_404 } | ||
567 | |||
568 | await testEndpoints({ ...options, jobUUID, jobToken }) | ||
569 | await fetchVideoInputFiles({ ...options, jobUUID, videoUUID, jobToken }) | ||
570 | await fetchStudioFiles({ | ||
571 | ...options, | ||
572 | jobToken: studioAcceptedJob.jobToken, | ||
573 | jobUUID: studioAcceptedJob.uuid, | ||
574 | videoUUID: videoStudioUUID, | ||
575 | studioFile | ||
576 | }) | ||
577 | }) | ||
578 | |||
579 | it('Should fail with a job uuid not associated to the job token', async function () { | ||
580 | { | ||
581 | const options = { jobUUID: jobUUID2, runnerToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 } | ||
582 | |||
583 | await testEndpoints({ ...options, jobToken }) | ||
584 | await fetchVideoInputFiles({ ...options, jobToken, videoUUID }) | ||
585 | await fetchStudioFiles({ ...options, jobToken: studioAcceptedJob.jobToken, videoUUID: videoStudioUUID, studioFile }) | ||
586 | } | ||
587 | |||
588 | { | ||
589 | const options = { runnerToken, jobToken: jobToken2, expectedStatus: HttpStatusCode.NOT_FOUND_404 } | ||
590 | |||
591 | await testEndpoints({ ...options, jobUUID }) | ||
592 | await fetchVideoInputFiles({ ...options, jobUUID, videoUUID }) | ||
593 | await fetchStudioFiles({ ...options, jobUUID: studioAcceptedJob.uuid, videoUUID: videoStudioUUID, studioFile }) | ||
594 | } | ||
595 | }) | ||
596 | }) | ||
597 | |||
598 | describe('Unregister', function () { | ||
599 | |||
600 | it('Should fail without a runner token', async function () { | ||
601 | await server.runners.unregister({ runnerToken: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
602 | }) | ||
603 | |||
604 | it('Should fail with a bad a runner token', async function () { | ||
605 | await server.runners.unregister({ runnerToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
606 | }) | ||
607 | |||
608 | it('Should fail with an unknown runner token', async function () { | ||
609 | await server.runners.unregister({ runnerToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
610 | }) | ||
611 | }) | ||
612 | |||
613 | describe('Request', function () { | ||
614 | |||
615 | it('Should fail without a runner token', async function () { | ||
616 | await server.runnerJobs.request({ runnerToken: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
617 | }) | ||
618 | |||
619 | it('Should fail with a bad a runner token', async function () { | ||
620 | await server.runnerJobs.request({ runnerToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
621 | }) | ||
622 | |||
623 | it('Should fail with an unknown runner token', async function () { | ||
624 | await server.runnerJobs.request({ runnerToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
625 | }) | ||
626 | }) | ||
627 | |||
628 | describe('Accept', function () { | ||
629 | |||
630 | it('Should fail with a bad a job uuid', async function () { | ||
631 | await server.runnerJobs.accept({ jobUUID: '', runnerToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
632 | }) | ||
633 | |||
634 | it('Should fail with an unknown job uuid', async function () { | ||
635 | await server.runnerJobs.accept({ jobUUID: badUUID, runnerToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
636 | }) | ||
637 | |||
638 | it('Should fail with a job not in pending state', async function () { | ||
639 | await server.runnerJobs.accept({ jobUUID: completedJobUUID, runnerToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
640 | await server.runnerJobs.accept({ jobUUID: cancelledJobUUID, runnerToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
641 | }) | ||
642 | |||
643 | it('Should fail without a runner token', async function () { | ||
644 | await server.runnerJobs.accept({ jobUUID: pendingUUID, runnerToken: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
645 | }) | ||
646 | |||
647 | it('Should fail with a bad a runner token', async function () { | ||
648 | await server.runnerJobs.accept({ jobUUID: pendingUUID, runnerToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
649 | }) | ||
650 | |||
651 | it('Should fail with an unknown runner token', async function () { | ||
652 | await server.runnerJobs.accept({ jobUUID: pendingUUID, runnerToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
653 | }) | ||
654 | }) | ||
655 | |||
656 | describe('Abort', function () { | ||
657 | |||
658 | it('Should fail without a reason', async function () { | ||
659 | await server.runnerJobs.abort({ jobUUID, jobToken, runnerToken, reason: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
660 | }) | ||
661 | |||
662 | it('Should fail with a bad reason', async function () { | ||
663 | const reason = 'reason'.repeat(5000) | ||
664 | await server.runnerJobs.abort({ jobUUID, jobToken, runnerToken, reason, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
665 | }) | ||
666 | |||
667 | it('Should fail with a job not in processing state', async function () { | ||
668 | await server.runnerJobs.abort({ | ||
669 | jobUUID: completedJobUUID, | ||
670 | jobToken: completedJobToken, | ||
671 | runnerToken, | ||
672 | reason: 'reason', | ||
673 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
674 | }) | ||
675 | }) | ||
676 | }) | ||
677 | |||
678 | describe('Update', function () { | ||
679 | |||
680 | describe('Common', function () { | ||
681 | |||
682 | it('Should fail with an invalid progress', async function () { | ||
683 | await server.runnerJobs.update({ jobUUID, jobToken, runnerToken, progress: 101, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
684 | }) | ||
685 | |||
686 | it('Should fail with a job not in processing state', async function () { | ||
687 | await server.runnerJobs.update({ | ||
688 | jobUUID: cancelledJobUUID, | ||
689 | jobToken: cancelledJobToken, | ||
690 | runnerToken, | ||
691 | expectedStatus: HttpStatusCode.NOT_FOUND_404 | ||
692 | }) | ||
693 | }) | ||
694 | }) | ||
695 | |||
696 | describe('Live RTMP to HLS', function () { | ||
697 | const base: RunnerJobUpdatePayload = { | ||
698 | masterPlaylistFile: 'live/master.m3u8', | ||
699 | resolutionPlaylistFilename: '0.m3u8', | ||
700 | resolutionPlaylistFile: 'live/1.m3u8', | ||
701 | type: 'add-chunk', | ||
702 | videoChunkFile: 'live/1-000069.ts', | ||
703 | videoChunkFilename: '1-000068.ts' | ||
704 | } | ||
705 | |||
706 | function testUpdate (payload: RunnerJobUpdatePayload) { | ||
707 | return server.runnerJobs.update({ | ||
708 | jobUUID: liveAcceptedJob.uuid, | ||
709 | jobToken: liveAcceptedJob.jobToken, | ||
710 | payload, | ||
711 | runnerToken, | ||
712 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
713 | }) | ||
714 | } | ||
715 | |||
716 | it('Should fail with an invalid resolutionPlaylistFilename', async function () { | ||
717 | await testUpdate({ ...base, resolutionPlaylistFilename: undefined }) | ||
718 | await testUpdate({ ...base, resolutionPlaylistFilename: 'coucou/hello' }) | ||
719 | await testUpdate({ ...base, resolutionPlaylistFilename: 'hello' }) | ||
720 | }) | ||
721 | |||
722 | it('Should fail with an invalid videoChunkFilename', async function () { | ||
723 | await testUpdate({ ...base, resolutionPlaylistFilename: undefined }) | ||
724 | await testUpdate({ ...base, resolutionPlaylistFilename: 'coucou/hello' }) | ||
725 | await testUpdate({ ...base, resolutionPlaylistFilename: 'hello' }) | ||
726 | }) | ||
727 | |||
728 | it('Should fail with an invalid type', async function () { | ||
729 | await testUpdate({ ...base, type: undefined }) | ||
730 | await testUpdate({ ...base, type: 'toto' as any }) | ||
731 | }) | ||
732 | }) | ||
733 | }) | ||
734 | |||
735 | describe('Error', function () { | ||
736 | |||
737 | it('Should fail with a missing error message', async function () { | ||
738 | await server.runnerJobs.error({ jobUUID, jobToken, runnerToken, message: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
739 | }) | ||
740 | |||
741 | it('Should fail with an invalid error messgae', async function () { | ||
742 | const message = 'a'.repeat(6000) | ||
743 | await server.runnerJobs.error({ jobUUID, jobToken, runnerToken, message, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
744 | }) | ||
745 | |||
746 | it('Should fail with a job not in processing state', async function () { | ||
747 | await server.runnerJobs.error({ | ||
748 | jobUUID: completedJobUUID, | ||
749 | jobToken: completedJobToken, | ||
750 | message: 'my message', | ||
751 | runnerToken, | ||
752 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
753 | }) | ||
754 | }) | ||
755 | }) | ||
756 | |||
757 | describe('Success', function () { | ||
758 | let vodJobUUID: string | ||
759 | let vodJobToken: string | ||
760 | |||
761 | describe('Common', function () { | ||
762 | |||
763 | it('Should fail with a job not in processing state', async function () { | ||
764 | await server.runnerJobs.success({ | ||
765 | jobUUID: completedJobUUID, | ||
766 | jobToken: completedJobToken, | ||
767 | payload: { videoFile: 'video_short.mp4' }, | ||
768 | runnerToken, | ||
769 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
770 | }) | ||
771 | }) | ||
772 | }) | ||
773 | |||
774 | describe('VOD', function () { | ||
775 | |||
776 | it('Should fail with an invalid vod web video payload', async function () { | ||
777 | const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'vod-web-video-transcoding' }) | ||
778 | |||
779 | await server.runnerJobs.success({ | ||
780 | jobUUID: job.uuid, | ||
781 | jobToken: job.jobToken, | ||
782 | payload: { hello: 'video_short.mp4' } as any, | ||
783 | runnerToken, | ||
784 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
785 | }) | ||
786 | |||
787 | vodJobUUID = job.uuid | ||
788 | vodJobToken = job.jobToken | ||
789 | }) | ||
790 | |||
791 | it('Should fail with an invalid vod hls payload', async function () { | ||
792 | // To create HLS jobs | ||
793 | const payload: RunnerJobSuccessPayload = { videoFile: 'video_short.mp4' } | ||
794 | await server.runnerJobs.success({ runnerToken, jobUUID: vodJobUUID, jobToken: vodJobToken, payload }) | ||
795 | |||
796 | await waitJobs([ server ]) | ||
797 | |||
798 | const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'vod-hls-transcoding' }) | ||
799 | |||
800 | await server.runnerJobs.success({ | ||
801 | jobUUID: job.uuid, | ||
802 | jobToken: job.jobToken, | ||
803 | payload: { videoFile: 'video_short.mp4' } as any, | ||
804 | runnerToken, | ||
805 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
806 | }) | ||
807 | }) | ||
808 | |||
809 | it('Should fail with an invalid vod audio merge payload', async function () { | ||
810 | const attributes = { name: 'audio_with_preview', previewfile: 'custom-preview.jpg', fixture: 'sample.ogg' } | ||
811 | await server.videos.upload({ attributes, mode: 'legacy' }) | ||
812 | |||
813 | await waitJobs([ server ]) | ||
814 | |||
815 | const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'vod-audio-merge-transcoding' }) | ||
816 | |||
817 | await server.runnerJobs.success({ | ||
818 | jobUUID: job.uuid, | ||
819 | jobToken: job.jobToken, | ||
820 | payload: { hello: 'video_short.mp4' } as any, | ||
821 | runnerToken, | ||
822 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
823 | }) | ||
824 | }) | ||
825 | }) | ||
826 | |||
827 | describe('Video studio', function () { | ||
828 | |||
829 | it('Should fail with an invalid video studio transcoding payload', async function () { | ||
830 | await server.runnerJobs.success({ | ||
831 | jobUUID: studioAcceptedJob.uuid, | ||
832 | jobToken: studioAcceptedJob.jobToken, | ||
833 | payload: { hello: 'video_short.mp4' } as any, | ||
834 | runnerToken, | ||
835 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
836 | }) | ||
837 | }) | ||
838 | }) | ||
839 | }) | ||
840 | |||
841 | describe('Job files', function () { | ||
842 | |||
843 | describe('Check video param for common job file routes', function () { | ||
844 | |||
845 | async function fetchFiles (options: { | ||
846 | videoUUID?: string | ||
847 | expectedStatus: HttpStatusCode | ||
848 | }) { | ||
849 | await fetchVideoInputFiles({ videoUUID, ...options, jobToken, jobUUID, runnerToken }) | ||
850 | |||
851 | await fetchStudioFiles({ | ||
852 | videoUUID: videoStudioUUID, | ||
853 | |||
854 | ...options, | ||
855 | |||
856 | jobToken: studioAcceptedJob.jobToken, | ||
857 | jobUUID: studioAcceptedJob.uuid, | ||
858 | runnerToken, | ||
859 | studioFile | ||
860 | }) | ||
861 | } | ||
862 | |||
863 | it('Should fail with an invalid video id', async function () { | ||
864 | await fetchFiles({ | ||
865 | videoUUID: 'a', | ||
866 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
867 | }) | ||
868 | }) | ||
869 | |||
870 | it('Should fail with an unknown video id', async function () { | ||
871 | const videoUUID = '910ec12a-d9e6-458b-a274-0abb655f9464' | ||
872 | |||
873 | await fetchFiles({ | ||
874 | videoUUID, | ||
875 | expectedStatus: HttpStatusCode.NOT_FOUND_404 | ||
876 | }) | ||
877 | }) | ||
878 | |||
879 | it('Should fail with a video id not associated to this job', async function () { | ||
880 | await fetchFiles({ | ||
881 | videoUUID: videoUUID2, | ||
882 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
883 | }) | ||
884 | }) | ||
885 | |||
886 | it('Should succeed with the correct params', async function () { | ||
887 | await fetchFiles({ expectedStatus: HttpStatusCode.OK_200 }) | ||
888 | }) | ||
889 | }) | ||
890 | |||
891 | describe('Video studio tasks file routes', function () { | ||
892 | |||
893 | it('Should fail with an invalid studio filename', async function () { | ||
894 | await fetchStudioFiles({ | ||
895 | videoUUID: videoStudioUUID, | ||
896 | jobUUID: studioAcceptedJob.uuid, | ||
897 | runnerToken, | ||
898 | jobToken: studioAcceptedJob.jobToken, | ||
899 | studioFile: 'toto', | ||
900 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
901 | }) | ||
902 | }) | ||
903 | }) | ||
904 | }) | ||
905 | }) | ||
906 | |||
907 | after(async function () { | ||
908 | await cleanupTests([ server ]) | ||
909 | }) | ||
910 | }) | ||