aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests
diff options
context:
space:
mode:
Diffstat (limited to 'server/tests')
-rw-r--r--server/tests/api/check-params/custom-pages.ts81
-rw-r--r--server/tests/api/check-params/index.ts2
-rw-r--r--server/tests/api/check-params/plugins.ts12
-rw-r--r--server/tests/api/check-params/upload-quota.ts152
-rw-r--r--server/tests/api/check-params/users.ts105
-rw-r--r--server/tests/api/check-params/videos.ts393
-rw-r--r--server/tests/api/live/live-constraints.ts70
-rw-r--r--server/tests/api/live/live-permanent.ts21
-rw-r--r--server/tests/api/live/live-save-replay.ts11
-rw-r--r--server/tests/api/moderation/blocklist.ts56
-rw-r--r--server/tests/api/notifications/comments-notifications.ts25
-rw-r--r--server/tests/api/server/bulk.ts9
-rw-r--r--server/tests/api/server/follow-constraints.ts2
-rw-r--r--server/tests/api/server/follows.ts48
-rw-r--r--server/tests/api/server/handle-down.ts14
-rw-r--r--server/tests/api/server/homepage.ts85
-rw-r--r--server/tests/api/server/index.ts1
-rw-r--r--server/tests/api/server/plugins.ts12
-rw-r--r--server/tests/api/users/users-multiple-servers.ts28
-rw-r--r--server/tests/api/videos/index.ts1
-rw-r--r--server/tests/api/videos/multiple-servers.ts15
-rw-r--r--server/tests/api/videos/resumable-upload.ts187
-rw-r--r--server/tests/api/videos/single-server.ts724
-rw-r--r--server/tests/api/videos/video-channels.ts82
-rw-r--r--server/tests/api/videos/video-comments.ts3
-rw-r--r--server/tests/api/videos/video-transcoder.ts159
-rw-r--r--server/tests/client.ts28
-rw-r--r--server/tests/fixtures/peertube-plugin-test-four/main.js5
-rw-r--r--server/tests/plugins/filter-hooks.ts8
-rw-r--r--server/tests/plugins/plugin-helpers.ts1
-rw-r--r--server/tests/plugins/plugin-transcoding.ts20
31 files changed, 1394 insertions, 966 deletions
diff --git a/server/tests/api/check-params/custom-pages.ts b/server/tests/api/check-params/custom-pages.ts
new file mode 100644
index 000000000..74ca3384c
--- /dev/null
+++ b/server/tests/api/check-params/custom-pages.ts
@@ -0,0 +1,81 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
5import {
6 cleanupTests,
7 createUser,
8 flushAndRunServer,
9 ServerInfo,
10 setAccessTokensToServers,
11 userLogin
12} from '../../../../shared/extra-utils'
13import { makeGetRequest, makePutBodyRequest } from '../../../../shared/extra-utils/requests/requests'
14
15describe('Test custom pages validators', function () {
16 const path = '/api/v1/custom-pages/homepage/instance'
17
18 let server: ServerInfo
19 let userAccessToken: string
20
21 // ---------------------------------------------------------------
22
23 before(async function () {
24 this.timeout(120000)
25
26 server = await flushAndRunServer(1)
27 await setAccessTokensToServers([ server ])
28
29 const user = { username: 'user1', password: 'password' }
30 await createUser({ url: server.url, accessToken: server.accessToken, username: user.username, password: user.password })
31
32 userAccessToken = await userLogin(server, user)
33 })
34
35 describe('When updating instance homepage', function () {
36
37 it('Should fail with an unauthenticated user', async function () {
38 await makePutBodyRequest({
39 url: server.url,
40 path,
41 fields: { content: 'super content' },
42 statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
43 })
44 })
45
46 it('Should fail with a non admin user', async function () {
47 await makePutBodyRequest({
48 url: server.url,
49 path,
50 token: userAccessToken,
51 fields: { content: 'super content' },
52 statusCodeExpected: HttpStatusCode.FORBIDDEN_403
53 })
54 })
55
56 it('Should succeed with the correct params', async function () {
57 await makePutBodyRequest({
58 url: server.url,
59 path,
60 token: server.accessToken,
61 fields: { content: 'super content' },
62 statusCodeExpected: HttpStatusCode.NO_CONTENT_204
63 })
64 })
65 })
66
67 describe('When getting instance homapage', function () {
68
69 it('Should succeed with the correct params', async function () {
70 await makeGetRequest({
71 url: server.url,
72 path,
73 statusCodeExpected: HttpStatusCode.OK_200
74 })
75 })
76 })
77
78 after(async function () {
79 await cleanupTests([ server ])
80 })
81})
diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts
index d0b0b9c21..ce2335e42 100644
--- a/server/tests/api/check-params/index.ts
+++ b/server/tests/api/check-params/index.ts
@@ -3,6 +3,7 @@ import './accounts'
3import './blocklist' 3import './blocklist'
4import './bulk' 4import './bulk'
5import './config' 5import './config'
6import './custom-pages'
6import './contact-form' 7import './contact-form'
7import './debug' 8import './debug'
8import './follows' 9import './follows'
@@ -13,6 +14,7 @@ import './plugins'
13import './redundancy' 14import './redundancy'
14import './search' 15import './search'
15import './services' 16import './services'
17import './upload-quota'
16import './user-notifications' 18import './user-notifications'
17import './user-subscriptions' 19import './user-subscriptions'
18import './users' 20import './users'
diff --git a/server/tests/api/check-params/plugins.ts b/server/tests/api/check-params/plugins.ts
index 6e540bcbb..a833fe6ff 100644
--- a/server/tests/api/check-params/plugins.ts
+++ b/server/tests/api/check-params/plugins.ts
@@ -1,7 +1,7 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4import { HttpStatusCode } from '@shared/core-utils'
5import { 5import {
6 checkBadCountPagination, 6 checkBadCountPagination,
7 checkBadSortPagination, 7 checkBadSortPagination,
@@ -11,14 +11,14 @@ import {
11 flushAndRunServer, 11 flushAndRunServer,
12 immutableAssign, 12 immutableAssign,
13 installPlugin, 13 installPlugin,
14 makeGetRequest, makePostBodyRequest, makePutBodyRequest, 14 makeGetRequest,
15 makePostBodyRequest,
16 makePutBodyRequest,
15 ServerInfo, 17 ServerInfo,
16 setAccessTokensToServers, 18 setAccessTokensToServers,
17 userLogin 19 userLogin
18} from '../../../../shared/extra-utils' 20} from '@shared/extra-utils'
19import { PluginType } from '../../../../shared/models/plugins/plugin.type' 21import { PeerTubePlugin, PluginType } from '@shared/models'
20import { PeerTubePlugin } from '../../../../shared/models/plugins/peertube-plugin.model'
21import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
22 22
23describe('Test server plugins API validators', function () { 23describe('Test server plugins API validators', function () {
24 let server: ServerInfo 24 let server: ServerInfo
diff --git a/server/tests/api/check-params/upload-quota.ts b/server/tests/api/check-params/upload-quota.ts
new file mode 100644
index 000000000..d0fbec415
--- /dev/null
+++ b/server/tests/api/check-params/upload-quota.ts
@@ -0,0 +1,152 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import { expect } from 'chai'
5import { HttpStatusCode, randomInt } from '@shared/core-utils'
6import { getGoodVideoUrl, getMagnetURI, getMyVideoImports, importVideo } from '@shared/extra-utils/videos/video-imports'
7import { MyUser, VideoImport, VideoImportState, VideoPrivacy } from '@shared/models'
8import {
9 cleanupTests,
10 flushAndRunServer,
11 getMyUserInformation,
12 immutableAssign,
13 registerUser,
14 ServerInfo,
15 setAccessTokensToServers,
16 setDefaultVideoChannel,
17 updateUser,
18 uploadVideo,
19 userLogin,
20 waitJobs
21} from '../../../../shared/extra-utils'
22
23describe('Test upload quota', function () {
24 let server: ServerInfo
25 let rootId: number
26
27 // ---------------------------------------------------------------
28
29 before(async function () {
30 this.timeout(30000)
31
32 server = await flushAndRunServer(1)
33 await setAccessTokensToServers([ server ])
34 await setDefaultVideoChannel([ server ])
35
36 const res = await getMyUserInformation(server.url, server.accessToken)
37 rootId = (res.body as MyUser).id
38
39 await updateUser({
40 url: server.url,
41 userId: rootId,
42 accessToken: server.accessToken,
43 videoQuota: 42
44 })
45 })
46
47 describe('When having a video quota', function () {
48
49 it('Should fail with a registered user having too many videos with legacy upload', async function () {
50 this.timeout(30000)
51
52 const user = { username: 'registered' + randomInt(1, 1500), password: 'password' }
53 await registerUser(server.url, user.username, user.password)
54 const userAccessToken = await userLogin(server, user)
55
56 const videoAttributes = { fixture: 'video_short2.webm' }
57 for (let i = 0; i < 5; i++) {
58 await uploadVideo(server.url, userAccessToken, videoAttributes)
59 }
60
61 await uploadVideo(server.url, userAccessToken, videoAttributes, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'legacy')
62 })
63
64 it('Should fail with a registered user having too many videos with resumable upload', async function () {
65 this.timeout(30000)
66
67 const user = { username: 'registered' + randomInt(1, 1500), password: 'password' }
68 await registerUser(server.url, user.username, user.password)
69 const userAccessToken = await userLogin(server, user)
70
71 const videoAttributes = { fixture: 'video_short2.webm' }
72 for (let i = 0; i < 5; i++) {
73 await uploadVideo(server.url, userAccessToken, videoAttributes)
74 }
75
76 await uploadVideo(server.url, userAccessToken, videoAttributes, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'resumable')
77 })
78
79 it('Should fail to import with HTTP/Torrent/magnet', async function () {
80 this.timeout(120000)
81
82 const baseAttributes = {
83 channelId: server.videoChannel.id,
84 privacy: VideoPrivacy.PUBLIC
85 }
86 await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { targetUrl: getGoodVideoUrl() }))
87 await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { magnetUri: getMagnetURI() }))
88 await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { torrentfile: 'video-720p.torrent' as any }))
89
90 await waitJobs([ server ])
91
92 const res = await getMyVideoImports(server.url, server.accessToken)
93
94 expect(res.body.total).to.equal(3)
95 const videoImports: VideoImport[] = res.body.data
96 expect(videoImports).to.have.lengthOf(3)
97
98 for (const videoImport of videoImports) {
99 expect(videoImport.state.id).to.equal(VideoImportState.FAILED)
100 expect(videoImport.error).not.to.be.undefined
101 expect(videoImport.error).to.contain('user video quota is exceeded')
102 }
103 })
104 })
105
106 describe('When having a daily video quota', function () {
107
108 it('Should fail with a user having too many videos daily', async function () {
109 await updateUser({
110 url: server.url,
111 userId: rootId,
112 accessToken: server.accessToken,
113 videoQuotaDaily: 42
114 })
115
116 await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'legacy')
117 await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'resumable')
118 })
119 })
120
121 describe('When having an absolute and daily video quota', function () {
122 it('Should fail if exceeding total quota', async function () {
123 await updateUser({
124 url: server.url,
125 userId: rootId,
126 accessToken: server.accessToken,
127 videoQuota: 42,
128 videoQuotaDaily: 1024 * 1024 * 1024
129 })
130
131 await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'legacy')
132 await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'resumable')
133 })
134
135 it('Should fail if exceeding daily quota', async function () {
136 await updateUser({
137 url: server.url,
138 userId: rootId,
139 accessToken: server.accessToken,
140 videoQuota: 1024 * 1024 * 1024,
141 videoQuotaDaily: 42
142 })
143
144 await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'legacy')
145 await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413, 'resumable')
146 })
147 })
148
149 after(async function () {
150 await cleanupTests([ server ])
151 })
152})
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts
index 2b03fde2d..dcff0d52b 100644
--- a/server/tests/api/check-params/users.ts
+++ b/server/tests/api/check-params/users.ts
@@ -1,10 +1,10 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { expect } from 'chai'
5import { omit } from 'lodash' 4import { omit } from 'lodash'
6import { join } from 'path' 5import { join } from 'path'
7import { User, UserRole, VideoImport, VideoImportState } from '../../../../shared' 6import { User, UserRole } from '../../../../shared'
7import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
8import { 8import {
9 addVideoChannel, 9 addVideoChannel,
10 blockUser, 10 blockUser,
@@ -29,7 +29,6 @@ import {
29 ServerInfo, 29 ServerInfo,
30 setAccessTokensToServers, 30 setAccessTokensToServers,
31 unblockUser, 31 unblockUser,
32 updateUser,
33 uploadVideo, 32 uploadVideo,
34 userLogin 33 userLogin
35} from '../../../../shared/extra-utils' 34} from '../../../../shared/extra-utils'
@@ -39,11 +38,7 @@ import {
39 checkBadSortPagination, 38 checkBadSortPagination,
40 checkBadStartPagination 39 checkBadStartPagination
41} from '../../../../shared/extra-utils/requests/check-api-params' 40} from '../../../../shared/extra-utils/requests/check-api-params'
42import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
43import { getGoodVideoUrl, getMagnetURI, getMyVideoImports, importVideo } from '../../../../shared/extra-utils/videos/video-imports'
44import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' 41import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
45import { VideoPrivacy } from '../../../../shared/models/videos'
46import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
47 42
48describe('Test users API validators', function () { 43describe('Test users API validators', function () {
49 const path = '/api/v1/users/' 44 const path = '/api/v1/users/'
@@ -1093,102 +1088,6 @@ describe('Test users API validators', function () {
1093 }) 1088 })
1094 }) 1089 })
1095 1090
1096 describe('When having a video quota', function () {
1097 it('Should fail with a user having too many videos', async function () {
1098 await updateUser({
1099 url: server.url,
1100 userId: rootId,
1101 accessToken: server.accessToken,
1102 videoQuota: 42
1103 })
1104
1105 await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413)
1106 })
1107
1108 it('Should fail with a registered user having too many videos', async function () {
1109 this.timeout(30000)
1110
1111 const user = {
1112 username: 'user3',
1113 password: 'my super password'
1114 }
1115 userAccessToken = await userLogin(server, user)
1116
1117 const videoAttributes = { fixture: 'video_short2.webm' }
1118 await uploadVideo(server.url, userAccessToken, videoAttributes)
1119 await uploadVideo(server.url, userAccessToken, videoAttributes)
1120 await uploadVideo(server.url, userAccessToken, videoAttributes)
1121 await uploadVideo(server.url, userAccessToken, videoAttributes)
1122 await uploadVideo(server.url, userAccessToken, videoAttributes)
1123 await uploadVideo(server.url, userAccessToken, videoAttributes, HttpStatusCode.PAYLOAD_TOO_LARGE_413)
1124 })
1125
1126 it('Should fail to import with HTTP/Torrent/magnet', async function () {
1127 this.timeout(120000)
1128
1129 const baseAttributes = {
1130 channelId: 1,
1131 privacy: VideoPrivacy.PUBLIC
1132 }
1133 await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { targetUrl: getGoodVideoUrl() }))
1134 await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { magnetUri: getMagnetURI() }))
1135 await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { torrentfile: 'video-720p.torrent' as any }))
1136
1137 await waitJobs([ server ])
1138
1139 const res = await getMyVideoImports(server.url, server.accessToken)
1140
1141 expect(res.body.total).to.equal(3)
1142 const videoImports: VideoImport[] = res.body.data
1143 expect(videoImports).to.have.lengthOf(3)
1144
1145 for (const videoImport of videoImports) {
1146 expect(videoImport.state.id).to.equal(VideoImportState.FAILED)
1147 expect(videoImport.error).not.to.be.undefined
1148 expect(videoImport.error).to.contain('user video quota is exceeded')
1149 }
1150 })
1151 })
1152
1153 describe('When having a daily video quota', function () {
1154 it('Should fail with a user having too many videos daily', async function () {
1155 await updateUser({
1156 url: server.url,
1157 userId: rootId,
1158 accessToken: server.accessToken,
1159 videoQuotaDaily: 42
1160 })
1161
1162 await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413)
1163 })
1164 })
1165
1166 describe('When having an absolute and daily video quota', function () {
1167 it('Should fail if exceeding total quota', async function () {
1168 await updateUser({
1169 url: server.url,
1170 userId: rootId,
1171 accessToken: server.accessToken,
1172 videoQuota: 42,
1173 videoQuotaDaily: 1024 * 1024 * 1024
1174 })
1175
1176 await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413)
1177 })
1178
1179 it('Should fail if exceeding daily quota', async function () {
1180 await updateUser({
1181 url: server.url,
1182 userId: rootId,
1183 accessToken: server.accessToken,
1184 videoQuota: 1024 * 1024 * 1024,
1185 videoQuotaDaily: 42
1186 })
1187
1188 await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413)
1189 })
1190 })
1191
1192 describe('When asking a password reset', function () { 1091 describe('When asking a password reset', function () {
1193 const path = '/api/v1/users/ask-reset-password' 1092 const path = '/api/v1/users/ask-reset-password'
1194 1093
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts
index 188d1835c..c970c4a15 100644
--- a/server/tests/api/check-params/videos.ts
+++ b/server/tests/api/check-params/videos.ts
@@ -1,11 +1,12 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha'
3import * as chai from 'chai' 4import * as chai from 'chai'
4import { omit } from 'lodash' 5import { omit } from 'lodash'
5import 'mocha'
6import { join } from 'path' 6import { join } from 'path'
7import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum' 7import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
8import { 8import {
9 checkUploadVideoParam,
9 cleanupTests, 10 cleanupTests,
10 createUser, 11 createUser,
11 flushAndRunServer, 12 flushAndRunServer,
@@ -18,17 +19,18 @@ import {
18 makePutBodyRequest, 19 makePutBodyRequest,
19 makeUploadRequest, 20 makeUploadRequest,
20 removeVideo, 21 removeVideo,
22 root,
21 ServerInfo, 23 ServerInfo,
22 setAccessTokensToServers, 24 setAccessTokensToServers,
23 userLogin, 25 userLogin
24 root
25} from '../../../../shared/extra-utils' 26} from '../../../../shared/extra-utils'
26import { 27import {
27 checkBadCountPagination, 28 checkBadCountPagination,
28 checkBadSortPagination, 29 checkBadSortPagination,
29 checkBadStartPagination 30 checkBadStartPagination
30} from '../../../../shared/extra-utils/requests/check-api-params' 31} from '../../../../shared/extra-utils/requests/check-api-params'
31import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 32import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
33import { randomInt } from '@shared/core-utils'
32 34
33const expect = chai.expect 35const expect = chai.expect
34 36
@@ -183,7 +185,7 @@ describe('Test videos API validator', function () {
183 describe('When adding a video', function () { 185 describe('When adding a video', function () {
184 let baseCorrectParams 186 let baseCorrectParams
185 const baseCorrectAttaches = { 187 const baseCorrectAttaches = {
186 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.webm') 188 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.webm')
187 } 189 }
188 190
189 before(function () { 191 before(function () {
@@ -206,256 +208,243 @@ describe('Test videos API validator', function () {
206 } 208 }
207 }) 209 })
208 210
209 it('Should fail with nothing', async function () { 211 function runSuite (mode: 'legacy' | 'resumable') {
210 const fields = {}
211 const attaches = {}
212 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
213 })
214 212
215 it('Should fail without name', async function () { 213 it('Should fail with nothing', async function () {
216 const fields = omit(baseCorrectParams, 'name') 214 const fields = {}
217 const attaches = baseCorrectAttaches 215 const attaches = {}
216 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
217 })
218 218
219 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 219 it('Should fail without name', async function () {
220 }) 220 const fields = omit(baseCorrectParams, 'name')
221 const attaches = baseCorrectAttaches
221 222
222 it('Should fail with a long name', async function () { 223 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
223 const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) }) 224 })
224 const attaches = baseCorrectAttaches
225 225
226 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 226 it('Should fail with a long name', async function () {
227 }) 227 const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) })
228 const attaches = baseCorrectAttaches
228 229
229 it('Should fail with a bad category', async function () { 230 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
230 const fields = immutableAssign(baseCorrectParams, { category: 125 }) 231 })
231 const attaches = baseCorrectAttaches
232 232
233 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 233 it('Should fail with a bad category', async function () {
234 }) 234 const fields = immutableAssign(baseCorrectParams, { category: 125 })
235 const attaches = baseCorrectAttaches
235 236
236 it('Should fail with a bad licence', async function () { 237 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
237 const fields = immutableAssign(baseCorrectParams, { licence: 125 }) 238 })
238 const attaches = baseCorrectAttaches
239 239
240 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 240 it('Should fail with a bad licence', async function () {
241 }) 241 const fields = immutableAssign(baseCorrectParams, { licence: 125 })
242 const attaches = baseCorrectAttaches
242 243
243 it('Should fail with a bad language', async function () { 244 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
244 const fields = immutableAssign(baseCorrectParams, { language: 'a'.repeat(15) }) 245 })
245 const attaches = baseCorrectAttaches
246 246
247 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 247 it('Should fail with a bad language', async function () {
248 }) 248 const fields = immutableAssign(baseCorrectParams, { language: 'a'.repeat(15) })
249 const attaches = baseCorrectAttaches
249 250
250 it('Should fail with a long description', async function () { 251 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
251 const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(2500) }) 252 })
252 const attaches = baseCorrectAttaches
253 253
254 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 254 it('Should fail with a long description', async function () {
255 }) 255 const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(2500) })
256 const attaches = baseCorrectAttaches
256 257
257 it('Should fail with a long support text', async function () { 258 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
258 const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(201) }) 259 })
259 const attaches = baseCorrectAttaches
260 260
261 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 261 it('Should fail with a long support text', async function () {
262 }) 262 const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(201) })
263 const attaches = baseCorrectAttaches
263 264
264 it('Should fail without a channel', async function () { 265 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
265 const fields = omit(baseCorrectParams, 'channelId') 266 })
266 const attaches = baseCorrectAttaches
267 267
268 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 268 it('Should fail without a channel', async function () {
269 }) 269 const fields = omit(baseCorrectParams, 'channelId')
270 const attaches = baseCorrectAttaches
270 271
271 it('Should fail with a bad channel', async function () { 272 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
272 const fields = immutableAssign(baseCorrectParams, { channelId: 545454 }) 273 })
273 const attaches = baseCorrectAttaches
274 274
275 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 275 it('Should fail with a bad channel', async function () {
276 }) 276 const fields = immutableAssign(baseCorrectParams, { channelId: 545454 })
277 const attaches = baseCorrectAttaches
277 278
278 it('Should fail with another user channel', async function () { 279 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
279 const user = { 280 })
280 username: 'fake',
281 password: 'fake_password'
282 }
283 await createUser({ url: server.url, accessToken: server.accessToken, username: user.username, password: user.password })
284 281
285 const accessTokenUser = await userLogin(server, user) 282 it('Should fail with another user channel', async function () {
286 const res = await getMyUserInformation(server.url, accessTokenUser) 283 const user = {
287 const customChannelId = res.body.videoChannels[0].id 284 username: 'fake' + randomInt(0, 1500),
285 password: 'fake_password'
286 }
287 await createUser({ url: server.url, accessToken: server.accessToken, username: user.username, password: user.password })
288 288
289 const fields = immutableAssign(baseCorrectParams, { channelId: customChannelId }) 289 const accessTokenUser = await userLogin(server, user)
290 const attaches = baseCorrectAttaches 290 const res = await getMyUserInformation(server.url, accessTokenUser)
291 const customChannelId = res.body.videoChannels[0].id
291 292
292 await makeUploadRequest({ url: server.url, path: path + '/upload', token: userAccessToken, fields, attaches }) 293 const fields = immutableAssign(baseCorrectParams, { channelId: customChannelId })
293 }) 294 const attaches = baseCorrectAttaches
294 295
295 it('Should fail with too many tags', async function () { 296 await checkUploadVideoParam(server.url, userAccessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
296 const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }) 297 })
297 const attaches = baseCorrectAttaches
298 298
299 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 299 it('Should fail with too many tags', async function () {
300 }) 300 const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] })
301 const attaches = baseCorrectAttaches
301 302
302 it('Should fail with a tag length too low', async function () { 303 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
303 const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 't' ] }) 304 })
304 const attaches = baseCorrectAttaches
305 305
306 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 306 it('Should fail with a tag length too low', async function () {
307 }) 307 const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 't' ] })
308 const attaches = baseCorrectAttaches
308 309
309 it('Should fail with a tag length too big', async function () { 310 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
310 const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }) 311 })
311 const attaches = baseCorrectAttaches
312 312
313 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 313 it('Should fail with a tag length too big', async function () {
314 }) 314 const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] })
315 const attaches = baseCorrectAttaches
315 316
316 it('Should fail with a bad schedule update (miss updateAt)', async function () { 317 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
317 const fields = immutableAssign(baseCorrectParams, { 'scheduleUpdate[privacy]': VideoPrivacy.PUBLIC }) 318 })
318 const attaches = baseCorrectAttaches
319 319
320 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 320 it('Should fail with a bad schedule update (miss updateAt)', async function () {
321 }) 321 const fields = immutableAssign(baseCorrectParams, { scheduleUpdate: { privacy: VideoPrivacy.PUBLIC } })
322 const attaches = baseCorrectAttaches
322 323
323 it('Should fail with a bad schedule update (wrong updateAt)', async function () { 324 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
324 const fields = immutableAssign(baseCorrectParams, {
325 'scheduleUpdate[privacy]': VideoPrivacy.PUBLIC,
326 'scheduleUpdate[updateAt]': 'toto'
327 }) 325 })
328 const attaches = baseCorrectAttaches
329 326
330 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 327 it('Should fail with a bad schedule update (wrong updateAt)', async function () {
331 }) 328 const fields = immutableAssign(baseCorrectParams, {
329 scheduleUpdate: {
330 privacy: VideoPrivacy.PUBLIC,
331 updateAt: 'toto'
332 }
333 })
334 const attaches = baseCorrectAttaches
332 335
333 it('Should fail with a bad originally published at attribute', async function () { 336 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
334 const fields = immutableAssign(baseCorrectParams, { originallyPublishedAt: 'toto' }) 337 })
335 const attaches = baseCorrectAttaches
336 338
337 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 339 it('Should fail with a bad originally published at attribute', async function () {
338 }) 340 const fields = immutableAssign(baseCorrectParams, { originallyPublishedAt: 'toto' })
341 const attaches = baseCorrectAttaches
339 342
340 it('Should fail without an input file', async function () { 343 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
341 const fields = baseCorrectParams 344 })
342 const attaches = {}
343 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
344 })
345 345
346 it('Should fail with an incorrect input file', async function () { 346 it('Should fail without an input file', async function () {
347 const fields = baseCorrectParams 347 const fields = baseCorrectParams
348 let attaches = { 348 const attaches = {}
349 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm') 349 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
350 }
351 await makeUploadRequest({
352 url: server.url,
353 path: path + '/upload',
354 token: server.accessToken,
355 fields,
356 attaches,
357 statusCodeExpected: HttpStatusCode.UNPROCESSABLE_ENTITY_422
358 }) 350 })
359 351
360 attaches = { 352 it('Should fail with an incorrect input file', async function () {
361 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv') 353 const fields = baseCorrectParams
362 } 354 let attaches = { fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm') }
363 await makeUploadRequest({ 355
364 url: server.url, 356 await checkUploadVideoParam(
365 path: path + '/upload', 357 server.url,
366 token: server.accessToken, 358 server.accessToken,
367 fields, 359 { ...fields, ...attaches },
368 attaches, 360 HttpStatusCode.UNPROCESSABLE_ENTITY_422,
369 statusCodeExpected: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415 361 mode
362 )
363
364 attaches = { fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv') }
365 await checkUploadVideoParam(
366 server.url,
367 server.accessToken,
368 { ...fields, ...attaches },
369 HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415,
370 mode
371 )
370 }) 372 })
371 })
372 373
373 it('Should fail with an incorrect thumbnail file', async function () { 374 it('Should fail with an incorrect thumbnail file', async function () {
374 const fields = baseCorrectParams 375 const fields = baseCorrectParams
375 const attaches = { 376 const attaches = {
376 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4'), 377 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4'),
377 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') 378 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
378 } 379 }
379 380
380 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 381 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
381 }) 382 })
382 383
383 it('Should fail with a big thumbnail file', async function () { 384 it('Should fail with a big thumbnail file', async function () {
384 const fields = baseCorrectParams 385 const fields = baseCorrectParams
385 const attaches = { 386 const attaches = {
386 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'preview-big.png'), 387 thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'preview-big.png'),
387 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') 388 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
388 } 389 }
389 390
390 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 391 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
391 }) 392 })
392 393
393 it('Should fail with an incorrect preview file', async function () { 394 it('Should fail with an incorrect preview file', async function () {
394 const fields = baseCorrectParams 395 const fields = baseCorrectParams
395 const attaches = { 396 const attaches = {
396 previewfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4'), 397 previewfile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4'),
397 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') 398 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
398 } 399 }
399 400
400 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 401 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
401 }) 402 })
402 403
403 it('Should fail with a big preview file', async function () { 404 it('Should fail with a big preview file', async function () {
404 const fields = baseCorrectParams 405 const fields = baseCorrectParams
405 const attaches = { 406 const attaches = {
406 previewfile: join(root(), 'server', 'tests', 'fixtures', 'preview-big.png'), 407 previewfile: join(root(), 'server', 'tests', 'fixtures', 'preview-big.png'),
407 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') 408 fixture: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
408 } 409 }
409 410
410 await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) 411 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
411 }) 412 })
412 413
413 it('Should succeed with the correct parameters', async function () { 414 it('Should succeed with the correct parameters', async function () {
414 this.timeout(10000) 415 this.timeout(10000)
415 416
416 const fields = baseCorrectParams 417 const fields = baseCorrectParams
417 418
418 { 419 {
419 const attaches = baseCorrectAttaches 420 const attaches = baseCorrectAttaches
420 await makeUploadRequest({ 421 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.OK_200, mode)
421 url: server.url, 422 }
422 path: path + '/upload',
423 token: server.accessToken,
424 fields,
425 attaches,
426 statusCodeExpected: HttpStatusCode.OK_200
427 })
428 }
429 423
430 { 424 {
431 const attaches = immutableAssign(baseCorrectAttaches, { 425 const attaches = immutableAssign(baseCorrectAttaches, {
432 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') 426 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
433 }) 427 })
434 428
435 await makeUploadRequest({ 429 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.OK_200, mode)
436 url: server.url, 430 }
437 path: path + '/upload',
438 token: server.accessToken,
439 fields,
440 attaches,
441 statusCodeExpected: HttpStatusCode.OK_200
442 })
443 }
444 431
445 { 432 {
446 const attaches = immutableAssign(baseCorrectAttaches, { 433 const attaches = immutableAssign(baseCorrectAttaches, {
447 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.ogv') 434 videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.ogv')
448 }) 435 })
449 436
450 await makeUploadRequest({ 437 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.OK_200, mode)
451 url: server.url, 438 }
452 path: path + '/upload', 439 })
453 token: server.accessToken, 440 }
454 fields, 441
455 attaches, 442 describe('Resumable upload', function () {
456 statusCodeExpected: HttpStatusCode.OK_200 443 runSuite('resumable')
457 }) 444 })
458 } 445
446 describe('Legacy upload', function () {
447 runSuite('legacy')
459 }) 448 })
460 }) 449 })
461 450
@@ -678,7 +667,7 @@ describe('Test videos API validator', function () {
678 }) 667 })
679 668
680 expect(res.body.data).to.be.an('array') 669 expect(res.body.data).to.be.an('array')
681 expect(res.body.data.length).to.equal(3) 670 expect(res.body.data.length).to.equal(6)
682 }) 671 })
683 672
684 it('Should fail without a correct uuid', async function () { 673 it('Should fail without a correct uuid', async function () {
diff --git a/server/tests/api/live/live-constraints.ts b/server/tests/api/live/live-constraints.ts
index 5569e6066..cc635de33 100644
--- a/server/tests/api/live/live-constraints.ts
+++ b/server/tests/api/live/live-constraints.ts
@@ -2,15 +2,15 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { User, VideoDetails, VideoPrivacy } from '@shared/models' 5import { VideoDetails, VideoPrivacy } from '@shared/models'
6import { 6import {
7 checkLiveCleanup, 7 checkLiveCleanup,
8 cleanupTests, 8 cleanupTests,
9 createLive, 9 createLive,
10 createUser,
11 doubleFollow, 10 doubleFollow,
12 flushAndRunMultipleServers, 11 flushAndRunMultipleServers,
13 getMyUserInformation, 12 generateUser,
13 getCustomConfigResolutions,
14 getVideo, 14 getVideo,
15 runAndTestFfmpegStreamError, 15 runAndTestFfmpegStreamError,
16 ServerInfo, 16 ServerInfo,
@@ -18,7 +18,6 @@ import {
18 setDefaultVideoChannel, 18 setDefaultVideoChannel,
19 updateCustomSubConfig, 19 updateCustomSubConfig,
20 updateUser, 20 updateUser,
21 userLogin,
22 wait, 21 wait,
23 waitJobs, 22 waitJobs,
24 waitUntilLivePublished 23 waitUntilLivePublished
@@ -62,6 +61,16 @@ describe('Test live constraints', function () {
62 } 61 }
63 } 62 }
64 63
64 function updateQuota (options: { total: number, daily: number }) {
65 return updateUser({
66 url: servers[0].url,
67 accessToken: servers[0].accessToken,
68 userId,
69 videoQuota: options.total,
70 videoQuotaDaily: options.daily
71 })
72 }
73
65 before(async function () { 74 before(async function () {
66 this.timeout(120000) 75 this.timeout(120000)
67 76
@@ -82,27 +91,12 @@ describe('Test live constraints', function () {
82 }) 91 })
83 92
84 { 93 {
85 const user = { username: 'user1', password: 'superpassword' } 94 const res = await generateUser(servers[0], 'user1')
86 const res = await createUser({ 95 userId = res.userId
87 url: servers[0].url, 96 userChannelId = res.userChannelId
88 accessToken: servers[0].accessToken, 97 userAccessToken = res.token
89 username: user.username, 98
90 password: user.password 99 await updateQuota({ total: 1, daily: -1 })
91 })
92 userId = res.body.user.id
93
94 userAccessToken = await userLogin(servers[0], user)
95
96 const resMe = await getMyUserInformation(servers[0].url, userAccessToken)
97 userChannelId = (resMe.body as User).videoChannels[0].id
98
99 await updateUser({
100 url: servers[0].url,
101 userId,
102 accessToken: servers[0].accessToken,
103 videoQuota: 1,
104 videoQuotaDaily: -1
105 })
106 } 100 }
107 101
108 // Server 1 and server 2 follow each other 102 // Server 1 and server 2 follow each other
@@ -137,13 +131,7 @@ describe('Test live constraints', function () {
137 // Wait for user quota memoize cache invalidation 131 // Wait for user quota memoize cache invalidation
138 await wait(5000) 132 await wait(5000)
139 133
140 await updateUser({ 134 await updateQuota({ total: -1, daily: 1 })
141 url: servers[0].url,
142 userId,
143 accessToken: servers[0].accessToken,
144 videoQuota: -1,
145 videoQuotaDaily: 1
146 })
147 135
148 const userVideoLiveoId = await createLiveWrapper(true) 136 const userVideoLiveoId = await createLiveWrapper(true)
149 await runAndTestFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, true) 137 await runAndTestFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, true)
@@ -160,13 +148,7 @@ describe('Test live constraints', function () {
160 // Wait for user quota memoize cache invalidation 148 // Wait for user quota memoize cache invalidation
161 await wait(5000) 149 await wait(5000)
162 150
163 await updateUser({ 151 await updateQuota({ total: 10 * 1000 * 1000, daily: -1 })
164 url: servers[0].url,
165 userId,
166 accessToken: servers[0].accessToken,
167 videoQuota: 10 * 1000 * 1000,
168 videoQuotaDaily: -1
169 })
170 152
171 const userVideoLiveoId = await createLiveWrapper(true) 153 const userVideoLiveoId = await createLiveWrapper(true)
172 await runAndTestFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, false) 154 await runAndTestFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, false)
@@ -182,15 +164,7 @@ describe('Test live constraints', function () {
182 maxDuration: 1, 164 maxDuration: 1,
183 transcoding: { 165 transcoding: {
184 enabled: true, 166 enabled: true,
185 resolutions: { 167 resolutions: getCustomConfigResolutions(true)
186 '240p': true,
187 '360p': true,
188 '480p': true,
189 '720p': true,
190 '1080p': true,
191 '1440p': true,
192 '2160p': true
193 }
194 } 168 }
195 } 169 }
196 }) 170 })
diff --git a/server/tests/api/live/live-permanent.ts b/server/tests/api/live/live-permanent.ts
index a5bda009f..d52e8c7e4 100644
--- a/server/tests/api/live/live-permanent.ts
+++ b/server/tests/api/live/live-permanent.ts
@@ -8,6 +8,7 @@ import {
8 createLive, 8 createLive,
9 doubleFollow, 9 doubleFollow,
10 flushAndRunMultipleServers, 10 flushAndRunMultipleServers,
11 getCustomConfigResolutions,
11 getLive, 12 getLive,
12 getPlaylistsCount, 13 getPlaylistsCount,
13 getVideo, 14 getVideo,
@@ -69,15 +70,7 @@ describe('Permenant live', function () {
69 maxDuration: -1, 70 maxDuration: -1,
70 transcoding: { 71 transcoding: {
71 enabled: true, 72 enabled: true,
72 resolutions: { 73 resolutions: getCustomConfigResolutions(true)
73 '240p': true,
74 '360p': true,
75 '480p': true,
76 '720p': true,
77 '1080p': true,
78 '1440p': true,
79 '2160p': true
80 }
81 } 74 }
82 } 75 }
83 }) 76 })
@@ -159,15 +152,7 @@ describe('Permenant live', function () {
159 maxDuration: -1, 152 maxDuration: -1,
160 transcoding: { 153 transcoding: {
161 enabled: true, 154 enabled: true,
162 resolutions: { 155 resolutions: getCustomConfigResolutions(false)
163 '240p': false,
164 '360p': false,
165 '480p': false,
166 '720p': false,
167 '1080p': false,
168 '1440p': false,
169 '2160p': false
170 }
171 } 156 }
172 } 157 }
173 }) 158 })
diff --git a/server/tests/api/live/live-save-replay.ts b/server/tests/api/live/live-save-replay.ts
index 61c8e74dd..3d4736c8f 100644
--- a/server/tests/api/live/live-save-replay.ts
+++ b/server/tests/api/live/live-save-replay.ts
@@ -12,6 +12,7 @@ import {
12 createLive, 12 createLive,
13 doubleFollow, 13 doubleFollow,
14 flushAndRunMultipleServers, 14 flushAndRunMultipleServers,
15 getCustomConfigResolutions,
15 getVideo, 16 getVideo,
16 getVideosList, 17 getVideosList,
17 removeVideo, 18 removeVideo,
@@ -108,15 +109,7 @@ describe('Save replay setting', function () {
108 maxDuration: -1, 109 maxDuration: -1,
109 transcoding: { 110 transcoding: {
110 enabled: false, 111 enabled: false,
111 resolutions: { 112 resolutions: getCustomConfigResolutions(true)
112 '240p': true,
113 '360p': true,
114 '480p': true,
115 '720p': true,
116 '1080p': true,
117 '1440p': true,
118 '2160p': true
119 }
120 } 113 }
121 } 114 }
122 }) 115 })
diff --git a/server/tests/api/moderation/blocklist.ts b/server/tests/api/moderation/blocklist.ts
index e8202aff1..b767d38c7 100644
--- a/server/tests/api/moderation/blocklist.ts
+++ b/server/tests/api/moderation/blocklist.ts
@@ -1,46 +1,50 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
5import { AccountBlock, ServerBlock, Video, UserNotification, UserNotificationType } from '../../../../shared/index' 4import * as chai from 'chai'
6import { 5import {
6 addAccountToAccountBlocklist,
7 addAccountToServerBlocklist,
8 addServerToAccountBlocklist,
9 addServerToServerBlocklist,
10 addVideoCommentReply,
11 addVideoCommentThread,
7 cleanupTests, 12 cleanupTests,
8 createUser, 13 createUser,
9 deleteVideoComment, 14 deleteVideoComment,
10 doubleFollow, 15 doubleFollow,
16 findCommentId,
11 flushAndRunMultipleServers, 17 flushAndRunMultipleServers,
12 ServerInfo,
13 uploadVideo,
14 userLogin,
15 follow, 18 follow,
16 unfollow
17} from '../../../../shared/extra-utils/index'
18import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
19import { getVideosList, getVideosListWithToken } from '../../../../shared/extra-utils/videos/videos'
20import {
21 addVideoCommentReply,
22 addVideoCommentThread,
23 getVideoCommentThreads,
24 getVideoThreadComments,
25 findCommentId
26} from '../../../../shared/extra-utils/videos/video-comments'
27import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
28import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
29import {
30 addAccountToAccountBlocklist,
31 addAccountToServerBlocklist,
32 addServerToAccountBlocklist,
33 addServerToServerBlocklist,
34 getAccountBlocklistByAccount, 19 getAccountBlocklistByAccount,
35 getAccountBlocklistByServer, 20 getAccountBlocklistByServer,
36 getServerBlocklistByAccount, 21 getServerBlocklistByAccount,
37 getServerBlocklistByServer, 22 getServerBlocklistByServer,
23 getUserNotifications,
24 getVideoCommentThreads,
25 getVideosList,
26 getVideosListWithToken,
27 getVideoThreadComments,
38 removeAccountFromAccountBlocklist, 28 removeAccountFromAccountBlocklist,
39 removeAccountFromServerBlocklist, 29 removeAccountFromServerBlocklist,
40 removeServerFromAccountBlocklist, 30 removeServerFromAccountBlocklist,
41 removeServerFromServerBlocklist 31 removeServerFromServerBlocklist,
42} from '../../../../shared/extra-utils/users/blocklist' 32 ServerInfo,
43import { getUserNotifications } from '../../../../shared/extra-utils/users/user-notifications' 33 setAccessTokensToServers,
34 unfollow,
35 uploadVideo,
36 userLogin,
37 waitJobs
38} from '@shared/extra-utils'
39import {
40 AccountBlock,
41 ServerBlock,
42 UserNotification,
43 UserNotificationType,
44 Video,
45 VideoComment,
46 VideoCommentThreadTree
47} from '@shared/models'
44 48
45const expect = chai.expect 49const expect = chai.expect
46 50
diff --git a/server/tests/api/notifications/comments-notifications.ts b/server/tests/api/notifications/comments-notifications.ts
index 5e4ab0d6c..d2badf237 100644
--- a/server/tests/api/notifications/comments-notifications.ts
+++ b/server/tests/api/notifications/comments-notifications.ts
@@ -2,20 +2,25 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { cleanupTests, getVideoCommentThreads, getVideoThreadComments, updateMyUser } from '../../../../shared/extra-utils'
6import { ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index'
7import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
8import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
9import { addAccountToAccountBlocklist, removeAccountFromAccountBlocklist } from '../../../../shared/extra-utils/users/blocklist'
10import { 5import {
6 addAccountToAccountBlocklist,
7 addVideoCommentReply,
8 addVideoCommentThread,
11 checkCommentMention, 9 checkCommentMention,
12 CheckerBaseParams, 10 CheckerBaseParams,
13 checkNewCommentOnMyVideo, 11 checkNewCommentOnMyVideo,
14 prepareNotificationsTest 12 cleanupTests,
15} from '../../../../shared/extra-utils/users/user-notifications' 13 getVideoCommentThreads,
16import { addVideoCommentReply, addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments' 14 getVideoThreadComments,
17import { UserNotification } from '../../../../shared/models/users' 15 MockSmtpServer,
18import { VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' 16 prepareNotificationsTest,
17 removeAccountFromAccountBlocklist,
18 ServerInfo,
19 updateMyUser,
20 uploadVideo,
21 waitJobs
22} from '@shared/extra-utils'
23import { UserNotification, VideoCommentThreadTree } from '@shared/models'
19 24
20const expect = chai.expect 25const expect = chai.expect
21 26
diff --git a/server/tests/api/server/bulk.ts b/server/tests/api/server/bulk.ts
index 51ba0e7af..80fa7fce6 100644
--- a/server/tests/api/server/bulk.ts
+++ b/server/tests/api/server/bulk.ts
@@ -2,12 +2,14 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { VideoComment } from '@shared/models/videos/video-comment.model' 5import { Video, VideoComment } from '@shared/models'
6import { 6import {
7 addVideoCommentReply,
7 addVideoCommentThread, 8 addVideoCommentThread,
8 bulkRemoveCommentsOf, 9 bulkRemoveCommentsOf,
9 cleanupTests, 10 cleanupTests,
10 createUser, 11 createUser,
12 doubleFollow,
11 flushAndRunMultipleServers, 13 flushAndRunMultipleServers,
12 getVideoCommentThreads, 14 getVideoCommentThreads,
13 getVideosList, 15 getVideosList,
@@ -15,11 +17,8 @@ import {
15 setAccessTokensToServers, 17 setAccessTokensToServers,
16 uploadVideo, 18 uploadVideo,
17 userLogin, 19 userLogin,
18 waitJobs, 20 waitJobs
19 addVideoCommentReply
20} from '../../../../shared/extra-utils/index' 21} from '../../../../shared/extra-utils/index'
21import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
22import { Video } from '@shared/models'
23 22
24const expect = chai.expect 23const expect = chai.expect
25 24
diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts
index 0846b04f4..8a91fbba3 100644
--- a/server/tests/api/server/follow-constraints.ts
+++ b/server/tests/api/server/follow-constraints.ts
@@ -28,7 +28,7 @@ describe('Test follow constraints', function () {
28 let userAccessToken: string 28 let userAccessToken: string
29 29
30 before(async function () { 30 before(async function () {
31 this.timeout(60000) 31 this.timeout(90000)
32 32
33 servers = await flushAndRunMultipleServers(2) 33 servers = await flushAndRunMultipleServers(2)
34 34
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts
index eb9ab10eb..e1c062020 100644
--- a/server/tests/api/server/follows.ts
+++ b/server/tests/api/server/follows.ts
@@ -1,37 +1,35 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
5import { Video, VideoPrivacy } from '../../../../shared/models/videos' 4import * as chai from 'chai'
6import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
7import { cleanupTests, completeVideoCheck, deleteVideoComment } from '../../../../shared/extra-utils'
8import { 5import {
6 addVideoCommentReply,
7 addVideoCommentThread,
8 cleanupTests,
9 completeVideoCheck,
10 createUser,
11 createVideoCaption,
12 dateIsValid,
13 deleteVideoComment,
14 expectAccountFollows,
9 flushAndRunMultipleServers, 15 flushAndRunMultipleServers,
10 getVideosList,
11 ServerInfo,
12 setAccessTokensToServers,
13 uploadVideo
14} from '../../../../shared/extra-utils/index'
15import { dateIsValid } from '../../../../shared/extra-utils/miscs/miscs'
16import {
17 follow, 16 follow,
18 getFollowersListPaginationAndSort, 17 getFollowersListPaginationAndSort,
19 getFollowingListPaginationAndSort, 18 getFollowingListPaginationAndSort,
20 unfollow
21} from '../../../../shared/extra-utils/server/follows'
22import { expectAccountFollows } from '../../../../shared/extra-utils/users/accounts'
23import { userLogin } from '../../../../shared/extra-utils/users/login'
24import { createUser } from '../../../../shared/extra-utils/users/users'
25import {
26 addVideoCommentReply,
27 addVideoCommentThread,
28 getVideoCommentThreads, 19 getVideoCommentThreads,
29 getVideoThreadComments 20 getVideosList,
30} from '../../../../shared/extra-utils/videos/video-comments' 21 getVideoThreadComments,
31import { rateVideo } from '../../../../shared/extra-utils/videos/videos' 22 listVideoCaptions,
32import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 23 rateVideo,
33import { createVideoCaption, listVideoCaptions, testCaptionFile } from '../../../../shared/extra-utils/videos/video-captions' 24 ServerInfo,
34import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model' 25 setAccessTokensToServers,
26 testCaptionFile,
27 unfollow,
28 uploadVideo,
29 userLogin,
30 waitJobs
31} from '@shared/extra-utils'
32import { Video, VideoCaption, VideoComment, VideoCommentThreadTree, VideoPrivacy } from '@shared/models'
35 33
36const expect = chai.expect 34const expect = chai.expect
37 35
diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts
index f3ba11950..fe4a0e100 100644
--- a/server/tests/api/server/handle-down.ts
+++ b/server/tests/api/server/handle-down.ts
@@ -4,7 +4,7 @@ import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { JobState, Video } from '../../../../shared/models' 5import { JobState, Video } from '../../../../shared/models'
6import { VideoPrivacy } from '../../../../shared/models/videos' 6import { VideoPrivacy } from '../../../../shared/models/videos'
7import { VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' 7import { VideoCommentThreadTree } from '../../../../shared/models/videos/comment/video-comment.model'
8 8
9import { 9import {
10 cleanupTests, 10 cleanupTests,
@@ -143,7 +143,7 @@ describe('Test handle downs', function () {
143 await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes) 143 await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
144 } 144 }
145 145
146 await waitJobs(servers[0]) 146 await waitJobs([ servers[0], servers[2] ])
147 147
148 // Kill server 3 148 // Kill server 3
149 killallServers([ servers[2] ]) 149 killallServers([ servers[2] ])
@@ -346,10 +346,12 @@ describe('Test handle downs', function () {
346 // Wait video expiration 346 // Wait video expiration
347 await wait(11000) 347 await wait(11000)
348 348
349 for (let i = 0; i < 3; i++) { 349 for (let i = 0; i < 5; i++) {
350 await getVideo(servers[1].url, videoIdsServer1[i]) 350 try {
351 await waitJobs([ servers[1] ]) 351 await getVideo(servers[1].url, videoIdsServer1[i])
352 await wait(1500) 352 await waitJobs([ servers[1] ])
353 await wait(1500)
354 } catch {}
353 } 355 }
354 356
355 for (const id of videoIdsServer1) { 357 for (const id of videoIdsServer1) {
diff --git a/server/tests/api/server/homepage.ts b/server/tests/api/server/homepage.ts
new file mode 100644
index 000000000..e8ba89ca6
--- /dev/null
+++ b/server/tests/api/server/homepage.ts
@@ -0,0 +1,85 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import { HttpStatusCode } from '@shared/core-utils'
6import { CustomPage, ServerConfig } from '@shared/models'
7import {
8 cleanupTests,
9 flushAndRunServer,
10 getConfig,
11 getInstanceHomepage,
12 killallServers,
13 reRunServer,
14 ServerInfo,
15 setAccessTokensToServers,
16 updateInstanceHomepage
17} from '../../../../shared/extra-utils/index'
18
19const expect = chai.expect
20
21async function getHomepageState (server: ServerInfo) {
22 const res = await getConfig(server.url)
23
24 const config = res.body as ServerConfig
25 return config.homepage.enabled
26}
27
28describe('Test instance homepage actions', function () {
29 let server: ServerInfo
30
31 before(async function () {
32 this.timeout(30000)
33
34 server = await flushAndRunServer(1)
35 await setAccessTokensToServers([ server ])
36 })
37
38 it('Should not have a homepage', async function () {
39 const state = await getHomepageState(server)
40 expect(state).to.be.false
41
42 await getInstanceHomepage(server.url, HttpStatusCode.NOT_FOUND_404)
43 })
44
45 it('Should set a homepage', async function () {
46 await updateInstanceHomepage(server.url, server.accessToken, '<picsou-magazine></picsou-magazine>')
47
48 const res = await getInstanceHomepage(server.url)
49 const page: CustomPage = res.body
50 expect(page.content).to.equal('<picsou-magazine></picsou-magazine>')
51
52 const state = await getHomepageState(server)
53 expect(state).to.be.true
54 })
55
56 it('Should have the same homepage after a restart', async function () {
57 this.timeout(30000)
58
59 killallServers([ server ])
60
61 await reRunServer(server)
62
63 const res = await getInstanceHomepage(server.url)
64 const page: CustomPage = res.body
65 expect(page.content).to.equal('<picsou-magazine></picsou-magazine>')
66
67 const state = await getHomepageState(server)
68 expect(state).to.be.true
69 })
70
71 it('Should empty the homepage', async function () {
72 await updateInstanceHomepage(server.url, server.accessToken, '')
73
74 const res = await getInstanceHomepage(server.url)
75 const page: CustomPage = res.body
76 expect(page.content).to.be.empty
77
78 const state = await getHomepageState(server)
79 expect(state).to.be.false
80 })
81
82 after(async function () {
83 await cleanupTests([ server ])
84 })
85})
diff --git a/server/tests/api/server/index.ts b/server/tests/api/server/index.ts
index be743973a..56e6eb5da 100644
--- a/server/tests/api/server/index.ts
+++ b/server/tests/api/server/index.ts
@@ -5,6 +5,7 @@ import './email'
5import './follow-constraints' 5import './follow-constraints'
6import './follows' 6import './follows'
7import './follows-moderation' 7import './follows-moderation'
8import './homepage'
8import './handle-down' 9import './handle-down'
9import './jobs' 10import './jobs'
10import './logs' 11import './logs'
diff --git a/server/tests/api/server/plugins.ts b/server/tests/api/server/plugins.ts
index 1c6eabe6d..6046ab97e 100644
--- a/server/tests/api/server/plugins.ts
+++ b/server/tests/api/server/plugins.ts
@@ -28,14 +28,8 @@ import {
28 updatePluginSettings, 28 updatePluginSettings,
29 wait, 29 wait,
30 waitUntilLog 30 waitUntilLog
31} from '../../../../shared/extra-utils' 31} from '@shared/extra-utils'
32import { PeerTubePluginIndex } from '../../../../shared/models/plugins/peertube-plugin-index.model' 32import { PeerTubePlugin, PeerTubePluginIndex, PluginPackageJson, PluginType, PublicServerSetting, ServerConfig, User } from '@shared/models'
33import { PeerTubePlugin } from '../../../../shared/models/plugins/peertube-plugin.model'
34import { PluginPackageJson } from '../../../../shared/models/plugins/plugin-package-json.model'
35import { PluginType } from '../../../../shared/models/plugins/plugin.type'
36import { PublicServerSetting } from '../../../../shared/models/plugins/public-server.setting'
37import { ServerConfig } from '../../../../shared/models/server'
38import { User } from '../../../../shared/models/users'
39 33
40const expect = chai.expect 34const expect = chai.expect
41 35
@@ -290,7 +284,7 @@ describe('Test plugins', function () {
290 }) 284 })
291 285
292 it('Should update the plugin and the theme', async function () { 286 it('Should update the plugin and the theme', async function () {
293 this.timeout(30000) 287 this.timeout(90000)
294 288
295 // Wait the scheduler that get the latest plugins versions 289 // Wait the scheduler that get the latest plugins versions
296 await wait(6000) 290 await wait(6000)
diff --git a/server/tests/api/users/users-multiple-servers.ts b/server/tests/api/users/users-multiple-servers.ts
index dcd03879b..f60c66e4b 100644
--- a/server/tests/api/users/users-multiple-servers.ts
+++ b/server/tests/api/users/users-multiple-servers.ts
@@ -130,26 +130,32 @@ describe('Test users with multiple servers', function () {
130 }) 130 })
131 131
132 it('Should have updated my profile on other servers too', async function () { 132 it('Should have updated my profile on other servers too', async function () {
133 let createdAt: string | Date
134
133 for (const server of servers) { 135 for (const server of servers) {
134 const resAccounts = await getAccountsList(server.url, '-createdAt') 136 const resAccounts = await getAccountsList(server.url, '-createdAt')
135 137
136 const rootServer1List = resAccounts.body.data.find(a => a.name === 'root' && a.host === 'localhost:' + servers[0].port) as Account 138 const resList = resAccounts.body.data.find(a => a.name === 'root' && a.host === 'localhost:' + servers[0].port) as Account
137 expect(rootServer1List).not.to.be.undefined 139 expect(resList).not.to.be.undefined
140
141 const resAccount = await getAccount(server.url, resList.name + '@' + resList.host)
142 const account = resAccount.body as Account
143
144 if (!createdAt) createdAt = account.createdAt
138 145
139 const resAccount = await getAccount(server.url, rootServer1List.name + '@' + rootServer1List.host) 146 expect(account.name).to.equal('root')
140 const rootServer1Get = resAccount.body as Account 147 expect(account.host).to.equal('localhost:' + servers[0].port)
141 expect(rootServer1Get.name).to.equal('root') 148 expect(account.displayName).to.equal('my super display name')
142 expect(rootServer1Get.host).to.equal('localhost:' + servers[0].port) 149 expect(account.description).to.equal('my super description updated')
143 expect(rootServer1Get.displayName).to.equal('my super display name') 150 expect(createdAt).to.equal(account.createdAt)
144 expect(rootServer1Get.description).to.equal('my super description updated')
145 151
146 if (server.serverNumber === 1) { 152 if (server.serverNumber === 1) {
147 expect(rootServer1Get.userId).to.be.a('number') 153 expect(account.userId).to.be.a('number')
148 } else { 154 } else {
149 expect(rootServer1Get.userId).to.be.undefined 155 expect(account.userId).to.be.undefined
150 } 156 }
151 157
152 await testImage(server.url, 'avatar2-resized', rootServer1Get.avatar.path, '.png') 158 await testImage(server.url, 'avatar2-resized', account.avatar.path, '.png')
153 } 159 }
154 }) 160 })
155 161
diff --git a/server/tests/api/videos/index.ts b/server/tests/api/videos/index.ts
index fc8b447b7..5c07f8926 100644
--- a/server/tests/api/videos/index.ts
+++ b/server/tests/api/videos/index.ts
@@ -1,5 +1,6 @@
1import './audio-only' 1import './audio-only'
2import './multiple-servers' 2import './multiple-servers'
3import './resumable-upload'
3import './single-server' 4import './single-server'
4import './video-captions' 5import './video-captions'
5import './video-change-ownership' 6import './video-change-ownership'
diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts
index 55e280e9f..6aa996038 100644
--- a/server/tests/api/videos/multiple-servers.ts
+++ b/server/tests/api/videos/multiple-servers.ts
@@ -1,11 +1,10 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
4import * as chai from 'chai'
5import { join } from 'path' 5import { join } from 'path'
6import * as request from 'supertest' 6import * as request from 'supertest'
7import { VideoPrivacy } from '../../../../shared/models/videos' 7import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
8import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
9import { 8import {
10 addVideoChannel, 9 addVideoChannel,
11 checkTmpIsEmpty, 10 checkTmpIsEmpty,
@@ -32,16 +31,16 @@ import {
32 wait, 31 wait,
33 webtorrentAdd 32 webtorrentAdd
34} from '../../../../shared/extra-utils' 33} from '../../../../shared/extra-utils'
34import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
35import { 35import {
36 addVideoCommentReply, 36 addVideoCommentReply,
37 addVideoCommentThread, 37 addVideoCommentThread,
38 deleteVideoComment, 38 deleteVideoComment,
39 findCommentId,
39 getVideoCommentThreads, 40 getVideoCommentThreads,
40 getVideoThreadComments, 41 getVideoThreadComments
41 findCommentId
42} from '../../../../shared/extra-utils/videos/video-comments' 42} from '../../../../shared/extra-utils/videos/video-comments'
43import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 43import { VideoComment, VideoCommentThreadTree, VideoPrivacy } from '../../../../shared/models/videos'
44import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
45 44
46const expect = chai.expect 45const expect = chai.expect
47 46
@@ -181,7 +180,7 @@ describe('Test multiple servers', function () {
181 thumbnailfile: 'thumbnail.jpg', 180 thumbnailfile: 'thumbnail.jpg',
182 previewfile: 'preview.jpg' 181 previewfile: 'preview.jpg'
183 } 182 }
184 await uploadVideo(servers[1].url, userAccessToken, videoAttributes) 183 await uploadVideo(servers[1].url, userAccessToken, videoAttributes, HttpStatusCode.OK_200, 'resumable')
185 184
186 // Transcoding 185 // Transcoding
187 await waitJobs(servers) 186 await waitJobs(servers)
diff --git a/server/tests/api/videos/resumable-upload.ts b/server/tests/api/videos/resumable-upload.ts
new file mode 100644
index 000000000..af9221c43
--- /dev/null
+++ b/server/tests/api/videos/resumable-upload.ts
@@ -0,0 +1,187 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import { pathExists, readdir, stat } from 'fs-extra'
6import { join } from 'path'
7import { HttpStatusCode } from '@shared/core-utils'
8import {
9 buildAbsoluteFixturePath,
10 buildServerDirectory,
11 flushAndRunServer,
12 getMyUserInformation,
13 prepareResumableUpload,
14 sendDebugCommand,
15 sendResumableChunks,
16 ServerInfo,
17 setAccessTokensToServers,
18 setDefaultVideoChannel,
19 updateUser
20} from '@shared/extra-utils'
21import { MyUser, VideoPrivacy } from '@shared/models'
22
23const expect = chai.expect
24
25// Most classic resumable upload tests are done in other test suites
26
27describe('Test resumable upload', function () {
28 const defaultFixture = 'video_short.mp4'
29 let server: ServerInfo
30 let rootId: number
31
32 async function buildSize (fixture: string, size?: number) {
33 if (size !== undefined) return size
34
35 const baseFixture = buildAbsoluteFixturePath(fixture)
36 return (await stat(baseFixture)).size
37 }
38
39 async function prepareUpload (sizeArg?: number) {
40 const size = await buildSize(defaultFixture, sizeArg)
41
42 const attributes = {
43 name: 'video',
44 channelId: server.videoChannel.id,
45 privacy: VideoPrivacy.PUBLIC,
46 fixture: defaultFixture
47 }
48
49 const mimetype = 'video/mp4'
50
51 const res = await prepareResumableUpload({ url: server.url, token: server.accessToken, attributes, size, mimetype })
52
53 return res.header['location'].split('?')[1]
54 }
55
56 async function sendChunks (options: {
57 pathUploadId: string
58 size?: number
59 expectedStatus?: HttpStatusCode
60 contentLength?: number
61 contentRange?: string
62 contentRangeBuilder?: (start: number, chunk: any) => string
63 }) {
64 const { pathUploadId, expectedStatus, contentLength, contentRangeBuilder } = options
65
66 const size = await buildSize(defaultFixture, options.size)
67 const absoluteFilePath = buildAbsoluteFixturePath(defaultFixture)
68
69 return sendResumableChunks({
70 url: server.url,
71 token: server.accessToken,
72 pathUploadId,
73 videoFilePath: absoluteFilePath,
74 size,
75 contentLength,
76 contentRangeBuilder,
77 specialStatus: expectedStatus
78 })
79 }
80
81 async function checkFileSize (uploadIdArg: string, expectedSize: number | null) {
82 const uploadId = uploadIdArg.replace(/^upload_id=/, '')
83
84 const subPath = join('tmp', 'resumable-uploads', uploadId)
85 const filePath = buildServerDirectory(server, subPath)
86 const exists = await pathExists(filePath)
87
88 if (expectedSize === null) {
89 expect(exists).to.be.false
90 return
91 }
92
93 expect(exists).to.be.true
94
95 expect((await stat(filePath)).size).to.equal(expectedSize)
96 }
97
98 async function countResumableUploads () {
99 const subPath = join('tmp', 'resumable-uploads')
100 const filePath = buildServerDirectory(server, subPath)
101
102 const files = await readdir(filePath)
103 return files.length
104 }
105
106 before(async function () {
107 this.timeout(30000)
108
109 server = await flushAndRunServer(1)
110 await setAccessTokensToServers([ server ])
111 await setDefaultVideoChannel([ server ])
112
113 const res = await getMyUserInformation(server.url, server.accessToken)
114 rootId = (res.body as MyUser).id
115
116 await updateUser({
117 url: server.url,
118 userId: rootId,
119 accessToken: server.accessToken,
120 videoQuota: 10_000_000
121 })
122 })
123
124 describe('Directory cleaning', function () {
125
126 it('Should correctly delete files after an upload', async function () {
127 const uploadId = await prepareUpload()
128 await sendChunks({ pathUploadId: uploadId })
129
130 expect(await countResumableUploads()).to.equal(0)
131 })
132
133 it('Should not delete files after an unfinished upload', async function () {
134 await prepareUpload()
135
136 expect(await countResumableUploads()).to.equal(2)
137 })
138
139 it('Should not delete recent uploads', async function () {
140 await sendDebugCommand(server.url, server.accessToken, { command: 'remove-dandling-resumable-uploads' })
141
142 expect(await countResumableUploads()).to.equal(2)
143 })
144
145 it('Should delete old uploads', async function () {
146 await sendDebugCommand(server.url, server.accessToken, { command: 'remove-dandling-resumable-uploads' })
147
148 expect(await countResumableUploads()).to.equal(0)
149 })
150 })
151
152 describe('Resumable upload and chunks', function () {
153
154 it('Should accept the same amount of chunks', async function () {
155 const uploadId = await prepareUpload()
156 await sendChunks({ pathUploadId: uploadId })
157
158 await checkFileSize(uploadId, null)
159 })
160
161 it('Should not accept more chunks than expected', async function () {
162 const size = 100
163 const uploadId = await prepareUpload(size)
164
165 await sendChunks({ pathUploadId: uploadId, expectedStatus: HttpStatusCode.CONFLICT_409 })
166 await checkFileSize(uploadId, 0)
167 })
168
169 it('Should not accept more chunks than expected with an invalid content length/content range', async function () {
170 const uploadId = await prepareUpload(1500)
171
172 await sendChunks({ pathUploadId: uploadId, expectedStatus: HttpStatusCode.BAD_REQUEST_400, contentLength: 1000 })
173 await checkFileSize(uploadId, 0)
174 })
175
176 it('Should not accept more chunks than expected with an invalid content length', async function () {
177 const uploadId = await prepareUpload(500)
178
179 const size = 1000
180
181 const contentRangeBuilder = start => `bytes ${start}-${start + size - 1}/${size}`
182 await sendChunks({ pathUploadId: uploadId, expectedStatus: HttpStatusCode.BAD_REQUEST_400, contentRangeBuilder, contentLength: size })
183 await checkFileSize(uploadId, 0)
184 })
185 })
186
187})
diff --git a/server/tests/api/videos/single-server.ts b/server/tests/api/videos/single-server.ts
index a79648bf7..1058a1e9c 100644
--- a/server/tests/api/videos/single-server.ts
+++ b/server/tests/api/videos/single-server.ts
@@ -1,9 +1,9 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha'
3import * as chai from 'chai' 4import * as chai from 'chai'
4import { keyBy } from 'lodash' 5import { keyBy } from 'lodash'
5import 'mocha' 6
6import { VideoPrivacy } from '../../../../shared/models/videos'
7import { 7import {
8 checkVideoFilesWereRemoved, 8 checkVideoFilesWereRemoved,
9 cleanupTests, 9 cleanupTests,
@@ -28,430 +28,432 @@ import {
28 viewVideo, 28 viewVideo,
29 wait 29 wait
30} from '../../../../shared/extra-utils' 30} from '../../../../shared/extra-utils'
31import { VideoPrivacy } from '../../../../shared/models/videos'
32import { HttpStatusCode } from '@shared/core-utils'
31 33
32const expect = chai.expect 34const expect = chai.expect
33 35
34describe('Test a single server', function () { 36describe('Test a single server', function () {
35 let server: ServerInfo = null
36 let videoId = -1
37 let videoId2 = -1
38 let videoUUID = ''
39 let videosListBase: any[] = null
40
41 const getCheckAttributes = () => ({
42 name: 'my super name',
43 category: 2,
44 licence: 6,
45 language: 'zh',
46 nsfw: true,
47 description: 'my super description',
48 support: 'my super support text',
49 account: {
50 name: 'root',
51 host: 'localhost:' + server.port
52 },
53 isLocal: true,
54 duration: 5,
55 tags: [ 'tag1', 'tag2', 'tag3' ],
56 privacy: VideoPrivacy.PUBLIC,
57 commentsEnabled: true,
58 downloadEnabled: true,
59 channel: {
60 displayName: 'Main root channel',
61 name: 'root_channel',
62 description: '',
63 isLocal: true
64 },
65 fixture: 'video_short.webm',
66 files: [
67 {
68 resolution: 720,
69 size: 218910
70 }
71 ]
72 })
73
74 const updateCheckAttributes = () => ({
75 name: 'my super video updated',
76 category: 4,
77 licence: 2,
78 language: 'ar',
79 nsfw: false,
80 description: 'my super description updated',
81 support: 'my super support text updated',
82 account: {
83 name: 'root',
84 host: 'localhost:' + server.port
85 },
86 isLocal: true,
87 tags: [ 'tagup1', 'tagup2' ],
88 privacy: VideoPrivacy.PUBLIC,
89 duration: 5,
90 commentsEnabled: false,
91 downloadEnabled: false,
92 channel: {
93 name: 'root_channel',
94 displayName: 'Main root channel',
95 description: '',
96 isLocal: true
97 },
98 fixture: 'video_short3.webm',
99 files: [
100 {
101 resolution: 720,
102 size: 292677
103 }
104 ]
105 })
106
107 before(async function () {
108 this.timeout(30000)
109
110 server = await flushAndRunServer(1)
111
112 await setAccessTokensToServers([ server ])
113 })
114
115 it('Should list video categories', async function () {
116 const res = await getVideoCategories(server.url)
117
118 const categories = res.body
119 expect(Object.keys(categories)).to.have.length.above(10)
120
121 expect(categories[11]).to.equal('News & Politics')
122 })
123
124 it('Should list video licences', async function () {
125 const res = await getVideoLicences(server.url)
126
127 const licences = res.body
128 expect(Object.keys(licences)).to.have.length.above(5)
129
130 expect(licences[3]).to.equal('Attribution - No Derivatives')
131 })
132
133 it('Should list video languages', async function () {
134 const res = await getVideoLanguages(server.url)
135
136 const languages = res.body
137 expect(Object.keys(languages)).to.have.length.above(5)
138
139 expect(languages['ru']).to.equal('Russian')
140 })
141
142 it('Should list video privacies', async function () {
143 const res = await getVideoPrivacies(server.url)
144
145 const privacies = res.body
146 expect(Object.keys(privacies)).to.have.length.at.least(3)
147
148 expect(privacies[3]).to.equal('Private')
149 })
150
151 it('Should not have videos', async function () {
152 const res = await getVideosList(server.url)
153
154 expect(res.body.total).to.equal(0)
155 expect(res.body.data).to.be.an('array')
156 expect(res.body.data.length).to.equal(0)
157 })
158 37
159 it('Should upload the video', async function () { 38 function runSuite (mode: 'legacy' | 'resumable') {
160 this.timeout(10000) 39 let server: ServerInfo = null
40 let videoId = -1
41 let videoId2 = -1
42 let videoUUID = ''
43 let videosListBase: any[] = null
161 44
162 const videoAttributes = { 45 const getCheckAttributes = () => ({
163 name: 'my super name', 46 name: 'my super name',
164 category: 2, 47 category: 2,
165 nsfw: true,
166 licence: 6, 48 licence: 6,
167 tags: [ 'tag1', 'tag2', 'tag3' ] 49 language: 'zh',
168 } 50 nsfw: true,
169 const res = await uploadVideo(server.url, server.accessToken, videoAttributes) 51 description: 'my super description',
170 expect(res.body.video).to.not.be.undefined 52 support: 'my super support text',
171 expect(res.body.video.id).to.equal(1) 53 account: {
172 expect(res.body.video.uuid).to.have.length.above(5) 54 name: 'root',
173 55 host: 'localhost:' + server.port
174 videoId = res.body.video.id 56 },
175 videoUUID = res.body.video.uuid 57 isLocal: true,
176 }) 58 duration: 5,
177 59 tags: [ 'tag1', 'tag2', 'tag3' ],
178 it('Should get and seed the uploaded video', async function () { 60 privacy: VideoPrivacy.PUBLIC,
179 this.timeout(5000) 61 commentsEnabled: true,
180 62 downloadEnabled: true,
181 const res = await getVideosList(server.url) 63 channel: {
182 64 displayName: 'Main root channel',
183 expect(res.body.total).to.equal(1) 65 name: 'root_channel',
184 expect(res.body.data).to.be.an('array') 66 description: '',
185 expect(res.body.data.length).to.equal(1) 67 isLocal: true
186 68 },
187 const video = res.body.data[0] 69 fixture: 'video_short.webm',
188 await completeVideoCheck(server.url, video, getCheckAttributes()) 70 files: [
189 }) 71 {
72 resolution: 720,
73 size: 218910
74 }
75 ]
76 })
77
78 const updateCheckAttributes = () => ({
79 name: 'my super video updated',
80 category: 4,
81 licence: 2,
82 language: 'ar',
83 nsfw: false,
84 description: 'my super description updated',
85 support: 'my super support text updated',
86 account: {
87 name: 'root',
88 host: 'localhost:' + server.port
89 },
90 isLocal: true,
91 tags: [ 'tagup1', 'tagup2' ],
92 privacy: VideoPrivacy.PUBLIC,
93 duration: 5,
94 commentsEnabled: false,
95 downloadEnabled: false,
96 channel: {
97 name: 'root_channel',
98 displayName: 'Main root channel',
99 description: '',
100 isLocal: true
101 },
102 fixture: 'video_short3.webm',
103 files: [
104 {
105 resolution: 720,
106 size: 292677
107 }
108 ]
109 })
190 110
191 it('Should get the video by UUID', async function () { 111 before(async function () {
192 this.timeout(5000) 112 this.timeout(30000)
193 113
194 const res = await getVideo(server.url, videoUUID) 114 server = await flushAndRunServer(1)
195 115
196 const video = res.body 116 await setAccessTokensToServers([ server ])
197 await completeVideoCheck(server.url, video, getCheckAttributes()) 117 })
198 })
199 118
200 it('Should have the views updated', async function () { 119 it('Should list video categories', async function () {
201 this.timeout(20000) 120 const res = await getVideoCategories(server.url)
202 121
203 await viewVideo(server.url, videoId) 122 const categories = res.body
204 await viewVideo(server.url, videoId) 123 expect(Object.keys(categories)).to.have.length.above(10)
205 await viewVideo(server.url, videoId)
206 124
207 await wait(1500) 125 expect(categories[11]).to.equal('News & Politics')
126 })
208 127
209 await viewVideo(server.url, videoId) 128 it('Should list video licences', async function () {
210 await viewVideo(server.url, videoId) 129 const res = await getVideoLicences(server.url)
211 130
212 await wait(1500) 131 const licences = res.body
132 expect(Object.keys(licences)).to.have.length.above(5)
213 133
214 await viewVideo(server.url, videoId) 134 expect(licences[3]).to.equal('Attribution - No Derivatives')
215 await viewVideo(server.url, videoId) 135 })
216 136
217 // Wait the repeatable job 137 it('Should list video languages', async function () {
218 await wait(8000) 138 const res = await getVideoLanguages(server.url)
219 139
220 const res = await getVideo(server.url, videoId) 140 const languages = res.body
141 expect(Object.keys(languages)).to.have.length.above(5)
221 142
222 const video = res.body 143 expect(languages['ru']).to.equal('Russian')
223 expect(video.views).to.equal(3) 144 })
224 })
225 145
226 it('Should remove the video', async function () { 146 it('Should list video privacies', async function () {
227 await removeVideo(server.url, server.accessToken, videoId) 147 const res = await getVideoPrivacies(server.url)
228 148
229 await checkVideoFilesWereRemoved(videoUUID, 1) 149 const privacies = res.body
230 }) 150 expect(Object.keys(privacies)).to.have.length.at.least(3)
231 151
232 it('Should not have videos', async function () { 152 expect(privacies[3]).to.equal('Private')
233 const res = await getVideosList(server.url) 153 })
234 154
235 expect(res.body.total).to.equal(0) 155 it('Should not have videos', async function () {
236 expect(res.body.data).to.be.an('array') 156 const res = await getVideosList(server.url)
237 expect(res.body.data).to.have.lengthOf(0)
238 })
239 157
240 it('Should upload 6 videos', async function () { 158 expect(res.body.total).to.equal(0)
241 this.timeout(25000) 159 expect(res.body.data).to.be.an('array')
160 expect(res.body.data.length).to.equal(0)
161 })
242 162
243 const videos = new Set([ 163 it('Should upload the video', async function () {
244 'video_short.mp4', 'video_short.ogv', 'video_short.webm', 164 this.timeout(10000)
245 'video_short1.webm', 'video_short2.webm', 'video_short3.webm'
246 ])
247 165
248 for (const video of videos) {
249 const videoAttributes = { 166 const videoAttributes = {
250 name: video + ' name', 167 name: 'my super name',
251 description: video + ' description',
252 category: 2, 168 category: 2,
253 licence: 1,
254 language: 'en',
255 nsfw: true, 169 nsfw: true,
256 tags: [ 'tag1', 'tag2', 'tag3' ], 170 licence: 6,
257 fixture: video 171 tags: [ 'tag1', 'tag2', 'tag3' ]
258 } 172 }
173 const res = await uploadVideo(server.url, server.accessToken, videoAttributes, HttpStatusCode.OK_200, mode)
174 expect(res.body.video).to.not.be.undefined
175 expect(res.body.video.id).to.equal(1)
176 expect(res.body.video.uuid).to.have.length.above(5)
259 177
260 await uploadVideo(server.url, server.accessToken, videoAttributes) 178 videoId = res.body.video.id
261 } 179 videoUUID = res.body.video.uuid
262 }) 180 })
263 181
264 it('Should have the correct durations', async function () { 182 it('Should get and seed the uploaded video', async function () {
265 const res = await getVideosList(server.url) 183 this.timeout(5000)
266
267 expect(res.body.total).to.equal(6)
268 const videos = res.body.data
269 expect(videos).to.be.an('array')
270 expect(videos).to.have.lengthOf(6)
271
272 const videosByName = keyBy<{ duration: number }>(videos, 'name')
273 expect(videosByName['video_short.mp4 name'].duration).to.equal(5)
274 expect(videosByName['video_short.ogv name'].duration).to.equal(5)
275 expect(videosByName['video_short.webm name'].duration).to.equal(5)
276 expect(videosByName['video_short1.webm name'].duration).to.equal(10)
277 expect(videosByName['video_short2.webm name'].duration).to.equal(5)
278 expect(videosByName['video_short3.webm name'].duration).to.equal(5)
279 })
280 184
281 it('Should have the correct thumbnails', async function () { 185 const res = await getVideosList(server.url)
282 const res = await getVideosList(server.url)
283 186
284 const videos = res.body.data 187 expect(res.body.total).to.equal(1)
285 // For the next test 188 expect(res.body.data).to.be.an('array')
286 videosListBase = videos 189 expect(res.body.data.length).to.equal(1)
287 190
288 for (const video of videos) { 191 const video = res.body.data[0]
289 const videoName = video.name.replace(' name', '') 192 await completeVideoCheck(server.url, video, getCheckAttributes())
290 await testImage(server.url, videoName, video.thumbnailPath) 193 })
291 }
292 })
293 194
294 it('Should list only the two first videos', async function () { 195 it('Should get the video by UUID', async function () {
295 const res = await getVideosListPagination(server.url, 0, 2, 'name') 196 this.timeout(5000)
296 197
297 const videos = res.body.data 198 const res = await getVideo(server.url, videoUUID)
298 expect(res.body.total).to.equal(6)
299 expect(videos.length).to.equal(2)
300 expect(videos[0].name).to.equal(videosListBase[0].name)
301 expect(videos[1].name).to.equal(videosListBase[1].name)
302 })
303 199
304 it('Should list only the next three videos', async function () { 200 const video = res.body
305 const res = await getVideosListPagination(server.url, 2, 3, 'name') 201 await completeVideoCheck(server.url, video, getCheckAttributes())
202 })
306 203
307 const videos = res.body.data 204 it('Should have the views updated', async function () {
308 expect(res.body.total).to.equal(6) 205 this.timeout(20000)
309 expect(videos.length).to.equal(3)
310 expect(videos[0].name).to.equal(videosListBase[2].name)
311 expect(videos[1].name).to.equal(videosListBase[3].name)
312 expect(videos[2].name).to.equal(videosListBase[4].name)
313 })
314 206
315 it('Should list the last video', async function () { 207 await viewVideo(server.url, videoId)
316 const res = await getVideosListPagination(server.url, 5, 6, 'name') 208 await viewVideo(server.url, videoId)
209 await viewVideo(server.url, videoId)
317 210
318 const videos = res.body.data 211 await wait(1500)
319 expect(res.body.total).to.equal(6)
320 expect(videos.length).to.equal(1)
321 expect(videos[0].name).to.equal(videosListBase[5].name)
322 })
323 212
324 it('Should not have the total field', async function () { 213 await viewVideo(server.url, videoId)
325 const res = await getVideosListPagination(server.url, 5, 6, 'name', true) 214 await viewVideo(server.url, videoId)
326 215
327 const videos = res.body.data 216 await wait(1500)
328 expect(res.body.total).to.not.exist
329 expect(videos.length).to.equal(1)
330 expect(videos[0].name).to.equal(videosListBase[5].name)
331 })
332 217
333 it('Should list and sort by name in descending order', async function () { 218 await viewVideo(server.url, videoId)
334 const res = await getVideosListSort(server.url, '-name') 219 await viewVideo(server.url, videoId)
335
336 const videos = res.body.data
337 expect(res.body.total).to.equal(6)
338 expect(videos.length).to.equal(6)
339 expect(videos[0].name).to.equal('video_short.webm name')
340 expect(videos[1].name).to.equal('video_short.ogv name')
341 expect(videos[2].name).to.equal('video_short.mp4 name')
342 expect(videos[3].name).to.equal('video_short3.webm name')
343 expect(videos[4].name).to.equal('video_short2.webm name')
344 expect(videos[5].name).to.equal('video_short1.webm name')
345
346 videoId = videos[3].uuid
347 videoId2 = videos[5].uuid
348 })
349 220
350 it('Should list and sort by trending in descending order', async function () { 221 // Wait the repeatable job
351 const res = await getVideosListPagination(server.url, 0, 2, '-trending') 222 await wait(8000)
352 223
353 const videos = res.body.data 224 const res = await getVideo(server.url, videoId)
354 expect(res.body.total).to.equal(6)
355 expect(videos.length).to.equal(2)
356 })
357 225
358 it('Should list and sort by hotness in descending order', async function () { 226 const video = res.body
359 const res = await getVideosListPagination(server.url, 0, 2, '-hot') 227 expect(video.views).to.equal(3)
228 })
360 229
361 const videos = res.body.data 230 it('Should remove the video', async function () {
362 expect(res.body.total).to.equal(6) 231 await removeVideo(server.url, server.accessToken, videoId)
363 expect(videos.length).to.equal(2)
364 })
365 232
366 it('Should list and sort by best in descending order', async function () { 233 await checkVideoFilesWereRemoved(videoUUID, 1)
367 const res = await getVideosListPagination(server.url, 0, 2, '-best') 234 })
368 235
369 const videos = res.body.data 236 it('Should not have videos', async function () {
370 expect(res.body.total).to.equal(6) 237 const res = await getVideosList(server.url)
371 expect(videos.length).to.equal(2)
372 })
373 238
374 it('Should update a video', async function () { 239 expect(res.body.total).to.equal(0)
375 const attributes = { 240 expect(res.body.data).to.be.an('array')
376 name: 'my super video updated', 241 expect(res.body.data).to.have.lengthOf(0)
377 category: 4, 242 })
378 licence: 2,
379 language: 'ar',
380 nsfw: false,
381 description: 'my super description updated',
382 commentsEnabled: false,
383 downloadEnabled: false,
384 tags: [ 'tagup1', 'tagup2' ]
385 }
386 await updateVideo(server.url, server.accessToken, videoId, attributes)
387 })
388 243
389 it('Should filter by tags and category', async function () { 244 it('Should upload 6 videos', async function () {
390 const res1 = await getVideosWithFilters(server.url, { tagsAllOf: [ 'tagup1', 'tagup2' ], categoryOneOf: [ 4 ] }) 245 this.timeout(25000)
391 expect(res1.body.total).to.equal(1)
392 expect(res1.body.data[0].name).to.equal('my super video updated')
393 246
394 const res2 = await getVideosWithFilters(server.url, { tagsAllOf: [ 'tagup1', 'tagup2' ], categoryOneOf: [ 3 ] }) 247 const videos = new Set([
395 expect(res2.body.total).to.equal(0) 248 'video_short.mp4', 'video_short.ogv', 'video_short.webm',
396 }) 249 'video_short1.webm', 'video_short2.webm', 'video_short3.webm'
250 ])
397 251
398 it('Should have the video updated', async function () { 252 for (const video of videos) {
399 this.timeout(60000) 253 const videoAttributes = {
254 name: video + ' name',
255 description: video + ' description',
256 category: 2,
257 licence: 1,
258 language: 'en',
259 nsfw: true,
260 tags: [ 'tag1', 'tag2', 'tag3' ],
261 fixture: video
262 }
400 263
401 const res = await getVideo(server.url, videoId) 264 await uploadVideo(server.url, server.accessToken, videoAttributes, HttpStatusCode.OK_200, mode)
402 const video = res.body 265 }
266 })
267
268 it('Should have the correct durations', async function () {
269 const res = await getVideosList(server.url)
270
271 expect(res.body.total).to.equal(6)
272 const videos = res.body.data
273 expect(videos).to.be.an('array')
274 expect(videos).to.have.lengthOf(6)
275
276 const videosByName = keyBy<{ duration: number }>(videos, 'name')
277 expect(videosByName['video_short.mp4 name'].duration).to.equal(5)
278 expect(videosByName['video_short.ogv name'].duration).to.equal(5)
279 expect(videosByName['video_short.webm name'].duration).to.equal(5)
280 expect(videosByName['video_short1.webm name'].duration).to.equal(10)
281 expect(videosByName['video_short2.webm name'].duration).to.equal(5)
282 expect(videosByName['video_short3.webm name'].duration).to.equal(5)
283 })
284
285 it('Should have the correct thumbnails', async function () {
286 const res = await getVideosList(server.url)
287
288 const videos = res.body.data
289 // For the next test
290 videosListBase = videos
291
292 for (const video of videos) {
293 const videoName = video.name.replace(' name', '')
294 await testImage(server.url, videoName, video.thumbnailPath)
295 }
296 })
297
298 it('Should list only the two first videos', async function () {
299 const res = await getVideosListPagination(server.url, 0, 2, 'name')
300
301 const videos = res.body.data
302 expect(res.body.total).to.equal(6)
303 expect(videos.length).to.equal(2)
304 expect(videos[0].name).to.equal(videosListBase[0].name)
305 expect(videos[1].name).to.equal(videosListBase[1].name)
306 })
307
308 it('Should list only the next three videos', async function () {
309 const res = await getVideosListPagination(server.url, 2, 3, 'name')
310
311 const videos = res.body.data
312 expect(res.body.total).to.equal(6)
313 expect(videos.length).to.equal(3)
314 expect(videos[0].name).to.equal(videosListBase[2].name)
315 expect(videos[1].name).to.equal(videosListBase[3].name)
316 expect(videos[2].name).to.equal(videosListBase[4].name)
317 })
318
319 it('Should list the last video', async function () {
320 const res = await getVideosListPagination(server.url, 5, 6, 'name')
321
322 const videos = res.body.data
323 expect(res.body.total).to.equal(6)
324 expect(videos.length).to.equal(1)
325 expect(videos[0].name).to.equal(videosListBase[5].name)
326 })
327
328 it('Should not have the total field', async function () {
329 const res = await getVideosListPagination(server.url, 5, 6, 'name', true)
330
331 const videos = res.body.data
332 expect(res.body.total).to.not.exist
333 expect(videos.length).to.equal(1)
334 expect(videos[0].name).to.equal(videosListBase[5].name)
335 })
336
337 it('Should list and sort by name in descending order', async function () {
338 const res = await getVideosListSort(server.url, '-name')
339
340 const videos = res.body.data
341 expect(res.body.total).to.equal(6)
342 expect(videos.length).to.equal(6)
343 expect(videos[0].name).to.equal('video_short.webm name')
344 expect(videos[1].name).to.equal('video_short.ogv name')
345 expect(videos[2].name).to.equal('video_short.mp4 name')
346 expect(videos[3].name).to.equal('video_short3.webm name')
347 expect(videos[4].name).to.equal('video_short2.webm name')
348 expect(videos[5].name).to.equal('video_short1.webm name')
349
350 videoId = videos[3].uuid
351 videoId2 = videos[5].uuid
352 })
353
354 it('Should list and sort by trending in descending order', async function () {
355 const res = await getVideosListPagination(server.url, 0, 2, '-trending')
356
357 const videos = res.body.data
358 expect(res.body.total).to.equal(6)
359 expect(videos.length).to.equal(2)
360 })
361
362 it('Should list and sort by hotness in descending order', async function () {
363 const res = await getVideosListPagination(server.url, 0, 2, '-hot')
364
365 const videos = res.body.data
366 expect(res.body.total).to.equal(6)
367 expect(videos.length).to.equal(2)
368 })
369
370 it('Should list and sort by best in descending order', async function () {
371 const res = await getVideosListPagination(server.url, 0, 2, '-best')
372
373 const videos = res.body.data
374 expect(res.body.total).to.equal(6)
375 expect(videos.length).to.equal(2)
376 })
377
378 it('Should update a video', async function () {
379 const attributes = {
380 name: 'my super video updated',
381 category: 4,
382 licence: 2,
383 language: 'ar',
384 nsfw: false,
385 description: 'my super description updated',
386 commentsEnabled: false,
387 downloadEnabled: false,
388 tags: [ 'tagup1', 'tagup2' ]
389 }
390 await updateVideo(server.url, server.accessToken, videoId, attributes)
391 })
403 392
404 await completeVideoCheck(server.url, video, updateCheckAttributes()) 393 it('Should filter by tags and category', async function () {
405 }) 394 const res1 = await getVideosWithFilters(server.url, { tagsAllOf: [ 'tagup1', 'tagup2' ], categoryOneOf: [ 4 ] })
395 expect(res1.body.total).to.equal(1)
396 expect(res1.body.data[0].name).to.equal('my super video updated')
406 397
407 it('Should update only the tags of a video', async function () { 398 const res2 = await getVideosWithFilters(server.url, { tagsAllOf: [ 'tagup1', 'tagup2' ], categoryOneOf: [ 3 ] })
408 const attributes = { 399 expect(res2.body.total).to.equal(0)
409 tags: [ 'supertag', 'tag1', 'tag2' ] 400 })
410 }
411 await updateVideo(server.url, server.accessToken, videoId, attributes)
412 401
413 const res = await getVideo(server.url, videoId) 402 it('Should have the video updated', async function () {
414 const video = res.body 403 this.timeout(60000)
415 404
416 await completeVideoCheck(server.url, video, Object.assign(updateCheckAttributes(), attributes)) 405 const res = await getVideo(server.url, videoId)
417 }) 406 const video = res.body
418 407
419 it('Should update only the description of a video', async function () { 408 await completeVideoCheck(server.url, video, updateCheckAttributes())
420 const attributes = { 409 })
421 description: 'hello everybody'
422 }
423 await updateVideo(server.url, server.accessToken, videoId, attributes)
424 410
425 const res = await getVideo(server.url, videoId) 411 it('Should update only the tags of a video', async function () {
426 const video = res.body 412 const attributes = {
413 tags: [ 'supertag', 'tag1', 'tag2' ]
414 }
415 await updateVideo(server.url, server.accessToken, videoId, attributes)
427 416
428 const expectedAttributes = Object.assign(updateCheckAttributes(), { tags: [ 'supertag', 'tag1', 'tag2' ] }, attributes) 417 const res = await getVideo(server.url, videoId)
429 await completeVideoCheck(server.url, video, expectedAttributes) 418 const video = res.body
430 })
431 419
432 it('Should like a video', async function () { 420 await completeVideoCheck(server.url, video, Object.assign(updateCheckAttributes(), attributes))
433 await rateVideo(server.url, server.accessToken, videoId, 'like') 421 })
434 422
435 const res = await getVideo(server.url, videoId) 423 it('Should update only the description of a video', async function () {
436 const video = res.body 424 const attributes = {
425 description: 'hello everybody'
426 }
427 await updateVideo(server.url, server.accessToken, videoId, attributes)
437 428
438 expect(video.likes).to.equal(1) 429 const res = await getVideo(server.url, videoId)
439 expect(video.dislikes).to.equal(0) 430 const video = res.body
440 })
441 431
442 it('Should dislike the same video', async function () { 432 const expectedAttributes = Object.assign(updateCheckAttributes(), { tags: [ 'supertag', 'tag1', 'tag2' ] }, attributes)
443 await rateVideo(server.url, server.accessToken, videoId, 'dislike') 433 await completeVideoCheck(server.url, video, expectedAttributes)
434 })
444 435
445 const res = await getVideo(server.url, videoId) 436 it('Should like a video', async function () {
446 const video = res.body 437 await rateVideo(server.url, server.accessToken, videoId, 'like')
447 438
448 expect(video.likes).to.equal(0) 439 const res = await getVideo(server.url, videoId)
449 expect(video.dislikes).to.equal(1) 440 const video = res.body
450 })
451 441
452 it('Should sort by originallyPublishedAt', async function () { 442 expect(video.likes).to.equal(1)
453 { 443 expect(video.dislikes).to.equal(0)
444 })
454 445
446 it('Should dislike the same video', async function () {
447 await rateVideo(server.url, server.accessToken, videoId, 'dislike')
448
449 const res = await getVideo(server.url, videoId)
450 const video = res.body
451
452 expect(video.likes).to.equal(0)
453 expect(video.dislikes).to.equal(1)
454 })
455
456 it('Should sort by originallyPublishedAt', async function () {
455 { 457 {
456 const now = new Date() 458 const now = new Date()
457 const attributes = { originallyPublishedAt: now.toISOString() } 459 const attributes = { originallyPublishedAt: now.toISOString() }
@@ -483,10 +485,18 @@ describe('Test a single server', function () {
483 expect(names[4]).to.equal('video_short.ogv name') 485 expect(names[4]).to.equal('video_short.ogv name')
484 expect(names[5]).to.equal('video_short.mp4 name') 486 expect(names[5]).to.equal('video_short.mp4 name')
485 } 487 }
486 } 488 })
489
490 after(async function () {
491 await cleanupTests([ server ])
492 })
493 }
494
495 describe('Legacy upload', function () {
496 runSuite('legacy')
487 }) 497 })
488 498
489 after(async function () { 499 describe('Resumable upload', function () {
490 await cleanupTests([ server ]) 500 runSuite('resumable')
491 }) 501 })
492}) 502})
diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts
index d12d58e75..7e7ad028c 100644
--- a/server/tests/api/videos/video-channels.ts
+++ b/server/tests/api/videos/video-channels.ts
@@ -3,6 +3,7 @@
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { basename } from 'path' 5import { basename } from 'path'
6import { ACTOR_IMAGES_SIZE } from '@server/initializers/constants'
6import { 7import {
7 cleanupTests, 8 cleanupTests,
8 createUser, 9 createUser,
@@ -13,6 +14,7 @@ import {
13 getVideo, 14 getVideo,
14 getVideoChannel, 15 getVideoChannel,
15 getVideoChannelVideos, 16 getVideoChannelVideos,
17 setDefaultVideoChannel,
16 testImage, 18 testImage,
17 updateVideo, 19 updateVideo,
18 updateVideoChannelImage, 20 updateVideoChannelImage,
@@ -33,7 +35,6 @@ import {
33} from '../../../../shared/extra-utils/index' 35} from '../../../../shared/extra-utils/index'
34import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 36import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
35import { User, Video, VideoChannel, VideoDetails } from '../../../../shared/index' 37import { User, Video, VideoChannel, VideoDetails } from '../../../../shared/index'
36import { ACTOR_IMAGES_SIZE } from '@server/initializers/constants'
37 38
38const expect = chai.expect 39const expect = chai.expect
39 40
@@ -47,9 +48,10 @@ async function findChannel (server: ServerInfo, channelId: number) {
47describe('Test video channels', function () { 48describe('Test video channels', function () {
48 let servers: ServerInfo[] 49 let servers: ServerInfo[]
49 let userInfo: User 50 let userInfo: User
50 let firstVideoChannelId: number
51 let secondVideoChannelId: number 51 let secondVideoChannelId: number
52 let totoChannel: number
52 let videoUUID: string 53 let videoUUID: string
54 let accountName: string
53 55
54 before(async function () { 56 before(async function () {
55 this.timeout(60000) 57 this.timeout(60000)
@@ -57,16 +59,9 @@ describe('Test video channels', function () {
57 servers = await flushAndRunMultipleServers(2) 59 servers = await flushAndRunMultipleServers(2)
58 60
59 await setAccessTokensToServers(servers) 61 await setAccessTokensToServers(servers)
60 await doubleFollow(servers[0], servers[1]) 62 await setDefaultVideoChannel(servers)
61
62 {
63 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
64 const user: User = res.body
65
66 firstVideoChannelId = user.videoChannels[0].id
67 }
68 63
69 await waitJobs(servers) 64 await doubleFollow(servers[0], servers[1])
70 }) 65 })
71 66
72 it('Should have one video channel (created with root)', async () => { 67 it('Should have one video channel (created with root)', async () => {
@@ -116,12 +111,14 @@ describe('Test video channels', function () {
116 expect(videoChannels[1].displayName).to.equal('second video channel') 111 expect(videoChannels[1].displayName).to.equal('second video channel')
117 expect(videoChannels[1].description).to.equal('super video channel description') 112 expect(videoChannels[1].description).to.equal('super video channel description')
118 expect(videoChannels[1].support).to.equal('super video channel support text') 113 expect(videoChannels[1].support).to.equal('super video channel support text')
114
115 accountName = userInfo.account.name + '@' + userInfo.account.host
119 }) 116 })
120 117
121 it('Should have two video channels when getting account channels on server 1', async function () { 118 it('Should have two video channels when getting account channels on server 1', async function () {
122 const res = await getAccountVideoChannelsList({ 119 const res = await getAccountVideoChannelsList({
123 url: servers[0].url, 120 url: servers[0].url,
124 accountName: userInfo.account.name + '@' + userInfo.account.host 121 accountName
125 }) 122 })
126 123
127 expect(res.body.total).to.equal(2) 124 expect(res.body.total).to.equal(2)
@@ -142,7 +139,7 @@ describe('Test video channels', function () {
142 { 139 {
143 const res = await getAccountVideoChannelsList({ 140 const res = await getAccountVideoChannelsList({
144 url: servers[0].url, 141 url: servers[0].url,
145 accountName: userInfo.account.name + '@' + userInfo.account.host, 142 accountName,
146 start: 0, 143 start: 0,
147 count: 1, 144 count: 1,
148 sort: 'createdAt' 145 sort: 'createdAt'
@@ -158,7 +155,7 @@ describe('Test video channels', function () {
158 { 155 {
159 const res = await getAccountVideoChannelsList({ 156 const res = await getAccountVideoChannelsList({
160 url: servers[0].url, 157 url: servers[0].url,
161 accountName: userInfo.account.name + '@' + userInfo.account.host, 158 accountName,
162 start: 0, 159 start: 0,
163 count: 1, 160 count: 1,
164 sort: '-createdAt' 161 sort: '-createdAt'
@@ -174,7 +171,7 @@ describe('Test video channels', function () {
174 { 171 {
175 const res = await getAccountVideoChannelsList({ 172 const res = await getAccountVideoChannelsList({
176 url: servers[0].url, 173 url: servers[0].url,
177 accountName: userInfo.account.name + '@' + userInfo.account.host, 174 accountName,
178 start: 1, 175 start: 1,
179 count: 1, 176 count: 1,
180 sort: '-createdAt' 177 sort: '-createdAt'
@@ -191,7 +188,7 @@ describe('Test video channels', function () {
191 it('Should have one video channel when getting account channels on server 2', async function () { 188 it('Should have one video channel when getting account channels on server 2', async function () {
192 const res = await getAccountVideoChannelsList({ 189 const res = await getAccountVideoChannelsList({
193 url: servers[1].url, 190 url: servers[1].url,
194 accountName: userInfo.account.name + '@' + userInfo.account.host 191 accountName
195 }) 192 })
196 193
197 expect(res.body.total).to.equal(1) 194 expect(res.body.total).to.equal(1)
@@ -379,7 +376,7 @@ describe('Test video channels', function () {
379 it('Should change the video channel of a video', async function () { 376 it('Should change the video channel of a video', async function () {
380 this.timeout(10000) 377 this.timeout(10000)
381 378
382 await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { channelId: firstVideoChannelId }) 379 await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { channelId: servers[0].videoChannel.id })
383 380
384 await waitJobs(servers) 381 await waitJobs(servers)
385 }) 382 })
@@ -419,7 +416,8 @@ describe('Test video channels', function () {
419 it('Should create the main channel with an uuid if there is a conflict', async function () { 416 it('Should create the main channel with an uuid if there is a conflict', async function () {
420 { 417 {
421 const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' } 418 const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' }
422 await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel) 419 const res = await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
420 totoChannel = res.body.videoChannel.id
423 } 421 }
424 422
425 { 423 {
@@ -438,7 +436,7 @@ describe('Test video channels', function () {
438 { 436 {
439 const res = await getAccountVideoChannelsList({ 437 const res = await getAccountVideoChannelsList({
440 url: servers[0].url, 438 url: servers[0].url,
441 accountName: userInfo.account.name + '@' + userInfo.account.host, 439 accountName,
442 withStats: true 440 withStats: true
443 }) 441 })
444 442
@@ -456,7 +454,7 @@ describe('Test video channels', function () {
456 } 454 }
457 455
458 { 456 {
459 // video has been posted on channel firstVideoChannelId since last update 457 // video has been posted on channel servers[0].videoChannel.id since last update
460 await viewVideo(servers[0].url, videoUUID, 204, '0.0.0.1,127.0.0.1') 458 await viewVideo(servers[0].url, videoUUID, 204, '0.0.0.1,127.0.0.1')
461 await viewVideo(servers[0].url, videoUUID, 204, '0.0.0.2,127.0.0.1') 459 await viewVideo(servers[0].url, videoUUID, 204, '0.0.0.2,127.0.0.1')
462 460
@@ -465,10 +463,10 @@ describe('Test video channels', function () {
465 463
466 const res = await getAccountVideoChannelsList({ 464 const res = await getAccountVideoChannelsList({
467 url: servers[0].url, 465 url: servers[0].url,
468 accountName: userInfo.account.name + '@' + userInfo.account.host, 466 accountName,
469 withStats: true 467 withStats: true
470 }) 468 })
471 const channelWithView = res.body.data.find((channel: VideoChannel) => channel.id === firstVideoChannelId) 469 const channelWithView = res.body.data.find((channel: VideoChannel) => channel.id === servers[0].videoChannel.id)
472 expect(channelWithView.viewsPerDay.slice(-1)[0].views).to.equal(2) 470 expect(channelWithView.viewsPerDay.slice(-1)[0].views).to.equal(2)
473 } 471 }
474 }) 472 })
@@ -476,7 +474,7 @@ describe('Test video channels', function () {
476 it('Should report correct videos count', async function () { 474 it('Should report correct videos count', async function () {
477 const res = await getAccountVideoChannelsList({ 475 const res = await getAccountVideoChannelsList({
478 url: servers[0].url, 476 url: servers[0].url,
479 accountName: userInfo.account.name + '@' + userInfo.account.host, 477 accountName,
480 withStats: true 478 withStats: true
481 }) 479 })
482 const channels: VideoChannel[] = res.body.data 480 const channels: VideoChannel[] = res.body.data
@@ -492,7 +490,7 @@ describe('Test video channels', function () {
492 { 490 {
493 const res = await getAccountVideoChannelsList({ 491 const res = await getAccountVideoChannelsList({
494 url: servers[0].url, 492 url: servers[0].url,
495 accountName: userInfo.account.name + '@' + userInfo.account.host, 493 accountName,
496 search: 'root' 494 search: 'root'
497 }) 495 })
498 expect(res.body.total).to.equal(1) 496 expect(res.body.total).to.equal(1)
@@ -504,7 +502,7 @@ describe('Test video channels', function () {
504 { 502 {
505 const res = await getAccountVideoChannelsList({ 503 const res = await getAccountVideoChannelsList({
506 url: servers[0].url, 504 url: servers[0].url,
507 accountName: userInfo.account.name + '@' + userInfo.account.host, 505 accountName,
508 search: 'does not exist' 506 search: 'does not exist'
509 }) 507 })
510 expect(res.body.total).to.equal(0) 508 expect(res.body.total).to.equal(0)
@@ -514,6 +512,40 @@ describe('Test video channels', function () {
514 } 512 }
515 }) 513 })
516 514
515 it('Should list channels by updatedAt desc if a video has been uploaded', async function () {
516 this.timeout(30000)
517
518 await uploadVideo(servers[0].url, servers[0].accessToken, { channelId: totoChannel })
519 await waitJobs(servers)
520
521 for (const server of servers) {
522 const res = await getAccountVideoChannelsList({
523 url: server.url,
524 accountName,
525 sort: '-updatedAt'
526 })
527
528 const channels: VideoChannel[] = res.body.data
529 expect(channels[0].name).to.equal('toto_channel')
530 expect(channels[1].name).to.equal('root_channel')
531 }
532
533 await uploadVideo(servers[0].url, servers[0].accessToken, { channelId: servers[0].videoChannel.id })
534 await waitJobs(servers)
535
536 for (const server of servers) {
537 const res = await getAccountVideoChannelsList({
538 url: server.url,
539 accountName,
540 sort: '-updatedAt'
541 })
542
543 const channels: VideoChannel[] = res.body.data
544 expect(channels[0].name).to.equal('root_channel')
545 expect(channels[1].name).to.equal('toto_channel')
546 }
547 })
548
517 after(async function () { 549 after(async function () {
518 await cleanupTests(servers) 550 await cleanupTests(servers)
519 }) 551 })
diff --git a/server/tests/api/videos/video-comments.ts b/server/tests/api/videos/video-comments.ts
index 615e0ea45..a5ff3a39d 100644
--- a/server/tests/api/videos/video-comments.ts
+++ b/server/tests/api/videos/video-comments.ts
@@ -2,7 +2,7 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5 5import { VideoComment, VideoCommentAdmin, VideoCommentThreadTree } from '@shared/models'
6import { cleanupTests, testImage } from '../../../../shared/extra-utils' 6import { cleanupTests, testImage } from '../../../../shared/extra-utils'
7import { 7import {
8 createUser, 8 createUser,
@@ -22,7 +22,6 @@ import {
22 getVideoCommentThreads, 22 getVideoCommentThreads,
23 getVideoThreadComments 23 getVideoThreadComments
24} from '../../../../shared/extra-utils/videos/video-comments' 24} from '../../../../shared/extra-utils/videos/video-comments'
25import { VideoComment, VideoCommentAdmin, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
26 25
27const expect = chai.expect 26const expect = chai.expect
28 27
diff --git a/server/tests/api/videos/video-transcoder.ts b/server/tests/api/videos/video-transcoder.ts
index 1c99f26df..ea5ffd239 100644
--- a/server/tests/api/videos/video-transcoder.ts
+++ b/server/tests/api/videos/video-transcoder.ts
@@ -361,106 +361,117 @@ describe('Test video transcoding', function () {
361 361
362 describe('Audio upload', function () { 362 describe('Audio upload', function () {
363 363
364 before(async function () { 364 function runSuite (mode: 'legacy' | 'resumable') {
365 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, { 365
366 transcoding: { 366 before(async function () {
367 hls: { enabled: true }, 367 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, {
368 webtorrent: { enabled: true }, 368 transcoding: {
369 resolutions: { 369 hls: { enabled: true },
370 '0p': false, 370 webtorrent: { enabled: true },
371 '240p': false, 371 resolutions: {
372 '360p': false, 372 '0p': false,
373 '480p': false, 373 '240p': false,
374 '720p': false, 374 '360p': false,
375 '1080p': false, 375 '480p': false,
376 '1440p': false, 376 '720p': false,
377 '2160p': false 377 '1080p': false,
378 '1440p': false,
379 '2160p': false
380 }
378 } 381 }
379 } 382 })
380 }) 383 })
381 })
382
383 it('Should merge an audio file with the preview file', async function () {
384 this.timeout(60_000)
385
386 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' }
387 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg)
388 384
389 await waitJobs(servers) 385 it('Should merge an audio file with the preview file', async function () {
386 this.timeout(60_000)
390 387
391 for (const server of servers) { 388 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' }
392 const res = await getVideosList(server.url) 389 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg, HttpStatusCode.OK_200, mode)
393 390
394 const video = res.body.data.find(v => v.name === 'audio_with_preview') 391 await waitJobs(servers)
395 const res2 = await getVideo(server.url, video.id)
396 const videoDetails: VideoDetails = res2.body
397 392
398 expect(videoDetails.files).to.have.lengthOf(1) 393 for (const server of servers) {
394 const res = await getVideosList(server.url)
399 395
400 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: HttpStatusCode.OK_200 }) 396 const video = res.body.data.find(v => v.name === 'audio_with_preview')
401 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: HttpStatusCode.OK_200 }) 397 const res2 = await getVideo(server.url, video.id)
398 const videoDetails: VideoDetails = res2.body
402 399
403 const magnetUri = videoDetails.files[0].magnetUri 400 expect(videoDetails.files).to.have.lengthOf(1)
404 expect(magnetUri).to.contain('.mp4')
405 }
406 })
407 401
408 it('Should upload an audio file and choose a default background image', async function () { 402 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: HttpStatusCode.OK_200 })
409 this.timeout(60_000) 403 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: HttpStatusCode.OK_200 })
410 404
411 const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' } 405 const magnetUri = videoDetails.files[0].magnetUri
412 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg) 406 expect(magnetUri).to.contain('.mp4')
407 }
408 })
413 409
414 await waitJobs(servers) 410 it('Should upload an audio file and choose a default background image', async function () {
411 this.timeout(60_000)
415 412
416 for (const server of servers) { 413 const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' }
417 const res = await getVideosList(server.url) 414 await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg, HttpStatusCode.OK_200, mode)
418 415
419 const video = res.body.data.find(v => v.name === 'audio_without_preview') 416 await waitJobs(servers)
420 const res2 = await getVideo(server.url, video.id)
421 const videoDetails = res2.body
422 417
423 expect(videoDetails.files).to.have.lengthOf(1) 418 for (const server of servers) {
419 const res = await getVideosList(server.url)
424 420
425 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: HttpStatusCode.OK_200 }) 421 const video = res.body.data.find(v => v.name === 'audio_without_preview')
426 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: HttpStatusCode.OK_200 }) 422 const res2 = await getVideo(server.url, video.id)
423 const videoDetails = res2.body
427 424
428 const magnetUri = videoDetails.files[0].magnetUri 425 expect(videoDetails.files).to.have.lengthOf(1)
429 expect(magnetUri).to.contain('.mp4')
430 }
431 })
432 426
433 it('Should upload an audio file and create an audio version only', async function () { 427 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: HttpStatusCode.OK_200 })
434 this.timeout(60_000) 428 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: HttpStatusCode.OK_200 })
435 429
436 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, { 430 const magnetUri = videoDetails.files[0].magnetUri
437 transcoding: { 431 expect(magnetUri).to.contain('.mp4')
438 hls: { enabled: true },
439 webtorrent: { enabled: true },
440 resolutions: {
441 '0p': true,
442 '240p': false,
443 '360p': false
444 }
445 } 432 }
446 }) 433 })
447 434
448 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } 435 it('Should upload an audio file and create an audio version only', async function () {
449 const resVideo = await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg) 436 this.timeout(60_000)
437
438 await updateCustomSubConfig(servers[1].url, servers[1].accessToken, {
439 transcoding: {
440 hls: { enabled: true },
441 webtorrent: { enabled: true },
442 resolutions: {
443 '0p': true,
444 '240p': false,
445 '360p': false
446 }
447 }
448 })
450 449
451 await waitJobs(servers) 450 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' }
451 const resVideo = await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg, HttpStatusCode.OK_200, mode)
452 452
453 for (const server of servers) { 453 await waitJobs(servers)
454 const res2 = await getVideo(server.url, resVideo.body.video.id) 454
455 const videoDetails: VideoDetails = res2.body 455 for (const server of servers) {
456 const res2 = await getVideo(server.url, resVideo.body.video.id)
457 const videoDetails: VideoDetails = res2.body
456 458
457 for (const files of [ videoDetails.files, videoDetails.streamingPlaylists[0].files ]) { 459 for (const files of [ videoDetails.files, videoDetails.streamingPlaylists[0].files ]) {
458 expect(files).to.have.lengthOf(2) 460 expect(files).to.have.lengthOf(2)
459 expect(files.find(f => f.resolution.id === 0)).to.not.be.undefined 461 expect(files.find(f => f.resolution.id === 0)).to.not.be.undefined
462 }
460 } 463 }
461 }
462 464
463 await updateConfigForTranscoding(servers[1]) 465 await updateConfigForTranscoding(servers[1])
466 })
467 }
468
469 describe('Legacy upload', function () {
470 runSuite('legacy')
471 })
472
473 describe('Resumable upload', function () {
474 runSuite('resumable')
464 }) 475 })
465 }) 476 })
466 477
diff --git a/server/tests/client.ts b/server/tests/client.ts
index e76220631..d9a472fdd 100644
--- a/server/tests/client.ts
+++ b/server/tests/client.ts
@@ -3,7 +3,7 @@
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import * as request from 'supertest' 5import * as request from 'supertest'
6import { Account, VideoPlaylistPrivacy } from '@shared/models' 6import { Account, HTMLServerConfig, ServerConfig, VideoPlaylistPrivacy } from '@shared/models'
7import { 7import {
8 addVideoInPlaylist, 8 addVideoInPlaylist,
9 cleanupTests, 9 cleanupTests,
@@ -11,6 +11,7 @@ import {
11 doubleFollow, 11 doubleFollow,
12 flushAndRunMultipleServers, 12 flushAndRunMultipleServers,
13 getAccount, 13 getAccount,
14 getConfig,
14 getCustomConfig, 15 getCustomConfig,
15 getVideosList, 16 getVideosList,
16 makeHTMLRequest, 17 makeHTMLRequest,
@@ -25,13 +26,17 @@ import {
25 waitJobs 26 waitJobs
26} from '../../shared/extra-utils' 27} from '../../shared/extra-utils'
27import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' 28import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
29import { omit } from 'lodash'
28 30
29const expect = chai.expect 31const expect = chai.expect
30 32
31function checkIndexTags (html: string, title: string, description: string, css: string) { 33function checkIndexTags (html: string, title: string, description: string, css: string, config: ServerConfig) {
32 expect(html).to.contain('<title>' + title + '</title>') 34 expect(html).to.contain('<title>' + title + '</title>')
33 expect(html).to.contain('<meta name="description" content="' + description + '" />') 35 expect(html).to.contain('<meta name="description" content="' + description + '" />')
34 expect(html).to.contain('<style class="custom-css-style">' + css + '</style>') 36 expect(html).to.contain('<style class="custom-css-style">' + css + '</style>')
37
38 const htmlConfig: HTMLServerConfig = omit(config, 'signup')
39 expect(html).to.contain(`<script type="application/javascript">window.PeerTubeServerConfig = '${JSON.stringify(htmlConfig)}'</script>`)
35} 40}
36 41
37describe('Test a client controllers', function () { 42describe('Test a client controllers', function () {
@@ -368,10 +373,11 @@ describe('Test a client controllers', function () {
368 describe('Index HTML', function () { 373 describe('Index HTML', function () {
369 374
370 it('Should have valid index html tags (title, description...)', async function () { 375 it('Should have valid index html tags (title, description...)', async function () {
376 const resConfig = await getConfig(servers[0].url)
371 const res = await makeHTMLRequest(servers[0].url, '/videos/trending') 377 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
372 378
373 const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.' 379 const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.'
374 checkIndexTags(res.text, 'PeerTube', description, '') 380 checkIndexTags(res.text, 'PeerTube', description, '', resConfig.body)
375 }) 381 })
376 382
377 it('Should update the customized configuration and have the correct index html tags', async function () { 383 it('Should update the customized configuration and have the correct index html tags', async function () {
@@ -390,15 +396,17 @@ describe('Test a client controllers', function () {
390 } 396 }
391 }) 397 })
392 398
399 const resConfig = await getConfig(servers[0].url)
393 const res = await makeHTMLRequest(servers[0].url, '/videos/trending') 400 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
394 401
395 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }') 402 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
396 }) 403 })
397 404
398 it('Should have valid index html updated tags (title, description...)', async function () { 405 it('Should have valid index html updated tags (title, description...)', async function () {
406 const resConfig = await getConfig(servers[0].url)
399 const res = await makeHTMLRequest(servers[0].url, '/videos/trending') 407 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
400 408
401 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }') 409 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
402 }) 410 })
403 411
404 it('Should use the original video URL for the canonical tag', async function () { 412 it('Should use the original video URL for the canonical tag', async function () {
@@ -432,6 +440,16 @@ describe('Test a client controllers', function () {
432 }) 440 })
433 }) 441 })
434 442
443 describe('Embed HTML', function () {
444
445 it('Should have the correct embed html tags', async function () {
446 const resConfig = await getConfig(servers[0].url)
447 const res = await makeHTMLRequest(servers[0].url, servers[0].video.embedPath)
448
449 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
450 })
451 })
452
435 after(async function () { 453 after(async function () {
436 await cleanupTests(servers) 454 await cleanupTests(servers)
437 }) 455 })
diff --git a/server/tests/fixtures/peertube-plugin-test-four/main.js b/server/tests/fixtures/peertube-plugin-test-four/main.js
index 6ed0c20d2..b9b207b81 100644
--- a/server/tests/fixtures/peertube-plugin-test-four/main.js
+++ b/server/tests/fixtures/peertube-plugin-test-four/main.js
@@ -88,8 +88,8 @@ async function register ({
88 return res.json({ routerRoute }) 88 return res.json({ routerRoute })
89 }) 89 })
90 90
91 router.get('/user', (req, res) => { 91 router.get('/user', async (req, res) => {
92 const user = peertubeHelpers.user.getAuthUser(res) 92 const user = await peertubeHelpers.user.getAuthUser(res)
93 if (!user) return res.sendStatus(404) 93 if (!user) return res.sendStatus(404)
94 94
95 const isAdmin = user.role === 0 95 const isAdmin = user.role === 0
@@ -98,6 +98,7 @@ async function register ({
98 98
99 return res.json({ 99 return res.json({
100 username: user.username, 100 username: user.username,
101 displayName: user.Account.name,
101 isAdmin, 102 isAdmin,
102 isModerator, 103 isModerator,
103 isUser 104 isUser
diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts
index ac958c5f5..1d6bb6cf4 100644
--- a/server/tests/plugins/filter-hooks.ts
+++ b/server/tests/plugins/filter-hooks.ts
@@ -38,6 +38,7 @@ import {
38import { cleanupTests, flushAndRunMultipleServers, ServerInfo, waitUntilLog } from '../../../shared/extra-utils/server/servers' 38import { cleanupTests, flushAndRunMultipleServers, ServerInfo, waitUntilLog } from '../../../shared/extra-utils/server/servers'
39import { getGoodVideoUrl, getMyVideoImports, importVideo } from '../../../shared/extra-utils/videos/video-imports' 39import { getGoodVideoUrl, getMyVideoImports, importVideo } from '../../../shared/extra-utils/videos/video-imports'
40import { 40import {
41 VideoCommentThreadTree,
41 VideoDetails, 42 VideoDetails,
42 VideoImport, 43 VideoImport,
43 VideoImportState, 44 VideoImportState,
@@ -45,7 +46,6 @@ import {
45 VideoPlaylistPrivacy, 46 VideoPlaylistPrivacy,
46 VideoPrivacy 47 VideoPrivacy
47} from '../../../shared/models/videos' 48} from '../../../shared/models/videos'
48import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model'
49 49
50const expect = chai.expect 50const expect = chai.expect
51 51
@@ -55,7 +55,7 @@ describe('Test plugin filter hooks', function () {
55 let threadId: number 55 let threadId: number
56 56
57 before(async function () { 57 before(async function () {
58 this.timeout(30000) 58 this.timeout(60000)
59 59
60 servers = await flushAndRunMultipleServers(2) 60 servers = await flushAndRunMultipleServers(2)
61 await setAccessTokensToServers(servers) 61 await setAccessTokensToServers(servers)
@@ -326,7 +326,7 @@ describe('Test plugin filter hooks', function () {
326 }) 326 })
327 327
328 it('Should blacklist on remote upload', async function () { 328 it('Should blacklist on remote upload', async function () {
329 this.timeout(45000) 329 this.timeout(60000)
330 330
331 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'remote please blacklist me' }) 331 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'remote please blacklist me' })
332 await waitJobs(servers) 332 await waitJobs(servers)
@@ -335,7 +335,7 @@ describe('Test plugin filter hooks', function () {
335 }) 335 })
336 336
337 it('Should blacklist on remote update', async function () { 337 it('Should blacklist on remote update', async function () {
338 this.timeout(45000) 338 this.timeout(60000)
339 339
340 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video' }) 340 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video' })
341 await waitJobs(servers) 341 await waitJobs(servers)
diff --git a/server/tests/plugins/plugin-helpers.ts b/server/tests/plugins/plugin-helpers.ts
index 20020ec41..f72de8229 100644
--- a/server/tests/plugins/plugin-helpers.ts
+++ b/server/tests/plugins/plugin-helpers.ts
@@ -133,6 +133,7 @@ describe('Test plugin helpers', function () {
133 }) 133 })
134 134
135 expect(res.body.username).to.equal('root') 135 expect(res.body.username).to.equal('root')
136 expect(res.body.displayName).to.equal('root')
136 expect(res.body.isAdmin).to.be.true 137 expect(res.body.isAdmin).to.be.true
137 expect(res.body.isModerator).to.be.false 138 expect(res.body.isModerator).to.be.false
138 expect(res.body.isUser).to.be.false 139 expect(res.body.isUser).to.be.false
diff --git a/server/tests/plugins/plugin-transcoding.ts b/server/tests/plugins/plugin-transcoding.ts
index c834b6985..eefb2294d 100644
--- a/server/tests/plugins/plugin-transcoding.ts
+++ b/server/tests/plugins/plugin-transcoding.ts
@@ -125,7 +125,7 @@ describe('Test transcoding plugins', function () {
125 }) 125 })
126 126
127 it('Should not use the plugin profile if not chosen by the admin', async function () { 127 it('Should not use the plugin profile if not chosen by the admin', async function () {
128 this.timeout(120000) 128 this.timeout(240000)
129 129
130 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid 130 const videoUUID = (await uploadVideoAndGetId({ server, videoName: 'video' })).uuid
131 await waitJobs([ server ]) 131 await waitJobs([ server ])
@@ -134,7 +134,7 @@ describe('Test transcoding plugins', function () {
134 }) 134 })
135 135
136 it('Should use the vod profile', async function () { 136 it('Should use the vod profile', async function () {
137 this.timeout(120000) 137 this.timeout(240000)
138 138
139 await updateConf(server, 'low-vod', 'default') 139 await updateConf(server, 'low-vod', 'default')
140 140
@@ -145,7 +145,7 @@ describe('Test transcoding plugins', function () {
145 }) 145 })
146 146
147 it('Should apply input options in vod profile', async function () { 147 it('Should apply input options in vod profile', async function () {
148 this.timeout(120000) 148 this.timeout(240000)
149 149
150 await updateConf(server, 'input-options-vod', 'default') 150 await updateConf(server, 'input-options-vod', 'default')
151 151
@@ -156,7 +156,7 @@ describe('Test transcoding plugins', function () {
156 }) 156 })
157 157
158 it('Should apply the scale filter in vod profile', async function () { 158 it('Should apply the scale filter in vod profile', async function () {
159 this.timeout(120000) 159 this.timeout(240000)
160 160
161 await updateConf(server, 'bad-scale-vod', 'default') 161 await updateConf(server, 'bad-scale-vod', 'default')
162 162
@@ -172,7 +172,7 @@ describe('Test transcoding plugins', function () {
172 }) 172 })
173 173
174 it('Should not use the plugin profile if not chosen by the admin', async function () { 174 it('Should not use the plugin profile if not chosen by the admin', async function () {
175 this.timeout(120000) 175 this.timeout(240000)
176 176
177 const liveVideoId = await createLiveWrapper(server) 177 const liveVideoId = await createLiveWrapper(server)
178 178
@@ -184,7 +184,7 @@ describe('Test transcoding plugins', function () {
184 }) 184 })
185 185
186 it('Should use the live profile', async function () { 186 it('Should use the live profile', async function () {
187 this.timeout(120000) 187 this.timeout(240000)
188 188
189 await updateConf(server, 'low-vod', 'low-live') 189 await updateConf(server, 'low-vod', 'low-live')
190 190
@@ -198,7 +198,7 @@ describe('Test transcoding plugins', function () {
198 }) 198 })
199 199
200 it('Should apply the input options on live profile', async function () { 200 it('Should apply the input options on live profile', async function () {
201 this.timeout(120000) 201 this.timeout(240000)
202 202
203 await updateConf(server, 'low-vod', 'input-options-live') 203 await updateConf(server, 'low-vod', 'input-options-live')
204 204
@@ -212,7 +212,7 @@ describe('Test transcoding plugins', function () {
212 }) 212 })
213 213
214 it('Should apply the scale filter name on live profile', async function () { 214 it('Should apply the scale filter name on live profile', async function () {
215 this.timeout(120000) 215 this.timeout(240000)
216 216
217 await updateConf(server, 'low-vod', 'bad-scale-live') 217 await updateConf(server, 'low-vod', 'bad-scale-live')
218 218
@@ -223,7 +223,7 @@ describe('Test transcoding plugins', function () {
223 }) 223 })
224 224
225 it('Should default to the default profile if the specified profile does not exist', async function () { 225 it('Should default to the default profile if the specified profile does not exist', async function () {
226 this.timeout(120000) 226 this.timeout(240000)
227 227
228 await uninstallPlugin({ url: server.url, accessToken: server.accessToken, npmName: 'peertube-plugin-test-transcoding-one' }) 228 await uninstallPlugin({ url: server.url, accessToken: server.accessToken, npmName: 'peertube-plugin-test-transcoding-one' })
229 229
@@ -268,7 +268,7 @@ describe('Test transcoding plugins', function () {
268 }) 268 })
269 269
270 it('Should use the new live encoders', async function () { 270 it('Should use the new live encoders', async function () {
271 this.timeout(120000) 271 this.timeout(240000)
272 272
273 const liveVideoId = await createLiveWrapper(server) 273 const liveVideoId = await createLiveWrapper(server)
274 274