aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/api/check-params/runners.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/tests/api/check-params/runners.ts')
-rw-r--r--server/tests/api/check-params/runners.ts910
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 */
2import { basename } from 'path'
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
4import {
5 HttpStatusCode,
6 isVideoStudioTaskIntro,
7 RunnerJob,
8 RunnerJobState,
9 RunnerJobStudioTranscodingPayload,
10 RunnerJobSuccessPayload,
11 RunnerJobUpdatePayload,
12 VideoPrivacy,
13 VideoStudioTaskIntro
14} from '@shared/models'
15import {
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
28const badUUID = '910ec12a-d9e6-458b-a274-0abb655f9464'
29
30describe('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})