diff options
author | kontrollanten <6680299+kontrollanten@users.noreply.github.com> | 2021-05-10 11:13:41 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-10 11:13:41 +0200 |
commit | f6d6e7f861189a4446f406efb775a29688764b48 (patch) | |
tree | c3dda9958c3f189d4c39e8743c738d8c1fef4c2d /server/tests/api/check-params | |
parent | d29ced1a8582d99b776f664475a157adcf555d98 (diff) | |
download | PeerTube-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/check-params')
-rw-r--r-- | server/tests/api/check-params/index.ts | 1 | ||||
-rw-r--r-- | server/tests/api/check-params/upload-quota.ts | 152 | ||||
-rw-r--r-- | server/tests/api/check-params/users.ts | 105 | ||||
-rw-r--r-- | server/tests/api/check-params/videos.ts | 393 |
4 files changed, 346 insertions, 305 deletions
diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts index d0b0b9c21..143515838 100644 --- a/server/tests/api/check-params/index.ts +++ b/server/tests/api/check-params/index.ts | |||
@@ -13,6 +13,7 @@ import './plugins' | |||
13 | import './redundancy' | 13 | import './redundancy' |
14 | import './search' | 14 | import './search' |
15 | import './services' | 15 | import './services' |
16 | import './upload-quota' | ||
16 | import './user-notifications' | 17 | import './user-notifications' |
17 | import './user-subscriptions' | 18 | import './user-subscriptions' |
18 | import './users' | 19 | import './users' |
diff --git a/server/tests/api/check-params/upload-quota.ts b/server/tests/api/check-params/upload-quota.ts new file mode 100644 index 000000000..d0fbec415 --- /dev/null +++ b/server/tests/api/check-params/upload-quota.ts | |||
@@ -0,0 +1,152 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import 'mocha' | ||
4 | import { expect } from 'chai' | ||
5 | import { HttpStatusCode, randomInt } from '@shared/core-utils' | ||
6 | import { getGoodVideoUrl, getMagnetURI, getMyVideoImports, importVideo } from '@shared/extra-utils/videos/video-imports' | ||
7 | import { MyUser, VideoImport, VideoImportState, VideoPrivacy } from '@shared/models' | ||
8 | import { | ||
9 | cleanupTests, | ||
10 | flushAndRunServer, | ||
11 | getMyUserInformation, | ||
12 | immutableAssign, | ||
13 | registerUser, | ||
14 | ServerInfo, | ||
15 | setAccessTokensToServers, | ||
16 | setDefaultVideoChannel, | ||
17 | updateUser, | ||
18 | uploadVideo, | ||
19 | userLogin, | ||
20 | waitJobs | ||
21 | } from '../../../../shared/extra-utils' | ||
22 | |||
23 | describe('Test upload quota', function () { | ||
24 | let server: ServerInfo | ||
25 | let rootId: number | ||
26 | |||
27 | // --------------------------------------------------------------- | ||
28 | |||
29 | before(async function () { | ||
30 | this.timeout(30000) | ||
31 | |||
32 | server = await flushAndRunServer(1) | ||
33 | await setAccessTokensToServers([ server ]) | ||
34 | await setDefaultVideoChannel([ server ]) | ||
35 | |||
36 | const res = await getMyUserInformation(server.url, server.accessToken) | ||
37 | rootId = (res.body as MyUser).id | ||
38 | |||
39 | await updateUser({ | ||
40 | url: server.url, | ||
41 | userId: rootId, | ||
42 | accessToken: server.accessToken, | ||
43 | videoQuota: 42 | ||
44 | }) | ||
45 | }) | ||
46 | |||
47 | describe('When having a video quota', function () { | ||
48 | |||
49 | it('Should fail with a registered user having too many videos with legacy upload', async function () { | ||
50 | this.timeout(30000) | ||
51 | |||
52 | const user = { username: 'registered' + randomInt(1, 1500), password: 'password' } | ||
53 | await registerUser(server.url, user.username, user.password) | ||
54 | const userAccessToken = await userLogin(server, user) | ||
55 | |||
56 | const videoAttributes = { fixture: 'video_short2.webm' } | ||
57 | for (let i = 0; i < 5; i++) { | ||
58 | await uploadVideo(server.url, userAccessToken, videoAttributes) | ||
59 | } | ||
60 | |||
61 | await uploadVideo(server.url, userAccessToken, videoAttributes, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'legacy') | ||
62 | }) | ||
63 | |||
64 | it('Should fail with a registered user having too many videos with resumable upload', async function () { | ||
65 | this.timeout(30000) | ||
66 | |||
67 | const user = { username: 'registered' + randomInt(1, 1500), password: 'password' } | ||
68 | await registerUser(server.url, user.username, user.password) | ||
69 | const userAccessToken = await userLogin(server, user) | ||
70 | |||
71 | const videoAttributes = { fixture: 'video_short2.webm' } | ||
72 | for (let i = 0; i < 5; i++) { | ||
73 | await uploadVideo(server.url, userAccessToken, videoAttributes) | ||
74 | } | ||
75 | |||
76 | await uploadVideo(server.url, userAccessToken, videoAttributes, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'resumable') | ||
77 | }) | ||
78 | |||
79 | it('Should fail to import with HTTP/Torrent/magnet', async function () { | ||
80 | this.timeout(120000) | ||
81 | |||
82 | const baseAttributes = { | ||
83 | channelId: server.videoChannel.id, | ||
84 | privacy: VideoPrivacy.PUBLIC | ||
85 | } | ||
86 | await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { targetUrl: getGoodVideoUrl() })) | ||
87 | await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { magnetUri: getMagnetURI() })) | ||
88 | await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { torrentfile: 'video-720p.torrent' as any })) | ||
89 | |||
90 | await waitJobs([ server ]) | ||
91 | |||
92 | const res = await getMyVideoImports(server.url, server.accessToken) | ||
93 | |||
94 | expect(res.body.total).to.equal(3) | ||
95 | const videoImports: VideoImport[] = res.body.data | ||
96 | expect(videoImports).to.have.lengthOf(3) | ||
97 | |||
98 | for (const videoImport of videoImports) { | ||
99 | expect(videoImport.state.id).to.equal(VideoImportState.FAILED) | ||
100 | expect(videoImport.error).not.to.be.undefined | ||
101 | expect(videoImport.error).to.contain('user video quota is exceeded') | ||
102 | } | ||
103 | }) | ||
104 | }) | ||
105 | |||
106 | describe('When having a daily video quota', function () { | ||
107 | |||
108 | it('Should fail with a user having too many videos daily', async function () { | ||
109 | await updateUser({ | ||
110 | url: server.url, | ||
111 | userId: rootId, | ||
112 | accessToken: server.accessToken, | ||
113 | videoQuotaDaily: 42 | ||
114 | }) | ||
115 | |||
116 | await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'legacy') | ||
117 | await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'resumable') | ||
118 | }) | ||
119 | }) | ||
120 | |||
121 | describe('When having an absolute and daily video quota', function () { | ||
122 | it('Should fail if exceeding total quota', async function () { | ||
123 | await updateUser({ | ||
124 | url: server.url, | ||
125 | userId: rootId, | ||
126 | accessToken: server.accessToken, | ||
127 | videoQuota: 42, | ||
128 | videoQuotaDaily: 1024 * 1024 * 1024 | ||
129 | }) | ||
130 | |||
131 | await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'legacy') | ||
132 | await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'resumable') | ||
133 | }) | ||
134 | |||
135 | it('Should fail if exceeding daily quota', async function () { | ||
136 | await updateUser({ | ||
137 | url: server.url, | ||
138 | userId: rootId, | ||
139 | accessToken: server.accessToken, | ||
140 | videoQuota: 1024 * 1024 * 1024, | ||
141 | videoQuotaDaily: 42 | ||
142 | }) | ||
143 | |||
144 | await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'legacy') | ||
145 | await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'resumable') | ||
146 | }) | ||
147 | }) | ||
148 | |||
149 | after(async function () { | ||
150 | await cleanupTests([ server ]) | ||
151 | }) | ||
152 | }) | ||
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts index 2b03fde2d..dcff0d52b 100644 --- a/server/tests/api/check-params/users.ts +++ b/server/tests/api/check-params/users.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | ||
5 | import { omit } from 'lodash' | 4 | import { omit } from 'lodash' |
6 | import { join } from 'path' | 5 | import { join } from 'path' |
7 | import { User, UserRole, VideoImport, VideoImportState } from '../../../../shared' | 6 | import { User, UserRole } from '../../../../shared' |
7 | import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' | ||
8 | import { | 8 | import { |
9 | addVideoChannel, | 9 | addVideoChannel, |
10 | blockUser, | 10 | blockUser, |
@@ -29,7 +29,6 @@ import { | |||
29 | ServerInfo, | 29 | ServerInfo, |
30 | setAccessTokensToServers, | 30 | setAccessTokensToServers, |
31 | unblockUser, | 31 | unblockUser, |
32 | updateUser, | ||
33 | uploadVideo, | 32 | uploadVideo, |
34 | userLogin | 33 | userLogin |
35 | } from '../../../../shared/extra-utils' | 34 | } from '../../../../shared/extra-utils' |
@@ -39,11 +38,7 @@ import { | |||
39 | checkBadSortPagination, | 38 | checkBadSortPagination, |
40 | checkBadStartPagination | 39 | checkBadStartPagination |
41 | } from '../../../../shared/extra-utils/requests/check-api-params' | 40 | } from '../../../../shared/extra-utils/requests/check-api-params' |
42 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | ||
43 | import { getGoodVideoUrl, getMagnetURI, getMyVideoImports, importVideo } from '../../../../shared/extra-utils/videos/video-imports' | ||
44 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' | 41 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' |
45 | import { VideoPrivacy } from '../../../../shared/models/videos' | ||
46 | import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' | ||
47 | 42 | ||
48 | describe('Test users API validators', function () { | 43 | describe('Test users API validators', function () { |
49 | const path = '/api/v1/users/' | 44 | const path = '/api/v1/users/' |
@@ -1093,102 +1088,6 @@ describe('Test users API validators', function () { | |||
1093 | }) | 1088 | }) |
1094 | }) | 1089 | }) |
1095 | 1090 | ||
1096 | describe('When having a video quota', function () { | ||
1097 | it('Should fail with a user having too many videos', async function () { | ||
1098 | await updateUser({ | ||
1099 | url: server.url, | ||
1100 | userId: rootId, | ||
1101 | accessToken: server.accessToken, | ||
1102 | videoQuota: 42 | ||
1103 | }) | ||
1104 | |||
1105 | await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413) | ||
1106 | }) | ||
1107 | |||
1108 | it('Should fail with a registered user having too many videos', async function () { | ||
1109 | this.timeout(30000) | ||
1110 | |||
1111 | const user = { | ||
1112 | username: 'user3', | ||
1113 | password: 'my super password' | ||
1114 | } | ||
1115 | userAccessToken = await userLogin(server, user) | ||
1116 | |||
1117 | const videoAttributes = { fixture: 'video_short2.webm' } | ||
1118 | await uploadVideo(server.url, userAccessToken, videoAttributes) | ||
1119 | await uploadVideo(server.url, userAccessToken, videoAttributes) | ||
1120 | await uploadVideo(server.url, userAccessToken, videoAttributes) | ||
1121 | await uploadVideo(server.url, userAccessToken, videoAttributes) | ||
1122 | await uploadVideo(server.url, userAccessToken, videoAttributes) | ||
1123 | await uploadVideo(server.url, userAccessToken, videoAttributes, HttpStatusCode.PAYLOAD_TOO_LARGE_413) | ||
1124 | }) | ||
1125 | |||
1126 | it('Should fail to import with HTTP/Torrent/magnet', async function () { | ||
1127 | this.timeout(120000) | ||
1128 | |||
1129 | const baseAttributes = { | ||
1130 | channelId: 1, | ||
1131 | privacy: VideoPrivacy.PUBLIC | ||
1132 | } | ||
1133 | await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { targetUrl: getGoodVideoUrl() })) | ||
1134 | await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { magnetUri: getMagnetURI() })) | ||
1135 | await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { torrentfile: 'video-720p.torrent' as any })) | ||
1136 | |||
1137 | await waitJobs([ server ]) | ||
1138 | |||
1139 | const res = await getMyVideoImports(server.url, server.accessToken) | ||
1140 | |||
1141 | expect(res.body.total).to.equal(3) | ||
1142 | const videoImports: VideoImport[] = res.body.data | ||
1143 | expect(videoImports).to.have.lengthOf(3) | ||
1144 | |||
1145 | for (const videoImport of videoImports) { | ||
1146 | expect(videoImport.state.id).to.equal(VideoImportState.FAILED) | ||
1147 | expect(videoImport.error).not.to.be.undefined | ||
1148 | expect(videoImport.error).to.contain('user video quota is exceeded') | ||
1149 | } | ||
1150 | }) | ||
1151 | }) | ||
1152 | |||
1153 | describe('When having a daily video quota', function () { | ||
1154 | it('Should fail with a user having too many videos daily', async function () { | ||
1155 | await updateUser({ | ||
1156 | url: server.url, | ||
1157 | userId: rootId, | ||
1158 | accessToken: server.accessToken, | ||
1159 | videoQuotaDaily: 42 | ||
1160 | }) | ||
1161 | |||
1162 | await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413) | ||
1163 | }) | ||
1164 | }) | ||
1165 | |||
1166 | describe('When having an absolute and daily video quota', function () { | ||
1167 | it('Should fail if exceeding total quota', async function () { | ||
1168 | await updateUser({ | ||
1169 | url: server.url, | ||
1170 | userId: rootId, | ||
1171 | accessToken: server.accessToken, | ||
1172 | videoQuota: 42, | ||
1173 | videoQuotaDaily: 1024 * 1024 * 1024 | ||
1174 | }) | ||
1175 | |||
1176 | await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413) | ||
1177 | }) | ||
1178 | |||
1179 | it('Should fail if exceeding daily quota', async function () { | ||
1180 | await updateUser({ | ||
1181 | url: server.url, | ||
1182 | userId: rootId, | ||
1183 | accessToken: server.accessToken, | ||
1184 | videoQuota: 1024 * 1024 * 1024, | ||
1185 | videoQuotaDaily: 42 | ||
1186 | }) | ||
1187 | |||
1188 | await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413) | ||
1189 | }) | ||
1190 | }) | ||
1191 | |||
1192 | describe('When asking a password reset', function () { | 1091 | describe('When asking a password reset', function () { |
1193 | const path = '/api/v1/users/ask-reset-password' | 1092 | const path = '/api/v1/users/ask-reset-password' |
1194 | 1093 | ||
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts index 188d1835c..c970c4a15 100644 --- a/server/tests/api/check-params/videos.ts +++ b/server/tests/api/check-params/videos.ts | |||
@@ -1,11 +1,12 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | ||
3 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
4 | import { omit } from 'lodash' | 5 | import { omit } from 'lodash' |
5 | import 'mocha' | ||
6 | import { join } from 'path' | 6 | import { join } from 'path' |
7 | import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum' | 7 | import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' |
8 | import { | 8 | import { |
9 | checkUploadVideoParam, | ||
9 | cleanupTests, | 10 | cleanupTests, |
10 | createUser, | 11 | createUser, |
11 | flushAndRunServer, | 12 | flushAndRunServer, |
@@ -18,17 +19,18 @@ import { | |||
18 | makePutBodyRequest, | 19 | makePutBodyRequest, |
19 | makeUploadRequest, | 20 | makeUploadRequest, |
20 | removeVideo, | 21 | removeVideo, |
22 | root, | ||
21 | ServerInfo, | 23 | ServerInfo, |
22 | setAccessTokensToServers, | 24 | setAccessTokensToServers, |
23 | userLogin, | 25 | userLogin |
24 | root | ||
25 | } from '../../../../shared/extra-utils' | 26 | } from '../../../../shared/extra-utils' |
26 | import { | 27 | import { |
27 | checkBadCountPagination, | 28 | checkBadCountPagination, |
28 | checkBadSortPagination, | 29 | checkBadSortPagination, |
29 | checkBadStartPagination | 30 | checkBadStartPagination |
30 | } from '../../../../shared/extra-utils/requests/check-api-params' | 31 | } from '../../../../shared/extra-utils/requests/check-api-params' |
31 | import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' | 32 | import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum' |
33 | import { randomInt } from '@shared/core-utils' | ||
32 | 34 | ||
33 | const expect = chai.expect | 35 | const expect = chai.expect |
34 | 36 | ||
@@ -183,7 +185,7 @@ describe('Test videos API validator', function () { | |||
183 | describe('When adding a video', function () { | 185 | describe('When adding a video', function () { |
184 | let baseCorrectParams | 186 | let baseCorrectParams |
185 | const baseCorrectAttaches = { | 187 | const baseCorrectAttaches = { |
186 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.webm') | 188 | fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.webm') |
187 | } | 189 | } |
188 | 190 | ||
189 | before(function () { | 191 | before(function () { |
@@ -206,256 +208,243 @@ describe('Test videos API validator', function () { | |||
206 | } | 208 | } |
207 | }) | 209 | }) |
208 | 210 | ||
209 | it('Should fail with nothing', async function () { | 211 | function runSuite (mode: 'legacy' | 'resumable') { |
210 | const fields = {} | ||
211 | const attaches = {} | ||
212 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | ||
213 | }) | ||
214 | 212 | ||
215 | it('Should fail without name', async function () { | 213 | it('Should fail with nothing', async function () { |
216 | const fields = omit(baseCorrectParams, 'name') | 214 | const fields = {} |
217 | const attaches = baseCorrectAttaches | 215 | const attaches = {} |
216 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) | ||
217 | }) | ||
218 | 218 | ||
219 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 219 | it('Should fail without name', async function () { |
220 | }) | 220 | const fields = omit(baseCorrectParams, 'name') |
221 | const attaches = baseCorrectAttaches | ||
221 | 222 | ||
222 | it('Should fail with a long name', async function () { | 223 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
223 | const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) }) | 224 | }) |
224 | const attaches = baseCorrectAttaches | ||
225 | 225 | ||
226 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 226 | it('Should fail with a long name', async function () { |
227 | }) | 227 | const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) }) |
228 | const attaches = baseCorrectAttaches | ||
228 | 229 | ||
229 | it('Should fail with a bad category', async function () { | 230 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
230 | const fields = immutableAssign(baseCorrectParams, { category: 125 }) | 231 | }) |
231 | const attaches = baseCorrectAttaches | ||
232 | 232 | ||
233 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 233 | it('Should fail with a bad category', async function () { |
234 | }) | 234 | const fields = immutableAssign(baseCorrectParams, { category: 125 }) |
235 | const attaches = baseCorrectAttaches | ||
235 | 236 | ||
236 | it('Should fail with a bad licence', async function () { | 237 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
237 | const fields = immutableAssign(baseCorrectParams, { licence: 125 }) | 238 | }) |
238 | const attaches = baseCorrectAttaches | ||
239 | 239 | ||
240 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 240 | it('Should fail with a bad licence', async function () { |
241 | }) | 241 | const fields = immutableAssign(baseCorrectParams, { licence: 125 }) |
242 | const attaches = baseCorrectAttaches | ||
242 | 243 | ||
243 | it('Should fail with a bad language', async function () { | 244 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
244 | const fields = immutableAssign(baseCorrectParams, { language: 'a'.repeat(15) }) | 245 | }) |
245 | const attaches = baseCorrectAttaches | ||
246 | 246 | ||
247 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 247 | it('Should fail with a bad language', async function () { |
248 | }) | 248 | const fields = immutableAssign(baseCorrectParams, { language: 'a'.repeat(15) }) |
249 | const attaches = baseCorrectAttaches | ||
249 | 250 | ||
250 | it('Should fail with a long description', async function () { | 251 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
251 | const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(2500) }) | 252 | }) |
252 | const attaches = baseCorrectAttaches | ||
253 | 253 | ||
254 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 254 | it('Should fail with a long description', async function () { |
255 | }) | 255 | const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(2500) }) |
256 | const attaches = baseCorrectAttaches | ||
256 | 257 | ||
257 | it('Should fail with a long support text', async function () { | 258 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
258 | const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(201) }) | 259 | }) |
259 | const attaches = baseCorrectAttaches | ||
260 | 260 | ||
261 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 261 | it('Should fail with a long support text', async function () { |
262 | }) | 262 | const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(201) }) |
263 | const attaches = baseCorrectAttaches | ||
263 | 264 | ||
264 | it('Should fail without a channel', async function () { | 265 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
265 | const fields = omit(baseCorrectParams, 'channelId') | 266 | }) |
266 | const attaches = baseCorrectAttaches | ||
267 | 267 | ||
268 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 268 | it('Should fail without a channel', async function () { |
269 | }) | 269 | const fields = omit(baseCorrectParams, 'channelId') |
270 | const attaches = baseCorrectAttaches | ||
270 | 271 | ||
271 | it('Should fail with a bad channel', async function () { | 272 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
272 | const fields = immutableAssign(baseCorrectParams, { channelId: 545454 }) | 273 | }) |
273 | const attaches = baseCorrectAttaches | ||
274 | 274 | ||
275 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 275 | it('Should fail with a bad channel', async function () { |
276 | }) | 276 | const fields = immutableAssign(baseCorrectParams, { channelId: 545454 }) |
277 | const attaches = baseCorrectAttaches | ||
277 | 278 | ||
278 | it('Should fail with another user channel', async function () { | 279 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
279 | const user = { | 280 | }) |
280 | username: 'fake', | ||
281 | password: 'fake_password' | ||
282 | } | ||
283 | await createUser({ url: server.url, accessToken: server.accessToken, username: user.username, password: user.password }) | ||
284 | 281 | ||
285 | const accessTokenUser = await userLogin(server, user) | 282 | it('Should fail with another user channel', async function () { |
286 | const res = await getMyUserInformation(server.url, accessTokenUser) | 283 | const user = { |
287 | const customChannelId = res.body.videoChannels[0].id | 284 | username: 'fake' + randomInt(0, 1500), |
285 | password: 'fake_password' | ||
286 | } | ||
287 | await createUser({ url: server.url, accessToken: server.accessToken, username: user.username, password: user.password }) | ||
288 | 288 | ||
289 | const fields = immutableAssign(baseCorrectParams, { channelId: customChannelId }) | 289 | const accessTokenUser = await userLogin(server, user) |
290 | const attaches = baseCorrectAttaches | 290 | const res = await getMyUserInformation(server.url, accessTokenUser) |
291 | const customChannelId = res.body.videoChannels[0].id | ||
291 | 292 | ||
292 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: userAccessToken, fields, attaches }) | 293 | const fields = immutableAssign(baseCorrectParams, { channelId: customChannelId }) |
293 | }) | 294 | const attaches = baseCorrectAttaches |
294 | 295 | ||
295 | it('Should fail with too many tags', async function () { | 296 | await checkUploadVideoParam(server.url, userAccessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
296 | const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }) | 297 | }) |
297 | const attaches = baseCorrectAttaches | ||
298 | 298 | ||
299 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 299 | it('Should fail with too many tags', async function () { |
300 | }) | 300 | const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }) |
301 | const attaches = baseCorrectAttaches | ||
301 | 302 | ||
302 | it('Should fail with a tag length too low', async function () { | 303 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
303 | const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 't' ] }) | 304 | }) |
304 | const attaches = baseCorrectAttaches | ||
305 | 305 | ||
306 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 306 | it('Should fail with a tag length too low', async function () { |
307 | }) | 307 | const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 't' ] }) |
308 | const attaches = baseCorrectAttaches | ||
308 | 309 | ||
309 | it('Should fail with a tag length too big', async function () { | 310 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
310 | const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }) | 311 | }) |
311 | const attaches = baseCorrectAttaches | ||
312 | 312 | ||
313 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 313 | it('Should fail with a tag length too big', async function () { |
314 | }) | 314 | const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }) |
315 | const attaches = baseCorrectAttaches | ||
315 | 316 | ||
316 | it('Should fail with a bad schedule update (miss updateAt)', async function () { | 317 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
317 | const fields = immutableAssign(baseCorrectParams, { 'scheduleUpdate[privacy]': VideoPrivacy.PUBLIC }) | 318 | }) |
318 | const attaches = baseCorrectAttaches | ||
319 | 319 | ||
320 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 320 | it('Should fail with a bad schedule update (miss updateAt)', async function () { |
321 | }) | 321 | const fields = immutableAssign(baseCorrectParams, { scheduleUpdate: { privacy: VideoPrivacy.PUBLIC } }) |
322 | const attaches = baseCorrectAttaches | ||
322 | 323 | ||
323 | it('Should fail with a bad schedule update (wrong updateAt)', async function () { | 324 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
324 | const fields = immutableAssign(baseCorrectParams, { | ||
325 | 'scheduleUpdate[privacy]': VideoPrivacy.PUBLIC, | ||
326 | 'scheduleUpdate[updateAt]': 'toto' | ||
327 | }) | 325 | }) |
328 | const attaches = baseCorrectAttaches | ||
329 | 326 | ||
330 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 327 | it('Should fail with a bad schedule update (wrong updateAt)', async function () { |
331 | }) | 328 | const fields = immutableAssign(baseCorrectParams, { |
329 | scheduleUpdate: { | ||
330 | privacy: VideoPrivacy.PUBLIC, | ||
331 | updateAt: 'toto' | ||
332 | } | ||
333 | }) | ||
334 | const attaches = baseCorrectAttaches | ||
332 | 335 | ||
333 | it('Should fail with a bad originally published at attribute', async function () { | 336 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
334 | const fields = immutableAssign(baseCorrectParams, { originallyPublishedAt: 'toto' }) | 337 | }) |
335 | const attaches = baseCorrectAttaches | ||
336 | 338 | ||
337 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 339 | it('Should fail with a bad originally published at attribute', async function () { |
338 | }) | 340 | const fields = immutableAssign(baseCorrectParams, { originallyPublishedAt: 'toto' }) |
341 | const attaches = baseCorrectAttaches | ||
339 | 342 | ||
340 | it('Should fail without an input file', async function () { | 343 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
341 | const fields = baseCorrectParams | 344 | }) |
342 | const attaches = {} | ||
343 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | ||
344 | }) | ||
345 | 345 | ||
346 | it('Should fail with an incorrect input file', async function () { | 346 | it('Should fail without an input file', async function () { |
347 | const fields = baseCorrectParams | 347 | const fields = baseCorrectParams |
348 | let attaches = { | 348 | const attaches = {} |
349 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm') | 349 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
350 | } | ||
351 | await makeUploadRequest({ | ||
352 | url: server.url, | ||
353 | path: path + '/upload', | ||
354 | token: server.accessToken, | ||
355 | fields, | ||
356 | attaches, | ||
357 | statusCodeExpected: HttpStatusCode.UNPROCESSABLE_ENTITY_422 | ||
358 | }) | 350 | }) |
359 | 351 | ||
360 | attaches = { | 352 | it('Should fail with an incorrect input file', async function () { |
361 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv') | 353 | const fields = baseCorrectParams |
362 | } | 354 | let attaches = { fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm') } |
363 | await makeUploadRequest({ | 355 | |
364 | url: server.url, | 356 | await checkUploadVideoParam( |
365 | path: path + '/upload', | 357 | server.url, |
366 | token: server.accessToken, | 358 | server.accessToken, |
367 | fields, | 359 | { ...fields, ...attaches }, |
368 | attaches, | 360 | HttpStatusCode.UNPROCESSABLE_ENTITY_422, |
369 | statusCodeExpected: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415 | 361 | mode |
362 | ) | ||
363 | |||
364 | attaches = { fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv') } | ||
365 | await checkUploadVideoParam( | ||
366 | server.url, | ||
367 | server.accessToken, | ||
368 | { ...fields, ...attaches }, | ||
369 | HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415, | ||
370 | mode | ||
371 | ) | ||
370 | }) | 372 | }) |
371 | }) | ||
372 | 373 | ||
373 | it('Should fail with an incorrect thumbnail file', async function () { | 374 | it('Should fail with an incorrect thumbnail file', async function () { |
374 | const fields = baseCorrectParams | 375 | const fields = baseCorrectParams |
375 | const attaches = { | 376 | const attaches = { |
376 | thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4'), | 377 | thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4'), |
377 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 378 | fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
378 | } | 379 | } |
379 | 380 | ||
380 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 381 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
381 | }) | 382 | }) |
382 | 383 | ||
383 | it('Should fail with a big thumbnail file', async function () { | 384 | it('Should fail with a big thumbnail file', async function () { |
384 | const fields = baseCorrectParams | 385 | const fields = baseCorrectParams |
385 | const attaches = { | 386 | const attaches = { |
386 | thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'preview-big.png'), | 387 | thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'preview-big.png'), |
387 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 388 | fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
388 | } | 389 | } |
389 | 390 | ||
390 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 391 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
391 | }) | 392 | }) |
392 | 393 | ||
393 | it('Should fail with an incorrect preview file', async function () { | 394 | it('Should fail with an incorrect preview file', async function () { |
394 | const fields = baseCorrectParams | 395 | const fields = baseCorrectParams |
395 | const attaches = { | 396 | const attaches = { |
396 | previewfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4'), | 397 | previewfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4'), |
397 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 398 | fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
398 | } | 399 | } |
399 | 400 | ||
400 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 401 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
401 | }) | 402 | }) |
402 | 403 | ||
403 | it('Should fail with a big preview file', async function () { | 404 | it('Should fail with a big preview file', async function () { |
404 | const fields = baseCorrectParams | 405 | const fields = baseCorrectParams |
405 | const attaches = { | 406 | const attaches = { |
406 | previewfile: join(root(), 'server', 'tests', 'fixtures', 'preview-big.png'), | 407 | previewfile: join(root(), 'server', 'tests', 'fixtures', 'preview-big.png'), |
407 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 408 | fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
408 | } | 409 | } |
409 | 410 | ||
410 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 411 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) |
411 | }) | 412 | }) |
412 | 413 | ||
413 | it('Should succeed with the correct parameters', async function () { | 414 | it('Should succeed with the correct parameters', async function () { |
414 | this.timeout(10000) | 415 | this.timeout(10000) |
415 | 416 | ||
416 | const fields = baseCorrectParams | 417 | const fields = baseCorrectParams |
417 | 418 | ||
418 | { | 419 | { |
419 | const attaches = baseCorrectAttaches | 420 | const attaches = baseCorrectAttaches |
420 | await makeUploadRequest({ | 421 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.OK_200, mode) |
421 | url: server.url, | 422 | } |
422 | path: path + '/upload', | ||
423 | token: server.accessToken, | ||
424 | fields, | ||
425 | attaches, | ||
426 | statusCodeExpected: HttpStatusCode.OK_200 | ||
427 | }) | ||
428 | } | ||
429 | 423 | ||
430 | { | 424 | { |
431 | const attaches = immutableAssign(baseCorrectAttaches, { | 425 | const attaches = immutableAssign(baseCorrectAttaches, { |
432 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 426 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
433 | }) | 427 | }) |
434 | 428 | ||
435 | await makeUploadRequest({ | 429 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.OK_200, mode) |
436 | url: server.url, | 430 | } |
437 | path: path + '/upload', | ||
438 | token: server.accessToken, | ||
439 | fields, | ||
440 | attaches, | ||
441 | statusCodeExpected: HttpStatusCode.OK_200 | ||
442 | }) | ||
443 | } | ||
444 | 431 | ||
445 | { | 432 | { |
446 | const attaches = immutableAssign(baseCorrectAttaches, { | 433 | const attaches = immutableAssign(baseCorrectAttaches, { |
447 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.ogv') | 434 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.ogv') |
448 | }) | 435 | }) |
449 | 436 | ||
450 | await makeUploadRequest({ | 437 | await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.OK_200, mode) |
451 | url: server.url, | 438 | } |
452 | path: path + '/upload', | 439 | }) |
453 | token: server.accessToken, | 440 | } |
454 | fields, | 441 | |
455 | attaches, | 442 | describe('Resumable upload', function () { |
456 | statusCodeExpected: HttpStatusCode.OK_200 | 443 | runSuite('resumable') |
457 | }) | 444 | }) |
458 | } | 445 | |
446 | describe('Legacy upload', function () { | ||
447 | runSuite('legacy') | ||
459 | }) | 448 | }) |
460 | }) | 449 | }) |
461 | 450 | ||
@@ -678,7 +667,7 @@ describe('Test videos API validator', function () { | |||
678 | }) | 667 | }) |
679 | 668 | ||
680 | expect(res.body.data).to.be.an('array') | 669 | expect(res.body.data).to.be.an('array') |
681 | expect(res.body.data.length).to.equal(3) | 670 | expect(res.body.data.length).to.equal(6) |
682 | }) | 671 | }) |
683 | 672 | ||
684 | it('Should fail without a correct uuid', async function () { | 673 | it('Should fail without a correct uuid', async function () { |