aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/api/videos/video-transcoder.ts
diff options
context:
space:
mode:
authorkontrollanten <6680299+kontrollanten@users.noreply.github.com>2021-05-10 11:13:41 +0200
committerGitHub <noreply@github.com>2021-05-10 11:13:41 +0200
commitf6d6e7f861189a4446f406efb775a29688764b48 (patch)
treec3dda9958c3f189d4c39e8743c738d8c1fef4c2d /server/tests/api/videos/video-transcoder.ts
parentd29ced1a8582d99b776f664475a157adcf555d98 (diff)
downloadPeerTube-f6d6e7f861189a4446f406efb775a29688764b48.tar.gz
PeerTube-f6d6e7f861189a4446f406efb775a29688764b48.tar.zst
PeerTube-f6d6e7f861189a4446f406efb775a29688764b48.zip
Resumable video uploads (#3933)
* WIP: resumable video uploads relates to #324 * fix review comments * video upload: error handling * fix audio upload * fixes after self review * Update server/controllers/api/videos/index.ts Co-authored-by: Rigel Kent <par@rigelk.eu> * Update server/middlewares/validators/videos/videos.ts Co-authored-by: Rigel Kent <par@rigelk.eu> * Update server/controllers/api/videos/index.ts Co-authored-by: Rigel Kent <par@rigelk.eu> * update after code review * refactor upload route - restore multipart upload route - move resumable to dedicated upload-resumable route - move checks to middleware - do not leak internal fs structure in response * fix yarn.lock upon rebase * factorize addVideo for reuse in both endpoints * add resumable upload API to openapi spec * add initial test and test helper for resumable upload * typings for videoAddResumable middleware * avoid including aws and google packages via node-uploadx, by only including uploadx/core * rename ex-isAudioBg to more explicit name mentioning it is a preview file for audio * add video-upload-tmp-folder-cleaner job * stronger typing of video upload middleware * reduce dependency to @uploadx/core * add audio upload test * refactor resumable uploads cleanup from job to scheduler * refactor resumable uploads scheduler to compare to last execution time * make resumable upload validator to always cleanup on failure * move legacy upload request building outside of uploadVideo test helper * filter upload-resumable middlewares down to POST, PUT, DELETE also begin to type metadata * merge add duration functions * stronger typings and documentation for uploadx behaviour, move init validator up * refactor(client/video-edit): options > uploadxOptions * refactor(client/video-edit): remove obsolete else * scheduler/remove-dangling-resum: rename tag * refactor(server/video): add UploadVideoFiles type * refactor(mw/validators): restructure eslint disable * refactor(mw/validators/videos): rename import * refactor(client/vid-upload): rename html elem id * refactor(sched/remove-dangl): move fn to method * refactor(mw/async): add method typing * refactor(mw/vali/video): double quote > single * refactor(server/upload-resum): express use > all * proper http methud enum server/middlewares/async.ts * properly type http methods * factorize common video upload validation steps * add check for maximum partially uploaded file size * fix audioBg use * fix extname(filename) in addVideo * document parameters for uploadx's resumable protocol * clear META files in scheduler * last audio refactor before cramming preview in the initial POST form data * refactor as mulitpart/form-data initial post request this allows preview/thumbnail uploads alongside the initial request, and cleans up the upload form * Add more tests for resumable uploads * Refactor remove dangling resumable uploads * Prepare changelog * Add more resumable upload tests * Remove user quota check for resumable uploads * Fix upload error handler * Update nginx template for upload-resumable * Cleanup comment * Remove unused express methods * Prefer to use got instead of raw http * Don't retry on error 500 Co-authored-by: Rigel Kent <par@rigelk.eu> Co-authored-by: Rigel Kent <sendmemail@rigelk.eu> Co-authored-by: Chocobozzz <me@florianbigard.com>
Diffstat (limited to 'server/tests/api/videos/video-transcoder.ts')
-rw-r--r--server/tests/api/videos/video-transcoder.ts159
1 files changed, 85 insertions, 74 deletions
diff --git a/server/tests/api/videos/video-transcoder.ts b/server/tests/api/videos/video-transcoder.ts
index 1c99f26df..ea5ffd239 100644
--- a/server/tests/api/videos/video-transcoder.ts
+++ b/server/tests/api/videos/video-transcoder.ts
@@ -361,106 +361,117 @@ describe('Test video transcoding', function () {
361 361
362 describe('Audio upload', function () { 362 describe('Audio upload', function () {
363 363
364 before(async function () { 364 function runSuite (mode: 'legacy' | 'resumable') {
365 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, { 365
366 transcoding: { 366 before(async function () {
367 hls: { enabled: true }, 367 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, {
368 webtorrent: { enabled: true }, 368 transcoding: {
369 resolutions: { 369 hls: { enabled: true },
370 '0p': false, 370 webtorrent: { enabled: true },
371 '240p': false, 371 resolutions: {
372 '360p': false, 372 '0p': false,
373 '480p': false, 373 '240p': false,
374 '720p': false, 374 '360p': false,
375 '1080p': false, 375 '480p': false,
376 '1440p': false, 376 '720p': false,
377 '2160p': false 377 '1080p': false,
378 '1440p': false,
379 '2160p': false
380 }
378 } 381 }
379 } 382 })
380 }) 383 })
381 })
382
383 it('Should merge an audio file with the preview file', async function () {
384 this.timeout(60_000)
385
386 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' }
387 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg)
388 384
389 await waitJobs(servers) 385 it('Should merge an audio file with the preview file', async function () {
386 this.timeout(60_000)
390 387
391 for (const server of servers) { 388 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' }
392 const res = await getVideosList(server.url) 389 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg, HttpStatusCode.OK_200, mode)
393 390
394 const video = res.body.data.find(v => v.name === 'audio_with_preview') 391 await waitJobs(servers)
395 const res2 = await getVideo(server.url, video.id)
396 const videoDetails: VideoDetails = res2.body
397 392
398 expect(videoDetails.files).to.have.lengthOf(1) 393 for (const server of servers) {
394 const res = await getVideosList(server.url)
399 395
400 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: HttpStatusCode.OK_200 }) 396 const video = res.body.data.find(v => v.name === 'audio_with_preview')
401 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: HttpStatusCode.OK_200 }) 397 const res2 = await getVideo(server.url, video.id)
398 const videoDetails: VideoDetails = res2.body
402 399
403 const magnetUri = videoDetails.files[0].magnetUri 400 expect(videoDetails.files).to.have.lengthOf(1)
404 expect(magnetUri).to.contain('.mp4')
405 }
406 })
407 401
408 it('Should upload an audio file and choose a default background image', async function () { 402 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: HttpStatusCode.OK_200 })
409 this.timeout(60_000) 403 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: HttpStatusCode.OK_200 })
410 404
411 const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' } 405 const magnetUri = videoDetails.files[0].magnetUri
412 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg) 406 expect(magnetUri).to.contain('.mp4')
407 }
408 })
413 409
414 await waitJobs(servers) 410 it('Should upload an audio file and choose a default background image', async function () {
411 this.timeout(60_000)
415 412
416 for (const server of servers) { 413 const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' }
417 const res = await getVideosList(server.url) 414 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg, HttpStatusCode.OK_200, mode)
418 415
419 const video = res.body.data.find(v => v.name === 'audio_without_preview') 416 await waitJobs(servers)
420 const res2 = await getVideo(server.url, video.id)
421 const videoDetails = res2.body
422 417
423 expect(videoDetails.files).to.have.lengthOf(1) 418 for (const server of servers) {
419 const res = await getVideosList(server.url)
424 420
425 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: HttpStatusCode.OK_200 }) 421 const video = res.body.data.find(v => v.name === 'audio_without_preview')
426 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: HttpStatusCode.OK_200 }) 422 const res2 = await getVideo(server.url, video.id)
423 const videoDetails = res2.body
427 424
428 const magnetUri = videoDetails.files[0].magnetUri 425 expect(videoDetails.files).to.have.lengthOf(1)
429 expect(magnetUri).to.contain('.mp4')
430 }
431 })
432 426
433 it('Should upload an audio file and create an audio version only', async function () { 427 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: HttpStatusCode.OK_200 })
434 this.timeout(60_000) 428 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: HttpStatusCode.OK_200 })
435 429
436 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, { 430 const magnetUri = videoDetails.files[0].magnetUri
437 transcoding: { 431 expect(magnetUri).to.contain('.mp4')
438 hls: { enabled: true },
439 webtorrent: { enabled: true },
440 resolutions: {
441 '0p': true,
442 '240p': false,
443 '360p': false
444 }
445 } 432 }
446 }) 433 })
447 434
448 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } 435 it('Should upload an audio file and create an audio version only', async function () {
449 const resVideo = await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg) 436 this.timeout(60_000)
437
438 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, {
439 transcoding: {
440 hls: { enabled: true },
441 webtorrent: { enabled: true },
442 resolutions: {
443 '0p': true,
444 '240p': false,
445 '360p': false
446 }
447 }
448 })
450 449
451 await waitJobs(servers) 450 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' }
451 const resVideo = await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg, HttpStatusCode.OK_200, mode)
452 452
453 for (const server of servers) { 453 await waitJobs(servers)
454 const res2 = await getVideo(server.url, resVideo.body.video.id) 454
455 const videoDetails: VideoDetails = res2.body 455 for (const server of servers) {
456 const res2 = await getVideo(server.url, resVideo.body.video.id)
457 const videoDetails: VideoDetails = res2.body
456 458
457 for (const files of [ videoDetails.files, videoDetails.streamingPlaylists[0].files ]) { 459 for (const files of [ videoDetails.files, videoDetails.streamingPlaylists[0].files ]) {
458 expect(files).to.have.lengthOf(2) 460 expect(files).to.have.lengthOf(2)
459 expect(files.find(f => f.resolution.id === 0)).to.not.be.undefined 461 expect(files.find(f => f.resolution.id === 0)).to.not.be.undefined
462 }
460 } 463 }
461 }
462 464
463 await updateConfigForTranscoding(servers[1]) 465 await updateConfigForTranscoding(servers[1])
466 })
467 }
468
469 describe('Legacy upload', function () {
470 runSuite('legacy')
471 })
472
473 describe('Resumable upload', function () {
474 runSuite('resumable')
464 }) 475 })
465 }) 476 })
466 477