aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/api/check-params
diff options
context:
space:
mode:
Diffstat (limited to 'server/tests/api/check-params')
-rw-r--r--server/tests/api/check-params/abuses.ts438
-rw-r--r--server/tests/api/check-params/accounts.ts43
-rw-r--r--server/tests/api/check-params/blocklist.ts556
-rw-r--r--server/tests/api/check-params/bulk.ts80
-rw-r--r--server/tests/api/check-params/channel-import-videos.ts209
-rw-r--r--server/tests/api/check-params/config.ts428
-rw-r--r--server/tests/api/check-params/contact-form.ts86
-rw-r--r--server/tests/api/check-params/custom-pages.ts79
-rw-r--r--server/tests/api/check-params/debug.ts61
-rw-r--r--server/tests/api/check-params/follows.ts369
-rw-r--r--server/tests/api/check-params/index.ts45
-rw-r--r--server/tests/api/check-params/jobs.ts125
-rw-r--r--server/tests/api/check-params/live.ts589
-rw-r--r--server/tests/api/check-params/logs.ts157
-rw-r--r--server/tests/api/check-params/metrics.ts208
-rw-r--r--server/tests/api/check-params/my-user.ts491
-rw-r--r--server/tests/api/check-params/plugins.ts490
-rw-r--r--server/tests/api/check-params/redundancy.ts240
-rw-r--r--server/tests/api/check-params/registrations.ts446
-rw-r--r--server/tests/api/check-params/runners.ts910
-rw-r--r--server/tests/api/check-params/search.ts272
-rw-r--r--server/tests/api/check-params/services.ts195
-rw-r--r--server/tests/api/check-params/transcoding.ts112
-rw-r--r--server/tests/api/check-params/two-factor.ts288
-rw-r--r--server/tests/api/check-params/upload-quota.ts134
-rw-r--r--server/tests/api/check-params/user-notifications.ts290
-rw-r--r--server/tests/api/check-params/user-subscriptions.ts298
-rw-r--r--server/tests/api/check-params/users-admin.ts456
-rw-r--r--server/tests/api/check-params/users-emails.ts116
-rw-r--r--server/tests/api/check-params/video-blacklist.ts292
-rw-r--r--server/tests/api/check-params/video-captions.ts307
-rw-r--r--server/tests/api/check-params/video-channel-syncs.ts318
-rw-r--r--server/tests/api/check-params/video-channels.ts378
-rw-r--r--server/tests/api/check-params/video-comments.ts484
-rw-r--r--server/tests/api/check-params/video-files.ts195
-rw-r--r--server/tests/api/check-params/video-imports.ts431
-rw-r--r--server/tests/api/check-params/video-passwords.ts609
-rw-r--r--server/tests/api/check-params/video-playlists.ts695
-rw-r--r--server/tests/api/check-params/video-source.ts154
-rw-r--r--server/tests/api/check-params/video-storyboards.ts45
-rw-r--r--server/tests/api/check-params/video-studio.ts388
-rw-r--r--server/tests/api/check-params/video-token.ts70
-rw-r--r--server/tests/api/check-params/videos-common-filters.ts163
-rw-r--r--server/tests/api/check-params/videos-history.ts145
-rw-r--r--server/tests/api/check-params/videos-overviews.ts31
-rw-r--r--server/tests/api/check-params/videos.ts881
-rw-r--r--server/tests/api/check-params/views.ts227
47 files changed, 0 insertions, 14024 deletions
diff --git a/server/tests/api/check-params/abuses.ts b/server/tests/api/check-params/abuses.ts
deleted file mode 100644
index 331d3f8f7..000000000
--- a/server/tests/api/check-params/abuses.ts
+++ /dev/null
@@ -1,438 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
4import { AbuseCreate, AbuseState, HttpStatusCode } from '@shared/models'
5import {
6 AbusesCommand,
7 cleanupTests,
8 createSingleServer,
9 doubleFollow,
10 makeGetRequest,
11 makePostBodyRequest,
12 PeerTubeServer,
13 setAccessTokensToServers,
14 waitJobs
15} from '@shared/server-commands'
16
17describe('Test abuses API validators', function () {
18 const basePath = '/api/v1/abuses/'
19
20 let server: PeerTubeServer
21
22 let userToken = ''
23 let userToken2 = ''
24 let abuseId: number
25 let messageId: number
26
27 let command: AbusesCommand
28
29 // ---------------------------------------------------------------
30
31 before(async function () {
32 this.timeout(30000)
33
34 server = await createSingleServer(1)
35
36 await setAccessTokensToServers([ server ])
37
38 userToken = await server.users.generateUserAndToken('user_1')
39 userToken2 = await server.users.generateUserAndToken('user_2')
40
41 server.store.videoCreated = await server.videos.upload()
42
43 command = server.abuses
44 })
45
46 describe('When listing abuses for admins', function () {
47 const path = basePath
48
49 it('Should fail with a bad start pagination', async function () {
50 await checkBadStartPagination(server.url, path, server.accessToken)
51 })
52
53 it('Should fail with a bad count pagination', async function () {
54 await checkBadCountPagination(server.url, path, server.accessToken)
55 })
56
57 it('Should fail with an incorrect sort', async function () {
58 await checkBadSortPagination(server.url, path, server.accessToken)
59 })
60
61 it('Should fail with a non authenticated user', async function () {
62 await makeGetRequest({
63 url: server.url,
64 path,
65 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
66 })
67 })
68
69 it('Should fail with a non admin user', async function () {
70 await makeGetRequest({
71 url: server.url,
72 path,
73 token: userToken,
74 expectedStatus: HttpStatusCode.FORBIDDEN_403
75 })
76 })
77
78 it('Should fail with a bad id filter', async function () {
79 await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { id: 'toto' } })
80 })
81
82 it('Should fail with a bad filter', async function () {
83 await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { filter: 'toto' } })
84 await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { filter: 'videos' } })
85 })
86
87 it('Should fail with bad predefined reason', async function () {
88 await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { predefinedReason: 'violentOrRepulsives' } })
89 })
90
91 it('Should fail with a bad state filter', async function () {
92 await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { state: 'toto' } })
93 await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { state: 0 } })
94 })
95
96 it('Should fail with a bad videoIs filter', async function () {
97 await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { videoIs: 'toto' } })
98 })
99
100 it('Should succeed with the correct params', async function () {
101 const query = {
102 id: 13,
103 predefinedReason: 'violentOrRepulsive',
104 filter: 'comment',
105 state: 2,
106 videoIs: 'deleted'
107 }
108
109 await makeGetRequest({ url: server.url, path, token: server.accessToken, query, expectedStatus: HttpStatusCode.OK_200 })
110 })
111 })
112
113 describe('When listing abuses for users', function () {
114 const path = '/api/v1/users/me/abuses'
115
116 it('Should fail with a bad start pagination', async function () {
117 await checkBadStartPagination(server.url, path, userToken)
118 })
119
120 it('Should fail with a bad count pagination', async function () {
121 await checkBadCountPagination(server.url, path, userToken)
122 })
123
124 it('Should fail with an incorrect sort', async function () {
125 await checkBadSortPagination(server.url, path, userToken)
126 })
127
128 it('Should fail with a non authenticated user', async function () {
129 await makeGetRequest({
130 url: server.url,
131 path,
132 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
133 })
134 })
135
136 it('Should fail with a bad id filter', async function () {
137 await makeGetRequest({ url: server.url, path, token: userToken, query: { id: 'toto' } })
138 })
139
140 it('Should fail with a bad state filter', async function () {
141 await makeGetRequest({ url: server.url, path, token: userToken, query: { state: 'toto' } })
142 await makeGetRequest({ url: server.url, path, token: userToken, query: { state: 0 } })
143 })
144
145 it('Should succeed with the correct params', async function () {
146 const query = {
147 id: 13,
148 state: 2
149 }
150
151 await makeGetRequest({ url: server.url, path, token: userToken, query, expectedStatus: HttpStatusCode.OK_200 })
152 })
153 })
154
155 describe('When reporting an abuse', function () {
156 const path = basePath
157
158 it('Should fail with nothing', async function () {
159 const fields = {}
160 await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
161 })
162
163 it('Should fail with a wrong video', async function () {
164 const fields = { video: { id: 'blabla' }, reason: 'my super reason' }
165 await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
166 })
167
168 it('Should fail with an unknown video', async function () {
169 const fields = { video: { id: 42 }, reason: 'my super reason' }
170 await makePostBodyRequest({
171 url: server.url,
172 path,
173 token: userToken,
174 fields,
175 expectedStatus: HttpStatusCode.NOT_FOUND_404
176 })
177 })
178
179 it('Should fail with a wrong comment', async function () {
180 const fields = { comment: { id: 'blabla' }, reason: 'my super reason' }
181 await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
182 })
183
184 it('Should fail with an unknown comment', async function () {
185 const fields = { comment: { id: 42 }, reason: 'my super reason' }
186 await makePostBodyRequest({
187 url: server.url,
188 path,
189 token: userToken,
190 fields,
191 expectedStatus: HttpStatusCode.NOT_FOUND_404
192 })
193 })
194
195 it('Should fail with a wrong account', async function () {
196 const fields = { account: { id: 'blabla' }, reason: 'my super reason' }
197 await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
198 })
199
200 it('Should fail with an unknown account', async function () {
201 const fields = { account: { id: 42 }, reason: 'my super reason' }
202 await makePostBodyRequest({
203 url: server.url,
204 path,
205 token: userToken,
206 fields,
207 expectedStatus: HttpStatusCode.NOT_FOUND_404
208 })
209 })
210
211 it('Should fail with not account, comment or video', async function () {
212 const fields = { reason: 'my super reason' }
213 await makePostBodyRequest({
214 url: server.url,
215 path,
216 token: userToken,
217 fields,
218 expectedStatus: HttpStatusCode.BAD_REQUEST_400
219 })
220 })
221
222 it('Should fail with a non authenticated user', async function () {
223 const fields = { video: { id: server.store.videoCreated.id }, reason: 'my super reason' }
224
225 await makePostBodyRequest({ url: server.url, path, token: 'hello', fields, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
226 })
227
228 it('Should fail with a reason too short', async function () {
229 const fields = { video: { id: server.store.videoCreated.id }, reason: 'h' }
230
231 await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
232 })
233
234 it('Should fail with a too big reason', async function () {
235 const fields = { video: { id: server.store.videoCreated.id }, reason: 'super'.repeat(605) }
236
237 await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
238 })
239
240 it('Should succeed with the correct parameters (basic)', async function () {
241 const fields: AbuseCreate = { video: { id: server.store.videoCreated.shortUUID }, reason: 'my super reason' }
242
243 const res = await makePostBodyRequest({
244 url: server.url,
245 path,
246 token: userToken,
247 fields,
248 expectedStatus: HttpStatusCode.OK_200
249 })
250 abuseId = res.body.abuse.id
251 })
252
253 it('Should fail with a wrong predefined reason', async function () {
254 const fields = { video: server.store.videoCreated, reason: 'my super reason', predefinedReasons: [ 'wrongPredefinedReason' ] }
255
256 await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
257 })
258
259 it('Should fail with negative timestamps', async function () {
260 const fields = { video: { id: server.store.videoCreated.id, startAt: -1 }, reason: 'my super reason' }
261
262 await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
263 })
264
265 it('Should fail mith misordered startAt/endAt', async function () {
266 const fields = { video: { id: server.store.videoCreated.id, startAt: 5, endAt: 1 }, reason: 'my super reason' }
267
268 await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
269 })
270
271 it('Should succeed with the correct parameters (advanced)', async function () {
272 const fields: AbuseCreate = {
273 video: {
274 id: server.store.videoCreated.id,
275 startAt: 1,
276 endAt: 5
277 },
278 reason: 'my super reason',
279 predefinedReasons: [ 'serverRules' ]
280 }
281
282 await makePostBodyRequest({ url: server.url, path, token: userToken, fields, expectedStatus: HttpStatusCode.OK_200 })
283 })
284 })
285
286 describe('When updating an abuse', function () {
287
288 it('Should fail with a non authenticated user', async function () {
289 await command.update({ token: 'blabla', abuseId, body: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
290 })
291
292 it('Should fail with a non admin user', async function () {
293 await command.update({ token: userToken, abuseId, body: {}, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
294 })
295
296 it('Should fail with a bad abuse id', async function () {
297 await command.update({ abuseId: 45, body: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
298 })
299
300 it('Should fail with a bad state', async function () {
301 const body = { state: 5 }
302 await command.update({ abuseId, body, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
303 })
304
305 it('Should fail with a bad moderation comment', async function () {
306 const body = { moderationComment: 'b'.repeat(3001) }
307 await command.update({ abuseId, body, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
308 })
309
310 it('Should succeed with the correct params', async function () {
311 const body = { state: AbuseState.ACCEPTED }
312 await command.update({ abuseId, body })
313 })
314 })
315
316 describe('When creating an abuse message', function () {
317 const message = 'my super message'
318
319 it('Should fail with an invalid abuse id', async function () {
320 await command.addMessage({ token: userToken2, abuseId: 888, message, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
321 })
322
323 it('Should fail with a non authenticated user', async function () {
324 await command.addMessage({ token: 'fake_token', abuseId, message, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
325 })
326
327 it('Should fail with an invalid logged in user', async function () {
328 await command.addMessage({ token: userToken2, abuseId, message, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
329 })
330
331 it('Should fail with an invalid message', async function () {
332 await command.addMessage({ token: userToken, abuseId, message: 'a'.repeat(5000), expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
333 })
334
335 it('Should succeed with the correct params', async function () {
336 const res = await command.addMessage({ token: userToken, abuseId, message })
337 messageId = res.body.abuseMessage.id
338 })
339 })
340
341 describe('When listing abuse messages', function () {
342
343 it('Should fail with an invalid abuse id', async function () {
344 await command.listMessages({ token: userToken, abuseId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
345 })
346
347 it('Should fail with a non authenticated user', async function () {
348 await command.listMessages({ token: 'fake_token', abuseId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
349 })
350
351 it('Should fail with an invalid logged in user', async function () {
352 await command.listMessages({ token: userToken2, abuseId, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
353 })
354
355 it('Should succeed with the correct params', async function () {
356 await command.listMessages({ token: userToken, abuseId })
357 })
358 })
359
360 describe('When deleting an abuse message', function () {
361 it('Should fail with an invalid abuse id', async function () {
362 await command.deleteMessage({ token: userToken, abuseId: 888, messageId, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
363 })
364
365 it('Should fail with an invalid message id', async function () {
366 await command.deleteMessage({ token: userToken, abuseId, messageId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
367 })
368
369 it('Should fail with a non authenticated user', async function () {
370 await command.deleteMessage({ token: 'fake_token', abuseId, messageId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
371 })
372
373 it('Should fail with an invalid logged in user', async function () {
374 await command.deleteMessage({ token: userToken2, abuseId, messageId, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
375 })
376
377 it('Should succeed with the correct params', async function () {
378 await command.deleteMessage({ token: userToken, abuseId, messageId })
379 })
380 })
381
382 describe('When deleting a video abuse', function () {
383
384 it('Should fail with a non authenticated user', async function () {
385 await command.delete({ token: 'blabla', abuseId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
386 })
387
388 it('Should fail with a non admin user', async function () {
389 await command.delete({ token: userToken, abuseId, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
390 })
391
392 it('Should fail with a bad abuse id', async function () {
393 await command.delete({ abuseId: 45, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
394 })
395
396 it('Should succeed with the correct params', async function () {
397 await command.delete({ abuseId })
398 })
399 })
400
401 describe('When trying to manage messages of a remote abuse', function () {
402 let remoteAbuseId: number
403 let anotherServer: PeerTubeServer
404
405 before(async function () {
406 this.timeout(50000)
407
408 anotherServer = await createSingleServer(2)
409 await setAccessTokensToServers([ anotherServer ])
410
411 await doubleFollow(anotherServer, server)
412
413 const server2VideoId = await anotherServer.videos.getId({ uuid: server.store.videoCreated.uuid })
414 await anotherServer.abuses.report({ reason: 'remote server', videoId: server2VideoId })
415
416 await waitJobs([ server, anotherServer ])
417
418 const body = await command.getAdminList({ sort: '-createdAt' })
419 remoteAbuseId = body.data[0].id
420 })
421
422 it('Should fail when listing abuse messages of a remote abuse', async function () {
423 await command.listMessages({ abuseId: remoteAbuseId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
424 })
425
426 it('Should fail when creating abuse message of a remote abuse', async function () {
427 await command.addMessage({ abuseId: remoteAbuseId, message: 'message', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
428 })
429
430 after(async function () {
431 await cleanupTests([ anotherServer ])
432 })
433 })
434
435 after(async function () {
436 await cleanupTests([ server ])
437 })
438})
diff --git a/server/tests/api/check-params/accounts.ts b/server/tests/api/check-params/accounts.ts
deleted file mode 100644
index afc0049ff..000000000
--- a/server/tests/api/check-params/accounts.ts
+++ /dev/null
@@ -1,43 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
4import { HttpStatusCode } from '@shared/models'
5import { cleanupTests, createSingleServer, PeerTubeServer } from '@shared/server-commands'
6
7describe('Test accounts API validators', function () {
8 const path = '/api/v1/accounts/'
9 let server: PeerTubeServer
10
11 // ---------------------------------------------------------------
12
13 before(async function () {
14 this.timeout(30000)
15
16 server = await createSingleServer(1)
17 })
18
19 describe('When listing accounts', function () {
20 it('Should fail with a bad start pagination', async function () {
21 await checkBadStartPagination(server.url, path, server.accessToken)
22 })
23
24 it('Should fail with a bad count pagination', async function () {
25 await checkBadCountPagination(server.url, path, server.accessToken)
26 })
27
28 it('Should fail with an incorrect sort', async function () {
29 await checkBadSortPagination(server.url, path, server.accessToken)
30 })
31 })
32
33 describe('When getting an account', function () {
34
35 it('Should return 404 with a non existing name', async function () {
36 await server.accounts.get({ accountName: 'arfaze', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
37 })
38 })
39
40 after(async function () {
41 await cleanupTests([ server ])
42 })
43})
diff --git a/server/tests/api/check-params/blocklist.ts b/server/tests/api/check-params/blocklist.ts
deleted file mode 100644
index 169b591a3..000000000
--- a/server/tests/api/check-params/blocklist.ts
+++ /dev/null
@@ -1,556 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
4import { HttpStatusCode } from '@shared/models'
5import {
6 cleanupTests,
7 createMultipleServers,
8 doubleFollow,
9 makeDeleteRequest,
10 makeGetRequest,
11 makePostBodyRequest,
12 PeerTubeServer,
13 setAccessTokensToServers
14} from '@shared/server-commands'
15
16describe('Test blocklist API validators', function () {
17 let servers: PeerTubeServer[]
18 let server: PeerTubeServer
19 let userAccessToken: string
20
21 before(async function () {
22 this.timeout(60000)
23
24 servers = await createMultipleServers(2)
25 await setAccessTokensToServers(servers)
26
27 server = servers[0]
28
29 const user = { username: 'user1', password: 'password' }
30 await server.users.create({ username: user.username, password: user.password })
31
32 userAccessToken = await server.login.getAccessToken(user)
33
34 await doubleFollow(servers[0], servers[1])
35 })
36
37 // ---------------------------------------------------------------
38
39 describe('When managing user blocklist', function () {
40
41 describe('When managing user accounts blocklist', function () {
42 const path = '/api/v1/users/me/blocklist/accounts'
43
44 describe('When listing blocked accounts', function () {
45 it('Should fail with an unauthenticated user', async function () {
46 await makeGetRequest({
47 url: server.url,
48 path,
49 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
50 })
51 })
52
53 it('Should fail with a bad start pagination', async function () {
54 await checkBadStartPagination(server.url, path, server.accessToken)
55 })
56
57 it('Should fail with a bad count pagination', async function () {
58 await checkBadCountPagination(server.url, path, server.accessToken)
59 })
60
61 it('Should fail with an incorrect sort', async function () {
62 await checkBadSortPagination(server.url, path, server.accessToken)
63 })
64 })
65
66 describe('When blocking an account', function () {
67 it('Should fail with an unauthenticated user', async function () {
68 await makePostBodyRequest({
69 url: server.url,
70 path,
71 fields: { accountName: 'user1' },
72 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
73 })
74 })
75
76 it('Should fail with an unknown account', async function () {
77 await makePostBodyRequest({
78 url: server.url,
79 token: server.accessToken,
80 path,
81 fields: { accountName: 'user2' },
82 expectedStatus: HttpStatusCode.NOT_FOUND_404
83 })
84 })
85
86 it('Should fail to block ourselves', async function () {
87 await makePostBodyRequest({
88 url: server.url,
89 token: server.accessToken,
90 path,
91 fields: { accountName: 'root' },
92 expectedStatus: HttpStatusCode.CONFLICT_409
93 })
94 })
95
96 it('Should succeed with the correct params', async function () {
97 await makePostBodyRequest({
98 url: server.url,
99 token: server.accessToken,
100 path,
101 fields: { accountName: 'user1' },
102 expectedStatus: HttpStatusCode.NO_CONTENT_204
103 })
104 })
105 })
106
107 describe('When unblocking an account', function () {
108 it('Should fail with an unauthenticated user', async function () {
109 await makeDeleteRequest({
110 url: server.url,
111 path: path + '/user1',
112 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
113 })
114 })
115
116 it('Should fail with an unknown account block', async function () {
117 await makeDeleteRequest({
118 url: server.url,
119 path: path + '/user2',
120 token: server.accessToken,
121 expectedStatus: HttpStatusCode.NOT_FOUND_404
122 })
123 })
124
125 it('Should succeed with the correct params', async function () {
126 await makeDeleteRequest({
127 url: server.url,
128 path: path + '/user1',
129 token: server.accessToken,
130 expectedStatus: HttpStatusCode.NO_CONTENT_204
131 })
132 })
133 })
134 })
135
136 describe('When managing user servers blocklist', function () {
137 const path = '/api/v1/users/me/blocklist/servers'
138
139 describe('When listing blocked servers', function () {
140 it('Should fail with an unauthenticated user', async function () {
141 await makeGetRequest({
142 url: server.url,
143 path,
144 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
145 })
146 })
147
148 it('Should fail with a bad start pagination', async function () {
149 await checkBadStartPagination(server.url, path, server.accessToken)
150 })
151
152 it('Should fail with a bad count pagination', async function () {
153 await checkBadCountPagination(server.url, path, server.accessToken)
154 })
155
156 it('Should fail with an incorrect sort', async function () {
157 await checkBadSortPagination(server.url, path, server.accessToken)
158 })
159 })
160
161 describe('When blocking a server', function () {
162 it('Should fail with an unauthenticated user', async function () {
163 await makePostBodyRequest({
164 url: server.url,
165 path,
166 fields: { host: '127.0.0.1:9002' },
167 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
168 })
169 })
170
171 it('Should succeed with an unknown server', async function () {
172 await makePostBodyRequest({
173 url: server.url,
174 token: server.accessToken,
175 path,
176 fields: { host: '127.0.0.1:9003' },
177 expectedStatus: HttpStatusCode.NO_CONTENT_204
178 })
179 })
180
181 it('Should fail with our own server', async function () {
182 await makePostBodyRequest({
183 url: server.url,
184 token: server.accessToken,
185 path,
186 fields: { host: server.host },
187 expectedStatus: HttpStatusCode.CONFLICT_409
188 })
189 })
190
191 it('Should succeed with the correct params', async function () {
192 await makePostBodyRequest({
193 url: server.url,
194 token: server.accessToken,
195 path,
196 fields: { host: servers[1].host },
197 expectedStatus: HttpStatusCode.NO_CONTENT_204
198 })
199 })
200 })
201
202 describe('When unblocking a server', function () {
203 it('Should fail with an unauthenticated user', async function () {
204 await makeDeleteRequest({
205 url: server.url,
206 path: path + '/' + servers[1].host,
207 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
208 })
209 })
210
211 it('Should fail with an unknown server block', async function () {
212 await makeDeleteRequest({
213 url: server.url,
214 path: path + '/127.0.0.1:9004',
215 token: server.accessToken,
216 expectedStatus: HttpStatusCode.NOT_FOUND_404
217 })
218 })
219
220 it('Should succeed with the correct params', async function () {
221 await makeDeleteRequest({
222 url: server.url,
223 path: path + '/' + servers[1].host,
224 token: server.accessToken,
225 expectedStatus: HttpStatusCode.NO_CONTENT_204
226 })
227 })
228 })
229 })
230 })
231
232 describe('When managing server blocklist', function () {
233
234 describe('When managing server accounts blocklist', function () {
235 const path = '/api/v1/server/blocklist/accounts'
236
237 describe('When listing blocked accounts', function () {
238 it('Should fail with an unauthenticated user', async function () {
239 await makeGetRequest({
240 url: server.url,
241 path,
242 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
243 })
244 })
245
246 it('Should fail with a user without the appropriate rights', async function () {
247 await makeGetRequest({
248 url: server.url,
249 token: userAccessToken,
250 path,
251 expectedStatus: HttpStatusCode.FORBIDDEN_403
252 })
253 })
254
255 it('Should fail with a bad start pagination', async function () {
256 await checkBadStartPagination(server.url, path, server.accessToken)
257 })
258
259 it('Should fail with a bad count pagination', async function () {
260 await checkBadCountPagination(server.url, path, server.accessToken)
261 })
262
263 it('Should fail with an incorrect sort', async function () {
264 await checkBadSortPagination(server.url, path, server.accessToken)
265 })
266 })
267
268 describe('When blocking an account', function () {
269 it('Should fail with an unauthenticated user', async function () {
270 await makePostBodyRequest({
271 url: server.url,
272 path,
273 fields: { accountName: 'user1' },
274 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
275 })
276 })
277
278 it('Should fail with a user without the appropriate rights', async function () {
279 await makePostBodyRequest({
280 url: server.url,
281 token: userAccessToken,
282 path,
283 fields: { accountName: 'user1' },
284 expectedStatus: HttpStatusCode.FORBIDDEN_403
285 })
286 })
287
288 it('Should fail with an unknown account', async function () {
289 await makePostBodyRequest({
290 url: server.url,
291 token: server.accessToken,
292 path,
293 fields: { accountName: 'user2' },
294 expectedStatus: HttpStatusCode.NOT_FOUND_404
295 })
296 })
297
298 it('Should fail to block ourselves', async function () {
299 await makePostBodyRequest({
300 url: server.url,
301 token: server.accessToken,
302 path,
303 fields: { accountName: 'root' },
304 expectedStatus: HttpStatusCode.CONFLICT_409
305 })
306 })
307
308 it('Should succeed with the correct params', async function () {
309 await makePostBodyRequest({
310 url: server.url,
311 token: server.accessToken,
312 path,
313 fields: { accountName: 'user1' },
314 expectedStatus: HttpStatusCode.NO_CONTENT_204
315 })
316 })
317 })
318
319 describe('When unblocking an account', function () {
320 it('Should fail with an unauthenticated user', async function () {
321 await makeDeleteRequest({
322 url: server.url,
323 path: path + '/user1',
324 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
325 })
326 })
327
328 it('Should fail with a user without the appropriate rights', async function () {
329 await makeDeleteRequest({
330 url: server.url,
331 path: path + '/user1',
332 token: userAccessToken,
333 expectedStatus: HttpStatusCode.FORBIDDEN_403
334 })
335 })
336
337 it('Should fail with an unknown account block', async function () {
338 await makeDeleteRequest({
339 url: server.url,
340 path: path + '/user2',
341 token: server.accessToken,
342 expectedStatus: HttpStatusCode.NOT_FOUND_404
343 })
344 })
345
346 it('Should succeed with the correct params', async function () {
347 await makeDeleteRequest({
348 url: server.url,
349 path: path + '/user1',
350 token: server.accessToken,
351 expectedStatus: HttpStatusCode.NO_CONTENT_204
352 })
353 })
354 })
355 })
356
357 describe('When managing server servers blocklist', function () {
358 const path = '/api/v1/server/blocklist/servers'
359
360 describe('When listing blocked servers', function () {
361 it('Should fail with an unauthenticated user', async function () {
362 await makeGetRequest({
363 url: server.url,
364 path,
365 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
366 })
367 })
368
369 it('Should fail with a user without the appropriate rights', async function () {
370 await makeGetRequest({
371 url: server.url,
372 token: userAccessToken,
373 path,
374 expectedStatus: HttpStatusCode.FORBIDDEN_403
375 })
376 })
377
378 it('Should fail with a bad start pagination', async function () {
379 await checkBadStartPagination(server.url, path, server.accessToken)
380 })
381
382 it('Should fail with a bad count pagination', async function () {
383 await checkBadCountPagination(server.url, path, server.accessToken)
384 })
385
386 it('Should fail with an incorrect sort', async function () {
387 await checkBadSortPagination(server.url, path, server.accessToken)
388 })
389 })
390
391 describe('When blocking a server', function () {
392 it('Should fail with an unauthenticated user', async function () {
393 await makePostBodyRequest({
394 url: server.url,
395 path,
396 fields: { host: servers[1].host },
397 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
398 })
399 })
400
401 it('Should fail with a user without the appropriate rights', async function () {
402 await makePostBodyRequest({
403 url: server.url,
404 token: userAccessToken,
405 path,
406 fields: { host: servers[1].host },
407 expectedStatus: HttpStatusCode.FORBIDDEN_403
408 })
409 })
410
411 it('Should succeed with an unknown server', async function () {
412 await makePostBodyRequest({
413 url: server.url,
414 token: server.accessToken,
415 path,
416 fields: { host: '127.0.0.1:9003' },
417 expectedStatus: HttpStatusCode.NO_CONTENT_204
418 })
419 })
420
421 it('Should fail with our own server', async function () {
422 await makePostBodyRequest({
423 url: server.url,
424 token: server.accessToken,
425 path,
426 fields: { host: server.host },
427 expectedStatus: HttpStatusCode.CONFLICT_409
428 })
429 })
430
431 it('Should succeed with the correct params', async function () {
432 await makePostBodyRequest({
433 url: server.url,
434 token: server.accessToken,
435 path,
436 fields: { host: servers[1].host },
437 expectedStatus: HttpStatusCode.NO_CONTENT_204
438 })
439 })
440 })
441
442 describe('When unblocking a server', function () {
443 it('Should fail with an unauthenticated user', async function () {
444 await makeDeleteRequest({
445 url: server.url,
446 path: path + '/' + servers[1].host,
447 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
448 })
449 })
450
451 it('Should fail with a user without the appropriate rights', async function () {
452 await makeDeleteRequest({
453 url: server.url,
454 path: path + '/' + servers[1].host,
455 token: userAccessToken,
456 expectedStatus: HttpStatusCode.FORBIDDEN_403
457 })
458 })
459
460 it('Should fail with an unknown server block', async function () {
461 await makeDeleteRequest({
462 url: server.url,
463 path: path + '/127.0.0.1:9004',
464 token: server.accessToken,
465 expectedStatus: HttpStatusCode.NOT_FOUND_404
466 })
467 })
468
469 it('Should succeed with the correct params', async function () {
470 await makeDeleteRequest({
471 url: server.url,
472 path: path + '/' + servers[1].host,
473 token: server.accessToken,
474 expectedStatus: HttpStatusCode.NO_CONTENT_204
475 })
476 })
477 })
478 })
479 })
480
481 describe('When getting blocklist status', function () {
482 const path = '/api/v1/blocklist/status'
483
484 it('Should fail with a bad token', async function () {
485 await makeGetRequest({
486 url: server.url,
487 path,
488 token: 'false',
489 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
490 })
491 })
492
493 it('Should fail with a bad accounts field', async function () {
494 await makeGetRequest({
495 url: server.url,
496 path,
497 query: {
498 accounts: 1
499 },
500 expectedStatus: HttpStatusCode.BAD_REQUEST_400
501 })
502
503 await makeGetRequest({
504 url: server.url,
505 path,
506 query: {
507 accounts: [ 1 ]
508 },
509 expectedStatus: HttpStatusCode.BAD_REQUEST_400
510 })
511 })
512
513 it('Should fail with a bad hosts field', async function () {
514 await makeGetRequest({
515 url: server.url,
516 path,
517 query: {
518 hosts: 1
519 },
520 expectedStatus: HttpStatusCode.BAD_REQUEST_400
521 })
522
523 await makeGetRequest({
524 url: server.url,
525 path,
526 query: {
527 hosts: [ 1 ]
528 },
529 expectedStatus: HttpStatusCode.BAD_REQUEST_400
530 })
531 })
532
533 it('Should succeed with the correct parameters', async function () {
534 await makeGetRequest({
535 url: server.url,
536 path,
537 query: {},
538 expectedStatus: HttpStatusCode.OK_200
539 })
540
541 await makeGetRequest({
542 url: server.url,
543 path,
544 query: {
545 hosts: [ 'example.com' ],
546 accounts: [ 'john@example.com' ]
547 },
548 expectedStatus: HttpStatusCode.OK_200
549 })
550 })
551 })
552
553 after(async function () {
554 await cleanupTests(servers)
555 })
556})
diff --git a/server/tests/api/check-params/bulk.ts b/server/tests/api/check-params/bulk.ts
deleted file mode 100644
index f03264b4f..000000000
--- a/server/tests/api/check-params/bulk.ts
+++ /dev/null
@@ -1,80 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { cleanupTests, createSingleServer, makePostBodyRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
4import { HttpStatusCode } from '@shared/models'
5
6describe('Test bulk API validators', function () {
7 let server: PeerTubeServer
8 let userAccessToken: string
9
10 // ---------------------------------------------------------------
11
12 before(async function () {
13 this.timeout(120000)
14
15 server = await createSingleServer(1)
16 await setAccessTokensToServers([ server ])
17
18 const user = { username: 'user1', password: 'password' }
19 await server.users.create({ username: user.username, password: user.password })
20
21 userAccessToken = await server.login.getAccessToken(user)
22 })
23
24 describe('When removing comments of', function () {
25 const path = '/api/v1/bulk/remove-comments-of'
26
27 it('Should fail with an unauthenticated user', async function () {
28 await makePostBodyRequest({
29 url: server.url,
30 path,
31 fields: { accountName: 'user1', scope: 'my-videos' },
32 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
33 })
34 })
35
36 it('Should fail with an unknown account', async function () {
37 await makePostBodyRequest({
38 url: server.url,
39 token: server.accessToken,
40 path,
41 fields: { accountName: 'user2', scope: 'my-videos' },
42 expectedStatus: HttpStatusCode.NOT_FOUND_404
43 })
44 })
45
46 it('Should fail with an invalid scope', async function () {
47 await makePostBodyRequest({
48 url: server.url,
49 token: server.accessToken,
50 path,
51 fields: { accountName: 'user1', scope: 'my-videoss' },
52 expectedStatus: HttpStatusCode.BAD_REQUEST_400
53 })
54 })
55
56 it('Should fail to delete comments of the instance without the appropriate rights', async function () {
57 await makePostBodyRequest({
58 url: server.url,
59 token: userAccessToken,
60 path,
61 fields: { accountName: 'user1', scope: 'instance' },
62 expectedStatus: HttpStatusCode.FORBIDDEN_403
63 })
64 })
65
66 it('Should succeed with the correct params', async function () {
67 await makePostBodyRequest({
68 url: server.url,
69 token: server.accessToken,
70 path,
71 fields: { accountName: 'user1', scope: 'instance' },
72 expectedStatus: HttpStatusCode.NO_CONTENT_204
73 })
74 })
75 })
76
77 after(async function () {
78 await cleanupTests([ server ])
79 })
80})
diff --git a/server/tests/api/check-params/channel-import-videos.ts b/server/tests/api/check-params/channel-import-videos.ts
deleted file mode 100644
index 2de13b629..000000000
--- a/server/tests/api/check-params/channel-import-videos.ts
+++ /dev/null
@@ -1,209 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { FIXTURE_URLS } from '@server/tests/shared'
4import { areHttpImportTestsDisabled } from '@shared/core-utils'
5import { HttpStatusCode } from '@shared/models'
6import {
7 ChannelsCommand,
8 cleanupTests,
9 createSingleServer,
10 PeerTubeServer,
11 setAccessTokensToServers,
12 setDefaultVideoChannel
13} from '@shared/server-commands'
14
15describe('Test videos import in a channel API validator', function () {
16 let server: PeerTubeServer
17 const userInfo = {
18 accessToken: '',
19 channelName: 'fake_channel',
20 channelId: -1,
21 id: -1,
22 videoQuota: -1,
23 videoQuotaDaily: -1,
24 channelSyncId: -1
25 }
26 let command: ChannelsCommand
27
28 // ---------------------------------------------------------------
29
30 before(async function () {
31 this.timeout(120000)
32
33 server = await createSingleServer(1)
34
35 await setAccessTokensToServers([ server ])
36 await setDefaultVideoChannel([ server ])
37
38 await server.config.enableImports()
39 await server.config.enableChannelSync()
40
41 const userCreds = {
42 username: 'fake',
43 password: 'fake_password'
44 }
45
46 {
47 const user = await server.users.create({ username: userCreds.username, password: userCreds.password })
48 userInfo.id = user.id
49 userInfo.accessToken = await server.login.getAccessToken(userCreds)
50
51 const info = await server.users.getMyInfo({ token: userInfo.accessToken })
52 userInfo.channelId = info.videoChannels[0].id
53 }
54
55 {
56 const { videoChannelSync } = await server.channelSyncs.create({
57 token: userInfo.accessToken,
58 attributes: {
59 externalChannelUrl: FIXTURE_URLS.youtubeChannel,
60 videoChannelId: userInfo.channelId
61 }
62 })
63 userInfo.channelSyncId = videoChannelSync.id
64 }
65
66 command = server.channels
67 })
68
69 it('Should fail when HTTP upload is disabled', async function () {
70 await server.config.disableChannelSync()
71 await server.config.disableImports()
72
73 await command.importVideos({
74 channelName: server.store.channel.name,
75 externalChannelUrl: FIXTURE_URLS.youtubeChannel,
76 token: server.accessToken,
77 expectedStatus: HttpStatusCode.FORBIDDEN_403
78 })
79
80 await server.config.enableImports()
81 })
82
83 it('Should fail when externalChannelUrl is not provided', async function () {
84 await command.importVideos({
85 channelName: server.store.channel.name,
86 externalChannelUrl: null,
87 token: server.accessToken,
88 expectedStatus: HttpStatusCode.BAD_REQUEST_400
89 })
90 })
91
92 it('Should fail when externalChannelUrl is malformed', async function () {
93 await command.importVideos({
94 channelName: server.store.channel.name,
95 externalChannelUrl: 'not-a-url',
96 token: server.accessToken,
97 expectedStatus: HttpStatusCode.BAD_REQUEST_400
98 })
99 })
100
101 it('Should fail with a bad sync id', async function () {
102 await command.importVideos({
103 channelName: server.store.channel.name,
104 externalChannelUrl: FIXTURE_URLS.youtubeChannel,
105 videoChannelSyncId: 'toto' as any,
106 token: server.accessToken,
107 expectedStatus: HttpStatusCode.BAD_REQUEST_400
108 })
109 })
110
111 it('Should fail with a unknown sync id', async function () {
112 await command.importVideos({
113 channelName: server.store.channel.name,
114 externalChannelUrl: FIXTURE_URLS.youtubeChannel,
115 videoChannelSyncId: 42,
116 token: server.accessToken,
117 expectedStatus: HttpStatusCode.NOT_FOUND_404
118 })
119 })
120
121 it('Should fail with a sync id of another channel', async function () {
122 await command.importVideos({
123 channelName: server.store.channel.name,
124 externalChannelUrl: FIXTURE_URLS.youtubeChannel,
125 videoChannelSyncId: userInfo.channelSyncId,
126 token: server.accessToken,
127 expectedStatus: HttpStatusCode.FORBIDDEN_403
128 })
129 })
130
131 it('Should fail with no authentication', async function () {
132 await command.importVideos({
133 channelName: server.store.channel.name,
134 externalChannelUrl: FIXTURE_URLS.youtubeChannel,
135 token: null,
136 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
137 })
138 })
139
140 it('Should fail when sync is not owned by the user', async function () {
141 await command.importVideos({
142 channelName: server.store.channel.name,
143 externalChannelUrl: FIXTURE_URLS.youtubeChannel,
144 token: userInfo.accessToken,
145 expectedStatus: HttpStatusCode.FORBIDDEN_403
146 })
147 })
148
149 it('Should fail when the user has no quota', async function () {
150 await server.users.update({
151 userId: userInfo.id,
152 videoQuota: 0
153 })
154
155 await command.importVideos({
156 channelName: 'fake_channel',
157 externalChannelUrl: FIXTURE_URLS.youtubeChannel,
158 token: userInfo.accessToken,
159 expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413
160 })
161
162 await server.users.update({
163 userId: userInfo.id,
164 videoQuota: userInfo.videoQuota
165 })
166 })
167
168 it('Should fail when the user has no daily quota', async function () {
169 await server.users.update({
170 userId: userInfo.id,
171 videoQuotaDaily: 0
172 })
173
174 await command.importVideos({
175 channelName: 'fake_channel',
176 externalChannelUrl: FIXTURE_URLS.youtubeChannel,
177 token: userInfo.accessToken,
178 expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413
179 })
180
181 await server.users.update({
182 userId: userInfo.id,
183 videoQuotaDaily: userInfo.videoQuotaDaily
184 })
185 })
186
187 it('Should succeed when sync is run by its owner', async function () {
188 if (!areHttpImportTestsDisabled()) return
189
190 await command.importVideos({
191 channelName: 'fake_channel',
192 externalChannelUrl: FIXTURE_URLS.youtubeChannel,
193 token: userInfo.accessToken
194 })
195 })
196
197 it('Should succeed when sync is run with root and for another user\'s channel', async function () {
198 if (!areHttpImportTestsDisabled()) return
199
200 await command.importVideos({
201 channelName: 'fake_channel',
202 externalChannelUrl: FIXTURE_URLS.youtubeChannel
203 })
204 })
205
206 after(async function () {
207 await cleanupTests([ server ])
208 })
209})
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts
deleted file mode 100644
index 2f523d4ce..000000000
--- a/server/tests/api/check-params/config.ts
+++ /dev/null
@@ -1,428 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2import { merge } from 'lodash'
3import { omit } from '@shared/core-utils'
4import { CustomConfig, HttpStatusCode } from '@shared/models'
5import {
6 cleanupTests,
7 createSingleServer,
8 makeDeleteRequest,
9 makeGetRequest,
10 makePutBodyRequest,
11 PeerTubeServer,
12 setAccessTokensToServers
13} from '@shared/server-commands'
14
15describe('Test config API validators', function () {
16 const path = '/api/v1/config/custom'
17 let server: PeerTubeServer
18 let userAccessToken: string
19 const updateParams: CustomConfig = {
20 instance: {
21 name: 'PeerTube updated',
22 shortDescription: 'my short description',
23 description: 'my super description',
24 terms: 'my super terms',
25 codeOfConduct: 'my super coc',
26
27 creationReason: 'my super reason',
28 moderationInformation: 'my super moderation information',
29 administrator: 'Kuja',
30 maintenanceLifetime: 'forever',
31 businessModel: 'my super business model',
32 hardwareInformation: '2vCore 3GB RAM',
33
34 languages: [ 'en', 'es' ],
35 categories: [ 1, 2 ],
36
37 isNSFW: true,
38 defaultNSFWPolicy: 'blur',
39
40 defaultClientRoute: '/videos/recently-added',
41
42 customizations: {
43 javascript: 'alert("coucou")',
44 css: 'body { background-color: red; }'
45 }
46 },
47 theme: {
48 default: 'default'
49 },
50 services: {
51 twitter: {
52 username: '@MySuperUsername',
53 whitelisted: true
54 }
55 },
56 client: {
57 videos: {
58 miniature: {
59 preferAuthorDisplayName: false
60 }
61 },
62 menu: {
63 login: {
64 redirectOnSingleExternalAuth: false
65 }
66 }
67 },
68 cache: {
69 previews: {
70 size: 2
71 },
72 captions: {
73 size: 3
74 },
75 torrents: {
76 size: 4
77 },
78 storyboards: {
79 size: 5
80 }
81 },
82 signup: {
83 enabled: false,
84 limit: 5,
85 requiresApproval: false,
86 requiresEmailVerification: false,
87 minimumAge: 16
88 },
89 admin: {
90 email: 'superadmin1@example.com'
91 },
92 contactForm: {
93 enabled: false
94 },
95 user: {
96 history: {
97 videos: {
98 enabled: true
99 }
100 },
101 videoQuota: 5242881,
102 videoQuotaDaily: 318742
103 },
104 videoChannels: {
105 maxPerUser: 20
106 },
107 transcoding: {
108 enabled: true,
109 remoteRunners: {
110 enabled: true
111 },
112 allowAdditionalExtensions: true,
113 allowAudioFiles: true,
114 concurrency: 1,
115 threads: 1,
116 profile: 'vod_profile',
117 resolutions: {
118 '0p': false,
119 '144p': false,
120 '240p': false,
121 '360p': true,
122 '480p': true,
123 '720p': false,
124 '1080p': false,
125 '1440p': false,
126 '2160p': false
127 },
128 alwaysTranscodeOriginalResolution: false,
129 webVideos: {
130 enabled: true
131 },
132 hls: {
133 enabled: false
134 }
135 },
136 live: {
137 enabled: true,
138
139 allowReplay: false,
140 latencySetting: {
141 enabled: false
142 },
143 maxDuration: 30,
144 maxInstanceLives: -1,
145 maxUserLives: 50,
146
147 transcoding: {
148 enabled: true,
149 remoteRunners: {
150 enabled: true
151 },
152 threads: 4,
153 profile: 'live_profile',
154 resolutions: {
155 '144p': true,
156 '240p': true,
157 '360p': true,
158 '480p': true,
159 '720p': true,
160 '1080p': true,
161 '1440p': true,
162 '2160p': true
163 },
164 alwaysTranscodeOriginalResolution: false
165 }
166 },
167 videoStudio: {
168 enabled: true,
169 remoteRunners: {
170 enabled: true
171 }
172 },
173 videoFile: {
174 update: {
175 enabled: true
176 }
177 },
178 import: {
179 videos: {
180 concurrency: 1,
181 http: {
182 enabled: false
183 },
184 torrent: {
185 enabled: false
186 }
187 },
188 videoChannelSynchronization: {
189 enabled: false,
190 maxPerUser: 10
191 }
192 },
193 trending: {
194 videos: {
195 algorithms: {
196 enabled: [ 'hot', 'most-viewed', 'most-liked' ],
197 default: 'most-viewed'
198 }
199 }
200 },
201 autoBlacklist: {
202 videos: {
203 ofUsers: {
204 enabled: false
205 }
206 }
207 },
208 followers: {
209 instance: {
210 enabled: false,
211 manualApproval: true
212 }
213 },
214 followings: {
215 instance: {
216 autoFollowBack: {
217 enabled: true
218 },
219 autoFollowIndex: {
220 enabled: true,
221 indexUrl: 'https://index.example.com'
222 }
223 }
224 },
225 broadcastMessage: {
226 enabled: true,
227 dismissable: true,
228 message: 'super message',
229 level: 'warning'
230 },
231 search: {
232 remoteUri: {
233 users: true,
234 anonymous: true
235 },
236 searchIndex: {
237 enabled: true,
238 url: 'https://search.joinpeertube.org',
239 disableLocalSearch: true,
240 isDefaultSearch: true
241 }
242 }
243 }
244
245 // ---------------------------------------------------------------
246
247 before(async function () {
248 this.timeout(30000)
249
250 server = await createSingleServer(1)
251
252 await setAccessTokensToServers([ server ])
253
254 const user = {
255 username: 'user1',
256 password: 'password'
257 }
258 await server.users.create({ username: user.username, password: user.password })
259 userAccessToken = await server.login.getAccessToken(user)
260 })
261
262 describe('When getting the configuration', function () {
263 it('Should fail without token', async function () {
264 await makeGetRequest({
265 url: server.url,
266 path,
267 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
268 })
269 })
270
271 it('Should fail if the user is not an administrator', async function () {
272 await makeGetRequest({
273 url: server.url,
274 path,
275 token: userAccessToken,
276 expectedStatus: HttpStatusCode.FORBIDDEN_403
277 })
278 })
279 })
280
281 describe('When updating the configuration', function () {
282 it('Should fail without token', async function () {
283 await makePutBodyRequest({
284 url: server.url,
285 path,
286 fields: updateParams,
287 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
288 })
289 })
290
291 it('Should fail if the user is not an administrator', async function () {
292 await makePutBodyRequest({
293 url: server.url,
294 path,
295 fields: updateParams,
296 token: userAccessToken,
297 expectedStatus: HttpStatusCode.FORBIDDEN_403
298 })
299 })
300
301 it('Should fail if it misses a key', async function () {
302 const newUpdateParams = { ...updateParams, admin: omit(updateParams.admin, [ 'email' ]) }
303
304 await makePutBodyRequest({
305 url: server.url,
306 path,
307 fields: newUpdateParams,
308 token: server.accessToken,
309 expectedStatus: HttpStatusCode.BAD_REQUEST_400
310 })
311 })
312
313 it('Should fail with a bad default NSFW policy', async function () {
314 const newUpdateParams = {
315 ...updateParams,
316
317 instance: {
318 defaultNSFWPolicy: 'hello'
319 }
320 }
321
322 await makePutBodyRequest({
323 url: server.url,
324 path,
325 fields: newUpdateParams,
326 token: server.accessToken,
327 expectedStatus: HttpStatusCode.BAD_REQUEST_400
328 })
329 })
330
331 it('Should fail if email disabled and signup requires email verification', async function () {
332 // opposite scenario - success when enable enabled - covered via tests/api/users/user-verification.ts
333 const newUpdateParams = {
334 ...updateParams,
335
336 signup: {
337 enabled: true,
338 limit: 5,
339 requiresApproval: true,
340 requiresEmailVerification: true
341 }
342 }
343
344 await makePutBodyRequest({
345 url: server.url,
346 path,
347 fields: newUpdateParams,
348 token: server.accessToken,
349 expectedStatus: HttpStatusCode.BAD_REQUEST_400
350 })
351 })
352
353 it('Should fail with a disabled web videos & hls transcoding', async function () {
354 const newUpdateParams = {
355 ...updateParams,
356
357 transcoding: {
358 hls: {
359 enabled: false
360 },
361 web_videos: {
362 enabled: false
363 }
364 }
365 }
366
367 await makePutBodyRequest({
368 url: server.url,
369 path,
370 fields: newUpdateParams,
371 token: server.accessToken,
372 expectedStatus: HttpStatusCode.BAD_REQUEST_400
373 })
374 })
375
376 it('Should fail with a disabled http upload & enabled sync', async function () {
377 const newUpdateParams: CustomConfig = merge({}, updateParams, {
378 import: {
379 videos: {
380 http: { enabled: false }
381 },
382 videoChannelSynchronization: { enabled: true }
383 }
384 })
385
386 await makePutBodyRequest({
387 url: server.url,
388 path,
389 fields: newUpdateParams,
390 token: server.accessToken,
391 expectedStatus: HttpStatusCode.BAD_REQUEST_400
392 })
393 })
394
395 it('Should succeed with the correct parameters', async function () {
396 await makePutBodyRequest({
397 url: server.url,
398 path,
399 fields: updateParams,
400 token: server.accessToken,
401 expectedStatus: HttpStatusCode.OK_200
402 })
403 })
404 })
405
406 describe('When deleting the configuration', function () {
407 it('Should fail without token', async function () {
408 await makeDeleteRequest({
409 url: server.url,
410 path,
411 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
412 })
413 })
414
415 it('Should fail if the user is not an administrator', async function () {
416 await makeDeleteRequest({
417 url: server.url,
418 path,
419 token: userAccessToken,
420 expectedStatus: HttpStatusCode.FORBIDDEN_403
421 })
422 })
423 })
424
425 after(async function () {
426 await cleanupTests([ server ])
427 })
428})
diff --git a/server/tests/api/check-params/contact-form.ts b/server/tests/api/check-params/contact-form.ts
deleted file mode 100644
index f0f8819b9..000000000
--- a/server/tests/api/check-params/contact-form.ts
+++ /dev/null
@@ -1,86 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { MockSmtpServer } from '@server/tests/shared'
4import { HttpStatusCode } from '@shared/models'
5import {
6 cleanupTests,
7 ConfigCommand,
8 ContactFormCommand,
9 createSingleServer,
10 killallServers,
11 PeerTubeServer
12} from '@shared/server-commands'
13
14describe('Test contact form API validators', function () {
15 let server: PeerTubeServer
16 const emails: object[] = []
17 const defaultBody = {
18 fromName: 'super name',
19 fromEmail: 'toto@example.com',
20 subject: 'my subject',
21 body: 'Hello, how are you?'
22 }
23 let emailPort: number
24 let command: ContactFormCommand
25
26 // ---------------------------------------------------------------
27
28 before(async function () {
29 this.timeout(60000)
30
31 emailPort = await MockSmtpServer.Instance.collectEmails(emails)
32
33 // Email is disabled
34 server = await createSingleServer(1)
35 command = server.contactForm
36 })
37
38 it('Should not accept a contact form if emails are disabled', async function () {
39 await command.send({ ...defaultBody, expectedStatus: HttpStatusCode.CONFLICT_409 })
40 })
41
42 it('Should not accept a contact form if it is disabled in the configuration', async function () {
43 this.timeout(25000)
44
45 await killallServers([ server ])
46
47 // Contact form is disabled
48 await server.run({ ...ConfigCommand.getEmailOverrideConfig(emailPort), contact_form: { enabled: false } })
49 await command.send({ ...defaultBody, expectedStatus: HttpStatusCode.CONFLICT_409 })
50 })
51
52 it('Should not accept a contact form if from email is invalid', async function () {
53 this.timeout(25000)
54
55 await killallServers([ server ])
56
57 // Email & contact form enabled
58 await server.run(ConfigCommand.getEmailOverrideConfig(emailPort))
59
60 await command.send({ ...defaultBody, fromEmail: 'badEmail', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
61 await command.send({ ...defaultBody, fromEmail: 'badEmail@', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
62 await command.send({ ...defaultBody, fromEmail: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
63 })
64
65 it('Should not accept a contact form if from name is invalid', async function () {
66 await command.send({ ...defaultBody, fromName: 'name'.repeat(100), expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
67 await command.send({ ...defaultBody, fromName: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
68 await command.send({ ...defaultBody, fromName: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
69 })
70
71 it('Should not accept a contact form if body is invalid', async function () {
72 await command.send({ ...defaultBody, body: 'body'.repeat(5000), expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
73 await command.send({ ...defaultBody, body: 'a', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
74 await command.send({ ...defaultBody, body: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
75 })
76
77 it('Should accept a contact form with the correct parameters', async function () {
78 await command.send(defaultBody)
79 })
80
81 after(async function () {
82 MockSmtpServer.Instance.kill()
83
84 await cleanupTests([ server ])
85 })
86})
diff --git a/server/tests/api/check-params/custom-pages.ts b/server/tests/api/check-params/custom-pages.ts
deleted file mode 100644
index 63e3da3d5..000000000
--- a/server/tests/api/check-params/custom-pages.ts
+++ /dev/null
@@ -1,79 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { HttpStatusCode } from '@shared/models'
4import {
5 cleanupTests,
6 createSingleServer,
7 makeGetRequest,
8 makePutBodyRequest,
9 PeerTubeServer,
10 setAccessTokensToServers
11} from '@shared/server-commands'
12
13describe('Test custom pages validators', function () {
14 const path = '/api/v1/custom-pages/homepage/instance'
15
16 let server: PeerTubeServer
17 let userAccessToken: string
18
19 // ---------------------------------------------------------------
20
21 before(async function () {
22 this.timeout(120000)
23
24 server = await createSingleServer(1)
25 await setAccessTokensToServers([ server ])
26
27 const user = { username: 'user1', password: 'password' }
28 await server.users.create({ username: user.username, password: user.password })
29
30 userAccessToken = await server.login.getAccessToken(user)
31 })
32
33 describe('When updating instance homepage', function () {
34
35 it('Should fail with an unauthenticated user', async function () {
36 await makePutBodyRequest({
37 url: server.url,
38 path,
39 fields: { content: 'super content' },
40 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
41 })
42 })
43
44 it('Should fail with a non admin user', async function () {
45 await makePutBodyRequest({
46 url: server.url,
47 path,
48 token: userAccessToken,
49 fields: { content: 'super content' },
50 expectedStatus: HttpStatusCode.FORBIDDEN_403
51 })
52 })
53
54 it('Should succeed with the correct params', async function () {
55 await makePutBodyRequest({
56 url: server.url,
57 path,
58 token: server.accessToken,
59 fields: { content: 'super content' },
60 expectedStatus: HttpStatusCode.NO_CONTENT_204
61 })
62 })
63 })
64
65 describe('When getting instance homapage', function () {
66
67 it('Should succeed with the correct params', async function () {
68 await makeGetRequest({
69 url: server.url,
70 path,
71 expectedStatus: HttpStatusCode.OK_200
72 })
73 })
74 })
75
76 after(async function () {
77 await cleanupTests([ server ])
78 })
79})
diff --git a/server/tests/api/check-params/debug.ts b/server/tests/api/check-params/debug.ts
deleted file mode 100644
index d7b68f163..000000000
--- a/server/tests/api/check-params/debug.ts
+++ /dev/null
@@ -1,61 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
4import { HttpStatusCode } from '@shared/models'
5
6describe('Test debug API validators', function () {
7 const path = '/api/v1/server/debug'
8 let server: PeerTubeServer
9 let userAccessToken = ''
10
11 // ---------------------------------------------------------------
12
13 before(async function () {
14 this.timeout(120000)
15
16 server = await createSingleServer(1)
17
18 await setAccessTokensToServers([ server ])
19
20 const user = {
21 username: 'user1',
22 password: 'my super password'
23 }
24 await server.users.create({ username: user.username, password: user.password })
25 userAccessToken = await server.login.getAccessToken(user)
26 })
27
28 describe('When getting debug endpoint', function () {
29
30 it('Should fail with a non authenticated user', async function () {
31 await makeGetRequest({
32 url: server.url,
33 path,
34 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
35 })
36 })
37
38 it('Should fail with a non admin user', async function () {
39 await makeGetRequest({
40 url: server.url,
41 path,
42 token: userAccessToken,
43 expectedStatus: HttpStatusCode.FORBIDDEN_403
44 })
45 })
46
47 it('Should succeed with the correct params', async function () {
48 await makeGetRequest({
49 url: server.url,
50 path,
51 token: server.accessToken,
52 query: { startDate: new Date().toISOString() },
53 expectedStatus: HttpStatusCode.OK_200
54 })
55 })
56 })
57
58 after(async function () {
59 await cleanupTests([ server ])
60 })
61})
diff --git a/server/tests/api/check-params/follows.ts b/server/tests/api/check-params/follows.ts
deleted file mode 100644
index 3c911dcee..000000000
--- a/server/tests/api/check-params/follows.ts
+++ /dev/null
@@ -1,369 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
4import { HttpStatusCode } from '@shared/models'
5import {
6 cleanupTests,
7 createSingleServer,
8 makeDeleteRequest,
9 makeGetRequest,
10 makePostBodyRequest,
11 PeerTubeServer,
12 setAccessTokensToServers
13} from '@shared/server-commands'
14
15describe('Test server follows API validators', function () {
16 let server: PeerTubeServer
17
18 // ---------------------------------------------------------------
19
20 before(async function () {
21 this.timeout(30000)
22
23 server = await createSingleServer(1)
24
25 await setAccessTokensToServers([ server ])
26 })
27
28 describe('When managing following', function () {
29 let userAccessToken = null
30
31 before(async function () {
32 userAccessToken = await server.users.generateUserAndToken('user1')
33 })
34
35 describe('When adding follows', function () {
36 const path = '/api/v1/server/following'
37
38 it('Should fail with nothing', async function () {
39 await makePostBodyRequest({
40 url: server.url,
41 path,
42 token: server.accessToken,
43 expectedStatus: HttpStatusCode.BAD_REQUEST_400
44 })
45 })
46
47 it('Should fail if hosts is not composed by hosts', async function () {
48 await makePostBodyRequest({
49 url: server.url,
50 path,
51 fields: { hosts: [ '127.0.0.1:9002', '127.0.0.1:coucou' ] },
52 token: server.accessToken,
53 expectedStatus: HttpStatusCode.BAD_REQUEST_400
54 })
55 })
56
57 it('Should fail if hosts is composed with http schemes', async function () {
58 await makePostBodyRequest({
59 url: server.url,
60 path,
61 fields: { hosts: [ '127.0.0.1:9002', 'http://127.0.0.1:9003' ] },
62 token: server.accessToken,
63 expectedStatus: HttpStatusCode.BAD_REQUEST_400
64 })
65 })
66
67 it('Should fail if hosts are not unique', async function () {
68 await makePostBodyRequest({
69 url: server.url,
70 path,
71 fields: { urls: [ '127.0.0.1:9002', '127.0.0.1:9002' ] },
72 token: server.accessToken,
73 expectedStatus: HttpStatusCode.BAD_REQUEST_400
74 })
75 })
76
77 it('Should fail if handles is not composed by handles', async function () {
78 await makePostBodyRequest({
79 url: server.url,
80 path,
81 fields: { handles: [ 'hello@example.com', '127.0.0.1:9001' ] },
82 token: server.accessToken,
83 expectedStatus: HttpStatusCode.BAD_REQUEST_400
84 })
85 })
86
87 it('Should fail if handles are not unique', async function () {
88 await makePostBodyRequest({
89 url: server.url,
90 path,
91 fields: { urls: [ 'hello@example.com', 'hello@example.com' ] },
92 token: server.accessToken,
93 expectedStatus: HttpStatusCode.BAD_REQUEST_400
94 })
95 })
96
97 it('Should fail with an invalid token', async function () {
98 await makePostBodyRequest({
99 url: server.url,
100 path,
101 fields: { hosts: [ '127.0.0.1:9002' ] },
102 token: 'fake_token',
103 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
104 })
105 })
106
107 it('Should fail if the user is not an administrator', async function () {
108 await makePostBodyRequest({
109 url: server.url,
110 path,
111 fields: { hosts: [ '127.0.0.1:9002' ] },
112 token: userAccessToken,
113 expectedStatus: HttpStatusCode.FORBIDDEN_403
114 })
115 })
116 })
117
118 describe('When listing followings', function () {
119 const path = '/api/v1/server/following'
120
121 it('Should fail with a bad start pagination', async function () {
122 await checkBadStartPagination(server.url, path)
123 })
124
125 it('Should fail with a bad count pagination', async function () {
126 await checkBadCountPagination(server.url, path)
127 })
128
129 it('Should fail with an incorrect sort', async function () {
130 await checkBadSortPagination(server.url, path)
131 })
132
133 it('Should fail with an incorrect state', async function () {
134 await makeGetRequest({
135 url: server.url,
136 path,
137 query: {
138 state: 'blabla'
139 }
140 })
141 })
142
143 it('Should fail with an incorrect actor type', async function () {
144 await makeGetRequest({
145 url: server.url,
146 path,
147 query: {
148 actorType: 'blabla'
149 }
150 })
151 })
152
153 it('Should fail succeed with the correct params', async function () {
154 await makeGetRequest({
155 url: server.url,
156 path,
157 expectedStatus: HttpStatusCode.OK_200,
158 query: {
159 state: 'accepted',
160 actorType: 'Application'
161 }
162 })
163 })
164 })
165
166 describe('When listing followers', function () {
167 const path = '/api/v1/server/followers'
168
169 it('Should fail with a bad start pagination', async function () {
170 await checkBadStartPagination(server.url, path)
171 })
172
173 it('Should fail with a bad count pagination', async function () {
174 await checkBadCountPagination(server.url, path)
175 })
176
177 it('Should fail with an incorrect sort', async function () {
178 await checkBadSortPagination(server.url, path)
179 })
180
181 it('Should fail with an incorrect actor type', async function () {
182 await makeGetRequest({
183 url: server.url,
184 path,
185 query: {
186 actorType: 'blabla'
187 }
188 })
189 })
190
191 it('Should fail with an incorrect state', async function () {
192 await makeGetRequest({
193 url: server.url,
194 path,
195 query: {
196 state: 'blabla',
197 actorType: 'Application'
198 }
199 })
200 })
201
202 it('Should fail succeed with the correct params', async function () {
203 await makeGetRequest({
204 url: server.url,
205 path,
206 expectedStatus: HttpStatusCode.OK_200,
207 query: {
208 state: 'accepted'
209 }
210 })
211 })
212 })
213
214 describe('When removing a follower', function () {
215 const path = '/api/v1/server/followers'
216
217 it('Should fail with an invalid token', async function () {
218 await makeDeleteRequest({
219 url: server.url,
220 path: path + '/toto@127.0.0.1:9002',
221 token: 'fake_token',
222 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
223 })
224 })
225
226 it('Should fail if the user is not an administrator', async function () {
227 await makeDeleteRequest({
228 url: server.url,
229 path: path + '/toto@127.0.0.1:9002',
230 token: userAccessToken,
231 expectedStatus: HttpStatusCode.FORBIDDEN_403
232 })
233 })
234
235 it('Should fail with an invalid follower', async function () {
236 await makeDeleteRequest({
237 url: server.url,
238 path: path + '/toto',
239 token: server.accessToken,
240 expectedStatus: HttpStatusCode.BAD_REQUEST_400
241 })
242 })
243
244 it('Should fail with an unknown follower', async function () {
245 await makeDeleteRequest({
246 url: server.url,
247 path: path + '/toto@127.0.0.1:9003',
248 token: server.accessToken,
249 expectedStatus: HttpStatusCode.NOT_FOUND_404
250 })
251 })
252 })
253
254 describe('When accepting a follower', function () {
255 const path = '/api/v1/server/followers'
256
257 it('Should fail with an invalid token', async function () {
258 await makePostBodyRequest({
259 url: server.url,
260 path: path + '/toto@127.0.0.1:9002/accept',
261 token: 'fake_token',
262 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
263 })
264 })
265
266 it('Should fail if the user is not an administrator', async function () {
267 await makePostBodyRequest({
268 url: server.url,
269 path: path + '/toto@127.0.0.1:9002/accept',
270 token: userAccessToken,
271 expectedStatus: HttpStatusCode.FORBIDDEN_403
272 })
273 })
274
275 it('Should fail with an invalid follower', async function () {
276 await makePostBodyRequest({
277 url: server.url,
278 path: path + '/toto/accept',
279 token: server.accessToken,
280 expectedStatus: HttpStatusCode.BAD_REQUEST_400
281 })
282 })
283
284 it('Should fail with an unknown follower', async function () {
285 await makePostBodyRequest({
286 url: server.url,
287 path: path + '/toto@127.0.0.1:9003/accept',
288 token: server.accessToken,
289 expectedStatus: HttpStatusCode.NOT_FOUND_404
290 })
291 })
292 })
293
294 describe('When rejecting a follower', function () {
295 const path = '/api/v1/server/followers'
296
297 it('Should fail with an invalid token', async function () {
298 await makePostBodyRequest({
299 url: server.url,
300 path: path + '/toto@127.0.0.1:9002/reject',
301 token: 'fake_token',
302 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
303 })
304 })
305
306 it('Should fail if the user is not an administrator', async function () {
307 await makePostBodyRequest({
308 url: server.url,
309 path: path + '/toto@127.0.0.1:9002/reject',
310 token: userAccessToken,
311 expectedStatus: HttpStatusCode.FORBIDDEN_403
312 })
313 })
314
315 it('Should fail with an invalid follower', async function () {
316 await makePostBodyRequest({
317 url: server.url,
318 path: path + '/toto/reject',
319 token: server.accessToken,
320 expectedStatus: HttpStatusCode.BAD_REQUEST_400
321 })
322 })
323
324 it('Should fail with an unknown follower', async function () {
325 await makePostBodyRequest({
326 url: server.url,
327 path: path + '/toto@127.0.0.1:9003/reject',
328 token: server.accessToken,
329 expectedStatus: HttpStatusCode.NOT_FOUND_404
330 })
331 })
332 })
333
334 describe('When removing following', function () {
335 const path = '/api/v1/server/following'
336
337 it('Should fail with an invalid token', async function () {
338 await makeDeleteRequest({
339 url: server.url,
340 path: path + '/127.0.0.1:9002',
341 token: 'fake_token',
342 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
343 })
344 })
345
346 it('Should fail if the user is not an administrator', async function () {
347 await makeDeleteRequest({
348 url: server.url,
349 path: path + '/127.0.0.1:9002',
350 token: userAccessToken,
351 expectedStatus: HttpStatusCode.FORBIDDEN_403
352 })
353 })
354
355 it('Should fail if we do not follow this server', async function () {
356 await makeDeleteRequest({
357 url: server.url,
358 path: path + '/example.com',
359 token: server.accessToken,
360 expectedStatus: HttpStatusCode.NOT_FOUND_404
361 })
362 })
363 })
364 })
365
366 after(async function () {
367 await cleanupTests([ server ])
368 })
369})
diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts
deleted file mode 100644
index c2a7ccd78..000000000
--- a/server/tests/api/check-params/index.ts
+++ /dev/null
@@ -1,45 +0,0 @@
1import './abuses'
2import './accounts'
3import './blocklist'
4import './bulk'
5import './channel-import-videos'
6import './config'
7import './contact-form'
8import './custom-pages'
9import './debug'
10import './follows'
11import './jobs'
12import './live'
13import './logs'
14import './metrics'
15import './my-user'
16import './plugins'
17import './redundancy'
18import './registrations'
19import './runners'
20import './search'
21import './services'
22import './transcoding'
23import './two-factor'
24import './upload-quota'
25import './user-notifications'
26import './user-subscriptions'
27import './users-admin'
28import './users-emails'
29import './video-blacklist'
30import './video-captions'
31import './video-channel-syncs'
32import './video-channels'
33import './video-comments'
34import './video-files'
35import './video-imports'
36import './video-playlists'
37import './video-storyboards'
38import './video-source'
39import './video-studio'
40import './video-token'
41import './videos-common-filters'
42import './videos-history'
43import './videos-overviews'
44import './videos'
45import './views'
diff --git a/server/tests/api/check-params/jobs.ts b/server/tests/api/check-params/jobs.ts
deleted file mode 100644
index 873da3955..000000000
--- a/server/tests/api/check-params/jobs.ts
+++ /dev/null
@@ -1,125 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
4import { HttpStatusCode } from '@shared/models'
5import {
6 cleanupTests,
7 createSingleServer,
8 makeGetRequest,
9 makePostBodyRequest,
10 PeerTubeServer,
11 setAccessTokensToServers
12} from '@shared/server-commands'
13
14describe('Test jobs API validators', function () {
15 const path = '/api/v1/jobs/failed'
16 let server: PeerTubeServer
17 let userAccessToken = ''
18
19 // ---------------------------------------------------------------
20
21 before(async function () {
22 this.timeout(120000)
23
24 server = await createSingleServer(1)
25
26 await setAccessTokensToServers([ server ])
27
28 const user = {
29 username: 'user1',
30 password: 'my super password'
31 }
32 await server.users.create({ username: user.username, password: user.password })
33 userAccessToken = await server.login.getAccessToken(user)
34 })
35
36 describe('When listing jobs', function () {
37
38 it('Should fail with a bad state', async function () {
39 await makeGetRequest({
40 url: server.url,
41 token: server.accessToken,
42 path: path + 'ade'
43 })
44 })
45
46 it('Should fail with an incorrect job type', async function () {
47 await makeGetRequest({
48 url: server.url,
49 token: server.accessToken,
50 path,
51 query: {
52 jobType: 'toto'
53 }
54 })
55 })
56
57 it('Should fail with a bad start pagination', async function () {
58 await checkBadStartPagination(server.url, path, server.accessToken)
59 })
60
61 it('Should fail with a bad count pagination', async function () {
62 await checkBadCountPagination(server.url, path, server.accessToken)
63 })
64
65 it('Should fail with an incorrect sort', async function () {
66 await checkBadSortPagination(server.url, path, server.accessToken)
67 })
68
69 it('Should fail with a non authenticated user', async function () {
70 await makeGetRequest({
71 url: server.url,
72 path,
73 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
74 })
75 })
76
77 it('Should fail with a non admin user', async function () {
78 await makeGetRequest({
79 url: server.url,
80 path,
81 token: userAccessToken,
82 expectedStatus: HttpStatusCode.FORBIDDEN_403
83 })
84 })
85 })
86
87 describe('When pausing/resuming the job queue', async function () {
88 const commands = [ 'pause', 'resume' ]
89
90 it('Should fail with a non authenticated user', async function () {
91 for (const command of commands) {
92 await makePostBodyRequest({
93 url: server.url,
94 path: '/api/v1/jobs/' + command,
95 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
96 })
97 }
98 })
99
100 it('Should fail with a non admin user', async function () {
101 for (const command of commands) {
102 await makePostBodyRequest({
103 url: server.url,
104 path: '/api/v1/jobs/' + command,
105 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
106 })
107 }
108 })
109
110 it('Should succeed with the correct params', async function () {
111 for (const command of commands) {
112 await makePostBodyRequest({
113 url: server.url,
114 path: '/api/v1/jobs/' + command,
115 token: server.accessToken,
116 expectedStatus: HttpStatusCode.NO_CONTENT_204
117 })
118 }
119 })
120 })
121
122 after(async function () {
123 await cleanupTests([ server ])
124 })
125})
diff --git a/server/tests/api/check-params/live.ts b/server/tests/api/check-params/live.ts
deleted file mode 100644
index 5021db516..000000000
--- a/server/tests/api/check-params/live.ts
+++ /dev/null
@@ -1,589 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { buildAbsoluteFixturePath, omit } from '@shared/core-utils'
5import { HttpStatusCode, LiveVideoLatencyMode, VideoCreateResult, VideoPrivacy } from '@shared/models'
6import {
7 cleanupTests,
8 createSingleServer,
9 LiveCommand,
10 makePostBodyRequest,
11 makeUploadRequest,
12 PeerTubeServer,
13 sendRTMPStream,
14 setAccessTokensToServers,
15 stopFfmpeg
16} from '@shared/server-commands'
17
18describe('Test video lives API validator', function () {
19 const path = '/api/v1/videos/live'
20 let server: PeerTubeServer
21 let userAccessToken = ''
22 let channelId: number
23 let video: VideoCreateResult
24 let videoIdNotLive: number
25 let command: LiveCommand
26
27 // ---------------------------------------------------------------
28
29 before(async function () {
30 this.timeout(30000)
31
32 server = await createSingleServer(1)
33
34 await setAccessTokensToServers([ server ])
35
36 await server.config.updateCustomSubConfig({
37 newConfig: {
38 live: {
39 enabled: true,
40 latencySetting: {
41 enabled: false
42 },
43 maxInstanceLives: 20,
44 maxUserLives: 20,
45 allowReplay: true
46 }
47 }
48 })
49
50 const username = 'user1'
51 const password = 'my super password'
52 await server.users.create({ username, password })
53 userAccessToken = await server.login.getAccessToken({ username, password })
54
55 {
56 const { videoChannels } = await server.users.getMyInfo()
57 channelId = videoChannels[0].id
58 }
59
60 {
61 videoIdNotLive = (await server.videos.quickUpload({ name: 'not live' })).id
62 }
63
64 command = server.live
65 })
66
67 describe('When creating a live', function () {
68 let baseCorrectParams
69
70 before(function () {
71 baseCorrectParams = {
72 name: 'my super name',
73 category: 5,
74 licence: 1,
75 language: 'pt',
76 nsfw: false,
77 commentsEnabled: true,
78 downloadEnabled: true,
79 waitTranscoding: true,
80 description: 'my super description',
81 support: 'my super support text',
82 tags: [ 'tag1', 'tag2' ],
83 privacy: VideoPrivacy.PUBLIC,
84 channelId,
85 saveReplay: false,
86 replaySettings: undefined,
87 permanentLive: false,
88 latencyMode: LiveVideoLatencyMode.DEFAULT
89 }
90 })
91
92 it('Should fail with nothing', async function () {
93 const fields = {}
94 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
95 })
96
97 it('Should fail with a long name', async function () {
98 const fields = { ...baseCorrectParams, name: 'super'.repeat(65) }
99
100 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
101 })
102
103 it('Should fail with a bad category', async function () {
104 const fields = { ...baseCorrectParams, category: 125 }
105
106 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
107 })
108
109 it('Should fail with a bad licence', async function () {
110 const fields = { ...baseCorrectParams, licence: 125 }
111
112 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
113 })
114
115 it('Should fail with a bad language', async function () {
116 const fields = { ...baseCorrectParams, language: 'a'.repeat(15) }
117
118 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
119 })
120
121 it('Should fail with a long description', async function () {
122 const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) }
123
124 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
125 })
126
127 it('Should fail with a long support text', async function () {
128 const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
129
130 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
131 })
132
133 it('Should fail without a channel', async function () {
134 const fields = omit(baseCorrectParams, [ 'channelId' ])
135
136 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
137 })
138
139 it('Should fail with a bad channel', async function () {
140 const fields = { ...baseCorrectParams, channelId: 545454 }
141
142 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
143 })
144
145 it('Should fail with a bad privacy for replay settings', async function () {
146 const fields = { ...baseCorrectParams, saveReplay: true, replaySettings: { privacy: 999 } }
147
148 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
149 })
150
151 it('Should fail with another user channel', async function () {
152 const user = {
153 username: 'fake',
154 password: 'fake_password'
155 }
156 await server.users.create({ username: user.username, password: user.password })
157
158 const accessTokenUser = await server.login.getAccessToken(user)
159 const { videoChannels } = await server.users.getMyInfo({ token: accessTokenUser })
160 const customChannelId = videoChannels[0].id
161
162 const fields = { ...baseCorrectParams, channelId: customChannelId }
163
164 await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields })
165 })
166
167 it('Should fail with too many tags', async function () {
168 const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }
169
170 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
171 })
172
173 it('Should fail with a tag length too low', async function () {
174 const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] }
175
176 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
177 })
178
179 it('Should fail with a tag length too big', async function () {
180 const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }
181
182 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
183 })
184
185 it('Should fail with an incorrect thumbnail file', async function () {
186 const fields = baseCorrectParams
187 const attaches = {
188 thumbnailfile: buildAbsoluteFixturePath('video_short.mp4')
189 }
190
191 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
192 })
193
194 it('Should fail with a big thumbnail file', async function () {
195 const fields = baseCorrectParams
196 const attaches = {
197 thumbnailfile: buildAbsoluteFixturePath('custom-preview-big.png')
198 }
199
200 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
201 })
202
203 it('Should fail with an incorrect preview file', async function () {
204 const fields = baseCorrectParams
205 const attaches = {
206 previewfile: buildAbsoluteFixturePath('video_short.mp4')
207 }
208
209 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
210 })
211
212 it('Should fail with a big preview file', async function () {
213 const fields = baseCorrectParams
214 const attaches = {
215 previewfile: buildAbsoluteFixturePath('custom-preview-big.png')
216 }
217
218 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
219 })
220
221 it('Should fail with bad latency setting', async function () {
222 const fields = { ...baseCorrectParams, latencyMode: 42 }
223
224 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
225 })
226
227 it('Should fail to set latency if the server does not allow it', async function () {
228 const fields = { ...baseCorrectParams, latencyMode: LiveVideoLatencyMode.HIGH_LATENCY }
229
230 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
231 })
232
233 it('Should succeed with the correct parameters', async function () {
234 this.timeout(30000)
235
236 const res = await makePostBodyRequest({
237 url: server.url,
238 path,
239 token: server.accessToken,
240 fields: baseCorrectParams,
241 expectedStatus: HttpStatusCode.OK_200
242 })
243
244 video = res.body.video
245 })
246
247 it('Should forbid if live is disabled', async function () {
248 await server.config.updateCustomSubConfig({
249 newConfig: {
250 live: {
251 enabled: false
252 }
253 }
254 })
255
256 await makePostBodyRequest({
257 url: server.url,
258 path,
259 token: server.accessToken,
260 fields: baseCorrectParams,
261 expectedStatus: HttpStatusCode.FORBIDDEN_403
262 })
263 })
264
265 it('Should forbid to save replay if not enabled by the admin', async function () {
266 const fields = { ...baseCorrectParams, saveReplay: true, replaySettings: { privacy: VideoPrivacy.PUBLIC } }
267
268 await server.config.updateCustomSubConfig({
269 newConfig: {
270 live: {
271 enabled: true,
272 allowReplay: false
273 }
274 }
275 })
276
277 await makePostBodyRequest({
278 url: server.url,
279 path,
280 token: server.accessToken,
281 fields,
282 expectedStatus: HttpStatusCode.FORBIDDEN_403
283 })
284 })
285
286 it('Should allow to save replay if enabled by the admin', async function () {
287 const fields = { ...baseCorrectParams, saveReplay: true, replaySettings: { privacy: VideoPrivacy.PUBLIC } }
288
289 await server.config.updateCustomSubConfig({
290 newConfig: {
291 live: {
292 enabled: true,
293 allowReplay: true
294 }
295 }
296 })
297
298 await makePostBodyRequest({
299 url: server.url,
300 path,
301 token: server.accessToken,
302 fields,
303 expectedStatus: HttpStatusCode.OK_200
304 })
305 })
306
307 it('Should not allow live if max instance lives is reached', async function () {
308 await server.config.updateCustomSubConfig({
309 newConfig: {
310 live: {
311 enabled: true,
312 maxInstanceLives: 1
313 }
314 }
315 })
316
317 await makePostBodyRequest({
318 url: server.url,
319 path,
320 token: server.accessToken,
321 fields: baseCorrectParams,
322 expectedStatus: HttpStatusCode.FORBIDDEN_403
323 })
324 })
325
326 it('Should not allow live if max user lives is reached', async function () {
327 await server.config.updateCustomSubConfig({
328 newConfig: {
329 live: {
330 enabled: true,
331 maxInstanceLives: 20,
332 maxUserLives: 1
333 }
334 }
335 })
336
337 await makePostBodyRequest({
338 url: server.url,
339 path,
340 token: server.accessToken,
341 fields: baseCorrectParams,
342 expectedStatus: HttpStatusCode.FORBIDDEN_403
343 })
344 })
345 })
346
347 describe('When getting live information', function () {
348
349 it('Should fail with a bad access token', async function () {
350 await command.get({ token: 'toto', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
351 })
352
353 it('Should not display private information without access token', async function () {
354 const live = await command.get({ token: '', videoId: video.id })
355
356 expect(live.rtmpUrl).to.not.exist
357 expect(live.streamKey).to.not.exist
358 expect(live.latencyMode).to.exist
359 })
360
361 it('Should not display private information with token of another user', async function () {
362 const live = await command.get({ token: userAccessToken, videoId: video.id })
363
364 expect(live.rtmpUrl).to.not.exist
365 expect(live.streamKey).to.not.exist
366 expect(live.latencyMode).to.exist
367 })
368
369 it('Should display private information with appropriate token', async function () {
370 const live = await command.get({ videoId: video.id })
371
372 expect(live.rtmpUrl).to.exist
373 expect(live.streamKey).to.exist
374 expect(live.latencyMode).to.exist
375 })
376
377 it('Should fail with a bad video id', async function () {
378 await command.get({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
379 })
380
381 it('Should fail with an unknown video id', async function () {
382 await command.get({ videoId: 454555, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
383 })
384
385 it('Should fail with a non live video', async function () {
386 await command.get({ videoId: videoIdNotLive, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
387 })
388
389 it('Should succeed with the correct params', async function () {
390 await command.get({ videoId: video.id })
391 await command.get({ videoId: video.uuid })
392 await command.get({ videoId: video.shortUUID })
393 })
394 })
395
396 describe('When getting live sessions', function () {
397
398 it('Should fail with a bad access token', async function () {
399 await command.listSessions({ token: 'toto', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
400 })
401
402 it('Should fail without token', async function () {
403 await command.listSessions({ token: null, videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
404 })
405
406 it('Should fail with the token of another user', async function () {
407 await command.listSessions({ token: userAccessToken, videoId: video.id, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
408 })
409
410 it('Should fail with a bad video id', async function () {
411 await command.listSessions({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
412 })
413
414 it('Should fail with an unknown video id', async function () {
415 await command.listSessions({ videoId: 454555, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
416 })
417
418 it('Should fail with a non live video', async function () {
419 await command.listSessions({ videoId: videoIdNotLive, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
420 })
421
422 it('Should succeed with the correct params', async function () {
423 await command.listSessions({ videoId: video.id })
424 })
425 })
426
427 describe('When getting live session of a replay', function () {
428
429 it('Should fail with a bad video id', async function () {
430 await command.getReplaySession({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
431 })
432
433 it('Should fail with an unknown video id', async function () {
434 await command.getReplaySession({ videoId: 454555, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
435 })
436
437 it('Should fail with a non replay video', async function () {
438 await command.getReplaySession({ videoId: videoIdNotLive, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
439 })
440 })
441
442 describe('When updating live information', async function () {
443
444 it('Should fail without access token', async function () {
445 await command.update({ token: '', videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
446 })
447
448 it('Should fail with a bad access token', async function () {
449 await command.update({ token: 'toto', videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
450 })
451
452 it('Should fail with access token of another user', async function () {
453 await command.update({ token: userAccessToken, videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
454 })
455
456 it('Should fail with a bad video id', async function () {
457 await command.update({ videoId: 'toto', fields: {}, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
458 })
459
460 it('Should fail with an unknown video id', async function () {
461 await command.update({ videoId: 454555, fields: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
462 })
463
464 it('Should fail with a non live video', async function () {
465 await command.update({ videoId: videoIdNotLive, fields: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
466 })
467
468 it('Should fail with bad latency setting', async function () {
469 const fields = { latencyMode: 42 }
470
471 await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
472 })
473
474 it('Should fail with a bad privacy for replay settings', async function () {
475 const fields = { saveReplay: true, replaySettings: { privacy: 999 } }
476
477 await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
478 })
479
480 it('Should fail with save replay enabled but without replay settings', async function () {
481 await server.config.updateCustomSubConfig({
482 newConfig: {
483 live: {
484 enabled: true,
485 allowReplay: true
486 }
487 }
488 })
489
490 const fields = { saveReplay: true }
491
492 await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
493 })
494
495 it('Should fail with save replay disabled and replay settings', async function () {
496 const fields = { saveReplay: false, replaySettings: { privacy: VideoPrivacy.INTERNAL } }
497
498 await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
499 })
500
501 it('Should fail with only replay settings when save replay is disabled', async function () {
502 const fields = { replaySettings: { privacy: VideoPrivacy.INTERNAL } }
503
504 await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
505 })
506
507 it('Should fail to set latency if the server does not allow it', async function () {
508 const fields = { latencyMode: LiveVideoLatencyMode.HIGH_LATENCY }
509
510 await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
511 })
512
513 it('Should succeed with the correct params', async function () {
514 await command.update({ videoId: video.id, fields: { saveReplay: false } })
515 await command.update({ videoId: video.uuid, fields: { saveReplay: false } })
516 await command.update({ videoId: video.shortUUID, fields: { saveReplay: false } })
517
518 await command.update({ videoId: video.id, fields: { saveReplay: true, replaySettings: { privacy: VideoPrivacy.PUBLIC } } })
519
520 })
521
522 it('Should fail to update replay status if replay is not allowed on the instance', async function () {
523 await server.config.updateCustomSubConfig({
524 newConfig: {
525 live: {
526 enabled: true,
527 allowReplay: false
528 }
529 }
530 })
531
532 await command.update({ videoId: video.id, fields: { saveReplay: true }, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
533 })
534
535 it('Should fail to update a live if it has already started', async function () {
536 this.timeout(40000)
537
538 const live = await command.get({ videoId: video.id })
539
540 const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey })
541
542 await command.waitUntilPublished({ videoId: video.id })
543 await command.update({ videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
544
545 await stopFfmpeg(ffmpegCommand)
546 })
547
548 it('Should fail to change live privacy if it has already started', async function () {
549 this.timeout(40000)
550
551 const live = await command.get({ videoId: video.id })
552
553 const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey })
554
555 await command.waitUntilPublished({ videoId: video.id })
556
557 await server.videos.update({
558 id: video.id,
559 attributes: { privacy: VideoPrivacy.PUBLIC } // Same privacy, it's fine
560 })
561
562 await server.videos.update({
563 id: video.id,
564 attributes: { privacy: VideoPrivacy.UNLISTED },
565 expectedStatus: HttpStatusCode.BAD_REQUEST_400
566 })
567
568 await stopFfmpeg(ffmpegCommand)
569 })
570
571 it('Should fail to stream twice in the save live', async function () {
572 this.timeout(40000)
573
574 const live = await command.get({ videoId: video.id })
575
576 const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey })
577
578 await command.waitUntilPublished({ videoId: video.id })
579
580 await command.runAndTestStreamError({ videoId: video.id, shouldHaveError: true })
581
582 await stopFfmpeg(ffmpegCommand)
583 })
584 })
585
586 after(async function () {
587 await cleanupTests([ server ])
588 })
589})
diff --git a/server/tests/api/check-params/logs.ts b/server/tests/api/check-params/logs.ts
deleted file mode 100644
index 2496cee31..000000000
--- a/server/tests/api/check-params/logs.ts
+++ /dev/null
@@ -1,157 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { HttpStatusCode } from '@shared/models'
5import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
6
7describe('Test logs API validators', function () {
8 const path = '/api/v1/server/logs'
9 let server: PeerTubeServer
10 let userAccessToken = ''
11
12 // ---------------------------------------------------------------
13
14 before(async function () {
15 this.timeout(120000)
16
17 server = await createSingleServer(1)
18
19 await setAccessTokensToServers([ server ])
20
21 const user = {
22 username: 'user1',
23 password: 'my super password'
24 }
25 await server.users.create({ username: user.username, password: user.password })
26 userAccessToken = await server.login.getAccessToken(user)
27 })
28
29 describe('When getting logs', function () {
30
31 it('Should fail with a non authenticated user', async function () {
32 await makeGetRequest({
33 url: server.url,
34 path,
35 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
36 })
37 })
38
39 it('Should fail with a non admin user', async function () {
40 await makeGetRequest({
41 url: server.url,
42 path,
43 token: userAccessToken,
44 expectedStatus: HttpStatusCode.FORBIDDEN_403
45 })
46 })
47
48 it('Should fail with a missing startDate query', async function () {
49 await makeGetRequest({
50 url: server.url,
51 path,
52 token: server.accessToken,
53 expectedStatus: HttpStatusCode.BAD_REQUEST_400
54 })
55 })
56
57 it('Should fail with a bad startDate query', async function () {
58 await makeGetRequest({
59 url: server.url,
60 path,
61 token: server.accessToken,
62 query: { startDate: 'toto' },
63 expectedStatus: HttpStatusCode.BAD_REQUEST_400
64 })
65 })
66
67 it('Should fail with a bad endDate query', async function () {
68 await makeGetRequest({
69 url: server.url,
70 path,
71 token: server.accessToken,
72 query: { startDate: new Date().toISOString(), endDate: 'toto' },
73 expectedStatus: HttpStatusCode.BAD_REQUEST_400
74 })
75 })
76
77 it('Should fail with a bad level parameter', async function () {
78 await makeGetRequest({
79 url: server.url,
80 path,
81 token: server.accessToken,
82 query: { startDate: new Date().toISOString(), level: 'toto' },
83 expectedStatus: HttpStatusCode.BAD_REQUEST_400
84 })
85 })
86
87 it('Should succeed with the correct params', async function () {
88 await makeGetRequest({
89 url: server.url,
90 path,
91 token: server.accessToken,
92 query: { startDate: new Date().toISOString() },
93 expectedStatus: HttpStatusCode.OK_200
94 })
95 })
96 })
97
98 describe('When creating client logs', function () {
99 const base = {
100 level: 'warn' as 'warn',
101 message: 'my super message',
102 url: 'https://example.com/toto'
103 }
104 const expectedStatus = HttpStatusCode.BAD_REQUEST_400
105
106 it('Should fail with an invalid level', async function () {
107 await server.logs.createLogClient({ payload: { ...base, level: '' as any }, expectedStatus })
108 await server.logs.createLogClient({ payload: { ...base, level: undefined }, expectedStatus })
109 await server.logs.createLogClient({ payload: { ...base, level: 'toto' as any }, expectedStatus })
110 })
111
112 it('Should fail with an invalid message', async function () {
113 await server.logs.createLogClient({ payload: { ...base, message: undefined }, expectedStatus })
114 await server.logs.createLogClient({ payload: { ...base, message: '' }, expectedStatus })
115 await server.logs.createLogClient({ payload: { ...base, message: 'm'.repeat(2500) }, expectedStatus })
116 })
117
118 it('Should fail with an invalid url', async function () {
119 await server.logs.createLogClient({ payload: { ...base, url: undefined }, expectedStatus })
120 await server.logs.createLogClient({ payload: { ...base, url: 'toto' }, expectedStatus })
121 })
122
123 it('Should fail with an invalid stackTrace', async function () {
124 await server.logs.createLogClient({ payload: { ...base, stackTrace: 's'.repeat(20000) }, expectedStatus })
125 })
126
127 it('Should fail with an invalid userAgent', async function () {
128 await server.logs.createLogClient({ payload: { ...base, userAgent: 's'.repeat(500) }, expectedStatus })
129 })
130
131 it('Should fail with an invalid meta', async function () {
132 await server.logs.createLogClient({ payload: { ...base, meta: 's'.repeat(10000) }, expectedStatus })
133 })
134
135 it('Should succeed with the correct params', async function () {
136 await server.logs.createLogClient({ payload: { ...base, stackTrace: 'stackTrace', meta: '{toto}', userAgent: 'userAgent' } })
137 })
138
139 it('Should rate limit log creation', async function () {
140 let fail = false
141
142 for (let i = 0; i < 10; i++) {
143 try {
144 await server.logs.createLogClient({ token: null, payload: base })
145 } catch {
146 fail = true
147 }
148 }
149
150 expect(fail).to.be.true
151 })
152 })
153
154 after(async function () {
155 await cleanupTests([ server ])
156 })
157})
diff --git a/server/tests/api/check-params/metrics.ts b/server/tests/api/check-params/metrics.ts
deleted file mode 100644
index 302bef4f5..000000000
--- a/server/tests/api/check-params/metrics.ts
+++ /dev/null
@@ -1,208 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { omit } from '@shared/core-utils'
4import { HttpStatusCode, PlaybackMetricCreate, VideoResolution } from '@shared/models'
5import { cleanupTests, createSingleServer, makePostBodyRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
6
7describe('Test metrics API validators', function () {
8 let server: PeerTubeServer
9 let videoUUID: string
10
11 // ---------------------------------------------------------------
12
13 before(async function () {
14 this.timeout(120000)
15
16 server = await createSingleServer(1, {
17 open_telemetry: {
18 metrics: {
19 enabled: true
20 }
21 }
22 })
23
24 await setAccessTokensToServers([ server ])
25
26 const { uuid } = await server.videos.quickUpload({ name: 'video' })
27 videoUUID = uuid
28 })
29
30 describe('When adding playback metrics', function () {
31 const path = '/api/v1/metrics/playback'
32 let baseParams: PlaybackMetricCreate
33
34 before(function () {
35 baseParams = {
36 playerMode: 'p2p-media-loader',
37 resolution: VideoResolution.H_1080P,
38 fps: 30,
39 resolutionChanges: 1,
40 errors: 2,
41 p2pEnabled: true,
42 downloadedBytesP2P: 0,
43 downloadedBytesHTTP: 0,
44 uploadedBytesP2P: 0,
45 videoId: videoUUID
46 }
47 })
48
49 it('Should fail with an invalid resolution', async function () {
50 await makePostBodyRequest({
51 url: server.url,
52 path,
53 fields: { ...baseParams, resolution: 'toto' }
54 })
55 })
56
57 it('Should fail with an invalid fps', async function () {
58 await makePostBodyRequest({
59 url: server.url,
60 path,
61 fields: { ...baseParams, fps: 'toto' }
62 })
63 })
64
65 it('Should fail with a missing/invalid player mode', async function () {
66 await makePostBodyRequest({
67 url: server.url,
68 path,
69 fields: omit(baseParams, [ 'playerMode' ])
70 })
71
72 await makePostBodyRequest({
73 url: server.url,
74 path,
75 fields: { ...baseParams, playerMode: 'toto' }
76 })
77 })
78
79 it('Should fail with an missing/invalid resolution changes', async function () {
80 await makePostBodyRequest({
81 url: server.url,
82 path,
83 fields: omit(baseParams, [ 'resolutionChanges' ])
84 })
85
86 await makePostBodyRequest({
87 url: server.url,
88 path,
89 fields: { ...baseParams, resolutionChanges: 'toto' }
90 })
91 })
92
93 it('Should fail with an missing/invalid errors', async function () {
94 await makePostBodyRequest({
95 url: server.url,
96 path,
97 fields: omit(baseParams, [ 'errors' ])
98 })
99
100 await makePostBodyRequest({
101 url: server.url,
102 path,
103 fields: { ...baseParams, errors: 'toto' }
104 })
105 })
106
107 it('Should fail with an missing/invalid downloadedBytesP2P', async function () {
108 await makePostBodyRequest({
109 url: server.url,
110 path,
111 fields: omit(baseParams, [ 'downloadedBytesP2P' ])
112 })
113
114 await makePostBodyRequest({
115 url: server.url,
116 path,
117 fields: { ...baseParams, downloadedBytesP2P: 'toto' }
118 })
119 })
120
121 it('Should fail with an missing/invalid downloadedBytesHTTP', async function () {
122 await makePostBodyRequest({
123 url: server.url,
124 path,
125 fields: omit(baseParams, [ 'downloadedBytesHTTP' ])
126 })
127
128 await makePostBodyRequest({
129 url: server.url,
130 path,
131 fields: { ...baseParams, downloadedBytesHTTP: 'toto' }
132 })
133 })
134
135 it('Should fail with an missing/invalid uploadedBytesP2P', async function () {
136 await makePostBodyRequest({
137 url: server.url,
138 path,
139 fields: omit(baseParams, [ 'uploadedBytesP2P' ])
140 })
141
142 await makePostBodyRequest({
143 url: server.url,
144 path,
145 fields: { ...baseParams, uploadedBytesP2P: 'toto' }
146 })
147 })
148
149 it('Should fail with a missing/invalid p2pEnabled', async function () {
150 await makePostBodyRequest({
151 url: server.url,
152 path,
153 fields: omit(baseParams, [ 'p2pEnabled' ])
154 })
155
156 await makePostBodyRequest({
157 url: server.url,
158 path,
159 fields: { ...baseParams, p2pEnabled: 'toto' }
160 })
161 })
162
163 it('Should fail with an invalid totalPeers', async function () {
164 await makePostBodyRequest({
165 url: server.url,
166 path,
167 fields: { ...baseParams, p2pPeers: 'toto' }
168 })
169 })
170
171 it('Should fail with a bad video id', async function () {
172 await makePostBodyRequest({
173 url: server.url,
174 path,
175 fields: { ...baseParams, videoId: 'toto' }
176 })
177 })
178
179 it('Should fail with an unknown video', async function () {
180 await makePostBodyRequest({
181 url: server.url,
182 path,
183 fields: { ...baseParams, videoId: 42 },
184 expectedStatus: HttpStatusCode.NOT_FOUND_404
185 })
186 })
187
188 it('Should succeed with the correct params', async function () {
189 await makePostBodyRequest({
190 url: server.url,
191 path,
192 fields: baseParams,
193 expectedStatus: HttpStatusCode.NO_CONTENT_204
194 })
195
196 await makePostBodyRequest({
197 url: server.url,
198 path,
199 fields: { ...baseParams, p2pEnabled: false, totalPeers: 32 },
200 expectedStatus: HttpStatusCode.NO_CONTENT_204
201 })
202 })
203 })
204
205 after(async function () {
206 await cleanupTests([ server ])
207 })
208})
diff --git a/server/tests/api/check-params/my-user.ts b/server/tests/api/check-params/my-user.ts
deleted file mode 100644
index 18f32d46b..000000000
--- a/server/tests/api/check-params/my-user.ts
+++ /dev/null
@@ -1,491 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, MockSmtpServer } from '@server/tests/shared'
4import { buildAbsoluteFixturePath } from '@shared/core-utils'
5import { HttpStatusCode, UserRole, VideoCreateResult } from '@shared/models'
6import {
7 cleanupTests,
8 createSingleServer,
9 makeGetRequest,
10 makePutBodyRequest,
11 makeUploadRequest,
12 PeerTubeServer,
13 setAccessTokensToServers,
14 UsersCommand
15} from '@shared/server-commands'
16
17describe('Test my user API validators', function () {
18 const path = '/api/v1/users/'
19 let userId: number
20 let rootId: number
21 let moderatorId: number
22 let video: VideoCreateResult
23 let server: PeerTubeServer
24 let userToken = ''
25 let moderatorToken = ''
26
27 // ---------------------------------------------------------------
28
29 before(async function () {
30 this.timeout(30000)
31
32 {
33 server = await createSingleServer(1)
34 await setAccessTokensToServers([ server ])
35 }
36
37 {
38 const result = await server.users.generate('user1')
39 userToken = result.token
40 userId = result.userId
41 }
42
43 {
44 const result = await server.users.generate('moderator1', UserRole.MODERATOR)
45 moderatorToken = result.token
46 }
47
48 {
49 const result = await server.users.generate('moderator2', UserRole.MODERATOR)
50 moderatorId = result.userId
51 }
52
53 {
54 video = await server.videos.upload()
55 }
56 })
57
58 describe('When updating my account', function () {
59
60 it('Should fail with an invalid email attribute', async function () {
61 const fields = {
62 email: 'blabla'
63 }
64
65 await makePutBodyRequest({ url: server.url, path: path + 'me', token: server.accessToken, fields })
66 })
67
68 it('Should fail with a too small password', async function () {
69 const fields = {
70 currentPassword: 'password',
71 password: 'bla'
72 }
73
74 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
75 })
76
77 it('Should fail with a too long password', async function () {
78 const fields = {
79 currentPassword: 'password',
80 password: 'super'.repeat(61)
81 }
82
83 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
84 })
85
86 it('Should fail without the current password', async function () {
87 const fields = {
88 currentPassword: 'password',
89 password: 'super'.repeat(61)
90 }
91
92 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
93 })
94
95 it('Should fail with an invalid current password', async function () {
96 const fields = {
97 currentPassword: 'my super password fail',
98 password: 'super'.repeat(61)
99 }
100
101 await makePutBodyRequest({
102 url: server.url,
103 path: path + 'me',
104 token: userToken,
105 fields,
106 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
107 })
108 })
109
110 it('Should fail with an invalid NSFW policy attribute', async function () {
111 const fields = {
112 nsfwPolicy: 'hello'
113 }
114
115 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
116 })
117
118 it('Should fail with an invalid autoPlayVideo attribute', async function () {
119 const fields = {
120 autoPlayVideo: -1
121 }
122
123 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
124 })
125
126 it('Should fail with an invalid autoPlayNextVideo attribute', async function () {
127 const fields = {
128 autoPlayNextVideo: -1
129 }
130
131 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
132 })
133
134 it('Should fail with an invalid videosHistoryEnabled attribute', async function () {
135 const fields = {
136 videosHistoryEnabled: -1
137 }
138
139 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
140 })
141
142 it('Should fail with an non authenticated user', async function () {
143 const fields = {
144 currentPassword: 'password',
145 password: 'my super password'
146 }
147
148 await makePutBodyRequest({
149 url: server.url,
150 path: path + 'me',
151 token: 'super token',
152 fields,
153 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
154 })
155 })
156
157 it('Should fail with a too long description', async function () {
158 const fields = {
159 description: 'super'.repeat(201)
160 }
161
162 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
163 })
164
165 it('Should fail with an invalid videoLanguages attribute', async function () {
166 {
167 const fields = {
168 videoLanguages: 'toto'
169 }
170
171 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
172 }
173
174 {
175 const languages = []
176 for (let i = 0; i < 1000; i++) {
177 languages.push('fr')
178 }
179
180 const fields = {
181 videoLanguages: languages
182 }
183
184 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
185 }
186 })
187
188 it('Should fail with an invalid theme', async function () {
189 const fields = { theme: 'invalid' }
190 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
191 })
192
193 it('Should fail with an unknown theme', async function () {
194 const fields = { theme: 'peertube-theme-unknown' }
195 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
196 })
197
198 it('Should fail with invalid no modal attributes', async function () {
199 const keys = [
200 'noInstanceConfigWarningModal',
201 'noAccountSetupWarningModal',
202 'noWelcomeModal'
203 ]
204
205 for (const key of keys) {
206 const fields = {
207 [key]: -1
208 }
209
210 await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
211 }
212 })
213
214 it('Should succeed to change password with the correct params', async function () {
215 const fields = {
216 currentPassword: 'password',
217 password: 'my super password',
218 nsfwPolicy: 'blur',
219 autoPlayVideo: false,
220 email: 'super_email@example.com',
221 theme: 'default',
222 noInstanceConfigWarningModal: true,
223 noWelcomeModal: true,
224 noAccountSetupWarningModal: true
225 }
226
227 await makePutBodyRequest({
228 url: server.url,
229 path: path + 'me',
230 token: userToken,
231 fields,
232 expectedStatus: HttpStatusCode.NO_CONTENT_204
233 })
234 })
235
236 it('Should succeed without password change with the correct params', async function () {
237 const fields = {
238 nsfwPolicy: 'blur',
239 autoPlayVideo: false
240 }
241
242 await makePutBodyRequest({
243 url: server.url,
244 path: path + 'me',
245 token: userToken,
246 fields,
247 expectedStatus: HttpStatusCode.NO_CONTENT_204
248 })
249 })
250 })
251
252 describe('When updating my avatar', function () {
253 it('Should fail without an incorrect input file', async function () {
254 const fields = {}
255 const attaches = {
256 avatarfile: buildAbsoluteFixturePath('video_short.mp4')
257 }
258 await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
259 })
260
261 it('Should fail with a big file', async function () {
262 const fields = {}
263 const attaches = {
264 avatarfile: buildAbsoluteFixturePath('avatar-big.png')
265 }
266 await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
267 })
268
269 it('Should fail with an unauthenticated user', async function () {
270 const fields = {}
271 const attaches = {
272 avatarfile: buildAbsoluteFixturePath('avatar.png')
273 }
274 await makeUploadRequest({
275 url: server.url,
276 path: path + '/me/avatar/pick',
277 fields,
278 attaches,
279 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
280 })
281 })
282
283 it('Should succeed with the correct params', async function () {
284 const fields = {}
285 const attaches = {
286 avatarfile: buildAbsoluteFixturePath('avatar.png')
287 }
288 await makeUploadRequest({
289 url: server.url,
290 path: path + '/me/avatar/pick',
291 token: server.accessToken,
292 fields,
293 attaches,
294 expectedStatus: HttpStatusCode.OK_200
295 })
296 })
297 })
298
299 describe('When managing my scoped tokens', function () {
300
301 it('Should fail to get my scoped tokens with an non authenticated user', async function () {
302 await server.users.getMyScopedTokens({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
303 })
304
305 it('Should fail to get my scoped tokens with a bad token', async function () {
306 await server.users.getMyScopedTokens({ token: 'bad', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
307
308 })
309
310 it('Should succeed to get my scoped tokens', async function () {
311 await server.users.getMyScopedTokens()
312 })
313
314 it('Should fail to renew my scoped tokens with an non authenticated user', async function () {
315 await server.users.renewMyScopedTokens({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
316 })
317
318 it('Should fail to renew my scoped tokens with a bad token', async function () {
319 await server.users.renewMyScopedTokens({ token: 'bad', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
320 })
321
322 it('Should succeed to renew my scoped tokens', async function () {
323 await server.users.renewMyScopedTokens()
324 })
325 })
326
327 describe('When getting my information', function () {
328 it('Should fail with a non authenticated user', async function () {
329 await server.users.getMyInfo({ token: 'fake_token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
330 })
331
332 it('Should success with the correct parameters', async function () {
333 await server.users.getMyInfo({ token: userToken })
334 })
335 })
336
337 describe('When getting my video rating', function () {
338 let command: UsersCommand
339
340 before(function () {
341 command = server.users
342 })
343
344 it('Should fail with a non authenticated user', async function () {
345 await command.getMyRating({ token: 'fake_token', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
346 })
347
348 it('Should fail with an incorrect video uuid', async function () {
349 await command.getMyRating({ videoId: 'blabla', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
350 })
351
352 it('Should fail with an unknown video', async function () {
353 await command.getMyRating({ videoId: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
354 })
355
356 it('Should succeed with the correct parameters', async function () {
357 await command.getMyRating({ videoId: video.id })
358 await command.getMyRating({ videoId: video.uuid })
359 await command.getMyRating({ videoId: video.shortUUID })
360 })
361 })
362
363 describe('When retrieving my global ratings', function () {
364 const path = '/api/v1/accounts/user1/ratings'
365
366 it('Should fail with a bad start pagination', async function () {
367 await checkBadStartPagination(server.url, path, userToken)
368 })
369
370 it('Should fail with a bad count pagination', async function () {
371 await checkBadCountPagination(server.url, path, userToken)
372 })
373
374 it('Should fail with an incorrect sort', async function () {
375 await checkBadSortPagination(server.url, path, userToken)
376 })
377
378 it('Should fail with a unauthenticated user', async function () {
379 await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
380 })
381
382 it('Should fail with a another user', async function () {
383 await makeGetRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
384 })
385
386 it('Should fail with a bad type', async function () {
387 await makeGetRequest({
388 url: server.url,
389 path,
390 token: userToken,
391 query: { rating: 'toto ' },
392 expectedStatus: HttpStatusCode.BAD_REQUEST_400
393 })
394 })
395
396 it('Should succeed with the correct params', async function () {
397 await makeGetRequest({ url: server.url, path, token: userToken, expectedStatus: HttpStatusCode.OK_200 })
398 })
399 })
400
401 describe('When getting my global followers', function () {
402 const path = '/api/v1/accounts/user1/followers'
403
404 it('Should fail with a bad start pagination', async function () {
405 await checkBadStartPagination(server.url, path, userToken)
406 })
407
408 it('Should fail with a bad count pagination', async function () {
409 await checkBadCountPagination(server.url, path, userToken)
410 })
411
412 it('Should fail with an incorrect sort', async function () {
413 await checkBadSortPagination(server.url, path, userToken)
414 })
415
416 it('Should fail with a unauthenticated user', async function () {
417 await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
418 })
419
420 it('Should fail with a another user', async function () {
421 await makeGetRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
422 })
423
424 it('Should succeed with the correct params', async function () {
425 await makeGetRequest({ url: server.url, path, token: userToken, expectedStatus: HttpStatusCode.OK_200 })
426 })
427 })
428
429 describe('When blocking/unblocking/removing user', function () {
430
431 it('Should fail with an incorrect id', async function () {
432 const options = { userId: 'blabla' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }
433
434 await server.users.remove(options)
435 await server.users.banUser({ userId: 'blabla' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
436 await server.users.unbanUser({ userId: 'blabla' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
437 })
438
439 it('Should fail with the root user', async function () {
440 const options = { userId: rootId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }
441
442 await server.users.remove(options)
443 await server.users.banUser(options)
444 await server.users.unbanUser(options)
445 })
446
447 it('Should return 404 with a non existing id', async function () {
448 const options = { userId: 4545454, expectedStatus: HttpStatusCode.NOT_FOUND_404 }
449
450 await server.users.remove(options)
451 await server.users.banUser(options)
452 await server.users.unbanUser(options)
453 })
454
455 it('Should fail with a non admin user', async function () {
456 const options = { userId, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }
457
458 await server.users.remove(options)
459 await server.users.banUser(options)
460 await server.users.unbanUser(options)
461 })
462
463 it('Should fail on a moderator with a moderator', async function () {
464 const options = { userId: moderatorId, token: moderatorToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }
465
466 await server.users.remove(options)
467 await server.users.banUser(options)
468 await server.users.unbanUser(options)
469 })
470
471 it('Should succeed on a user with a moderator', async function () {
472 const options = { userId, token: moderatorToken }
473
474 await server.users.banUser(options)
475 await server.users.unbanUser(options)
476 })
477 })
478
479 describe('When deleting our account', function () {
480
481 it('Should fail with with the root account', async function () {
482 await server.users.deleteMe({ expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
483 })
484 })
485
486 after(async function () {
487 MockSmtpServer.Instance.kill()
488
489 await cleanupTests([ server ])
490 })
491})
diff --git a/server/tests/api/check-params/plugins.ts b/server/tests/api/check-params/plugins.ts
deleted file mode 100644
index e08cd7ab8..000000000
--- a/server/tests/api/check-params/plugins.ts
+++ /dev/null
@@ -1,490 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
4import { HttpStatusCode, PeerTubePlugin, PluginType } from '@shared/models'
5import {
6 cleanupTests,
7 createSingleServer,
8 makeGetRequest,
9 makePostBodyRequest,
10 makePutBodyRequest,
11 PeerTubeServer,
12 setAccessTokensToServers
13} from '@shared/server-commands'
14
15describe('Test server plugins API validators', function () {
16 let server: PeerTubeServer
17 let userAccessToken = null
18
19 const npmPlugin = 'peertube-plugin-hello-world'
20 const pluginName = 'hello-world'
21 let npmVersion: string
22
23 const themePlugin = 'peertube-theme-background-red'
24 const themeName = 'background-red'
25 let themeVersion: string
26
27 // ---------------------------------------------------------------
28
29 before(async function () {
30 this.timeout(60000)
31
32 server = await createSingleServer(1)
33
34 await setAccessTokensToServers([ server ])
35
36 const user = {
37 username: 'user1',
38 password: 'password'
39 }
40
41 await server.users.create({ username: user.username, password: user.password })
42 userAccessToken = await server.login.getAccessToken(user)
43
44 {
45 const res = await server.plugins.install({ npmName: npmPlugin })
46 const plugin = res.body as PeerTubePlugin
47 npmVersion = plugin.version
48 }
49
50 {
51 const res = await server.plugins.install({ npmName: themePlugin })
52 const plugin = res.body as PeerTubePlugin
53 themeVersion = plugin.version
54 }
55 })
56
57 describe('With static plugin routes', function () {
58 it('Should fail with an unknown plugin name/plugin version', async function () {
59 const paths = [
60 '/plugins/' + pluginName + '/0.0.1/auth/fake-auth',
61 '/plugins/' + pluginName + '/0.0.1/static/images/chocobo.png',
62 '/plugins/' + pluginName + '/0.0.1/client-scripts/client/common-client-plugin.js',
63 '/themes/' + themeName + '/0.0.1/static/images/chocobo.png',
64 '/themes/' + themeName + '/0.0.1/client-scripts/client/video-watch-client-plugin.js',
65 '/themes/' + themeName + '/0.0.1/css/assets/style1.css'
66 ]
67
68 for (const p of paths) {
69 await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
70 }
71 })
72
73 it('Should fail when requesting a plugin in the theme path', async function () {
74 await makeGetRequest({
75 url: server.url,
76 path: '/themes/' + pluginName + '/' + npmVersion + '/static/images/chocobo.png',
77 expectedStatus: HttpStatusCode.NOT_FOUND_404
78 })
79 })
80
81 it('Should fail with invalid versions', async function () {
82 const paths = [
83 '/plugins/' + pluginName + '/0.0.1.1/auth/fake-auth',
84 '/plugins/' + pluginName + '/0.0.1.1/static/images/chocobo.png',
85 '/plugins/' + pluginName + '/0.1/client-scripts/client/common-client-plugin.js',
86 '/themes/' + themeName + '/1/static/images/chocobo.png',
87 '/themes/' + themeName + '/0.0.1000a/client-scripts/client/video-watch-client-plugin.js',
88 '/themes/' + themeName + '/0.a.1/css/assets/style1.css'
89 ]
90
91 for (const p of paths) {
92 await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
93 }
94 })
95
96 it('Should fail with invalid paths', async function () {
97 const paths = [
98 '/plugins/' + pluginName + '/' + npmVersion + '/static/images/../chocobo.png',
99 '/plugins/' + pluginName + '/' + npmVersion + '/client-scripts/../client/common-client-plugin.js',
100 '/themes/' + themeName + '/' + themeVersion + '/static/../images/chocobo.png',
101 '/themes/' + themeName + '/' + themeVersion + '/client-scripts/client/video-watch-client-plugin.js/..',
102 '/themes/' + themeName + '/' + themeVersion + '/css/../assets/style1.css'
103 ]
104
105 for (const p of paths) {
106 await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
107 }
108 })
109
110 it('Should fail with an unknown auth name', async function () {
111 const path = '/plugins/' + pluginName + '/' + npmVersion + '/auth/bad-auth'
112
113 await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
114 })
115
116 it('Should fail with an unknown static file', async function () {
117 const paths = [
118 '/plugins/' + pluginName + '/' + npmVersion + '/static/fake/chocobo.png',
119 '/plugins/' + pluginName + '/' + npmVersion + '/client-scripts/client/fake.js',
120 '/themes/' + themeName + '/' + themeVersion + '/static/fake/chocobo.png',
121 '/themes/' + themeName + '/' + themeVersion + '/client-scripts/client/fake.js'
122 ]
123
124 for (const p of paths) {
125 await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
126 }
127 })
128
129 it('Should fail with an unknown CSS file', async function () {
130 await makeGetRequest({
131 url: server.url,
132 path: '/themes/' + themeName + '/' + themeVersion + '/css/assets/fake.css',
133 expectedStatus: HttpStatusCode.NOT_FOUND_404
134 })
135 })
136
137 it('Should succeed with the correct parameters', async function () {
138 const paths = [
139 '/plugins/' + pluginName + '/' + npmVersion + '/static/images/chocobo.png',
140 '/plugins/' + pluginName + '/' + npmVersion + '/client-scripts/client/common-client-plugin.js',
141 '/themes/' + themeName + '/' + themeVersion + '/static/images/chocobo.png',
142 '/themes/' + themeName + '/' + themeVersion + '/client-scripts/client/video-watch-client-plugin.js',
143 '/themes/' + themeName + '/' + themeVersion + '/css/assets/style1.css'
144 ]
145
146 for (const p of paths) {
147 await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.OK_200 })
148 }
149
150 const authPath = '/plugins/' + pluginName + '/' + npmVersion + '/auth/fake-auth'
151 await makeGetRequest({ url: server.url, path: authPath, expectedStatus: HttpStatusCode.FOUND_302 })
152 })
153 })
154
155 describe('When listing available plugins/themes', function () {
156 const path = '/api/v1/plugins/available'
157 const baseQuery = {
158 search: 'super search',
159 pluginType: PluginType.PLUGIN,
160 currentPeerTubeEngine: '1.2.3'
161 }
162
163 it('Should fail with an invalid token', async function () {
164 await makeGetRequest({
165 url: server.url,
166 path,
167 token: 'fake_token',
168 query: baseQuery,
169 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
170 })
171 })
172
173 it('Should fail if the user is not an administrator', async function () {
174 await makeGetRequest({
175 url: server.url,
176 path,
177 token: userAccessToken,
178 query: baseQuery,
179 expectedStatus: HttpStatusCode.FORBIDDEN_403
180 })
181 })
182
183 it('Should fail with a bad start pagination', async function () {
184 await checkBadStartPagination(server.url, path, server.accessToken)
185 })
186
187 it('Should fail with a bad count pagination', async function () {
188 await checkBadCountPagination(server.url, path, server.accessToken)
189 })
190
191 it('Should fail with an incorrect sort', async function () {
192 await checkBadSortPagination(server.url, path, server.accessToken)
193 })
194
195 it('Should fail with an invalid plugin type', async function () {
196 const query = { ...baseQuery, pluginType: 5 }
197
198 await makeGetRequest({
199 url: server.url,
200 path,
201 token: server.accessToken,
202 query
203 })
204 })
205
206 it('Should fail with an invalid current peertube engine', async function () {
207 const query = { ...baseQuery, currentPeerTubeEngine: '1.0' }
208
209 await makeGetRequest({
210 url: server.url,
211 path,
212 token: server.accessToken,
213 query
214 })
215 })
216
217 it('Should success with the correct parameters', async function () {
218 await makeGetRequest({
219 url: server.url,
220 path,
221 token: server.accessToken,
222 query: baseQuery,
223 expectedStatus: HttpStatusCode.OK_200
224 })
225 })
226 })
227
228 describe('When listing local plugins/themes', function () {
229 const path = '/api/v1/plugins'
230 const baseQuery = {
231 pluginType: PluginType.THEME
232 }
233
234 it('Should fail with an invalid token', async function () {
235 await makeGetRequest({
236 url: server.url,
237 path,
238 token: 'fake_token',
239 query: baseQuery,
240 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
241 })
242 })
243
244 it('Should fail if the user is not an administrator', async function () {
245 await makeGetRequest({
246 url: server.url,
247 path,
248 token: userAccessToken,
249 query: baseQuery,
250 expectedStatus: HttpStatusCode.FORBIDDEN_403
251 })
252 })
253
254 it('Should fail with a bad start pagination', async function () {
255 await checkBadStartPagination(server.url, path, server.accessToken)
256 })
257
258 it('Should fail with a bad count pagination', async function () {
259 await checkBadCountPagination(server.url, path, server.accessToken)
260 })
261
262 it('Should fail with an incorrect sort', async function () {
263 await checkBadSortPagination(server.url, path, server.accessToken)
264 })
265
266 it('Should fail with an invalid plugin type', async function () {
267 const query = { ...baseQuery, pluginType: 5 }
268
269 await makeGetRequest({
270 url: server.url,
271 path,
272 token: server.accessToken,
273 query
274 })
275 })
276
277 it('Should success with the correct parameters', async function () {
278 await makeGetRequest({
279 url: server.url,
280 path,
281 token: server.accessToken,
282 query: baseQuery,
283 expectedStatus: HttpStatusCode.OK_200
284 })
285 })
286 })
287
288 describe('When getting a plugin or the registered settings or public settings', function () {
289 const path = '/api/v1/plugins/'
290
291 it('Should fail with an invalid token', async function () {
292 for (const suffix of [ npmPlugin, `${npmPlugin}/registered-settings` ]) {
293 await makeGetRequest({
294 url: server.url,
295 path: path + suffix,
296 token: 'fake_token',
297 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
298 })
299 }
300 })
301
302 it('Should fail if the user is not an administrator', async function () {
303 for (const suffix of [ npmPlugin, `${npmPlugin}/registered-settings` ]) {
304 await makeGetRequest({
305 url: server.url,
306 path: path + suffix,
307 token: userAccessToken,
308 expectedStatus: HttpStatusCode.FORBIDDEN_403
309 })
310 }
311 })
312
313 it('Should fail with an invalid npm name', async function () {
314 for (const suffix of [ 'toto', 'toto/registered-settings', 'toto/public-settings' ]) {
315 await makeGetRequest({
316 url: server.url,
317 path: path + suffix,
318 token: server.accessToken,
319 expectedStatus: HttpStatusCode.BAD_REQUEST_400
320 })
321 }
322
323 for (const suffix of [ 'peertube-plugin-TOTO', 'peertube-plugin-TOTO/registered-settings', 'peertube-plugin-TOTO/public-settings' ]) {
324 await makeGetRequest({
325 url: server.url,
326 path: path + suffix,
327 token: server.accessToken,
328 expectedStatus: HttpStatusCode.BAD_REQUEST_400
329 })
330 }
331 })
332
333 it('Should fail with an unknown plugin', async function () {
334 for (const suffix of [ 'peertube-plugin-toto', 'peertube-plugin-toto/registered-settings', 'peertube-plugin-toto/public-settings' ]) {
335 await makeGetRequest({
336 url: server.url,
337 path: path + suffix,
338 token: server.accessToken,
339 expectedStatus: HttpStatusCode.NOT_FOUND_404
340 })
341 }
342 })
343
344 it('Should succeed with the correct parameters', async function () {
345 for (const suffix of [ npmPlugin, `${npmPlugin}/registered-settings`, `${npmPlugin}/public-settings` ]) {
346 await makeGetRequest({
347 url: server.url,
348 path: path + suffix,
349 token: server.accessToken,
350 expectedStatus: HttpStatusCode.OK_200
351 })
352 }
353 })
354 })
355
356 describe('When updating plugin settings', function () {
357 const path = '/api/v1/plugins/'
358 const settings = { setting1: 'value1' }
359
360 it('Should fail with an invalid token', async function () {
361 await makePutBodyRequest({
362 url: server.url,
363 path: path + npmPlugin + '/settings',
364 fields: { settings },
365 token: 'fake_token',
366 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
367 })
368 })
369
370 it('Should fail if the user is not an administrator', async function () {
371 await makePutBodyRequest({
372 url: server.url,
373 path: path + npmPlugin + '/settings',
374 fields: { settings },
375 token: userAccessToken,
376 expectedStatus: HttpStatusCode.FORBIDDEN_403
377 })
378 })
379
380 it('Should fail with an invalid npm name', async function () {
381 await makePutBodyRequest({
382 url: server.url,
383 path: path + 'toto/settings',
384 fields: { settings },
385 token: server.accessToken,
386 expectedStatus: HttpStatusCode.BAD_REQUEST_400
387 })
388
389 await makePutBodyRequest({
390 url: server.url,
391 path: path + 'peertube-plugin-TOTO/settings',
392 fields: { settings },
393 token: server.accessToken,
394 expectedStatus: HttpStatusCode.BAD_REQUEST_400
395 })
396 })
397
398 it('Should fail with an unknown plugin', async function () {
399 await makePutBodyRequest({
400 url: server.url,
401 path: path + 'peertube-plugin-toto/settings',
402 fields: { settings },
403 token: server.accessToken,
404 expectedStatus: HttpStatusCode.NOT_FOUND_404
405 })
406 })
407
408 it('Should succeed with the correct parameters', async function () {
409 await makePutBodyRequest({
410 url: server.url,
411 path: path + npmPlugin + '/settings',
412 fields: { settings },
413 token: server.accessToken,
414 expectedStatus: HttpStatusCode.NO_CONTENT_204
415 })
416 })
417 })
418
419 describe('When installing/updating/uninstalling a plugin', function () {
420 const path = '/api/v1/plugins/'
421
422 it('Should fail with an invalid token', async function () {
423 for (const suffix of [ 'install', 'update', 'uninstall' ]) {
424 await makePostBodyRequest({
425 url: server.url,
426 path: path + suffix,
427 fields: { npmName: npmPlugin },
428 token: 'fake_token',
429 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
430 })
431 }
432 })
433
434 it('Should fail if the user is not an administrator', async function () {
435 for (const suffix of [ 'install', 'update', 'uninstall' ]) {
436 await makePostBodyRequest({
437 url: server.url,
438 path: path + suffix,
439 fields: { npmName: npmPlugin },
440 token: userAccessToken,
441 expectedStatus: HttpStatusCode.FORBIDDEN_403
442 })
443 }
444 })
445
446 it('Should fail with an invalid npm name', async function () {
447 for (const suffix of [ 'install', 'update', 'uninstall' ]) {
448 await makePostBodyRequest({
449 url: server.url,
450 path: path + suffix,
451 fields: { npmName: 'toto' },
452 token: server.accessToken,
453 expectedStatus: HttpStatusCode.BAD_REQUEST_400
454 })
455 }
456
457 for (const suffix of [ 'install', 'update', 'uninstall' ]) {
458 await makePostBodyRequest({
459 url: server.url,
460 path: path + suffix,
461 fields: { npmName: 'peertube-plugin-TOTO' },
462 token: server.accessToken,
463 expectedStatus: HttpStatusCode.BAD_REQUEST_400
464 })
465 }
466 })
467
468 it('Should succeed with the correct parameters', async function () {
469 const it = [
470 { suffix: 'install', status: HttpStatusCode.OK_200 },
471 { suffix: 'update', status: HttpStatusCode.OK_200 },
472 { suffix: 'uninstall', status: HttpStatusCode.NO_CONTENT_204 }
473 ]
474
475 for (const obj of it) {
476 await makePostBodyRequest({
477 url: server.url,
478 path: path + obj.suffix,
479 fields: { npmName: npmPlugin },
480 token: server.accessToken,
481 expectedStatus: obj.status
482 })
483 }
484 })
485 })
486
487 after(async function () {
488 await cleanupTests([ server ])
489 })
490})
diff --git a/server/tests/api/check-params/redundancy.ts b/server/tests/api/check-params/redundancy.ts
deleted file mode 100644
index 73dfd489d..000000000
--- a/server/tests/api/check-params/redundancy.ts
+++ /dev/null
@@ -1,240 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
4import { HttpStatusCode, VideoCreateResult } from '@shared/models'
5import {
6 cleanupTests,
7 createMultipleServers,
8 doubleFollow,
9 makeDeleteRequest,
10 makeGetRequest,
11 makePostBodyRequest,
12 makePutBodyRequest,
13 PeerTubeServer,
14 setAccessTokensToServers,
15 waitJobs
16} from '@shared/server-commands'
17
18describe('Test server redundancy API validators', function () {
19 let servers: PeerTubeServer[]
20 let userAccessToken = null
21 let videoIdLocal: number
22 let videoRemote: VideoCreateResult
23
24 // ---------------------------------------------------------------
25
26 before(async function () {
27 this.timeout(160000)
28
29 servers = await createMultipleServers(2)
30
31 await setAccessTokensToServers(servers)
32 await doubleFollow(servers[0], servers[1])
33
34 const user = {
35 username: 'user1',
36 password: 'password'
37 }
38
39 await servers[0].users.create({ username: user.username, password: user.password })
40 userAccessToken = await servers[0].login.getAccessToken(user)
41
42 videoIdLocal = (await servers[0].videos.quickUpload({ name: 'video' })).id
43
44 const remoteUUID = (await servers[1].videos.quickUpload({ name: 'video' })).uuid
45
46 await waitJobs(servers)
47
48 videoRemote = await servers[0].videos.get({ id: remoteUUID })
49 })
50
51 describe('When listing redundancies', function () {
52 const path = '/api/v1/server/redundancy/videos'
53
54 let url: string
55 let token: string
56
57 before(function () {
58 url = servers[0].url
59 token = servers[0].accessToken
60 })
61
62 it('Should fail with an invalid token', async function () {
63 await makeGetRequest({ url, path, token: 'fake_token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
64 })
65
66 it('Should fail if the user is not an administrator', async function () {
67 await makeGetRequest({ url, path, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
68 })
69
70 it('Should fail with a bad start pagination', async function () {
71 await checkBadStartPagination(url, path, servers[0].accessToken)
72 })
73
74 it('Should fail with a bad count pagination', async function () {
75 await checkBadCountPagination(url, path, servers[0].accessToken)
76 })
77
78 it('Should fail with an incorrect sort', async function () {
79 await checkBadSortPagination(url, path, servers[0].accessToken)
80 })
81
82 it('Should fail with a bad target', async function () {
83 await makeGetRequest({ url, path, token, query: { target: 'bad target' } })
84 })
85
86 it('Should fail without target', async function () {
87 await makeGetRequest({ url, path, token })
88 })
89
90 it('Should succeed with the correct params', async function () {
91 await makeGetRequest({ url, path, token, query: { target: 'my-videos' }, expectedStatus: HttpStatusCode.OK_200 })
92 })
93 })
94
95 describe('When manually adding a redundancy', function () {
96 const path = '/api/v1/server/redundancy/videos'
97
98 let url: string
99 let token: string
100
101 before(function () {
102 url = servers[0].url
103 token = servers[0].accessToken
104 })
105
106 it('Should fail with an invalid token', async function () {
107 await makePostBodyRequest({ url, path, token: 'fake_token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
108 })
109
110 it('Should fail if the user is not an administrator', async function () {
111 await makePostBodyRequest({ url, path, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
112 })
113
114 it('Should fail without a video id', async function () {
115 await makePostBodyRequest({ url, path, token })
116 })
117
118 it('Should fail with an incorrect video id', async function () {
119 await makePostBodyRequest({ url, path, token, fields: { videoId: 'peertube' } })
120 })
121
122 it('Should fail with a not found video id', async function () {
123 await makePostBodyRequest({ url, path, token, fields: { videoId: 6565 }, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
124 })
125
126 it('Should fail with a local a video id', async function () {
127 await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdLocal } })
128 })
129
130 it('Should succeed with the correct params', async function () {
131 await makePostBodyRequest({
132 url,
133 path,
134 token,
135 fields: { videoId: videoRemote.shortUUID },
136 expectedStatus: HttpStatusCode.NO_CONTENT_204
137 })
138 })
139
140 it('Should fail if the video is already duplicated', async function () {
141 this.timeout(30000)
142
143 await waitJobs(servers)
144
145 await makePostBodyRequest({
146 url,
147 path,
148 token,
149 fields: { videoId: videoRemote.uuid },
150 expectedStatus: HttpStatusCode.CONFLICT_409
151 })
152 })
153 })
154
155 describe('When manually removing a redundancy', function () {
156 const path = '/api/v1/server/redundancy/videos/'
157
158 let url: string
159 let token: string
160
161 before(function () {
162 url = servers[0].url
163 token = servers[0].accessToken
164 })
165
166 it('Should fail with an invalid token', async function () {
167 await makeDeleteRequest({ url, path: path + '1', token: 'fake_token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
168 })
169
170 it('Should fail if the user is not an administrator', async function () {
171 await makeDeleteRequest({ url, path: path + '1', token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
172 })
173
174 it('Should fail with an incorrect video id', async function () {
175 await makeDeleteRequest({ url, path: path + 'toto', token })
176 })
177
178 it('Should fail with a not found video redundancy', async function () {
179 await makeDeleteRequest({ url, path: path + '454545', token, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
180 })
181 })
182
183 describe('When updating server redundancy', function () {
184 const path = '/api/v1/server/redundancy'
185
186 it('Should fail with an invalid token', async function () {
187 await makePutBodyRequest({
188 url: servers[0].url,
189 path: path + '/' + servers[1].host,
190 fields: { redundancyAllowed: true },
191 token: 'fake_token',
192 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
193 })
194 })
195
196 it('Should fail if the user is not an administrator', async function () {
197 await makePutBodyRequest({
198 url: servers[0].url,
199 path: path + '/' + servers[1].host,
200 fields: { redundancyAllowed: true },
201 token: userAccessToken,
202 expectedStatus: HttpStatusCode.FORBIDDEN_403
203 })
204 })
205
206 it('Should fail if we do not follow this server', async function () {
207 await makePutBodyRequest({
208 url: servers[0].url,
209 path: path + '/example.com',
210 fields: { redundancyAllowed: true },
211 token: servers[0].accessToken,
212 expectedStatus: HttpStatusCode.NOT_FOUND_404
213 })
214 })
215
216 it('Should fail without de redundancyAllowed param', async function () {
217 await makePutBodyRequest({
218 url: servers[0].url,
219 path: path + '/' + servers[1].host,
220 fields: { blabla: true },
221 token: servers[0].accessToken,
222 expectedStatus: HttpStatusCode.BAD_REQUEST_400
223 })
224 })
225
226 it('Should succeed with the correct parameters', async function () {
227 await makePutBodyRequest({
228 url: servers[0].url,
229 path: path + '/' + servers[1].host,
230 fields: { redundancyAllowed: true },
231 token: servers[0].accessToken,
232 expectedStatus: HttpStatusCode.NO_CONTENT_204
233 })
234 })
235 })
236
237 after(async function () {
238 await cleanupTests(servers)
239 })
240})
diff --git a/server/tests/api/check-params/registrations.ts b/server/tests/api/check-params/registrations.ts
deleted file mode 100644
index 8cbecdd07..000000000
--- a/server/tests/api/check-params/registrations.ts
+++ /dev/null
@@ -1,446 +0,0 @@
1import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
2import { omit } from '@shared/core-utils'
3import { HttpStatusCode, UserRole } from '@shared/models'
4import {
5 cleanupTests,
6 createSingleServer,
7 makePostBodyRequest,
8 PeerTubeServer,
9 setAccessTokensToServers,
10 setDefaultAccountAvatar,
11 setDefaultChannelAvatar
12} from '@shared/server-commands'
13
14describe('Test registrations API validators', function () {
15 let server: PeerTubeServer
16 let userToken: string
17 let moderatorToken: string
18
19 // ---------------------------------------------------------------
20
21 before(async function () {
22 this.timeout(30000)
23
24 server = await createSingleServer(1)
25
26 await setAccessTokensToServers([ server ])
27 await setDefaultAccountAvatar([ server ])
28 await setDefaultChannelAvatar([ server ])
29
30 await server.config.enableSignup(false);
31
32 ({ token: moderatorToken } = await server.users.generate('moderator', UserRole.MODERATOR));
33 ({ token: userToken } = await server.users.generate('user', UserRole.USER))
34 })
35
36 describe('Register', function () {
37 const registrationPath = '/api/v1/users/register'
38 const registrationRequestPath = '/api/v1/users/registrations/request'
39
40 const baseCorrectParams = {
41 username: 'user3',
42 displayName: 'super user',
43 email: 'test3@example.com',
44 password: 'my super password',
45 registrationReason: 'my super registration reason'
46 }
47
48 describe('When registering a new user or requesting user registration', function () {
49
50 async function check (fields: any, expectedStatus = HttpStatusCode.BAD_REQUEST_400) {
51 await server.config.enableSignup(false)
52 await makePostBodyRequest({ url: server.url, path: registrationPath, fields, expectedStatus })
53
54 await server.config.enableSignup(true)
55 await makePostBodyRequest({ url: server.url, path: registrationRequestPath, fields, expectedStatus })
56 }
57
58 it('Should fail with a too small username', async function () {
59 const fields = { ...baseCorrectParams, username: '' }
60
61 await check(fields)
62 })
63
64 it('Should fail with a too long username', async function () {
65 const fields = { ...baseCorrectParams, username: 'super'.repeat(50) }
66
67 await check(fields)
68 })
69
70 it('Should fail with an incorrect username', async function () {
71 const fields = { ...baseCorrectParams, username: 'my username' }
72
73 await check(fields)
74 })
75
76 it('Should fail with a missing email', async function () {
77 const fields = omit(baseCorrectParams, [ 'email' ])
78
79 await check(fields)
80 })
81
82 it('Should fail with an invalid email', async function () {
83 const fields = { ...baseCorrectParams, email: 'test_example.com' }
84
85 await check(fields)
86 })
87
88 it('Should fail with a too small password', async function () {
89 const fields = { ...baseCorrectParams, password: 'bla' }
90
91 await check(fields)
92 })
93
94 it('Should fail with a too long password', async function () {
95 const fields = { ...baseCorrectParams, password: 'super'.repeat(61) }
96
97 await check(fields)
98 })
99
100 it('Should fail if we register a user with the same username', async function () {
101 const fields = { ...baseCorrectParams, username: 'root' }
102
103 await check(fields, HttpStatusCode.CONFLICT_409)
104 })
105
106 it('Should fail with a "peertube" username', async function () {
107 const fields = { ...baseCorrectParams, username: 'peertube' }
108
109 await check(fields, HttpStatusCode.CONFLICT_409)
110 })
111
112 it('Should fail if we register a user with the same email', async function () {
113 const fields = { ...baseCorrectParams, email: 'admin' + server.internalServerNumber + '@example.com' }
114
115 await check(fields, HttpStatusCode.CONFLICT_409)
116 })
117
118 it('Should fail with a bad display name', async function () {
119 const fields = { ...baseCorrectParams, displayName: 'a'.repeat(150) }
120
121 await check(fields)
122 })
123
124 it('Should fail with a bad channel name', async function () {
125 const fields = { ...baseCorrectParams, channel: { name: '[]azf', displayName: 'toto' } }
126
127 await check(fields)
128 })
129
130 it('Should fail with a bad channel display name', async function () {
131 const fields = { ...baseCorrectParams, channel: { name: 'toto', displayName: '' } }
132
133 await check(fields)
134 })
135
136 it('Should fail with a channel name that is the same as username', async function () {
137 const source = { username: 'super_user', channel: { name: 'super_user', displayName: 'display name' } }
138 const fields = { ...baseCorrectParams, ...source }
139
140 await check(fields)
141 })
142
143 it('Should fail with an existing channel', async function () {
144 const attributes = { name: 'existing_channel', displayName: 'hello', description: 'super description' }
145 await server.channels.create({ attributes })
146
147 const fields = { ...baseCorrectParams, channel: { name: 'existing_channel', displayName: 'toto' } }
148
149 await check(fields, HttpStatusCode.CONFLICT_409)
150 })
151
152 it('Should fail on a server with registration disabled', async function () {
153 this.timeout(60000)
154
155 await server.config.updateExistingSubConfig({
156 newConfig: {
157 signup: {
158 enabled: false
159 }
160 }
161 })
162
163 await server.registrations.register({ username: 'user4', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
164 await server.registrations.requestRegistration({
165 username: 'user4',
166 registrationReason: 'reason',
167 expectedStatus: HttpStatusCode.FORBIDDEN_403
168 })
169 })
170
171 it('Should fail if the user limit is reached', async function () {
172 this.timeout(60000)
173
174 const { total } = await server.users.list()
175
176 await server.config.enableSignup(false, total)
177 await server.registrations.register({ username: 'user42', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
178
179 await server.config.enableSignup(true, total)
180 await server.registrations.requestRegistration({
181 username: 'user42',
182 registrationReason: 'reason',
183 expectedStatus: HttpStatusCode.FORBIDDEN_403
184 })
185 })
186
187 it('Should succeed if the user limit is not reached', async function () {
188 this.timeout(60000)
189
190 const { total } = await server.users.list()
191
192 await server.config.enableSignup(false, total + 1)
193 await server.registrations.register({ username: 'user43', expectedStatus: HttpStatusCode.NO_CONTENT_204 })
194
195 await server.config.enableSignup(true, total + 2)
196 await server.registrations.requestRegistration({
197 username: 'user44',
198 registrationReason: 'reason',
199 expectedStatus: HttpStatusCode.OK_200
200 })
201 })
202 })
203
204 describe('On direct registration', function () {
205
206 it('Should succeed with the correct params', async function () {
207 await server.config.enableSignup(false)
208
209 const fields = {
210 username: 'user_direct_1',
211 displayName: 'super user direct 1',
212 email: 'user_direct_1@example.com',
213 password: 'my super password',
214 channel: { name: 'super_user_direct_1_channel', displayName: 'super user direct 1 channel' }
215 }
216
217 await makePostBodyRequest({ url: server.url, path: registrationPath, fields, expectedStatus: HttpStatusCode.NO_CONTENT_204 })
218 })
219
220 it('Should fail if the instance requires approval', async function () {
221 this.timeout(60000)
222
223 await server.config.enableSignup(true)
224 await server.registrations.register({ username: 'user42', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
225 })
226 })
227
228 describe('On registration request', function () {
229
230 before(async function () {
231 this.timeout(60000)
232
233 await server.config.enableSignup(true)
234 })
235
236 it('Should fail with an invalid registration reason', async function () {
237 for (const registrationReason of [ '', 't', 't'.repeat(5000) ]) {
238 await server.registrations.requestRegistration({
239 username: 'user_request_1',
240 registrationReason,
241 expectedStatus: HttpStatusCode.BAD_REQUEST_400
242 })
243 }
244 })
245
246 it('Should succeed with the correct params', async function () {
247 await server.registrations.requestRegistration({
248 username: 'user_request_2',
249 registrationReason: 'tt',
250 channel: {
251 displayName: 'my user request 2 channel',
252 name: 'user_request_2_channel'
253 }
254 })
255 })
256
257 it('Should fail if the username is already awaiting registration approval', async function () {
258 await server.registrations.requestRegistration({
259 username: 'user_request_2',
260 registrationReason: 'tt',
261 channel: {
262 displayName: 'my user request 42 channel',
263 name: 'user_request_42_channel'
264 },
265 expectedStatus: HttpStatusCode.CONFLICT_409
266 })
267 })
268
269 it('Should fail if the email is already awaiting registration approval', async function () {
270 await server.registrations.requestRegistration({
271 username: 'user42',
272 email: 'user_request_2@example.com',
273 registrationReason: 'tt',
274 channel: {
275 displayName: 'my user request 42 channel',
276 name: 'user_request_42_channel'
277 },
278 expectedStatus: HttpStatusCode.CONFLICT_409
279 })
280 })
281
282 it('Should fail if the channel is already awaiting registration approval', async function () {
283 await server.registrations.requestRegistration({
284 username: 'user42',
285 registrationReason: 'tt',
286 channel: {
287 displayName: 'my user request 2 channel',
288 name: 'user_request_2_channel'
289 },
290 expectedStatus: HttpStatusCode.CONFLICT_409
291 })
292 })
293
294 it('Should fail if the instance does not require approval', async function () {
295 this.timeout(60000)
296
297 await server.config.enableSignup(false)
298
299 await server.registrations.requestRegistration({
300 username: 'user42',
301 registrationReason: 'toto',
302 expectedStatus: HttpStatusCode.BAD_REQUEST_400
303 })
304 })
305 })
306 })
307
308 describe('Registrations accept/reject', function () {
309 let id1: number
310 let id2: number
311
312 before(async function () {
313 this.timeout(60000)
314
315 await server.config.enableSignup(true);
316
317 ({ id: id1 } = await server.registrations.requestRegistration({ username: 'request_2', registrationReason: 'toto' }));
318 ({ id: id2 } = await server.registrations.requestRegistration({ username: 'request_3', registrationReason: 'toto' }))
319 })
320
321 it('Should fail to accept/reject registration without token', async function () {
322 const options = { id: id1, moderationResponse: 'tt', token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }
323 await server.registrations.accept(options)
324 await server.registrations.reject(options)
325 })
326
327 it('Should fail to accept/reject registration with a non moderator user', async function () {
328 const options = { id: id1, moderationResponse: 'tt', token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }
329 await server.registrations.accept(options)
330 await server.registrations.reject(options)
331 })
332
333 it('Should fail to accept/reject registration with a bad registration id', async function () {
334 {
335 const options = { id: 't' as any, moderationResponse: 'tt', token: moderatorToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }
336 await server.registrations.accept(options)
337 await server.registrations.reject(options)
338 }
339
340 {
341 const options = { id: 42, moderationResponse: 'tt', token: moderatorToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 }
342 await server.registrations.accept(options)
343 await server.registrations.reject(options)
344 }
345 })
346
347 it('Should fail to accept/reject registration with a bad moderation resposne', async function () {
348 for (const moderationResponse of [ '', 't', 't'.repeat(5000) ]) {
349 const options = { id: id1, moderationResponse, token: moderatorToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }
350 await server.registrations.accept(options)
351 await server.registrations.reject(options)
352 }
353 })
354
355 it('Should succeed to accept a registration', async function () {
356 await server.registrations.accept({ id: id1, moderationResponse: 'tt', token: moderatorToken })
357 })
358
359 it('Should succeed to reject a registration', async function () {
360 await server.registrations.reject({ id: id2, moderationResponse: 'tt', token: moderatorToken })
361 })
362
363 it('Should fail to accept/reject a registration that was already accepted/rejected', async function () {
364 for (const id of [ id1, id2 ]) {
365 const options = { id, moderationResponse: 'tt', token: moderatorToken, expectedStatus: HttpStatusCode.CONFLICT_409 }
366 await server.registrations.accept(options)
367 await server.registrations.reject(options)
368 }
369 })
370 })
371
372 describe('Registrations deletion', function () {
373 let id1: number
374 let id2: number
375 let id3: number
376
377 before(async function () {
378 ({ id: id1 } = await server.registrations.requestRegistration({ username: 'request_4', registrationReason: 'toto' }));
379 ({ id: id2 } = await server.registrations.requestRegistration({ username: 'request_5', registrationReason: 'toto' }));
380 ({ id: id3 } = await server.registrations.requestRegistration({ username: 'request_6', registrationReason: 'toto' }))
381
382 await server.registrations.accept({ id: id2, moderationResponse: 'tt' })
383 await server.registrations.reject({ id: id3, moderationResponse: 'tt' })
384 })
385
386 it('Should fail to delete registration without token', async function () {
387 await server.registrations.delete({ id: id1, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
388 })
389
390 it('Should fail to delete registration with a non moderator user', async function () {
391 await server.registrations.delete({ id: id1, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
392 })
393
394 it('Should fail to delete registration with a bad registration id', async function () {
395 await server.registrations.delete({ id: 't' as any, token: moderatorToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
396 await server.registrations.delete({ id: 42, token: moderatorToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
397 })
398
399 it('Should succeed with the correct params', async function () {
400 await server.registrations.delete({ id: id1, token: moderatorToken })
401 await server.registrations.delete({ id: id2, token: moderatorToken })
402 await server.registrations.delete({ id: id3, token: moderatorToken })
403 })
404 })
405
406 describe('Listing registrations', function () {
407 const path = '/api/v1/users/registrations'
408
409 it('Should fail with a bad start pagination', async function () {
410 await checkBadStartPagination(server.url, path, server.accessToken)
411 })
412
413 it('Should fail with a bad count pagination', async function () {
414 await checkBadCountPagination(server.url, path, server.accessToken)
415 })
416
417 it('Should fail with an incorrect sort', async function () {
418 await checkBadSortPagination(server.url, path, server.accessToken)
419 })
420
421 it('Should fail with a non authenticated user', async function () {
422 await server.registrations.list({
423 token: null,
424 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
425 })
426 })
427
428 it('Should fail with a non admin user', async function () {
429 await server.registrations.list({
430 token: userToken,
431 expectedStatus: HttpStatusCode.FORBIDDEN_403
432 })
433 })
434
435 it('Should succeed with the correct params', async function () {
436 await server.registrations.list({
437 token: moderatorToken,
438 search: 'toto'
439 })
440 })
441 })
442
443 after(async function () {
444 await cleanupTests([ server ])
445 })
446})
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})
diff --git a/server/tests/api/check-params/search.ts b/server/tests/api/check-params/search.ts
deleted file mode 100644
index b04d30b7f..000000000
--- a/server/tests/api/check-params/search.ts
+++ /dev/null
@@ -1,272 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
4import { HttpStatusCode } from '@shared/models'
5import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
6
7function updateSearchIndex (server: PeerTubeServer, enabled: boolean, disableLocalSearch = false) {
8 return server.config.updateCustomSubConfig({
9 newConfig: {
10 search: {
11 searchIndex: {
12 enabled,
13 disableLocalSearch
14 }
15 }
16 }
17 })
18}
19
20describe('Test videos API validator', function () {
21 let server: PeerTubeServer
22
23 // ---------------------------------------------------------------
24
25 before(async function () {
26 this.timeout(30000)
27
28 server = await createSingleServer(1)
29 await setAccessTokensToServers([ server ])
30 })
31
32 describe('When searching videos', function () {
33 const path = '/api/v1/search/videos/'
34
35 const query = {
36 search: 'coucou'
37 }
38
39 it('Should fail with a bad start pagination', async function () {
40 await checkBadStartPagination(server.url, path, null, query)
41 })
42
43 it('Should fail with a bad count pagination', async function () {
44 await checkBadCountPagination(server.url, path, null, query)
45 })
46
47 it('Should fail with an incorrect sort', async function () {
48 await checkBadSortPagination(server.url, path, null, query)
49 })
50
51 it('Should succeed with the correct parameters', async function () {
52 await makeGetRequest({ url: server.url, path, query, expectedStatus: HttpStatusCode.OK_200 })
53 })
54
55 it('Should fail with an invalid category', async function () {
56 const customQuery1 = { ...query, categoryOneOf: [ 'aa', 'b' ] }
57 await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
58
59 const customQuery2 = { ...query, categoryOneOf: 'a' }
60 await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
61 })
62
63 it('Should succeed with a valid category', async function () {
64 const customQuery1 = { ...query, categoryOneOf: [ 1, 7 ] }
65 await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.OK_200 })
66
67 const customQuery2 = { ...query, categoryOneOf: 1 }
68 await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.OK_200 })
69 })
70
71 it('Should fail with an invalid licence', async function () {
72 const customQuery1 = { ...query, licenceOneOf: [ 'aa', 'b' ] }
73 await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
74
75 const customQuery2 = { ...query, licenceOneOf: 'a' }
76 await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
77 })
78
79 it('Should succeed with a valid licence', async function () {
80 const customQuery1 = { ...query, licenceOneOf: [ 1, 2 ] }
81 await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.OK_200 })
82
83 const customQuery2 = { ...query, licenceOneOf: 1 }
84 await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.OK_200 })
85 })
86
87 it('Should succeed with a valid language', async function () {
88 const customQuery1 = { ...query, languageOneOf: [ 'fr', 'en' ] }
89 await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.OK_200 })
90
91 const customQuery2 = { ...query, languageOneOf: 'fr' }
92 await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.OK_200 })
93 })
94
95 it('Should succeed with valid tags', async function () {
96 const customQuery1 = { ...query, tagsOneOf: [ 'tag1', 'tag2' ] }
97 await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.OK_200 })
98
99 const customQuery2 = { ...query, tagsOneOf: 'tag1' }
100 await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.OK_200 })
101
102 const customQuery3 = { ...query, tagsAllOf: [ 'tag1', 'tag2' ] }
103 await makeGetRequest({ url: server.url, path, query: customQuery3, expectedStatus: HttpStatusCode.OK_200 })
104
105 const customQuery4 = { ...query, tagsAllOf: 'tag1' }
106 await makeGetRequest({ url: server.url, path, query: customQuery4, expectedStatus: HttpStatusCode.OK_200 })
107 })
108
109 it('Should fail with invalid durations', async function () {
110 const customQuery1 = { ...query, durationMin: 'hello' }
111 await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
112
113 const customQuery2 = { ...query, durationMax: 'hello' }
114 await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
115 })
116
117 it('Should fail with invalid dates', async function () {
118 const customQuery1 = { ...query, startDate: 'hello' }
119 await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
120
121 const customQuery2 = { ...query, endDate: 'hello' }
122 await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
123
124 const customQuery3 = { ...query, originallyPublishedStartDate: 'hello' }
125 await makeGetRequest({ url: server.url, path, query: customQuery3, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
126
127 const customQuery4 = { ...query, originallyPublishedEndDate: 'hello' }
128 await makeGetRequest({ url: server.url, path, query: customQuery4, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
129 })
130
131 it('Should fail with an invalid host', async function () {
132 const customQuery = { ...query, host: '6565' }
133 await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
134 })
135
136 it('Should succeed with a host', async function () {
137 const customQuery = { ...query, host: 'example.com' }
138 await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
139 })
140
141 it('Should fail with invalid uuids', async function () {
142 const customQuery = { ...query, uuids: [ '6565', 'dfd70b83-639f-4980-94af-304a56ab4b35' ] }
143 await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
144 })
145
146 it('Should succeed with valid uuids', async function () {
147 const customQuery = { ...query, uuids: [ 'dfd70b83-639f-4980-94af-304a56ab4b35' ] }
148 await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
149 })
150 })
151
152 describe('When searching video playlists', function () {
153 const path = '/api/v1/search/video-playlists/'
154
155 const query = {
156 search: 'coucou',
157 host: 'example.com'
158 }
159
160 it('Should fail with a bad start pagination', async function () {
161 await checkBadStartPagination(server.url, path, null, query)
162 })
163
164 it('Should fail with a bad count pagination', async function () {
165 await checkBadCountPagination(server.url, path, null, query)
166 })
167
168 it('Should fail with an incorrect sort', async function () {
169 await checkBadSortPagination(server.url, path, null, query)
170 })
171
172 it('Should fail with an invalid host', async function () {
173 await makeGetRequest({ url: server.url, path, query: { ...query, host: '6565' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
174 })
175
176 it('Should fail with invalid uuids', async function () {
177 const customQuery = { ...query, uuids: [ '6565', 'dfd70b83-639f-4980-94af-304a56ab4b35' ] }
178 await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
179 })
180
181 it('Should succeed with the correct parameters', async function () {
182 await makeGetRequest({ url: server.url, path, query, expectedStatus: HttpStatusCode.OK_200 })
183 })
184 })
185
186 describe('When searching video channels', function () {
187 const path = '/api/v1/search/video-channels/'
188
189 const query = {
190 search: 'coucou',
191 host: 'example.com'
192 }
193
194 it('Should fail with a bad start pagination', async function () {
195 await checkBadStartPagination(server.url, path, null, query)
196 })
197
198 it('Should fail with a bad count pagination', async function () {
199 await checkBadCountPagination(server.url, path, null, query)
200 })
201
202 it('Should fail with an incorrect sort', async function () {
203 await checkBadSortPagination(server.url, path, null, query)
204 })
205
206 it('Should fail with an invalid host', async function () {
207 await makeGetRequest({ url: server.url, path, query: { ...query, host: '6565' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
208 })
209
210 it('Should fail with invalid handles', async function () {
211 await makeGetRequest({ url: server.url, path, query: { ...query, handles: [ '' ] }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
212 })
213
214 it('Should succeed with the correct parameters', async function () {
215 await makeGetRequest({ url: server.url, path, query, expectedStatus: HttpStatusCode.OK_200 })
216 })
217 })
218
219 describe('Search target', function () {
220
221 it('Should fail/succeed depending on the search target', async function () {
222 const query = { search: 'coucou' }
223 const paths = [
224 '/api/v1/search/video-playlists/',
225 '/api/v1/search/video-channels/',
226 '/api/v1/search/videos/'
227 ]
228
229 for (const path of paths) {
230 {
231 const customQuery = { ...query, searchTarget: 'hello' }
232 await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
233 }
234
235 {
236 const customQuery = { ...query, searchTarget: undefined }
237 await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
238 }
239
240 {
241 const customQuery = { ...query, searchTarget: 'local' }
242 await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
243 }
244
245 {
246 const customQuery = { ...query, searchTarget: 'search-index' }
247 await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
248 }
249
250 await updateSearchIndex(server, true, true)
251
252 {
253 const customQuery = { ...query, searchTarget: 'search-index' }
254 await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
255 }
256
257 await updateSearchIndex(server, true, false)
258
259 {
260 const customQuery = { ...query, searchTarget: 'local' }
261 await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
262 }
263
264 await updateSearchIndex(server, false, false)
265 }
266 })
267 })
268
269 after(async function () {
270 await cleanupTests([ server ])
271 })
272})
diff --git a/server/tests/api/check-params/services.ts b/server/tests/api/check-params/services.ts
deleted file mode 100644
index d45868f36..000000000
--- a/server/tests/api/check-params/services.ts
+++ /dev/null
@@ -1,195 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { HttpStatusCode, VideoCreateResult, VideoPlaylistCreateResult, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models'
4import {
5 cleanupTests,
6 createSingleServer,
7 makeGetRequest,
8 PeerTubeServer,
9 setAccessTokensToServers,
10 setDefaultVideoChannel
11} from '@shared/server-commands'
12
13describe('Test services API validators', function () {
14 let server: PeerTubeServer
15 let playlistUUID: string
16
17 let privateVideo: VideoCreateResult
18 let unlistedVideo: VideoCreateResult
19
20 let privatePlaylist: VideoPlaylistCreateResult
21 let unlistedPlaylist: VideoPlaylistCreateResult
22
23 // ---------------------------------------------------------------
24
25 before(async function () {
26 this.timeout(60000)
27
28 server = await createSingleServer(1)
29 await setAccessTokensToServers([ server ])
30 await setDefaultVideoChannel([ server ])
31
32 server.store.videoCreated = await server.videos.upload({ attributes: { name: 'my super name' } })
33
34 privateVideo = await server.videos.quickUpload({ name: 'private', privacy: VideoPrivacy.PRIVATE })
35 unlistedVideo = await server.videos.quickUpload({ name: 'unlisted', privacy: VideoPrivacy.UNLISTED })
36
37 {
38 const created = await server.playlists.create({
39 attributes: {
40 displayName: 'super playlist',
41 privacy: VideoPlaylistPrivacy.PUBLIC,
42 videoChannelId: server.store.channel.id
43 }
44 })
45
46 playlistUUID = created.uuid
47
48 privatePlaylist = await server.playlists.create({
49 attributes: {
50 displayName: 'private',
51 privacy: VideoPlaylistPrivacy.PRIVATE,
52 videoChannelId: server.store.channel.id
53 }
54 })
55
56 unlistedPlaylist = await server.playlists.create({
57 attributes: {
58 displayName: 'unlisted',
59 privacy: VideoPlaylistPrivacy.UNLISTED,
60 videoChannelId: server.store.channel.id
61 }
62 })
63 }
64 })
65
66 describe('Test oEmbed API validators', function () {
67
68 it('Should fail with an invalid url', async function () {
69 const embedUrl = 'hello.com'
70 await checkParamEmbed(server, embedUrl)
71 })
72
73 it('Should fail with an invalid host', async function () {
74 const embedUrl = 'http://hello.com/videos/watch/' + server.store.videoCreated.uuid
75 await checkParamEmbed(server, embedUrl)
76 })
77
78 it('Should fail with an invalid element id', async function () {
79 const embedUrl = `${server.url}/videos/watch/blabla`
80 await checkParamEmbed(server, embedUrl)
81 })
82
83 it('Should fail with an unknown element', async function () {
84 const embedUrl = `${server.url}/videos/watch/88fc0165-d1f0-4a35-a51a-3b47f668689c`
85 await checkParamEmbed(server, embedUrl, HttpStatusCode.NOT_FOUND_404)
86 })
87
88 it('Should fail with an invalid path', async function () {
89 const embedUrl = `${server.url}/videos/watchs/${server.store.videoCreated.uuid}`
90
91 await checkParamEmbed(server, embedUrl)
92 })
93
94 it('Should fail with an invalid max height', async function () {
95 const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}`
96
97 await checkParamEmbed(server, embedUrl, HttpStatusCode.BAD_REQUEST_400, { maxheight: 'hello' })
98 })
99
100 it('Should fail with an invalid max width', async function () {
101 const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}`
102
103 await checkParamEmbed(server, embedUrl, HttpStatusCode.BAD_REQUEST_400, { maxwidth: 'hello' })
104 })
105
106 it('Should fail with an invalid format', async function () {
107 const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}`
108
109 await checkParamEmbed(server, embedUrl, HttpStatusCode.BAD_REQUEST_400, { format: 'blabla' })
110 })
111
112 it('Should fail with a non supported format', async function () {
113 const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}`
114
115 await checkParamEmbed(server, embedUrl, HttpStatusCode.NOT_IMPLEMENTED_501, { format: 'xml' })
116 })
117
118 it('Should fail with a private video', async function () {
119 const embedUrl = `${server.url}/videos/watch/${privateVideo.uuid}`
120
121 await checkParamEmbed(server, embedUrl, HttpStatusCode.FORBIDDEN_403)
122 })
123
124 it('Should fail with an unlisted video with the int id', async function () {
125 const embedUrl = `${server.url}/videos/watch/${unlistedVideo.id}`
126
127 await checkParamEmbed(server, embedUrl, HttpStatusCode.FORBIDDEN_403)
128 })
129
130 it('Should succeed with an unlisted video using the uuid id', async function () {
131 for (const uuid of [ unlistedVideo.uuid, unlistedVideo.shortUUID ]) {
132 const embedUrl = `${server.url}/videos/watch/${uuid}`
133
134 await checkParamEmbed(server, embedUrl, HttpStatusCode.OK_200)
135 }
136 })
137
138 it('Should fail with a private playlist', async function () {
139 const embedUrl = `${server.url}/videos/watch/playlist/${privatePlaylist.uuid}`
140
141 await checkParamEmbed(server, embedUrl, HttpStatusCode.FORBIDDEN_403)
142 })
143
144 it('Should fail with an unlisted playlist using the int id', async function () {
145 const embedUrl = `${server.url}/videos/watch/playlist/${unlistedPlaylist.id}`
146
147 await checkParamEmbed(server, embedUrl, HttpStatusCode.FORBIDDEN_403)
148 })
149
150 it('Should succeed with an unlisted playlist using the uuid id', async function () {
151 for (const uuid of [ unlistedPlaylist.uuid, unlistedPlaylist.shortUUID ]) {
152 const embedUrl = `${server.url}/videos/watch/playlist/${uuid}`
153
154 await checkParamEmbed(server, embedUrl, HttpStatusCode.OK_200)
155 }
156 })
157
158 it('Should succeed with the correct params with a video', async function () {
159 const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}`
160 const query = {
161 format: 'json',
162 maxheight: 400,
163 maxwidth: 400
164 }
165
166 await checkParamEmbed(server, embedUrl, HttpStatusCode.OK_200, query)
167 })
168
169 it('Should succeed with the correct params with a playlist', async function () {
170 const embedUrl = `${server.url}/videos/watch/playlist/${playlistUUID}`
171 const query = {
172 format: 'json',
173 maxheight: 400,
174 maxwidth: 400
175 }
176
177 await checkParamEmbed(server, embedUrl, HttpStatusCode.OK_200, query)
178 })
179 })
180
181 after(async function () {
182 await cleanupTests([ server ])
183 })
184})
185
186function checkParamEmbed (server: PeerTubeServer, embedUrl: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400, query = {}) {
187 const path = '/services/oembed'
188
189 return makeGetRequest({
190 url: server.url,
191 path,
192 query: Object.assign(query, { url: embedUrl }),
193 expectedStatus
194 })
195}
diff --git a/server/tests/api/check-params/transcoding.ts b/server/tests/api/check-params/transcoding.ts
deleted file mode 100644
index d5899e11b..000000000
--- a/server/tests/api/check-params/transcoding.ts
+++ /dev/null
@@ -1,112 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { HttpStatusCode, UserRole } from '@shared/models'
4import {
5 cleanupTests,
6 createMultipleServers,
7 doubleFollow,
8 PeerTubeServer,
9 setAccessTokensToServers,
10 waitJobs
11} from '@shared/server-commands'
12
13describe('Test transcoding API validators', function () {
14 let servers: PeerTubeServer[]
15
16 let userToken: string
17 let moderatorToken: string
18
19 let remoteId: string
20 let validId: string
21
22 // ---------------------------------------------------------------
23
24 before(async function () {
25 this.timeout(120000)
26
27 servers = await createMultipleServers(2)
28 await setAccessTokensToServers(servers)
29
30 await doubleFollow(servers[0], servers[1])
31
32 userToken = await servers[0].users.generateUserAndToken('user', UserRole.USER)
33 moderatorToken = await servers[0].users.generateUserAndToken('moderator', UserRole.MODERATOR)
34
35 {
36 const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' })
37 remoteId = uuid
38 }
39
40 {
41 const { uuid } = await servers[0].videos.quickUpload({ name: 'both 1' })
42 validId = uuid
43 }
44
45 await waitJobs(servers)
46
47 await servers[0].config.enableTranscoding()
48 })
49
50 it('Should not run transcoding of a unknown video', async function () {
51 await servers[0].videos.runTranscoding({ videoId: 404, transcodingType: 'hls', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
52 await servers[0].videos.runTranscoding({ videoId: 404, transcodingType: 'web-video', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
53 })
54
55 it('Should not run transcoding of a remote video', async function () {
56 const expectedStatus = HttpStatusCode.BAD_REQUEST_400
57
58 await servers[0].videos.runTranscoding({ videoId: remoteId, transcodingType: 'hls', expectedStatus })
59 await servers[0].videos.runTranscoding({ videoId: remoteId, transcodingType: 'web-video', expectedStatus })
60 })
61
62 it('Should not run transcoding by a non admin user', async function () {
63 const expectedStatus = HttpStatusCode.FORBIDDEN_403
64
65 await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'hls', token: userToken, expectedStatus })
66 await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', token: moderatorToken, expectedStatus })
67 })
68
69 it('Should not run transcoding without transcoding type', async function () {
70 await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
71 })
72
73 it('Should not run transcoding with an incorrect transcoding type', async function () {
74 const expectedStatus = HttpStatusCode.BAD_REQUEST_400
75
76 await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'toto' as any, expectedStatus })
77 })
78
79 it('Should not run transcoding if the instance disabled it', async function () {
80 const expectedStatus = HttpStatusCode.BAD_REQUEST_400
81
82 await servers[0].config.disableTranscoding()
83
84 await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'hls', expectedStatus })
85 await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', expectedStatus })
86 })
87
88 it('Should run transcoding', async function () {
89 this.timeout(120_000)
90
91 await servers[0].config.enableTranscoding()
92
93 await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'hls' })
94 await waitJobs(servers)
95
96 await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', forceTranscoding: true })
97 await waitJobs(servers)
98 })
99
100 it('Should not run transcoding on a video that is already being transcoded if forceTranscoding is not set', async function () {
101 await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video' })
102
103 const expectedStatus = HttpStatusCode.CONFLICT_409
104 await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', expectedStatus })
105
106 await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', forceTranscoding: true })
107 })
108
109 after(async function () {
110 await cleanupTests(servers)
111 })
112})
diff --git a/server/tests/api/check-params/two-factor.ts b/server/tests/api/check-params/two-factor.ts
deleted file mode 100644
index f8365f1b5..000000000
--- a/server/tests/api/check-params/two-factor.ts
+++ /dev/null
@@ -1,288 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { HttpStatusCode } from '@shared/models'
4import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, TwoFactorCommand } from '@shared/server-commands'
5
6describe('Test two factor API validators', function () {
7 let server: PeerTubeServer
8
9 let rootId: number
10 let rootPassword: string
11 let rootRequestToken: string
12 let rootOTPToken: string
13
14 let userId: number
15 let userToken = ''
16 let userPassword: string
17 let userRequestToken: string
18 let userOTPToken: string
19
20 // ---------------------------------------------------------------
21
22 before(async function () {
23 this.timeout(30000)
24
25 {
26 server = await createSingleServer(1)
27 await setAccessTokensToServers([ server ])
28 }
29
30 {
31 const result = await server.users.generate('user1')
32 userToken = result.token
33 userId = result.userId
34 userPassword = result.password
35 }
36
37 {
38 const { id } = await server.users.getMyInfo()
39 rootId = id
40 rootPassword = server.store.user.password
41 }
42 })
43
44 describe('When requesting two factor', function () {
45
46 it('Should fail with an unknown user id', async function () {
47 await server.twoFactor.request({ userId: 42, currentPassword: rootPassword, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
48 })
49
50 it('Should fail with an invalid user id', async function () {
51 await server.twoFactor.request({
52 userId: 'invalid' as any,
53 currentPassword: rootPassword,
54 expectedStatus: HttpStatusCode.BAD_REQUEST_400
55 })
56 })
57
58 it('Should fail to request another user two factor without the appropriate rights', async function () {
59 await server.twoFactor.request({
60 userId: rootId,
61 token: userToken,
62 currentPassword: userPassword,
63 expectedStatus: HttpStatusCode.FORBIDDEN_403
64 })
65 })
66
67 it('Should succeed to request another user two factor with the appropriate rights', async function () {
68 await server.twoFactor.request({ userId, currentPassword: rootPassword })
69 })
70
71 it('Should fail to request two factor without a password', async function () {
72 await server.twoFactor.request({
73 userId,
74 token: userToken,
75 currentPassword: undefined,
76 expectedStatus: HttpStatusCode.BAD_REQUEST_400
77 })
78 })
79
80 it('Should fail to request two factor with an incorrect password', async function () {
81 await server.twoFactor.request({
82 userId,
83 token: userToken,
84 currentPassword: rootPassword,
85 expectedStatus: HttpStatusCode.FORBIDDEN_403
86 })
87 })
88
89 it('Should succeed to request two factor without a password when targeting a remote user with an admin account', async function () {
90 await server.twoFactor.request({ userId })
91 })
92
93 it('Should fail to request two factor without a password when targeting myself with an admin account', async function () {
94 await server.twoFactor.request({ userId: rootId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
95 await server.twoFactor.request({ userId: rootId, currentPassword: 'bad', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
96 })
97
98 it('Should succeed to request my two factor auth', async function () {
99 {
100 const { otpRequest } = await server.twoFactor.request({ userId, token: userToken, currentPassword: userPassword })
101 userRequestToken = otpRequest.requestToken
102 userOTPToken = TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate()
103 }
104
105 {
106 const { otpRequest } = await server.twoFactor.request({ userId: rootId, currentPassword: rootPassword })
107 rootRequestToken = otpRequest.requestToken
108 rootOTPToken = TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate()
109 }
110 })
111 })
112
113 describe('When confirming two factor request', function () {
114
115 it('Should fail with an unknown user id', async function () {
116 await server.twoFactor.confirmRequest({
117 userId: 42,
118 requestToken: rootRequestToken,
119 otpToken: rootOTPToken,
120 expectedStatus: HttpStatusCode.NOT_FOUND_404
121 })
122 })
123
124 it('Should fail with an invalid user id', async function () {
125 await server.twoFactor.confirmRequest({
126 userId: 'invalid' as any,
127 requestToken: rootRequestToken,
128 otpToken: rootOTPToken,
129 expectedStatus: HttpStatusCode.BAD_REQUEST_400
130 })
131 })
132
133 it('Should fail to confirm another user two factor request without the appropriate rights', async function () {
134 await server.twoFactor.confirmRequest({
135 userId: rootId,
136 token: userToken,
137 requestToken: rootRequestToken,
138 otpToken: rootOTPToken,
139 expectedStatus: HttpStatusCode.FORBIDDEN_403
140 })
141 })
142
143 it('Should fail without request token', async function () {
144 await server.twoFactor.confirmRequest({
145 userId,
146 requestToken: undefined,
147 otpToken: userOTPToken,
148 expectedStatus: HttpStatusCode.BAD_REQUEST_400
149 })
150 })
151
152 it('Should fail with an invalid request token', async function () {
153 await server.twoFactor.confirmRequest({
154 userId,
155 requestToken: 'toto',
156 otpToken: userOTPToken,
157 expectedStatus: HttpStatusCode.FORBIDDEN_403
158 })
159 })
160
161 it('Should fail with request token of another user', async function () {
162 await server.twoFactor.confirmRequest({
163 userId,
164 requestToken: rootRequestToken,
165 otpToken: userOTPToken,
166 expectedStatus: HttpStatusCode.FORBIDDEN_403
167 })
168 })
169
170 it('Should fail without an otp token', async function () {
171 await server.twoFactor.confirmRequest({
172 userId,
173 requestToken: userRequestToken,
174 otpToken: undefined,
175 expectedStatus: HttpStatusCode.BAD_REQUEST_400
176 })
177 })
178
179 it('Should fail with a bad otp token', async function () {
180 await server.twoFactor.confirmRequest({
181 userId,
182 requestToken: userRequestToken,
183 otpToken: '123456',
184 expectedStatus: HttpStatusCode.FORBIDDEN_403
185 })
186 })
187
188 it('Should succeed to confirm another user two factor request with the appropriate rights', async function () {
189 await server.twoFactor.confirmRequest({
190 userId,
191 requestToken: userRequestToken,
192 otpToken: userOTPToken
193 })
194
195 // Reinit
196 await server.twoFactor.disable({ userId, currentPassword: rootPassword })
197 })
198
199 it('Should succeed to confirm my two factor request', async function () {
200 await server.twoFactor.confirmRequest({
201 userId,
202 token: userToken,
203 requestToken: userRequestToken,
204 otpToken: userOTPToken
205 })
206 })
207
208 it('Should fail to confirm again two factor request', async function () {
209 await server.twoFactor.confirmRequest({
210 userId,
211 token: userToken,
212 requestToken: userRequestToken,
213 otpToken: userOTPToken,
214 expectedStatus: HttpStatusCode.BAD_REQUEST_400
215 })
216 })
217 })
218
219 describe('When disabling two factor', function () {
220
221 it('Should fail with an unknown user id', async function () {
222 await server.twoFactor.disable({
223 userId: 42,
224 currentPassword: rootPassword,
225 expectedStatus: HttpStatusCode.NOT_FOUND_404
226 })
227 })
228
229 it('Should fail with an invalid user id', async function () {
230 await server.twoFactor.disable({
231 userId: 'invalid' as any,
232 currentPassword: rootPassword,
233 expectedStatus: HttpStatusCode.BAD_REQUEST_400
234 })
235 })
236
237 it('Should fail to disable another user two factor without the appropriate rights', async function () {
238 await server.twoFactor.disable({
239 userId: rootId,
240 token: userToken,
241 currentPassword: userPassword,
242 expectedStatus: HttpStatusCode.FORBIDDEN_403
243 })
244 })
245
246 it('Should fail to disable two factor with an incorrect password', async function () {
247 await server.twoFactor.disable({
248 userId,
249 token: userToken,
250 currentPassword: rootPassword,
251 expectedStatus: HttpStatusCode.FORBIDDEN_403
252 })
253 })
254
255 it('Should succeed to disable two factor without a password when targeting a remote user with an admin account', async function () {
256 await server.twoFactor.disable({ userId })
257 await server.twoFactor.requestAndConfirm({ userId })
258 })
259
260 it('Should fail to disable two factor without a password when targeting myself with an admin account', async function () {
261 await server.twoFactor.disable({ userId: rootId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
262 await server.twoFactor.disable({ userId: rootId, currentPassword: 'bad', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
263 })
264
265 it('Should succeed to disable another user two factor with the appropriate rights', async function () {
266 await server.twoFactor.disable({ userId, currentPassword: rootPassword })
267
268 await server.twoFactor.requestAndConfirm({ userId })
269 })
270
271 it('Should succeed to update my two factor auth', async function () {
272 await server.twoFactor.disable({ userId, token: userToken, currentPassword: userPassword })
273 })
274
275 it('Should fail to disable again two factor', async function () {
276 await server.twoFactor.disable({
277 userId,
278 token: userToken,
279 currentPassword: userPassword,
280 expectedStatus: HttpStatusCode.BAD_REQUEST_400
281 })
282 })
283 })
284
285 after(async function () {
286 await cleanupTests([ server ])
287 })
288})
diff --git a/server/tests/api/check-params/upload-quota.ts b/server/tests/api/check-params/upload-quota.ts
deleted file mode 100644
index 06698c056..000000000
--- a/server/tests/api/check-params/upload-quota.ts
+++ /dev/null
@@ -1,134 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { FIXTURE_URLS } from '@server/tests/shared'
5import { randomInt } from '@shared/core-utils'
6import { HttpStatusCode, VideoImportState, VideoPrivacy } from '@shared/models'
7import {
8 cleanupTests,
9 createSingleServer,
10 PeerTubeServer,
11 setAccessTokensToServers,
12 setDefaultVideoChannel,
13 VideosCommand,
14 waitJobs
15} from '@shared/server-commands'
16
17describe('Test upload quota', function () {
18 let server: PeerTubeServer
19 let rootId: number
20 let command: VideosCommand
21
22 // ---------------------------------------------------------------
23
24 before(async function () {
25 this.timeout(30000)
26
27 server = await createSingleServer(1)
28 await setAccessTokensToServers([ server ])
29 await setDefaultVideoChannel([ server ])
30
31 const user = await server.users.getMyInfo()
32 rootId = user.id
33
34 await server.users.update({ userId: rootId, videoQuota: 42 })
35
36 command = server.videos
37 })
38
39 describe('When having a video quota', function () {
40
41 it('Should fail with a registered user having too many videos with legacy upload', async function () {
42 this.timeout(120000)
43
44 const user = { username: 'registered' + randomInt(1, 1500), password: 'password' }
45 await server.registrations.register(user)
46 const userToken = await server.login.getAccessToken(user)
47
48 const attributes = { fixture: 'video_short2.webm' }
49 for (let i = 0; i < 5; i++) {
50 await command.upload({ token: userToken, attributes })
51 }
52
53 await command.upload({ token: userToken, attributes, expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'legacy' })
54 })
55
56 it('Should fail with a registered user having too many videos with resumable upload', async function () {
57 this.timeout(120000)
58
59 const user = { username: 'registered' + randomInt(1, 1500), password: 'password' }
60 await server.registrations.register(user)
61 const userToken = await server.login.getAccessToken(user)
62
63 const attributes = { fixture: 'video_short2.webm' }
64 for (let i = 0; i < 5; i++) {
65 await command.upload({ token: userToken, attributes })
66 }
67
68 await command.upload({ token: userToken, attributes, expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'resumable' })
69 })
70
71 it('Should fail to import with HTTP/Torrent/magnet', async function () {
72 this.timeout(120_000)
73
74 const baseAttributes = {
75 channelId: server.store.channel.id,
76 privacy: VideoPrivacy.PUBLIC
77 }
78 await server.imports.importVideo({ attributes: { ...baseAttributes, targetUrl: FIXTURE_URLS.goodVideo } })
79 await server.imports.importVideo({ attributes: { ...baseAttributes, magnetUri: FIXTURE_URLS.magnet } })
80 await server.imports.importVideo({ attributes: { ...baseAttributes, torrentfile: 'video-720p.torrent' as any } })
81
82 await waitJobs([ server ])
83
84 const { total, data: videoImports } = await server.imports.getMyVideoImports()
85 expect(total).to.equal(3)
86
87 expect(videoImports).to.have.lengthOf(3)
88
89 for (const videoImport of videoImports) {
90 expect(videoImport.state.id).to.equal(VideoImportState.FAILED)
91 expect(videoImport.error).not.to.be.undefined
92 expect(videoImport.error).to.contain('user video quota is exceeded')
93 }
94 })
95 })
96
97 describe('When having a daily video quota', function () {
98
99 it('Should fail with a user having too many videos daily', async function () {
100 await server.users.update({ userId: rootId, videoQuotaDaily: 42 })
101
102 await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'legacy' })
103 await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'resumable' })
104 })
105 })
106
107 describe('When having an absolute and daily video quota', function () {
108 it('Should fail if exceeding total quota', async function () {
109 await server.users.update({
110 userId: rootId,
111 videoQuota: 42,
112 videoQuotaDaily: 1024 * 1024 * 1024
113 })
114
115 await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'legacy' })
116 await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'resumable' })
117 })
118
119 it('Should fail if exceeding daily quota', async function () {
120 await server.users.update({
121 userId: rootId,
122 videoQuota: 1024 * 1024 * 1024,
123 videoQuotaDaily: 42
124 })
125
126 await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'legacy' })
127 await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'resumable' })
128 })
129 })
130
131 after(async function () {
132 await cleanupTests([ server ])
133 })
134})
diff --git a/server/tests/api/check-params/user-notifications.ts b/server/tests/api/check-params/user-notifications.ts
deleted file mode 100644
index 6a588e446..000000000
--- a/server/tests/api/check-params/user-notifications.ts
+++ /dev/null
@@ -1,290 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { io } from 'socket.io-client'
4import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
5import { wait } from '@shared/core-utils'
6import { HttpStatusCode, UserNotificationSetting, UserNotificationSettingValue } from '@shared/models'
7import {
8 cleanupTests,
9 createSingleServer,
10 makeGetRequest,
11 makePostBodyRequest,
12 makePutBodyRequest,
13 PeerTubeServer,
14 setAccessTokensToServers
15} from '@shared/server-commands'
16
17describe('Test user notifications API validators', function () {
18 let server: PeerTubeServer
19
20 // ---------------------------------------------------------------
21
22 before(async function () {
23 this.timeout(30000)
24
25 server = await createSingleServer(1)
26
27 await setAccessTokensToServers([ server ])
28 })
29
30 describe('When listing my notifications', function () {
31 const path = '/api/v1/users/me/notifications'
32
33 it('Should fail with a bad start pagination', async function () {
34 await checkBadStartPagination(server.url, path, server.accessToken)
35 })
36
37 it('Should fail with a bad count pagination', async function () {
38 await checkBadCountPagination(server.url, path, server.accessToken)
39 })
40
41 it('Should fail with an incorrect sort', async function () {
42 await checkBadSortPagination(server.url, path, server.accessToken)
43 })
44
45 it('Should fail with an incorrect unread parameter', async function () {
46 await makeGetRequest({
47 url: server.url,
48 path,
49 query: {
50 unread: 'toto'
51 },
52 token: server.accessToken,
53 expectedStatus: HttpStatusCode.OK_200
54 })
55 })
56
57 it('Should fail with a non authenticated user', async function () {
58 await makeGetRequest({
59 url: server.url,
60 path,
61 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
62 })
63 })
64
65 it('Should succeed with the correct parameters', async function () {
66 await makeGetRequest({
67 url: server.url,
68 path,
69 token: server.accessToken,
70 expectedStatus: HttpStatusCode.OK_200
71 })
72 })
73 })
74
75 describe('When marking as read my notifications', function () {
76 const path = '/api/v1/users/me/notifications/read'
77
78 it('Should fail with wrong ids parameters', async function () {
79 await makePostBodyRequest({
80 url: server.url,
81 path,
82 fields: {
83 ids: [ 'hello' ]
84 },
85 token: server.accessToken,
86 expectedStatus: HttpStatusCode.BAD_REQUEST_400
87 })
88
89 await makePostBodyRequest({
90 url: server.url,
91 path,
92 fields: {
93 ids: [ ]
94 },
95 token: server.accessToken,
96 expectedStatus: HttpStatusCode.BAD_REQUEST_400
97 })
98
99 await makePostBodyRequest({
100 url: server.url,
101 path,
102 fields: {
103 ids: 5
104 },
105 token: server.accessToken,
106 expectedStatus: HttpStatusCode.BAD_REQUEST_400
107 })
108 })
109
110 it('Should fail with a non authenticated user', async function () {
111 await makePostBodyRequest({
112 url: server.url,
113 path,
114 fields: {
115 ids: [ 5 ]
116 },
117 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
118 })
119 })
120
121 it('Should succeed with the correct parameters', async function () {
122 await makePostBodyRequest({
123 url: server.url,
124 path,
125 fields: {
126 ids: [ 5 ]
127 },
128 token: server.accessToken,
129 expectedStatus: HttpStatusCode.NO_CONTENT_204
130 })
131 })
132 })
133
134 describe('When marking as read my notifications', function () {
135 const path = '/api/v1/users/me/notifications/read-all'
136
137 it('Should fail with a non authenticated user', async function () {
138 await makePostBodyRequest({
139 url: server.url,
140 path,
141 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
142 })
143 })
144
145 it('Should succeed with the correct parameters', async function () {
146 await makePostBodyRequest({
147 url: server.url,
148 path,
149 token: server.accessToken,
150 expectedStatus: HttpStatusCode.NO_CONTENT_204
151 })
152 })
153 })
154
155 describe('When updating my notification settings', function () {
156 const path = '/api/v1/users/me/notification-settings'
157 const correctFields: UserNotificationSetting = {
158 newVideoFromSubscription: UserNotificationSettingValue.WEB,
159 newCommentOnMyVideo: UserNotificationSettingValue.WEB,
160 abuseAsModerator: UserNotificationSettingValue.WEB,
161 videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB,
162 blacklistOnMyVideo: UserNotificationSettingValue.WEB,
163 myVideoImportFinished: UserNotificationSettingValue.WEB,
164 myVideoPublished: UserNotificationSettingValue.WEB,
165 commentMention: UserNotificationSettingValue.WEB,
166 newFollow: UserNotificationSettingValue.WEB,
167 newUserRegistration: UserNotificationSettingValue.WEB,
168 newInstanceFollower: UserNotificationSettingValue.WEB,
169 autoInstanceFollowing: UserNotificationSettingValue.WEB,
170 abuseNewMessage: UserNotificationSettingValue.WEB,
171 abuseStateChange: UserNotificationSettingValue.WEB,
172 newPeerTubeVersion: UserNotificationSettingValue.WEB,
173 myVideoStudioEditionFinished: UserNotificationSettingValue.WEB,
174 newPluginVersion: UserNotificationSettingValue.WEB
175 }
176
177 it('Should fail with missing fields', async function () {
178 await makePutBodyRequest({
179 url: server.url,
180 path,
181 token: server.accessToken,
182 fields: { newVideoFromSubscription: UserNotificationSettingValue.WEB },
183 expectedStatus: HttpStatusCode.BAD_REQUEST_400
184 })
185 })
186
187 it('Should fail with incorrect field values', async function () {
188 {
189 const fields = { ...correctFields, newCommentOnMyVideo: 15 }
190
191 await makePutBodyRequest({
192 url: server.url,
193 path,
194 token: server.accessToken,
195 fields,
196 expectedStatus: HttpStatusCode.BAD_REQUEST_400
197 })
198 }
199
200 {
201 const fields = { ...correctFields, newCommentOnMyVideo: 'toto' }
202
203 await makePutBodyRequest({
204 url: server.url,
205 path,
206 fields,
207 token: server.accessToken,
208 expectedStatus: HttpStatusCode.BAD_REQUEST_400
209 })
210 }
211 })
212
213 it('Should fail with a non authenticated user', async function () {
214 await makePutBodyRequest({
215 url: server.url,
216 path,
217 fields: correctFields,
218 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
219 })
220 })
221
222 it('Should succeed with the correct parameters', async function () {
223 await makePutBodyRequest({
224 url: server.url,
225 path,
226 token: server.accessToken,
227 fields: correctFields,
228 expectedStatus: HttpStatusCode.NO_CONTENT_204
229 })
230 })
231 })
232
233 describe('When connecting to my notification socket', function () {
234
235 it('Should fail with no token', function (next) {
236 const socket = io(`${server.url}/user-notifications`, { reconnection: false })
237
238 socket.once('connect_error', function () {
239 socket.disconnect()
240 next()
241 })
242
243 socket.on('connect', () => {
244 socket.disconnect()
245 next(new Error('Connected with a missing token.'))
246 })
247 })
248
249 it('Should fail with an invalid token', function (next) {
250 const socket = io(`${server.url}/user-notifications`, {
251 query: { accessToken: 'bad_access_token' },
252 reconnection: false
253 })
254
255 socket.once('connect_error', function () {
256 socket.disconnect()
257 next()
258 })
259
260 socket.on('connect', () => {
261 socket.disconnect()
262 next(new Error('Connected with an invalid token.'))
263 })
264 })
265
266 it('Should success with the correct token', function (next) {
267 const socket = io(`${server.url}/user-notifications`, {
268 query: { accessToken: server.accessToken },
269 reconnection: false
270 })
271
272 function errorListener (err) {
273 next(new Error('Error in connection: ' + err))
274 }
275
276 socket.on('connect_error', errorListener)
277
278 socket.once('connect', async () => {
279 socket.disconnect()
280
281 await wait(500)
282 next()
283 })
284 })
285 })
286
287 after(async function () {
288 await cleanupTests([ server ])
289 })
290})
diff --git a/server/tests/api/check-params/user-subscriptions.ts b/server/tests/api/check-params/user-subscriptions.ts
deleted file mode 100644
index c4922c7a2..000000000
--- a/server/tests/api/check-params/user-subscriptions.ts
+++ /dev/null
@@ -1,298 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import {
4 cleanupTests,
5 createSingleServer,
6 makeDeleteRequest,
7 makeGetRequest,
8 makePostBodyRequest,
9 PeerTubeServer,
10 setAccessTokensToServers,
11 waitJobs
12} from '@shared/server-commands'
13import { HttpStatusCode } from '@shared/models'
14import { checkBadStartPagination, checkBadCountPagination, checkBadSortPagination } from '@server/tests/shared'
15
16describe('Test user subscriptions API validators', function () {
17 const path = '/api/v1/users/me/subscriptions'
18 let server: PeerTubeServer
19 let userAccessToken = ''
20
21 // ---------------------------------------------------------------
22
23 before(async function () {
24 this.timeout(30000)
25
26 server = await createSingleServer(1)
27
28 await setAccessTokensToServers([ server ])
29
30 const user = {
31 username: 'user1',
32 password: 'my super password'
33 }
34 await server.users.create({ username: user.username, password: user.password })
35 userAccessToken = await server.login.getAccessToken(user)
36 })
37
38 describe('When listing my subscriptions', function () {
39 it('Should fail with a bad start pagination', async function () {
40 await checkBadStartPagination(server.url, path, server.accessToken)
41 })
42
43 it('Should fail with a bad count pagination', async function () {
44 await checkBadCountPagination(server.url, path, server.accessToken)
45 })
46
47 it('Should fail with an incorrect sort', async function () {
48 await checkBadSortPagination(server.url, path, server.accessToken)
49 })
50
51 it('Should fail with a non authenticated user', async function () {
52 await makeGetRequest({
53 url: server.url,
54 path,
55 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
56 })
57 })
58
59 it('Should succeed with the correct parameters', async function () {
60 await makeGetRequest({
61 url: server.url,
62 path,
63 token: userAccessToken,
64 expectedStatus: HttpStatusCode.OK_200
65 })
66 })
67 })
68
69 describe('When listing my subscriptions videos', function () {
70 const path = '/api/v1/users/me/subscriptions/videos'
71
72 it('Should fail with a bad start pagination', async function () {
73 await checkBadStartPagination(server.url, path, server.accessToken)
74 })
75
76 it('Should fail with a bad count pagination', async function () {
77 await checkBadCountPagination(server.url, path, server.accessToken)
78 })
79
80 it('Should fail with an incorrect sort', async function () {
81 await checkBadSortPagination(server.url, path, server.accessToken)
82 })
83
84 it('Should fail with a non authenticated user', async function () {
85 await makeGetRequest({
86 url: server.url,
87 path,
88 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
89 })
90 })
91
92 it('Should succeed with the correct parameters', async function () {
93 await makeGetRequest({
94 url: server.url,
95 path,
96 token: userAccessToken,
97 expectedStatus: HttpStatusCode.OK_200
98 })
99 })
100 })
101
102 describe('When adding a subscription', function () {
103 it('Should fail with a non authenticated user', async function () {
104 await makePostBodyRequest({
105 url: server.url,
106 path,
107 fields: { uri: 'user1_channel@' + server.host },
108 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
109 })
110 })
111
112 it('Should fail with bad URIs', async function () {
113 await makePostBodyRequest({
114 url: server.url,
115 path,
116 token: server.accessToken,
117 fields: { uri: 'root' },
118 expectedStatus: HttpStatusCode.BAD_REQUEST_400
119 })
120
121 await makePostBodyRequest({
122 url: server.url,
123 path,
124 token: server.accessToken,
125 fields: { uri: 'root@' },
126 expectedStatus: HttpStatusCode.BAD_REQUEST_400
127 })
128
129 await makePostBodyRequest({
130 url: server.url,
131 path,
132 token: server.accessToken,
133 fields: { uri: 'root@hello@' },
134 expectedStatus: HttpStatusCode.BAD_REQUEST_400
135 })
136 })
137
138 it('Should succeed with the correct parameters', async function () {
139 this.timeout(20000)
140
141 await makePostBodyRequest({
142 url: server.url,
143 path,
144 token: server.accessToken,
145 fields: { uri: 'user1_channel@' + server.host },
146 expectedStatus: HttpStatusCode.NO_CONTENT_204
147 })
148
149 await waitJobs([ server ])
150 })
151 })
152
153 describe('When getting a subscription', function () {
154 it('Should fail with a non authenticated user', async function () {
155 await makeGetRequest({
156 url: server.url,
157 path: path + '/user1_channel@' + server.host,
158 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
159 })
160 })
161
162 it('Should fail with bad URIs', async function () {
163 await makeGetRequest({
164 url: server.url,
165 path: path + '/root',
166 token: server.accessToken,
167 expectedStatus: HttpStatusCode.BAD_REQUEST_400
168 })
169
170 await makeGetRequest({
171 url: server.url,
172 path: path + '/root@',
173 token: server.accessToken,
174 expectedStatus: HttpStatusCode.BAD_REQUEST_400
175 })
176
177 await makeGetRequest({
178 url: server.url,
179 path: path + '/root@hello@',
180 token: server.accessToken,
181 expectedStatus: HttpStatusCode.BAD_REQUEST_400
182 })
183 })
184
185 it('Should fail with an unknown subscription', async function () {
186 await makeGetRequest({
187 url: server.url,
188 path: path + '/root1@' + server.host,
189 token: server.accessToken,
190 expectedStatus: HttpStatusCode.NOT_FOUND_404
191 })
192 })
193
194 it('Should succeed with the correct parameters', async function () {
195 await makeGetRequest({
196 url: server.url,
197 path: path + '/user1_channel@' + server.host,
198 token: server.accessToken,
199 expectedStatus: HttpStatusCode.OK_200
200 })
201 })
202 })
203
204 describe('When checking if subscriptions exist', function () {
205 const existPath = path + '/exist'
206
207 it('Should fail with a non authenticated user', async function () {
208 await makeGetRequest({
209 url: server.url,
210 path: existPath,
211 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
212 })
213 })
214
215 it('Should fail with bad URIs', async function () {
216 await makeGetRequest({
217 url: server.url,
218 path: existPath,
219 query: { uris: 'toto' },
220 token: server.accessToken,
221 expectedStatus: HttpStatusCode.BAD_REQUEST_400
222 })
223
224 await makeGetRequest({
225 url: server.url,
226 path: existPath,
227 query: { 'uris[]': 1 },
228 token: server.accessToken,
229 expectedStatus: HttpStatusCode.BAD_REQUEST_400
230 })
231 })
232
233 it('Should succeed with the correct parameters', async function () {
234 await makeGetRequest({
235 url: server.url,
236 path: existPath,
237 query: { 'uris[]': 'coucou@' + server.host },
238 token: server.accessToken,
239 expectedStatus: HttpStatusCode.OK_200
240 })
241 })
242 })
243
244 describe('When removing a subscription', function () {
245 it('Should fail with a non authenticated user', async function () {
246 await makeDeleteRequest({
247 url: server.url,
248 path: path + '/user1_channel@' + server.host,
249 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
250 })
251 })
252
253 it('Should fail with bad URIs', async function () {
254 await makeDeleteRequest({
255 url: server.url,
256 path: path + '/root',
257 token: server.accessToken,
258 expectedStatus: HttpStatusCode.BAD_REQUEST_400
259 })
260
261 await makeDeleteRequest({
262 url: server.url,
263 path: path + '/root@',
264 token: server.accessToken,
265 expectedStatus: HttpStatusCode.BAD_REQUEST_400
266 })
267
268 await makeDeleteRequest({
269 url: server.url,
270 path: path + '/root@hello@',
271 token: server.accessToken,
272 expectedStatus: HttpStatusCode.BAD_REQUEST_400
273 })
274 })
275
276 it('Should fail with an unknown subscription', async function () {
277 await makeDeleteRequest({
278 url: server.url,
279 path: path + '/root1@' + server.host,
280 token: server.accessToken,
281 expectedStatus: HttpStatusCode.NOT_FOUND_404
282 })
283 })
284
285 it('Should succeed with the correct parameters', async function () {
286 await makeDeleteRequest({
287 url: server.url,
288 path: path + '/user1_channel@' + server.host,
289 token: server.accessToken,
290 expectedStatus: HttpStatusCode.NO_CONTENT_204
291 })
292 })
293 })
294
295 after(async function () {
296 await cleanupTests([ server ])
297 })
298})
diff --git a/server/tests/api/check-params/users-admin.ts b/server/tests/api/check-params/users-admin.ts
deleted file mode 100644
index 819da0bb2..000000000
--- a/server/tests/api/check-params/users-admin.ts
+++ /dev/null
@@ -1,456 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, MockSmtpServer } from '@server/tests/shared'
4import { omit } from '@shared/core-utils'
5import { HttpStatusCode, UserAdminFlag, UserRole } from '@shared/models'
6import {
7 cleanupTests,
8 ConfigCommand,
9 createSingleServer,
10 killallServers,
11 makeGetRequest,
12 makePostBodyRequest,
13 makePutBodyRequest,
14 PeerTubeServer,
15 setAccessTokensToServers
16} from '@shared/server-commands'
17
18describe('Test users admin API validators', function () {
19 const path = '/api/v1/users/'
20 let userId: number
21 let rootId: number
22 let moderatorId: number
23 let server: PeerTubeServer
24 let userToken = ''
25 let moderatorToken = ''
26 let emailPort: number
27
28 // ---------------------------------------------------------------
29
30 before(async function () {
31 this.timeout(30000)
32
33 const emails: object[] = []
34 emailPort = await MockSmtpServer.Instance.collectEmails(emails)
35
36 {
37 server = await createSingleServer(1)
38
39 await setAccessTokensToServers([ server ])
40 }
41
42 {
43 const result = await server.users.generate('user1')
44 userToken = result.token
45 userId = result.userId
46 }
47
48 {
49 const result = await server.users.generate('moderator1', UserRole.MODERATOR)
50 moderatorToken = result.token
51 }
52
53 {
54 const result = await server.users.generate('moderator2', UserRole.MODERATOR)
55 moderatorId = result.userId
56 }
57 })
58
59 describe('When listing users', function () {
60 it('Should fail with a bad start pagination', async function () {
61 await checkBadStartPagination(server.url, path, server.accessToken)
62 })
63
64 it('Should fail with a bad count pagination', async function () {
65 await checkBadCountPagination(server.url, path, server.accessToken)
66 })
67
68 it('Should fail with an incorrect sort', async function () {
69 await checkBadSortPagination(server.url, path, server.accessToken)
70 })
71
72 it('Should fail with a non authenticated user', async function () {
73 await makeGetRequest({
74 url: server.url,
75 path,
76 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
77 })
78 })
79
80 it('Should fail with a non admin user', async function () {
81 await makeGetRequest({
82 url: server.url,
83 path,
84 token: userToken,
85 expectedStatus: HttpStatusCode.FORBIDDEN_403
86 })
87 })
88 })
89
90 describe('When adding a new user', function () {
91 const baseCorrectParams = {
92 username: 'user2',
93 email: 'test@example.com',
94 password: 'my super password',
95 videoQuota: -1,
96 videoQuotaDaily: -1,
97 role: UserRole.USER,
98 adminFlags: UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST
99 }
100
101 it('Should fail with a too small username', async function () {
102 const fields = { ...baseCorrectParams, username: '' }
103
104 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
105 })
106
107 it('Should fail with a too long username', async function () {
108 const fields = { ...baseCorrectParams, username: 'super'.repeat(50) }
109
110 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
111 })
112
113 it('Should fail with a not lowercase username', async function () {
114 const fields = { ...baseCorrectParams, username: 'Toto' }
115
116 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
117 })
118
119 it('Should fail with an incorrect username', async function () {
120 const fields = { ...baseCorrectParams, username: 'my username' }
121
122 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
123 })
124
125 it('Should fail with a missing email', async function () {
126 const fields = omit(baseCorrectParams, [ 'email' ])
127
128 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
129 })
130
131 it('Should fail with an invalid email', async function () {
132 const fields = { ...baseCorrectParams, email: 'test_example.com' }
133
134 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
135 })
136
137 it('Should fail with a too small password', async function () {
138 const fields = { ...baseCorrectParams, password: 'bla' }
139
140 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
141 })
142
143 it('Should fail with a too long password', async function () {
144 const fields = { ...baseCorrectParams, password: 'super'.repeat(61) }
145
146 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
147 })
148
149 it('Should fail with empty password and no smtp configured', async function () {
150 const fields = { ...baseCorrectParams, password: '' }
151
152 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
153 })
154
155 it('Should succeed with no password on a server with smtp enabled', async function () {
156 this.timeout(20000)
157
158 await killallServers([ server ])
159
160 await server.run(ConfigCommand.getEmailOverrideConfig(emailPort))
161
162 const fields = {
163 ...baseCorrectParams,
164
165 password: '',
166 username: 'create_password',
167 email: 'create_password@example.com'
168 }
169
170 await makePostBodyRequest({
171 url: server.url,
172 path,
173 token: server.accessToken,
174 fields,
175 expectedStatus: HttpStatusCode.OK_200
176 })
177 })
178
179 it('Should fail with invalid admin flags', async function () {
180 const fields = { ...baseCorrectParams, adminFlags: 'toto' }
181
182 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
183 })
184
185 it('Should fail with an non authenticated user', async function () {
186 await makePostBodyRequest({
187 url: server.url,
188 path,
189 token: 'super token',
190 fields: baseCorrectParams,
191 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
192 })
193 })
194
195 it('Should fail if we add a user with the same username', async function () {
196 const fields = { ...baseCorrectParams, username: 'user1' }
197
198 await makePostBodyRequest({
199 url: server.url,
200 path,
201 token: server.accessToken,
202 fields,
203 expectedStatus: HttpStatusCode.CONFLICT_409
204 })
205 })
206
207 it('Should fail if we add a user with the same email', async function () {
208 const fields = { ...baseCorrectParams, email: 'user1@example.com' }
209
210 await makePostBodyRequest({
211 url: server.url,
212 path,
213 token: server.accessToken,
214 fields,
215 expectedStatus: HttpStatusCode.CONFLICT_409
216 })
217 })
218
219 it('Should fail with an invalid videoQuota', async function () {
220 const fields = { ...baseCorrectParams, videoQuota: -5 }
221
222 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
223 })
224
225 it('Should fail with an invalid videoQuotaDaily', async function () {
226 const fields = { ...baseCorrectParams, videoQuotaDaily: -7 }
227
228 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
229 })
230
231 it('Should fail without a user role', async function () {
232 const fields = omit(baseCorrectParams, [ 'role' ])
233
234 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
235 })
236
237 it('Should fail with an invalid user role', async function () {
238 const fields = { ...baseCorrectParams, role: 88989 }
239
240 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
241 })
242
243 it('Should fail with a "peertube" username', async function () {
244 const fields = { ...baseCorrectParams, username: 'peertube' }
245
246 await makePostBodyRequest({
247 url: server.url,
248 path,
249 token: server.accessToken,
250 fields,
251 expectedStatus: HttpStatusCode.CONFLICT_409
252 })
253 })
254
255 it('Should fail to create a moderator or an admin with a moderator', async function () {
256 for (const role of [ UserRole.MODERATOR, UserRole.ADMINISTRATOR ]) {
257 const fields = { ...baseCorrectParams, role }
258
259 await makePostBodyRequest({
260 url: server.url,
261 path,
262 token: moderatorToken,
263 fields,
264 expectedStatus: HttpStatusCode.FORBIDDEN_403
265 })
266 }
267 })
268
269 it('Should succeed to create a user with a moderator', async function () {
270 const fields = { ...baseCorrectParams, username: 'a4656', email: 'a4656@example.com', role: UserRole.USER }
271
272 await makePostBodyRequest({
273 url: server.url,
274 path,
275 token: moderatorToken,
276 fields,
277 expectedStatus: HttpStatusCode.OK_200
278 })
279 })
280
281 it('Should succeed with the correct params', async function () {
282 await makePostBodyRequest({
283 url: server.url,
284 path,
285 token: server.accessToken,
286 fields: baseCorrectParams,
287 expectedStatus: HttpStatusCode.OK_200
288 })
289 })
290
291 it('Should fail with a non admin user', async function () {
292 const user = { username: 'user1' }
293 userToken = await server.login.getAccessToken(user)
294
295 const fields = {
296 username: 'user3',
297 email: 'test@example.com',
298 password: 'my super password',
299 videoQuota: 42000000
300 }
301 await makePostBodyRequest({ url: server.url, path, token: userToken, fields, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
302 })
303 })
304
305 describe('When getting a user', function () {
306
307 it('Should fail with an non authenticated user', async function () {
308 await makeGetRequest({
309 url: server.url,
310 path: path + userId,
311 token: 'super token',
312 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
313 })
314 })
315
316 it('Should fail with a non admin user', async function () {
317 await makeGetRequest({ url: server.url, path, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
318 })
319
320 it('Should succeed with the correct params', async function () {
321 await makeGetRequest({ url: server.url, path: path + userId, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
322 })
323 })
324
325 describe('When updating a user', function () {
326
327 it('Should fail with an invalid email attribute', async function () {
328 const fields = {
329 email: 'blabla'
330 }
331
332 await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
333 })
334
335 it('Should fail with an invalid emailVerified attribute', async function () {
336 const fields = {
337 emailVerified: 'yes'
338 }
339
340 await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
341 })
342
343 it('Should fail with an invalid videoQuota attribute', async function () {
344 const fields = {
345 videoQuota: -90
346 }
347
348 await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
349 })
350
351 it('Should fail with an invalid user role attribute', async function () {
352 const fields = {
353 role: 54878
354 }
355
356 await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
357 })
358
359 it('Should fail with a too small password', async function () {
360 const fields = {
361 currentPassword: 'password',
362 password: 'bla'
363 }
364
365 await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
366 })
367
368 it('Should fail with a too long password', async function () {
369 const fields = {
370 currentPassword: 'password',
371 password: 'super'.repeat(61)
372 }
373
374 await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
375 })
376
377 it('Should fail with an non authenticated user', async function () {
378 const fields = {
379 videoQuota: 42
380 }
381
382 await makePutBodyRequest({
383 url: server.url,
384 path: path + userId,
385 token: 'super token',
386 fields,
387 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
388 })
389 })
390
391 it('Should fail when updating root role', async function () {
392 const fields = {
393 role: UserRole.MODERATOR
394 }
395
396 await makePutBodyRequest({ url: server.url, path: path + rootId, token: server.accessToken, fields })
397 })
398
399 it('Should fail with invalid admin flags', async function () {
400 const fields = { adminFlags: 'toto' }
401
402 await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
403 })
404
405 it('Should fail to update an admin with a moderator', async function () {
406 const fields = {
407 videoQuota: 42
408 }
409
410 await makePutBodyRequest({
411 url: server.url,
412 path: path + moderatorId,
413 token: moderatorToken,
414 fields,
415 expectedStatus: HttpStatusCode.FORBIDDEN_403
416 })
417 })
418
419 it('Should succeed to update a user with a moderator', async function () {
420 const fields = {
421 videoQuota: 42
422 }
423
424 await makePutBodyRequest({
425 url: server.url,
426 path: path + userId,
427 token: moderatorToken,
428 fields,
429 expectedStatus: HttpStatusCode.NO_CONTENT_204
430 })
431 })
432
433 it('Should succeed with the correct params', async function () {
434 const fields = {
435 email: 'email@example.com',
436 emailVerified: true,
437 videoQuota: 42,
438 role: UserRole.USER
439 }
440
441 await makePutBodyRequest({
442 url: server.url,
443 path: path + userId,
444 token: server.accessToken,
445 fields,
446 expectedStatus: HttpStatusCode.NO_CONTENT_204
447 })
448 })
449 })
450
451 after(async function () {
452 MockSmtpServer.Instance.kill()
453
454 await cleanupTests([ server ])
455 })
456})
diff --git a/server/tests/api/check-params/users-emails.ts b/server/tests/api/check-params/users-emails.ts
deleted file mode 100644
index 6ebcc8ffe..000000000
--- a/server/tests/api/check-params/users-emails.ts
+++ /dev/null
@@ -1,116 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2import { HttpStatusCode, UserRole } from '@shared/models'
3import { cleanupTests, createSingleServer, makePostBodyRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
4
5describe('Test users API validators', function () {
6 let server: PeerTubeServer
7
8 // ---------------------------------------------------------------
9
10 before(async function () {
11 this.timeout(30000)
12
13 server = await createSingleServer(1, {
14 rates_limit: {
15 ask_send_email: {
16 max: 10
17 }
18 }
19 })
20
21 await setAccessTokensToServers([ server ])
22 await server.config.enableSignup(true)
23
24 await server.users.generate('moderator2', UserRole.MODERATOR)
25
26 await server.registrations.requestRegistration({
27 username: 'request1',
28 registrationReason: 'tt'
29 })
30 })
31
32 describe('When asking a password reset', function () {
33 const path = '/api/v1/users/ask-reset-password'
34
35 it('Should fail with a missing email', async function () {
36 const fields = {}
37
38 await makePostBodyRequest({ url: server.url, path, fields })
39 })
40
41 it('Should fail with an invalid email', async function () {
42 const fields = { email: 'hello' }
43
44 await makePostBodyRequest({ url: server.url, path, fields })
45 })
46
47 it('Should success with the correct params', async function () {
48 const fields = { email: 'admin@example.com' }
49
50 await makePostBodyRequest({
51 url: server.url,
52 path,
53 fields,
54 expectedStatus: HttpStatusCode.NO_CONTENT_204
55 })
56 })
57 })
58
59 describe('When asking for an account verification email', function () {
60 const path = '/api/v1/users/ask-send-verify-email'
61
62 it('Should fail with a missing email', async function () {
63 const fields = {}
64
65 await makePostBodyRequest({ url: server.url, path, fields })
66 })
67
68 it('Should fail with an invalid email', async function () {
69 const fields = { email: 'hello' }
70
71 await makePostBodyRequest({ url: server.url, path, fields })
72 })
73
74 it('Should succeed with the correct params', async function () {
75 const fields = { email: 'admin@example.com' }
76
77 await makePostBodyRequest({
78 url: server.url,
79 path,
80 fields,
81 expectedStatus: HttpStatusCode.NO_CONTENT_204
82 })
83 })
84 })
85
86 describe('When asking for a registration verification email', function () {
87 const path = '/api/v1/users/registrations/ask-send-verify-email'
88
89 it('Should fail with a missing email', async function () {
90 const fields = {}
91
92 await makePostBodyRequest({ url: server.url, path, fields })
93 })
94
95 it('Should fail with an invalid email', async function () {
96 const fields = { email: 'hello' }
97
98 await makePostBodyRequest({ url: server.url, path, fields })
99 })
100
101 it('Should succeed with the correct params', async function () {
102 const fields = { email: 'request1@example.com' }
103
104 await makePostBodyRequest({
105 url: server.url,
106 path,
107 fields,
108 expectedStatus: HttpStatusCode.NO_CONTENT_204
109 })
110 })
111 })
112
113 after(async function () {
114 await cleanupTests([ server ])
115 })
116})
diff --git a/server/tests/api/check-params/video-blacklist.ts b/server/tests/api/check-params/video-blacklist.ts
deleted file mode 100644
index 8e9f61596..000000000
--- a/server/tests/api/check-params/video-blacklist.ts
+++ /dev/null
@@ -1,292 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
5import { HttpStatusCode, VideoBlacklistType } from '@shared/models'
6import {
7 BlacklistCommand,
8 cleanupTests,
9 createMultipleServers,
10 doubleFollow,
11 makePostBodyRequest,
12 makePutBodyRequest,
13 PeerTubeServer,
14 setAccessTokensToServers,
15 waitJobs
16} from '@shared/server-commands'
17
18describe('Test video blacklist API validators', function () {
19 let servers: PeerTubeServer[]
20 let notBlacklistedVideoId: string
21 let remoteVideoUUID: string
22 let userAccessToken1 = ''
23 let userAccessToken2 = ''
24 let command: BlacklistCommand
25
26 // ---------------------------------------------------------------
27
28 before(async function () {
29 this.timeout(120000)
30
31 servers = await createMultipleServers(2)
32
33 await setAccessTokensToServers(servers)
34 await doubleFollow(servers[0], servers[1])
35
36 {
37 const username = 'user1'
38 const password = 'my super password'
39 await servers[0].users.create({ username, password })
40 userAccessToken1 = await servers[0].login.getAccessToken({ username, password })
41 }
42
43 {
44 const username = 'user2'
45 const password = 'my super password'
46 await servers[0].users.create({ username, password })
47 userAccessToken2 = await servers[0].login.getAccessToken({ username, password })
48 }
49
50 {
51 servers[0].store.videoCreated = await servers[0].videos.upload({ token: userAccessToken1 })
52 }
53
54 {
55 const { uuid } = await servers[0].videos.upload()
56 notBlacklistedVideoId = uuid
57 }
58
59 {
60 const { uuid } = await servers[1].videos.upload()
61 remoteVideoUUID = uuid
62 }
63
64 await waitJobs(servers)
65
66 command = servers[0].blacklist
67 })
68
69 describe('When adding a video in blacklist', function () {
70 const basePath = '/api/v1/videos/'
71
72 it('Should fail with nothing', async function () {
73 const path = basePath + servers[0].store.videoCreated + '/blacklist'
74 const fields = {}
75 await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields })
76 })
77
78 it('Should fail with a wrong video', async function () {
79 const wrongPath = '/api/v1/videos/blabla/blacklist'
80 const fields = {}
81 await makePostBodyRequest({ url: servers[0].url, path: wrongPath, token: servers[0].accessToken, fields })
82 })
83
84 it('Should fail with a non authenticated user', async function () {
85 const path = basePath + servers[0].store.videoCreated + '/blacklist'
86 const fields = {}
87 await makePostBodyRequest({ url: servers[0].url, path, token: 'hello', fields, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
88 })
89
90 it('Should fail with a non admin user', async function () {
91 const path = basePath + servers[0].store.videoCreated + '/blacklist'
92 const fields = {}
93 await makePostBodyRequest({
94 url: servers[0].url,
95 path,
96 token: userAccessToken2,
97 fields,
98 expectedStatus: HttpStatusCode.FORBIDDEN_403
99 })
100 })
101
102 it('Should fail with an invalid reason', async function () {
103 const path = basePath + servers[0].store.videoCreated.uuid + '/blacklist'
104 const fields = { reason: 'a'.repeat(305) }
105
106 await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields })
107 })
108
109 it('Should fail to unfederate a remote video', async function () {
110 const path = basePath + remoteVideoUUID + '/blacklist'
111 const fields = { unfederate: true }
112
113 await makePostBodyRequest({
114 url: servers[0].url,
115 path,
116 token: servers[0].accessToken,
117 fields,
118 expectedStatus: HttpStatusCode.CONFLICT_409
119 })
120 })
121
122 it('Should succeed with the correct params', async function () {
123 const path = basePath + servers[0].store.videoCreated.uuid + '/blacklist'
124 const fields = {}
125
126 await makePostBodyRequest({
127 url: servers[0].url,
128 path,
129 token: servers[0].accessToken,
130 fields,
131 expectedStatus: HttpStatusCode.NO_CONTENT_204
132 })
133 })
134 })
135
136 describe('When updating a video in blacklist', function () {
137 const basePath = '/api/v1/videos/'
138
139 it('Should fail with a wrong video', async function () {
140 const wrongPath = '/api/v1/videos/blabla/blacklist'
141 const fields = {}
142 await makePutBodyRequest({ url: servers[0].url, path: wrongPath, token: servers[0].accessToken, fields })
143 })
144
145 it('Should fail with a video not blacklisted', async function () {
146 const path = '/api/v1/videos/' + notBlacklistedVideoId + '/blacklist'
147 const fields = {}
148 await makePutBodyRequest({
149 url: servers[0].url,
150 path,
151 token: servers[0].accessToken,
152 fields,
153 expectedStatus: HttpStatusCode.NOT_FOUND_404
154 })
155 })
156
157 it('Should fail with a non authenticated user', async function () {
158 const path = basePath + servers[0].store.videoCreated + '/blacklist'
159 const fields = {}
160 await makePutBodyRequest({ url: servers[0].url, path, token: 'hello', fields, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
161 })
162
163 it('Should fail with a non admin user', async function () {
164 const path = basePath + servers[0].store.videoCreated + '/blacklist'
165 const fields = {}
166 await makePutBodyRequest({
167 url: servers[0].url,
168 path,
169 token: userAccessToken2,
170 fields,
171 expectedStatus: HttpStatusCode.FORBIDDEN_403
172 })
173 })
174
175 it('Should fail with an invalid reason', async function () {
176 const path = basePath + servers[0].store.videoCreated.uuid + '/blacklist'
177 const fields = { reason: 'a'.repeat(305) }
178
179 await makePutBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields })
180 })
181
182 it('Should succeed with the correct params', async function () {
183 const path = basePath + servers[0].store.videoCreated.shortUUID + '/blacklist'
184 const fields = { reason: 'hello' }
185
186 await makePutBodyRequest({
187 url: servers[0].url,
188 path,
189 token: servers[0].accessToken,
190 fields,
191 expectedStatus: HttpStatusCode.NO_CONTENT_204
192 })
193 })
194 })
195
196 describe('When getting blacklisted video', function () {
197
198 it('Should fail with a non authenticated user', async function () {
199 await servers[0].videos.get({ id: servers[0].store.videoCreated.uuid, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
200 })
201
202 it('Should fail with another user', async function () {
203 await servers[0].videos.getWithToken({
204 token: userAccessToken2,
205 id: servers[0].store.videoCreated.uuid,
206 expectedStatus: HttpStatusCode.FORBIDDEN_403
207 })
208 })
209
210 it('Should succeed with the owner authenticated user', async function () {
211 const video = await servers[0].videos.getWithToken({ token: userAccessToken1, id: servers[0].store.videoCreated.uuid })
212 expect(video.blacklisted).to.be.true
213 })
214
215 it('Should succeed with an admin', async function () {
216 const video = servers[0].store.videoCreated
217
218 for (const id of [ video.id, video.uuid, video.shortUUID ]) {
219 const video = await servers[0].videos.getWithToken({ id, expectedStatus: HttpStatusCode.OK_200 })
220 expect(video.blacklisted).to.be.true
221 }
222 })
223 })
224
225 describe('When removing a video in blacklist', function () {
226
227 it('Should fail with a non authenticated user', async function () {
228 await command.remove({
229 token: 'fake token',
230 videoId: servers[0].store.videoCreated.uuid,
231 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
232 })
233 })
234
235 it('Should fail with a non admin user', async function () {
236 await command.remove({
237 token: userAccessToken2,
238 videoId: servers[0].store.videoCreated.uuid,
239 expectedStatus: HttpStatusCode.FORBIDDEN_403
240 })
241 })
242
243 it('Should fail with an incorrect id', async function () {
244 await command.remove({ videoId: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
245 })
246
247 it('Should fail with a not blacklisted video', async function () {
248 // The video was not added to the blacklist so it should fail
249 await command.remove({ videoId: notBlacklistedVideoId, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
250 })
251
252 it('Should succeed with the correct params', async function () {
253 await command.remove({ videoId: servers[0].store.videoCreated.uuid, expectedStatus: HttpStatusCode.NO_CONTENT_204 })
254 })
255 })
256
257 describe('When listing videos in blacklist', function () {
258 const basePath = '/api/v1/videos/blacklist/'
259
260 it('Should fail with a non authenticated user', async function () {
261 await servers[0].blacklist.list({ token: 'fake token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
262 })
263
264 it('Should fail with a non admin user', async function () {
265 await servers[0].blacklist.list({ token: userAccessToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
266 })
267
268 it('Should fail with a bad start pagination', async function () {
269 await checkBadStartPagination(servers[0].url, basePath, servers[0].accessToken)
270 })
271
272 it('Should fail with a bad count pagination', async function () {
273 await checkBadCountPagination(servers[0].url, basePath, servers[0].accessToken)
274 })
275
276 it('Should fail with an incorrect sort', async function () {
277 await checkBadSortPagination(servers[0].url, basePath, servers[0].accessToken)
278 })
279
280 it('Should fail with an invalid type', async function () {
281 await servers[0].blacklist.list({ type: 0 as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
282 })
283
284 it('Should succeed with the correct parameters', async function () {
285 await servers[0].blacklist.list({ type: VideoBlacklistType.MANUAL })
286 })
287 })
288
289 after(async function () {
290 await cleanupTests(servers)
291 })
292})
diff --git a/server/tests/api/check-params/video-captions.ts b/server/tests/api/check-params/video-captions.ts
deleted file mode 100644
index 532dab1c4..000000000
--- a/server/tests/api/check-params/video-captions.ts
+++ /dev/null
@@ -1,307 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { buildAbsoluteFixturePath } from '@shared/core-utils'
4import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models'
5import {
6 cleanupTests,
7 createSingleServer,
8 makeDeleteRequest,
9 makeGetRequest,
10 makeUploadRequest,
11 PeerTubeServer,
12 setAccessTokensToServers
13} from '@shared/server-commands'
14
15describe('Test video captions API validator', function () {
16 const path = '/api/v1/videos/'
17
18 let server: PeerTubeServer
19 let userAccessToken: string
20 let video: VideoCreateResult
21 let privateVideo: VideoCreateResult
22
23 // ---------------------------------------------------------------
24
25 before(async function () {
26 this.timeout(120000)
27
28 server = await createSingleServer(1)
29
30 await setAccessTokensToServers([ server ])
31
32 video = await server.videos.upload()
33 privateVideo = await server.videos.upload({ attributes: { privacy: VideoPrivacy.PRIVATE } })
34
35 {
36 const user = {
37 username: 'user1',
38 password: 'my super password'
39 }
40 await server.users.create({ username: user.username, password: user.password })
41 userAccessToken = await server.login.getAccessToken(user)
42 }
43 })
44
45 describe('When adding video caption', function () {
46 const fields = { }
47 const attaches = {
48 captionfile: buildAbsoluteFixturePath('subtitle-good1.vtt')
49 }
50
51 it('Should fail without a valid uuid', async function () {
52 await makeUploadRequest({
53 method: 'PUT',
54 url: server.url,
55 path: path + '4da6fde3-88f7-4d16-b119-108df563d0b06/captions/fr',
56 token: server.accessToken,
57 fields,
58 attaches
59 })
60 })
61
62 it('Should fail with an unknown id', async function () {
63 await makeUploadRequest({
64 method: 'PUT',
65 url: server.url,
66 path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/captions/fr',
67 token: server.accessToken,
68 fields,
69 attaches,
70 expectedStatus: 404
71 })
72 })
73
74 it('Should fail with a missing language in path', async function () {
75 const captionPath = path + video.uuid + '/captions'
76 await makeUploadRequest({
77 method: 'PUT',
78 url: server.url,
79 path: captionPath,
80 token: server.accessToken,
81 fields,
82 attaches
83 })
84 })
85
86 it('Should fail with an unknown language', async function () {
87 const captionPath = path + video.uuid + '/captions/15'
88 await makeUploadRequest({
89 method: 'PUT',
90 url: server.url,
91 path: captionPath,
92 token: server.accessToken,
93 fields,
94 attaches
95 })
96 })
97
98 it('Should fail without access token', async function () {
99 const captionPath = path + video.uuid + '/captions/fr'
100 await makeUploadRequest({
101 method: 'PUT',
102 url: server.url,
103 path: captionPath,
104 fields,
105 attaches,
106 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
107 })
108 })
109
110 it('Should fail with a bad access token', async function () {
111 const captionPath = path + video.uuid + '/captions/fr'
112 await makeUploadRequest({
113 method: 'PUT',
114 url: server.url,
115 path: captionPath,
116 token: 'blabla',
117 fields,
118 attaches,
119 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
120 })
121 })
122
123 // We accept any file now
124 // it('Should fail with an invalid captionfile extension', async function () {
125 // const attaches = {
126 // 'captionfile': buildAbsoluteFixturePath('subtitle-bad.txt')
127 // }
128 //
129 // const captionPath = path + video.uuid + '/captions/fr'
130 // await makeUploadRequest({
131 // method: 'PUT',
132 // url: server.url,
133 // path: captionPath,
134 // token: server.accessToken,
135 // fields,
136 // attaches,
137 // expectedStatus: HttpStatusCode.BAD_REQUEST_400
138 // })
139 // })
140
141 // We don't check the extension yet
142 // it('Should fail with an invalid captionfile extension and octet-stream mime type', async function () {
143 // await createVideoCaption({
144 // url: server.url,
145 // accessToken: server.accessToken,
146 // language: 'zh',
147 // videoId: video.uuid,
148 // fixture: 'subtitle-bad.txt',
149 // mimeType: 'application/octet-stream',
150 // expectedStatus: HttpStatusCode.BAD_REQUEST_400
151 // })
152 // })
153
154 it('Should succeed with a valid captionfile extension and octet-stream mime type', async function () {
155 await server.captions.add({
156 language: 'zh',
157 videoId: video.uuid,
158 fixture: 'subtitle-good.srt',
159 mimeType: 'application/octet-stream'
160 })
161 })
162
163 // We don't check the file validity yet
164 // it('Should fail with an invalid captionfile srt', async function () {
165 // const attaches = {
166 // 'captionfile': buildAbsoluteFixturePath('subtitle-bad.srt')
167 // }
168 //
169 // const captionPath = path + video.uuid + '/captions/fr'
170 // await makeUploadRequest({
171 // method: 'PUT',
172 // url: server.url,
173 // path: captionPath,
174 // token: server.accessToken,
175 // fields,
176 // attaches,
177 // expectedStatus: HttpStatusCode.INTERNAL_SERVER_ERROR_500
178 // })
179 // })
180
181 it('Should success with the correct parameters', async function () {
182 const captionPath = path + video.uuid + '/captions/fr'
183 await makeUploadRequest({
184 method: 'PUT',
185 url: server.url,
186 path: captionPath,
187 token: server.accessToken,
188 fields,
189 attaches,
190 expectedStatus: HttpStatusCode.NO_CONTENT_204
191 })
192 })
193 })
194
195 describe('When listing video captions', function () {
196 it('Should fail without a valid uuid', async function () {
197 await makeGetRequest({ url: server.url, path: path + '4da6fde3-88f7-4d16-b119-108df563d0b06/captions' })
198 })
199
200 it('Should fail with an unknown id', async function () {
201 await makeGetRequest({
202 url: server.url,
203 path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/captions',
204 expectedStatus: HttpStatusCode.NOT_FOUND_404
205 })
206 })
207
208 it('Should fail with a private video without token', async function () {
209 await makeGetRequest({
210 url: server.url,
211 path: path + privateVideo.shortUUID + '/captions',
212 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
213 })
214 })
215
216 it('Should fail with another user token', async function () {
217 await makeGetRequest({
218 url: server.url,
219 token: userAccessToken,
220 path: path + privateVideo.shortUUID + '/captions',
221 expectedStatus: HttpStatusCode.FORBIDDEN_403
222 })
223 })
224
225 it('Should success with the correct parameters', async function () {
226 await makeGetRequest({ url: server.url, path: path + video.shortUUID + '/captions', expectedStatus: HttpStatusCode.OK_200 })
227
228 await makeGetRequest({
229 url: server.url,
230 path: path + privateVideo.shortUUID + '/captions',
231 token: server.accessToken,
232 expectedStatus: HttpStatusCode.OK_200
233 })
234 })
235 })
236
237 describe('When deleting video caption', function () {
238 it('Should fail without a valid uuid', async function () {
239 await makeDeleteRequest({
240 url: server.url,
241 path: path + '4da6fde3-88f7-4d16-b119-108df563d0b06/captions/fr',
242 token: server.accessToken
243 })
244 })
245
246 it('Should fail with an unknown id', async function () {
247 await makeDeleteRequest({
248 url: server.url,
249 path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/captions/fr',
250 token: server.accessToken,
251 expectedStatus: HttpStatusCode.NOT_FOUND_404
252 })
253 })
254
255 it('Should fail with an invalid language', async function () {
256 await makeDeleteRequest({
257 url: server.url,
258 path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/captions/16',
259 token: server.accessToken
260 })
261 })
262
263 it('Should fail with a missing language', async function () {
264 const captionPath = path + video.shortUUID + '/captions'
265 await makeDeleteRequest({ url: server.url, path: captionPath, token: server.accessToken })
266 })
267
268 it('Should fail with an unknown language', async function () {
269 const captionPath = path + video.shortUUID + '/captions/15'
270 await makeDeleteRequest({ url: server.url, path: captionPath, token: server.accessToken })
271 })
272
273 it('Should fail without access token', async function () {
274 const captionPath = path + video.shortUUID + '/captions/fr'
275 await makeDeleteRequest({ url: server.url, path: captionPath, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
276 })
277
278 it('Should fail with a bad access token', async function () {
279 const captionPath = path + video.shortUUID + '/captions/fr'
280 await makeDeleteRequest({ url: server.url, path: captionPath, token: 'coucou', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
281 })
282
283 it('Should fail with another user', async function () {
284 const captionPath = path + video.shortUUID + '/captions/fr'
285 await makeDeleteRequest({
286 url: server.url,
287 path: captionPath,
288 token: userAccessToken,
289 expectedStatus: HttpStatusCode.FORBIDDEN_403
290 })
291 })
292
293 it('Should success with the correct parameters', async function () {
294 const captionPath = path + video.shortUUID + '/captions/fr'
295 await makeDeleteRequest({
296 url: server.url,
297 path: captionPath,
298 token: server.accessToken,
299 expectedStatus: HttpStatusCode.NO_CONTENT_204
300 })
301 })
302 })
303
304 after(async function () {
305 await cleanupTests([ server ])
306 })
307})
diff --git a/server/tests/api/check-params/video-channel-syncs.ts b/server/tests/api/check-params/video-channel-syncs.ts
deleted file mode 100644
index bcd8984df..000000000
--- a/server/tests/api/check-params/video-channel-syncs.ts
+++ /dev/null
@@ -1,318 +0,0 @@
1import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, FIXTURE_URLS } from '@server/tests/shared'
2import { HttpStatusCode, VideoChannelSyncCreate } from '@shared/models'
3import {
4 ChannelSyncsCommand,
5 createSingleServer,
6 makePostBodyRequest,
7 PeerTubeServer,
8 setAccessTokensToServers,
9 setDefaultVideoChannel
10} from '@shared/server-commands'
11
12describe('Test video channel sync API validator', () => {
13 const path = '/api/v1/video-channel-syncs'
14 let server: PeerTubeServer
15 let command: ChannelSyncsCommand
16 let rootChannelId: number
17 let rootChannelSyncId: number
18 const userInfo = {
19 accessToken: '',
20 username: 'user1',
21 id: -1,
22 channelId: -1,
23 syncId: -1
24 }
25
26 async function withChannelSyncDisabled<T> (callback: () => Promise<T>): Promise<void> {
27 try {
28 await server.config.disableChannelSync()
29 await callback()
30 } finally {
31 await server.config.enableChannelSync()
32 }
33 }
34
35 async function withMaxSyncsPerUser<T> (maxSync: number, callback: () => Promise<T>): Promise<void> {
36 const origConfig = await server.config.getCustomConfig()
37
38 await server.config.updateExistingSubConfig({
39 newConfig: {
40 import: {
41 videoChannelSynchronization: {
42 maxPerUser: maxSync
43 }
44 }
45 }
46 })
47
48 try {
49 await callback()
50 } finally {
51 await server.config.updateCustomConfig({ newCustomConfig: origConfig })
52 }
53 }
54
55 before(async function () {
56 this.timeout(30_000)
57
58 server = await createSingleServer(1)
59
60 await setAccessTokensToServers([ server ])
61 await setDefaultVideoChannel([ server ])
62
63 command = server.channelSyncs
64
65 rootChannelId = server.store.channel.id
66
67 {
68 userInfo.accessToken = await server.users.generateUserAndToken(userInfo.username)
69
70 const { videoChannels, id: userId } = await server.users.getMyInfo({ token: userInfo.accessToken })
71 userInfo.id = userId
72 userInfo.channelId = videoChannels[0].id
73 }
74
75 await server.config.enableChannelSync()
76 })
77
78 describe('When creating a sync', function () {
79 let baseCorrectParams: VideoChannelSyncCreate
80
81 before(function () {
82 baseCorrectParams = {
83 externalChannelUrl: FIXTURE_URLS.youtubeChannel,
84 videoChannelId: rootChannelId
85 }
86 })
87
88 it('Should fail when sync is disabled', async function () {
89 await withChannelSyncDisabled(async () => {
90 await command.create({
91 token: server.accessToken,
92 attributes: baseCorrectParams,
93 expectedStatus: HttpStatusCode.FORBIDDEN_403
94 })
95 })
96 })
97
98 it('Should fail with nothing', async function () {
99 const fields = {}
100 await makePostBodyRequest({
101 url: server.url,
102 path,
103 token: server.accessToken,
104 fields,
105 expectedStatus: HttpStatusCode.BAD_REQUEST_400
106 })
107 })
108
109 it('Should fail with no authentication', async function () {
110 await command.create({
111 token: null,
112 attributes: baseCorrectParams,
113 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
114 })
115 })
116
117 it('Should fail without a target url', async function () {
118 const attributes: VideoChannelSyncCreate = {
119 ...baseCorrectParams,
120 externalChannelUrl: null
121 }
122 await command.create({
123 token: server.accessToken,
124 attributes,
125 expectedStatus: HttpStatusCode.BAD_REQUEST_400
126 })
127 })
128
129 it('Should fail without a channelId', async function () {
130 const attributes: VideoChannelSyncCreate = {
131 ...baseCorrectParams,
132 videoChannelId: null
133 }
134 await command.create({
135 token: server.accessToken,
136 attributes,
137 expectedStatus: HttpStatusCode.BAD_REQUEST_400
138 })
139 })
140
141 it('Should fail with a channelId refering nothing', async function () {
142 const attributes: VideoChannelSyncCreate = {
143 ...baseCorrectParams,
144 videoChannelId: 42
145 }
146 await command.create({
147 token: server.accessToken,
148 attributes,
149 expectedStatus: HttpStatusCode.NOT_FOUND_404
150 })
151 })
152
153 it('Should fail to create a sync when the user does not own the channel', async function () {
154 await command.create({
155 token: userInfo.accessToken,
156 attributes: baseCorrectParams,
157 expectedStatus: HttpStatusCode.FORBIDDEN_403
158 })
159 })
160
161 it('Should succeed to create a sync with root and for another user\'s channel', async function () {
162 const { videoChannelSync } = await command.create({
163 token: server.accessToken,
164 attributes: {
165 ...baseCorrectParams,
166 videoChannelId: userInfo.channelId
167 },
168 expectedStatus: HttpStatusCode.OK_200
169 })
170 userInfo.syncId = videoChannelSync.id
171 })
172
173 it('Should succeed with the correct parameters', async function () {
174 const { videoChannelSync } = await command.create({
175 token: server.accessToken,
176 attributes: baseCorrectParams,
177 expectedStatus: HttpStatusCode.OK_200
178 })
179 rootChannelSyncId = videoChannelSync.id
180 })
181
182 it('Should fail when the user exceeds allowed number of synchronizations', async function () {
183 await withMaxSyncsPerUser(1, async () => {
184 await command.create({
185 token: server.accessToken,
186 attributes: {
187 ...baseCorrectParams,
188 videoChannelId: userInfo.channelId
189 },
190 expectedStatus: HttpStatusCode.BAD_REQUEST_400
191 })
192 })
193 })
194 })
195
196 describe('When listing my channel syncs', function () {
197 const myPath = '/api/v1/accounts/root/video-channel-syncs'
198
199 it('Should fail with a bad start pagination', async function () {
200 await checkBadStartPagination(server.url, myPath, server.accessToken)
201 })
202
203 it('Should fail with a bad count pagination', async function () {
204 await checkBadCountPagination(server.url, myPath, server.accessToken)
205 })
206
207 it('Should fail with an incorrect sort', async function () {
208 await checkBadSortPagination(server.url, myPath, server.accessToken)
209 })
210
211 it('Should succeed with the correct parameters', async function () {
212 await command.listByAccount({
213 accountName: 'root',
214 token: server.accessToken,
215 expectedStatus: HttpStatusCode.OK_200
216 })
217 })
218
219 it('Should fail with no authentication', async function () {
220 await command.listByAccount({
221 accountName: 'root',
222 token: null,
223 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
224 })
225 })
226
227 it('Should fail when a simple user lists another user\'s synchronizations', async function () {
228 await command.listByAccount({
229 accountName: 'root',
230 token: userInfo.accessToken,
231 expectedStatus: HttpStatusCode.FORBIDDEN_403
232 })
233 })
234
235 it('Should succeed when root lists another user\'s synchronizations', async function () {
236 await command.listByAccount({
237 accountName: userInfo.username,
238 token: server.accessToken,
239 expectedStatus: HttpStatusCode.OK_200
240 })
241 })
242
243 it('Should succeed even with synchronization disabled', async function () {
244 await withChannelSyncDisabled(async function () {
245 await command.listByAccount({
246 accountName: 'root',
247 token: server.accessToken,
248 expectedStatus: HttpStatusCode.OK_200
249 })
250 })
251 })
252 })
253
254 describe('When triggering deletion', function () {
255 it('should fail with no authentication', async function () {
256 await command.delete({
257 channelSyncId: userInfo.syncId,
258 token: null,
259 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
260 })
261 })
262
263 it('Should fail when channelSyncId does not refer to any sync', async function () {
264 await command.delete({
265 channelSyncId: 42,
266 token: server.accessToken,
267 expectedStatus: HttpStatusCode.NOT_FOUND_404
268 })
269 })
270
271 it('Should fail when sync is not owned by the user', async function () {
272 await command.delete({
273 channelSyncId: rootChannelSyncId,
274 token: userInfo.accessToken,
275 expectedStatus: HttpStatusCode.FORBIDDEN_403
276 })
277 })
278
279 it('Should succeed when root delete a sync they do not own', async function () {
280 await command.delete({
281 channelSyncId: userInfo.syncId,
282 token: server.accessToken,
283 expectedStatus: HttpStatusCode.NO_CONTENT_204
284 })
285 })
286
287 it('should succeed when user delete a sync they own', async function () {
288 const { videoChannelSync } = await command.create({
289 attributes: {
290 externalChannelUrl: FIXTURE_URLS.youtubeChannel,
291 videoChannelId: userInfo.channelId
292 },
293 token: server.accessToken,
294 expectedStatus: HttpStatusCode.OK_200
295 })
296
297 await command.delete({
298 channelSyncId: videoChannelSync.id,
299 token: server.accessToken,
300 expectedStatus: HttpStatusCode.NO_CONTENT_204
301 })
302 })
303
304 it('Should succeed even when synchronization is disabled', async function () {
305 await withChannelSyncDisabled(async function () {
306 await command.delete({
307 channelSyncId: rootChannelSyncId,
308 token: server.accessToken,
309 expectedStatus: HttpStatusCode.NO_CONTENT_204
310 })
311 })
312 })
313 })
314
315 after(async function () {
316 await server?.kill()
317 })
318})
diff --git a/server/tests/api/check-params/video-channels.ts b/server/tests/api/check-params/video-channels.ts
deleted file mode 100644
index 1782474fd..000000000
--- a/server/tests/api/check-params/video-channels.ts
+++ /dev/null
@@ -1,378 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
5import { buildAbsoluteFixturePath, omit } from '@shared/core-utils'
6import { HttpStatusCode, VideoChannelUpdate } from '@shared/models'
7import {
8 ChannelsCommand,
9 cleanupTests,
10 createSingleServer,
11 makeGetRequest,
12 makePostBodyRequest,
13 makePutBodyRequest,
14 makeUploadRequest,
15 PeerTubeServer,
16 setAccessTokensToServers
17} from '@shared/server-commands'
18
19describe('Test video channels API validator', function () {
20 const videoChannelPath = '/api/v1/video-channels'
21 let server: PeerTubeServer
22 const userInfo = {
23 accessToken: '',
24 channelName: 'fake_channel',
25 id: -1,
26 videoQuota: -1,
27 videoQuotaDaily: -1
28 }
29 let command: ChannelsCommand
30
31 // ---------------------------------------------------------------
32
33 before(async function () {
34 this.timeout(30000)
35
36 server = await createSingleServer(1)
37
38 await setAccessTokensToServers([ server ])
39
40 const userCreds = {
41 username: 'fake',
42 password: 'fake_password'
43 }
44
45 {
46 const user = await server.users.create({ username: userCreds.username, password: userCreds.password })
47 userInfo.id = user.id
48 userInfo.accessToken = await server.login.getAccessToken(userCreds)
49 }
50
51 command = server.channels
52 })
53
54 describe('When listing a video channels', function () {
55 it('Should fail with a bad start pagination', async function () {
56 await checkBadStartPagination(server.url, videoChannelPath, server.accessToken)
57 })
58
59 it('Should fail with a bad count pagination', async function () {
60 await checkBadCountPagination(server.url, videoChannelPath, server.accessToken)
61 })
62
63 it('Should fail with an incorrect sort', async function () {
64 await checkBadSortPagination(server.url, videoChannelPath, server.accessToken)
65 })
66 })
67
68 describe('When listing account video channels', function () {
69 const accountChannelPath = '/api/v1/accounts/fake/video-channels'
70
71 it('Should fail with a bad start pagination', async function () {
72 await checkBadStartPagination(server.url, accountChannelPath, server.accessToken)
73 })
74
75 it('Should fail with a bad count pagination', async function () {
76 await checkBadCountPagination(server.url, accountChannelPath, server.accessToken)
77 })
78
79 it('Should fail with an incorrect sort', async function () {
80 await checkBadSortPagination(server.url, accountChannelPath, server.accessToken)
81 })
82
83 it('Should fail with a unknown account', async function () {
84 await server.channels.listByAccount({ accountName: 'unknown', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
85 })
86
87 it('Should succeed with the correct parameters', async function () {
88 await makeGetRequest({
89 url: server.url,
90 path: accountChannelPath,
91 expectedStatus: HttpStatusCode.OK_200
92 })
93 })
94 })
95
96 describe('When adding a video channel', function () {
97 const baseCorrectParams = {
98 name: 'super_channel',
99 displayName: 'hello',
100 description: 'super description',
101 support: 'super support text'
102 }
103
104 it('Should fail with a non authenticated user', async function () {
105 await makePostBodyRequest({
106 url: server.url,
107 path: videoChannelPath,
108 token: 'none',
109 fields: baseCorrectParams,
110 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
111 })
112 })
113
114 it('Should fail with nothing', async function () {
115 const fields = {}
116 await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
117 })
118
119 it('Should fail without a name', async function () {
120 const fields = omit(baseCorrectParams, [ 'name' ])
121 await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
122 })
123
124 it('Should fail with a bad name', async function () {
125 const fields = { ...baseCorrectParams, name: 'super name' }
126 await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
127 })
128
129 it('Should fail without a name', async function () {
130 const fields = omit(baseCorrectParams, [ 'displayName' ])
131 await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
132 })
133
134 it('Should fail with a long name', async function () {
135 const fields = { ...baseCorrectParams, displayName: 'super'.repeat(25) }
136 await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
137 })
138
139 it('Should fail with a long description', async function () {
140 const fields = { ...baseCorrectParams, description: 'super'.repeat(201) }
141 await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
142 })
143
144 it('Should fail with a long support text', async function () {
145 const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
146 await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
147 })
148
149 it('Should succeed with the correct parameters', async function () {
150 await makePostBodyRequest({
151 url: server.url,
152 path: videoChannelPath,
153 token: server.accessToken,
154 fields: baseCorrectParams,
155 expectedStatus: HttpStatusCode.OK_200
156 })
157 })
158
159 it('Should fail when adding a channel with the same username', async function () {
160 await makePostBodyRequest({
161 url: server.url,
162 path: videoChannelPath,
163 token: server.accessToken,
164 fields: baseCorrectParams,
165 expectedStatus: HttpStatusCode.CONFLICT_409
166 })
167 })
168 })
169
170 describe('When updating a video channel', function () {
171 const baseCorrectParams: VideoChannelUpdate = {
172 displayName: 'hello',
173 description: 'super description',
174 support: 'toto',
175 bulkVideosSupportUpdate: false
176 }
177 let path: string
178
179 before(async function () {
180 path = videoChannelPath + '/super_channel'
181 })
182
183 it('Should fail with a non authenticated user', async function () {
184 await makePutBodyRequest({
185 url: server.url,
186 path,
187 token: 'hi',
188 fields: baseCorrectParams,
189 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
190 })
191 })
192
193 it('Should fail with another authenticated user', async function () {
194 await makePutBodyRequest({
195 url: server.url,
196 path,
197 token: userInfo.accessToken,
198 fields: baseCorrectParams,
199 expectedStatus: HttpStatusCode.FORBIDDEN_403
200 })
201 })
202
203 it('Should fail with a long name', async function () {
204 const fields = { ...baseCorrectParams, displayName: 'super'.repeat(25) }
205 await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
206 })
207
208 it('Should fail with a long description', async function () {
209 const fields = { ...baseCorrectParams, description: 'super'.repeat(201) }
210 await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
211 })
212
213 it('Should fail with a long support text', async function () {
214 const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
215 await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
216 })
217
218 it('Should fail with a bad bulkVideosSupportUpdate field', async function () {
219 const fields = { ...baseCorrectParams, bulkVideosSupportUpdate: 'super' }
220 await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
221 })
222
223 it('Should succeed with the correct parameters', async function () {
224 await makePutBodyRequest({
225 url: server.url,
226 path,
227 token: server.accessToken,
228 fields: baseCorrectParams,
229 expectedStatus: HttpStatusCode.NO_CONTENT_204
230 })
231 })
232 })
233
234 describe('When updating video channel avatars/banners', function () {
235 const types = [ 'avatar', 'banner' ]
236 let path: string
237
238 before(async function () {
239 path = videoChannelPath + '/super_channel'
240 })
241
242 it('Should fail with an incorrect input file', async function () {
243 for (const type of types) {
244 const fields = {}
245 const attaches = {
246 [type + 'file']: buildAbsoluteFixturePath('video_short.mp4')
247 }
248
249 await makeUploadRequest({ url: server.url, path: `${path}/${type}/pick`, token: server.accessToken, fields, attaches })
250 }
251 })
252
253 it('Should fail with a big file', async function () {
254 for (const type of types) {
255 const fields = {}
256 const attaches = {
257 [type + 'file']: buildAbsoluteFixturePath('avatar-big.png')
258 }
259 await makeUploadRequest({ url: server.url, path: `${path}/${type}/pick`, token: server.accessToken, fields, attaches })
260 }
261 })
262
263 it('Should fail with an unauthenticated user', async function () {
264 for (const type of types) {
265 const fields = {}
266 const attaches = {
267 [type + 'file']: buildAbsoluteFixturePath('avatar.png')
268 }
269 await makeUploadRequest({
270 url: server.url,
271 path: `${path}/${type}/pick`,
272 fields,
273 attaches,
274 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
275 })
276 }
277 })
278
279 it('Should succeed with the correct params', async function () {
280 for (const type of types) {
281 const fields = {}
282 const attaches = {
283 [type + 'file']: buildAbsoluteFixturePath('avatar.png')
284 }
285 await makeUploadRequest({
286 url: server.url,
287 path: `${path}/${type}/pick`,
288 token: server.accessToken,
289 fields,
290 attaches,
291 expectedStatus: HttpStatusCode.OK_200
292 })
293 }
294 })
295 })
296
297 describe('When getting a video channel', function () {
298 it('Should return the list of the video channels with nothing', async function () {
299 const res = await makeGetRequest({
300 url: server.url,
301 path: videoChannelPath,
302 expectedStatus: HttpStatusCode.OK_200
303 })
304
305 expect(res.body.data).to.be.an('array')
306 })
307
308 it('Should return 404 with an incorrect video channel', async function () {
309 await makeGetRequest({
310 url: server.url,
311 path: videoChannelPath + '/super_channel2',
312 expectedStatus: HttpStatusCode.NOT_FOUND_404
313 })
314 })
315
316 it('Should succeed with the correct parameters', async function () {
317 await makeGetRequest({
318 url: server.url,
319 path: videoChannelPath + '/super_channel',
320 expectedStatus: HttpStatusCode.OK_200
321 })
322 })
323 })
324
325 describe('When getting channel followers', function () {
326 const path = '/api/v1/video-channels/super_channel/followers'
327
328 it('Should fail with a bad start pagination', async function () {
329 await checkBadStartPagination(server.url, path, server.accessToken)
330 })
331
332 it('Should fail with a bad count pagination', async function () {
333 await checkBadCountPagination(server.url, path, server.accessToken)
334 })
335
336 it('Should fail with an incorrect sort', async function () {
337 await checkBadSortPagination(server.url, path, server.accessToken)
338 })
339
340 it('Should fail with a unauthenticated user', async function () {
341 await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
342 })
343
344 it('Should fail with a another user', async function () {
345 await makeGetRequest({ url: server.url, path, token: userInfo.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
346 })
347
348 it('Should succeed with the correct params', async function () {
349 await makeGetRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
350 })
351 })
352
353 describe('When deleting a video channel', function () {
354 it('Should fail with a non authenticated user', async function () {
355 await command.delete({ token: 'coucou', channelName: 'super_channel', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
356 })
357
358 it('Should fail with another authenticated user', async function () {
359 await command.delete({ token: userInfo.accessToken, channelName: 'super_channel', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
360 })
361
362 it('Should fail with an unknown video channel id', async function () {
363 await command.delete({ channelName: 'super_channel2', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
364 })
365
366 it('Should succeed with the correct parameters', async function () {
367 await command.delete({ channelName: 'super_channel' })
368 })
369
370 it('Should fail to delete the last user video channel', async function () {
371 await command.delete({ channelName: 'root_channel', expectedStatus: HttpStatusCode.CONFLICT_409 })
372 })
373 })
374
375 after(async function () {
376 await cleanupTests([ server ])
377 })
378})
diff --git a/server/tests/api/check-params/video-comments.ts b/server/tests/api/check-params/video-comments.ts
deleted file mode 100644
index 9f497c0cf..000000000
--- a/server/tests/api/check-params/video-comments.ts
+++ /dev/null
@@ -1,484 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
5import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models'
6import {
7 cleanupTests,
8 createSingleServer,
9 makeDeleteRequest,
10 makeGetRequest,
11 makePostBodyRequest,
12 PeerTubeServer,
13 setAccessTokensToServers
14} from '@shared/server-commands'
15
16describe('Test video comments API validator', function () {
17 let pathThread: string
18 let pathComment: string
19
20 let server: PeerTubeServer
21
22 let video: VideoCreateResult
23
24 let userAccessToken: string
25 let userAccessToken2: string
26
27 let commentId: number
28 let privateCommentId: number
29 let privateVideo: VideoCreateResult
30
31 // ---------------------------------------------------------------
32
33 before(async function () {
34 this.timeout(120000)
35
36 server = await createSingleServer(1)
37
38 await setAccessTokensToServers([ server ])
39
40 {
41 video = await server.videos.upload({ attributes: {} })
42 pathThread = '/api/v1/videos/' + video.uuid + '/comment-threads'
43 }
44
45 {
46 privateVideo = await server.videos.upload({ attributes: { privacy: VideoPrivacy.PRIVATE } })
47 }
48
49 {
50 const created = await server.comments.createThread({ videoId: video.uuid, text: 'coucou' })
51 commentId = created.id
52 pathComment = '/api/v1/videos/' + video.uuid + '/comments/' + commentId
53 }
54
55 {
56 const created = await server.comments.createThread({ videoId: privateVideo.uuid, text: 'coucou' })
57 privateCommentId = created.id
58 }
59
60 {
61 const user = { username: 'user1', password: 'my super password' }
62 await server.users.create({ username: user.username, password: user.password })
63 userAccessToken = await server.login.getAccessToken(user)
64 }
65
66 {
67 const user = { username: 'user2', password: 'my super password' }
68 await server.users.create({ username: user.username, password: user.password })
69 userAccessToken2 = await server.login.getAccessToken(user)
70 }
71 })
72
73 describe('When listing video comment threads', function () {
74 it('Should fail with a bad start pagination', async function () {
75 await checkBadStartPagination(server.url, pathThread, server.accessToken)
76 })
77
78 it('Should fail with a bad count pagination', async function () {
79 await checkBadCountPagination(server.url, pathThread, server.accessToken)
80 })
81
82 it('Should fail with an incorrect sort', async function () {
83 await checkBadSortPagination(server.url, pathThread, server.accessToken)
84 })
85
86 it('Should fail with an incorrect video', async function () {
87 await makeGetRequest({
88 url: server.url,
89 path: '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comment-threads',
90 expectedStatus: HttpStatusCode.NOT_FOUND_404
91 })
92 })
93
94 it('Should fail with a private video without token', async function () {
95 await makeGetRequest({
96 url: server.url,
97 path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads',
98 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
99 })
100 })
101
102 it('Should fail with another user token', async function () {
103 await makeGetRequest({
104 url: server.url,
105 token: userAccessToken,
106 path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads',
107 expectedStatus: HttpStatusCode.FORBIDDEN_403
108 })
109 })
110
111 it('Should succeed with the correct params', async function () {
112 await makeGetRequest({
113 url: server.url,
114 token: server.accessToken,
115 path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads',
116 expectedStatus: HttpStatusCode.OK_200
117 })
118 })
119 })
120
121 describe('When listing comments of a thread', function () {
122 it('Should fail with an incorrect video', async function () {
123 await makeGetRequest({
124 url: server.url,
125 path: '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comment-threads/' + commentId,
126 expectedStatus: HttpStatusCode.NOT_FOUND_404
127 })
128 })
129
130 it('Should fail with an incorrect thread id', async function () {
131 await makeGetRequest({
132 url: server.url,
133 path: '/api/v1/videos/' + video.shortUUID + '/comment-threads/156',
134 expectedStatus: HttpStatusCode.NOT_FOUND_404
135 })
136 })
137
138 it('Should fail with a private video without token', async function () {
139 await makeGetRequest({
140 url: server.url,
141 path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads/' + privateCommentId,
142 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
143 })
144 })
145
146 it('Should fail with another user token', async function () {
147 await makeGetRequest({
148 url: server.url,
149 token: userAccessToken,
150 path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads/' + privateCommentId,
151 expectedStatus: HttpStatusCode.FORBIDDEN_403
152 })
153 })
154
155 it('Should success with the correct params', async function () {
156 await makeGetRequest({
157 url: server.url,
158 token: server.accessToken,
159 path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads/' + privateCommentId,
160 expectedStatus: HttpStatusCode.OK_200
161 })
162
163 await makeGetRequest({
164 url: server.url,
165 path: '/api/v1/videos/' + video.shortUUID + '/comment-threads/' + commentId,
166 expectedStatus: HttpStatusCode.OK_200
167 })
168 })
169 })
170
171 describe('When adding a video thread', function () {
172
173 it('Should fail with a non authenticated user', async function () {
174 const fields = {
175 text: 'text'
176 }
177 await makePostBodyRequest({
178 url: server.url,
179 path: pathThread,
180 token: 'none',
181 fields,
182 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
183 })
184 })
185
186 it('Should fail with nothing', async function () {
187 const fields = {}
188 await makePostBodyRequest({ url: server.url, path: pathThread, token: server.accessToken, fields })
189 })
190
191 it('Should fail with a short comment', async function () {
192 const fields = {
193 text: ''
194 }
195 await makePostBodyRequest({ url: server.url, path: pathThread, token: server.accessToken, fields })
196 })
197
198 it('Should fail with a long comment', async function () {
199 const fields = {
200 text: 'h'.repeat(10001)
201 }
202 await makePostBodyRequest({ url: server.url, path: pathThread, token: server.accessToken, fields })
203 })
204
205 it('Should fail with an incorrect video', async function () {
206 const path = '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comment-threads'
207 const fields = { text: 'super comment' }
208
209 await makePostBodyRequest({
210 url: server.url,
211 path,
212 token: server.accessToken,
213 fields,
214 expectedStatus: HttpStatusCode.NOT_FOUND_404
215 })
216 })
217
218 it('Should fail with a private video of another user', async function () {
219 const fields = { text: 'super comment' }
220
221 await makePostBodyRequest({
222 url: server.url,
223 path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads',
224 token: userAccessToken,
225 fields,
226 expectedStatus: HttpStatusCode.FORBIDDEN_403
227 })
228 })
229
230 it('Should succeed with the correct parameters', async function () {
231 const fields = { text: 'super comment' }
232
233 await makePostBodyRequest({
234 url: server.url,
235 path: pathThread,
236 token: server.accessToken,
237 fields,
238 expectedStatus: HttpStatusCode.OK_200
239 })
240 })
241 })
242
243 describe('When adding a comment to a thread', function () {
244
245 it('Should fail with a non authenticated user', async function () {
246 const fields = {
247 text: 'text'
248 }
249 await makePostBodyRequest({
250 url: server.url,
251 path: pathComment,
252 token: 'none',
253 fields,
254 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
255 })
256 })
257
258 it('Should fail with nothing', async function () {
259 const fields = {}
260 await makePostBodyRequest({ url: server.url, path: pathComment, token: server.accessToken, fields })
261 })
262
263 it('Should fail with a short comment', async function () {
264 const fields = {
265 text: ''
266 }
267 await makePostBodyRequest({ url: server.url, path: pathComment, token: server.accessToken, fields })
268 })
269
270 it('Should fail with a long comment', async function () {
271 const fields = {
272 text: 'h'.repeat(10001)
273 }
274 await makePostBodyRequest({ url: server.url, path: pathComment, token: server.accessToken, fields })
275 })
276
277 it('Should fail with an incorrect video', async function () {
278 const path = '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comments/' + commentId
279 const fields = {
280 text: 'super comment'
281 }
282 await makePostBodyRequest({
283 url: server.url,
284 path,
285 token: server.accessToken,
286 fields,
287 expectedStatus: HttpStatusCode.NOT_FOUND_404
288 })
289 })
290
291 it('Should fail with a private video of another user', async function () {
292 const fields = { text: 'super comment' }
293
294 await makePostBodyRequest({
295 url: server.url,
296 path: '/api/v1/videos/' + privateVideo.uuid + '/comments/' + privateCommentId,
297 token: userAccessToken,
298 fields,
299 expectedStatus: HttpStatusCode.FORBIDDEN_403
300 })
301 })
302
303 it('Should fail with an incorrect comment', async function () {
304 const path = '/api/v1/videos/' + video.uuid + '/comments/124'
305 const fields = {
306 text: 'super comment'
307 }
308 await makePostBodyRequest({
309 url: server.url,
310 path,
311 token: server.accessToken,
312 fields,
313 expectedStatus: HttpStatusCode.NOT_FOUND_404
314 })
315 })
316
317 it('Should succeed with the correct parameters', async function () {
318 const fields = {
319 text: 'super comment'
320 }
321 await makePostBodyRequest({
322 url: server.url,
323 path: pathComment,
324 token: server.accessToken,
325 fields,
326 expectedStatus: HttpStatusCode.OK_200
327 })
328 })
329 })
330
331 describe('When removing video comments', function () {
332 it('Should fail with a non authenticated user', async function () {
333 await makeDeleteRequest({ url: server.url, path: pathComment, token: 'none', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
334 })
335
336 it('Should fail with another user', async function () {
337 await makeDeleteRequest({
338 url: server.url,
339 path: pathComment,
340 token: userAccessToken,
341 expectedStatus: HttpStatusCode.FORBIDDEN_403
342 })
343 })
344
345 it('Should fail with an incorrect video', async function () {
346 const path = '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comments/' + commentId
347 await makeDeleteRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
348 })
349
350 it('Should fail with an incorrect comment', async function () {
351 const path = '/api/v1/videos/' + video.uuid + '/comments/124'
352 await makeDeleteRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
353 })
354
355 it('Should succeed with the same user', async function () {
356 let commentToDelete: number
357
358 {
359 const created = await server.comments.createThread({ videoId: video.uuid, token: userAccessToken, text: 'hello' })
360 commentToDelete = created.id
361 }
362
363 const path = '/api/v1/videos/' + video.uuid + '/comments/' + commentToDelete
364
365 await makeDeleteRequest({ url: server.url, path, token: userAccessToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
366 await makeDeleteRequest({ url: server.url, path, token: userAccessToken, expectedStatus: HttpStatusCode.NO_CONTENT_204 })
367 })
368
369 it('Should succeed with the owner of the video', async function () {
370 let commentToDelete: number
371 let anotherVideoUUID: string
372
373 {
374 const { uuid } = await server.videos.upload({ token: userAccessToken, attributes: { name: 'video' } })
375 anotherVideoUUID = uuid
376 }
377
378 {
379 const created = await server.comments.createThread({ videoId: anotherVideoUUID, text: 'hello' })
380 commentToDelete = created.id
381 }
382
383 const path = '/api/v1/videos/' + anotherVideoUUID + '/comments/' + commentToDelete
384
385 await makeDeleteRequest({ url: server.url, path, token: userAccessToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
386 await makeDeleteRequest({ url: server.url, path, token: userAccessToken, expectedStatus: HttpStatusCode.NO_CONTENT_204 })
387 })
388
389 it('Should succeed with the correct parameters', async function () {
390 await makeDeleteRequest({
391 url: server.url,
392 path: pathComment,
393 token: server.accessToken,
394 expectedStatus: HttpStatusCode.NO_CONTENT_204
395 })
396 })
397 })
398
399 describe('When a video has comments disabled', function () {
400 before(async function () {
401 video = await server.videos.upload({ attributes: { commentsEnabled: false } })
402 pathThread = '/api/v1/videos/' + video.uuid + '/comment-threads'
403 })
404
405 it('Should return an empty thread list', async function () {
406 const res = await makeGetRequest({
407 url: server.url,
408 path: pathThread,
409 expectedStatus: HttpStatusCode.OK_200
410 })
411 expect(res.body.total).to.equal(0)
412 expect(res.body.data).to.have.lengthOf(0)
413 })
414
415 it('Should return an thread comments list')
416
417 it('Should return conflict on thread add', async function () {
418 const fields = {
419 text: 'super comment'
420 }
421 await makePostBodyRequest({
422 url: server.url,
423 path: pathThread,
424 token: server.accessToken,
425 fields,
426 expectedStatus: HttpStatusCode.CONFLICT_409
427 })
428 })
429
430 it('Should return conflict on comment thread add')
431 })
432
433 describe('When listing admin comments threads', function () {
434 const path = '/api/v1/videos/comments'
435
436 it('Should fail with a bad start pagination', async function () {
437 await checkBadStartPagination(server.url, path, server.accessToken)
438 })
439
440 it('Should fail with a bad count pagination', async function () {
441 await checkBadCountPagination(server.url, path, server.accessToken)
442 })
443
444 it('Should fail with an incorrect sort', async function () {
445 await checkBadSortPagination(server.url, path, server.accessToken)
446 })
447
448 it('Should fail with a non authenticated user', async function () {
449 await makeGetRequest({
450 url: server.url,
451 path,
452 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
453 })
454 })
455
456 it('Should fail with a non admin user', async function () {
457 await makeGetRequest({
458 url: server.url,
459 path,
460 token: userAccessToken,
461 expectedStatus: HttpStatusCode.FORBIDDEN_403
462 })
463 })
464
465 it('Should succeed with the correct params', async function () {
466 await makeGetRequest({
467 url: server.url,
468 path,
469 token: server.accessToken,
470 query: {
471 isLocal: false,
472 search: 'toto',
473 searchAccount: 'toto',
474 searchVideo: 'toto'
475 },
476 expectedStatus: HttpStatusCode.OK_200
477 })
478 })
479 })
480
481 after(async function () {
482 await cleanupTests([ server ])
483 })
484})
diff --git a/server/tests/api/check-params/video-files.ts b/server/tests/api/check-params/video-files.ts
deleted file mode 100644
index 01d6a912b..000000000
--- a/server/tests/api/check-params/video-files.ts
+++ /dev/null
@@ -1,195 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { getAllFiles } from '@shared/core-utils'
4import { HttpStatusCode, UserRole, VideoDetails, VideoPrivacy } from '@shared/models'
5import {
6 cleanupTests,
7 createMultipleServers,
8 doubleFollow,
9 makeRawRequest,
10 PeerTubeServer,
11 setAccessTokensToServers,
12 waitJobs
13} from '@shared/server-commands'
14
15describe('Test videos files', function () {
16 let servers: PeerTubeServer[]
17
18 let userToken: string
19 let moderatorToken: string
20
21 // ---------------------------------------------------------------
22
23 before(async function () {
24 this.timeout(300_000)
25
26 servers = await createMultipleServers(2)
27 await setAccessTokensToServers(servers)
28
29 await doubleFollow(servers[0], servers[1])
30
31 userToken = await servers[0].users.generateUserAndToken('user', UserRole.USER)
32 moderatorToken = await servers[0].users.generateUserAndToken('moderator', UserRole.MODERATOR)
33 })
34
35 describe('Getting metadata', function () {
36 let video: VideoDetails
37
38 before(async function () {
39 const { uuid } = await servers[0].videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE })
40 video = await servers[0].videos.getWithToken({ id: uuid })
41 })
42
43 it('Should not get metadata of private video without token', async function () {
44 for (const file of getAllFiles(video)) {
45 await makeRawRequest({ url: file.metadataUrl, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
46 }
47 })
48
49 it('Should not get metadata of private video without the appropriate token', async function () {
50 for (const file of getAllFiles(video)) {
51 await makeRawRequest({ url: file.metadataUrl, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
52 }
53 })
54
55 it('Should get metadata of private video with the appropriate token', async function () {
56 for (const file of getAllFiles(video)) {
57 await makeRawRequest({ url: file.metadataUrl, token: servers[0].accessToken, expectedStatus: HttpStatusCode.OK_200 })
58 }
59 })
60 })
61
62 describe('Deleting files', function () {
63 let webVideoId: string
64 let hlsId: string
65 let remoteId: string
66
67 let validId1: string
68 let validId2: string
69
70 let hlsFileId: number
71 let webVideoFileId: number
72
73 let remoteHLSFileId: number
74 let remoteWebVideoFileId: number
75
76 before(async function () {
77 this.timeout(300_000)
78
79 {
80 const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' })
81 await waitJobs(servers)
82
83 const video = await servers[1].videos.get({ id: uuid })
84 remoteId = video.uuid
85 remoteHLSFileId = video.streamingPlaylists[0].files[0].id
86 remoteWebVideoFileId = video.files[0].id
87 }
88
89 {
90 await servers[0].config.enableTranscoding({ hls: true, webVideo: true })
91
92 {
93 const { uuid } = await servers[0].videos.quickUpload({ name: 'both 1' })
94 await waitJobs(servers)
95
96 const video = await servers[0].videos.get({ id: uuid })
97 validId1 = video.uuid
98 hlsFileId = video.streamingPlaylists[0].files[0].id
99 webVideoFileId = video.files[0].id
100 }
101
102 {
103 const { uuid } = await servers[0].videos.quickUpload({ name: 'both 2' })
104 validId2 = uuid
105 }
106 }
107
108 await waitJobs(servers)
109
110 {
111 await servers[0].config.enableTranscoding({ hls: true, webVideo: false })
112 const { uuid } = await servers[0].videos.quickUpload({ name: 'hls' })
113 hlsId = uuid
114 }
115
116 await waitJobs(servers)
117
118 {
119 await servers[0].config.enableTranscoding({ webVideo: true, hls: false })
120 const { uuid } = await servers[0].videos.quickUpload({ name: 'web-video' })
121 webVideoId = uuid
122 }
123
124 await waitJobs(servers)
125 })
126
127 it('Should not delete files of a unknown video', async function () {
128 const expectedStatus = HttpStatusCode.NOT_FOUND_404
129
130 await servers[0].videos.removeHLSPlaylist({ videoId: 404, expectedStatus })
131 await servers[0].videos.removeAllWebVideoFiles({ videoId: 404, expectedStatus })
132
133 await servers[0].videos.removeHLSFile({ videoId: 404, fileId: hlsFileId, expectedStatus })
134 await servers[0].videos.removeWebVideoFile({ videoId: 404, fileId: webVideoFileId, expectedStatus })
135 })
136
137 it('Should not delete unknown files', async function () {
138 const expectedStatus = HttpStatusCode.NOT_FOUND_404
139
140 await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: webVideoFileId, expectedStatus })
141 await servers[0].videos.removeWebVideoFile({ videoId: validId1, fileId: hlsFileId, expectedStatus })
142 })
143
144 it('Should not delete files of a remote video', async function () {
145 const expectedStatus = HttpStatusCode.BAD_REQUEST_400
146
147 await servers[0].videos.removeHLSPlaylist({ videoId: remoteId, expectedStatus })
148 await servers[0].videos.removeAllWebVideoFiles({ videoId: remoteId, expectedStatus })
149
150 await servers[0].videos.removeHLSFile({ videoId: remoteId, fileId: remoteHLSFileId, expectedStatus })
151 await servers[0].videos.removeWebVideoFile({ videoId: remoteId, fileId: remoteWebVideoFileId, expectedStatus })
152 })
153
154 it('Should not delete files by a non admin user', async function () {
155 const expectedStatus = HttpStatusCode.FORBIDDEN_403
156
157 await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: userToken, expectedStatus })
158 await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: moderatorToken, expectedStatus })
159
160 await servers[0].videos.removeAllWebVideoFiles({ videoId: validId1, token: userToken, expectedStatus })
161 await servers[0].videos.removeAllWebVideoFiles({ videoId: validId1, token: moderatorToken, expectedStatus })
162
163 await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: userToken, expectedStatus })
164 await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: moderatorToken, expectedStatus })
165
166 await servers[0].videos.removeWebVideoFile({ videoId: validId1, fileId: webVideoFileId, token: userToken, expectedStatus })
167 await servers[0].videos.removeWebVideoFile({ videoId: validId1, fileId: webVideoFileId, token: moderatorToken, expectedStatus })
168 })
169
170 it('Should not delete files if the files are not available', async function () {
171 await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
172 await servers[0].videos.removeAllWebVideoFiles({ videoId: webVideoId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
173
174 await servers[0].videos.removeHLSFile({ videoId: hlsId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
175 await servers[0].videos.removeWebVideoFile({ videoId: webVideoId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
176 })
177
178 it('Should not delete files if no both versions are available', async function () {
179 await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
180 await servers[0].videos.removeAllWebVideoFiles({ videoId: webVideoId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
181 })
182
183 it('Should delete files if both versions are available', async function () {
184 await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId })
185 await servers[0].videos.removeWebVideoFile({ videoId: validId1, fileId: webVideoFileId })
186
187 await servers[0].videos.removeHLSPlaylist({ videoId: validId1 })
188 await servers[0].videos.removeAllWebVideoFiles({ videoId: validId2 })
189 })
190 })
191
192 after(async function () {
193 await cleanupTests(servers)
194 })
195})
diff --git a/server/tests/api/check-params/video-imports.ts b/server/tests/api/check-params/video-imports.ts
deleted file mode 100644
index 8c6f43c12..000000000
--- a/server/tests/api/check-params/video-imports.ts
+++ /dev/null
@@ -1,431 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, FIXTURE_URLS } from '@server/tests/shared'
4import { buildAbsoluteFixturePath, omit } from '@shared/core-utils'
5import { HttpStatusCode, VideoPrivacy } from '@shared/models'
6import {
7 cleanupTests,
8 createSingleServer,
9 makeGetRequest,
10 makePostBodyRequest,
11 makeUploadRequest,
12 PeerTubeServer,
13 setAccessTokensToServers,
14 setDefaultVideoChannel,
15 waitJobs
16} from '@shared/server-commands'
17
18describe('Test video imports API validator', function () {
19 const path = '/api/v1/videos/imports'
20 let server: PeerTubeServer
21 let userAccessToken = ''
22 let channelId: number
23
24 // ---------------------------------------------------------------
25
26 before(async function () {
27 this.timeout(30000)
28
29 server = await createSingleServer(1)
30
31 await setAccessTokensToServers([ server ])
32 await setDefaultVideoChannel([ server ])
33
34 const username = 'user1'
35 const password = 'my super password'
36 await server.users.create({ username, password })
37 userAccessToken = await server.login.getAccessToken({ username, password })
38
39 {
40 const { videoChannels } = await server.users.getMyInfo()
41 channelId = videoChannels[0].id
42 }
43 })
44
45 describe('When listing my video imports', function () {
46 const myPath = '/api/v1/users/me/videos/imports'
47
48 it('Should fail with a bad start pagination', async function () {
49 await checkBadStartPagination(server.url, myPath, server.accessToken)
50 })
51
52 it('Should fail with a bad count pagination', async function () {
53 await checkBadCountPagination(server.url, myPath, server.accessToken)
54 })
55
56 it('Should fail with an incorrect sort', async function () {
57 await checkBadSortPagination(server.url, myPath, server.accessToken)
58 })
59
60 it('Should fail with a bad videoChannelSyncId param', async function () {
61 await makeGetRequest({
62 url: server.url,
63 path: myPath,
64 query: { videoChannelSyncId: 'toto' },
65 token: server.accessToken
66 })
67 })
68
69 it('Should success with the correct parameters', async function () {
70 await makeGetRequest({ url: server.url, path: myPath, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken })
71 })
72 })
73
74 describe('When adding a video import', function () {
75 let baseCorrectParams
76
77 before(function () {
78 baseCorrectParams = {
79 targetUrl: FIXTURE_URLS.goodVideo,
80 name: 'my super name',
81 category: 5,
82 licence: 1,
83 language: 'pt',
84 nsfw: false,
85 commentsEnabled: true,
86 downloadEnabled: true,
87 waitTranscoding: true,
88 description: 'my super description',
89 support: 'my super support text',
90 tags: [ 'tag1', 'tag2' ],
91 privacy: VideoPrivacy.PUBLIC,
92 channelId
93 }
94 })
95
96 it('Should fail with nothing', async function () {
97 const fields = {}
98 await makePostBodyRequest({
99 url: server.url,
100 path,
101 token: server.accessToken,
102 fields,
103 expectedStatus: HttpStatusCode.BAD_REQUEST_400
104 })
105 })
106
107 it('Should fail without a target url', async function () {
108 const fields = omit(baseCorrectParams, [ 'targetUrl' ])
109 await makePostBodyRequest({
110 url: server.url,
111 path,
112 token: server.accessToken,
113 fields,
114 expectedStatus: HttpStatusCode.BAD_REQUEST_400
115 })
116 })
117
118 it('Should fail with a bad target url', async function () {
119 const fields = { ...baseCorrectParams, targetUrl: 'htt://hello' }
120
121 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
122 })
123
124 it('Should fail with localhost', async function () {
125 const fields = { ...baseCorrectParams, targetUrl: 'http://localhost:8000' }
126
127 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
128 })
129
130 it('Should fail with a private IP target urls', async function () {
131 const targetUrls = [
132 'http://127.0.0.1:8000',
133 'http://127.0.0.1',
134 'http://127.0.0.1/hello',
135 'https://192.168.1.42',
136 'http://192.168.1.42',
137 'http://127.0.0.1.cpy.re'
138 ]
139
140 for (const targetUrl of targetUrls) {
141 const fields = { ...baseCorrectParams, targetUrl }
142
143 await makePostBodyRequest({
144 url: server.url,
145 path,
146 token: server.accessToken,
147 fields,
148 expectedStatus: HttpStatusCode.FORBIDDEN_403
149 })
150 }
151 })
152
153 it('Should fail with a long name', async function () {
154 const fields = { ...baseCorrectParams, name: 'super'.repeat(65) }
155
156 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
157 })
158
159 it('Should fail with a bad category', async function () {
160 const fields = { ...baseCorrectParams, category: 125 }
161
162 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
163 })
164
165 it('Should fail with a bad licence', async function () {
166 const fields = { ...baseCorrectParams, licence: 125 }
167
168 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
169 })
170
171 it('Should fail with a bad language', async function () {
172 const fields = { ...baseCorrectParams, language: 'a'.repeat(15) }
173
174 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
175 })
176
177 it('Should fail with a long description', async function () {
178 const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) }
179
180 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
181 })
182
183 it('Should fail with a long support text', async function () {
184 const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
185
186 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
187 })
188
189 it('Should fail without a channel', async function () {
190 const fields = omit(baseCorrectParams, [ 'channelId' ])
191
192 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
193 })
194
195 it('Should fail with a bad channel', async function () {
196 const fields = { ...baseCorrectParams, channelId: 545454 }
197
198 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
199 })
200
201 it('Should fail with another user channel', async function () {
202 const user = {
203 username: 'fake',
204 password: 'fake_password'
205 }
206 await server.users.create({ username: user.username, password: user.password })
207
208 const accessTokenUser = await server.login.getAccessToken(user)
209 const { videoChannels } = await server.users.getMyInfo({ token: accessTokenUser })
210 const customChannelId = videoChannels[0].id
211
212 const fields = { ...baseCorrectParams, channelId: customChannelId }
213
214 await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields })
215 })
216
217 it('Should fail with too many tags', async function () {
218 const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }
219
220 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
221 })
222
223 it('Should fail with a tag length too low', async function () {
224 const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] }
225
226 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
227 })
228
229 it('Should fail with a tag length too big', async function () {
230 const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }
231
232 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
233 })
234
235 it('Should fail with an incorrect thumbnail file', async function () {
236 const fields = baseCorrectParams
237 const attaches = {
238 thumbnailfile: buildAbsoluteFixturePath('video_short.mp4')
239 }
240
241 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
242 })
243
244 it('Should fail with a big thumbnail file', async function () {
245 const fields = baseCorrectParams
246 const attaches = {
247 thumbnailfile: buildAbsoluteFixturePath('custom-preview-big.png')
248 }
249
250 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
251 })
252
253 it('Should fail with an incorrect preview file', async function () {
254 const fields = baseCorrectParams
255 const attaches = {
256 previewfile: buildAbsoluteFixturePath('video_short.mp4')
257 }
258
259 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
260 })
261
262 it('Should fail with a big preview file', async function () {
263 const fields = baseCorrectParams
264 const attaches = {
265 previewfile: buildAbsoluteFixturePath('custom-preview-big.png')
266 }
267
268 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
269 })
270
271 it('Should fail with an invalid torrent file', async function () {
272 const fields = omit(baseCorrectParams, [ 'targetUrl' ])
273 const attaches = {
274 torrentfile: buildAbsoluteFixturePath('avatar-big.png')
275 }
276
277 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
278 })
279
280 it('Should fail with an invalid magnet URI', async function () {
281 let fields = omit(baseCorrectParams, [ 'targetUrl' ])
282 fields = { ...fields, magnetUri: 'blabla' }
283
284 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
285 })
286
287 it('Should succeed with the correct parameters', async function () {
288 this.timeout(120000)
289
290 await makePostBodyRequest({
291 url: server.url,
292 path,
293 token: server.accessToken,
294 fields: baseCorrectParams,
295 expectedStatus: HttpStatusCode.OK_200
296 })
297 })
298
299 it('Should forbid to import http videos', async function () {
300 await server.config.updateCustomSubConfig({
301 newConfig: {
302 import: {
303 videos: {
304 http: {
305 enabled: false
306 },
307 torrent: {
308 enabled: true
309 }
310 }
311 }
312 }
313 })
314
315 await makePostBodyRequest({
316 url: server.url,
317 path,
318 token: server.accessToken,
319 fields: baseCorrectParams,
320 expectedStatus: HttpStatusCode.CONFLICT_409
321 })
322 })
323
324 it('Should forbid to import torrent videos', async function () {
325 await server.config.updateCustomSubConfig({
326 newConfig: {
327 import: {
328 videos: {
329 http: {
330 enabled: true
331 },
332 torrent: {
333 enabled: false
334 }
335 }
336 }
337 }
338 })
339
340 let fields = omit(baseCorrectParams, [ 'targetUrl' ])
341 fields = { ...fields, magnetUri: FIXTURE_URLS.magnet }
342
343 await makePostBodyRequest({
344 url: server.url,
345 path,
346 token: server.accessToken,
347 fields,
348 expectedStatus: HttpStatusCode.CONFLICT_409
349 })
350
351 fields = omit(fields, [ 'magnetUri' ])
352 const attaches = {
353 torrentfile: buildAbsoluteFixturePath('video-720p.torrent')
354 }
355
356 await makeUploadRequest({
357 url: server.url,
358 path,
359 token: server.accessToken,
360 fields,
361 attaches,
362 expectedStatus: HttpStatusCode.CONFLICT_409
363 })
364 })
365 })
366
367 describe('Deleting/cancelling a video import', function () {
368 let importId: number
369
370 async function importVideo () {
371 const attributes = { channelId: server.store.channel.id, targetUrl: FIXTURE_URLS.goodVideo }
372 const res = await server.imports.importVideo({ attributes })
373
374 return res.id
375 }
376
377 before(async function () {
378 importId = await importVideo()
379 })
380
381 it('Should fail with an invalid import id', async function () {
382 await server.imports.cancel({ importId: 'artyom' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
383 await server.imports.delete({ importId: 'artyom' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
384 })
385
386 it('Should fail with an unknown import id', async function () {
387 await server.imports.cancel({ importId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
388 await server.imports.delete({ importId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
389 })
390
391 it('Should fail without token', async function () {
392 await server.imports.cancel({ importId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
393 await server.imports.delete({ importId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
394 })
395
396 it('Should fail with another user token', async function () {
397 await server.imports.cancel({ importId, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
398 await server.imports.delete({ importId, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
399 })
400
401 it('Should fail to cancel non pending import', async function () {
402 this.timeout(60000)
403
404 await waitJobs([ server ])
405
406 await server.imports.cancel({ importId, expectedStatus: HttpStatusCode.CONFLICT_409 })
407 })
408
409 it('Should succeed to delete an import', async function () {
410 await server.imports.delete({ importId })
411 })
412
413 it('Should fail to delete a pending import', async function () {
414 await server.jobs.pauseJobQueue()
415
416 importId = await importVideo()
417
418 await server.imports.delete({ importId, expectedStatus: HttpStatusCode.CONFLICT_409 })
419 })
420
421 it('Should succeed to cancel an import', async function () {
422 importId = await importVideo()
423
424 await server.imports.cancel({ importId })
425 })
426 })
427
428 after(async function () {
429 await cleanupTests([ server ])
430 })
431})
diff --git a/server/tests/api/check-params/video-passwords.ts b/server/tests/api/check-params/video-passwords.ts
deleted file mode 100644
index 50b0bacb3..000000000
--- a/server/tests/api/check-params/video-passwords.ts
+++ /dev/null
@@ -1,609 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2import {
3 FIXTURE_URLS,
4 checkBadCountPagination,
5 checkBadSortPagination,
6 checkBadStartPagination,
7 checkUploadVideoParam
8} from '@server/tests/shared'
9import { root } from '@shared/core-utils'
10import {
11 HttpStatusCode,
12 PeerTubeProblemDocument,
13 ServerErrorCode,
14 VideoCreateResult,
15 VideoPrivacy
16} from '@shared/models'
17import {
18 cleanupTests,
19 createSingleServer,
20 makePostBodyRequest,
21 PeerTubeServer,
22 setAccessTokensToServers
23} from '@shared/server-commands'
24import { expect } from 'chai'
25import { join } from 'path'
26
27describe('Test video passwords validator', function () {
28 let path: string
29 let server: PeerTubeServer
30 let userAccessToken = ''
31 let video: VideoCreateResult
32 let channelId: number
33 let publicVideo: VideoCreateResult
34 let commentId: number
35 // ---------------------------------------------------------------
36
37 before(async function () {
38 this.timeout(50000)
39
40 server = await createSingleServer(1)
41
42 await setAccessTokensToServers([ server ])
43
44 await server.config.updateCustomSubConfig({
45 newConfig: {
46 live: {
47 enabled: true,
48 latencySetting: {
49 enabled: false
50 },
51 allowReplay: false
52 },
53 import: {
54 videos: {
55 http:{
56 enabled: true
57 }
58 }
59 }
60 }
61 })
62
63 userAccessToken = await server.users.generateUserAndToken('user1')
64
65 {
66 const body = await server.users.getMyInfo()
67 channelId = body.videoChannels[0].id
68 }
69
70 {
71 video = await server.videos.quickUpload({
72 name: 'password protected video',
73 privacy: VideoPrivacy.PASSWORD_PROTECTED,
74 videoPasswords: [ 'password1', 'password2' ]
75 })
76 }
77 path = '/api/v1/videos/'
78 })
79
80 async function checkVideoPasswordOptions (options: {
81 server: PeerTubeServer
82 token: string
83 videoPasswords: string[]
84 expectedStatus: HttpStatusCode
85 mode: 'uploadLegacy' | 'uploadResumable' | 'import' | 'updateVideo' | 'updatePasswords' | 'live'
86 }) {
87 const { server, token, videoPasswords, expectedStatus = HttpStatusCode.OK_200, mode } = options
88 const attaches = {
89 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.webm')
90 }
91 const baseCorrectParams = {
92 name: 'my super name',
93 category: 5,
94 licence: 1,
95 language: 'pt',
96 nsfw: false,
97 commentsEnabled: true,
98 downloadEnabled: true,
99 waitTranscoding: true,
100 description: 'my super description',
101 support: 'my super support text',
102 tags: [ 'tag1', 'tag2' ],
103 privacy: VideoPrivacy.PASSWORD_PROTECTED,
104 channelId,
105 originallyPublishedAt: new Date().toISOString()
106 }
107 if (mode === 'uploadLegacy') {
108 const fields = { ...baseCorrectParams, videoPasswords }
109 return checkUploadVideoParam({ server, token, attributes: { ...fields, ...attaches }, expectedStatus, mode: 'legacy' })
110 }
111
112 if (mode === 'uploadResumable') {
113 const fields = { ...baseCorrectParams, videoPasswords }
114 return checkUploadVideoParam({ server, token, attributes: { ...fields, ...attaches }, expectedStatus, mode: 'resumable' })
115 }
116
117 if (mode === 'import') {
118 const attributes = { ...baseCorrectParams, targetUrl: FIXTURE_URLS.goodVideo, videoPasswords }
119 return server.imports.importVideo({ attributes, expectedStatus })
120 }
121
122 if (mode === 'updateVideo') {
123 const attributes = { ...baseCorrectParams, videoPasswords }
124 return server.videos.update({ token, expectedStatus, id: video.id, attributes })
125 }
126
127 if (mode === 'updatePasswords') {
128 return server.videoPasswords.updateAll({ token, expectedStatus, videoId: video.id, passwords: videoPasswords })
129 }
130
131 if (mode === 'live') {
132 const fields = { ...baseCorrectParams, videoPasswords }
133
134 return server.live.create({ fields, expectedStatus })
135 }
136 }
137
138 function validateVideoPasswordList (mode: 'uploadLegacy' | 'uploadResumable' | 'import' | 'updateVideo' | 'updatePasswords' | 'live') {
139
140 it('Should fail with a password protected privacy without providing a password', async function () {
141 await checkVideoPasswordOptions({
142 server,
143 token: server.accessToken,
144 videoPasswords: undefined,
145 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
146 mode
147 })
148 })
149
150 it('Should fail with a password protected privacy and an empty password list', async function () {
151 const videoPasswords = []
152
153 await checkVideoPasswordOptions({
154 server,
155 token: server.accessToken,
156 videoPasswords,
157 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
158 mode
159 })
160 })
161
162 it('Should fail with a password protected privacy and a too short password', async function () {
163 const videoPasswords = [ 'p' ]
164
165 await checkVideoPasswordOptions({
166 server,
167 token: server.accessToken,
168 videoPasswords,
169 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
170 mode
171 })
172 })
173
174 it('Should fail with a password protected privacy and a too long password', async function () {
175 const videoPasswords = [ 'Very very very very very very very very very very very very very very very very very very long password' ]
176
177 await checkVideoPasswordOptions({
178 server,
179 token: server.accessToken,
180 videoPasswords,
181 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
182 mode
183 })
184 })
185
186 it('Should fail with a password protected privacy and an empty password', async function () {
187 const videoPasswords = [ '' ]
188
189 await checkVideoPasswordOptions({
190 server,
191 token: server.accessToken,
192 videoPasswords,
193 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
194 mode
195 })
196 })
197
198 it('Should fail with a password protected privacy and duplicated passwords', async function () {
199 const videoPasswords = [ 'password', 'password' ]
200
201 await checkVideoPasswordOptions({
202 server,
203 token: server.accessToken,
204 videoPasswords,
205 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
206 mode
207 })
208 })
209
210 if (mode === 'updatePasswords') {
211 it('Should fail for an unauthenticated user', async function () {
212 const videoPasswords = [ 'password' ]
213 await checkVideoPasswordOptions({
214 server,
215 token: null,
216 videoPasswords,
217 expectedStatus: HttpStatusCode.UNAUTHORIZED_401,
218 mode
219 })
220 })
221
222 it('Should fail for an unauthorized user', async function () {
223 const videoPasswords = [ 'password' ]
224 await checkVideoPasswordOptions({
225 server,
226 token: userAccessToken,
227 videoPasswords,
228 expectedStatus: HttpStatusCode.FORBIDDEN_403,
229 mode
230 })
231 })
232 }
233
234 it('Should succeed with a password protected privacy and correct passwords', async function () {
235 const videoPasswords = [ 'password1', 'password2' ]
236 const expectedStatus = mode === 'updatePasswords' || mode === 'updateVideo'
237 ? HttpStatusCode.NO_CONTENT_204
238 : HttpStatusCode.OK_200
239
240 await checkVideoPasswordOptions({ server, token: server.accessToken, videoPasswords, expectedStatus, mode })
241 })
242 }
243
244 describe('When adding or updating a video', function () {
245 describe('Resumable upload', function () {
246 validateVideoPasswordList('uploadResumable')
247 })
248
249 describe('Legacy upload', function () {
250 validateVideoPasswordList('uploadLegacy')
251 })
252
253 describe('When importing a video', function () {
254 validateVideoPasswordList('import')
255 })
256
257 describe('When updating a video', function () {
258 validateVideoPasswordList('updateVideo')
259 })
260
261 describe('When updating the password list of a video', function () {
262 validateVideoPasswordList('updatePasswords')
263 })
264
265 describe('When creating a live', function () {
266 validateVideoPasswordList('live')
267 })
268 })
269
270 async function checkVideoAccessOptions (options: {
271 server: PeerTubeServer
272 token?: string
273 videoPassword?: string
274 expectedStatus: HttpStatusCode
275 mode: 'get' | 'getWithPassword' | 'getWithToken' | 'listCaptions' | 'createThread' | 'listThreads' | 'replyThread' | 'rate' | 'token'
276 }) {
277 const { server, token = null, videoPassword, expectedStatus, mode } = options
278
279 if (mode === 'get') {
280 return server.videos.get({ id: video.id, expectedStatus })
281 }
282
283 if (mode === 'getWithToken') {
284 return server.videos.getWithToken({
285 id: video.id,
286 token,
287 expectedStatus
288 })
289 }
290
291 if (mode === 'getWithPassword') {
292 return server.videos.getWithPassword({
293 id: video.id,
294 token,
295 expectedStatus,
296 password: videoPassword
297 })
298 }
299
300 if (mode === 'rate') {
301 return server.videos.rate({
302 id: video.id,
303 token,
304 expectedStatus,
305 rating: 'like',
306 videoPassword
307 })
308 }
309
310 if (mode === 'createThread') {
311 const fields = { text: 'super comment' }
312 const headers = videoPassword !== undefined && videoPassword !== null
313 ? { 'x-peertube-video-password': videoPassword }
314 : undefined
315 const body = await makePostBodyRequest({
316 url: server.url,
317 path: path + video.uuid + '/comment-threads',
318 token,
319 fields,
320 headers,
321 expectedStatus
322 })
323 return JSON.parse(body.text)
324 }
325
326 if (mode === 'replyThread') {
327 const fields = { text: 'super reply' }
328 const headers = videoPassword !== undefined && videoPassword !== null
329 ? { 'x-peertube-video-password': videoPassword }
330 : undefined
331 return makePostBodyRequest({
332 url: server.url,
333 path: path + video.uuid + '/comments/' + commentId,
334 token,
335 fields,
336 headers,
337 expectedStatus
338 })
339 }
340 if (mode === 'listThreads') {
341 return server.comments.listThreads({
342 videoId: video.id,
343 token,
344 expectedStatus,
345 videoPassword
346 })
347 }
348
349 if (mode === 'listCaptions') {
350 return server.captions.list({
351 videoId: video.id,
352 token,
353 expectedStatus,
354 videoPassword
355 })
356 }
357
358 if (mode === 'token') {
359 return server.videoToken.create({
360 videoId: video.id,
361 token,
362 expectedStatus,
363 videoPassword
364 })
365 }
366 }
367
368 function checkVideoError (error: any, mode: 'providePassword' | 'incorrectPassword') {
369 const serverCode = mode === 'providePassword'
370 ? ServerErrorCode.VIDEO_REQUIRES_PASSWORD
371 : ServerErrorCode.INCORRECT_VIDEO_PASSWORD
372
373 const message = mode === 'providePassword'
374 ? 'Please provide a password to access this password protected video'
375 : 'Incorrect video password. Access to the video is denied.'
376
377 if (!error.code) {
378 error = JSON.parse(error.text)
379 }
380
381 expect(error.code).to.equal(serverCode)
382 expect(error.detail).to.equal(message)
383 expect(error.error).to.equal(message)
384
385 expect(error.status).to.equal(HttpStatusCode.FORBIDDEN_403)
386 }
387
388 function validateVideoAccess (mode: 'get' | 'listCaptions' | 'createThread' | 'listThreads' | 'replyThread' | 'rate' | 'token') {
389 const requiresUserAuth = [ 'createThread', 'replyThread', 'rate' ].includes(mode)
390 let tokens: string[]
391 if (!requiresUserAuth) {
392 it('Should fail without providing a password for an unlogged user', async function () {
393 const body = await checkVideoAccessOptions({ server, expectedStatus: HttpStatusCode.FORBIDDEN_403, mode })
394 const error = body as unknown as PeerTubeProblemDocument
395
396 checkVideoError(error, 'providePassword')
397 })
398 }
399
400 it('Should fail without providing a password for an unauthorised user', async function () {
401 const tmp = mode === 'get' ? 'getWithToken' : mode
402
403 const body = await checkVideoAccessOptions({
404 server,
405 token: userAccessToken,
406 expectedStatus: HttpStatusCode.FORBIDDEN_403,
407 mode: tmp
408 })
409
410 const error = body as unknown as PeerTubeProblemDocument
411
412 checkVideoError(error, 'providePassword')
413 })
414
415 it('Should fail if a wrong password is entered', async function () {
416 const tmp = mode === 'get' ? 'getWithPassword' : mode
417 tokens = [ userAccessToken, server.accessToken ]
418
419 if (!requiresUserAuth) tokens.push(null)
420
421 for (const token of tokens) {
422 const body = await checkVideoAccessOptions({
423 server,
424 token,
425 videoPassword: 'toto',
426 expectedStatus: HttpStatusCode.FORBIDDEN_403,
427 mode: tmp
428 })
429 const error = body as unknown as PeerTubeProblemDocument
430
431 checkVideoError(error, 'incorrectPassword')
432 }
433 })
434
435 it('Should fail if an empty password is entered', async function () {
436 const tmp = mode === 'get' ? 'getWithPassword' : mode
437
438 for (const token of tokens) {
439 const body = await checkVideoAccessOptions({
440 server,
441 token,
442 videoPassword: '',
443 expectedStatus: HttpStatusCode.FORBIDDEN_403,
444 mode: tmp
445 })
446 const error = body as unknown as PeerTubeProblemDocument
447
448 checkVideoError(error, 'incorrectPassword')
449 }
450 })
451
452 it('Should fail if an inccorect password containing the correct password is entered', async function () {
453 const tmp = mode === 'get' ? 'getWithPassword' : mode
454
455 for (const token of tokens) {
456 const body = await checkVideoAccessOptions({
457 server,
458 token,
459 videoPassword: 'password11',
460 expectedStatus: HttpStatusCode.FORBIDDEN_403,
461 mode: tmp
462 })
463 const error = body as unknown as PeerTubeProblemDocument
464
465 checkVideoError(error, 'incorrectPassword')
466 }
467 })
468
469 it('Should succeed without providing a password for an authorised user', async function () {
470 const tmp = mode === 'get' ? 'getWithToken' : mode
471 const expectedStatus = mode === 'rate' ? HttpStatusCode.NO_CONTENT_204 : HttpStatusCode.OK_200
472
473 const body = await checkVideoAccessOptions({ server, token: server.accessToken, expectedStatus, mode: tmp })
474
475 if (mode === 'createThread') commentId = body.comment.id
476 })
477
478 it('Should succeed using correct passwords', async function () {
479 const tmp = mode === 'get' ? 'getWithPassword' : mode
480 const expectedStatus = mode === 'rate' ? HttpStatusCode.NO_CONTENT_204 : HttpStatusCode.OK_200
481
482 for (const token of tokens) {
483 await checkVideoAccessOptions({ server, videoPassword: 'password1', token, expectedStatus, mode: tmp })
484 await checkVideoAccessOptions({ server, videoPassword: 'password2', token, expectedStatus, mode: tmp })
485 }
486 })
487 }
488
489 describe('When accessing password protected video', function () {
490
491 describe('For getting a password protected video', function () {
492 validateVideoAccess('get')
493 })
494
495 describe('For rating a video', function () {
496 validateVideoAccess('rate')
497 })
498
499 describe('For creating a thread', function () {
500 validateVideoAccess('createThread')
501 })
502
503 describe('For replying to a thread', function () {
504 validateVideoAccess('replyThread')
505 })
506
507 describe('For listing threads', function () {
508 validateVideoAccess('listThreads')
509 })
510
511 describe('For getting captions', function () {
512 validateVideoAccess('listCaptions')
513 })
514
515 describe('For creating video file token', function () {
516 validateVideoAccess('token')
517 })
518 })
519
520 describe('When listing passwords', function () {
521 it('Should fail with a bad start pagination', async function () {
522 await checkBadStartPagination(server.url, path + video.uuid + '/passwords', server.accessToken)
523 })
524
525 it('Should fail with a bad count pagination', async function () {
526 await checkBadCountPagination(server.url, path + video.uuid + '/passwords', server.accessToken)
527 })
528
529 it('Should fail with an incorrect sort', async function () {
530 await checkBadSortPagination(server.url, path + video.uuid + '/passwords', server.accessToken)
531 })
532
533 it('Should fail for unauthenticated user', async function () {
534 await server.videoPasswords.list({
535 token: null,
536 expectedStatus: HttpStatusCode.UNAUTHORIZED_401,
537 videoId: video.id
538 })
539 })
540
541 it('Should fail for unauthorized user', async function () {
542 await server.videoPasswords.list({
543 token: userAccessToken,
544 expectedStatus: HttpStatusCode.FORBIDDEN_403,
545 videoId: video.id
546 })
547 })
548
549 it('Should succeed with the correct parameters', async function () {
550 await server.videoPasswords.list({
551 token: server.accessToken,
552 expectedStatus: HttpStatusCode.OK_200,
553 videoId: video.id
554 })
555 })
556 })
557
558 describe('When deleting a password', async function () {
559 const passwords = (await server.videoPasswords.list({ videoId: video.id })).data
560
561 it('Should fail with wrong password id', async function () {
562 await server.videoPasswords.remove({ id: -1, videoId: video.id, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
563 })
564
565 it('Should fail for unauthenticated user', async function () {
566 await server.videoPasswords.remove({
567 id: passwords[0].id,
568 token: null,
569 videoId: video.id,
570 expectedStatus: HttpStatusCode.FORBIDDEN_403
571 })
572 })
573
574 it('Should fail for unauthorized user', async function () {
575 await server.videoPasswords.remove({
576 id: passwords[0].id,
577 token: userAccessToken,
578 videoId: video.id,
579 expectedStatus: HttpStatusCode.BAD_REQUEST_400
580 })
581 })
582
583 it('Should fail for non password protected video', async function () {
584 publicVideo = await server.videos.quickUpload({ name: 'public video' })
585 await server.videoPasswords.remove({ id: passwords[0].id, videoId: publicVideo.id, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
586 })
587
588 it('Should fail for password not linked to correct video', async function () {
589 const video2 = await server.videos.quickUpload({
590 name: 'password protected video',
591 privacy: VideoPrivacy.PASSWORD_PROTECTED,
592 videoPasswords: [ 'password1', 'password2' ]
593 })
594 await server.videoPasswords.remove({ id: passwords[0].id, videoId: video2.id, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
595 })
596
597 it('Should succeed with correct parameter', async function () {
598 await server.videoPasswords.remove({ id: passwords[0].id, videoId: video.id, expectedStatus: HttpStatusCode.NO_CONTENT_204 })
599 })
600
601 it('Should fail for last password of a video', async function () {
602 await server.videoPasswords.remove({ id: passwords[1].id, videoId: video.id, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
603 })
604 })
605
606 after(async function () {
607 await cleanupTests([ server ])
608 })
609})
diff --git a/server/tests/api/check-params/video-playlists.ts b/server/tests/api/check-params/video-playlists.ts
deleted file mode 100644
index 8c3233e0b..000000000
--- a/server/tests/api/check-params/video-playlists.ts
+++ /dev/null
@@ -1,695 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared'
4import {
5 HttpStatusCode,
6 VideoPlaylistCreate,
7 VideoPlaylistCreateResult,
8 VideoPlaylistElementCreate,
9 VideoPlaylistElementUpdate,
10 VideoPlaylistPrivacy,
11 VideoPlaylistReorder,
12 VideoPlaylistType
13} from '@shared/models'
14import {
15 cleanupTests,
16 createSingleServer,
17 makeGetRequest,
18 PeerTubeServer,
19 PlaylistsCommand,
20 setAccessTokensToServers,
21 setDefaultVideoChannel
22} from '@shared/server-commands'
23
24describe('Test video playlists API validator', function () {
25 let server: PeerTubeServer
26 let userAccessToken: string
27
28 let playlist: VideoPlaylistCreateResult
29 let privatePlaylistUUID: string
30
31 let watchLaterPlaylistId: number
32 let videoId: number
33 let elementId: number
34
35 let command: PlaylistsCommand
36
37 // ---------------------------------------------------------------
38
39 before(async function () {
40 this.timeout(30000)
41
42 server = await createSingleServer(1)
43
44 await setAccessTokensToServers([ server ])
45 await setDefaultVideoChannel([ server ])
46
47 userAccessToken = await server.users.generateUserAndToken('user1')
48 videoId = (await server.videos.quickUpload({ name: 'video 1' })).id
49
50 command = server.playlists
51
52 {
53 const { data } = await command.listByAccount({
54 token: server.accessToken,
55 handle: 'root',
56 start: 0,
57 count: 5,
58 playlistType: VideoPlaylistType.WATCH_LATER
59 })
60 watchLaterPlaylistId = data[0].id
61 }
62
63 {
64 playlist = await command.create({
65 attributes: {
66 displayName: 'super playlist',
67 privacy: VideoPlaylistPrivacy.PUBLIC,
68 videoChannelId: server.store.channel.id
69 }
70 })
71 }
72
73 {
74 const created = await command.create({
75 attributes: {
76 displayName: 'private',
77 privacy: VideoPlaylistPrivacy.PRIVATE
78 }
79 })
80 privatePlaylistUUID = created.uuid
81 }
82 })
83
84 describe('When listing playlists', function () {
85 const globalPath = '/api/v1/video-playlists'
86 const accountPath = '/api/v1/accounts/root/video-playlists'
87 const videoChannelPath = '/api/v1/video-channels/root_channel/video-playlists'
88
89 it('Should fail with a bad start pagination', async function () {
90 await checkBadStartPagination(server.url, globalPath, server.accessToken)
91 await checkBadStartPagination(server.url, accountPath, server.accessToken)
92 await checkBadStartPagination(server.url, videoChannelPath, server.accessToken)
93 })
94
95 it('Should fail with a bad count pagination', async function () {
96 await checkBadCountPagination(server.url, globalPath, server.accessToken)
97 await checkBadCountPagination(server.url, accountPath, server.accessToken)
98 await checkBadCountPagination(server.url, videoChannelPath, server.accessToken)
99 })
100
101 it('Should fail with an incorrect sort', async function () {
102 await checkBadSortPagination(server.url, globalPath, server.accessToken)
103 await checkBadSortPagination(server.url, accountPath, server.accessToken)
104 await checkBadSortPagination(server.url, videoChannelPath, server.accessToken)
105 })
106
107 it('Should fail with a bad playlist type', async function () {
108 await makeGetRequest({ url: server.url, path: globalPath, query: { playlistType: 3 } })
109 await makeGetRequest({ url: server.url, path: accountPath, query: { playlistType: 3 } })
110 await makeGetRequest({ url: server.url, path: videoChannelPath, query: { playlistType: 3 } })
111 })
112
113 it('Should fail with a bad account parameter', async function () {
114 const accountPath = '/api/v1/accounts/root2/video-playlists'
115
116 await makeGetRequest({
117 url: server.url,
118 path: accountPath,
119 expectedStatus: HttpStatusCode.NOT_FOUND_404,
120 token: server.accessToken
121 })
122 })
123
124 it('Should fail with a bad video channel parameter', async function () {
125 const accountPath = '/api/v1/video-channels/bad_channel/video-playlists'
126
127 await makeGetRequest({
128 url: server.url,
129 path: accountPath,
130 expectedStatus: HttpStatusCode.NOT_FOUND_404,
131 token: server.accessToken
132 })
133 })
134
135 it('Should success with the correct parameters', async function () {
136 await makeGetRequest({ url: server.url, path: globalPath, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken })
137 await makeGetRequest({ url: server.url, path: accountPath, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken })
138 await makeGetRequest({
139 url: server.url,
140 path: videoChannelPath,
141 expectedStatus: HttpStatusCode.OK_200,
142 token: server.accessToken
143 })
144 })
145 })
146
147 describe('When listing videos of a playlist', function () {
148 const path = '/api/v1/video-playlists/'
149
150 it('Should fail with a bad start pagination', async function () {
151 await checkBadStartPagination(server.url, path + playlist.shortUUID + '/videos', server.accessToken)
152 })
153
154 it('Should fail with a bad count pagination', async function () {
155 await checkBadCountPagination(server.url, path + playlist.shortUUID + '/videos', server.accessToken)
156 })
157
158 it('Should success with the correct parameters', async function () {
159 await makeGetRequest({ url: server.url, path: path + playlist.shortUUID + '/videos', expectedStatus: HttpStatusCode.OK_200 })
160 })
161 })
162
163 describe('When getting a video playlist', function () {
164 it('Should fail with a bad id or uuid', async function () {
165 await command.get({ playlistId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
166 })
167
168 it('Should fail with an unknown playlist', async function () {
169 await command.get({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
170 })
171
172 it('Should fail to get an unlisted playlist with the number id', async function () {
173 const playlist = await command.create({
174 attributes: {
175 displayName: 'super playlist',
176 videoChannelId: server.store.channel.id,
177 privacy: VideoPlaylistPrivacy.UNLISTED
178 }
179 })
180
181 await command.get({ playlistId: playlist.id, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
182 await command.get({ playlistId: playlist.uuid, expectedStatus: HttpStatusCode.OK_200 })
183 })
184
185 it('Should succeed with the correct params', async function () {
186 await command.get({ playlistId: playlist.uuid, expectedStatus: HttpStatusCode.OK_200 })
187 })
188 })
189
190 describe('When creating/updating a video playlist', function () {
191 const getBase = (
192 attributes?: Partial<VideoPlaylistCreate>,
193 wrapper?: Partial<Parameters<PlaylistsCommand['create']>[0]>
194 ) => {
195 return {
196 attributes: {
197 displayName: 'display name',
198 privacy: VideoPlaylistPrivacy.UNLISTED,
199 thumbnailfile: 'custom-thumbnail.jpg',
200 videoChannelId: server.store.channel.id,
201
202 ...attributes
203 },
204
205 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
206
207 ...wrapper
208 }
209 }
210 const getUpdate = (params: any, playlistId: number | string) => {
211 return { ...params, playlistId }
212 }
213
214 it('Should fail with an unauthenticated user', async function () {
215 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
216
217 await command.create(params)
218 await command.update(getUpdate(params, playlist.shortUUID))
219 })
220
221 it('Should fail without displayName', async function () {
222 const params = getBase({ displayName: undefined })
223
224 await command.create(params)
225 })
226
227 it('Should fail with an incorrect display name', async function () {
228 const params = getBase({ displayName: 's'.repeat(300) })
229
230 await command.create(params)
231 await command.update(getUpdate(params, playlist.shortUUID))
232 })
233
234 it('Should fail with an incorrect description', async function () {
235 const params = getBase({ description: 't' })
236
237 await command.create(params)
238 await command.update(getUpdate(params, playlist.shortUUID))
239 })
240
241 it('Should fail with an incorrect privacy', async function () {
242 const params = getBase({ privacy: 45 as any })
243
244 await command.create(params)
245 await command.update(getUpdate(params, playlist.shortUUID))
246 })
247
248 it('Should fail with an unknown video channel id', async function () {
249 const params = getBase({ videoChannelId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 })
250
251 await command.create(params)
252 await command.update(getUpdate(params, playlist.shortUUID))
253 })
254
255 it('Should fail with an incorrect thumbnail file', async function () {
256 const params = getBase({ thumbnailfile: 'video_short.mp4' })
257
258 await command.create(params)
259 await command.update(getUpdate(params, playlist.shortUUID))
260 })
261
262 it('Should fail with a thumbnail file too big', async function () {
263 const params = getBase({ thumbnailfile: 'custom-preview-big.png' })
264
265 await command.create(params)
266 await command.update(getUpdate(params, playlist.shortUUID))
267 })
268
269 it('Should fail to set "public" a playlist not assigned to a channel', async function () {
270 const params = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: undefined })
271 const params2 = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: 'null' as any })
272 const params3 = getBase({ privacy: undefined, videoChannelId: 'null' as any })
273
274 await command.create(params)
275 await command.create(params2)
276 await command.update(getUpdate(params, privatePlaylistUUID))
277 await command.update(getUpdate(params2, playlist.shortUUID))
278 await command.update(getUpdate(params3, playlist.shortUUID))
279 })
280
281 it('Should fail with an unknown playlist to update', async function () {
282 await command.update(getUpdate(
283 getBase({}, { expectedStatus: HttpStatusCode.NOT_FOUND_404 }),
284 42
285 ))
286 })
287
288 it('Should fail to update a playlist of another user', async function () {
289 await command.update(getUpdate(
290 getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }),
291 playlist.shortUUID
292 ))
293 })
294
295 it('Should fail to update the watch later playlist', async function () {
296 await command.update(getUpdate(
297 getBase({}, { expectedStatus: HttpStatusCode.BAD_REQUEST_400 }),
298 watchLaterPlaylistId
299 ))
300 })
301
302 it('Should succeed with the correct params', async function () {
303 {
304 const params = getBase({}, { expectedStatus: HttpStatusCode.OK_200 })
305 await command.create(params)
306 }
307
308 {
309 const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
310 await command.update(getUpdate(params, playlist.shortUUID))
311 }
312 })
313 })
314
315 describe('When adding an element in a playlist', function () {
316 const getBase = (
317 attributes?: Partial<VideoPlaylistElementCreate>,
318 wrapper?: Partial<Parameters<PlaylistsCommand['addElement']>[0]>
319 ) => {
320 return {
321 attributes: {
322 videoId,
323 startTimestamp: 2,
324 stopTimestamp: 3,
325
326 ...attributes
327 },
328
329 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
330 playlistId: playlist.id,
331
332 ...wrapper
333 }
334 }
335
336 it('Should fail with an unauthenticated user', async function () {
337 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
338 await command.addElement(params)
339 })
340
341 it('Should fail with the playlist of another user', async function () {
342 const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
343 await command.addElement(params)
344 })
345
346 it('Should fail with an unknown or incorrect playlist id', async function () {
347 {
348 const params = getBase({}, { playlistId: 'toto' })
349 await command.addElement(params)
350 }
351
352 {
353 const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
354 await command.addElement(params)
355 }
356 })
357
358 it('Should fail with an unknown or incorrect video id', async function () {
359 const params = getBase({ videoId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 })
360 await command.addElement(params)
361 })
362
363 it('Should fail with a bad start/stop timestamp', async function () {
364 {
365 const params = getBase({ startTimestamp: -42 })
366 await command.addElement(params)
367 }
368
369 {
370 const params = getBase({ stopTimestamp: 'toto' as any })
371 await command.addElement(params)
372 }
373 })
374
375 it('Succeed with the correct params', async function () {
376 const params = getBase({}, { expectedStatus: HttpStatusCode.OK_200 })
377 const created = await command.addElement(params)
378 elementId = created.id
379 })
380 })
381
382 describe('When updating an element in a playlist', function () {
383 const getBase = (
384 attributes?: Partial<VideoPlaylistElementUpdate>,
385 wrapper?: Partial<Parameters<PlaylistsCommand['updateElement']>[0]>
386 ) => {
387 return {
388 attributes: {
389 startTimestamp: 1,
390 stopTimestamp: 2,
391
392 ...attributes
393 },
394
395 elementId,
396 playlistId: playlist.id,
397 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
398
399 ...wrapper
400 }
401 }
402
403 it('Should fail with an unauthenticated user', async function () {
404 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
405 await command.updateElement(params)
406 })
407
408 it('Should fail with the playlist of another user', async function () {
409 const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
410 await command.updateElement(params)
411 })
412
413 it('Should fail with an unknown or incorrect playlist id', async function () {
414 {
415 const params = getBase({}, { playlistId: 'toto' })
416 await command.updateElement(params)
417 }
418
419 {
420 const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
421 await command.updateElement(params)
422 }
423 })
424
425 it('Should fail with an unknown or incorrect playlistElement id', async function () {
426 {
427 const params = getBase({}, { elementId: 'toto' })
428 await command.updateElement(params)
429 }
430
431 {
432 const params = getBase({}, { elementId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
433 await command.updateElement(params)
434 }
435 })
436
437 it('Should fail with a bad start/stop timestamp', async function () {
438 {
439 const params = getBase({ startTimestamp: 'toto' as any })
440 await command.updateElement(params)
441 }
442
443 {
444 const params = getBase({ stopTimestamp: -42 })
445 await command.updateElement(params)
446 }
447 })
448
449 it('Should fail with an unknown element', async function () {
450 const params = getBase({}, { elementId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
451 await command.updateElement(params)
452 })
453
454 it('Succeed with the correct params', async function () {
455 const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
456 await command.updateElement(params)
457 })
458 })
459
460 describe('When reordering elements of a playlist', function () {
461 let videoId3: number
462 let videoId4: number
463
464 const getBase = (
465 attributes?: Partial<VideoPlaylistReorder>,
466 wrapper?: Partial<Parameters<PlaylistsCommand['reorderElements']>[0]>
467 ) => {
468 return {
469 attributes: {
470 startPosition: 1,
471 insertAfterPosition: 2,
472 reorderLength: 3,
473
474 ...attributes
475 },
476
477 playlistId: playlist.shortUUID,
478 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
479
480 ...wrapper
481 }
482 }
483
484 before(async function () {
485 videoId3 = (await server.videos.quickUpload({ name: 'video 3' })).id
486 videoId4 = (await server.videos.quickUpload({ name: 'video 4' })).id
487
488 for (const id of [ videoId3, videoId4 ]) {
489 await command.addElement({ playlistId: playlist.shortUUID, attributes: { videoId: id } })
490 }
491 })
492
493 it('Should fail with an unauthenticated user', async function () {
494 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
495 await command.reorderElements(params)
496 })
497
498 it('Should fail with the playlist of another user', async function () {
499 const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
500 await command.reorderElements(params)
501 })
502
503 it('Should fail with an invalid playlist', async function () {
504 {
505 const params = getBase({}, { playlistId: 'toto' })
506 await command.reorderElements(params)
507 }
508
509 {
510 const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
511 await command.reorderElements(params)
512 }
513 })
514
515 it('Should fail with an invalid start position', async function () {
516 {
517 const params = getBase({ startPosition: -1 })
518 await command.reorderElements(params)
519 }
520
521 {
522 const params = getBase({ startPosition: 'toto' as any })
523 await command.reorderElements(params)
524 }
525
526 {
527 const params = getBase({ startPosition: 42 })
528 await command.reorderElements(params)
529 }
530 })
531
532 it('Should fail with an invalid insert after position', async function () {
533 {
534 const params = getBase({ insertAfterPosition: 'toto' as any })
535 await command.reorderElements(params)
536 }
537
538 {
539 const params = getBase({ insertAfterPosition: -2 })
540 await command.reorderElements(params)
541 }
542
543 {
544 const params = getBase({ insertAfterPosition: 42 })
545 await command.reorderElements(params)
546 }
547 })
548
549 it('Should fail with an invalid reorder length', async function () {
550 {
551 const params = getBase({ reorderLength: 'toto' as any })
552 await command.reorderElements(params)
553 }
554
555 {
556 const params = getBase({ reorderLength: -2 })
557 await command.reorderElements(params)
558 }
559
560 {
561 const params = getBase({ reorderLength: 42 })
562 await command.reorderElements(params)
563 }
564 })
565
566 it('Succeed with the correct params', async function () {
567 const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
568 await command.reorderElements(params)
569 })
570 })
571
572 describe('When checking exists in playlist endpoint', function () {
573 const path = '/api/v1/users/me/video-playlists/videos-exist'
574
575 it('Should fail with an unauthenticated user', async function () {
576 await makeGetRequest({
577 url: server.url,
578 path,
579 query: { videoIds: [ 1, 2 ] },
580 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
581 })
582 })
583
584 it('Should fail with invalid video ids', async function () {
585 await makeGetRequest({
586 url: server.url,
587 token: server.accessToken,
588 path,
589 query: { videoIds: 'toto' }
590 })
591
592 await makeGetRequest({
593 url: server.url,
594 token: server.accessToken,
595 path,
596 query: { videoIds: [ 'toto' ] }
597 })
598
599 await makeGetRequest({
600 url: server.url,
601 token: server.accessToken,
602 path,
603 query: { videoIds: [ 1, 'toto' ] }
604 })
605 })
606
607 it('Should succeed with the correct params', async function () {
608 await makeGetRequest({
609 url: server.url,
610 token: server.accessToken,
611 path,
612 query: { videoIds: [ 1, 2 ] },
613 expectedStatus: HttpStatusCode.OK_200
614 })
615 })
616 })
617
618 describe('When deleting an element in a playlist', function () {
619 const getBase = (wrapper: Partial<Parameters<PlaylistsCommand['removeElement']>[0]>) => {
620 return {
621 elementId,
622 playlistId: playlist.uuid,
623 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
624
625 ...wrapper
626 }
627 }
628
629 it('Should fail with an unauthenticated user', async function () {
630 const params = getBase({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
631 await command.removeElement(params)
632 })
633
634 it('Should fail with the playlist of another user', async function () {
635 const params = getBase({ token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
636 await command.removeElement(params)
637 })
638
639 it('Should fail with an unknown or incorrect playlist id', async function () {
640 {
641 const params = getBase({ playlistId: 'toto' })
642 await command.removeElement(params)
643 }
644
645 {
646 const params = getBase({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
647 await command.removeElement(params)
648 }
649 })
650
651 it('Should fail with an unknown or incorrect video id', async function () {
652 {
653 const params = getBase({ elementId: 'toto' as any })
654 await command.removeElement(params)
655 }
656
657 {
658 const params = getBase({ elementId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
659 await command.removeElement(params)
660 }
661 })
662
663 it('Should fail with an unknown element', async function () {
664 const params = getBase({ elementId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
665 await command.removeElement(params)
666 })
667
668 it('Succeed with the correct params', async function () {
669 const params = getBase({ expectedStatus: HttpStatusCode.NO_CONTENT_204 })
670 await command.removeElement(params)
671 })
672 })
673
674 describe('When deleting a playlist', function () {
675 it('Should fail with an unknown playlist', async function () {
676 await command.delete({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
677 })
678
679 it('Should fail with a playlist of another user', async function () {
680 await command.delete({ token: userAccessToken, playlistId: playlist.uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
681 })
682
683 it('Should fail with the watch later playlist', async function () {
684 await command.delete({ playlistId: watchLaterPlaylistId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
685 })
686
687 it('Should succeed with the correct params', async function () {
688 await command.delete({ playlistId: playlist.uuid })
689 })
690 })
691
692 after(async function () {
693 await cleanupTests([ server ])
694 })
695})
diff --git a/server/tests/api/check-params/video-source.ts b/server/tests/api/check-params/video-source.ts
deleted file mode 100644
index 767590d5e..000000000
--- a/server/tests/api/check-params/video-source.ts
+++ /dev/null
@@ -1,154 +0,0 @@
1import { HttpStatusCode } from '@shared/models'
2import {
3 cleanupTests,
4 createSingleServer,
5 PeerTubeServer,
6 setAccessTokensToServers,
7 setDefaultVideoChannel,
8 waitJobs
9} from '@shared/server-commands'
10
11describe('Test video sources API validator', function () {
12 let server: PeerTubeServer = null
13 let uuid: string
14 let userToken: string
15
16 before(async function () {
17 this.timeout(120000)
18
19 server = await createSingleServer(1)
20 await setAccessTokensToServers([ server ])
21 await setDefaultVideoChannel([ server ])
22
23 userToken = await server.users.generateUserAndToken('user1')
24 })
25
26 describe('When getting latest source', function () {
27
28 before(async function () {
29 const created = await server.videos.quickUpload({ name: 'video' })
30 uuid = created.uuid
31 })
32
33 it('Should fail without a valid uuid', async function () {
34 await server.videos.getSource({ id: '4da6fde3-88f7-4d16-b119-108df563d0b0', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
35 })
36
37 it('Should receive 404 when passing a non existing video id', async function () {
38 await server.videos.getSource({ id: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
39 })
40
41 it('Should not get the source as unauthenticated', async function () {
42 await server.videos.getSource({ id: uuid, expectedStatus: HttpStatusCode.UNAUTHORIZED_401, token: null })
43 })
44
45 it('Should not get the source with another user', async function () {
46 await server.videos.getSource({ id: uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403, token: userToken })
47 })
48
49 it('Should succeed with the correct parameters get the source as another user', async function () {
50 await server.videos.getSource({ id: uuid })
51 })
52 })
53
54 describe('When updating source video file', function () {
55 let userAccessToken: string
56 let userId: number
57
58 let videoId: string
59 let userVideoId: string
60
61 before(async function () {
62 const res = await server.users.generate('user2')
63 userAccessToken = res.token
64 userId = res.userId
65
66 const { uuid } = await server.videos.quickUpload({ name: 'video' })
67 videoId = uuid
68
69 await waitJobs([ server ])
70 })
71
72 it('Should fail if not enabled on the instance', async function () {
73 await server.config.disableFileUpdate()
74
75 await server.videos.replaceSourceFile({ videoId, fixture: 'video_short.mp4', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
76 })
77
78 it('Should fail on an unknown video', async function () {
79 await server.config.enableFileUpdate()
80
81 await server.videos.replaceSourceFile({ videoId: 404, fixture: 'video_short.mp4', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
82 })
83
84 it('Should fail with an invalid video', async function () {
85 await server.config.enableLive({ allowReplay: false })
86
87 const { video } = await server.live.quickCreate({ saveReplay: false, permanentLive: true })
88 await server.videos.replaceSourceFile({
89 videoId: video.uuid,
90 fixture: 'video_short.mp4',
91 expectedStatus: HttpStatusCode.BAD_REQUEST_400
92 })
93 })
94
95 it('Should fail without token', async function () {
96 await server.videos.replaceSourceFile({
97 token: null,
98 videoId,
99 fixture: 'video_short.mp4',
100 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
101 })
102 })
103
104 it('Should fail with another user', async function () {
105 await server.videos.replaceSourceFile({
106 token: userAccessToken,
107 videoId,
108 fixture: 'video_short.mp4',
109 expectedStatus: HttpStatusCode.FORBIDDEN_403
110 })
111 })
112
113 it('Should fail with an incorrect input file', async function () {
114 await server.videos.replaceSourceFile({
115 fixture: 'video_short_fake.webm',
116 videoId,
117 completedExpectedStatus: HttpStatusCode.UNPROCESSABLE_ENTITY_422
118 })
119
120 await server.videos.replaceSourceFile({
121 fixture: 'video_short.mkv',
122 videoId,
123 expectedStatus: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415
124 })
125 })
126
127 it('Should fail if quota is exceeded', async function () {
128 this.timeout(60000)
129
130 const { uuid } = await server.videos.quickUpload({ name: 'user video' })
131 userVideoId = uuid
132 await waitJobs([ server ])
133
134 await server.users.update({ userId, videoQuota: 1 })
135 await server.videos.replaceSourceFile({
136 token: userAccessToken,
137 videoId: uuid,
138 fixture: 'video_short.mp4',
139 expectedStatus: HttpStatusCode.FORBIDDEN_403
140 })
141 })
142
143 it('Should succeed with the correct params', async function () {
144 this.timeout(60000)
145
146 await server.users.update({ userId, videoQuota: 1000 * 1000 * 1000 })
147 await server.videos.replaceSourceFile({ videoId: userVideoId, fixture: 'video_short.mp4' })
148 })
149 })
150
151 after(async function () {
152 await cleanupTests([ server ])
153 })
154})
diff --git a/server/tests/api/check-params/video-storyboards.ts b/server/tests/api/check-params/video-storyboards.ts
deleted file mode 100644
index c038e7370..000000000
--- a/server/tests/api/check-params/video-storyboards.ts
+++ /dev/null
@@ -1,45 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { HttpStatusCode, VideoPrivacy } from '@shared/models'
4import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
5
6describe('Test video storyboards API validator', function () {
7 let server: PeerTubeServer
8
9 let publicVideo: { uuid: string }
10 let privateVideo: { uuid: string }
11
12 // ---------------------------------------------------------------
13
14 before(async function () {
15 this.timeout(120000)
16
17 server = await createSingleServer(1)
18 await setAccessTokensToServers([ server ])
19
20 publicVideo = await server.videos.quickUpload({ name: 'public' })
21 privateVideo = await server.videos.quickUpload({ name: 'private', privacy: VideoPrivacy.PRIVATE })
22 })
23
24 it('Should fail without a valid uuid', async function () {
25 await server.storyboard.list({ id: '4da6fde3-88f7-4d16-b119-108df563d0b0', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
26 })
27
28 it('Should receive 404 when passing a non existing video id', async function () {
29 await server.storyboard.list({ id: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
30 })
31
32 it('Should not get the private storyboard without the appropriate token', async function () {
33 await server.storyboard.list({ id: privateVideo.uuid, expectedStatus: HttpStatusCode.UNAUTHORIZED_401, token: null })
34 await server.storyboard.list({ id: publicVideo.uuid, expectedStatus: HttpStatusCode.OK_200, token: null })
35 })
36
37 it('Should succeed with the correct parameters', async function () {
38 await server.storyboard.list({ id: privateVideo.uuid })
39 await server.storyboard.list({ id: publicVideo.uuid })
40 })
41
42 after(async function () {
43 await cleanupTests([ server ])
44 })
45})
diff --git a/server/tests/api/check-params/video-studio.ts b/server/tests/api/check-params/video-studio.ts
deleted file mode 100644
index 4ac0d93ed..000000000
--- a/server/tests/api/check-params/video-studio.ts
+++ /dev/null
@@ -1,388 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { HttpStatusCode, VideoStudioTask } from '@shared/models'
4import {
5 cleanupTests,
6 createSingleServer,
7 PeerTubeServer,
8 setAccessTokensToServers,
9 VideoStudioCommand,
10 waitJobs
11} from '@shared/server-commands'
12
13describe('Test video studio API validator', function () {
14 let server: PeerTubeServer
15 let command: VideoStudioCommand
16 let userAccessToken: string
17 let videoUUID: string
18
19 // ---------------------------------------------------------------
20
21 before(async function () {
22 this.timeout(120_000)
23
24 server = await createSingleServer(1)
25
26 await setAccessTokensToServers([ server ])
27 userAccessToken = await server.users.generateUserAndToken('user1')
28
29 await server.config.enableMinimumTranscoding()
30
31 const { uuid } = await server.videos.quickUpload({ name: 'video' })
32 videoUUID = uuid
33
34 command = server.videoStudio
35
36 await waitJobs([ server ])
37 })
38
39 describe('Task creation', function () {
40
41 describe('Config settings', function () {
42
43 it('Should fail if studio is disabled', async function () {
44 await server.config.updateExistingSubConfig({
45 newConfig: {
46 videoStudio: {
47 enabled: false
48 }
49 }
50 })
51
52 await command.createEditionTasks({
53 videoId: videoUUID,
54 tasks: VideoStudioCommand.getComplexTask(),
55 expectedStatus: HttpStatusCode.BAD_REQUEST_400
56 })
57 })
58
59 it('Should fail to enable studio if transcoding is disabled', async function () {
60 await server.config.updateExistingSubConfig({
61 newConfig: {
62 videoStudio: {
63 enabled: true
64 },
65 transcoding: {
66 enabled: false
67 }
68 },
69 expectedStatus: HttpStatusCode.BAD_REQUEST_400
70 })
71 })
72
73 it('Should succeed to enable video studio', async function () {
74 await server.config.updateExistingSubConfig({
75 newConfig: {
76 videoStudio: {
77 enabled: true
78 },
79 transcoding: {
80 enabled: true
81 }
82 }
83 })
84 })
85 })
86
87 describe('Common tasks', function () {
88
89 it('Should fail without token', async function () {
90 await command.createEditionTasks({
91 token: null,
92 videoId: videoUUID,
93 tasks: VideoStudioCommand.getComplexTask(),
94 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
95 })
96 })
97
98 it('Should fail with another user token', async function () {
99 await command.createEditionTasks({
100 token: userAccessToken,
101 videoId: videoUUID,
102 tasks: VideoStudioCommand.getComplexTask(),
103 expectedStatus: HttpStatusCode.FORBIDDEN_403
104 })
105 })
106
107 it('Should fail with an invalid video', async function () {
108 await command.createEditionTasks({
109 videoId: 'tintin',
110 tasks: VideoStudioCommand.getComplexTask(),
111 expectedStatus: HttpStatusCode.BAD_REQUEST_400
112 })
113 })
114
115 it('Should fail with an unknown video', async function () {
116 await command.createEditionTasks({
117 videoId: 42,
118 tasks: VideoStudioCommand.getComplexTask(),
119 expectedStatus: HttpStatusCode.NOT_FOUND_404
120 })
121 })
122
123 it('Should fail with an already in transcoding state video', async function () {
124 this.timeout(60000)
125
126 const { uuid } = await server.videos.quickUpload({ name: 'transcoded video' })
127 await waitJobs([ server ])
128
129 await server.jobs.pauseJobQueue()
130 await server.videos.runTranscoding({ videoId: uuid, transcodingType: 'hls' })
131
132 await command.createEditionTasks({
133 videoId: uuid,
134 tasks: VideoStudioCommand.getComplexTask(),
135 expectedStatus: HttpStatusCode.CONFLICT_409
136 })
137
138 await server.jobs.resumeJobQueue()
139 })
140
141 it('Should fail with a bad complex task', async function () {
142 await command.createEditionTasks({
143 videoId: videoUUID,
144 tasks: [
145 {
146 name: 'cut',
147 options: {
148 start: 1,
149 end: 2
150 }
151 },
152 {
153 name: 'hadock',
154 options: {
155 start: 1,
156 end: 2
157 }
158 }
159 ] as any,
160 expectedStatus: HttpStatusCode.BAD_REQUEST_400
161 })
162 })
163
164 it('Should fail without task', async function () {
165 await command.createEditionTasks({
166 videoId: videoUUID,
167 tasks: [],
168 expectedStatus: HttpStatusCode.BAD_REQUEST_400
169 })
170 })
171
172 it('Should fail with too many tasks', async function () {
173 const tasks: VideoStudioTask[] = []
174
175 for (let i = 0; i < 110; i++) {
176 tasks.push({
177 name: 'cut',
178 options: {
179 start: 1
180 }
181 })
182 }
183
184 await command.createEditionTasks({
185 videoId: videoUUID,
186 tasks,
187 expectedStatus: HttpStatusCode.BAD_REQUEST_400
188 })
189 })
190
191 it('Should succeed with correct parameters', async function () {
192 await server.jobs.pauseJobQueue()
193
194 await command.createEditionTasks({
195 videoId: videoUUID,
196 tasks: VideoStudioCommand.getComplexTask(),
197 expectedStatus: HttpStatusCode.NO_CONTENT_204
198 })
199 })
200
201 it('Should fail with a video that is already waiting for edition', async function () {
202 this.timeout(120000)
203
204 await command.createEditionTasks({
205 videoId: videoUUID,
206 tasks: VideoStudioCommand.getComplexTask(),
207 expectedStatus: HttpStatusCode.CONFLICT_409
208 })
209
210 await server.jobs.resumeJobQueue()
211
212 await waitJobs([ server ])
213 })
214 })
215
216 describe('Cut task', function () {
217
218 async function cut (start: number, end: number, expectedStatus = HttpStatusCode.BAD_REQUEST_400) {
219 await command.createEditionTasks({
220 videoId: videoUUID,
221 tasks: [
222 {
223 name: 'cut',
224 options: {
225 start,
226 end
227 }
228 }
229 ],
230 expectedStatus
231 })
232 }
233
234 it('Should fail with bad start/end', async function () {
235 const invalid = [
236 'tintin',
237 -1,
238 undefined
239 ]
240
241 for (const value of invalid) {
242 await cut(value as any, undefined)
243 await cut(undefined, value as any)
244 }
245 })
246
247 it('Should fail with the same start/end', async function () {
248 await cut(2, 2)
249 })
250
251 it('Should fail with inconsistents start/end', async function () {
252 await cut(2, 1)
253 })
254
255 it('Should fail without start and end', async function () {
256 await cut(undefined, undefined)
257 })
258
259 it('Should succeed with the correct params', async function () {
260 this.timeout(120000)
261
262 await cut(0, 2, HttpStatusCode.NO_CONTENT_204)
263
264 await waitJobs([ server ])
265 })
266 })
267
268 describe('Watermark task', function () {
269
270 async function addWatermark (file: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400) {
271 await command.createEditionTasks({
272 videoId: videoUUID,
273 tasks: [
274 {
275 name: 'add-watermark',
276 options: {
277 file
278 }
279 }
280 ],
281 expectedStatus
282 })
283 }
284
285 it('Should fail without waterkmark', async function () {
286 await addWatermark(undefined)
287 })
288
289 it('Should fail with an invalid watermark', async function () {
290 await addWatermark('video_short.mp4')
291 })
292
293 it('Should succeed with the correct params', async function () {
294 this.timeout(120000)
295
296 await addWatermark('custom-thumbnail.jpg', HttpStatusCode.NO_CONTENT_204)
297
298 await waitJobs([ server ])
299 })
300 })
301
302 describe('Intro/Outro task', function () {
303
304 async function addIntroOutro (type: 'add-intro' | 'add-outro', file: string, expectedStatus = HttpStatusCode.BAD_REQUEST_400) {
305 await command.createEditionTasks({
306 videoId: videoUUID,
307 tasks: [
308 {
309 name: type,
310 options: {
311 file
312 }
313 }
314 ],
315 expectedStatus
316 })
317 }
318
319 it('Should fail without file', async function () {
320 await addIntroOutro('add-intro', undefined)
321 await addIntroOutro('add-outro', undefined)
322 })
323
324 it('Should fail with an invalid file', async function () {
325 await addIntroOutro('add-intro', 'custom-thumbnail.jpg')
326 await addIntroOutro('add-outro', 'custom-thumbnail.jpg')
327 })
328
329 it('Should fail with a file that does not contain video stream', async function () {
330 await addIntroOutro('add-intro', 'sample.ogg')
331 await addIntroOutro('add-outro', 'sample.ogg')
332
333 })
334
335 it('Should succeed with the correct params', async function () {
336 this.timeout(120000)
337
338 await addIntroOutro('add-intro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204)
339 await waitJobs([ server ])
340
341 await addIntroOutro('add-outro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204)
342 await waitJobs([ server ])
343 })
344
345 it('Should check total quota when creating the task', async function () {
346 this.timeout(120000)
347
348 const user = await server.users.create({ username: 'user_quota_1' })
349 const token = await server.login.getAccessToken('user_quota_1')
350 const { uuid } = await server.videos.quickUpload({ token, name: 'video_quota_1', fixture: 'video_short.mp4' })
351
352 const addIntroOutroByUser = (type: 'add-intro' | 'add-outro', expectedStatus: HttpStatusCode) => {
353 return command.createEditionTasks({
354 token,
355 videoId: uuid,
356 tasks: [
357 {
358 name: type,
359 options: {
360 file: 'video_short.mp4'
361 }
362 }
363 ],
364 expectedStatus
365 })
366 }
367
368 await waitJobs([ server ])
369
370 const { videoQuotaUsed } = await server.users.getMyQuotaUsed({ token })
371 await server.users.update({ userId: user.id, videoQuota: Math.round(videoQuotaUsed * 2.5) })
372
373 // Still valid
374 await addIntroOutroByUser('add-intro', HttpStatusCode.NO_CONTENT_204)
375
376 await waitJobs([ server ])
377
378 // Too much quota
379 await addIntroOutroByUser('add-intro', HttpStatusCode.PAYLOAD_TOO_LARGE_413)
380 await addIntroOutroByUser('add-outro', HttpStatusCode.PAYLOAD_TOO_LARGE_413)
381 })
382 })
383 })
384
385 after(async function () {
386 await cleanupTests([ server ])
387 })
388})
diff --git a/server/tests/api/check-params/video-token.ts b/server/tests/api/check-params/video-token.ts
deleted file mode 100644
index 7cb3e84a2..000000000
--- a/server/tests/api/check-params/video-token.ts
+++ /dev/null
@@ -1,70 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { HttpStatusCode, VideoPrivacy } from '@shared/models'
4import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
5
6describe('Test video tokens', function () {
7 let server: PeerTubeServer
8 let privateVideoId: string
9 let passwordProtectedVideoId: string
10 let userToken: string
11
12 const videoPassword = 'password'
13
14 // ---------------------------------------------------------------
15
16 before(async function () {
17 this.timeout(300_000)
18
19 server = await createSingleServer(1)
20 await setAccessTokensToServers([ server ])
21 {
22 const { uuid } = await server.videos.quickUpload({ name: 'private video', privacy: VideoPrivacy.PRIVATE })
23 privateVideoId = uuid
24 }
25 {
26 const { uuid } = await server.videos.quickUpload({
27 name: 'password protected video',
28 privacy: VideoPrivacy.PASSWORD_PROTECTED,
29 videoPasswords: [ videoPassword ]
30 })
31 passwordProtectedVideoId = uuid
32 }
33 userToken = await server.users.generateUserAndToken('user1')
34 })
35
36 it('Should not generate tokens on private video for unauthenticated user', async function () {
37 await server.videoToken.create({ videoId: privateVideoId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
38 })
39
40 it('Should not generate tokens of unknown video', async function () {
41 await server.videoToken.create({ videoId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
42 })
43
44 it('Should not generate tokens with incorrect password', async function () {
45 await server.videoToken.create({
46 videoId: passwordProtectedVideoId,
47 token: null,
48 expectedStatus: HttpStatusCode.FORBIDDEN_403,
49 videoPassword: 'incorrectPassword'
50 })
51 })
52
53 it('Should not generate tokens of a non owned video', async function () {
54 await server.videoToken.create({ videoId: privateVideoId, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
55 })
56
57 it('Should generate token', async function () {
58 await server.videoToken.create({ videoId: privateVideoId })
59 })
60
61 it('Should generate token on password protected video', async function () {
62 await server.videoToken.create({ videoId: passwordProtectedVideoId, videoPassword, token: null })
63 await server.videoToken.create({ videoId: passwordProtectedVideoId, videoPassword, token: userToken })
64 await server.videoToken.create({ videoId: passwordProtectedVideoId, videoPassword })
65 })
66
67 after(async function () {
68 await cleanupTests([ server ])
69 })
70})
diff --git a/server/tests/api/check-params/videos-common-filters.ts b/server/tests/api/check-params/videos-common-filters.ts
deleted file mode 100644
index 603f7f777..000000000
--- a/server/tests/api/check-params/videos-common-filters.ts
+++ /dev/null
@@ -1,163 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { HttpStatusCode, UserRole, VideoInclude, VideoPrivacy } from '@shared/models'
4import {
5 cleanupTests,
6 createSingleServer,
7 makeGetRequest,
8 PeerTubeServer,
9 setAccessTokensToServers,
10 setDefaultVideoChannel
11} from '@shared/server-commands'
12
13describe('Test video filters validators', function () {
14 let server: PeerTubeServer
15 let userAccessToken: string
16 let moderatorAccessToken: string
17
18 // ---------------------------------------------------------------
19
20 before(async function () {
21 this.timeout(30000)
22
23 server = await createSingleServer(1)
24
25 await setAccessTokensToServers([ server ])
26 await setDefaultVideoChannel([ server ])
27
28 const user = { username: 'user1', password: 'my super password' }
29 await server.users.create({ username: user.username, password: user.password })
30 userAccessToken = await server.login.getAccessToken(user)
31
32 const moderator = { username: 'moderator', password: 'my super password' }
33 await server.users.create({ username: moderator.username, password: moderator.password, role: UserRole.MODERATOR })
34
35 moderatorAccessToken = await server.login.getAccessToken(moderator)
36 })
37
38 describe('When setting video filters', function () {
39
40 const validIncludes = [
41 VideoInclude.NONE,
42 VideoInclude.BLOCKED_OWNER,
43 VideoInclude.NOT_PUBLISHED_STATE | VideoInclude.BLACKLISTED
44 ]
45
46 async function testEndpoints (options: {
47 token?: string
48 isLocal?: boolean
49 include?: VideoInclude
50 privacyOneOf?: VideoPrivacy[]
51 expectedStatus: HttpStatusCode
52 excludeAlreadyWatched?: boolean
53 unauthenticatedUser?: boolean
54 }) {
55 const paths = [
56 '/api/v1/video-channels/root_channel/videos',
57 '/api/v1/accounts/root/videos',
58 '/api/v1/videos',
59 '/api/v1/search/videos'
60 ]
61
62 for (const path of paths) {
63 const token = options.unauthenticatedUser
64 ? undefined
65 : options.token || server.accessToken
66
67 await makeGetRequest({
68 url: server.url,
69 path,
70 token,
71 query: {
72 isLocal: options.isLocal,
73 privacyOneOf: options.privacyOneOf,
74 include: options.include,
75 excludeAlreadyWatched: options.excludeAlreadyWatched
76 },
77 expectedStatus: options.expectedStatus
78 })
79 }
80 }
81
82 it('Should fail with a bad privacyOneOf', async function () {
83 await testEndpoints({ privacyOneOf: [ 'toto' ] as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
84 })
85
86 it('Should succeed with a good privacyOneOf', async function () {
87 await testEndpoints({ privacyOneOf: [ VideoPrivacy.INTERNAL ], expectedStatus: HttpStatusCode.OK_200 })
88 })
89
90 it('Should fail to use privacyOneOf with a simple user', async function () {
91 await testEndpoints({
92 privacyOneOf: [ VideoPrivacy.INTERNAL ],
93 token: userAccessToken,
94 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
95 })
96 })
97
98 it('Should fail with a bad include', async function () {
99 await testEndpoints({ include: 'toto' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
100 })
101
102 it('Should succeed with a good include', async function () {
103 for (const include of validIncludes) {
104 await testEndpoints({ include, expectedStatus: HttpStatusCode.OK_200 })
105 }
106 })
107
108 it('Should fail to include more videos with a simple user', async function () {
109 for (const include of validIncludes) {
110 await testEndpoints({ token: userAccessToken, include, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
111 }
112 })
113
114 it('Should succeed to list all local/all with a moderator', async function () {
115 for (const include of validIncludes) {
116 await testEndpoints({ token: moderatorAccessToken, include, expectedStatus: HttpStatusCode.OK_200 })
117 }
118 })
119
120 it('Should succeed to list all local/all with an admin', async function () {
121 for (const include of validIncludes) {
122 await testEndpoints({ token: server.accessToken, include, expectedStatus: HttpStatusCode.OK_200 })
123 }
124 })
125
126 // Because we cannot authenticate the user on the RSS endpoint
127 it('Should fail on the feeds endpoint with the all filter', async function () {
128 for (const include of [ VideoInclude.NOT_PUBLISHED_STATE ]) {
129 await makeGetRequest({
130 url: server.url,
131 path: '/feeds/videos.json',
132 expectedStatus: HttpStatusCode.UNAUTHORIZED_401,
133 query: {
134 include
135 }
136 })
137 }
138 })
139
140 it('Should succeed on the feeds endpoint with the local filter', async function () {
141 await makeGetRequest({
142 url: server.url,
143 path: '/feeds/videos.json',
144 expectedStatus: HttpStatusCode.OK_200,
145 query: {
146 isLocal: true
147 }
148 })
149 })
150
151 it('Should fail when trying to exclude already watched videos for an unlogged user', async function () {
152 await testEndpoints({ excludeAlreadyWatched: true, unauthenticatedUser: true, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
153 })
154
155 it('Should succeed when trying to exclude already watched videos for a logged user', async function () {
156 await testEndpoints({ token: userAccessToken, excludeAlreadyWatched: true, expectedStatus: HttpStatusCode.OK_200 })
157 })
158 })
159
160 after(async function () {
161 await cleanupTests([ server ])
162 })
163})
diff --git a/server/tests/api/check-params/videos-history.ts b/server/tests/api/check-params/videos-history.ts
deleted file mode 100644
index d96fe7ca9..000000000
--- a/server/tests/api/check-params/videos-history.ts
+++ /dev/null
@@ -1,145 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { checkBadCountPagination, checkBadStartPagination } from '@server/tests/shared'
4import { HttpStatusCode } from '@shared/models'
5import {
6 cleanupTests,
7 createSingleServer,
8 makeDeleteRequest,
9 makeGetRequest,
10 makePostBodyRequest,
11 makePutBodyRequest,
12 PeerTubeServer,
13 setAccessTokensToServers
14} from '@shared/server-commands'
15
16describe('Test videos history API validator', function () {
17 const myHistoryPath = '/api/v1/users/me/history/videos'
18 const myHistoryRemove = myHistoryPath + '/remove'
19 let viewPath: string
20 let server: PeerTubeServer
21 let videoId: number
22
23 // ---------------------------------------------------------------
24
25 before(async function () {
26 this.timeout(30000)
27
28 server = await createSingleServer(1)
29
30 await setAccessTokensToServers([ server ])
31
32 const { id, uuid } = await server.videos.upload()
33 viewPath = '/api/v1/videos/' + uuid + '/views'
34 videoId = id
35 })
36
37 describe('When notifying a user is watching a video', function () {
38
39 it('Should fail with a bad token', async function () {
40 const fields = { currentTime: 5 }
41 await makePutBodyRequest({ url: server.url, path: viewPath, fields, token: 'bad', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
42 })
43
44 it('Should succeed with the correct parameters', async function () {
45 const fields = { currentTime: 5 }
46
47 await makePutBodyRequest({
48 url: server.url,
49 path: viewPath,
50 fields,
51 token: server.accessToken,
52 expectedStatus: HttpStatusCode.NO_CONTENT_204
53 })
54 })
55 })
56
57 describe('When listing user videos history', function () {
58 it('Should fail with a bad start pagination', async function () {
59 await checkBadStartPagination(server.url, myHistoryPath, server.accessToken)
60 })
61
62 it('Should fail with a bad count pagination', async function () {
63 await checkBadCountPagination(server.url, myHistoryPath, server.accessToken)
64 })
65
66 it('Should fail with an unauthenticated user', async function () {
67 await makeGetRequest({ url: server.url, path: myHistoryPath, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
68 })
69
70 it('Should succeed with the correct params', async function () {
71 await makeGetRequest({ url: server.url, token: server.accessToken, path: myHistoryPath, expectedStatus: HttpStatusCode.OK_200 })
72 })
73 })
74
75 describe('When removing a specific user video history element', function () {
76 let path: string
77
78 before(function () {
79 path = myHistoryPath + '/' + videoId
80 })
81
82 it('Should fail with an unauthenticated user', async function () {
83 await makeDeleteRequest({ url: server.url, path, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
84 })
85
86 it('Should fail with a bad videoId parameter', async function () {
87 await makeDeleteRequest({
88 url: server.url,
89 token: server.accessToken,
90 path: myHistoryRemove + '/hi',
91 expectedStatus: HttpStatusCode.BAD_REQUEST_400
92 })
93 })
94
95 it('Should succeed with the correct parameters', async function () {
96 await makeDeleteRequest({
97 url: server.url,
98 token: server.accessToken,
99 path,
100 expectedStatus: HttpStatusCode.NO_CONTENT_204
101 })
102 })
103 })
104
105 describe('When removing all user videos history', function () {
106 it('Should fail with an unauthenticated user', async function () {
107 await makePostBodyRequest({ url: server.url, path: myHistoryPath + '/remove', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
108 })
109
110 it('Should fail with a bad beforeDate parameter', async function () {
111 const body = { beforeDate: '15' }
112 await makePostBodyRequest({
113 url: server.url,
114 token: server.accessToken,
115 path: myHistoryRemove,
116 fields: body,
117 expectedStatus: HttpStatusCode.BAD_REQUEST_400
118 })
119 })
120
121 it('Should succeed with a valid beforeDate param', async function () {
122 const body = { beforeDate: new Date().toISOString() }
123 await makePostBodyRequest({
124 url: server.url,
125 token: server.accessToken,
126 path: myHistoryRemove,
127 fields: body,
128 expectedStatus: HttpStatusCode.NO_CONTENT_204
129 })
130 })
131
132 it('Should succeed without body', async function () {
133 await makePostBodyRequest({
134 url: server.url,
135 token: server.accessToken,
136 path: myHistoryRemove,
137 expectedStatus: HttpStatusCode.NO_CONTENT_204
138 })
139 })
140 })
141
142 after(async function () {
143 await cleanupTests([ server ])
144 })
145})
diff --git a/server/tests/api/check-params/videos-overviews.ts b/server/tests/api/check-params/videos-overviews.ts
deleted file mode 100644
index ae7de24dd..000000000
--- a/server/tests/api/check-params/videos-overviews.ts
+++ /dev/null
@@ -1,31 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { cleanupTests, createSingleServer, PeerTubeServer } from '@shared/server-commands'
4
5describe('Test videos overview API validator', function () {
6 let server: PeerTubeServer
7
8 // ---------------------------------------------------------------
9
10 before(async function () {
11 this.timeout(30000)
12
13 server = await createSingleServer(1)
14 })
15
16 describe('When getting videos overview', function () {
17
18 it('Should fail with a bad pagination', async function () {
19 await server.overviews.getVideos({ page: 0, expectedStatus: 400 })
20 await server.overviews.getVideos({ page: 100, expectedStatus: 400 })
21 })
22
23 it('Should succeed with a good pagination', async function () {
24 await server.overviews.getVideos({ page: 1 })
25 })
26 })
27
28 after(async function () {
29 await cleanupTests([ server ])
30 })
31})
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts
deleted file mode 100644
index f00698fe3..000000000
--- a/server/tests/api/check-params/videos.ts
+++ /dev/null
@@ -1,881 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { join } from 'path'
5import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, checkUploadVideoParam } from '@server/tests/shared'
6import { omit, randomInt, root } from '@shared/core-utils'
7import { HttpStatusCode, PeerTubeProblemDocument, VideoCreateResult, VideoPrivacy } from '@shared/models'
8import {
9 cleanupTests,
10 createSingleServer,
11 makeDeleteRequest,
12 makeGetRequest,
13 makePutBodyRequest,
14 makeUploadRequest,
15 PeerTubeServer,
16 setAccessTokensToServers
17} from '@shared/server-commands'
18
19describe('Test videos API validator', function () {
20 const path = '/api/v1/videos/'
21 let server: PeerTubeServer
22 let userAccessToken = ''
23 let accountName: string
24 let channelId: number
25 let channelName: string
26 let video: VideoCreateResult
27 let privateVideo: VideoCreateResult
28
29 // ---------------------------------------------------------------
30
31 before(async function () {
32 this.timeout(30000)
33
34 server = await createSingleServer(1)
35
36 await setAccessTokensToServers([ server ])
37
38 userAccessToken = await server.users.generateUserAndToken('user1')
39
40 {
41 const body = await server.users.getMyInfo()
42 channelId = body.videoChannels[0].id
43 channelName = body.videoChannels[0].name
44 accountName = body.account.name + '@' + body.account.host
45 }
46
47 {
48 privateVideo = await server.videos.quickUpload({ name: 'private video', privacy: VideoPrivacy.PRIVATE })
49 }
50 })
51
52 describe('When listing videos', function () {
53 it('Should fail with a bad start pagination', async function () {
54 await checkBadStartPagination(server.url, path)
55 })
56
57 it('Should fail with a bad count pagination', async function () {
58 await checkBadCountPagination(server.url, path)
59 })
60
61 it('Should fail with an incorrect sort', async function () {
62 await checkBadSortPagination(server.url, path)
63 })
64
65 it('Should fail with a bad skipVideos query', async function () {
66 await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200, query: { skipCount: 'toto' } })
67 })
68
69 it('Should success with the correct parameters', async function () {
70 await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200, query: { skipCount: false } })
71 })
72 })
73
74 describe('When searching a video', function () {
75
76 it('Should fail with nothing', async function () {
77 await makeGetRequest({
78 url: server.url,
79 path: join(path, 'search'),
80 expectedStatus: HttpStatusCode.BAD_REQUEST_400
81 })
82 })
83
84 it('Should fail with a bad start pagination', async function () {
85 await checkBadStartPagination(server.url, join(path, 'search', 'test'))
86 })
87
88 it('Should fail with a bad count pagination', async function () {
89 await checkBadCountPagination(server.url, join(path, 'search', 'test'))
90 })
91
92 it('Should fail with an incorrect sort', async function () {
93 await checkBadSortPagination(server.url, join(path, 'search', 'test'))
94 })
95
96 it('Should success with the correct parameters', async function () {
97 await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200 })
98 })
99 })
100
101 describe('When listing my videos', function () {
102 const path = '/api/v1/users/me/videos'
103
104 it('Should fail with a bad start pagination', async function () {
105 await checkBadStartPagination(server.url, path, server.accessToken)
106 })
107
108 it('Should fail with a bad count pagination', async function () {
109 await checkBadCountPagination(server.url, path, server.accessToken)
110 })
111
112 it('Should fail with an incorrect sort', async function () {
113 await checkBadSortPagination(server.url, path, server.accessToken)
114 })
115
116 it('Should fail with an invalid channel', async function () {
117 await makeGetRequest({ url: server.url, token: server.accessToken, path, query: { channelId: 'toto' } })
118 })
119
120 it('Should fail with an unknown channel', async function () {
121 await makeGetRequest({
122 url: server.url,
123 token: server.accessToken,
124 path,
125 query: { channelId: 89898 },
126 expectedStatus: HttpStatusCode.NOT_FOUND_404
127 })
128 })
129
130 it('Should success with the correct parameters', async function () {
131 await makeGetRequest({ url: server.url, token: server.accessToken, path, expectedStatus: HttpStatusCode.OK_200 })
132 })
133 })
134
135 describe('When listing account videos', function () {
136 let path: string
137
138 before(async function () {
139 path = '/api/v1/accounts/' + accountName + '/videos'
140 })
141
142 it('Should fail with a bad start pagination', async function () {
143 await checkBadStartPagination(server.url, path, server.accessToken)
144 })
145
146 it('Should fail with a bad count pagination', async function () {
147 await checkBadCountPagination(server.url, path, server.accessToken)
148 })
149
150 it('Should fail with an incorrect sort', async function () {
151 await checkBadSortPagination(server.url, path, server.accessToken)
152 })
153
154 it('Should success with the correct parameters', async function () {
155 await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200 })
156 })
157 })
158
159 describe('When listing video channel videos', function () {
160 let path: string
161
162 before(async function () {
163 path = '/api/v1/video-channels/' + channelName + '/videos'
164 })
165
166 it('Should fail with a bad start pagination', async function () {
167 await checkBadStartPagination(server.url, path, server.accessToken)
168 })
169
170 it('Should fail with a bad count pagination', async function () {
171 await checkBadCountPagination(server.url, path, server.accessToken)
172 })
173
174 it('Should fail with an incorrect sort', async function () {
175 await checkBadSortPagination(server.url, path, server.accessToken)
176 })
177
178 it('Should success with the correct parameters', async function () {
179 await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200 })
180 })
181 })
182
183 describe('When adding a video', function () {
184 let baseCorrectParams
185 const baseCorrectAttaches = {
186 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.webm')
187 }
188
189 before(function () {
190 // Put in before to have channelId
191 baseCorrectParams = {
192 name: 'my super name',
193 category: 5,
194 licence: 1,
195 language: 'pt',
196 nsfw: false,
197 commentsEnabled: true,
198 downloadEnabled: true,
199 waitTranscoding: true,
200 description: 'my super description',
201 support: 'my super support text',
202 tags: [ 'tag1', 'tag2' ],
203 privacy: VideoPrivacy.PUBLIC,
204 channelId,
205 originallyPublishedAt: new Date().toISOString()
206 }
207 })
208
209 function runSuite (mode: 'legacy' | 'resumable') {
210
211 const baseOptions = () => {
212 return {
213 server,
214 token: server.accessToken,
215 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
216 mode
217 }
218 }
219
220 it('Should fail with nothing', async function () {
221 const fields = {}
222 const attaches = {}
223 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
224 })
225
226 it('Should fail without name', async function () {
227 const fields = omit(baseCorrectParams, [ 'name' ])
228 const attaches = baseCorrectAttaches
229
230 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
231 })
232
233 it('Should fail with a long name', async function () {
234 const fields = { ...baseCorrectParams, name: 'super'.repeat(65) }
235 const attaches = baseCorrectAttaches
236
237 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
238 })
239
240 it('Should fail with a bad category', async function () {
241 const fields = { ...baseCorrectParams, category: 125 }
242 const attaches = baseCorrectAttaches
243
244 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
245 })
246
247 it('Should fail with a bad licence', async function () {
248 const fields = { ...baseCorrectParams, licence: 125 }
249 const attaches = baseCorrectAttaches
250
251 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
252 })
253
254 it('Should fail with a bad language', async function () {
255 const fields = { ...baseCorrectParams, language: 'a'.repeat(15) }
256 const attaches = baseCorrectAttaches
257
258 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
259 })
260
261 it('Should fail with a long description', async function () {
262 const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) }
263 const attaches = baseCorrectAttaches
264
265 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
266 })
267
268 it('Should fail with a long support text', async function () {
269 const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
270 const attaches = baseCorrectAttaches
271
272 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
273 })
274
275 it('Should fail without a channel', async function () {
276 const fields = omit(baseCorrectParams, [ 'channelId' ])
277 const attaches = baseCorrectAttaches
278
279 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
280 })
281
282 it('Should fail with a bad channel', async function () {
283 const fields = { ...baseCorrectParams, channelId: 545454 }
284 const attaches = baseCorrectAttaches
285
286 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
287 })
288
289 it('Should fail with another user channel', async function () {
290 const user = {
291 username: 'fake' + randomInt(0, 1500),
292 password: 'fake_password'
293 }
294 await server.users.create({ username: user.username, password: user.password })
295
296 const accessTokenUser = await server.login.getAccessToken(user)
297 const { videoChannels } = await server.users.getMyInfo({ token: accessTokenUser })
298 const customChannelId = videoChannels[0].id
299
300 const fields = { ...baseCorrectParams, channelId: customChannelId }
301 const attaches = baseCorrectAttaches
302
303 await checkUploadVideoParam({
304 ...baseOptions(),
305 token: userAccessToken,
306 attributes: { ...fields, ...attaches }
307 })
308 })
309
310 it('Should fail with too many tags', async function () {
311 const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }
312 const attaches = baseCorrectAttaches
313
314 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
315 })
316
317 it('Should fail with a tag length too low', async function () {
318 const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] }
319 const attaches = baseCorrectAttaches
320
321 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
322 })
323
324 it('Should fail with a tag length too big', async function () {
325 const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }
326 const attaches = baseCorrectAttaches
327
328 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
329 })
330
331 it('Should fail with a bad schedule update (miss updateAt)', async function () {
332 const fields = { ...baseCorrectParams, scheduleUpdate: { privacy: VideoPrivacy.PUBLIC } }
333 const attaches = baseCorrectAttaches
334
335 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
336 })
337
338 it('Should fail with a bad schedule update (wrong updateAt)', async function () {
339 const fields = {
340 ...baseCorrectParams,
341
342 scheduleUpdate: {
343 privacy: VideoPrivacy.PUBLIC,
344 updateAt: 'toto'
345 }
346 }
347 const attaches = baseCorrectAttaches
348
349 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
350 })
351
352 it('Should fail with a bad originally published at attribute', async function () {
353 const fields = { ...baseCorrectParams, originallyPublishedAt: 'toto' }
354 const attaches = baseCorrectAttaches
355
356 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
357 })
358
359 it('Should fail without an input file', async function () {
360 const fields = baseCorrectParams
361 const attaches = {}
362 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
363 })
364
365 it('Should fail with an incorrect input file', async function () {
366 const fields = baseCorrectParams
367 let attaches = { fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm') }
368
369 await checkUploadVideoParam({
370 ...baseOptions(),
371 attributes: { ...fields, ...attaches },
372 // 200 for the init request, 422 when the file has finished being uploaded
373 expectedStatus: undefined,
374 completedExpectedStatus: HttpStatusCode.UNPROCESSABLE_ENTITY_422
375 })
376
377 attaches = { fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv') }
378 await checkUploadVideoParam({
379 ...baseOptions(),
380 attributes: { ...fields, ...attaches },
381 expectedStatus: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415
382 })
383 })
384
385 it('Should fail with an incorrect thumbnail file', async function () {
386 const fields = baseCorrectParams
387 const attaches = {
388 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4'),
389 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
390 }
391
392 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
393 })
394
395 it('Should fail with a big thumbnail file', async function () {
396 const fields = baseCorrectParams
397 const attaches = {
398 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'custom-preview-big.png'),
399 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
400 }
401
402 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
403 })
404
405 it('Should fail with an incorrect preview file', async function () {
406 const fields = baseCorrectParams
407 const attaches = {
408 previewfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4'),
409 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
410 }
411
412 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
413 })
414
415 it('Should fail with a big preview file', async function () {
416 const fields = baseCorrectParams
417 const attaches = {
418 previewfile: join(root(), 'server', 'tests', 'fixtures', 'custom-preview-big.png'),
419 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
420 }
421
422 await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
423 })
424
425 it('Should report the appropriate error', async function () {
426 const fields = { ...baseCorrectParams, language: 'a'.repeat(15) }
427 const attaches = baseCorrectAttaches
428
429 const attributes = { ...fields, ...attaches }
430 const body = await checkUploadVideoParam({ ...baseOptions(), attributes })
431
432 const error = body as unknown as PeerTubeProblemDocument
433
434 if (mode === 'legacy') {
435 expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadLegacy')
436 } else {
437 expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadResumableInit')
438 }
439
440 expect(error.type).to.equal('about:blank')
441 expect(error.title).to.equal('Bad Request')
442
443 expect(error.detail).to.equal('Incorrect request parameters: language')
444 expect(error.error).to.equal('Incorrect request parameters: language')
445
446 expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400)
447 expect(error['invalid-params'].language).to.exist
448 })
449
450 it('Should succeed with the correct parameters', async function () {
451 this.timeout(30000)
452
453 const fields = baseCorrectParams
454
455 {
456 const attaches = baseCorrectAttaches
457 await checkUploadVideoParam({
458 ...baseOptions(),
459 attributes: { ...fields, ...attaches },
460 expectedStatus: HttpStatusCode.OK_200
461 })
462 }
463
464 {
465 const attaches = {
466 ...baseCorrectAttaches,
467
468 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
469 }
470
471 await checkUploadVideoParam({
472 ...baseOptions(),
473 attributes: { ...fields, ...attaches },
474 expectedStatus: HttpStatusCode.OK_200
475 })
476 }
477
478 {
479 const attaches = {
480 ...baseCorrectAttaches,
481
482 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.ogv')
483 }
484
485 await checkUploadVideoParam({
486 ...baseOptions(),
487 attributes: { ...fields, ...attaches },
488 expectedStatus: HttpStatusCode.OK_200
489 })
490 }
491 })
492 }
493
494 describe('Resumable upload', function () {
495 runSuite('resumable')
496 })
497
498 describe('Legacy upload', function () {
499 runSuite('legacy')
500 })
501 })
502
503 describe('When updating a video', function () {
504 const baseCorrectParams = {
505 name: 'my super name',
506 category: 5,
507 licence: 2,
508 language: 'pt',
509 nsfw: false,
510 commentsEnabled: false,
511 downloadEnabled: false,
512 description: 'my super description',
513 privacy: VideoPrivacy.PUBLIC,
514 tags: [ 'tag1', 'tag2' ]
515 }
516
517 before(async function () {
518 const { data } = await server.videos.list()
519 video = data[0]
520 })
521
522 it('Should fail with nothing', async function () {
523 const fields = {}
524 await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
525 })
526
527 it('Should fail without a valid uuid', async function () {
528 const fields = baseCorrectParams
529 await makePutBodyRequest({ url: server.url, path: path + 'blabla', token: server.accessToken, fields })
530 })
531
532 it('Should fail with an unknown id', async function () {
533 const fields = baseCorrectParams
534
535 await makePutBodyRequest({
536 url: server.url,
537 path: path + '4da6fde3-88f7-4d16-b119-108df5630b06',
538 token: server.accessToken,
539 fields,
540 expectedStatus: HttpStatusCode.NOT_FOUND_404
541 })
542 })
543
544 it('Should fail with a long name', async function () {
545 const fields = { ...baseCorrectParams, name: 'super'.repeat(65) }
546
547 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
548 })
549
550 it('Should fail with a bad category', async function () {
551 const fields = { ...baseCorrectParams, category: 125 }
552
553 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
554 })
555
556 it('Should fail with a bad licence', async function () {
557 const fields = { ...baseCorrectParams, licence: 125 }
558
559 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
560 })
561
562 it('Should fail with a bad language', async function () {
563 const fields = { ...baseCorrectParams, language: 'a'.repeat(15) }
564
565 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
566 })
567
568 it('Should fail with a long description', async function () {
569 const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) }
570
571 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
572 })
573
574 it('Should fail with a long support text', async function () {
575 const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
576
577 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
578 })
579
580 it('Should fail with a bad channel', async function () {
581 const fields = { ...baseCorrectParams, channelId: 545454 }
582
583 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
584 })
585
586 it('Should fail with too many tags', async function () {
587 const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }
588
589 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
590 })
591
592 it('Should fail with a tag length too low', async function () {
593 const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] }
594
595 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
596 })
597
598 it('Should fail with a tag length too big', async function () {
599 const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }
600
601 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
602 })
603
604 it('Should fail with a bad schedule update (miss updateAt)', async function () {
605 const fields = { ...baseCorrectParams, scheduleUpdate: { privacy: VideoPrivacy.PUBLIC } }
606
607 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
608 })
609
610 it('Should fail with a bad schedule update (wrong updateAt)', async function () {
611 const fields = { ...baseCorrectParams, scheduleUpdate: { updateAt: 'toto', privacy: VideoPrivacy.PUBLIC } }
612
613 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
614 })
615
616 it('Should fail with a bad originally published at param', async function () {
617 const fields = { ...baseCorrectParams, originallyPublishedAt: 'toto' }
618
619 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
620 })
621
622 it('Should fail with an incorrect thumbnail file', async function () {
623 const fields = baseCorrectParams
624 const attaches = {
625 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
626 }
627
628 await makeUploadRequest({
629 url: server.url,
630 method: 'PUT',
631 path: path + video.shortUUID,
632 token: server.accessToken,
633 fields,
634 attaches
635 })
636 })
637
638 it('Should fail with a big thumbnail file', async function () {
639 const fields = baseCorrectParams
640 const attaches = {
641 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'custom-preview-big.png')
642 }
643
644 await makeUploadRequest({
645 url: server.url,
646 method: 'PUT',
647 path: path + video.shortUUID,
648 token: server.accessToken,
649 fields,
650 attaches
651 })
652 })
653
654 it('Should fail with an incorrect preview file', async function () {
655 const fields = baseCorrectParams
656 const attaches = {
657 previewfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
658 }
659
660 await makeUploadRequest({
661 url: server.url,
662 method: 'PUT',
663 path: path + video.shortUUID,
664 token: server.accessToken,
665 fields,
666 attaches
667 })
668 })
669
670 it('Should fail with a big preview file', async function () {
671 const fields = baseCorrectParams
672 const attaches = {
673 previewfile: join(root(), 'server', 'tests', 'fixtures', 'custom-preview-big.png')
674 }
675
676 await makeUploadRequest({
677 url: server.url,
678 method: 'PUT',
679 path: path + video.shortUUID,
680 token: server.accessToken,
681 fields,
682 attaches
683 })
684 })
685
686 it('Should fail with a video of another user without the appropriate right', async function () {
687 const fields = baseCorrectParams
688
689 await makePutBodyRequest({
690 url: server.url,
691 path: path + video.shortUUID,
692 token: userAccessToken,
693 fields,
694 expectedStatus: HttpStatusCode.FORBIDDEN_403
695 })
696 })
697
698 it('Should fail with a video of another server')
699
700 it('Shoud report the appropriate error', async function () {
701 const fields = { ...baseCorrectParams, licence: 125 }
702
703 const res = await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
704 const error = res.body as PeerTubeProblemDocument
705
706 expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/putVideo')
707
708 expect(error.type).to.equal('about:blank')
709 expect(error.title).to.equal('Bad Request')
710
711 expect(error.detail).to.equal('Incorrect request parameters: licence')
712 expect(error.error).to.equal('Incorrect request parameters: licence')
713
714 expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400)
715 expect(error['invalid-params'].licence).to.exist
716 })
717
718 it('Should succeed with the correct parameters', async function () {
719 const fields = baseCorrectParams
720
721 await makePutBodyRequest({
722 url: server.url,
723 path: path + video.shortUUID,
724 token: server.accessToken,
725 fields,
726 expectedStatus: HttpStatusCode.NO_CONTENT_204
727 })
728 })
729 })
730
731 describe('When getting a video', function () {
732 it('Should return the list of the videos with nothing', async function () {
733 const res = await makeGetRequest({
734 url: server.url,
735 path,
736 expectedStatus: HttpStatusCode.OK_200
737 })
738
739 expect(res.body.data).to.be.an('array')
740 expect(res.body.data.length).to.equal(6)
741 })
742
743 it('Should fail without a correct uuid', async function () {
744 await server.videos.get({ id: 'coucou', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
745 })
746
747 it('Should return 404 with an incorrect video', async function () {
748 await server.videos.get({ id: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
749 })
750
751 it('Shoud report the appropriate error', async function () {
752 const body = await server.videos.get({ id: 'hi', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
753 const error = body as unknown as PeerTubeProblemDocument
754
755 expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo')
756
757 expect(error.type).to.equal('about:blank')
758 expect(error.title).to.equal('Bad Request')
759
760 expect(error.detail).to.equal('Incorrect request parameters: id')
761 expect(error.error).to.equal('Incorrect request parameters: id')
762
763 expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400)
764 expect(error['invalid-params'].id).to.exist
765 })
766
767 it('Should succeed with the correct parameters', async function () {
768 await server.videos.get({ id: video.shortUUID })
769 })
770 })
771
772 describe('When rating a video', function () {
773 let videoId: number
774
775 before(async function () {
776 const { data } = await server.videos.list()
777 videoId = data[0].id
778 })
779
780 it('Should fail without a valid uuid', async function () {
781 const fields = {
782 rating: 'like'
783 }
784 await makePutBodyRequest({ url: server.url, path: path + 'blabla/rate', token: server.accessToken, fields })
785 })
786
787 it('Should fail with an unknown id', async function () {
788 const fields = {
789 rating: 'like'
790 }
791 await makePutBodyRequest({
792 url: server.url,
793 path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/rate',
794 token: server.accessToken,
795 fields,
796 expectedStatus: HttpStatusCode.NOT_FOUND_404
797 })
798 })
799
800 it('Should fail with a wrong rating', async function () {
801 const fields = {
802 rating: 'likes'
803 }
804 await makePutBodyRequest({ url: server.url, path: path + videoId + '/rate', token: server.accessToken, fields })
805 })
806
807 it('Should fail with a private video of another user', async function () {
808 const fields = {
809 rating: 'like'
810 }
811 await makePutBodyRequest({
812 url: server.url,
813 path: path + privateVideo.uuid + '/rate',
814 token: userAccessToken,
815 fields,
816 expectedStatus: HttpStatusCode.FORBIDDEN_403
817 })
818 })
819
820 it('Should succeed with the correct parameters', async function () {
821 const fields = {
822 rating: 'like'
823 }
824 await makePutBodyRequest({
825 url: server.url,
826 path: path + videoId + '/rate',
827 token: server.accessToken,
828 fields,
829 expectedStatus: HttpStatusCode.NO_CONTENT_204
830 })
831 })
832 })
833
834 describe('When removing a video', function () {
835 it('Should have 404 with nothing', async function () {
836 await makeDeleteRequest({
837 url: server.url,
838 path,
839 expectedStatus: HttpStatusCode.BAD_REQUEST_400
840 })
841 })
842
843 it('Should fail without a correct uuid', async function () {
844 await server.videos.remove({ id: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
845 })
846
847 it('Should fail with a video which does not exist', async function () {
848 await server.videos.remove({ id: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
849 })
850
851 it('Should fail with a video of another user without the appropriate right', async function () {
852 await server.videos.remove({ token: userAccessToken, id: video.uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
853 })
854
855 it('Should fail with a video of another server')
856
857 it('Shoud report the appropriate error', async function () {
858 const body = await server.videos.remove({ id: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
859 const error = body as PeerTubeProblemDocument
860
861 expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/delVideo')
862
863 expect(error.type).to.equal('about:blank')
864 expect(error.title).to.equal('Bad Request')
865
866 expect(error.detail).to.equal('Incorrect request parameters: id')
867 expect(error.error).to.equal('Incorrect request parameters: id')
868
869 expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400)
870 expect(error['invalid-params'].id).to.exist
871 })
872
873 it('Should succeed with the correct parameters', async function () {
874 await server.videos.remove({ id: video.uuid })
875 })
876 })
877
878 after(async function () {
879 await cleanupTests([ server ])
880 })
881})
diff --git a/server/tests/api/check-params/views.ts b/server/tests/api/check-params/views.ts
deleted file mode 100644
index 11416ccb8..000000000
--- a/server/tests/api/check-params/views.ts
+++ /dev/null
@@ -1,227 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { HttpStatusCode, VideoPrivacy } from '@shared/models'
4import {
5 cleanupTests,
6 createMultipleServers,
7 doubleFollow,
8 PeerTubeServer,
9 setAccessTokensToServers,
10 setDefaultVideoChannel
11} from '@shared/server-commands'
12
13describe('Test videos views', function () {
14 let servers: PeerTubeServer[]
15 let liveVideoId: string
16 let videoId: string
17 let remoteVideoId: string
18 let userAccessToken: string
19
20 before(async function () {
21 this.timeout(120000)
22
23 servers = await createMultipleServers(2)
24 await setAccessTokensToServers(servers)
25 await setDefaultVideoChannel(servers)
26
27 await servers[0].config.enableLive({ allowReplay: false, transcoding: false });
28
29 ({ uuid: videoId } = await servers[0].videos.quickUpload({ name: 'video' }));
30 ({ uuid: remoteVideoId } = await servers[1].videos.quickUpload({ name: 'video' }));
31 ({ uuid: liveVideoId } = await servers[0].live.create({
32 fields: {
33 name: 'live',
34 privacy: VideoPrivacy.PUBLIC,
35 channelId: servers[0].store.channel.id
36 }
37 }))
38
39 userAccessToken = await servers[0].users.generateUserAndToken('user')
40
41 await doubleFollow(servers[0], servers[1])
42 })
43
44 describe('When viewing a video', async function () {
45
46 it('Should fail without current time', async function () {
47 await servers[0].views.view({ id: videoId, currentTime: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
48 })
49
50 it('Should fail with an invalid current time', async function () {
51 await servers[0].views.view({ id: videoId, currentTime: -1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
52 await servers[0].views.view({ id: videoId, currentTime: 10, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
53 })
54
55 it('Should succeed with correct parameters', async function () {
56 await servers[0].views.view({ id: videoId, currentTime: 1 })
57 })
58 })
59
60 describe('When getting overall stats', function () {
61
62 it('Should fail with a remote video', async function () {
63 await servers[0].videoStats.getOverallStats({ videoId: remoteVideoId, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
64 })
65
66 it('Should fail without token', async function () {
67 await servers[0].videoStats.getOverallStats({ videoId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
68 })
69
70 it('Should fail with another token', async function () {
71 await servers[0].videoStats.getOverallStats({
72 videoId,
73 token: userAccessToken,
74 expectedStatus: HttpStatusCode.FORBIDDEN_403
75 })
76 })
77
78 it('Should fail with an invalid start date', async function () {
79 await servers[0].videoStats.getOverallStats({
80 videoId,
81 startDate: 'fake' as any,
82 endDate: new Date().toISOString(),
83 expectedStatus: HttpStatusCode.BAD_REQUEST_400
84 })
85 })
86
87 it('Should fail with an invalid end date', async function () {
88 await servers[0].videoStats.getOverallStats({
89 videoId,
90 startDate: new Date().toISOString(),
91 endDate: 'fake' as any,
92 expectedStatus: HttpStatusCode.BAD_REQUEST_400
93 })
94 })
95
96 it('Should succeed with the correct parameters', async function () {
97 await servers[0].videoStats.getOverallStats({
98 videoId,
99 startDate: new Date().toISOString(),
100 endDate: new Date().toISOString()
101 })
102 })
103 })
104
105 describe('When getting timeserie stats', function () {
106
107 it('Should fail with a remote video', async function () {
108 await servers[0].videoStats.getTimeserieStats({
109 videoId: remoteVideoId,
110 metric: 'viewers',
111 expectedStatus: HttpStatusCode.FORBIDDEN_403
112 })
113 })
114
115 it('Should fail without token', async function () {
116 await servers[0].videoStats.getTimeserieStats({
117 videoId,
118 token: null,
119 metric: 'viewers',
120 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
121 })
122 })
123
124 it('Should fail with another token', async function () {
125 await servers[0].videoStats.getTimeserieStats({
126 videoId,
127 token: userAccessToken,
128 metric: 'viewers',
129 expectedStatus: HttpStatusCode.FORBIDDEN_403
130 })
131 })
132
133 it('Should fail with an invalid metric', async function () {
134 await servers[0].videoStats.getTimeserieStats({ videoId, metric: 'hello' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
135 })
136
137 it('Should fail with an invalid start date', async function () {
138 await servers[0].videoStats.getTimeserieStats({
139 videoId,
140 metric: 'viewers',
141 startDate: 'fake' as any,
142 endDate: new Date(),
143 expectedStatus: HttpStatusCode.BAD_REQUEST_400
144 })
145 })
146
147 it('Should fail with an invalid end date', async function () {
148 await servers[0].videoStats.getTimeserieStats({
149 videoId,
150 metric: 'viewers',
151 startDate: new Date(),
152 endDate: 'fake' as any,
153 expectedStatus: HttpStatusCode.BAD_REQUEST_400
154 })
155 })
156
157 it('Should fail if start date is specified but not end date', async function () {
158 await servers[0].videoStats.getTimeserieStats({
159 videoId,
160 metric: 'viewers',
161 startDate: new Date(),
162 expectedStatus: HttpStatusCode.BAD_REQUEST_400
163 })
164 })
165
166 it('Should fail if end date is specified but not start date', async function () {
167 await servers[0].videoStats.getTimeserieStats({
168 videoId,
169 metric: 'viewers',
170 endDate: new Date(),
171 expectedStatus: HttpStatusCode.BAD_REQUEST_400
172 })
173 })
174
175 it('Should fail with a too big interval', async function () {
176 await servers[0].videoStats.getTimeserieStats({
177 videoId,
178 metric: 'viewers',
179 startDate: new Date('2000-04-07T08:31:57.126Z'),
180 endDate: new Date(),
181 expectedStatus: HttpStatusCode.BAD_REQUEST_400
182 })
183 })
184
185 it('Should succeed with the correct parameters', async function () {
186 await servers[0].videoStats.getTimeserieStats({ videoId, metric: 'viewers' })
187 })
188 })
189
190 describe('When getting retention stats', function () {
191
192 it('Should fail with a remote video', async function () {
193 await servers[0].videoStats.getRetentionStats({
194 videoId: remoteVideoId,
195 expectedStatus: HttpStatusCode.FORBIDDEN_403
196 })
197 })
198
199 it('Should fail without token', async function () {
200 await servers[0].videoStats.getRetentionStats({
201 videoId,
202 token: null,
203 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
204 })
205 })
206
207 it('Should fail with another token', async function () {
208 await servers[0].videoStats.getRetentionStats({
209 videoId,
210 token: userAccessToken,
211 expectedStatus: HttpStatusCode.FORBIDDEN_403
212 })
213 })
214
215 it('Should fail on live video', async function () {
216 await servers[0].videoStats.getRetentionStats({ videoId: liveVideoId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
217 })
218
219 it('Should succeed with the correct parameters', async function () {
220 await servers[0].videoStats.getRetentionStats({ videoId })
221 })
222 })
223
224 after(async function () {
225 await cleanupTests(servers)
226 })
227})