1
0
Fork 0
peertube/server/tests/api/check-params/upload-quota.ts
kontrollanten f6d6e7f861
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>
2021-05-10 11:13:41 +02:00

152 lines
5.3 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import { expect } from 'chai'
import { HttpStatusCode, randomInt } from '@shared/core-utils'
import { getGoodVideoUrl, getMagnetURI, getMyVideoImports, importVideo } from '@shared/extra-utils/videos/video-imports'
import { MyUser, VideoImport, VideoImportState, VideoPrivacy } from '@shared/models'
import {
cleanupTests,
flushAndRunServer,
getMyUserInformation,
immutableAssign,
registerUser,
ServerInfo,
setAccessTokensToServers,
setDefaultVideoChannel,
updateUser,
uploadVideo,
userLogin,
waitJobs
} from '../../../../shared/extra-utils'
describe('Test upload quota', function () {
let server: ServerInfo
let rootId: number
// ---------------------------------------------------------------
before(async function () {
this.timeout(30000)
server = await flushAndRunServer(1)
await setAccessTokensToServers([ server ])
await setDefaultVideoChannel([ server ])
const res = await getMyUserInformation(server.url, server.accessToken)
rootId = (res.body as MyUser).id
await updateUser({
url: server.url,
userId: rootId,
accessToken: server.accessToken,
videoQuota: 42
})
})
describe('When having a video quota', function () {
it('Should fail with a registered user having too many videos with legacy upload', async function () {
this.timeout(30000)
const user = { username: 'registered' + randomInt(1, 1500), password: 'password' }
await registerUser(server.url, user.username, user.password)
const userAccessToken = await userLogin(server, user)
const videoAttributes = { fixture: 'video_short2.webm' }
for (let i = 0; i < 5; i++) {
await uploadVideo(server.url, userAccessToken, videoAttributes)
}
await uploadVideo(server.url, userAccessToken, videoAttributes, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'legacy')
})
it('Should fail with a registered user having too many videos with resumable upload', async function () {
this.timeout(30000)
const user = { username: 'registered' + randomInt(1, 1500), password: 'password' }
await registerUser(server.url, user.username, user.password)
const userAccessToken = await userLogin(server, user)
const videoAttributes = { fixture: 'video_short2.webm' }
for (let i = 0; i < 5; i++) {
await uploadVideo(server.url, userAccessToken, videoAttributes)
}
await uploadVideo(server.url, userAccessToken, videoAttributes, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'resumable')
})
it('Should fail to import with HTTP/Torrent/magnet', async function () {
this.timeout(120000)
const baseAttributes = {
channelId: server.videoChannel.id,
privacy: VideoPrivacy.PUBLIC
}
await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { targetUrl: getGoodVideoUrl() }))
await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { magnetUri: getMagnetURI() }))
await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { torrentfile: 'video-720p.torrent' as any }))
await waitJobs([ server ])
const res = await getMyVideoImports(server.url, server.accessToken)
expect(res.body.total).to.equal(3)
const videoImports: VideoImport[] = res.body.data
expect(videoImports).to.have.lengthOf(3)
for (const videoImport of videoImports) {
expect(videoImport.state.id).to.equal(VideoImportState.FAILED)
expect(videoImport.error).not.to.be.undefined
expect(videoImport.error).to.contain('user video quota is exceeded')
}
})
})
describe('When having a daily video quota', function () {
it('Should fail with a user having too many videos daily', async function () {
await updateUser({
url: server.url,
userId: rootId,
accessToken: server.accessToken,
videoQuotaDaily: 42
})
await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'legacy')
await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'resumable')
})
})
describe('When having an absolute and daily video quota', function () {
it('Should fail if exceeding total quota', async function () {
await updateUser({
url: server.url,
userId: rootId,
accessToken: server.accessToken,
videoQuota: 42,
videoQuotaDaily: 1024 * 1024 * 1024
})
await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'legacy')
await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'resumable')
})
it('Should fail if exceeding daily quota', async function () {
await updateUser({
url: server.url,
userId: rootId,
accessToken: server.accessToken,
videoQuota: 1024 * 1024 * 1024,
videoQuotaDaily: 42
})
await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'legacy')
await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'resumable')
})
})
after(async function () {
await cleanupTests([ server ])
})
})