diff options
Diffstat (limited to 'server/tests')
70 files changed, 3176 insertions, 769 deletions
diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts index cd7a38459..961093bb5 100644 --- a/server/tests/api/check-params/index.ts +++ b/server/tests/api/check-params/index.ts | |||
@@ -2,6 +2,7 @@ import './abuses' | |||
2 | import './accounts' | 2 | import './accounts' |
3 | import './blocklist' | 3 | import './blocklist' |
4 | import './bulk' | 4 | import './bulk' |
5 | import './channel-import-videos' | ||
5 | import './config' | 6 | import './config' |
6 | import './contact-form' | 7 | import './contact-form' |
7 | import './custom-pages' | 8 | import './custom-pages' |
@@ -17,6 +18,7 @@ import './redundancy' | |||
17 | import './search' | 18 | import './search' |
18 | import './services' | 19 | import './services' |
19 | import './transcoding' | 20 | import './transcoding' |
21 | import './two-factor' | ||
20 | import './upload-quota' | 22 | import './upload-quota' |
21 | import './user-notifications' | 23 | import './user-notifications' |
22 | import './user-subscriptions' | 24 | import './user-subscriptions' |
@@ -24,15 +26,15 @@ import './users-admin' | |||
24 | import './users' | 26 | import './users' |
25 | import './video-blacklist' | 27 | import './video-blacklist' |
26 | import './video-captions' | 28 | import './video-captions' |
29 | import './video-channel-syncs' | ||
27 | import './video-channels' | 30 | import './video-channels' |
28 | import './video-comments' | 31 | import './video-comments' |
29 | import './video-files' | 32 | import './video-files' |
30 | import './video-imports' | 33 | import './video-imports' |
31 | import './video-channel-syncs' | ||
32 | import './channel-import-videos' | ||
33 | import './video-playlists' | 34 | import './video-playlists' |
34 | import './video-source' | 35 | import './video-source' |
35 | import './video-studio' | 36 | import './video-studio' |
37 | import './video-token' | ||
36 | import './videos-common-filters' | 38 | import './videos-common-filters' |
37 | import './videos-history' | 39 | import './videos-history' |
38 | import './videos-overviews' | 40 | import './videos-overviews' |
diff --git a/server/tests/api/check-params/live.ts b/server/tests/api/check-params/live.ts index 3f553c42b..2eff9414b 100644 --- a/server/tests/api/check-params/live.ts +++ b/server/tests/api/check-params/live.ts | |||
@@ -502,6 +502,23 @@ describe('Test video lives API validator', function () { | |||
502 | await stopFfmpeg(ffmpegCommand) | 502 | await stopFfmpeg(ffmpegCommand) |
503 | }) | 503 | }) |
504 | 504 | ||
505 | it('Should fail to change live privacy if it has already started', async function () { | ||
506 | this.timeout(40000) | ||
507 | |||
508 | const live = await command.get({ videoId: video.id }) | ||
509 | |||
510 | const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) | ||
511 | |||
512 | await command.waitUntilPublished({ videoId: video.id }) | ||
513 | await server.videos.update({ | ||
514 | id: video.id, | ||
515 | attributes: { privacy: VideoPrivacy.PUBLIC }, | ||
516 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
517 | }) | ||
518 | |||
519 | await stopFfmpeg(ffmpegCommand) | ||
520 | }) | ||
521 | |||
505 | it('Should fail to stream twice in the save live', async function () { | 522 | it('Should fail to stream twice in the save live', async function () { |
506 | this.timeout(40000) | 523 | this.timeout(40000) |
507 | 524 | ||
diff --git a/server/tests/api/check-params/two-factor.ts b/server/tests/api/check-params/two-factor.ts new file mode 100644 index 000000000..f8365f1b5 --- /dev/null +++ b/server/tests/api/check-params/two-factor.ts | |||
@@ -0,0 +1,288 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { HttpStatusCode } from '@shared/models' | ||
4 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, TwoFactorCommand } from '@shared/server-commands' | ||
5 | |||
6 | describe('Test two factor API validators', function () { | ||
7 | let server: PeerTubeServer | ||
8 | |||
9 | let rootId: number | ||
10 | let rootPassword: string | ||
11 | let rootRequestToken: string | ||
12 | let rootOTPToken: string | ||
13 | |||
14 | let userId: number | ||
15 | let userToken = '' | ||
16 | let userPassword: string | ||
17 | let userRequestToken: string | ||
18 | let userOTPToken: string | ||
19 | |||
20 | // --------------------------------------------------------------- | ||
21 | |||
22 | before(async function () { | ||
23 | this.timeout(30000) | ||
24 | |||
25 | { | ||
26 | server = await createSingleServer(1) | ||
27 | await setAccessTokensToServers([ server ]) | ||
28 | } | ||
29 | |||
30 | { | ||
31 | const result = await server.users.generate('user1') | ||
32 | userToken = result.token | ||
33 | userId = result.userId | ||
34 | userPassword = result.password | ||
35 | } | ||
36 | |||
37 | { | ||
38 | const { id } = await server.users.getMyInfo() | ||
39 | rootId = id | ||
40 | rootPassword = server.store.user.password | ||
41 | } | ||
42 | }) | ||
43 | |||
44 | describe('When requesting two factor', function () { | ||
45 | |||
46 | it('Should fail with an unknown user id', async function () { | ||
47 | await server.twoFactor.request({ userId: 42, currentPassword: rootPassword, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
48 | }) | ||
49 | |||
50 | it('Should fail with an invalid user id', async function () { | ||
51 | await server.twoFactor.request({ | ||
52 | userId: 'invalid' as any, | ||
53 | currentPassword: rootPassword, | ||
54 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
55 | }) | ||
56 | }) | ||
57 | |||
58 | it('Should fail to request another user two factor without the appropriate rights', async function () { | ||
59 | await server.twoFactor.request({ | ||
60 | userId: rootId, | ||
61 | token: userToken, | ||
62 | currentPassword: userPassword, | ||
63 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
64 | }) | ||
65 | }) | ||
66 | |||
67 | it('Should succeed to request another user two factor with the appropriate rights', async function () { | ||
68 | await server.twoFactor.request({ userId, currentPassword: rootPassword }) | ||
69 | }) | ||
70 | |||
71 | it('Should fail to request two factor without a password', async function () { | ||
72 | await server.twoFactor.request({ | ||
73 | userId, | ||
74 | token: userToken, | ||
75 | currentPassword: undefined, | ||
76 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
77 | }) | ||
78 | }) | ||
79 | |||
80 | it('Should fail to request two factor with an incorrect password', async function () { | ||
81 | await server.twoFactor.request({ | ||
82 | userId, | ||
83 | token: userToken, | ||
84 | currentPassword: rootPassword, | ||
85 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
86 | }) | ||
87 | }) | ||
88 | |||
89 | it('Should succeed to request two factor without a password when targeting a remote user with an admin account', async function () { | ||
90 | await server.twoFactor.request({ userId }) | ||
91 | }) | ||
92 | |||
93 | it('Should fail to request two factor without a password when targeting myself with an admin account', async function () { | ||
94 | await server.twoFactor.request({ userId: rootId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
95 | await server.twoFactor.request({ userId: rootId, currentPassword: 'bad', expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
96 | }) | ||
97 | |||
98 | it('Should succeed to request my two factor auth', async function () { | ||
99 | { | ||
100 | const { otpRequest } = await server.twoFactor.request({ userId, token: userToken, currentPassword: userPassword }) | ||
101 | userRequestToken = otpRequest.requestToken | ||
102 | userOTPToken = TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate() | ||
103 | } | ||
104 | |||
105 | { | ||
106 | const { otpRequest } = await server.twoFactor.request({ userId: rootId, currentPassword: rootPassword }) | ||
107 | rootRequestToken = otpRequest.requestToken | ||
108 | rootOTPToken = TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate() | ||
109 | } | ||
110 | }) | ||
111 | }) | ||
112 | |||
113 | describe('When confirming two factor request', function () { | ||
114 | |||
115 | it('Should fail with an unknown user id', async function () { | ||
116 | await server.twoFactor.confirmRequest({ | ||
117 | userId: 42, | ||
118 | requestToken: rootRequestToken, | ||
119 | otpToken: rootOTPToken, | ||
120 | expectedStatus: HttpStatusCode.NOT_FOUND_404 | ||
121 | }) | ||
122 | }) | ||
123 | |||
124 | it('Should fail with an invalid user id', async function () { | ||
125 | await server.twoFactor.confirmRequest({ | ||
126 | userId: 'invalid' as any, | ||
127 | requestToken: rootRequestToken, | ||
128 | otpToken: rootOTPToken, | ||
129 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
130 | }) | ||
131 | }) | ||
132 | |||
133 | it('Should fail to confirm another user two factor request without the appropriate rights', async function () { | ||
134 | await server.twoFactor.confirmRequest({ | ||
135 | userId: rootId, | ||
136 | token: userToken, | ||
137 | requestToken: rootRequestToken, | ||
138 | otpToken: rootOTPToken, | ||
139 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
140 | }) | ||
141 | }) | ||
142 | |||
143 | it('Should fail without request token', async function () { | ||
144 | await server.twoFactor.confirmRequest({ | ||
145 | userId, | ||
146 | requestToken: undefined, | ||
147 | otpToken: userOTPToken, | ||
148 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
149 | }) | ||
150 | }) | ||
151 | |||
152 | it('Should fail with an invalid request token', async function () { | ||
153 | await server.twoFactor.confirmRequest({ | ||
154 | userId, | ||
155 | requestToken: 'toto', | ||
156 | otpToken: userOTPToken, | ||
157 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
158 | }) | ||
159 | }) | ||
160 | |||
161 | it('Should fail with request token of another user', async function () { | ||
162 | await server.twoFactor.confirmRequest({ | ||
163 | userId, | ||
164 | requestToken: rootRequestToken, | ||
165 | otpToken: userOTPToken, | ||
166 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
167 | }) | ||
168 | }) | ||
169 | |||
170 | it('Should fail without an otp token', async function () { | ||
171 | await server.twoFactor.confirmRequest({ | ||
172 | userId, | ||
173 | requestToken: userRequestToken, | ||
174 | otpToken: undefined, | ||
175 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
176 | }) | ||
177 | }) | ||
178 | |||
179 | it('Should fail with a bad otp token', async function () { | ||
180 | await server.twoFactor.confirmRequest({ | ||
181 | userId, | ||
182 | requestToken: userRequestToken, | ||
183 | otpToken: '123456', | ||
184 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
185 | }) | ||
186 | }) | ||
187 | |||
188 | it('Should succeed to confirm another user two factor request with the appropriate rights', async function () { | ||
189 | await server.twoFactor.confirmRequest({ | ||
190 | userId, | ||
191 | requestToken: userRequestToken, | ||
192 | otpToken: userOTPToken | ||
193 | }) | ||
194 | |||
195 | // Reinit | ||
196 | await server.twoFactor.disable({ userId, currentPassword: rootPassword }) | ||
197 | }) | ||
198 | |||
199 | it('Should succeed to confirm my two factor request', async function () { | ||
200 | await server.twoFactor.confirmRequest({ | ||
201 | userId, | ||
202 | token: userToken, | ||
203 | requestToken: userRequestToken, | ||
204 | otpToken: userOTPToken | ||
205 | }) | ||
206 | }) | ||
207 | |||
208 | it('Should fail to confirm again two factor request', async function () { | ||
209 | await server.twoFactor.confirmRequest({ | ||
210 | userId, | ||
211 | token: userToken, | ||
212 | requestToken: userRequestToken, | ||
213 | otpToken: userOTPToken, | ||
214 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
215 | }) | ||
216 | }) | ||
217 | }) | ||
218 | |||
219 | describe('When disabling two factor', function () { | ||
220 | |||
221 | it('Should fail with an unknown user id', async function () { | ||
222 | await server.twoFactor.disable({ | ||
223 | userId: 42, | ||
224 | currentPassword: rootPassword, | ||
225 | expectedStatus: HttpStatusCode.NOT_FOUND_404 | ||
226 | }) | ||
227 | }) | ||
228 | |||
229 | it('Should fail with an invalid user id', async function () { | ||
230 | await server.twoFactor.disable({ | ||
231 | userId: 'invalid' as any, | ||
232 | currentPassword: rootPassword, | ||
233 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
234 | }) | ||
235 | }) | ||
236 | |||
237 | it('Should fail to disable another user two factor without the appropriate rights', async function () { | ||
238 | await server.twoFactor.disable({ | ||
239 | userId: rootId, | ||
240 | token: userToken, | ||
241 | currentPassword: userPassword, | ||
242 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
243 | }) | ||
244 | }) | ||
245 | |||
246 | it('Should fail to disable two factor with an incorrect password', async function () { | ||
247 | await server.twoFactor.disable({ | ||
248 | userId, | ||
249 | token: userToken, | ||
250 | currentPassword: rootPassword, | ||
251 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
252 | }) | ||
253 | }) | ||
254 | |||
255 | it('Should succeed to disable two factor without a password when targeting a remote user with an admin account', async function () { | ||
256 | await server.twoFactor.disable({ userId }) | ||
257 | await server.twoFactor.requestAndConfirm({ userId }) | ||
258 | }) | ||
259 | |||
260 | it('Should fail to disable two factor without a password when targeting myself with an admin account', async function () { | ||
261 | await server.twoFactor.disable({ userId: rootId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
262 | await server.twoFactor.disable({ userId: rootId, currentPassword: 'bad', expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
263 | }) | ||
264 | |||
265 | it('Should succeed to disable another user two factor with the appropriate rights', async function () { | ||
266 | await server.twoFactor.disable({ userId, currentPassword: rootPassword }) | ||
267 | |||
268 | await server.twoFactor.requestAndConfirm({ userId }) | ||
269 | }) | ||
270 | |||
271 | it('Should succeed to update my two factor auth', async function () { | ||
272 | await server.twoFactor.disable({ userId, token: userToken, currentPassword: userPassword }) | ||
273 | }) | ||
274 | |||
275 | it('Should fail to disable again two factor', async function () { | ||
276 | await server.twoFactor.disable({ | ||
277 | userId, | ||
278 | token: userToken, | ||
279 | currentPassword: userPassword, | ||
280 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
281 | }) | ||
282 | }) | ||
283 | }) | ||
284 | |||
285 | after(async function () { | ||
286 | await cleanupTests([ server ]) | ||
287 | }) | ||
288 | }) | ||
diff --git a/server/tests/api/check-params/video-files.ts b/server/tests/api/check-params/video-files.ts index aa4de2c83..9dc59a1b5 100644 --- a/server/tests/api/check-params/video-files.ts +++ b/server/tests/api/check-params/video-files.ts | |||
@@ -1,10 +1,12 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { HttpStatusCode, UserRole } from '@shared/models' | 3 | import { getAllFiles } from '@shared/core-utils' |
4 | import { HttpStatusCode, UserRole, VideoDetails, VideoPrivacy } from '@shared/models' | ||
4 | import { | 5 | import { |
5 | cleanupTests, | 6 | cleanupTests, |
6 | createMultipleServers, | 7 | createMultipleServers, |
7 | doubleFollow, | 8 | doubleFollow, |
9 | makeRawRequest, | ||
8 | PeerTubeServer, | 10 | PeerTubeServer, |
9 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
10 | waitJobs | 12 | waitJobs |
@@ -13,22 +15,9 @@ import { | |||
13 | describe('Test videos files', function () { | 15 | describe('Test videos files', function () { |
14 | let servers: PeerTubeServer[] | 16 | let servers: PeerTubeServer[] |
15 | 17 | ||
16 | let webtorrentId: string | ||
17 | let hlsId: string | ||
18 | let remoteId: string | ||
19 | |||
20 | let userToken: string | 18 | let userToken: string |
21 | let moderatorToken: string | 19 | let moderatorToken: string |
22 | 20 | ||
23 | let validId1: string | ||
24 | let validId2: string | ||
25 | |||
26 | let hlsFileId: number | ||
27 | let webtorrentFileId: number | ||
28 | |||
29 | let remoteHLSFileId: number | ||
30 | let remoteWebtorrentFileId: number | ||
31 | |||
32 | // --------------------------------------------------------------- | 21 | // --------------------------------------------------------------- |
33 | 22 | ||
34 | before(async function () { | 23 | before(async function () { |
@@ -41,117 +30,163 @@ describe('Test videos files', function () { | |||
41 | 30 | ||
42 | userToken = await servers[0].users.generateUserAndToken('user', UserRole.USER) | 31 | userToken = await servers[0].users.generateUserAndToken('user', UserRole.USER) |
43 | moderatorToken = await servers[0].users.generateUserAndToken('moderator', UserRole.MODERATOR) | 32 | moderatorToken = await servers[0].users.generateUserAndToken('moderator', UserRole.MODERATOR) |
33 | }) | ||
44 | 34 | ||
45 | { | 35 | describe('Getting metadata', function () { |
46 | const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' }) | 36 | let video: VideoDetails |
47 | await waitJobs(servers) | 37 | |
38 | before(async function () { | ||
39 | const { uuid } = await servers[0].videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) | ||
40 | video = await servers[0].videos.getWithToken({ id: uuid }) | ||
41 | }) | ||
42 | |||
43 | it('Should not get metadata of private video without token', async function () { | ||
44 | for (const file of getAllFiles(video)) { | ||
45 | await makeRawRequest({ url: file.metadataUrl, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) | ||
46 | } | ||
47 | }) | ||
48 | |||
49 | it('Should not get metadata of private video without the appropriate token', async function () { | ||
50 | for (const file of getAllFiles(video)) { | ||
51 | await makeRawRequest({ url: file.metadataUrl, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
52 | } | ||
53 | }) | ||
54 | |||
55 | it('Should get metadata of private video with the appropriate token', async function () { | ||
56 | for (const file of getAllFiles(video)) { | ||
57 | await makeRawRequest({ url: file.metadataUrl, token: servers[0].accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
58 | } | ||
59 | }) | ||
60 | }) | ||
61 | |||
62 | describe('Deleting files', function () { | ||
63 | let webtorrentId: string | ||
64 | let hlsId: string | ||
65 | let remoteId: string | ||
66 | |||
67 | let validId1: string | ||
68 | let validId2: string | ||
48 | 69 | ||
49 | const video = await servers[1].videos.get({ id: uuid }) | 70 | let hlsFileId: number |
50 | remoteId = video.uuid | 71 | let webtorrentFileId: number |
51 | remoteHLSFileId = video.streamingPlaylists[0].files[0].id | ||
52 | remoteWebtorrentFileId = video.files[0].id | ||
53 | } | ||
54 | 72 | ||
55 | { | 73 | let remoteHLSFileId: number |
56 | await servers[0].config.enableTranscoding(true, true) | 74 | let remoteWebtorrentFileId: number |
75 | |||
76 | before(async function () { | ||
77 | this.timeout(300_000) | ||
57 | 78 | ||
58 | { | 79 | { |
59 | const { uuid } = await servers[0].videos.quickUpload({ name: 'both 1' }) | 80 | const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' }) |
60 | await waitJobs(servers) | 81 | await waitJobs(servers) |
61 | 82 | ||
62 | const video = await servers[0].videos.get({ id: uuid }) | 83 | const video = await servers[1].videos.get({ id: uuid }) |
63 | validId1 = video.uuid | 84 | remoteId = video.uuid |
64 | hlsFileId = video.streamingPlaylists[0].files[0].id | 85 | remoteHLSFileId = video.streamingPlaylists[0].files[0].id |
65 | webtorrentFileId = video.files[0].id | 86 | remoteWebtorrentFileId = video.files[0].id |
66 | } | 87 | } |
67 | 88 | ||
68 | { | 89 | { |
69 | const { uuid } = await servers[0].videos.quickUpload({ name: 'both 2' }) | 90 | await servers[0].config.enableTranscoding(true, true) |
70 | validId2 = uuid | 91 | |
92 | { | ||
93 | const { uuid } = await servers[0].videos.quickUpload({ name: 'both 1' }) | ||
94 | await waitJobs(servers) | ||
95 | |||
96 | const video = await servers[0].videos.get({ id: uuid }) | ||
97 | validId1 = video.uuid | ||
98 | hlsFileId = video.streamingPlaylists[0].files[0].id | ||
99 | webtorrentFileId = video.files[0].id | ||
100 | } | ||
101 | |||
102 | { | ||
103 | const { uuid } = await servers[0].videos.quickUpload({ name: 'both 2' }) | ||
104 | validId2 = uuid | ||
105 | } | ||
71 | } | 106 | } |
72 | } | ||
73 | 107 | ||
74 | await waitJobs(servers) | 108 | await waitJobs(servers) |
75 | 109 | ||
76 | { | 110 | { |
77 | await servers[0].config.enableTranscoding(false, true) | 111 | await servers[0].config.enableTranscoding(false, true) |
78 | const { uuid } = await servers[0].videos.quickUpload({ name: 'hls' }) | 112 | const { uuid } = await servers[0].videos.quickUpload({ name: 'hls' }) |
79 | hlsId = uuid | 113 | hlsId = uuid |
80 | } | 114 | } |
81 | 115 | ||
82 | await waitJobs(servers) | 116 | await waitJobs(servers) |
83 | 117 | ||
84 | { | 118 | { |
85 | await servers[0].config.enableTranscoding(false, true) | 119 | await servers[0].config.enableTranscoding(false, true) |
86 | const { uuid } = await servers[0].videos.quickUpload({ name: 'webtorrent' }) | 120 | const { uuid } = await servers[0].videos.quickUpload({ name: 'webtorrent' }) |
87 | webtorrentId = uuid | 121 | webtorrentId = uuid |
88 | } | 122 | } |
89 | 123 | ||
90 | await waitJobs(servers) | 124 | await waitJobs(servers) |
91 | }) | 125 | }) |
92 | 126 | ||
93 | it('Should not delete files of a unknown video', async function () { | 127 | it('Should not delete files of a unknown video', async function () { |
94 | const expectedStatus = HttpStatusCode.NOT_FOUND_404 | 128 | const expectedStatus = HttpStatusCode.NOT_FOUND_404 |
95 | 129 | ||
96 | await servers[0].videos.removeHLSPlaylist({ videoId: 404, expectedStatus }) | 130 | await servers[0].videos.removeHLSPlaylist({ videoId: 404, expectedStatus }) |
97 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: 404, expectedStatus }) | 131 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: 404, expectedStatus }) |
98 | 132 | ||
99 | await servers[0].videos.removeHLSFile({ videoId: 404, fileId: hlsFileId, expectedStatus }) | 133 | await servers[0].videos.removeHLSFile({ videoId: 404, fileId: hlsFileId, expectedStatus }) |
100 | await servers[0].videos.removeWebTorrentFile({ videoId: 404, fileId: webtorrentFileId, expectedStatus }) | 134 | await servers[0].videos.removeWebTorrentFile({ videoId: 404, fileId: webtorrentFileId, expectedStatus }) |
101 | }) | 135 | }) |
102 | 136 | ||
103 | it('Should not delete unknown files', async function () { | 137 | it('Should not delete unknown files', async function () { |
104 | const expectedStatus = HttpStatusCode.NOT_FOUND_404 | 138 | const expectedStatus = HttpStatusCode.NOT_FOUND_404 |
105 | 139 | ||
106 | await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: webtorrentFileId, expectedStatus }) | 140 | await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: webtorrentFileId, expectedStatus }) |
107 | await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: hlsFileId, expectedStatus }) | 141 | await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: hlsFileId, expectedStatus }) |
108 | }) | 142 | }) |
109 | 143 | ||
110 | it('Should not delete files of a remote video', async function () { | 144 | it('Should not delete files of a remote video', async function () { |
111 | const expectedStatus = HttpStatusCode.BAD_REQUEST_400 | 145 | const expectedStatus = HttpStatusCode.BAD_REQUEST_400 |
112 | 146 | ||
113 | await servers[0].videos.removeHLSPlaylist({ videoId: remoteId, expectedStatus }) | 147 | await servers[0].videos.removeHLSPlaylist({ videoId: remoteId, expectedStatus }) |
114 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: remoteId, expectedStatus }) | 148 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: remoteId, expectedStatus }) |
115 | 149 | ||
116 | await servers[0].videos.removeHLSFile({ videoId: remoteId, fileId: remoteHLSFileId, expectedStatus }) | 150 | await servers[0].videos.removeHLSFile({ videoId: remoteId, fileId: remoteHLSFileId, expectedStatus }) |
117 | await servers[0].videos.removeWebTorrentFile({ videoId: remoteId, fileId: remoteWebtorrentFileId, expectedStatus }) | 151 | await servers[0].videos.removeWebTorrentFile({ videoId: remoteId, fileId: remoteWebtorrentFileId, expectedStatus }) |
118 | }) | 152 | }) |
119 | 153 | ||
120 | it('Should not delete files by a non admin user', async function () { | 154 | it('Should not delete files by a non admin user', async function () { |
121 | const expectedStatus = HttpStatusCode.FORBIDDEN_403 | 155 | const expectedStatus = HttpStatusCode.FORBIDDEN_403 |
122 | 156 | ||
123 | await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: userToken, expectedStatus }) | 157 | await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: userToken, expectedStatus }) |
124 | await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: moderatorToken, expectedStatus }) | 158 | await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: moderatorToken, expectedStatus }) |
125 | 159 | ||
126 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: validId1, token: userToken, expectedStatus }) | 160 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: validId1, token: userToken, expectedStatus }) |
127 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: validId1, token: moderatorToken, expectedStatus }) | 161 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: validId1, token: moderatorToken, expectedStatus }) |
128 | 162 | ||
129 | await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: userToken, expectedStatus }) | 163 | await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: userToken, expectedStatus }) |
130 | await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: moderatorToken, expectedStatus }) | 164 | await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: moderatorToken, expectedStatus }) |
131 | 165 | ||
132 | await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: webtorrentFileId, token: userToken, expectedStatus }) | 166 | await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: webtorrentFileId, token: userToken, expectedStatus }) |
133 | await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: webtorrentFileId, token: moderatorToken, expectedStatus }) | 167 | await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: webtorrentFileId, token: moderatorToken, expectedStatus }) |
134 | }) | 168 | }) |
135 | 169 | ||
136 | it('Should not delete files if the files are not available', async function () { | 170 | it('Should not delete files if the files are not available', async function () { |
137 | await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | 171 | await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) |
138 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: webtorrentId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | 172 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: webtorrentId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) |
139 | 173 | ||
140 | await servers[0].videos.removeHLSFile({ videoId: hlsId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | 174 | await servers[0].videos.removeHLSFile({ videoId: hlsId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) |
141 | await servers[0].videos.removeWebTorrentFile({ videoId: webtorrentId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | 175 | await servers[0].videos.removeWebTorrentFile({ videoId: webtorrentId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) |
142 | }) | 176 | }) |
143 | 177 | ||
144 | it('Should not delete files if no both versions are available', async function () { | 178 | it('Should not delete files if no both versions are available', async function () { |
145 | await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | 179 | await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) |
146 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: webtorrentId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | 180 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: webtorrentId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) |
147 | }) | 181 | }) |
148 | 182 | ||
149 | it('Should delete files if both versions are available', async function () { | 183 | it('Should delete files if both versions are available', async function () { |
150 | await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId }) | 184 | await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId }) |
151 | await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: webtorrentFileId }) | 185 | await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: webtorrentFileId }) |
152 | 186 | ||
153 | await servers[0].videos.removeHLSPlaylist({ videoId: validId1 }) | 187 | await servers[0].videos.removeHLSPlaylist({ videoId: validId1 }) |
154 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: validId2 }) | 188 | await servers[0].videos.removeAllWebTorrentFiles({ videoId: validId2 }) |
189 | }) | ||
155 | }) | 190 | }) |
156 | 191 | ||
157 | after(async function () { | 192 | after(async function () { |
diff --git a/server/tests/api/check-params/video-token.ts b/server/tests/api/check-params/video-token.ts new file mode 100644 index 000000000..7acb9d580 --- /dev/null +++ b/server/tests/api/check-params/video-token.ts | |||
@@ -0,0 +1,44 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | ||
4 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | ||
5 | |||
6 | describe('Test video tokens', function () { | ||
7 | let server: PeerTubeServer | ||
8 | let videoId: string | ||
9 | let userToken: string | ||
10 | |||
11 | // --------------------------------------------------------------- | ||
12 | |||
13 | before(async function () { | ||
14 | this.timeout(300_000) | ||
15 | |||
16 | server = await createSingleServer(1) | ||
17 | await setAccessTokensToServers([ server ]) | ||
18 | |||
19 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) | ||
20 | videoId = uuid | ||
21 | |||
22 | userToken = await server.users.generateUserAndToken('user1') | ||
23 | }) | ||
24 | |||
25 | it('Should not generate tokens for unauthenticated user', async function () { | ||
26 | await server.videoToken.create({ videoId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) | ||
27 | }) | ||
28 | |||
29 | it('Should not generate tokens of unknown video', async function () { | ||
30 | await server.videoToken.create({ videoId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
31 | }) | ||
32 | |||
33 | it('Should not generate tokens of a non owned video', async function () { | ||
34 | await server.videoToken.create({ videoId, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
35 | }) | ||
36 | |||
37 | it('Should generate token', async function () { | ||
38 | await server.videoToken.create({ videoId }) | ||
39 | }) | ||
40 | |||
41 | after(async function () { | ||
42 | await cleanupTests([ server ]) | ||
43 | }) | ||
44 | }) | ||
diff --git a/server/tests/api/live/live-constraints.ts b/server/tests/api/live/live-constraints.ts index 64ef73a2a..c82585a9e 100644 --- a/server/tests/api/live/live-constraints.ts +++ b/server/tests/api/live/live-constraints.ts | |||
@@ -49,7 +49,7 @@ describe('Test live constraints', function () { | |||
49 | expect(video.duration).to.be.greaterThan(0) | 49 | expect(video.duration).to.be.greaterThan(0) |
50 | } | 50 | } |
51 | 51 | ||
52 | await checkLiveCleanup(servers[0], videoId, resolutions) | 52 | await checkLiveCleanup({ server: servers[0], permanent: false, videoUUID: videoId, savedResolutions: resolutions }) |
53 | } | 53 | } |
54 | 54 | ||
55 | function updateQuota (options: { total: number, daily: number }) { | 55 | function updateQuota (options: { total: number, daily: number }) { |
diff --git a/server/tests/api/live/live-fast-restream.ts b/server/tests/api/live/live-fast-restream.ts index 502959258..971df1a61 100644 --- a/server/tests/api/live/live-fast-restream.ts +++ b/server/tests/api/live/live-fast-restream.ts | |||
@@ -43,12 +43,31 @@ describe('Fast restream in live', function () { | |||
43 | // Streaming session #1 | 43 | // Streaming session #1 |
44 | let ffmpegCommand = await server.live.sendRTMPStreamInVideo(rtmpOptions) | 44 | let ffmpegCommand = await server.live.sendRTMPStreamInVideo(rtmpOptions) |
45 | await server.live.waitUntilPublished({ videoId: liveVideoUUID }) | 45 | await server.live.waitUntilPublished({ videoId: liveVideoUUID }) |
46 | |||
47 | const video = await server.videos.get({ id: liveVideoUUID }) | ||
48 | const session1PlaylistId = video.streamingPlaylists[0].id | ||
49 | |||
46 | await stopFfmpeg(ffmpegCommand) | 50 | await stopFfmpeg(ffmpegCommand) |
47 | await server.live.waitUntilWaiting({ videoId: liveVideoUUID }) | 51 | await server.live.waitUntilWaiting({ videoId: liveVideoUUID }) |
48 | 52 | ||
49 | // Streaming session #2 | 53 | // Streaming session #2 |
50 | ffmpegCommand = await server.live.sendRTMPStreamInVideo(rtmpOptions) | 54 | ffmpegCommand = await server.live.sendRTMPStreamInVideo(rtmpOptions) |
51 | await server.live.waitUntilSegmentGeneration({ videoUUID: liveVideoUUID, segment: 0, playlistNumber: 0, totalSessions: 2 }) | 55 | |
56 | let hasNewPlaylist = false | ||
57 | do { | ||
58 | const video = await server.videos.get({ id: liveVideoUUID }) | ||
59 | hasNewPlaylist = video.streamingPlaylists.length === 1 && video.streamingPlaylists[0].id !== session1PlaylistId | ||
60 | |||
61 | await wait(100) | ||
62 | } while (!hasNewPlaylist) | ||
63 | |||
64 | await server.live.waitUntilSegmentGeneration({ | ||
65 | server, | ||
66 | videoUUID: liveVideoUUID, | ||
67 | segment: 1, | ||
68 | playlistNumber: 0, | ||
69 | objectStorage: false | ||
70 | }) | ||
52 | 71 | ||
53 | return { ffmpegCommand, liveVideoUUID } | 72 | return { ffmpegCommand, liveVideoUUID } |
54 | } | 73 | } |
@@ -59,9 +78,9 @@ describe('Fast restream in live', function () { | |||
59 | const video = await server.videos.get({ id: liveId }) | 78 | const video = await server.videos.get({ id: liveId }) |
60 | expect(video.streamingPlaylists).to.have.lengthOf(1) | 79 | expect(video.streamingPlaylists).to.have.lengthOf(1) |
61 | 80 | ||
62 | await server.live.getSegment({ videoUUID: liveId, segment: 0, playlistNumber: 0 }) | 81 | await server.live.getSegmentFile({ videoUUID: liveId, segment: 0, playlistNumber: 0 }) |
63 | await makeRawRequest(video.streamingPlaylists[0].playlistUrl, HttpStatusCode.OK_200) | 82 | await makeRawRequest({ url: video.streamingPlaylists[0].playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) |
64 | await makeRawRequest(video.streamingPlaylists[0].segmentsSha256Url, HttpStatusCode.OK_200) | 83 | await makeRawRequest({ url: video.streamingPlaylists[0].segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) |
65 | 84 | ||
66 | await wait(100) | 85 | await wait(100) |
67 | } | 86 | } |
diff --git a/server/tests/api/live/live-permanent.ts b/server/tests/api/live/live-permanent.ts index 5d227200e..4203b1bfc 100644 --- a/server/tests/api/live/live-permanent.ts +++ b/server/tests/api/live/live-permanent.ts | |||
@@ -1,6 +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 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { checkLiveCleanup } from '@server/tests/shared' | ||
4 | import { wait } from '@shared/core-utils' | 5 | import { wait } from '@shared/core-utils' |
5 | import { LiveVideoCreate, VideoPrivacy, VideoState } from '@shared/models' | 6 | import { LiveVideoCreate, VideoPrivacy, VideoState } from '@shared/models' |
6 | import { | 7 | import { |
@@ -129,6 +130,8 @@ describe('Permanent live', function () { | |||
129 | 130 | ||
130 | expect(videoDetails.streamingPlaylists).to.have.lengthOf(0) | 131 | expect(videoDetails.streamingPlaylists).to.have.lengthOf(0) |
131 | } | 132 | } |
133 | |||
134 | await checkLiveCleanup({ server: servers[0], permanent: true, videoUUID }) | ||
132 | }) | 135 | }) |
133 | 136 | ||
134 | it('Should have set this live to waiting for live state', async function () { | 137 | it('Should have set this live to waiting for live state', async function () { |
@@ -186,6 +189,15 @@ describe('Permanent live', function () { | |||
186 | } | 189 | } |
187 | }) | 190 | }) |
188 | 191 | ||
192 | it('Should remove the live and have cleaned up the directory', async function () { | ||
193 | this.timeout(60000) | ||
194 | |||
195 | await servers[0].videos.remove({ id: videoUUID }) | ||
196 | await waitJobs(servers) | ||
197 | |||
198 | await checkLiveCleanup({ server: servers[0], permanent: true, videoUUID }) | ||
199 | }) | ||
200 | |||
189 | after(async function () { | 201 | after(async function () { |
190 | await cleanupTests(servers) | 202 | await cleanupTests(servers) |
191 | }) | 203 | }) |
diff --git a/server/tests/api/live/live-save-replay.ts b/server/tests/api/live/live-save-replay.ts index 7014292d0..8f17b4566 100644 --- a/server/tests/api/live/live-save-replay.ts +++ b/server/tests/api/live/live-save-replay.ts | |||
@@ -186,7 +186,7 @@ describe('Save replay setting', function () { | |||
186 | await checkVideoState(liveVideoUUID, VideoState.LIVE_ENDED) | 186 | await checkVideoState(liveVideoUUID, VideoState.LIVE_ENDED) |
187 | 187 | ||
188 | // No resolutions saved since we did not save replay | 188 | // No resolutions saved since we did not save replay |
189 | await checkLiveCleanup(servers[0], liveVideoUUID, []) | 189 | await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) |
190 | }) | 190 | }) |
191 | 191 | ||
192 | it('Should have appropriate ended session', async function () { | 192 | it('Should have appropriate ended session', async function () { |
@@ -220,7 +220,7 @@ describe('Save replay setting', function () { | |||
220 | 220 | ||
221 | await wait(5000) | 221 | await wait(5000) |
222 | await waitJobs(servers) | 222 | await waitJobs(servers) |
223 | await checkLiveCleanup(servers[0], liveVideoUUID, []) | 223 | await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) |
224 | }) | 224 | }) |
225 | 225 | ||
226 | it('Should have blacklisted session error', async function () { | 226 | it('Should have blacklisted session error', async function () { |
@@ -238,7 +238,7 @@ describe('Save replay setting', function () { | |||
238 | await publishLiveAndDelete({ permanent: false, replay: false }) | 238 | await publishLiveAndDelete({ permanent: false, replay: false }) |
239 | 239 | ||
240 | await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) | 240 | await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) |
241 | await checkLiveCleanup(servers[0], liveVideoUUID, []) | 241 | await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) |
242 | }) | 242 | }) |
243 | }) | 243 | }) |
244 | 244 | ||
@@ -317,7 +317,7 @@ describe('Save replay setting', function () { | |||
317 | }) | 317 | }) |
318 | 318 | ||
319 | it('Should have cleaned up the live files', async function () { | 319 | it('Should have cleaned up the live files', async function () { |
320 | await checkLiveCleanup(servers[0], liveVideoUUID, [ 720 ]) | 320 | await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false, savedResolutions: [ 720 ] }) |
321 | }) | 321 | }) |
322 | 322 | ||
323 | it('Should correctly terminate the stream on blacklist and blacklist the saved replay video', async function () { | 323 | it('Should correctly terminate the stream on blacklist and blacklist the saved replay video', async function () { |
@@ -332,7 +332,7 @@ describe('Save replay setting', function () { | |||
332 | 332 | ||
333 | await wait(5000) | 333 | await wait(5000) |
334 | await waitJobs(servers) | 334 | await waitJobs(servers) |
335 | await checkLiveCleanup(servers[0], liveVideoUUID, [ 720 ]) | 335 | await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false, savedResolutions: [ 720 ] }) |
336 | }) | 336 | }) |
337 | 337 | ||
338 | it('Should correctly terminate the stream on delete and delete the video', async function () { | 338 | it('Should correctly terminate the stream on delete and delete the video', async function () { |
@@ -341,7 +341,7 @@ describe('Save replay setting', function () { | |||
341 | await publishLiveAndDelete({ permanent: false, replay: true }) | 341 | await publishLiveAndDelete({ permanent: false, replay: true }) |
342 | 342 | ||
343 | await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) | 343 | await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) |
344 | await checkLiveCleanup(servers[0], liveVideoUUID, []) | 344 | await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) |
345 | }) | 345 | }) |
346 | }) | 346 | }) |
347 | 347 | ||
@@ -413,7 +413,7 @@ describe('Save replay setting', function () { | |||
413 | }) | 413 | }) |
414 | 414 | ||
415 | it('Should have cleaned up the live files', async function () { | 415 | it('Should have cleaned up the live files', async function () { |
416 | await checkLiveCleanup(servers[0], liveVideoUUID, []) | 416 | await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) |
417 | }) | 417 | }) |
418 | 418 | ||
419 | it('Should correctly terminate the stream on blacklist and blacklist the saved replay video', async function () { | 419 | it('Should correctly terminate the stream on blacklist and blacklist the saved replay video', async function () { |
@@ -432,7 +432,7 @@ describe('Save replay setting', function () { | |||
432 | await servers[1].videos.get({ id: videoId, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | 432 | await servers[1].videos.get({ id: videoId, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) |
433 | } | 433 | } |
434 | 434 | ||
435 | await checkLiveCleanup(servers[0], liveVideoUUID, []) | 435 | await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) |
436 | }) | 436 | }) |
437 | 437 | ||
438 | it('Should correctly terminate the stream on delete and not save the video', async function () { | 438 | it('Should correctly terminate the stream on delete and not save the video', async function () { |
@@ -444,7 +444,7 @@ describe('Save replay setting', function () { | |||
444 | expect(replay).to.not.exist | 444 | expect(replay).to.not.exist |
445 | 445 | ||
446 | await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) | 446 | await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) |
447 | await checkLiveCleanup(servers[0], liveVideoUUID, []) | 447 | await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: false }) |
448 | }) | 448 | }) |
449 | }) | 449 | }) |
450 | 450 | ||
diff --git a/server/tests/api/live/live.ts b/server/tests/api/live/live.ts index c436f0f01..003cc934f 100644 --- a/server/tests/api/live/live.ts +++ b/server/tests/api/live/live.ts | |||
@@ -3,7 +3,7 @@ | |||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { basename, join } from 'path' | 4 | import { basename, join } from 'path' |
5 | import { ffprobePromise, getVideoStream } from '@server/helpers/ffmpeg' | 5 | import { ffprobePromise, getVideoStream } from '@server/helpers/ffmpeg' |
6 | import { checkLiveSegmentHash, checkResolutionsInMasterPlaylist, testImage } from '@server/tests/shared' | 6 | import { testImage, testVideoResolutions } from '@server/tests/shared' |
7 | import { getAllFiles, wait } from '@shared/core-utils' | 7 | import { getAllFiles, wait } from '@shared/core-utils' |
8 | import { | 8 | import { |
9 | HttpStatusCode, | 9 | HttpStatusCode, |
@@ -21,6 +21,7 @@ import { | |||
21 | doubleFollow, | 21 | doubleFollow, |
22 | killallServers, | 22 | killallServers, |
23 | LiveCommand, | 23 | LiveCommand, |
24 | makeGetRequest, | ||
24 | makeRawRequest, | 25 | makeRawRequest, |
25 | PeerTubeServer, | 26 | PeerTubeServer, |
26 | sendRTMPStream, | 27 | sendRTMPStream, |
@@ -157,8 +158,8 @@ describe('Test live', function () { | |||
157 | expect(video.privacy.id).to.equal(VideoPrivacy.UNLISTED) | 158 | expect(video.privacy.id).to.equal(VideoPrivacy.UNLISTED) |
158 | expect(video.nsfw).to.be.true | 159 | expect(video.nsfw).to.be.true |
159 | 160 | ||
160 | await makeRawRequest(server.url + video.thumbnailPath, HttpStatusCode.OK_200) | 161 | await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) |
161 | await makeRawRequest(server.url + video.previewPath, HttpStatusCode.OK_200) | 162 | await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 }) |
162 | } | 163 | } |
163 | }) | 164 | }) |
164 | 165 | ||
@@ -372,46 +373,6 @@ describe('Test live', function () { | |||
372 | return uuid | 373 | return uuid |
373 | } | 374 | } |
374 | 375 | ||
375 | async function testVideoResolutions (liveVideoId: string, resolutions: number[]) { | ||
376 | for (const server of servers) { | ||
377 | const { data } = await server.videos.list() | ||
378 | expect(data.find(v => v.uuid === liveVideoId)).to.exist | ||
379 | |||
380 | const video = await server.videos.get({ id: liveVideoId }) | ||
381 | |||
382 | expect(video.streamingPlaylists).to.have.lengthOf(1) | ||
383 | |||
384 | const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS) | ||
385 | expect(hlsPlaylist).to.exist | ||
386 | |||
387 | // Only finite files are displayed | ||
388 | expect(hlsPlaylist.files).to.have.lengthOf(0) | ||
389 | |||
390 | await checkResolutionsInMasterPlaylist({ server, playlistUrl: hlsPlaylist.playlistUrl, resolutions }) | ||
391 | |||
392 | for (let i = 0; i < resolutions.length; i++) { | ||
393 | const segmentNum = 3 | ||
394 | const segmentName = `${i}-00000${segmentNum}.ts` | ||
395 | await commands[0].waitUntilSegmentGeneration({ videoUUID: video.uuid, playlistNumber: i, segment: segmentNum }) | ||
396 | |||
397 | const subPlaylist = await servers[0].streamingPlaylists.get({ | ||
398 | url: `${servers[0].url}/static/streaming-playlists/hls/${video.uuid}/${i}.m3u8` | ||
399 | }) | ||
400 | |||
401 | expect(subPlaylist).to.contain(segmentName) | ||
402 | |||
403 | const baseUrlAndPath = servers[0].url + '/static/streaming-playlists/hls' | ||
404 | await checkLiveSegmentHash({ | ||
405 | server, | ||
406 | baseUrlSegment: baseUrlAndPath, | ||
407 | videoUUID: video.uuid, | ||
408 | segmentName, | ||
409 | hlsPlaylist | ||
410 | }) | ||
411 | } | ||
412 | } | ||
413 | } | ||
414 | |||
415 | function updateConf (resolutions: number[]) { | 376 | function updateConf (resolutions: number[]) { |
416 | return servers[0].config.updateCustomSubConfig({ | 377 | return servers[0].config.updateCustomSubConfig({ |
417 | newConfig: { | 378 | newConfig: { |
@@ -449,7 +410,14 @@ describe('Test live', function () { | |||
449 | await waitUntilLivePublishedOnAllServers(servers, liveVideoId) | 410 | await waitUntilLivePublishedOnAllServers(servers, liveVideoId) |
450 | await waitJobs(servers) | 411 | await waitJobs(servers) |
451 | 412 | ||
452 | await testVideoResolutions(liveVideoId, [ 720 ]) | 413 | await testVideoResolutions({ |
414 | originServer: servers[0], | ||
415 | servers, | ||
416 | liveVideoId, | ||
417 | resolutions: [ 720 ], | ||
418 | objectStorage: false, | ||
419 | transcoded: true | ||
420 | }) | ||
453 | 421 | ||
454 | await stopFfmpeg(ffmpegCommand) | 422 | await stopFfmpeg(ffmpegCommand) |
455 | }) | 423 | }) |
@@ -477,7 +445,14 @@ describe('Test live', function () { | |||
477 | await waitUntilLivePublishedOnAllServers(servers, liveVideoId) | 445 | await waitUntilLivePublishedOnAllServers(servers, liveVideoId) |
478 | await waitJobs(servers) | 446 | await waitJobs(servers) |
479 | 447 | ||
480 | await testVideoResolutions(liveVideoId, resolutions.concat([ 720 ])) | 448 | await testVideoResolutions({ |
449 | originServer: servers[0], | ||
450 | servers, | ||
451 | liveVideoId, | ||
452 | resolutions: resolutions.concat([ 720 ]), | ||
453 | objectStorage: false, | ||
454 | transcoded: true | ||
455 | }) | ||
481 | 456 | ||
482 | await stopFfmpeg(ffmpegCommand) | 457 | await stopFfmpeg(ffmpegCommand) |
483 | }) | 458 | }) |
@@ -522,7 +497,14 @@ describe('Test live', function () { | |||
522 | await waitUntilLivePublishedOnAllServers(servers, liveVideoId) | 497 | await waitUntilLivePublishedOnAllServers(servers, liveVideoId) |
523 | await waitJobs(servers) | 498 | await waitJobs(servers) |
524 | 499 | ||
525 | await testVideoResolutions(liveVideoId, resolutions) | 500 | await testVideoResolutions({ |
501 | originServer: servers[0], | ||
502 | servers, | ||
503 | liveVideoId, | ||
504 | resolutions, | ||
505 | objectStorage: false, | ||
506 | transcoded: true | ||
507 | }) | ||
526 | 508 | ||
527 | await stopFfmpeg(ffmpegCommand) | 509 | await stopFfmpeg(ffmpegCommand) |
528 | await commands[0].waitUntilEnded({ videoId: liveVideoId }) | 510 | await commands[0].waitUntilEnded({ videoId: liveVideoId }) |
@@ -538,7 +520,7 @@ describe('Test live', function () { | |||
538 | } | 520 | } |
539 | 521 | ||
540 | const minBitrateLimits = { | 522 | const minBitrateLimits = { |
541 | 720: 5500 * 1000, | 523 | 720: 4800 * 1000, |
542 | 360: 1000 * 1000, | 524 | 360: 1000 * 1000, |
543 | 240: 550 * 1000 | 525 | 240: 550 * 1000 |
544 | } | 526 | } |
@@ -551,8 +533,8 @@ describe('Test live', function () { | |||
551 | expect(video.files).to.have.lengthOf(0) | 533 | expect(video.files).to.have.lengthOf(0) |
552 | 534 | ||
553 | const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS) | 535 | const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS) |
554 | await makeRawRequest(hlsPlaylist.playlistUrl, HttpStatusCode.OK_200) | 536 | await makeRawRequest({ url: hlsPlaylist.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) |
555 | await makeRawRequest(hlsPlaylist.segmentsSha256Url, HttpStatusCode.OK_200) | 537 | await makeRawRequest({ url: hlsPlaylist.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) |
556 | 538 | ||
557 | // We should have generated random filenames | 539 | // We should have generated random filenames |
558 | expect(basename(hlsPlaylist.playlistUrl)).to.not.equal('master.m3u8') | 540 | expect(basename(hlsPlaylist.playlistUrl)).to.not.equal('master.m3u8') |
@@ -569,7 +551,7 @@ describe('Test live', function () { | |||
569 | if (resolution >= 720) { | 551 | if (resolution >= 720) { |
570 | expect(file.fps).to.be.approximately(60, 10) | 552 | expect(file.fps).to.be.approximately(60, 10) |
571 | } else { | 553 | } else { |
572 | expect(file.fps).to.be.approximately(30, 2) | 554 | expect(file.fps).to.be.approximately(30, 3) |
573 | } | 555 | } |
574 | 556 | ||
575 | const filename = basename(file.fileUrl) | 557 | const filename = basename(file.fileUrl) |
@@ -583,8 +565,8 @@ describe('Test live', function () { | |||
583 | expect(probe.format.bit_rate).to.be.below(maxBitrateLimits[videoStream.height]) | 565 | expect(probe.format.bit_rate).to.be.below(maxBitrateLimits[videoStream.height]) |
584 | expect(probe.format.bit_rate).to.be.at.least(minBitrateLimits[videoStream.height]) | 566 | expect(probe.format.bit_rate).to.be.at.least(minBitrateLimits[videoStream.height]) |
585 | 567 | ||
586 | await makeRawRequest(file.torrentUrl, HttpStatusCode.OK_200) | 568 | await makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 }) |
587 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 569 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
588 | } | 570 | } |
589 | } | 571 | } |
590 | }) | 572 | }) |
@@ -611,7 +593,14 @@ describe('Test live', function () { | |||
611 | await waitUntilLivePublishedOnAllServers(servers, liveVideoId) | 593 | await waitUntilLivePublishedOnAllServers(servers, liveVideoId) |
612 | await waitJobs(servers) | 594 | await waitJobs(servers) |
613 | 595 | ||
614 | await testVideoResolutions(liveVideoId, resolutions) | 596 | await testVideoResolutions({ |
597 | originServer: servers[0], | ||
598 | servers, | ||
599 | liveVideoId, | ||
600 | resolutions, | ||
601 | objectStorage: false, | ||
602 | transcoded: true | ||
603 | }) | ||
615 | 604 | ||
616 | await stopFfmpeg(ffmpegCommand) | 605 | await stopFfmpeg(ffmpegCommand) |
617 | await commands[0].waitUntilEnded({ videoId: liveVideoId }) | 606 | await commands[0].waitUntilEnded({ videoId: liveVideoId }) |
@@ -640,7 +629,14 @@ describe('Test live', function () { | |||
640 | await waitUntilLivePublishedOnAllServers(servers, liveVideoId) | 629 | await waitUntilLivePublishedOnAllServers(servers, liveVideoId) |
641 | await waitJobs(servers) | 630 | await waitJobs(servers) |
642 | 631 | ||
643 | await testVideoResolutions(liveVideoId, [ 720 ]) | 632 | await testVideoResolutions({ |
633 | originServer: servers[0], | ||
634 | servers, | ||
635 | liveVideoId, | ||
636 | resolutions: [ 720 ], | ||
637 | objectStorage: false, | ||
638 | transcoded: true | ||
639 | }) | ||
644 | 640 | ||
645 | await stopFfmpeg(ffmpegCommand) | 641 | await stopFfmpeg(ffmpegCommand) |
646 | await commands[0].waitUntilEnded({ videoId: liveVideoId }) | 642 | await commands[0].waitUntilEnded({ videoId: liveVideoId }) |
@@ -700,9 +696,15 @@ describe('Test live', function () { | |||
700 | commands[0].waitUntilPublished({ videoId: liveVideoReplayId }) | 696 | commands[0].waitUntilPublished({ videoId: liveVideoReplayId }) |
701 | ]) | 697 | ]) |
702 | 698 | ||
703 | await commands[0].waitUntilSegmentGeneration({ videoUUID: liveVideoId, playlistNumber: 0, segment: 2 }) | 699 | for (const videoUUID of [ liveVideoId, liveVideoReplayId, permanentLiveVideoReplayId ]) { |
704 | await commands[0].waitUntilSegmentGeneration({ videoUUID: liveVideoReplayId, playlistNumber: 0, segment: 2 }) | 700 | await commands[0].waitUntilSegmentGeneration({ |
705 | await commands[0].waitUntilSegmentGeneration({ videoUUID: permanentLiveVideoReplayId, playlistNumber: 0, segment: 2 }) | 701 | server: servers[0], |
702 | videoUUID, | ||
703 | playlistNumber: 0, | ||
704 | segment: 2, | ||
705 | objectStorage: false | ||
706 | }) | ||
707 | } | ||
706 | 708 | ||
707 | { | 709 | { |
708 | const video = await servers[0].videos.get({ id: permanentLiveVideoReplayId }) | 710 | const video = await servers[0].videos.get({ id: permanentLiveVideoReplayId }) |
diff --git a/server/tests/api/notifications/admin-notifications.ts b/server/tests/api/notifications/admin-notifications.ts index b3bb4888e..07c981a37 100644 --- a/server/tests/api/notifications/admin-notifications.ts +++ b/server/tests/api/notifications/admin-notifications.ts | |||
@@ -37,7 +37,7 @@ describe('Test admin notifications', function () { | |||
37 | plugins: { | 37 | plugins: { |
38 | index: { | 38 | index: { |
39 | enabled: true, | 39 | enabled: true, |
40 | check_latest_versions_interval: '5 seconds' | 40 | check_latest_versions_interval: '3 seconds' |
41 | } | 41 | } |
42 | } | 42 | } |
43 | } | 43 | } |
@@ -62,7 +62,7 @@ describe('Test admin notifications', function () { | |||
62 | 62 | ||
63 | describe('Latest PeerTube version notification', function () { | 63 | describe('Latest PeerTube version notification', function () { |
64 | 64 | ||
65 | it('Should not send a notification to admins if there is not a new version', async function () { | 65 | it('Should not send a notification to admins if there is no new version', async function () { |
66 | this.timeout(30000) | 66 | this.timeout(30000) |
67 | 67 | ||
68 | joinPeerTubeServer.setLatestVersion('1.4.2') | 68 | joinPeerTubeServer.setLatestVersion('1.4.2') |
@@ -71,7 +71,7 @@ describe('Test admin notifications', function () { | |||
71 | await checkNewPeerTubeVersion({ ...baseParams, latestVersion: '1.4.2', checkType: 'absence' }) | 71 | await checkNewPeerTubeVersion({ ...baseParams, latestVersion: '1.4.2', checkType: 'absence' }) |
72 | }) | 72 | }) |
73 | 73 | ||
74 | it('Should send a notification to admins on new plugin version', async function () { | 74 | it('Should send a notification to admins on new version', async function () { |
75 | this.timeout(30000) | 75 | this.timeout(30000) |
76 | 76 | ||
77 | joinPeerTubeServer.setLatestVersion('15.4.2') | 77 | joinPeerTubeServer.setLatestVersion('15.4.2') |
diff --git a/server/tests/api/notifications/moderation-notifications.ts b/server/tests/api/notifications/moderation-notifications.ts index d8a7d576e..5a632fb22 100644 --- a/server/tests/api/notifications/moderation-notifications.ts +++ b/server/tests/api/notifications/moderation-notifications.ts | |||
@@ -382,7 +382,7 @@ describe('Test moderation notifications', function () { | |||
382 | }) | 382 | }) |
383 | 383 | ||
384 | it('Should send a notification only to admin when there is a new instance follower', async function () { | 384 | it('Should send a notification only to admin when there is a new instance follower', async function () { |
385 | this.timeout(20000) | 385 | this.timeout(60000) |
386 | 386 | ||
387 | await servers[2].follows.follow({ hosts: [ servers[0].url ] }) | 387 | await servers[2].follows.follow({ hosts: [ servers[0].url ] }) |
388 | 388 | ||
@@ -545,7 +545,7 @@ describe('Test moderation notifications', function () { | |||
545 | }) | 545 | }) |
546 | 546 | ||
547 | it('Should send unblacklist but not published/subscription notes after unblacklisted if scheduled update pending', async function () { | 547 | it('Should send unblacklist but not published/subscription notes after unblacklisted if scheduled update pending', async function () { |
548 | this.timeout(40000) | 548 | this.timeout(120000) |
549 | 549 | ||
550 | const updateAt = new Date(new Date().getTime() + 1000000) | 550 | const updateAt = new Date(new Date().getTime() + 1000000) |
551 | 551 | ||
diff --git a/server/tests/api/object-storage/index.ts b/server/tests/api/object-storage/index.ts index f319d6ef5..1f4489fa3 100644 --- a/server/tests/api/object-storage/index.ts +++ b/server/tests/api/object-storage/index.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | export * from './live' | 1 | export * from './live' |
2 | export * from './video-imports' | 2 | export * from './video-imports' |
3 | export * from './video-static-file-privacy' | ||
3 | export * from './videos' | 4 | export * from './videos' |
diff --git a/server/tests/api/object-storage/live.ts b/server/tests/api/object-storage/live.ts index 0958ffe0f..ad2b554b7 100644 --- a/server/tests/api/object-storage/live.ts +++ b/server/tests/api/object-storage/live.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 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { expectStartWith } from '@server/tests/shared' | 4 | import { expectStartWith, testVideoResolutions } from '@server/tests/shared' |
5 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | 5 | import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' |
6 | import { HttpStatusCode, LiveVideoCreate, VideoFile, VideoPrivacy } from '@shared/models' | 6 | import { HttpStatusCode, LiveVideoCreate, VideoPrivacy } from '@shared/models' |
7 | import { | 7 | import { |
8 | createMultipleServers, | 8 | createMultipleServers, |
9 | doubleFollow, | 9 | doubleFollow, |
@@ -35,54 +35,56 @@ async function createLive (server: PeerTubeServer, permanent: boolean) { | |||
35 | return uuid | 35 | return uuid |
36 | } | 36 | } |
37 | 37 | ||
38 | async function checkFiles (files: VideoFile[]) { | 38 | async function checkFilesExist (servers: PeerTubeServer[], videoUUID: string, numberOfFiles: number) { |
39 | for (const file of files) { | 39 | for (const server of servers) { |
40 | expectStartWith(file.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl()) | 40 | const video = await server.videos.get({ id: videoUUID }) |
41 | 41 | ||
42 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 42 | expect(video.files).to.have.lengthOf(0) |
43 | } | 43 | expect(video.streamingPlaylists).to.have.lengthOf(1) |
44 | } | ||
45 | 44 | ||
46 | async function getFiles (server: PeerTubeServer, videoUUID: string) { | 45 | const files = video.streamingPlaylists[0].files |
47 | const video = await server.videos.get({ id: videoUUID }) | 46 | expect(files).to.have.lengthOf(numberOfFiles) |
48 | 47 | ||
49 | expect(video.files).to.have.lengthOf(0) | 48 | for (const file of files) { |
50 | expect(video.streamingPlaylists).to.have.lengthOf(1) | 49 | expectStartWith(file.fileUrl, ObjectStorageCommand.getMockPlaylistBaseUrl()) |
51 | 50 | ||
52 | return video.streamingPlaylists[0].files | 51 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
52 | } | ||
53 | } | ||
53 | } | 54 | } |
54 | 55 | ||
55 | async function streamAndEnd (servers: PeerTubeServer[], liveUUID: string) { | 56 | async function checkFilesCleanup (server: PeerTubeServer, videoUUID: string, resolutions: number[]) { |
56 | const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveUUID }) | 57 | const resolutionFiles = resolutions.map((_value, i) => `${i}.m3u8`) |
57 | await waitUntilLivePublishedOnAllServers(servers, liveUUID) | ||
58 | |||
59 | const videoLiveDetails = await servers[0].videos.get({ id: liveUUID }) | ||
60 | const liveDetails = await servers[0].live.get({ videoId: liveUUID }) | ||
61 | 58 | ||
62 | await stopFfmpeg(ffmpegCommand) | 59 | for (const playlistName of [ 'master.m3u8' ].concat(resolutionFiles)) { |
63 | 60 | await server.live.getPlaylistFile({ | |
64 | if (liveDetails.permanentLive) { | 61 | videoUUID, |
65 | await waitUntilLiveWaitingOnAllServers(servers, liveUUID) | 62 | playlistName, |
66 | } else { | 63 | expectedStatus: HttpStatusCode.NOT_FOUND_404, |
67 | await waitUntilLiveReplacedByReplayOnAllServers(servers, liveUUID) | 64 | objectStorage: true |
65 | }) | ||
68 | } | 66 | } |
69 | 67 | ||
70 | await waitJobs(servers) | 68 | await server.live.getSegmentFile({ |
71 | 69 | videoUUID, | |
72 | return { videoLiveDetails, liveDetails } | 70 | playlistNumber: 0, |
71 | segment: 0, | ||
72 | objectStorage: true, | ||
73 | expectedStatus: HttpStatusCode.NOT_FOUND_404 | ||
74 | }) | ||
73 | } | 75 | } |
74 | 76 | ||
75 | describe('Object storage for lives', function () { | 77 | describe('Object storage for lives', function () { |
76 | if (areObjectStorageTestsDisabled()) return | 78 | if (areMockObjectStorageTestsDisabled()) return |
77 | 79 | ||
78 | let servers: PeerTubeServer[] | 80 | let servers: PeerTubeServer[] |
79 | 81 | ||
80 | before(async function () { | 82 | before(async function () { |
81 | this.timeout(120000) | 83 | this.timeout(120000) |
82 | 84 | ||
83 | await ObjectStorageCommand.prepareDefaultBuckets() | 85 | await ObjectStorageCommand.prepareDefaultMockBuckets() |
84 | 86 | ||
85 | servers = await createMultipleServers(2, ObjectStorageCommand.getDefaultConfig()) | 87 | servers = await createMultipleServers(2, ObjectStorageCommand.getDefaultMockConfig()) |
86 | 88 | ||
87 | await setAccessTokensToServers(servers) | 89 | await setAccessTokensToServers(servers) |
88 | await setDefaultVideoChannel(servers) | 90 | await setDefaultVideoChannel(servers) |
@@ -100,57 +102,124 @@ describe('Object storage for lives', function () { | |||
100 | videoUUID = await createLive(servers[0], false) | 102 | videoUUID = await createLive(servers[0], false) |
101 | }) | 103 | }) |
102 | 104 | ||
103 | it('Should create a live and save the replay on object storage', async function () { | 105 | it('Should create a live and publish it on object storage', async function () { |
106 | this.timeout(220000) | ||
107 | |||
108 | const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUID }) | ||
109 | await waitUntilLivePublishedOnAllServers(servers, videoUUID) | ||
110 | |||
111 | await testVideoResolutions({ | ||
112 | originServer: servers[0], | ||
113 | servers, | ||
114 | liveVideoId: videoUUID, | ||
115 | resolutions: [ 720 ], | ||
116 | transcoded: false, | ||
117 | objectStorage: true | ||
118 | }) | ||
119 | |||
120 | await stopFfmpeg(ffmpegCommand) | ||
121 | }) | ||
122 | |||
123 | it('Should have saved the replay on object storage', async function () { | ||
104 | this.timeout(220000) | 124 | this.timeout(220000) |
105 | 125 | ||
106 | await streamAndEnd(servers, videoUUID) | 126 | await waitUntilLiveReplacedByReplayOnAllServers(servers, videoUUID) |
127 | await waitJobs(servers) | ||
107 | 128 | ||
108 | for (const server of servers) { | 129 | await checkFilesExist(servers, videoUUID, 1) |
109 | const files = await getFiles(server, videoUUID) | 130 | }) |
110 | expect(files).to.have.lengthOf(1) | ||
111 | 131 | ||
112 | await checkFiles(files) | 132 | it('Should have cleaned up live files from object storage', async function () { |
113 | } | 133 | await checkFilesCleanup(servers[0], videoUUID, [ 720 ]) |
114 | }) | 134 | }) |
115 | }) | 135 | }) |
116 | 136 | ||
117 | describe('With live transcoding', async function () { | 137 | describe('With live transcoding', async function () { |
118 | let videoUUIDPermanent: string | 138 | const resolutions = [ 720, 480, 360, 240, 144 ] |
119 | let videoUUIDNonPermanent: string | ||
120 | 139 | ||
121 | before(async function () { | 140 | before(async function () { |
122 | await servers[0].config.enableLive({ transcoding: true }) | 141 | await servers[0].config.enableLive({ transcoding: true }) |
123 | |||
124 | videoUUIDPermanent = await createLive(servers[0], true) | ||
125 | videoUUIDNonPermanent = await createLive(servers[0], false) | ||
126 | }) | 142 | }) |
127 | 143 | ||
128 | it('Should create a live and save the replay on object storage', async function () { | 144 | describe('Normal replay', function () { |
129 | this.timeout(240000) | 145 | let videoUUIDNonPermanent: string |
146 | |||
147 | before(async function () { | ||
148 | videoUUIDNonPermanent = await createLive(servers[0], false) | ||
149 | }) | ||
150 | |||
151 | it('Should create a live and publish it on object storage', async function () { | ||
152 | this.timeout(240000) | ||
153 | |||
154 | const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDNonPermanent }) | ||
155 | await waitUntilLivePublishedOnAllServers(servers, videoUUIDNonPermanent) | ||
156 | |||
157 | await testVideoResolutions({ | ||
158 | originServer: servers[0], | ||
159 | servers, | ||
160 | liveVideoId: videoUUIDNonPermanent, | ||
161 | resolutions, | ||
162 | transcoded: true, | ||
163 | objectStorage: true | ||
164 | }) | ||
165 | |||
166 | await stopFfmpeg(ffmpegCommand) | ||
167 | }) | ||
130 | 168 | ||
131 | await streamAndEnd(servers, videoUUIDNonPermanent) | 169 | it('Should have saved the replay on object storage', async function () { |
170 | this.timeout(220000) | ||
132 | 171 | ||
133 | for (const server of servers) { | 172 | await waitUntilLiveReplacedByReplayOnAllServers(servers, videoUUIDNonPermanent) |
134 | const files = await getFiles(server, videoUUIDNonPermanent) | 173 | await waitJobs(servers) |
135 | expect(files).to.have.lengthOf(5) | ||
136 | 174 | ||
137 | await checkFiles(files) | 175 | await checkFilesExist(servers, videoUUIDNonPermanent, 5) |
138 | } | 176 | }) |
177 | |||
178 | it('Should have cleaned up live files from object storage', async function () { | ||
179 | await checkFilesCleanup(servers[0], videoUUIDNonPermanent, resolutions) | ||
180 | }) | ||
139 | }) | 181 | }) |
140 | 182 | ||
141 | it('Should create a live and save the replay of permanent live on object storage', async function () { | 183 | describe('Permanent replay', function () { |
142 | this.timeout(240000) | 184 | let videoUUIDPermanent: string |
185 | |||
186 | before(async function () { | ||
187 | videoUUIDPermanent = await createLive(servers[0], true) | ||
188 | }) | ||
189 | |||
190 | it('Should create a live and publish it on object storage', async function () { | ||
191 | this.timeout(240000) | ||
192 | |||
193 | const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDPermanent }) | ||
194 | await waitUntilLivePublishedOnAllServers(servers, videoUUIDPermanent) | ||
195 | |||
196 | await testVideoResolutions({ | ||
197 | originServer: servers[0], | ||
198 | servers, | ||
199 | liveVideoId: videoUUIDPermanent, | ||
200 | resolutions, | ||
201 | transcoded: true, | ||
202 | objectStorage: true | ||
203 | }) | ||
204 | |||
205 | await stopFfmpeg(ffmpegCommand) | ||
206 | }) | ||
207 | |||
208 | it('Should have saved the replay on object storage', async function () { | ||
209 | this.timeout(220000) | ||
143 | 210 | ||
144 | const { videoLiveDetails } = await streamAndEnd(servers, videoUUIDPermanent) | 211 | await waitUntilLiveWaitingOnAllServers(servers, videoUUIDPermanent) |
212 | await waitJobs(servers) | ||
145 | 213 | ||
146 | const replay = await findExternalSavedVideo(servers[0], videoLiveDetails) | 214 | const videoLiveDetails = await servers[0].videos.get({ id: videoUUIDPermanent }) |
215 | const replay = await findExternalSavedVideo(servers[0], videoLiveDetails) | ||
147 | 216 | ||
148 | for (const server of servers) { | 217 | await checkFilesExist(servers, replay.uuid, 5) |
149 | const files = await getFiles(server, replay.uuid) | 218 | }) |
150 | expect(files).to.have.lengthOf(5) | ||
151 | 219 | ||
152 | await checkFiles(files) | 220 | it('Should have cleaned up live files from object storage', async function () { |
153 | } | 221 | await checkFilesCleanup(servers[0], videoUUIDPermanent, resolutions) |
222 | }) | ||
154 | }) | 223 | }) |
155 | }) | 224 | }) |
156 | 225 | ||
diff --git a/server/tests/api/object-storage/video-imports.ts b/server/tests/api/object-storage/video-imports.ts index f688c7018..11c866411 100644 --- a/server/tests/api/object-storage/video-imports.ts +++ b/server/tests/api/object-storage/video-imports.ts | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { expectStartWith, FIXTURE_URLS } from '@server/tests/shared' | 4 | import { expectStartWith, FIXTURE_URLS } from '@server/tests/shared' |
5 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | 5 | import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' |
6 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | 6 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' |
7 | import { | 7 | import { |
8 | createSingleServer, | 8 | createSingleServer, |
@@ -29,16 +29,16 @@ async function importVideo (server: PeerTubeServer) { | |||
29 | } | 29 | } |
30 | 30 | ||
31 | describe('Object storage for video import', function () { | 31 | describe('Object storage for video import', function () { |
32 | if (areObjectStorageTestsDisabled()) return | 32 | if (areMockObjectStorageTestsDisabled()) return |
33 | 33 | ||
34 | let server: PeerTubeServer | 34 | let server: PeerTubeServer |
35 | 35 | ||
36 | before(async function () { | 36 | before(async function () { |
37 | this.timeout(120000) | 37 | this.timeout(120000) |
38 | 38 | ||
39 | await ObjectStorageCommand.prepareDefaultBuckets() | 39 | await ObjectStorageCommand.prepareDefaultMockBuckets() |
40 | 40 | ||
41 | server = await createSingleServer(1, ObjectStorageCommand.getDefaultConfig()) | 41 | server = await createSingleServer(1, ObjectStorageCommand.getDefaultMockConfig()) |
42 | 42 | ||
43 | await setAccessTokensToServers([ server ]) | 43 | await setAccessTokensToServers([ server ]) |
44 | await setDefaultVideoChannel([ server ]) | 44 | await setDefaultVideoChannel([ server ]) |
@@ -64,9 +64,9 @@ describe('Object storage for video import', function () { | |||
64 | expect(video.streamingPlaylists).to.have.lengthOf(0) | 64 | expect(video.streamingPlaylists).to.have.lengthOf(0) |
65 | 65 | ||
66 | const fileUrl = video.files[0].fileUrl | 66 | const fileUrl = video.files[0].fileUrl |
67 | expectStartWith(fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) | 67 | expectStartWith(fileUrl, ObjectStorageCommand.getMockWebTorrentBaseUrl()) |
68 | 68 | ||
69 | await makeRawRequest(fileUrl, HttpStatusCode.OK_200) | 69 | await makeRawRequest({ url: fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
70 | }) | 70 | }) |
71 | }) | 71 | }) |
72 | 72 | ||
@@ -89,15 +89,15 @@ describe('Object storage for video import', function () { | |||
89 | expect(video.streamingPlaylists[0].files).to.have.lengthOf(5) | 89 | expect(video.streamingPlaylists[0].files).to.have.lengthOf(5) |
90 | 90 | ||
91 | for (const file of video.files) { | 91 | for (const file of video.files) { |
92 | expectStartWith(file.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) | 92 | expectStartWith(file.fileUrl, ObjectStorageCommand.getMockWebTorrentBaseUrl()) |
93 | 93 | ||
94 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 94 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
95 | } | 95 | } |
96 | 96 | ||
97 | for (const file of video.streamingPlaylists[0].files) { | 97 | for (const file of video.streamingPlaylists[0].files) { |
98 | expectStartWith(file.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl()) | 98 | expectStartWith(file.fileUrl, ObjectStorageCommand.getMockPlaylistBaseUrl()) |
99 | 99 | ||
100 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 100 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
101 | } | 101 | } |
102 | }) | 102 | }) |
103 | }) | 103 | }) |
diff --git a/server/tests/api/object-storage/video-static-file-privacy.ts b/server/tests/api/object-storage/video-static-file-privacy.ts new file mode 100644 index 000000000..62edd10ba --- /dev/null +++ b/server/tests/api/object-storage/video-static-file-privacy.ts | |||
@@ -0,0 +1,402 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { basename } from 'path' | ||
5 | import { expectStartWith } from '@server/tests/shared' | ||
6 | import { areScalewayObjectStorageTestsDisabled, getAllFiles, getHLS } from '@shared/core-utils' | ||
7 | import { HttpStatusCode, LiveVideo, VideoDetails, VideoPrivacy } from '@shared/models' | ||
8 | import { | ||
9 | cleanupTests, | ||
10 | createSingleServer, | ||
11 | findExternalSavedVideo, | ||
12 | makeRawRequest, | ||
13 | ObjectStorageCommand, | ||
14 | PeerTubeServer, | ||
15 | sendRTMPStream, | ||
16 | setAccessTokensToServers, | ||
17 | setDefaultVideoChannel, | ||
18 | stopFfmpeg, | ||
19 | waitJobs | ||
20 | } from '@shared/server-commands' | ||
21 | |||
22 | function extractFilenameFromUrl (url: string) { | ||
23 | const parts = basename(url).split(':') | ||
24 | |||
25 | return parts[parts.length - 1] | ||
26 | } | ||
27 | |||
28 | describe('Object storage for video static file privacy', function () { | ||
29 | // We need real world object storage to check ACL | ||
30 | if (areScalewayObjectStorageTestsDisabled()) return | ||
31 | |||
32 | let server: PeerTubeServer | ||
33 | let userToken: string | ||
34 | |||
35 | // --------------------------------------------------------------------------- | ||
36 | |||
37 | async function checkPrivateVODFiles (uuid: string) { | ||
38 | const video = await server.videos.getWithToken({ id: uuid }) | ||
39 | |||
40 | for (const file of video.files) { | ||
41 | expectStartWith(file.fileUrl, server.url + '/object-storage-proxy/webseed/private/') | ||
42 | |||
43 | await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
44 | } | ||
45 | |||
46 | for (const file of getAllFiles(video)) { | ||
47 | const internalFileUrl = await server.sql.getInternalFileUrl(file.id) | ||
48 | expectStartWith(internalFileUrl, ObjectStorageCommand.getScalewayBaseUrl()) | ||
49 | await makeRawRequest({ url: internalFileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
50 | } | ||
51 | |||
52 | const hls = getHLS(video) | ||
53 | |||
54 | if (hls) { | ||
55 | for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { | ||
56 | expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/') | ||
57 | } | ||
58 | |||
59 | await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
60 | await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
61 | |||
62 | for (const file of hls.files) { | ||
63 | expectStartWith(file.fileUrl, server.url + '/object-storage-proxy/streaming-playlists/hls/private/') | ||
64 | |||
65 | await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | async function checkPublicVODFiles (uuid: string) { | ||
71 | const video = await server.videos.getWithToken({ id: uuid }) | ||
72 | |||
73 | for (const file of getAllFiles(video)) { | ||
74 | expectStartWith(file.fileUrl, ObjectStorageCommand.getScalewayBaseUrl()) | ||
75 | |||
76 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
77 | } | ||
78 | |||
79 | const hls = getHLS(video) | ||
80 | |||
81 | if (hls) { | ||
82 | expectStartWith(hls.playlistUrl, ObjectStorageCommand.getScalewayBaseUrl()) | ||
83 | expectStartWith(hls.segmentsSha256Url, ObjectStorageCommand.getScalewayBaseUrl()) | ||
84 | |||
85 | await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
86 | await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) | ||
87 | } | ||
88 | } | ||
89 | |||
90 | // --------------------------------------------------------------------------- | ||
91 | |||
92 | before(async function () { | ||
93 | this.timeout(120000) | ||
94 | |||
95 | server = await createSingleServer(1, ObjectStorageCommand.getDefaultScalewayConfig({ serverNumber: 1 })) | ||
96 | await setAccessTokensToServers([ server ]) | ||
97 | await setDefaultVideoChannel([ server ]) | ||
98 | |||
99 | await server.config.enableMinimumTranscoding() | ||
100 | |||
101 | userToken = await server.users.generateUserAndToken('user1') | ||
102 | }) | ||
103 | |||
104 | describe('VOD', function () { | ||
105 | let privateVideoUUID: string | ||
106 | let publicVideoUUID: string | ||
107 | let userPrivateVideoUUID: string | ||
108 | |||
109 | // --------------------------------------------------------------------------- | ||
110 | |||
111 | async function getSampleFileUrls (videoId: string) { | ||
112 | const video = await server.videos.getWithToken({ id: videoId }) | ||
113 | |||
114 | return { | ||
115 | webTorrentFile: video.files[0].fileUrl, | ||
116 | hlsFile: getHLS(video).files[0].fileUrl | ||
117 | } | ||
118 | } | ||
119 | |||
120 | // --------------------------------------------------------------------------- | ||
121 | |||
122 | it('Should upload a private video and have appropriate object storage ACL', async function () { | ||
123 | this.timeout(60000) | ||
124 | |||
125 | { | ||
126 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) | ||
127 | privateVideoUUID = uuid | ||
128 | } | ||
129 | |||
130 | { | ||
131 | const { uuid } = await server.videos.quickUpload({ name: 'user video', token: userToken, privacy: VideoPrivacy.PRIVATE }) | ||
132 | userPrivateVideoUUID = uuid | ||
133 | } | ||
134 | |||
135 | await waitJobs([ server ]) | ||
136 | |||
137 | await checkPrivateVODFiles(privateVideoUUID) | ||
138 | }) | ||
139 | |||
140 | it('Should upload a public video and have appropriate object storage ACL', async function () { | ||
141 | this.timeout(60000) | ||
142 | |||
143 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.UNLISTED }) | ||
144 | await waitJobs([ server ]) | ||
145 | |||
146 | publicVideoUUID = uuid | ||
147 | |||
148 | await checkPublicVODFiles(publicVideoUUID) | ||
149 | }) | ||
150 | |||
151 | it('Should not get files without appropriate OAuth token', async function () { | ||
152 | this.timeout(60000) | ||
153 | |||
154 | const { webTorrentFile, hlsFile } = await getSampleFileUrls(privateVideoUUID) | ||
155 | |||
156 | await makeRawRequest({ url: webTorrentFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
157 | await makeRawRequest({ url: webTorrentFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
158 | |||
159 | await makeRawRequest({ url: hlsFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
160 | await makeRawRequest({ url: hlsFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
161 | }) | ||
162 | |||
163 | it('Should not get HLS file of another video', async function () { | ||
164 | this.timeout(60000) | ||
165 | |||
166 | const privateVideo = await server.videos.getWithToken({ id: privateVideoUUID }) | ||
167 | const hlsFilename = basename(getHLS(privateVideo).files[0].fileUrl) | ||
168 | |||
169 | const badUrl = server.url + '/object-storage-proxy/streaming-playlists/hls/private/' + userPrivateVideoUUID + '/' + hlsFilename | ||
170 | const goodUrl = server.url + '/object-storage-proxy/streaming-playlists/hls/private/' + privateVideoUUID + '/' + hlsFilename | ||
171 | |||
172 | await makeRawRequest({ url: badUrl, token: server.accessToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
173 | await makeRawRequest({ url: goodUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
174 | }) | ||
175 | |||
176 | it('Should correctly check OAuth or video file token', async function () { | ||
177 | this.timeout(60000) | ||
178 | |||
179 | const badVideoFileToken = await server.videoToken.getVideoFileToken({ token: userToken, videoId: userPrivateVideoUUID }) | ||
180 | const goodVideoFileToken = await server.videoToken.getVideoFileToken({ videoId: privateVideoUUID }) | ||
181 | |||
182 | const { webTorrentFile, hlsFile } = await getSampleFileUrls(privateVideoUUID) | ||
183 | |||
184 | for (const url of [ webTorrentFile, hlsFile ]) { | ||
185 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
186 | await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
187 | await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
188 | |||
189 | await makeRawRequest({ url, query: { videoFileToken: badVideoFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
190 | await makeRawRequest({ url, query: { videoFileToken: goodVideoFileToken }, expectedStatus: HttpStatusCode.OK_200 }) | ||
191 | } | ||
192 | }) | ||
193 | |||
194 | it('Should update public video to private', async function () { | ||
195 | this.timeout(60000) | ||
196 | |||
197 | await server.videos.update({ id: publicVideoUUID, attributes: { privacy: VideoPrivacy.INTERNAL } }) | ||
198 | |||
199 | await checkPrivateVODFiles(publicVideoUUID) | ||
200 | }) | ||
201 | |||
202 | it('Should update private video to public', async function () { | ||
203 | this.timeout(60000) | ||
204 | |||
205 | await server.videos.update({ id: publicVideoUUID, attributes: { privacy: VideoPrivacy.PUBLIC } }) | ||
206 | |||
207 | await checkPublicVODFiles(publicVideoUUID) | ||
208 | }) | ||
209 | }) | ||
210 | |||
211 | describe('Live', function () { | ||
212 | let normalLiveId: string | ||
213 | let normalLive: LiveVideo | ||
214 | |||
215 | let permanentLiveId: string | ||
216 | let permanentLive: LiveVideo | ||
217 | |||
218 | let unrelatedFileToken: string | ||
219 | |||
220 | // --------------------------------------------------------------------------- | ||
221 | |||
222 | async function checkLiveFiles (live: LiveVideo, liveId: string) { | ||
223 | const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) | ||
224 | await server.live.waitUntilPublished({ videoId: liveId }) | ||
225 | |||
226 | const video = await server.videos.getWithToken({ id: liveId }) | ||
227 | const fileToken = await server.videoToken.getVideoFileToken({ videoId: video.uuid }) | ||
228 | |||
229 | const hls = video.streamingPlaylists[0] | ||
230 | |||
231 | for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { | ||
232 | expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/') | ||
233 | |||
234 | await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
235 | await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
236 | |||
237 | await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
238 | await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) | ||
239 | |||
240 | await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
241 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
242 | await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
243 | } | ||
244 | |||
245 | await stopFfmpeg(ffmpegCommand) | ||
246 | } | ||
247 | |||
248 | async function checkReplay (replay: VideoDetails) { | ||
249 | const fileToken = await server.videoToken.getVideoFileToken({ videoId: replay.uuid }) | ||
250 | |||
251 | const hls = replay.streamingPlaylists[0] | ||
252 | expect(hls.files).to.not.have.lengthOf(0) | ||
253 | |||
254 | for (const file of hls.files) { | ||
255 | await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
256 | await makeRawRequest({ url: file.fileUrl, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) | ||
257 | |||
258 | await makeRawRequest({ url: file.fileUrl, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
259 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
260 | await makeRawRequest({ | ||
261 | url: file.fileUrl, | ||
262 | query: { videoFileToken: unrelatedFileToken }, | ||
263 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
264 | }) | ||
265 | } | ||
266 | |||
267 | for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { | ||
268 | expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/') | ||
269 | |||
270 | await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
271 | await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) | ||
272 | |||
273 | await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
274 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
275 | await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
276 | } | ||
277 | } | ||
278 | |||
279 | // --------------------------------------------------------------------------- | ||
280 | |||
281 | before(async function () { | ||
282 | await server.config.enableMinimumTranscoding() | ||
283 | |||
284 | const { uuid } = await server.videos.quickUpload({ name: 'another video' }) | ||
285 | unrelatedFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) | ||
286 | |||
287 | await server.config.enableLive({ | ||
288 | allowReplay: true, | ||
289 | transcoding: true, | ||
290 | resolutions: 'min' | ||
291 | }) | ||
292 | |||
293 | { | ||
294 | const { video, live } = await server.live.quickCreate({ saveReplay: true, permanentLive: false, privacy: VideoPrivacy.PRIVATE }) | ||
295 | normalLiveId = video.uuid | ||
296 | normalLive = live | ||
297 | } | ||
298 | |||
299 | { | ||
300 | const { video, live } = await server.live.quickCreate({ saveReplay: true, permanentLive: true, privacy: VideoPrivacy.PRIVATE }) | ||
301 | permanentLiveId = video.uuid | ||
302 | permanentLive = live | ||
303 | } | ||
304 | }) | ||
305 | |||
306 | it('Should create a private normal live and have a private static path', async function () { | ||
307 | this.timeout(240000) | ||
308 | |||
309 | await checkLiveFiles(normalLive, normalLiveId) | ||
310 | }) | ||
311 | |||
312 | it('Should create a private permanent live and have a private static path', async function () { | ||
313 | this.timeout(240000) | ||
314 | |||
315 | await checkLiveFiles(permanentLive, permanentLiveId) | ||
316 | }) | ||
317 | |||
318 | it('Should have created a replay of the normal live with a private static path', async function () { | ||
319 | this.timeout(240000) | ||
320 | |||
321 | await server.live.waitUntilReplacedByReplay({ videoId: normalLiveId }) | ||
322 | |||
323 | const replay = await server.videos.getWithToken({ id: normalLiveId }) | ||
324 | await checkReplay(replay) | ||
325 | }) | ||
326 | |||
327 | it('Should have created a replay of the permanent live with a private static path', async function () { | ||
328 | this.timeout(240000) | ||
329 | |||
330 | await server.live.waitUntilWaiting({ videoId: permanentLiveId }) | ||
331 | await waitJobs([ server ]) | ||
332 | |||
333 | const live = await server.videos.getWithToken({ id: permanentLiveId }) | ||
334 | const replayFromList = await findExternalSavedVideo(server, live) | ||
335 | const replay = await server.videos.getWithToken({ id: replayFromList.id }) | ||
336 | |||
337 | await checkReplay(replay) | ||
338 | }) | ||
339 | }) | ||
340 | |||
341 | describe('With private files proxy disabled and public ACL for private files', function () { | ||
342 | let videoUUID: string | ||
343 | |||
344 | before(async function () { | ||
345 | this.timeout(240000) | ||
346 | |||
347 | await server.kill() | ||
348 | |||
349 | const config = ObjectStorageCommand.getDefaultScalewayConfig({ | ||
350 | serverNumber: 1, | ||
351 | enablePrivateProxy: false, | ||
352 | privateACL: 'public-read' | ||
353 | }) | ||
354 | await server.run(config) | ||
355 | |||
356 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) | ||
357 | videoUUID = uuid | ||
358 | |||
359 | await waitJobs([ server ]) | ||
360 | }) | ||
361 | |||
362 | it('Should display object storage path for a private video and be able to access them', async function () { | ||
363 | this.timeout(60000) | ||
364 | |||
365 | await checkPublicVODFiles(videoUUID) | ||
366 | }) | ||
367 | |||
368 | it('Should not be able to access object storage proxy', async function () { | ||
369 | const privateVideo = await server.videos.getWithToken({ id: videoUUID }) | ||
370 | const webtorrentFilename = extractFilenameFromUrl(privateVideo.files[0].fileUrl) | ||
371 | const hlsFilename = extractFilenameFromUrl(getHLS(privateVideo).files[0].fileUrl) | ||
372 | |||
373 | await makeRawRequest({ | ||
374 | url: server.url + '/object-storage-proxy/webseed/private/' + webtorrentFilename, | ||
375 | token: server.accessToken, | ||
376 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
377 | }) | ||
378 | |||
379 | await makeRawRequest({ | ||
380 | url: server.url + '/object-storage-proxy/streaming-playlists/hls/private/' + videoUUID + '/' + hlsFilename, | ||
381 | token: server.accessToken, | ||
382 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
383 | }) | ||
384 | }) | ||
385 | }) | ||
386 | |||
387 | after(async function () { | ||
388 | this.timeout(240000) | ||
389 | |||
390 | const { data } = await server.videos.listAllForAdmin() | ||
391 | |||
392 | for (const v of data) { | ||
393 | await server.videos.remove({ id: v.uuid }) | ||
394 | } | ||
395 | |||
396 | for (const v of data) { | ||
397 | await server.servers.waitUntilLog('Removed files of video ' + v.url) | ||
398 | } | ||
399 | |||
400 | await cleanupTests([ server ]) | ||
401 | }) | ||
402 | }) | ||
diff --git a/server/tests/api/object-storage/videos.ts b/server/tests/api/object-storage/videos.ts index 3e65e1093..d1875febb 100644 --- a/server/tests/api/object-storage/videos.ts +++ b/server/tests/api/object-storage/videos.ts | |||
@@ -11,7 +11,7 @@ import { | |||
11 | generateHighBitrateVideo, | 11 | generateHighBitrateVideo, |
12 | MockObjectStorage | 12 | MockObjectStorage |
13 | } from '@server/tests/shared' | 13 | } from '@server/tests/shared' |
14 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | 14 | import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' |
15 | import { HttpStatusCode, VideoDetails } from '@shared/models' | 15 | import { HttpStatusCode, VideoDetails } from '@shared/models' |
16 | import { | 16 | import { |
17 | cleanupTests, | 17 | cleanupTests, |
@@ -52,18 +52,18 @@ async function checkFiles (options: { | |||
52 | for (const file of video.files) { | 52 | for (const file of video.files) { |
53 | const baseUrl = baseMockUrl | 53 | const baseUrl = baseMockUrl |
54 | ? `${baseMockUrl}/${webtorrentBucket}/` | 54 | ? `${baseMockUrl}/${webtorrentBucket}/` |
55 | : `http://${webtorrentBucket}.${ObjectStorageCommand.getEndpointHost()}/` | 55 | : `http://${webtorrentBucket}.${ObjectStorageCommand.getMockEndpointHost()}/` |
56 | 56 | ||
57 | const prefix = webtorrentPrefix || '' | 57 | const prefix = webtorrentPrefix || '' |
58 | const start = baseUrl + prefix | 58 | const start = baseUrl + prefix |
59 | 59 | ||
60 | expectStartWith(file.fileUrl, start) | 60 | expectStartWith(file.fileUrl, start) |
61 | 61 | ||
62 | const res = await makeRawRequest(file.fileDownloadUrl, HttpStatusCode.FOUND_302) | 62 | const res = await makeRawRequest({ url: file.fileDownloadUrl, expectedStatus: HttpStatusCode.FOUND_302 }) |
63 | const location = res.headers['location'] | 63 | const location = res.headers['location'] |
64 | expectStartWith(location, start) | 64 | expectStartWith(location, start) |
65 | 65 | ||
66 | await makeRawRequest(location, HttpStatusCode.OK_200) | 66 | await makeRawRequest({ url: location, expectedStatus: HttpStatusCode.OK_200 }) |
67 | } | 67 | } |
68 | 68 | ||
69 | const hls = video.streamingPlaylists[0] | 69 | const hls = video.streamingPlaylists[0] |
@@ -73,7 +73,7 @@ async function checkFiles (options: { | |||
73 | 73 | ||
74 | const baseUrl = baseMockUrl | 74 | const baseUrl = baseMockUrl |
75 | ? `${baseMockUrl}/${playlistBucket}/` | 75 | ? `${baseMockUrl}/${playlistBucket}/` |
76 | : `http://${playlistBucket}.${ObjectStorageCommand.getEndpointHost()}/` | 76 | : `http://${playlistBucket}.${ObjectStorageCommand.getMockEndpointHost()}/` |
77 | 77 | ||
78 | const prefix = playlistPrefix || '' | 78 | const prefix = playlistPrefix || '' |
79 | const start = baseUrl + prefix | 79 | const start = baseUrl + prefix |
@@ -81,19 +81,19 @@ async function checkFiles (options: { | |||
81 | expectStartWith(hls.playlistUrl, start) | 81 | expectStartWith(hls.playlistUrl, start) |
82 | expectStartWith(hls.segmentsSha256Url, start) | 82 | expectStartWith(hls.segmentsSha256Url, start) |
83 | 83 | ||
84 | await makeRawRequest(hls.playlistUrl, HttpStatusCode.OK_200) | 84 | await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) |
85 | 85 | ||
86 | const resSha = await makeRawRequest(hls.segmentsSha256Url, HttpStatusCode.OK_200) | 86 | const resSha = await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) |
87 | expect(JSON.stringify(resSha.body)).to.not.throw | 87 | expect(JSON.stringify(resSha.body)).to.not.throw |
88 | 88 | ||
89 | for (const file of hls.files) { | 89 | for (const file of hls.files) { |
90 | expectStartWith(file.fileUrl, start) | 90 | expectStartWith(file.fileUrl, start) |
91 | 91 | ||
92 | const res = await makeRawRequest(file.fileDownloadUrl, HttpStatusCode.FOUND_302) | 92 | const res = await makeRawRequest({ url: file.fileDownloadUrl, expectedStatus: HttpStatusCode.FOUND_302 }) |
93 | const location = res.headers['location'] | 93 | const location = res.headers['location'] |
94 | expectStartWith(location, start) | 94 | expectStartWith(location, start) |
95 | 95 | ||
96 | await makeRawRequest(location, HttpStatusCode.OK_200) | 96 | await makeRawRequest({ url: location, expectedStatus: HttpStatusCode.OK_200 }) |
97 | } | 97 | } |
98 | } | 98 | } |
99 | 99 | ||
@@ -104,7 +104,7 @@ async function checkFiles (options: { | |||
104 | expect(torrent.files.length).to.equal(1) | 104 | expect(torrent.files.length).to.equal(1) |
105 | expect(torrent.files[0].path).to.exist.and.to.not.equal('') | 105 | expect(torrent.files[0].path).to.exist.and.to.not.equal('') |
106 | 106 | ||
107 | const res = await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 107 | const res = await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
108 | expect(res.body).to.have.length.above(100) | 108 | expect(res.body).to.have.length.above(100) |
109 | } | 109 | } |
110 | 110 | ||
@@ -141,16 +141,16 @@ function runTestSuite (options: { | |||
141 | const port = await mockObjectStorage.initialize() | 141 | const port = await mockObjectStorage.initialize() |
142 | baseMockUrl = options.useMockBaseUrl ? `http://localhost:${port}` : undefined | 142 | baseMockUrl = options.useMockBaseUrl ? `http://localhost:${port}` : undefined |
143 | 143 | ||
144 | await ObjectStorageCommand.createBucket(options.playlistBucket) | 144 | await ObjectStorageCommand.createMockBucket(options.playlistBucket) |
145 | await ObjectStorageCommand.createBucket(options.webtorrentBucket) | 145 | await ObjectStorageCommand.createMockBucket(options.webtorrentBucket) |
146 | 146 | ||
147 | const config = { | 147 | const config = { |
148 | object_storage: { | 148 | object_storage: { |
149 | enabled: true, | 149 | enabled: true, |
150 | endpoint: 'http://' + ObjectStorageCommand.getEndpointHost(), | 150 | endpoint: 'http://' + ObjectStorageCommand.getMockEndpointHost(), |
151 | region: ObjectStorageCommand.getRegion(), | 151 | region: ObjectStorageCommand.getMockRegion(), |
152 | 152 | ||
153 | credentials: ObjectStorageCommand.getCredentialsConfig(), | 153 | credentials: ObjectStorageCommand.getMockCredentialsConfig(), |
154 | 154 | ||
155 | max_upload_part: options.maxUploadPart || '5MB', | 155 | max_upload_part: options.maxUploadPart || '5MB', |
156 | 156 | ||
@@ -220,7 +220,7 @@ function runTestSuite (options: { | |||
220 | 220 | ||
221 | it('Should fetch correctly all the files', async function () { | 221 | it('Should fetch correctly all the files', async function () { |
222 | for (const url of deletedUrls.concat(keptUrls)) { | 222 | for (const url of deletedUrls.concat(keptUrls)) { |
223 | await makeRawRequest(url, HttpStatusCode.OK_200) | 223 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) |
224 | } | 224 | } |
225 | }) | 225 | }) |
226 | 226 | ||
@@ -231,13 +231,13 @@ function runTestSuite (options: { | |||
231 | await waitJobs(servers) | 231 | await waitJobs(servers) |
232 | 232 | ||
233 | for (const url of deletedUrls) { | 233 | for (const url of deletedUrls) { |
234 | await makeRawRequest(url, HttpStatusCode.NOT_FOUND_404) | 234 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) |
235 | } | 235 | } |
236 | }) | 236 | }) |
237 | 237 | ||
238 | it('Should have kept other files', async function () { | 238 | it('Should have kept other files', async function () { |
239 | for (const url of keptUrls) { | 239 | for (const url of keptUrls) { |
240 | await makeRawRequest(url, HttpStatusCode.OK_200) | 240 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) |
241 | } | 241 | } |
242 | }) | 242 | }) |
243 | 243 | ||
@@ -261,7 +261,7 @@ function runTestSuite (options: { | |||
261 | } | 261 | } |
262 | 262 | ||
263 | describe('Object storage for videos', function () { | 263 | describe('Object storage for videos', function () { |
264 | if (areObjectStorageTestsDisabled()) return | 264 | if (areMockObjectStorageTestsDisabled()) return |
265 | 265 | ||
266 | describe('Test config', function () { | 266 | describe('Test config', function () { |
267 | let server: PeerTubeServer | 267 | let server: PeerTubeServer |
@@ -269,17 +269,17 @@ describe('Object storage for videos', function () { | |||
269 | const baseConfig = { | 269 | const baseConfig = { |
270 | object_storage: { | 270 | object_storage: { |
271 | enabled: true, | 271 | enabled: true, |
272 | endpoint: 'http://' + ObjectStorageCommand.getEndpointHost(), | 272 | endpoint: 'http://' + ObjectStorageCommand.getMockEndpointHost(), |
273 | region: ObjectStorageCommand.getRegion(), | 273 | region: ObjectStorageCommand.getMockRegion(), |
274 | 274 | ||
275 | credentials: ObjectStorageCommand.getCredentialsConfig(), | 275 | credentials: ObjectStorageCommand.getMockCredentialsConfig(), |
276 | 276 | ||
277 | streaming_playlists: { | 277 | streaming_playlists: { |
278 | bucket_name: ObjectStorageCommand.DEFAULT_PLAYLIST_BUCKET | 278 | bucket_name: ObjectStorageCommand.DEFAULT_PLAYLIST_MOCK_BUCKET |
279 | }, | 279 | }, |
280 | 280 | ||
281 | videos: { | 281 | videos: { |
282 | bucket_name: ObjectStorageCommand.DEFAULT_WEBTORRENT_BUCKET | 282 | bucket_name: ObjectStorageCommand.DEFAULT_WEBTORRENT_MOCK_BUCKET |
283 | } | 283 | } |
284 | } | 284 | } |
285 | } | 285 | } |
@@ -310,7 +310,7 @@ describe('Object storage for videos', function () { | |||
310 | it('Should fail with bad credentials', async function () { | 310 | it('Should fail with bad credentials', async function () { |
311 | this.timeout(60000) | 311 | this.timeout(60000) |
312 | 312 | ||
313 | await ObjectStorageCommand.prepareDefaultBuckets() | 313 | await ObjectStorageCommand.prepareDefaultMockBuckets() |
314 | 314 | ||
315 | const config = merge({}, baseConfig, { | 315 | const config = merge({}, baseConfig, { |
316 | object_storage: { | 316 | object_storage: { |
@@ -323,7 +323,7 @@ describe('Object storage for videos', function () { | |||
323 | 323 | ||
324 | const { uuid } = await server.videos.quickUpload({ name: 'video' }) | 324 | const { uuid } = await server.videos.quickUpload({ name: 'video' }) |
325 | 325 | ||
326 | await waitJobs([ server ], true) | 326 | await waitJobs([ server ], { skipDelayed: true }) |
327 | const video = await server.videos.get({ id: uuid }) | 327 | const video = await server.videos.get({ id: uuid }) |
328 | 328 | ||
329 | expectStartWith(video.files[0].fileUrl, server.url) | 329 | expectStartWith(video.files[0].fileUrl, server.url) |
@@ -334,7 +334,7 @@ describe('Object storage for videos', function () { | |||
334 | it('Should succeed with credentials from env', async function () { | 334 | it('Should succeed with credentials from env', async function () { |
335 | this.timeout(60000) | 335 | this.timeout(60000) |
336 | 336 | ||
337 | await ObjectStorageCommand.prepareDefaultBuckets() | 337 | await ObjectStorageCommand.prepareDefaultMockBuckets() |
338 | 338 | ||
339 | const config = merge({}, baseConfig, { | 339 | const config = merge({}, baseConfig, { |
340 | object_storage: { | 340 | object_storage: { |
@@ -345,7 +345,7 @@ describe('Object storage for videos', function () { | |||
345 | } | 345 | } |
346 | }) | 346 | }) |
347 | 347 | ||
348 | const goodCredentials = ObjectStorageCommand.getCredentialsConfig() | 348 | const goodCredentials = ObjectStorageCommand.getMockCredentialsConfig() |
349 | 349 | ||
350 | server = await createSingleServer(1, config, { | 350 | server = await createSingleServer(1, config, { |
351 | env: { | 351 | env: { |
@@ -358,10 +358,10 @@ describe('Object storage for videos', function () { | |||
358 | 358 | ||
359 | const { uuid } = await server.videos.quickUpload({ name: 'video' }) | 359 | const { uuid } = await server.videos.quickUpload({ name: 'video' }) |
360 | 360 | ||
361 | await waitJobs([ server ], true) | 361 | await waitJobs([ server ], { skipDelayed: true }) |
362 | const video = await server.videos.get({ id: uuid }) | 362 | const video = await server.videos.get({ id: uuid }) |
363 | 363 | ||
364 | expectStartWith(video.files[0].fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) | 364 | expectStartWith(video.files[0].fileUrl, ObjectStorageCommand.getMockWebTorrentBaseUrl()) |
365 | }) | 365 | }) |
366 | 366 | ||
367 | after(async function () { | 367 | after(async function () { |
diff --git a/server/tests/api/redundancy/redundancy.ts b/server/tests/api/redundancy/redundancy.ts index 5abed358f..fb2e6e91c 100644 --- a/server/tests/api/redundancy/redundancy.ts +++ b/server/tests/api/redundancy/redundancy.ts | |||
@@ -5,7 +5,7 @@ import { readdir } from 'fs-extra' | |||
5 | import magnetUtil from 'magnet-uri' | 5 | import magnetUtil from 'magnet-uri' |
6 | import { basename, join } from 'path' | 6 | import { basename, join } from 'path' |
7 | import { checkSegmentHash, checkVideoFilesWereRemoved, saveVideoInServers } from '@server/tests/shared' | 7 | import { checkSegmentHash, checkVideoFilesWereRemoved, saveVideoInServers } from '@server/tests/shared' |
8 | import { root, wait } from '@shared/core-utils' | 8 | import { wait } from '@shared/core-utils' |
9 | import { | 9 | import { |
10 | HttpStatusCode, | 10 | HttpStatusCode, |
11 | VideoDetails, | 11 | VideoDetails, |
@@ -39,7 +39,7 @@ async function checkMagnetWebseeds (file: VideoFile, baseWebseeds: string[], ser | |||
39 | expect(parsed.urlList).to.have.lengthOf(baseWebseeds.length) | 39 | expect(parsed.urlList).to.have.lengthOf(baseWebseeds.length) |
40 | 40 | ||
41 | for (const url of parsed.urlList) { | 41 | for (const url of parsed.urlList) { |
42 | await makeRawRequest(url, HttpStatusCode.OK_200) | 42 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) |
43 | } | 43 | } |
44 | } | 44 | } |
45 | 45 | ||
@@ -125,7 +125,7 @@ async function check1WebSeed (videoUUID?: string) { | |||
125 | if (!videoUUID) videoUUID = video1Server2.uuid | 125 | if (!videoUUID) videoUUID = video1Server2.uuid |
126 | 126 | ||
127 | const webseeds = [ | 127 | const webseeds = [ |
128 | `http://localhost:${servers[1].port}/static/webseed/` | 128 | `${servers[1].url}/static/webseed/` |
129 | ] | 129 | ] |
130 | 130 | ||
131 | for (const server of servers) { | 131 | for (const server of servers) { |
@@ -144,8 +144,8 @@ async function check2Webseeds (videoUUID?: string) { | |||
144 | if (!videoUUID) videoUUID = video1Server2.uuid | 144 | if (!videoUUID) videoUUID = video1Server2.uuid |
145 | 145 | ||
146 | const webseeds = [ | 146 | const webseeds = [ |
147 | `http://localhost:${servers[0].port}/static/redundancy/`, | 147 | `${servers[0].url}/static/redundancy/`, |
148 | `http://localhost:${servers[1].port}/static/webseed/` | 148 | `${servers[1].url}/static/webseed/` |
149 | ] | 149 | ] |
150 | 150 | ||
151 | for (const server of servers) { | 151 | for (const server of servers) { |
@@ -159,12 +159,12 @@ async function check2Webseeds (videoUUID?: string) { | |||
159 | const { webtorrentFilenames } = await ensureSameFilenames(videoUUID) | 159 | const { webtorrentFilenames } = await ensureSameFilenames(videoUUID) |
160 | 160 | ||
161 | const directories = [ | 161 | const directories = [ |
162 | 'test' + servers[0].internalServerNumber + '/redundancy', | 162 | servers[0].getDirectoryPath('redundancy'), |
163 | 'test' + servers[1].internalServerNumber + '/videos' | 163 | servers[1].getDirectoryPath('videos') |
164 | ] | 164 | ] |
165 | 165 | ||
166 | for (const directory of directories) { | 166 | for (const directory of directories) { |
167 | const files = await readdir(join(root(), directory)) | 167 | const files = await readdir(directory) |
168 | expect(files).to.have.length.at.least(4) | 168 | expect(files).to.have.length.at.least(4) |
169 | 169 | ||
170 | // Ensure we files exist on disk | 170 | // Ensure we files exist on disk |
@@ -214,12 +214,12 @@ async function check1PlaylistRedundancies (videoUUID?: string) { | |||
214 | const { hlsFilenames } = await ensureSameFilenames(videoUUID) | 214 | const { hlsFilenames } = await ensureSameFilenames(videoUUID) |
215 | 215 | ||
216 | const directories = [ | 216 | const directories = [ |
217 | 'test' + servers[0].internalServerNumber + '/redundancy/hls', | 217 | servers[0].getDirectoryPath('redundancy/hls'), |
218 | 'test' + servers[1].internalServerNumber + '/streaming-playlists/hls' | 218 | servers[1].getDirectoryPath('streaming-playlists/hls') |
219 | ] | 219 | ] |
220 | 220 | ||
221 | for (const directory of directories) { | 221 | for (const directory of directories) { |
222 | const files = await readdir(join(root(), directory, videoUUID)) | 222 | const files = await readdir(join(directory, videoUUID)) |
223 | expect(files).to.have.length.at.least(4) | 223 | expect(files).to.have.length.at.least(4) |
224 | 224 | ||
225 | // Ensure we files exist on disk | 225 | // Ensure we files exist on disk |
diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts index 5998f58cc..e1ec2b069 100644 --- a/server/tests/api/server/follow-constraints.ts +++ b/server/tests/api/server/follow-constraints.ts | |||
@@ -1,8 +1,15 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { cleanupTests, createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | ||
5 | import { HttpStatusCode, PeerTubeProblemDocument, ServerErrorCode } from '@shared/models' | 4 | import { HttpStatusCode, PeerTubeProblemDocument, ServerErrorCode } from '@shared/models' |
5 | import { | ||
6 | cleanupTests, | ||
7 | createMultipleServers, | ||
8 | doubleFollow, | ||
9 | PeerTubeServer, | ||
10 | setAccessTokensToServers, | ||
11 | waitJobs | ||
12 | } from '@shared/server-commands' | ||
6 | 13 | ||
7 | describe('Test follow constraints', function () { | 14 | describe('Test follow constraints', function () { |
8 | let servers: PeerTubeServer[] = [] | 15 | let servers: PeerTubeServer[] = [] |
@@ -189,6 +196,7 @@ describe('Test follow constraints', function () { | |||
189 | }) | 196 | }) |
190 | 197 | ||
191 | describe('With a logged user', function () { | 198 | describe('With a logged user', function () { |
199 | |||
192 | it('Should get the local video', async function () { | 200 | it('Should get the local video', async function () { |
193 | await servers[0].videos.getWithToken({ token: userToken, id: video1UUID }) | 201 | await servers[0].videos.getWithToken({ token: userToken, id: video1UUID }) |
194 | }) | 202 | }) |
@@ -229,6 +237,84 @@ describe('Test follow constraints', function () { | |||
229 | }) | 237 | }) |
230 | }) | 238 | }) |
231 | 239 | ||
240 | describe('When following a remote account', function () { | ||
241 | |||
242 | before(async function () { | ||
243 | this.timeout(60000) | ||
244 | |||
245 | await servers[0].follows.follow({ handles: [ 'root@' + servers[1].host ] }) | ||
246 | await waitJobs(servers) | ||
247 | }) | ||
248 | |||
249 | it('Should get the remote video with an unlogged user', async function () { | ||
250 | await servers[0].videos.get({ id: video2UUID }) | ||
251 | }) | ||
252 | |||
253 | it('Should get the remote video with a logged in user', async function () { | ||
254 | await servers[0].videos.getWithToken({ token: userToken, id: video2UUID }) | ||
255 | }) | ||
256 | }) | ||
257 | |||
258 | describe('When unfollowing a remote account', function () { | ||
259 | |||
260 | before(async function () { | ||
261 | this.timeout(60000) | ||
262 | |||
263 | await servers[0].follows.unfollow({ target: 'root@' + servers[1].host }) | ||
264 | await waitJobs(servers) | ||
265 | }) | ||
266 | |||
267 | it('Should not get the remote video with an unlogged user', async function () { | ||
268 | const body = await servers[0].videos.get({ id: video2UUID, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
269 | |||
270 | const error = body as unknown as PeerTubeProblemDocument | ||
271 | expect(error.code).to.equal(ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS) | ||
272 | }) | ||
273 | |||
274 | it('Should get the remote video with a logged in user', async function () { | ||
275 | await servers[0].videos.getWithToken({ token: userToken, id: video2UUID }) | ||
276 | }) | ||
277 | }) | ||
278 | |||
279 | describe('When following a remote channel', function () { | ||
280 | |||
281 | before(async function () { | ||
282 | this.timeout(60000) | ||
283 | |||
284 | await servers[0].follows.follow({ handles: [ 'root_channel@' + servers[1].host ] }) | ||
285 | await waitJobs(servers) | ||
286 | }) | ||
287 | |||
288 | it('Should get the remote video with an unlogged user', async function () { | ||
289 | await servers[0].videos.get({ id: video2UUID }) | ||
290 | }) | ||
291 | |||
292 | it('Should get the remote video with a logged in user', async function () { | ||
293 | await servers[0].videos.getWithToken({ token: userToken, id: video2UUID }) | ||
294 | }) | ||
295 | }) | ||
296 | |||
297 | describe('When unfollowing a remote channel', function () { | ||
298 | |||
299 | before(async function () { | ||
300 | this.timeout(60000) | ||
301 | |||
302 | await servers[0].follows.unfollow({ target: 'root_channel@' + servers[1].host }) | ||
303 | await waitJobs(servers) | ||
304 | }) | ||
305 | |||
306 | it('Should not get the remote video with an unlogged user', async function () { | ||
307 | const body = await servers[0].videos.get({ id: video2UUID, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
308 | |||
309 | const error = body as unknown as PeerTubeProblemDocument | ||
310 | expect(error.code).to.equal(ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS) | ||
311 | }) | ||
312 | |||
313 | it('Should get the remote video with a logged in user', async function () { | ||
314 | await servers[0].videos.getWithToken({ token: userToken, id: video2UUID }) | ||
315 | }) | ||
316 | }) | ||
317 | |||
232 | after(async function () { | 318 | after(async function () { |
233 | await cleanupTests(servers) | 319 | await cleanupTests(servers) |
234 | }) | 320 | }) |
diff --git a/server/tests/api/server/open-telemetry.ts b/server/tests/api/server/open-telemetry.ts index 43a27cc32..7a294be82 100644 --- a/server/tests/api/server/open-telemetry.ts +++ b/server/tests/api/server/open-telemetry.ts | |||
@@ -18,7 +18,7 @@ describe('Open Telemetry', function () { | |||
18 | 18 | ||
19 | let hasError = false | 19 | let hasError = false |
20 | try { | 20 | try { |
21 | await makeRawRequest(metricsUrl, HttpStatusCode.NOT_FOUND_404) | 21 | await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) |
22 | } catch (err) { | 22 | } catch (err) { |
23 | hasError = err.message.includes('ECONNREFUSED') | 23 | hasError = err.message.includes('ECONNREFUSED') |
24 | } | 24 | } |
@@ -37,7 +37,7 @@ describe('Open Telemetry', function () { | |||
37 | } | 37 | } |
38 | }) | 38 | }) |
39 | 39 | ||
40 | const res = await makeRawRequest(metricsUrl, HttpStatusCode.OK_200) | 40 | const res = await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.OK_200 }) |
41 | expect(res.text).to.contain('peertube_job_queue_total{') | 41 | expect(res.text).to.contain('peertube_job_queue_total{') |
42 | }) | 42 | }) |
43 | 43 | ||
@@ -60,7 +60,7 @@ describe('Open Telemetry', function () { | |||
60 | } | 60 | } |
61 | }) | 61 | }) |
62 | 62 | ||
63 | const res = await makeRawRequest(metricsUrl, HttpStatusCode.OK_200) | 63 | const res = await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.OK_200 }) |
64 | expect(res.text).to.contain('peertube_playback_http_downloaded_bytes_total{') | 64 | expect(res.text).to.contain('peertube_playback_http_downloaded_bytes_total{') |
65 | }) | 65 | }) |
66 | 66 | ||
diff --git a/server/tests/api/server/proxy.ts b/server/tests/api/server/proxy.ts index a4151ebdd..71c444efd 100644 --- a/server/tests/api/server/proxy.ts +++ b/server/tests/api/server/proxy.ts | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { expectNotStartWith, expectStartWith, FIXTURE_URLS, MockProxy } from '@server/tests/shared' | 4 | import { expectNotStartWith, expectStartWith, FIXTURE_URLS, MockProxy } from '@server/tests/shared' |
5 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | 5 | import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' |
6 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | 6 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' |
7 | import { | 7 | import { |
8 | cleanupTests, | 8 | cleanupTests, |
@@ -120,40 +120,40 @@ describe('Test proxy', function () { | |||
120 | }) | 120 | }) |
121 | 121 | ||
122 | describe('Object storage', function () { | 122 | describe('Object storage', function () { |
123 | if (areObjectStorageTestsDisabled()) return | 123 | if (areMockObjectStorageTestsDisabled()) return |
124 | 124 | ||
125 | before(async function () { | 125 | before(async function () { |
126 | this.timeout(30000) | 126 | this.timeout(30000) |
127 | 127 | ||
128 | await ObjectStorageCommand.prepareDefaultBuckets() | 128 | await ObjectStorageCommand.prepareDefaultMockBuckets() |
129 | }) | 129 | }) |
130 | 130 | ||
131 | it('Should succeed to upload to object storage with the appropriate proxy config', async function () { | 131 | it('Should succeed to upload to object storage with the appropriate proxy config', async function () { |
132 | this.timeout(120000) | 132 | this.timeout(120000) |
133 | 133 | ||
134 | await servers[0].kill() | 134 | await servers[0].kill() |
135 | await servers[0].run(ObjectStorageCommand.getDefaultConfig(), { env: goodEnv }) | 135 | await servers[0].run(ObjectStorageCommand.getDefaultMockConfig(), { env: goodEnv }) |
136 | 136 | ||
137 | const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) | 137 | const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) |
138 | await waitJobs(servers) | 138 | await waitJobs(servers) |
139 | 139 | ||
140 | const video = await servers[0].videos.get({ id: uuid }) | 140 | const video = await servers[0].videos.get({ id: uuid }) |
141 | 141 | ||
142 | expectStartWith(video.files[0].fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) | 142 | expectStartWith(video.files[0].fileUrl, ObjectStorageCommand.getMockWebTorrentBaseUrl()) |
143 | }) | 143 | }) |
144 | 144 | ||
145 | it('Should fail to upload to object storage with a wrong proxy config', async function () { | 145 | it('Should fail to upload to object storage with a wrong proxy config', async function () { |
146 | this.timeout(120000) | 146 | this.timeout(120000) |
147 | 147 | ||
148 | await servers[0].kill() | 148 | await servers[0].kill() |
149 | await servers[0].run(ObjectStorageCommand.getDefaultConfig(), { env: badEnv }) | 149 | await servers[0].run(ObjectStorageCommand.getDefaultMockConfig(), { env: badEnv }) |
150 | 150 | ||
151 | const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) | 151 | const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) |
152 | await waitJobs(servers) | 152 | await waitJobs(servers, { skipDelayed: true }) |
153 | 153 | ||
154 | const video = await servers[0].videos.get({ id: uuid }) | 154 | const video = await servers[0].videos.get({ id: uuid }) |
155 | 155 | ||
156 | expectNotStartWith(video.files[0].fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) | 156 | expectNotStartWith(video.files[0].fileUrl, ObjectStorageCommand.getMockWebTorrentBaseUrl()) |
157 | }) | 157 | }) |
158 | }) | 158 | }) |
159 | 159 | ||
diff --git a/server/tests/api/transcoding/create-transcoding.ts b/server/tests/api/transcoding/create-transcoding.ts index a50bf7654..85389a949 100644 --- a/server/tests/api/transcoding/create-transcoding.ts +++ b/server/tests/api/transcoding/create-transcoding.ts | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { checkResolutionsInMasterPlaylist, expectStartWith } from '@server/tests/shared' | 4 | import { checkResolutionsInMasterPlaylist, expectStartWith } from '@server/tests/shared' |
5 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | 5 | import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' |
6 | import { HttpStatusCode, VideoDetails } from '@shared/models' | 6 | import { HttpStatusCode, VideoDetails } from '@shared/models' |
7 | import { | 7 | import { |
8 | cleanupTests, | 8 | cleanupTests, |
@@ -19,23 +19,23 @@ import { | |||
19 | 19 | ||
20 | async function checkFilesInObjectStorage (video: VideoDetails) { | 20 | async function checkFilesInObjectStorage (video: VideoDetails) { |
21 | for (const file of video.files) { | 21 | for (const file of video.files) { |
22 | expectStartWith(file.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) | 22 | expectStartWith(file.fileUrl, ObjectStorageCommand.getMockWebTorrentBaseUrl()) |
23 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 23 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
24 | } | 24 | } |
25 | 25 | ||
26 | if (video.streamingPlaylists.length === 0) return | 26 | if (video.streamingPlaylists.length === 0) return |
27 | 27 | ||
28 | const hlsPlaylist = video.streamingPlaylists[0] | 28 | const hlsPlaylist = video.streamingPlaylists[0] |
29 | for (const file of hlsPlaylist.files) { | 29 | for (const file of hlsPlaylist.files) { |
30 | expectStartWith(file.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl()) | 30 | expectStartWith(file.fileUrl, ObjectStorageCommand.getMockPlaylistBaseUrl()) |
31 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 31 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
32 | } | 32 | } |
33 | 33 | ||
34 | expectStartWith(hlsPlaylist.playlistUrl, ObjectStorageCommand.getPlaylistBaseUrl()) | 34 | expectStartWith(hlsPlaylist.playlistUrl, ObjectStorageCommand.getMockPlaylistBaseUrl()) |
35 | await makeRawRequest(hlsPlaylist.playlistUrl, HttpStatusCode.OK_200) | 35 | await makeRawRequest({ url: hlsPlaylist.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) |
36 | 36 | ||
37 | expectStartWith(hlsPlaylist.segmentsSha256Url, ObjectStorageCommand.getPlaylistBaseUrl()) | 37 | expectStartWith(hlsPlaylist.segmentsSha256Url, ObjectStorageCommand.getMockPlaylistBaseUrl()) |
38 | await makeRawRequest(hlsPlaylist.segmentsSha256Url, HttpStatusCode.OK_200) | 38 | await makeRawRequest({ url: hlsPlaylist.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) |
39 | } | 39 | } |
40 | 40 | ||
41 | function runTests (objectStorage: boolean) { | 41 | function runTests (objectStorage: boolean) { |
@@ -49,7 +49,7 @@ function runTests (objectStorage: boolean) { | |||
49 | this.timeout(120000) | 49 | this.timeout(120000) |
50 | 50 | ||
51 | const config = objectStorage | 51 | const config = objectStorage |
52 | ? ObjectStorageCommand.getDefaultConfig() | 52 | ? ObjectStorageCommand.getDefaultMockConfig() |
53 | : {} | 53 | : {} |
54 | 54 | ||
55 | // Run server 2 to have transcoding enabled | 55 | // Run server 2 to have transcoding enabled |
@@ -60,7 +60,7 @@ function runTests (objectStorage: boolean) { | |||
60 | 60 | ||
61 | await doubleFollow(servers[0], servers[1]) | 61 | await doubleFollow(servers[0], servers[1]) |
62 | 62 | ||
63 | if (objectStorage) await ObjectStorageCommand.prepareDefaultBuckets() | 63 | if (objectStorage) await ObjectStorageCommand.prepareDefaultMockBuckets() |
64 | 64 | ||
65 | const { shortUUID } = await servers[0].videos.quickUpload({ name: 'video' }) | 65 | const { shortUUID } = await servers[0].videos.quickUpload({ name: 'video' }) |
66 | videoUUID = shortUUID | 66 | videoUUID = shortUUID |
@@ -234,7 +234,7 @@ function runTests (objectStorage: boolean) { | |||
234 | 234 | ||
235 | it('Should have correctly deleted previous files', async function () { | 235 | it('Should have correctly deleted previous files', async function () { |
236 | for (const fileUrl of shouldBeDeleted) { | 236 | for (const fileUrl of shouldBeDeleted) { |
237 | await makeRawRequest(fileUrl, HttpStatusCode.NOT_FOUND_404) | 237 | await makeRawRequest({ url: fileUrl, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) |
238 | } | 238 | } |
239 | }) | 239 | }) |
240 | 240 | ||
@@ -256,7 +256,7 @@ describe('Test create transcoding jobs from API', function () { | |||
256 | }) | 256 | }) |
257 | 257 | ||
258 | describe('On object storage', function () { | 258 | describe('On object storage', function () { |
259 | if (areObjectStorageTestsDisabled()) return | 259 | if (areMockObjectStorageTestsDisabled()) return |
260 | 260 | ||
261 | runTests(true) | 261 | runTests(true) |
262 | }) | 262 | }) |
diff --git a/server/tests/api/transcoding/hls.ts b/server/tests/api/transcoding/hls.ts index 252422e5d..84a53c0bd 100644 --- a/server/tests/api/transcoding/hls.ts +++ b/server/tests/api/transcoding/hls.ts | |||
@@ -1,168 +1,48 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { expect } from 'chai' | 3 | import { join } from 'path' |
4 | import { basename, join } from 'path' | 4 | import { checkDirectoryIsEmpty, checkTmpIsEmpty, completeCheckHlsPlaylist } from '@server/tests/shared' |
5 | import { | 5 | import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' |
6 | checkDirectoryIsEmpty, | 6 | import { HttpStatusCode } from '@shared/models' |
7 | checkResolutionsInMasterPlaylist, | ||
8 | checkSegmentHash, | ||
9 | checkTmpIsEmpty, | ||
10 | expectStartWith, | ||
11 | hlsInfohashExist | ||
12 | } from '@server/tests/shared' | ||
13 | import { areObjectStorageTestsDisabled, removeFragmentedMP4Ext, uuidRegex } from '@shared/core-utils' | ||
14 | import { HttpStatusCode, VideoStreamingPlaylistType } from '@shared/models' | ||
15 | import { | 7 | import { |
16 | cleanupTests, | 8 | cleanupTests, |
17 | createMultipleServers, | 9 | createMultipleServers, |
18 | doubleFollow, | 10 | doubleFollow, |
19 | makeRawRequest, | ||
20 | ObjectStorageCommand, | 11 | ObjectStorageCommand, |
21 | PeerTubeServer, | 12 | PeerTubeServer, |
22 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
23 | waitJobs, | 14 | waitJobs |
24 | webtorrentAdd | ||
25 | } from '@shared/server-commands' | 15 | } from '@shared/server-commands' |
26 | import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' | 16 | import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' |
27 | 17 | ||
28 | async function checkHlsPlaylist (options: { | ||
29 | servers: PeerTubeServer[] | ||
30 | videoUUID: string | ||
31 | hlsOnly: boolean | ||
32 | |||
33 | resolutions?: number[] | ||
34 | objectStorageBaseUrl: string | ||
35 | }) { | ||
36 | const { videoUUID, hlsOnly, objectStorageBaseUrl } = options | ||
37 | |||
38 | const resolutions = options.resolutions ?? [ 240, 360, 480, 720 ] | ||
39 | |||
40 | for (const server of options.servers) { | ||
41 | const videoDetails = await server.videos.get({ id: videoUUID }) | ||
42 | const baseUrl = `http://${videoDetails.account.host}` | ||
43 | |||
44 | expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) | ||
45 | |||
46 | const hlsPlaylist = videoDetails.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) | ||
47 | expect(hlsPlaylist).to.not.be.undefined | ||
48 | |||
49 | const hlsFiles = hlsPlaylist.files | ||
50 | expect(hlsFiles).to.have.lengthOf(resolutions.length) | ||
51 | |||
52 | if (hlsOnly) expect(videoDetails.files).to.have.lengthOf(0) | ||
53 | else expect(videoDetails.files).to.have.lengthOf(resolutions.length) | ||
54 | |||
55 | // Check JSON files | ||
56 | for (const resolution of resolutions) { | ||
57 | const file = hlsFiles.find(f => f.resolution.id === resolution) | ||
58 | expect(file).to.not.be.undefined | ||
59 | |||
60 | expect(file.magnetUri).to.have.lengthOf.above(2) | ||
61 | expect(file.torrentUrl).to.match( | ||
62 | new RegExp(`http://${server.host}/lazy-static/torrents/${uuidRegex}-${file.resolution.id}-hls.torrent`) | ||
63 | ) | ||
64 | |||
65 | if (objectStorageBaseUrl) { | ||
66 | expectStartWith(file.fileUrl, objectStorageBaseUrl) | ||
67 | } else { | ||
68 | expect(file.fileUrl).to.match( | ||
69 | new RegExp(`${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${uuidRegex}-${file.resolution.id}-fragmented.mp4`) | ||
70 | ) | ||
71 | } | ||
72 | |||
73 | expect(file.resolution.label).to.equal(resolution + 'p') | ||
74 | |||
75 | await makeRawRequest(file.torrentUrl, HttpStatusCode.OK_200) | ||
76 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | ||
77 | |||
78 | const torrent = await webtorrentAdd(file.magnetUri, true) | ||
79 | expect(torrent.files).to.be.an('array') | ||
80 | expect(torrent.files.length).to.equal(1) | ||
81 | expect(torrent.files[0].path).to.exist.and.to.not.equal('') | ||
82 | } | ||
83 | |||
84 | // Check master playlist | ||
85 | { | ||
86 | await checkResolutionsInMasterPlaylist({ server, playlistUrl: hlsPlaylist.playlistUrl, resolutions }) | ||
87 | |||
88 | const masterPlaylist = await server.streamingPlaylists.get({ url: hlsPlaylist.playlistUrl }) | ||
89 | |||
90 | let i = 0 | ||
91 | for (const resolution of resolutions) { | ||
92 | expect(masterPlaylist).to.contain(`${resolution}.m3u8`) | ||
93 | expect(masterPlaylist).to.contain(`${resolution}.m3u8`) | ||
94 | |||
95 | const url = 'http://' + videoDetails.account.host | ||
96 | await hlsInfohashExist(url, hlsPlaylist.playlistUrl, i) | ||
97 | |||
98 | i++ | ||
99 | } | ||
100 | } | ||
101 | |||
102 | // Check resolution playlists | ||
103 | { | ||
104 | for (const resolution of resolutions) { | ||
105 | const file = hlsFiles.find(f => f.resolution.id === resolution) | ||
106 | const playlistName = removeFragmentedMP4Ext(basename(file.fileUrl)) + '.m3u8' | ||
107 | |||
108 | const url = objectStorageBaseUrl | ||
109 | ? `${objectStorageBaseUrl}hls/${videoUUID}/${playlistName}` | ||
110 | : `${baseUrl}/static/streaming-playlists/hls/${videoUUID}/${playlistName}` | ||
111 | |||
112 | const subPlaylist = await server.streamingPlaylists.get({ url }) | ||
113 | |||
114 | expect(subPlaylist).to.match(new RegExp(`${uuidRegex}-${resolution}-fragmented.mp4`)) | ||
115 | expect(subPlaylist).to.contain(basename(file.fileUrl)) | ||
116 | } | ||
117 | } | ||
118 | |||
119 | { | ||
120 | const baseUrlAndPath = objectStorageBaseUrl | ||
121 | ? objectStorageBaseUrl + 'hls/' + videoUUID | ||
122 | : baseUrl + '/static/streaming-playlists/hls/' + videoUUID | ||
123 | |||
124 | for (const resolution of resolutions) { | ||
125 | await checkSegmentHash({ | ||
126 | server, | ||
127 | baseUrlPlaylist: baseUrlAndPath, | ||
128 | baseUrlSegment: baseUrlAndPath, | ||
129 | resolution, | ||
130 | hlsPlaylist | ||
131 | }) | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
137 | describe('Test HLS videos', function () { | 18 | describe('Test HLS videos', function () { |
138 | let servers: PeerTubeServer[] = [] | 19 | let servers: PeerTubeServer[] = [] |
139 | let videoUUID = '' | ||
140 | let videoAudioUUID = '' | ||
141 | 20 | ||
142 | function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) { | 21 | function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) { |
22 | const videoUUIDs: string[] = [] | ||
143 | 23 | ||
144 | it('Should upload a video and transcode it to HLS', async function () { | 24 | it('Should upload a video and transcode it to HLS', async function () { |
145 | this.timeout(120000) | 25 | this.timeout(120000) |
146 | 26 | ||
147 | const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video 1', fixture: 'video_short.webm' } }) | 27 | const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video 1', fixture: 'video_short.webm' } }) |
148 | videoUUID = uuid | 28 | videoUUIDs.push(uuid) |
149 | 29 | ||
150 | await waitJobs(servers) | 30 | await waitJobs(servers) |
151 | 31 | ||
152 | await checkHlsPlaylist({ servers, videoUUID, hlsOnly, objectStorageBaseUrl }) | 32 | await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) |
153 | }) | 33 | }) |
154 | 34 | ||
155 | it('Should upload an audio file and transcode it to HLS', async function () { | 35 | it('Should upload an audio file and transcode it to HLS', async function () { |
156 | this.timeout(120000) | 36 | this.timeout(120000) |
157 | 37 | ||
158 | const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video audio', fixture: 'sample.ogg' } }) | 38 | const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video audio', fixture: 'sample.ogg' } }) |
159 | videoAudioUUID = uuid | 39 | videoUUIDs.push(uuid) |
160 | 40 | ||
161 | await waitJobs(servers) | 41 | await waitJobs(servers) |
162 | 42 | ||
163 | await checkHlsPlaylist({ | 43 | await completeCheckHlsPlaylist({ |
164 | servers, | 44 | servers, |
165 | videoUUID: videoAudioUUID, | 45 | videoUUID: uuid, |
166 | hlsOnly, | 46 | hlsOnly, |
167 | resolutions: [ DEFAULT_AUDIO_RESOLUTION, 360, 240 ], | 47 | resolutions: [ DEFAULT_AUDIO_RESOLUTION, 360, 240 ], |
168 | objectStorageBaseUrl | 48 | objectStorageBaseUrl |
@@ -172,31 +52,36 @@ describe('Test HLS videos', function () { | |||
172 | it('Should update the video', async function () { | 52 | it('Should update the video', async function () { |
173 | this.timeout(30000) | 53 | this.timeout(30000) |
174 | 54 | ||
175 | await servers[0].videos.update({ id: videoUUID, attributes: { name: 'video 1 updated' } }) | 55 | await servers[0].videos.update({ id: videoUUIDs[0], attributes: { name: 'video 1 updated' } }) |
176 | 56 | ||
177 | await waitJobs(servers) | 57 | await waitJobs(servers) |
178 | 58 | ||
179 | await checkHlsPlaylist({ servers, videoUUID, hlsOnly, objectStorageBaseUrl }) | 59 | await completeCheckHlsPlaylist({ servers, videoUUID: videoUUIDs[0], hlsOnly, objectStorageBaseUrl }) |
180 | }) | 60 | }) |
181 | 61 | ||
182 | it('Should delete videos', async function () { | 62 | it('Should delete videos', async function () { |
183 | this.timeout(10000) | 63 | this.timeout(10000) |
184 | 64 | ||
185 | await servers[0].videos.remove({ id: videoUUID }) | 65 | for (const uuid of videoUUIDs) { |
186 | await servers[0].videos.remove({ id: videoAudioUUID }) | 66 | await servers[0].videos.remove({ id: uuid }) |
67 | } | ||
187 | 68 | ||
188 | await waitJobs(servers) | 69 | await waitJobs(servers) |
189 | 70 | ||
190 | for (const server of servers) { | 71 | for (const server of servers) { |
191 | await server.videos.get({ id: videoUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | 72 | for (const uuid of videoUUIDs) { |
192 | await server.videos.get({ id: videoAudioUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | 73 | await server.videos.get({ id: uuid, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) |
74 | } | ||
193 | } | 75 | } |
194 | }) | 76 | }) |
195 | 77 | ||
196 | it('Should have the playlists/segment deleted from the disk', async function () { | 78 | it('Should have the playlists/segment deleted from the disk', async function () { |
197 | for (const server of servers) { | 79 | for (const server of servers) { |
198 | await checkDirectoryIsEmpty(server, 'videos') | 80 | await checkDirectoryIsEmpty(server, 'videos', [ 'private' ]) |
199 | await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls')) | 81 | await checkDirectoryIsEmpty(server, join('videos', 'private')) |
82 | |||
83 | await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls'), [ 'private' ]) | ||
84 | await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls', 'private')) | ||
200 | } | 85 | } |
201 | }) | 86 | }) |
202 | 87 | ||
@@ -265,19 +150,19 @@ describe('Test HLS videos', function () { | |||
265 | }) | 150 | }) |
266 | 151 | ||
267 | describe('With object storage enabled', function () { | 152 | describe('With object storage enabled', function () { |
268 | if (areObjectStorageTestsDisabled()) return | 153 | if (areMockObjectStorageTestsDisabled()) return |
269 | 154 | ||
270 | before(async function () { | 155 | before(async function () { |
271 | this.timeout(120000) | 156 | this.timeout(120000) |
272 | 157 | ||
273 | const configOverride = ObjectStorageCommand.getDefaultConfig() | 158 | const configOverride = ObjectStorageCommand.getDefaultMockConfig() |
274 | await ObjectStorageCommand.prepareDefaultBuckets() | 159 | await ObjectStorageCommand.prepareDefaultMockBuckets() |
275 | 160 | ||
276 | await servers[0].kill() | 161 | await servers[0].kill() |
277 | await servers[0].run(configOverride) | 162 | await servers[0].run(configOverride) |
278 | }) | 163 | }) |
279 | 164 | ||
280 | runTestSuite(true, ObjectStorageCommand.getPlaylistBaseUrl()) | 165 | runTestSuite(true, ObjectStorageCommand.getMockPlaylistBaseUrl()) |
281 | }) | 166 | }) |
282 | 167 | ||
283 | after(async function () { | 168 | after(async function () { |
diff --git a/server/tests/api/transcoding/index.ts b/server/tests/api/transcoding/index.ts index 0cc28b4a4..9866418d6 100644 --- a/server/tests/api/transcoding/index.ts +++ b/server/tests/api/transcoding/index.ts | |||
@@ -2,4 +2,5 @@ export * from './audio-only' | |||
2 | export * from './create-transcoding' | 2 | export * from './create-transcoding' |
3 | export * from './hls' | 3 | export * from './hls' |
4 | export * from './transcoder' | 4 | export * from './transcoder' |
5 | export * from './update-while-transcoding' | ||
5 | export * from './video-studio' | 6 | export * from './video-studio' |
diff --git a/server/tests/api/transcoding/update-while-transcoding.ts b/server/tests/api/transcoding/update-while-transcoding.ts new file mode 100644 index 000000000..8e32ea069 --- /dev/null +++ b/server/tests/api/transcoding/update-while-transcoding.ts | |||
@@ -0,0 +1,151 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { completeCheckHlsPlaylist } from '@server/tests/shared' | ||
4 | import { areMockObjectStorageTestsDisabled, wait } from '@shared/core-utils' | ||
5 | import { VideoPrivacy } from '@shared/models' | ||
6 | import { | ||
7 | cleanupTests, | ||
8 | createMultipleServers, | ||
9 | doubleFollow, | ||
10 | ObjectStorageCommand, | ||
11 | PeerTubeServer, | ||
12 | setAccessTokensToServers, | ||
13 | waitJobs | ||
14 | } from '@shared/server-commands' | ||
15 | |||
16 | describe('Test update video privacy while transcoding', function () { | ||
17 | let servers: PeerTubeServer[] = [] | ||
18 | |||
19 | const videoUUIDs: string[] = [] | ||
20 | |||
21 | function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) { | ||
22 | |||
23 | it('Should not have an error while quickly updating a private video to public after upload #1', async function () { | ||
24 | this.timeout(360_000) | ||
25 | |||
26 | const attributes = { | ||
27 | name: 'quick update', | ||
28 | privacy: VideoPrivacy.PRIVATE | ||
29 | } | ||
30 | |||
31 | const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: false }) | ||
32 | await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) | ||
33 | videoUUIDs.push(uuid) | ||
34 | |||
35 | await waitJobs(servers) | ||
36 | |||
37 | await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) | ||
38 | }) | ||
39 | |||
40 | it('Should not have an error while quickly updating a private video to public after upload #2', async function () { | ||
41 | |||
42 | { | ||
43 | const attributes = { | ||
44 | name: 'quick update 2', | ||
45 | privacy: VideoPrivacy.PRIVATE | ||
46 | } | ||
47 | |||
48 | const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: true }) | ||
49 | await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) | ||
50 | videoUUIDs.push(uuid) | ||
51 | |||
52 | await waitJobs(servers) | ||
53 | |||
54 | await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) | ||
55 | } | ||
56 | }) | ||
57 | |||
58 | it('Should not have an error while quickly updating a private video to public after upload #3', async function () { | ||
59 | const attributes = { | ||
60 | name: 'quick update 3', | ||
61 | privacy: VideoPrivacy.PRIVATE | ||
62 | } | ||
63 | |||
64 | const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: true }) | ||
65 | await wait(1000) | ||
66 | await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) | ||
67 | videoUUIDs.push(uuid) | ||
68 | |||
69 | await waitJobs(servers) | ||
70 | |||
71 | await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) | ||
72 | }) | ||
73 | } | ||
74 | |||
75 | before(async function () { | ||
76 | this.timeout(120000) | ||
77 | |||
78 | const configOverride = { | ||
79 | transcoding: { | ||
80 | enabled: true, | ||
81 | allow_audio_files: true, | ||
82 | hls: { | ||
83 | enabled: true | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | servers = await createMultipleServers(2, configOverride) | ||
88 | |||
89 | // Get the access tokens | ||
90 | await setAccessTokensToServers(servers) | ||
91 | |||
92 | // Server 1 and server 2 follow each other | ||
93 | await doubleFollow(servers[0], servers[1]) | ||
94 | }) | ||
95 | |||
96 | describe('With WebTorrent & HLS enabled', function () { | ||
97 | runTestSuite(false) | ||
98 | }) | ||
99 | |||
100 | describe('With only HLS enabled', function () { | ||
101 | |||
102 | before(async function () { | ||
103 | await servers[0].config.updateCustomSubConfig({ | ||
104 | newConfig: { | ||
105 | transcoding: { | ||
106 | enabled: true, | ||
107 | allowAudioFiles: true, | ||
108 | resolutions: { | ||
109 | '144p': false, | ||
110 | '240p': true, | ||
111 | '360p': true, | ||
112 | '480p': true, | ||
113 | '720p': true, | ||
114 | '1080p': true, | ||
115 | '1440p': true, | ||
116 | '2160p': true | ||
117 | }, | ||
118 | hls: { | ||
119 | enabled: true | ||
120 | }, | ||
121 | webtorrent: { | ||
122 | enabled: false | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | }) | ||
127 | }) | ||
128 | |||
129 | runTestSuite(true) | ||
130 | }) | ||
131 | |||
132 | describe('With object storage enabled', function () { | ||
133 | if (areMockObjectStorageTestsDisabled()) return | ||
134 | |||
135 | before(async function () { | ||
136 | this.timeout(120000) | ||
137 | |||
138 | const configOverride = ObjectStorageCommand.getDefaultMockConfig() | ||
139 | await ObjectStorageCommand.prepareDefaultMockBuckets() | ||
140 | |||
141 | await servers[0].kill() | ||
142 | await servers[0].run(configOverride) | ||
143 | }) | ||
144 | |||
145 | runTestSuite(true, ObjectStorageCommand.getMockPlaylistBaseUrl()) | ||
146 | }) | ||
147 | |||
148 | after(async function () { | ||
149 | await cleanupTests(servers) | ||
150 | }) | ||
151 | }) | ||
diff --git a/server/tests/api/transcoding/video-studio.ts b/server/tests/api/transcoding/video-studio.ts index 9613111b5..ab08e8fb6 100644 --- a/server/tests/api/transcoding/video-studio.ts +++ b/server/tests/api/transcoding/video-studio.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { expect } from 'chai' | 1 | import { expect } from 'chai' |
2 | import { expectStartWith } from '@server/tests/shared' | 2 | import { expectStartWith } from '@server/tests/shared' |
3 | import { areObjectStorageTestsDisabled, getAllFiles } from '@shared/core-utils' | 3 | import { areMockObjectStorageTestsDisabled, getAllFiles } from '@shared/core-utils' |
4 | import { VideoStudioTask } from '@shared/models' | 4 | import { VideoStudioTask } from '@shared/models' |
5 | import { | 5 | import { |
6 | cleanupTests, | 6 | cleanupTests, |
@@ -315,13 +315,13 @@ describe('Test video studio', function () { | |||
315 | }) | 315 | }) |
316 | 316 | ||
317 | describe('Object storage video edition', function () { | 317 | describe('Object storage video edition', function () { |
318 | if (areObjectStorageTestsDisabled()) return | 318 | if (areMockObjectStorageTestsDisabled()) return |
319 | 319 | ||
320 | before(async function () { | 320 | before(async function () { |
321 | await ObjectStorageCommand.prepareDefaultBuckets() | 321 | await ObjectStorageCommand.prepareDefaultMockBuckets() |
322 | 322 | ||
323 | await servers[0].kill() | 323 | await servers[0].kill() |
324 | await servers[0].run(ObjectStorageCommand.getDefaultConfig()) | 324 | await servers[0].run(ObjectStorageCommand.getDefaultMockConfig()) |
325 | 325 | ||
326 | await servers[0].config.enableMinimumTranscoding() | 326 | await servers[0].config.enableMinimumTranscoding() |
327 | }) | 327 | }) |
@@ -344,11 +344,11 @@ describe('Test video studio', function () { | |||
344 | } | 344 | } |
345 | 345 | ||
346 | for (const webtorrentFile of video.files) { | 346 | for (const webtorrentFile of video.files) { |
347 | expectStartWith(webtorrentFile.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) | 347 | expectStartWith(webtorrentFile.fileUrl, ObjectStorageCommand.getMockWebTorrentBaseUrl()) |
348 | } | 348 | } |
349 | 349 | ||
350 | for (const hlsFile of video.streamingPlaylists[0].files) { | 350 | for (const hlsFile of video.streamingPlaylists[0].files) { |
351 | expectStartWith(hlsFile.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl()) | 351 | expectStartWith(hlsFile.fileUrl, ObjectStorageCommand.getMockPlaylistBaseUrl()) |
352 | } | 352 | } |
353 | 353 | ||
354 | await checkDuration(server, 9) | 354 | await checkDuration(server, 9) |
diff --git a/server/tests/api/users/index.ts b/server/tests/api/users/index.ts index c65152c6f..643f1a531 100644 --- a/server/tests/api/users/index.ts +++ b/server/tests/api/users/index.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | import './two-factor' | ||
1 | import './user-subscriptions' | 2 | import './user-subscriptions' |
2 | import './user-videos' | 3 | import './user-videos' |
3 | import './users' | 4 | import './users' |
diff --git a/server/tests/api/users/two-factor.ts b/server/tests/api/users/two-factor.ts new file mode 100644 index 000000000..0dcab9e17 --- /dev/null +++ b/server/tests/api/users/two-factor.ts | |||
@@ -0,0 +1,200 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { expectStartWith } from '@server/tests/shared' | ||
5 | import { HttpStatusCode } from '@shared/models' | ||
6 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, TwoFactorCommand } from '@shared/server-commands' | ||
7 | |||
8 | async function login (options: { | ||
9 | server: PeerTubeServer | ||
10 | username: string | ||
11 | password: string | ||
12 | otpToken?: string | ||
13 | expectedStatus?: HttpStatusCode | ||
14 | }) { | ||
15 | const { server, username, password, otpToken, expectedStatus } = options | ||
16 | |||
17 | const user = { username, password } | ||
18 | const { res, body: { access_token: token } } = await server.login.loginAndGetResponse({ user, otpToken, expectedStatus }) | ||
19 | |||
20 | return { res, token } | ||
21 | } | ||
22 | |||
23 | describe('Test users', function () { | ||
24 | let server: PeerTubeServer | ||
25 | let otpSecret: string | ||
26 | let requestToken: string | ||
27 | |||
28 | const userUsername = 'user1' | ||
29 | let userId: number | ||
30 | let userPassword: string | ||
31 | let userToken: string | ||
32 | |||
33 | before(async function () { | ||
34 | this.timeout(30000) | ||
35 | |||
36 | server = await createSingleServer(1) | ||
37 | |||
38 | await setAccessTokensToServers([ server ]) | ||
39 | const res = await server.users.generate(userUsername) | ||
40 | userId = res.userId | ||
41 | userPassword = res.password | ||
42 | userToken = res.token | ||
43 | }) | ||
44 | |||
45 | it('Should not add the header on login if two factor is not enabled', async function () { | ||
46 | const { res, token } = await login({ server, username: userUsername, password: userPassword }) | ||
47 | |||
48 | expect(res.header['x-peertube-otp']).to.not.exist | ||
49 | |||
50 | await server.users.getMyInfo({ token }) | ||
51 | }) | ||
52 | |||
53 | it('Should request two factor and get the secret and uri', async function () { | ||
54 | const { otpRequest } = await server.twoFactor.request({ userId, token: userToken, currentPassword: userPassword }) | ||
55 | |||
56 | expect(otpRequest.requestToken).to.exist | ||
57 | |||
58 | expect(otpRequest.secret).to.exist | ||
59 | expect(otpRequest.secret).to.have.lengthOf(32) | ||
60 | |||
61 | expect(otpRequest.uri).to.exist | ||
62 | expectStartWith(otpRequest.uri, 'otpauth://') | ||
63 | expect(otpRequest.uri).to.include(otpRequest.secret) | ||
64 | |||
65 | requestToken = otpRequest.requestToken | ||
66 | otpSecret = otpRequest.secret | ||
67 | }) | ||
68 | |||
69 | it('Should not have two factor confirmed yet', async function () { | ||
70 | const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
71 | expect(twoFactorEnabled).to.be.false | ||
72 | }) | ||
73 | |||
74 | it('Should confirm two factor', async function () { | ||
75 | await server.twoFactor.confirmRequest({ | ||
76 | userId, | ||
77 | token: userToken, | ||
78 | otpToken: TwoFactorCommand.buildOTP({ secret: otpSecret }).generate(), | ||
79 | requestToken | ||
80 | }) | ||
81 | }) | ||
82 | |||
83 | it('Should not add the header on login if two factor is enabled and password is incorrect', async function () { | ||
84 | const { res, token } = await login({ server, username: userUsername, password: 'fake', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) | ||
85 | |||
86 | expect(res.header['x-peertube-otp']).to.not.exist | ||
87 | expect(token).to.not.exist | ||
88 | }) | ||
89 | |||
90 | it('Should add the header on login if two factor is enabled and password is correct', async function () { | ||
91 | const { res, token } = await login({ | ||
92 | server, | ||
93 | username: userUsername, | ||
94 | password: userPassword, | ||
95 | expectedStatus: HttpStatusCode.UNAUTHORIZED_401 | ||
96 | }) | ||
97 | |||
98 | expect(res.header['x-peertube-otp']).to.exist | ||
99 | expect(token).to.not.exist | ||
100 | |||
101 | await server.users.getMyInfo({ token }) | ||
102 | }) | ||
103 | |||
104 | it('Should not login with correct password and incorrect otp secret', async function () { | ||
105 | const otp = TwoFactorCommand.buildOTP({ secret: 'a'.repeat(32) }) | ||
106 | |||
107 | const { res, token } = await login({ | ||
108 | server, | ||
109 | username: userUsername, | ||
110 | password: userPassword, | ||
111 | otpToken: otp.generate(), | ||
112 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
113 | }) | ||
114 | |||
115 | expect(res.header['x-peertube-otp']).to.not.exist | ||
116 | expect(token).to.not.exist | ||
117 | }) | ||
118 | |||
119 | it('Should not login with correct password and incorrect otp code', async function () { | ||
120 | const { res, token } = await login({ | ||
121 | server, | ||
122 | username: userUsername, | ||
123 | password: userPassword, | ||
124 | otpToken: '123456', | ||
125 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
126 | }) | ||
127 | |||
128 | expect(res.header['x-peertube-otp']).to.not.exist | ||
129 | expect(token).to.not.exist | ||
130 | }) | ||
131 | |||
132 | it('Should not login with incorrect password and correct otp code', async function () { | ||
133 | const otpToken = TwoFactorCommand.buildOTP({ secret: otpSecret }).generate() | ||
134 | |||
135 | const { res, token } = await login({ | ||
136 | server, | ||
137 | username: userUsername, | ||
138 | password: 'fake', | ||
139 | otpToken, | ||
140 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
141 | }) | ||
142 | |||
143 | expect(res.header['x-peertube-otp']).to.not.exist | ||
144 | expect(token).to.not.exist | ||
145 | }) | ||
146 | |||
147 | it('Should correctly login with correct password and otp code', async function () { | ||
148 | const otpToken = TwoFactorCommand.buildOTP({ secret: otpSecret }).generate() | ||
149 | |||
150 | const { res, token } = await login({ server, username: userUsername, password: userPassword, otpToken }) | ||
151 | |||
152 | expect(res.header['x-peertube-otp']).to.not.exist | ||
153 | expect(token).to.exist | ||
154 | |||
155 | await server.users.getMyInfo({ token }) | ||
156 | }) | ||
157 | |||
158 | it('Should have two factor enabled when getting my info', async function () { | ||
159 | const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
160 | expect(twoFactorEnabled).to.be.true | ||
161 | }) | ||
162 | |||
163 | it('Should disable two factor and be able to login without otp token', async function () { | ||
164 | await server.twoFactor.disable({ userId, token: userToken, currentPassword: userPassword }) | ||
165 | |||
166 | const { res, token } = await login({ server, username: userUsername, password: userPassword }) | ||
167 | expect(res.header['x-peertube-otp']).to.not.exist | ||
168 | |||
169 | await server.users.getMyInfo({ token }) | ||
170 | }) | ||
171 | |||
172 | it('Should have two factor disabled when getting my info', async function () { | ||
173 | const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
174 | expect(twoFactorEnabled).to.be.false | ||
175 | }) | ||
176 | |||
177 | it('Should enable two factor auth without password from an admin', async function () { | ||
178 | const { otpRequest } = await server.twoFactor.request({ userId }) | ||
179 | |||
180 | await server.twoFactor.confirmRequest({ | ||
181 | userId, | ||
182 | otpToken: TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate(), | ||
183 | requestToken: otpRequest.requestToken | ||
184 | }) | ||
185 | |||
186 | const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
187 | expect(twoFactorEnabled).to.be.true | ||
188 | }) | ||
189 | |||
190 | it('Should disable two factor auth without password from an admin', async function () { | ||
191 | await server.twoFactor.disable({ userId }) | ||
192 | |||
193 | const { twoFactorEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
194 | expect(twoFactorEnabled).to.be.false | ||
195 | }) | ||
196 | |||
197 | after(async function () { | ||
198 | await cleanupTests([ server ]) | ||
199 | }) | ||
200 | }) | ||
diff --git a/server/tests/api/users/users-multiple-servers.ts b/server/tests/api/users/users-multiple-servers.ts index 62d668d1e..188e6f137 100644 --- a/server/tests/api/users/users-multiple-servers.ts +++ b/server/tests/api/users/users-multiple-servers.ts | |||
@@ -197,7 +197,7 @@ describe('Test users with multiple servers', function () { | |||
197 | it('Should not have actor files', async () => { | 197 | it('Should not have actor files', async () => { |
198 | for (const server of servers) { | 198 | for (const server of servers) { |
199 | for (const userAvatarFilename of userAvatarFilenames) { | 199 | for (const userAvatarFilename of userAvatarFilenames) { |
200 | await checkActorFilesWereRemoved(userAvatarFilename, server.internalServerNumber) | 200 | await checkActorFilesWereRemoved(userAvatarFilename, server) |
201 | } | 201 | } |
202 | } | 202 | } |
203 | }) | 203 | }) |
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts index 9e657b387..421b3ce16 100644 --- a/server/tests/api/users/users.ts +++ b/server/tests/api/users/users.ts | |||
@@ -181,7 +181,7 @@ describe('Test users', function () { | |||
181 | }) | 181 | }) |
182 | 182 | ||
183 | it('Should refresh the token', async function () { | 183 | it('Should refresh the token', async function () { |
184 | this.timeout(15000) | 184 | this.timeout(50000) |
185 | 185 | ||
186 | const futureDate = new Date(new Date().getTime() + 1000 * 60).toISOString() | 186 | const futureDate = new Date(new Date().getTime() + 1000 * 60).toISOString() |
187 | await server.sql.setTokenField(server.accessToken, 'refreshTokenExpiresAt', futureDate) | 187 | await server.sql.setTokenField(server.accessToken, 'refreshTokenExpiresAt', futureDate) |
@@ -219,7 +219,7 @@ describe('Test users', function () { | |||
219 | expect(user.email).to.equal('user_1@example.com') | 219 | expect(user.email).to.equal('user_1@example.com') |
220 | expect(user.nsfwPolicy).to.equal('display') | 220 | expect(user.nsfwPolicy).to.equal('display') |
221 | expect(user.videoQuota).to.equal(2 * 1024 * 1024) | 221 | expect(user.videoQuota).to.equal(2 * 1024 * 1024) |
222 | expect(user.roleLabel).to.equal('User') | 222 | expect(user.role.label).to.equal('User') |
223 | expect(user.id).to.be.a('number') | 223 | expect(user.id).to.be.a('number') |
224 | expect(user.account.displayName).to.equal('user_1') | 224 | expect(user.account.displayName).to.equal('user_1') |
225 | expect(user.account.description).to.be.null | 225 | expect(user.account.description).to.be.null |
@@ -277,7 +277,7 @@ describe('Test users', function () { | |||
277 | const user = data[0] | 277 | const user = data[0] |
278 | expect(user.username).to.equal('root') | 278 | expect(user.username).to.equal('root') |
279 | expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com') | 279 | expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com') |
280 | expect(user.roleLabel).to.equal('Administrator') | 280 | expect(user.role.label).to.equal('Administrator') |
281 | expect(user.nsfwPolicy).to.equal('display') | 281 | expect(user.nsfwPolicy).to.equal('display') |
282 | }) | 282 | }) |
283 | 283 | ||
@@ -531,7 +531,7 @@ describe('Test users', function () { | |||
531 | expect(user.emailVerified).to.be.true | 531 | expect(user.emailVerified).to.be.true |
532 | expect(user.nsfwPolicy).to.equal('do_not_list') | 532 | expect(user.nsfwPolicy).to.equal('do_not_list') |
533 | expect(user.videoQuota).to.equal(42) | 533 | expect(user.videoQuota).to.equal(42) |
534 | expect(user.roleLabel).to.equal('Moderator') | 534 | expect(user.role.label).to.equal('Moderator') |
535 | expect(user.id).to.be.a('number') | 535 | expect(user.id).to.be.a('number') |
536 | expect(user.adminFlags).to.equal(UserAdminFlag.NONE) | 536 | expect(user.adminFlags).to.equal(UserAdminFlag.NONE) |
537 | expect(user.pluginAuth).to.equal('toto') | 537 | expect(user.pluginAuth).to.equal('toto') |
diff --git a/server/tests/api/videos/channel-import-videos.ts b/server/tests/api/videos/channel-import-videos.ts index 7cfd02fbb..a66f88a0e 100644 --- a/server/tests/api/videos/channel-import-videos.ts +++ b/server/tests/api/videos/channel-import-videos.ts | |||
@@ -109,6 +109,45 @@ describe('Test videos import in a channel', function () { | |||
109 | } | 109 | } |
110 | }) | 110 | }) |
111 | 111 | ||
112 | it('Should limit max amount of videos synced on full sync', async function () { | ||
113 | this.timeout(240_000) | ||
114 | |||
115 | await server.kill() | ||
116 | await server.run({ | ||
117 | import: { | ||
118 | video_channel_synchronization: { | ||
119 | full_sync_videos_limit: 1 | ||
120 | } | ||
121 | } | ||
122 | }) | ||
123 | |||
124 | const { id } = await server.channels.create({ attributes: { name: 'channel3' } }) | ||
125 | const channel3Id = id | ||
126 | |||
127 | const { videoChannelSync } = await server.channelSyncs.create({ | ||
128 | attributes: { | ||
129 | externalChannelUrl: FIXTURE_URLS.youtubeChannel, | ||
130 | videoChannelId: channel3Id | ||
131 | } | ||
132 | }) | ||
133 | const syncId = videoChannelSync.id | ||
134 | |||
135 | await waitJobs(server) | ||
136 | |||
137 | await server.channels.importVideos({ | ||
138 | channelName: 'channel3', | ||
139 | externalChannelUrl: FIXTURE_URLS.youtubeChannel, | ||
140 | videoChannelSyncId: syncId | ||
141 | }) | ||
142 | |||
143 | await waitJobs(server) | ||
144 | |||
145 | const { total, data } = await server.videos.listByChannel({ handle: 'channel3' }) | ||
146 | |||
147 | expect(total).to.equal(1) | ||
148 | expect(data).to.have.lengthOf(1) | ||
149 | }) | ||
150 | |||
112 | after(async function () { | 151 | after(async function () { |
113 | await server?.kill() | 152 | await server?.kill() |
114 | }) | 153 | }) |
@@ -116,5 +155,7 @@ describe('Test videos import in a channel', function () { | |||
116 | } | 155 | } |
117 | 156 | ||
118 | runSuite('yt-dlp') | 157 | runSuite('yt-dlp') |
119 | runSuite('youtube-dl') | 158 | |
159 | // FIXME: With recent changes on youtube, youtube-dl doesn't fetch live replays which means the test suite fails | ||
160 | // runSuite('youtube-dl') | ||
120 | }) | 161 | }) |
diff --git a/server/tests/api/videos/index.ts b/server/tests/api/videos/index.ts index 266155297..357c08199 100644 --- a/server/tests/api/videos/index.ts +++ b/server/tests/api/videos/index.ts | |||
@@ -19,3 +19,4 @@ import './videos-common-filters' | |||
19 | import './videos-history' | 19 | import './videos-history' |
20 | import './videos-overview' | 20 | import './videos-overview' |
21 | import './video-source' | 21 | import './video-source' |
22 | import './video-static-file-privacy' | ||
diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts index d47807a79..2ad749fd4 100644 --- a/server/tests/api/videos/multiple-servers.ts +++ b/server/tests/api/videos/multiple-servers.ts | |||
@@ -156,7 +156,7 @@ describe('Test multiple servers', function () { | |||
156 | }) | 156 | }) |
157 | 157 | ||
158 | it('Should upload the video on server 2 and propagate on each server', async function () { | 158 | it('Should upload the video on server 2 and propagate on each server', async function () { |
159 | this.timeout(100000) | 159 | this.timeout(240000) |
160 | 160 | ||
161 | const user = { | 161 | const user = { |
162 | username: 'user1', | 162 | username: 'user1', |
diff --git a/server/tests/api/videos/video-channel-syncs.ts b/server/tests/api/videos/video-channel-syncs.ts index 865b25f04..91291524d 100644 --- a/server/tests/api/videos/video-channel-syncs.ts +++ b/server/tests/api/videos/video-channel-syncs.ts | |||
@@ -220,7 +220,7 @@ describe('Test channel synchronizations', function () { | |||
220 | expect(total).to.equal(0) | 220 | expect(total).to.equal(0) |
221 | }) | 221 | }) |
222 | 222 | ||
223 | // FIXME: youtube-dl doesn't work when speicifying a port after the hostname | 223 | // FIXME: youtube-dl/yt-dlp doesn't work when speicifying a port after the hostname |
224 | // it('Should import a remote PeerTube channel', async function () { | 224 | // it('Should import a remote PeerTube channel', async function () { |
225 | // this.timeout(240_000) | 225 | // this.timeout(240_000) |
226 | 226 | ||
diff --git a/server/tests/api/videos/video-description.ts b/server/tests/api/videos/video-description.ts index a4b3ff6e7..c4185882a 100644 --- a/server/tests/api/videos/video-description.ts +++ b/server/tests/api/videos/video-description.ts | |||
@@ -14,8 +14,12 @@ describe('Test video description', function () { | |||
14 | let servers: PeerTubeServer[] = [] | 14 | let servers: PeerTubeServer[] = [] |
15 | let videoUUID = '' | 15 | let videoUUID = '' |
16 | let videoId: number | 16 | let videoId: number |
17 | |||
17 | const longDescription = 'my super description for server 1'.repeat(50) | 18 | const longDescription = 'my super description for server 1'.repeat(50) |
18 | 19 | ||
20 | // 30 characters * 6 -> 240 characters | ||
21 | const truncatedDescription = 'my super description for server 1'.repeat(7) + 'my super descrip...' | ||
22 | |||
19 | before(async function () { | 23 | before(async function () { |
20 | this.timeout(40000) | 24 | this.timeout(40000) |
21 | 25 | ||
@@ -45,15 +49,22 @@ describe('Test video description', function () { | |||
45 | videoUUID = data[0].uuid | 49 | videoUUID = data[0].uuid |
46 | }) | 50 | }) |
47 | 51 | ||
48 | it('Should have a truncated description on each server', async function () { | 52 | it('Should have a truncated description on each server when listing videos', async function () { |
49 | for (const server of servers) { | 53 | for (const server of servers) { |
50 | const video = await server.videos.get({ id: videoUUID }) | 54 | const { data } = await server.videos.list() |
51 | 55 | const video = data.find(v => v.uuid === videoUUID) | |
52 | // 30 characters * 6 -> 240 characters | ||
53 | const truncatedDescription = 'my super description for server 1'.repeat(7) + | ||
54 | 'my super descrip...' | ||
55 | 56 | ||
56 | expect(video.description).to.equal(truncatedDescription) | 57 | expect(video.description).to.equal(truncatedDescription) |
58 | expect(video.truncatedDescription).to.equal(truncatedDescription) | ||
59 | } | ||
60 | }) | ||
61 | |||
62 | it('Should not have a truncated description on each server when getting videos', async function () { | ||
63 | for (const server of servers) { | ||
64 | const video = await server.videos.get({ id: videoUUID }) | ||
65 | |||
66 | expect(video.description).to.equal(longDescription) | ||
67 | expect(video.truncatedDescription).to.equal(truncatedDescription) | ||
57 | } | 68 | } |
58 | }) | 69 | }) |
59 | 70 | ||
diff --git a/server/tests/api/videos/video-files.ts b/server/tests/api/videos/video-files.ts index 10277b9cf..8c913bf31 100644 --- a/server/tests/api/videos/video-files.ts +++ b/server/tests/api/videos/video-files.ts | |||
@@ -33,7 +33,7 @@ describe('Test videos files', function () { | |||
33 | let validId2: string | 33 | let validId2: string |
34 | 34 | ||
35 | before(async function () { | 35 | before(async function () { |
36 | this.timeout(120_000) | 36 | this.timeout(360_000) |
37 | 37 | ||
38 | { | 38 | { |
39 | const { uuid } = await servers[0].videos.quickUpload({ name: 'video 1' }) | 39 | const { uuid } = await servers[0].videos.quickUpload({ name: 'video 1' }) |
@@ -153,7 +153,7 @@ describe('Test videos files', function () { | |||
153 | expect(video.streamingPlaylists[0].files).to.have.lengthOf(files.length - 1) | 153 | expect(video.streamingPlaylists[0].files).to.have.lengthOf(files.length - 1) |
154 | expect(video.streamingPlaylists[0].files.find(f => f.id === toDelete.id)).to.not.exist | 154 | expect(video.streamingPlaylists[0].files.find(f => f.id === toDelete.id)).to.not.exist |
155 | 155 | ||
156 | const { text } = await makeRawRequest(video.streamingPlaylists[0].playlistUrl) | 156 | const { text } = await makeRawRequest({ url: video.streamingPlaylists[0].playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) |
157 | 157 | ||
158 | expect(text.includes(`-${toDelete.resolution.id}.m3u8`)).to.be.false | 158 | expect(text.includes(`-${toDelete.resolution.id}.m3u8`)).to.be.false |
159 | expect(text.includes(`-${video.streamingPlaylists[0].files[0].resolution.id}.m3u8`)).to.be.true | 159 | expect(text.includes(`-${video.streamingPlaylists[0].files[0].resolution.id}.m3u8`)).to.be.true |
diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts index 47b8c7b1e..a3de73ba5 100644 --- a/server/tests/api/videos/video-playlists.ts +++ b/server/tests/api/videos/video-playlists.ts | |||
@@ -23,6 +23,7 @@ import { | |||
23 | setDefaultVideoChannel, | 23 | setDefaultVideoChannel, |
24 | waitJobs | 24 | waitJobs |
25 | } from '@shared/server-commands' | 25 | } from '@shared/server-commands' |
26 | import { uuidToShort } from '@shared/extra-utils' | ||
26 | 27 | ||
27 | async function checkPlaylistElementType ( | 28 | async function checkPlaylistElementType ( |
28 | servers: PeerTubeServer[], | 29 | servers: PeerTubeServer[], |
@@ -56,6 +57,7 @@ describe('Test video playlists', function () { | |||
56 | let playlistServer2UUID2: string | 57 | let playlistServer2UUID2: string |
57 | 58 | ||
58 | let playlistServer1Id: number | 59 | let playlistServer1Id: number |
60 | let playlistServer1DisplayName: string | ||
59 | let playlistServer1UUID: string | 61 | let playlistServer1UUID: string |
60 | let playlistServer1UUID2: string | 62 | let playlistServer1UUID2: string |
61 | 63 | ||
@@ -70,7 +72,7 @@ describe('Test video playlists', function () { | |||
70 | let commands: PlaylistsCommand[] | 72 | let commands: PlaylistsCommand[] |
71 | 73 | ||
72 | before(async function () { | 74 | before(async function () { |
73 | this.timeout(120000) | 75 | this.timeout(240000) |
74 | 76 | ||
75 | servers = await createMultipleServers(3) | 77 | servers = await createMultipleServers(3) |
76 | 78 | ||
@@ -489,15 +491,17 @@ describe('Test video playlists', function () { | |||
489 | return commands[0].addElement({ playlistId: playlistServer1Id, attributes }) | 491 | return commands[0].addElement({ playlistId: playlistServer1Id, attributes }) |
490 | } | 492 | } |
491 | 493 | ||
494 | const playlistDisplayName = 'playlist 4' | ||
492 | const playlist = await commands[0].create({ | 495 | const playlist = await commands[0].create({ |
493 | attributes: { | 496 | attributes: { |
494 | displayName: 'playlist 4', | 497 | displayName: playlistDisplayName, |
495 | privacy: VideoPlaylistPrivacy.PUBLIC, | 498 | privacy: VideoPlaylistPrivacy.PUBLIC, |
496 | videoChannelId: servers[0].store.channel.id | 499 | videoChannelId: servers[0].store.channel.id |
497 | } | 500 | } |
498 | }) | 501 | }) |
499 | 502 | ||
500 | playlistServer1Id = playlist.id | 503 | playlistServer1Id = playlist.id |
504 | playlistServer1DisplayName = playlistDisplayName | ||
501 | playlistServer1UUID = playlist.uuid | 505 | playlistServer1UUID = playlist.uuid |
502 | 506 | ||
503 | await addVideo({ videoId: servers[0].store.videos[0].uuid, startTimestamp: 15, stopTimestamp: 28 }) | 507 | await addVideo({ videoId: servers[0].store.videos[0].uuid, startTimestamp: 15, stopTimestamp: 28 }) |
@@ -908,6 +912,8 @@ describe('Test video playlists', function () { | |||
908 | const elem = obj[servers[0].store.videos[0].id] | 912 | const elem = obj[servers[0].store.videos[0].id] |
909 | expect(elem).to.have.lengthOf(1) | 913 | expect(elem).to.have.lengthOf(1) |
910 | expect(elem[0].playlistElementId).to.exist | 914 | expect(elem[0].playlistElementId).to.exist |
915 | expect(elem[0].playlistDisplayName).to.equal(playlistServer1DisplayName) | ||
916 | expect(elem[0].playlistShortUUID).to.equal(uuidToShort(playlistServer1UUID)) | ||
911 | expect(elem[0].playlistId).to.equal(playlistServer1Id) | 917 | expect(elem[0].playlistId).to.equal(playlistServer1Id) |
912 | expect(elem[0].startTimestamp).to.equal(15) | 918 | expect(elem[0].startTimestamp).to.equal(15) |
913 | expect(elem[0].stopTimestamp).to.equal(28) | 919 | expect(elem[0].stopTimestamp).to.equal(28) |
@@ -917,6 +923,8 @@ describe('Test video playlists', function () { | |||
917 | const elem = obj[servers[0].store.videos[3].id] | 923 | const elem = obj[servers[0].store.videos[3].id] |
918 | expect(elem).to.have.lengthOf(1) | 924 | expect(elem).to.have.lengthOf(1) |
919 | expect(elem[0].playlistElementId).to.equal(playlistElementServer1Video4) | 925 | expect(elem[0].playlistElementId).to.equal(playlistElementServer1Video4) |
926 | expect(elem[0].playlistDisplayName).to.equal(playlistServer1DisplayName) | ||
927 | expect(elem[0].playlistShortUUID).to.equal(uuidToShort(playlistServer1UUID)) | ||
920 | expect(elem[0].playlistId).to.equal(playlistServer1Id) | 928 | expect(elem[0].playlistId).to.equal(playlistServer1Id) |
921 | expect(elem[0].startTimestamp).to.equal(1) | 929 | expect(elem[0].startTimestamp).to.equal(1) |
922 | expect(elem[0].stopTimestamp).to.equal(35) | 930 | expect(elem[0].stopTimestamp).to.equal(35) |
@@ -926,6 +934,8 @@ describe('Test video playlists', function () { | |||
926 | const elem = obj[servers[0].store.videos[4].id] | 934 | const elem = obj[servers[0].store.videos[4].id] |
927 | expect(elem).to.have.lengthOf(1) | 935 | expect(elem).to.have.lengthOf(1) |
928 | expect(elem[0].playlistId).to.equal(playlistServer1Id) | 936 | expect(elem[0].playlistId).to.equal(playlistServer1Id) |
937 | expect(elem[0].playlistDisplayName).to.equal(playlistServer1DisplayName) | ||
938 | expect(elem[0].playlistShortUUID).to.equal(uuidToShort(playlistServer1UUID)) | ||
929 | expect(elem[0].startTimestamp).to.equal(45) | 939 | expect(elem[0].startTimestamp).to.equal(45) |
930 | expect(elem[0].stopTimestamp).to.equal(null) | 940 | expect(elem[0].stopTimestamp).to.equal(null) |
931 | } | 941 | } |
@@ -1049,7 +1059,7 @@ describe('Test video playlists', function () { | |||
1049 | this.timeout(30000) | 1059 | this.timeout(30000) |
1050 | 1060 | ||
1051 | for (const server of servers) { | 1061 | for (const server of servers) { |
1052 | await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.internalServerNumber) | 1062 | await checkPlaylistFilesWereRemoved(playlistServer1UUID, server) |
1053 | } | 1063 | } |
1054 | }) | 1064 | }) |
1055 | 1065 | ||
diff --git a/server/tests/api/videos/video-privacy.ts b/server/tests/api/videos/video-privacy.ts index b18c71c94..264a05d3f 100644 --- a/server/tests/api/videos/video-privacy.ts +++ b/server/tests/api/videos/video-privacy.ts | |||
@@ -45,7 +45,7 @@ describe('Test video privacy', function () { | |||
45 | describe('Private and internal videos', function () { | 45 | describe('Private and internal videos', function () { |
46 | 46 | ||
47 | it('Should upload a private and internal videos on server 1', async function () { | 47 | it('Should upload a private and internal videos on server 1', async function () { |
48 | this.timeout(10000) | 48 | this.timeout(50000) |
49 | 49 | ||
50 | for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) { | 50 | for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) { |
51 | const attributes = { privacy } | 51 | const attributes = { privacy } |
@@ -128,7 +128,7 @@ describe('Test video privacy', function () { | |||
128 | describe('Unlisted videos', function () { | 128 | describe('Unlisted videos', function () { |
129 | 129 | ||
130 | it('Should upload an unlisted video on server 2', async function () { | 130 | it('Should upload an unlisted video on server 2', async function () { |
131 | this.timeout(60000) | 131 | this.timeout(120000) |
132 | 132 | ||
133 | const attributes = { | 133 | const attributes = { |
134 | name: 'unlisted video', | 134 | name: 'unlisted video', |
diff --git a/server/tests/api/videos/video-static-file-privacy.ts b/server/tests/api/videos/video-static-file-privacy.ts new file mode 100644 index 000000000..eaaed5aad --- /dev/null +++ b/server/tests/api/videos/video-static-file-privacy.ts | |||
@@ -0,0 +1,422 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { decode } from 'magnet-uri' | ||
5 | import { expectStartWith } from '@server/tests/shared' | ||
6 | import { getAllFiles, wait } from '@shared/core-utils' | ||
7 | import { HttpStatusCode, LiveVideo, VideoDetails, VideoPrivacy } from '@shared/models' | ||
8 | import { | ||
9 | cleanupTests, | ||
10 | createSingleServer, | ||
11 | findExternalSavedVideo, | ||
12 | makeRawRequest, | ||
13 | parseTorrentVideo, | ||
14 | PeerTubeServer, | ||
15 | sendRTMPStream, | ||
16 | setAccessTokensToServers, | ||
17 | setDefaultVideoChannel, | ||
18 | stopFfmpeg, | ||
19 | waitJobs | ||
20 | } from '@shared/server-commands' | ||
21 | |||
22 | describe('Test video static file privacy', function () { | ||
23 | let server: PeerTubeServer | ||
24 | let userToken: string | ||
25 | |||
26 | before(async function () { | ||
27 | this.timeout(50000) | ||
28 | |||
29 | server = await createSingleServer(1) | ||
30 | await setAccessTokensToServers([ server ]) | ||
31 | await setDefaultVideoChannel([ server ]) | ||
32 | |||
33 | userToken = await server.users.generateUserAndToken('user1') | ||
34 | }) | ||
35 | |||
36 | describe('VOD static file path', function () { | ||
37 | |||
38 | function runSuite () { | ||
39 | |||
40 | async function checkPrivateFiles (uuid: string) { | ||
41 | const video = await server.videos.getWithToken({ id: uuid }) | ||
42 | |||
43 | for (const file of video.files) { | ||
44 | expect(file.fileDownloadUrl).to.not.include('/private/') | ||
45 | expectStartWith(file.fileUrl, server.url + '/static/webseed/private/') | ||
46 | |||
47 | const torrent = await parseTorrentVideo(server, file) | ||
48 | expect(torrent.urlList).to.have.lengthOf(0) | ||
49 | |||
50 | const magnet = decode(file.magnetUri) | ||
51 | expect(magnet.urlList).to.have.lengthOf(0) | ||
52 | |||
53 | await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
54 | } | ||
55 | |||
56 | const hls = video.streamingPlaylists[0] | ||
57 | if (hls) { | ||
58 | expectStartWith(hls.playlistUrl, server.url + '/static/streaming-playlists/hls/private/') | ||
59 | expectStartWith(hls.segmentsSha256Url, server.url + '/static/streaming-playlists/hls/private/') | ||
60 | |||
61 | await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
62 | await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
63 | } | ||
64 | } | ||
65 | |||
66 | async function checkPublicFiles (uuid: string) { | ||
67 | const video = await server.videos.get({ id: uuid }) | ||
68 | |||
69 | for (const file of getAllFiles(video)) { | ||
70 | expect(file.fileDownloadUrl).to.not.include('/private/') | ||
71 | expect(file.fileUrl).to.not.include('/private/') | ||
72 | |||
73 | const torrent = await parseTorrentVideo(server, file) | ||
74 | expect(torrent.urlList[0]).to.not.include('private') | ||
75 | |||
76 | const magnet = decode(file.magnetUri) | ||
77 | expect(magnet.urlList[0]).to.not.include('private') | ||
78 | |||
79 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
80 | await makeRawRequest({ url: torrent.urlList[0], expectedStatus: HttpStatusCode.OK_200 }) | ||
81 | await makeRawRequest({ url: magnet.urlList[0], expectedStatus: HttpStatusCode.OK_200 }) | ||
82 | } | ||
83 | |||
84 | const hls = video.streamingPlaylists[0] | ||
85 | if (hls) { | ||
86 | expect(hls.playlistUrl).to.not.include('private') | ||
87 | expect(hls.segmentsSha256Url).to.not.include('private') | ||
88 | |||
89 | await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
90 | await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) | ||
91 | } | ||
92 | } | ||
93 | |||
94 | it('Should upload a private/internal video and have a private static path', async function () { | ||
95 | this.timeout(120000) | ||
96 | |||
97 | for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) { | ||
98 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy }) | ||
99 | await waitJobs([ server ]) | ||
100 | |||
101 | await checkPrivateFiles(uuid) | ||
102 | } | ||
103 | }) | ||
104 | |||
105 | it('Should upload a public video and update it as private/internal to have a private static path', async function () { | ||
106 | this.timeout(120000) | ||
107 | |||
108 | for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) { | ||
109 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PUBLIC }) | ||
110 | await waitJobs([ server ]) | ||
111 | |||
112 | await server.videos.update({ id: uuid, attributes: { privacy } }) | ||
113 | await waitJobs([ server ]) | ||
114 | |||
115 | await checkPrivateFiles(uuid) | ||
116 | } | ||
117 | }) | ||
118 | |||
119 | it('Should upload a private video and update it to unlisted to have a public static path', async function () { | ||
120 | this.timeout(120000) | ||
121 | |||
122 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) | ||
123 | await waitJobs([ server ]) | ||
124 | |||
125 | await server.videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.UNLISTED } }) | ||
126 | await waitJobs([ server ]) | ||
127 | |||
128 | await checkPublicFiles(uuid) | ||
129 | }) | ||
130 | |||
131 | it('Should upload an internal video and update it to public to have a public static path', async function () { | ||
132 | this.timeout(120000) | ||
133 | |||
134 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.INTERNAL }) | ||
135 | await waitJobs([ server ]) | ||
136 | |||
137 | await server.videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) | ||
138 | await waitJobs([ server ]) | ||
139 | |||
140 | await checkPublicFiles(uuid) | ||
141 | }) | ||
142 | |||
143 | it('Should upload an internal video and schedule a public publish', async function () { | ||
144 | this.timeout(120000) | ||
145 | |||
146 | const attributes = { | ||
147 | name: 'video', | ||
148 | privacy: VideoPrivacy.PRIVATE, | ||
149 | scheduleUpdate: { | ||
150 | updateAt: new Date(Date.now() + 1000).toISOString(), | ||
151 | privacy: VideoPrivacy.PUBLIC as VideoPrivacy.PUBLIC | ||
152 | } | ||
153 | } | ||
154 | |||
155 | const { uuid } = await server.videos.upload({ attributes }) | ||
156 | |||
157 | await waitJobs([ server ]) | ||
158 | await wait(1000) | ||
159 | await server.debug.sendCommand({ body: { command: 'process-update-videos-scheduler' } }) | ||
160 | |||
161 | await waitJobs([ server ]) | ||
162 | |||
163 | await checkPublicFiles(uuid) | ||
164 | }) | ||
165 | } | ||
166 | |||
167 | describe('Without transcoding', function () { | ||
168 | runSuite() | ||
169 | }) | ||
170 | |||
171 | describe('With transcoding', function () { | ||
172 | |||
173 | before(async function () { | ||
174 | await server.config.enableMinimumTranscoding() | ||
175 | }) | ||
176 | |||
177 | runSuite() | ||
178 | }) | ||
179 | }) | ||
180 | |||
181 | describe('VOD static file right check', function () { | ||
182 | let unrelatedFileToken: string | ||
183 | |||
184 | async function checkVideoFiles (options: { | ||
185 | id: string | ||
186 | expectedStatus: HttpStatusCode | ||
187 | token: string | ||
188 | videoFileToken: string | ||
189 | }) { | ||
190 | const { id, expectedStatus, token, videoFileToken } = options | ||
191 | |||
192 | const video = await server.videos.getWithToken({ id }) | ||
193 | |||
194 | for (const file of getAllFiles(video)) { | ||
195 | await makeRawRequest({ url: file.fileUrl, token, expectedStatus }) | ||
196 | await makeRawRequest({ url: file.fileDownloadUrl, token, expectedStatus }) | ||
197 | |||
198 | await makeRawRequest({ url: file.fileUrl, query: { videoFileToken }, expectedStatus }) | ||
199 | await makeRawRequest({ url: file.fileDownloadUrl, query: { videoFileToken }, expectedStatus }) | ||
200 | } | ||
201 | |||
202 | const hls = video.streamingPlaylists[0] | ||
203 | await makeRawRequest({ url: hls.playlistUrl, token, expectedStatus }) | ||
204 | await makeRawRequest({ url: hls.segmentsSha256Url, token, expectedStatus }) | ||
205 | |||
206 | await makeRawRequest({ url: hls.playlistUrl, query: { videoFileToken }, expectedStatus }) | ||
207 | await makeRawRequest({ url: hls.segmentsSha256Url, query: { videoFileToken }, expectedStatus }) | ||
208 | } | ||
209 | |||
210 | before(async function () { | ||
211 | await server.config.enableMinimumTranscoding() | ||
212 | |||
213 | const { uuid } = await server.videos.quickUpload({ name: 'another video' }) | ||
214 | unrelatedFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) | ||
215 | }) | ||
216 | |||
217 | it('Should not be able to access a private video files without OAuth token and file token', async function () { | ||
218 | this.timeout(120000) | ||
219 | |||
220 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.INTERNAL }) | ||
221 | await waitJobs([ server ]) | ||
222 | |||
223 | await checkVideoFiles({ id: uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403, token: null, videoFileToken: null }) | ||
224 | }) | ||
225 | |||
226 | it('Should not be able to access an internal video files without appropriate OAuth token and file token', async function () { | ||
227 | this.timeout(120000) | ||
228 | |||
229 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) | ||
230 | await waitJobs([ server ]) | ||
231 | |||
232 | await checkVideoFiles({ | ||
233 | id: uuid, | ||
234 | expectedStatus: HttpStatusCode.FORBIDDEN_403, | ||
235 | token: userToken, | ||
236 | videoFileToken: unrelatedFileToken | ||
237 | }) | ||
238 | }) | ||
239 | |||
240 | it('Should be able to access a private video files with appropriate OAuth token or file token', async function () { | ||
241 | this.timeout(120000) | ||
242 | |||
243 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) | ||
244 | const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) | ||
245 | |||
246 | await waitJobs([ server ]) | ||
247 | |||
248 | await checkVideoFiles({ id: uuid, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken, videoFileToken }) | ||
249 | }) | ||
250 | |||
251 | it('Should be able to access a private video of another user with an admin OAuth token or file token', async function () { | ||
252 | this.timeout(120000) | ||
253 | |||
254 | const { uuid } = await server.videos.quickUpload({ name: 'video', token: userToken, privacy: VideoPrivacy.PRIVATE }) | ||
255 | const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) | ||
256 | |||
257 | await waitJobs([ server ]) | ||
258 | |||
259 | await checkVideoFiles({ id: uuid, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken, videoFileToken }) | ||
260 | }) | ||
261 | }) | ||
262 | |||
263 | describe('Live static file path and check', function () { | ||
264 | let normalLiveId: string | ||
265 | let normalLive: LiveVideo | ||
266 | |||
267 | let permanentLiveId: string | ||
268 | let permanentLive: LiveVideo | ||
269 | |||
270 | let unrelatedFileToken: string | ||
271 | |||
272 | async function checkLiveFiles (live: LiveVideo, liveId: string) { | ||
273 | const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) | ||
274 | await server.live.waitUntilPublished({ videoId: liveId }) | ||
275 | |||
276 | const video = await server.videos.getWithToken({ id: liveId }) | ||
277 | const fileToken = await server.videoToken.getVideoFileToken({ videoId: video.uuid }) | ||
278 | |||
279 | const hls = video.streamingPlaylists[0] | ||
280 | |||
281 | for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { | ||
282 | expectStartWith(url, server.url + '/static/streaming-playlists/hls/private/') | ||
283 | |||
284 | await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
285 | await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) | ||
286 | |||
287 | await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
288 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
289 | await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
290 | } | ||
291 | |||
292 | await stopFfmpeg(ffmpegCommand) | ||
293 | } | ||
294 | |||
295 | async function checkReplay (replay: VideoDetails) { | ||
296 | const fileToken = await server.videoToken.getVideoFileToken({ videoId: replay.uuid }) | ||
297 | |||
298 | const hls = replay.streamingPlaylists[0] | ||
299 | expect(hls.files).to.not.have.lengthOf(0) | ||
300 | |||
301 | for (const file of hls.files) { | ||
302 | await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
303 | await makeRawRequest({ url: file.fileUrl, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) | ||
304 | |||
305 | await makeRawRequest({ url: file.fileUrl, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
306 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
307 | await makeRawRequest({ | ||
308 | url: file.fileUrl, | ||
309 | query: { videoFileToken: unrelatedFileToken }, | ||
310 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
311 | }) | ||
312 | } | ||
313 | |||
314 | for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { | ||
315 | expectStartWith(url, server.url + '/static/streaming-playlists/hls/private/') | ||
316 | |||
317 | await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
318 | await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) | ||
319 | |||
320 | await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
321 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
322 | await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
323 | } | ||
324 | } | ||
325 | |||
326 | before(async function () { | ||
327 | await server.config.enableMinimumTranscoding() | ||
328 | |||
329 | const { uuid } = await server.videos.quickUpload({ name: 'another video' }) | ||
330 | unrelatedFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) | ||
331 | |||
332 | await server.config.enableLive({ | ||
333 | allowReplay: true, | ||
334 | transcoding: true, | ||
335 | resolutions: 'min' | ||
336 | }) | ||
337 | |||
338 | { | ||
339 | const { video, live } = await server.live.quickCreate({ saveReplay: true, permanentLive: false, privacy: VideoPrivacy.PRIVATE }) | ||
340 | normalLiveId = video.uuid | ||
341 | normalLive = live | ||
342 | } | ||
343 | |||
344 | { | ||
345 | const { video, live } = await server.live.quickCreate({ saveReplay: true, permanentLive: true, privacy: VideoPrivacy.PRIVATE }) | ||
346 | permanentLiveId = video.uuid | ||
347 | permanentLive = live | ||
348 | } | ||
349 | }) | ||
350 | |||
351 | it('Should create a private normal live and have a private static path', async function () { | ||
352 | this.timeout(240000) | ||
353 | |||
354 | await checkLiveFiles(normalLive, normalLiveId) | ||
355 | }) | ||
356 | |||
357 | it('Should create a private permanent live and have a private static path', async function () { | ||
358 | this.timeout(240000) | ||
359 | |||
360 | await checkLiveFiles(permanentLive, permanentLiveId) | ||
361 | }) | ||
362 | |||
363 | it('Should have created a replay of the normal live with a private static path', async function () { | ||
364 | this.timeout(240000) | ||
365 | |||
366 | await server.live.waitUntilReplacedByReplay({ videoId: normalLiveId }) | ||
367 | |||
368 | const replay = await server.videos.getWithToken({ id: normalLiveId }) | ||
369 | await checkReplay(replay) | ||
370 | }) | ||
371 | |||
372 | it('Should have created a replay of the permanent live with a private static path', async function () { | ||
373 | this.timeout(240000) | ||
374 | |||
375 | await server.live.waitUntilWaiting({ videoId: permanentLiveId }) | ||
376 | await waitJobs([ server ]) | ||
377 | |||
378 | const live = await server.videos.getWithToken({ id: permanentLiveId }) | ||
379 | const replayFromList = await findExternalSavedVideo(server, live) | ||
380 | const replay = await server.videos.getWithToken({ id: replayFromList.id }) | ||
381 | |||
382 | await checkReplay(replay) | ||
383 | }) | ||
384 | }) | ||
385 | |||
386 | describe('With static file right check disabled', function () { | ||
387 | let videoUUID: string | ||
388 | |||
389 | before(async function () { | ||
390 | this.timeout(240000) | ||
391 | |||
392 | await server.kill() | ||
393 | |||
394 | await server.run({ | ||
395 | static_files: { | ||
396 | private_files_require_auth: false | ||
397 | } | ||
398 | }) | ||
399 | |||
400 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.INTERNAL }) | ||
401 | videoUUID = uuid | ||
402 | |||
403 | await waitJobs([ server ]) | ||
404 | }) | ||
405 | |||
406 | it('Should not check auth for private static files', async function () { | ||
407 | const video = await server.videos.getWithToken({ id: videoUUID }) | ||
408 | |||
409 | for (const file of getAllFiles(video)) { | ||
410 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
411 | } | ||
412 | |||
413 | const hls = video.streamingPlaylists[0] | ||
414 | await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
415 | await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) | ||
416 | }) | ||
417 | }) | ||
418 | |||
419 | after(async function () { | ||
420 | await cleanupTests([ server ]) | ||
421 | }) | ||
422 | }) | ||
diff --git a/server/tests/api/videos/videos-common-filters.ts b/server/tests/api/videos/videos-common-filters.ts index e7fc15e42..b176d90ab 100644 --- a/server/tests/api/videos/videos-common-filters.ts +++ b/server/tests/api/videos/videos-common-filters.ts | |||
@@ -232,7 +232,7 @@ describe('Test videos filter', function () { | |||
232 | }) | 232 | }) |
233 | 233 | ||
234 | it('Should display only remote videos', async function () { | 234 | it('Should display only remote videos', async function () { |
235 | this.timeout(40000) | 235 | this.timeout(120000) |
236 | 236 | ||
237 | await servers[1].videos.upload({ attributes: { name: 'remote video' } }) | 237 | await servers[1].videos.upload({ attributes: { name: 'remote video' } }) |
238 | 238 | ||
diff --git a/server/tests/cli/create-import-video-file-job.ts b/server/tests/cli/create-import-video-file-job.ts index 2cf2dd8f8..43f53035b 100644 --- a/server/tests/cli/create-import-video-file-job.ts +++ b/server/tests/cli/create-import-video-file-job.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 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | 4 | import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' |
5 | import { HttpStatusCode, VideoDetails, VideoFile, VideoInclude } from '@shared/models' | 5 | import { HttpStatusCode, VideoDetails, VideoFile, VideoInclude } from '@shared/models' |
6 | import { | 6 | import { |
7 | cleanupTests, | 7 | cleanupTests, |
@@ -27,9 +27,9 @@ function assertVideoProperties (video: VideoFile, resolution: number, extname: s | |||
27 | 27 | ||
28 | async function checkFiles (video: VideoDetails, objectStorage: boolean) { | 28 | async function checkFiles (video: VideoDetails, objectStorage: boolean) { |
29 | for (const file of video.files) { | 29 | for (const file of video.files) { |
30 | if (objectStorage) expectStartWith(file.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) | 30 | if (objectStorage) expectStartWith(file.fileUrl, ObjectStorageCommand.getMockWebTorrentBaseUrl()) |
31 | 31 | ||
32 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 32 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
33 | } | 33 | } |
34 | } | 34 | } |
35 | 35 | ||
@@ -43,7 +43,7 @@ function runTests (objectStorage: boolean) { | |||
43 | this.timeout(90000) | 43 | this.timeout(90000) |
44 | 44 | ||
45 | const config = objectStorage | 45 | const config = objectStorage |
46 | ? ObjectStorageCommand.getDefaultConfig() | 46 | ? ObjectStorageCommand.getDefaultMockConfig() |
47 | : {} | 47 | : {} |
48 | 48 | ||
49 | // Run server 2 to have transcoding enabled | 49 | // Run server 2 to have transcoding enabled |
@@ -52,7 +52,7 @@ function runTests (objectStorage: boolean) { | |||
52 | 52 | ||
53 | await doubleFollow(servers[0], servers[1]) | 53 | await doubleFollow(servers[0], servers[1]) |
54 | 54 | ||
55 | if (objectStorage) await ObjectStorageCommand.prepareDefaultBuckets() | 55 | if (objectStorage) await ObjectStorageCommand.prepareDefaultMockBuckets() |
56 | 56 | ||
57 | // Upload two videos for our needs | 57 | // Upload two videos for our needs |
58 | { | 58 | { |
@@ -157,7 +157,7 @@ describe('Test create import video jobs', function () { | |||
157 | }) | 157 | }) |
158 | 158 | ||
159 | describe('On object storage', function () { | 159 | describe('On object storage', function () { |
160 | if (areObjectStorageTestsDisabled()) return | 160 | if (areMockObjectStorageTestsDisabled()) return |
161 | 161 | ||
162 | runTests(true) | 162 | runTests(true) |
163 | }) | 163 | }) |
diff --git a/server/tests/cli/create-move-video-storage-job.ts b/server/tests/cli/create-move-video-storage-job.ts index 6a12a2c6c..c357f501b 100644 --- a/server/tests/cli/create-move-video-storage-job.ts +++ b/server/tests/cli/create-move-video-storage-job.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | 3 | import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' |
4 | import { HttpStatusCode, VideoDetails } from '@shared/models' | 4 | import { HttpStatusCode, VideoDetails } from '@shared/models' |
5 | import { | 5 | import { |
6 | cleanupTests, | 6 | cleanupTests, |
@@ -17,16 +17,16 @@ import { expectStartWith } from '../shared' | |||
17 | async function checkFiles (origin: PeerTubeServer, video: VideoDetails, inObjectStorage: boolean) { | 17 | async function checkFiles (origin: PeerTubeServer, video: VideoDetails, inObjectStorage: boolean) { |
18 | for (const file of video.files) { | 18 | for (const file of video.files) { |
19 | const start = inObjectStorage | 19 | const start = inObjectStorage |
20 | ? ObjectStorageCommand.getWebTorrentBaseUrl() | 20 | ? ObjectStorageCommand.getMockWebTorrentBaseUrl() |
21 | : origin.url | 21 | : origin.url |
22 | 22 | ||
23 | expectStartWith(file.fileUrl, start) | 23 | expectStartWith(file.fileUrl, start) |
24 | 24 | ||
25 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 25 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
26 | } | 26 | } |
27 | 27 | ||
28 | const start = inObjectStorage | 28 | const start = inObjectStorage |
29 | ? ObjectStorageCommand.getPlaylistBaseUrl() | 29 | ? ObjectStorageCommand.getMockPlaylistBaseUrl() |
30 | : origin.url | 30 | : origin.url |
31 | 31 | ||
32 | const hls = video.streamingPlaylists[0] | 32 | const hls = video.streamingPlaylists[0] |
@@ -36,12 +36,12 @@ async function checkFiles (origin: PeerTubeServer, video: VideoDetails, inObject | |||
36 | for (const file of hls.files) { | 36 | for (const file of hls.files) { |
37 | expectStartWith(file.fileUrl, start) | 37 | expectStartWith(file.fileUrl, start) |
38 | 38 | ||
39 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 39 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
40 | } | 40 | } |
41 | } | 41 | } |
42 | 42 | ||
43 | describe('Test create move video storage job', function () { | 43 | describe('Test create move video storage job', function () { |
44 | if (areObjectStorageTestsDisabled()) return | 44 | if (areMockObjectStorageTestsDisabled()) return |
45 | 45 | ||
46 | let servers: PeerTubeServer[] = [] | 46 | let servers: PeerTubeServer[] = [] |
47 | const uuids: string[] = [] | 47 | const uuids: string[] = [] |
@@ -55,7 +55,7 @@ describe('Test create move video storage job', function () { | |||
55 | 55 | ||
56 | await doubleFollow(servers[0], servers[1]) | 56 | await doubleFollow(servers[0], servers[1]) |
57 | 57 | ||
58 | await ObjectStorageCommand.prepareDefaultBuckets() | 58 | await ObjectStorageCommand.prepareDefaultMockBuckets() |
59 | 59 | ||
60 | await servers[0].config.enableTranscoding() | 60 | await servers[0].config.enableTranscoding() |
61 | 61 | ||
@@ -67,14 +67,14 @@ describe('Test create move video storage job', function () { | |||
67 | await waitJobs(servers) | 67 | await waitJobs(servers) |
68 | 68 | ||
69 | await servers[0].kill() | 69 | await servers[0].kill() |
70 | await servers[0].run(ObjectStorageCommand.getDefaultConfig()) | 70 | await servers[0].run(ObjectStorageCommand.getDefaultMockConfig()) |
71 | }) | 71 | }) |
72 | 72 | ||
73 | it('Should move only one file', async function () { | 73 | it('Should move only one file', async function () { |
74 | this.timeout(120000) | 74 | this.timeout(120000) |
75 | 75 | ||
76 | const command = `npm run create-move-video-storage-job -- --to-object-storage -v ${uuids[1]}` | 76 | const command = `npm run create-move-video-storage-job -- --to-object-storage -v ${uuids[1]}` |
77 | await servers[0].cli.execWithEnv(command, ObjectStorageCommand.getDefaultConfig()) | 77 | await servers[0].cli.execWithEnv(command, ObjectStorageCommand.getDefaultMockConfig()) |
78 | await waitJobs(servers) | 78 | await waitJobs(servers) |
79 | 79 | ||
80 | for (const server of servers) { | 80 | for (const server of servers) { |
@@ -94,7 +94,7 @@ describe('Test create move video storage job', function () { | |||
94 | this.timeout(120000) | 94 | this.timeout(120000) |
95 | 95 | ||
96 | const command = `npm run create-move-video-storage-job -- --to-object-storage --all-videos` | 96 | const command = `npm run create-move-video-storage-job -- --to-object-storage --all-videos` |
97 | await servers[0].cli.execWithEnv(command, ObjectStorageCommand.getDefaultConfig()) | 97 | await servers[0].cli.execWithEnv(command, ObjectStorageCommand.getDefaultMockConfig()) |
98 | await waitJobs(servers) | 98 | await waitJobs(servers) |
99 | 99 | ||
100 | for (const server of servers) { | 100 | for (const server of servers) { |
diff --git a/server/tests/cli/create-transcoding-job.ts b/server/tests/cli/create-transcoding-job.ts index 8897d8c23..38b737829 100644 --- a/server/tests/cli/create-transcoding-job.ts +++ b/server/tests/cli/create-transcoding-job.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 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | 4 | import { areMockObjectStorageTestsDisabled } from '@shared/core-utils' |
5 | import { HttpStatusCode, VideoFile } from '@shared/models' | 5 | import { HttpStatusCode, VideoFile } from '@shared/models' |
6 | import { | 6 | import { |
7 | cleanupTests, | 7 | cleanupTests, |
@@ -18,12 +18,12 @@ import { checkResolutionsInMasterPlaylist, expectStartWith } from '../shared' | |||
18 | async function checkFilesInObjectStorage (files: VideoFile[], type: 'webtorrent' | 'playlist') { | 18 | async function checkFilesInObjectStorage (files: VideoFile[], type: 'webtorrent' | 'playlist') { |
19 | for (const file of files) { | 19 | for (const file of files) { |
20 | const shouldStartWith = type === 'webtorrent' | 20 | const shouldStartWith = type === 'webtorrent' |
21 | ? ObjectStorageCommand.getWebTorrentBaseUrl() | 21 | ? ObjectStorageCommand.getMockWebTorrentBaseUrl() |
22 | : ObjectStorageCommand.getPlaylistBaseUrl() | 22 | : ObjectStorageCommand.getMockPlaylistBaseUrl() |
23 | 23 | ||
24 | expectStartWith(file.fileUrl, shouldStartWith) | 24 | expectStartWith(file.fileUrl, shouldStartWith) |
25 | 25 | ||
26 | await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) | 26 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
27 | } | 27 | } |
28 | } | 28 | } |
29 | 29 | ||
@@ -36,7 +36,7 @@ function runTests (objectStorage: boolean) { | |||
36 | this.timeout(120000) | 36 | this.timeout(120000) |
37 | 37 | ||
38 | const config = objectStorage | 38 | const config = objectStorage |
39 | ? ObjectStorageCommand.getDefaultConfig() | 39 | ? ObjectStorageCommand.getDefaultMockConfig() |
40 | : {} | 40 | : {} |
41 | 41 | ||
42 | // Run server 2 to have transcoding enabled | 42 | // Run server 2 to have transcoding enabled |
@@ -47,7 +47,7 @@ function runTests (objectStorage: boolean) { | |||
47 | 47 | ||
48 | await doubleFollow(servers[0], servers[1]) | 48 | await doubleFollow(servers[0], servers[1]) |
49 | 49 | ||
50 | if (objectStorage) await ObjectStorageCommand.prepareDefaultBuckets() | 50 | if (objectStorage) await ObjectStorageCommand.prepareDefaultMockBuckets() |
51 | 51 | ||
52 | for (let i = 1; i <= 5; i++) { | 52 | for (let i = 1; i <= 5; i++) { |
53 | const { uuid, shortUUID } = await servers[0].videos.upload({ attributes: { name: 'video' + i } }) | 53 | const { uuid, shortUUID } = await servers[0].videos.upload({ attributes: { name: 'video' + i } }) |
@@ -255,7 +255,7 @@ describe('Test create transcoding jobs', function () { | |||
255 | }) | 255 | }) |
256 | 256 | ||
257 | describe('On object storage', function () { | 257 | describe('On object storage', function () { |
258 | if (areObjectStorageTestsDisabled()) return | 258 | if (areMockObjectStorageTestsDisabled()) return |
259 | 259 | ||
260 | runTests(true) | 260 | runTests(true) |
261 | }) | 261 | }) |
diff --git a/server/tests/cli/prune-storage.ts b/server/tests/cli/prune-storage.ts index a89e17e3c..ba0fa1f86 100644 --- a/server/tests/cli/prune-storage.ts +++ b/server/tests/cli/prune-storage.ts | |||
@@ -5,7 +5,7 @@ import { createFile, readdir } from 'fs-extra' | |||
5 | import { join } from 'path' | 5 | import { join } from 'path' |
6 | import { wait } from '@shared/core-utils' | 6 | import { wait } from '@shared/core-utils' |
7 | import { buildUUID } from '@shared/extra-utils' | 7 | import { buildUUID } from '@shared/extra-utils' |
8 | import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' | 8 | import { HttpStatusCode, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' |
9 | import { | 9 | import { |
10 | cleanupTests, | 10 | cleanupTests, |
11 | CLICommand, | 11 | CLICommand, |
@@ -36,22 +36,28 @@ async function assertNotExists (server: PeerTubeServer, directory: string, subst | |||
36 | async function assertCountAreOkay (servers: PeerTubeServer[]) { | 36 | async function assertCountAreOkay (servers: PeerTubeServer[]) { |
37 | for (const server of servers) { | 37 | for (const server of servers) { |
38 | const videosCount = await countFiles(server, 'videos') | 38 | const videosCount = await countFiles(server, 'videos') |
39 | expect(videosCount).to.equal(8) | 39 | expect(videosCount).to.equal(9) // 2 videos with 4 resolutions + private directory |
40 | |||
41 | const privateVideosCount = await countFiles(server, 'videos/private') | ||
42 | expect(privateVideosCount).to.equal(4) | ||
40 | 43 | ||
41 | const torrentsCount = await countFiles(server, 'torrents') | 44 | const torrentsCount = await countFiles(server, 'torrents') |
42 | expect(torrentsCount).to.equal(16) | 45 | expect(torrentsCount).to.equal(24) |
43 | 46 | ||
44 | const previewsCount = await countFiles(server, 'previews') | 47 | const previewsCount = await countFiles(server, 'previews') |
45 | expect(previewsCount).to.equal(2) | 48 | expect(previewsCount).to.equal(3) |
46 | 49 | ||
47 | const thumbnailsCount = await countFiles(server, 'thumbnails') | 50 | const thumbnailsCount = await countFiles(server, 'thumbnails') |
48 | expect(thumbnailsCount).to.equal(6) | 51 | expect(thumbnailsCount).to.equal(7) // 3 local videos, 1 local playlist, 2 remotes videos and 1 remote playlist |
49 | 52 | ||
50 | const avatarsCount = await countFiles(server, 'avatars') | 53 | const avatarsCount = await countFiles(server, 'avatars') |
51 | expect(avatarsCount).to.equal(4) | 54 | expect(avatarsCount).to.equal(4) |
52 | 55 | ||
53 | const hlsRootCount = await countFiles(server, 'streaming-playlists/hls') | 56 | const hlsRootCount = await countFiles(server, join('streaming-playlists', 'hls')) |
54 | expect(hlsRootCount).to.equal(2) | 57 | expect(hlsRootCount).to.equal(3) // 2 videos + private directory |
58 | |||
59 | const hlsPrivateRootCount = await countFiles(server, join('streaming-playlists', 'hls', 'private')) | ||
60 | expect(hlsPrivateRootCount).to.equal(1) | ||
55 | } | 61 | } |
56 | } | 62 | } |
57 | 63 | ||
@@ -67,8 +73,10 @@ describe('Test prune storage scripts', function () { | |||
67 | await setDefaultVideoChannel(servers) | 73 | await setDefaultVideoChannel(servers) |
68 | 74 | ||
69 | for (const server of servers) { | 75 | for (const server of servers) { |
70 | await server.videos.upload({ attributes: { name: 'video 1' } }) | 76 | await server.videos.upload({ attributes: { name: 'video 1', privacy: VideoPrivacy.PUBLIC } }) |
71 | await server.videos.upload({ attributes: { name: 'video 2' } }) | 77 | await server.videos.upload({ attributes: { name: 'video 2', privacy: VideoPrivacy.PUBLIC } }) |
78 | |||
79 | await server.videos.upload({ attributes: { name: 'video 3', privacy: VideoPrivacy.PRIVATE } }) | ||
72 | 80 | ||
73 | await server.users.updateMyAvatar({ fixture: 'avatar.png' }) | 81 | await server.users.updateMyAvatar({ fixture: 'avatar.png' }) |
74 | 82 | ||
@@ -123,13 +131,16 @@ describe('Test prune storage scripts', function () { | |||
123 | it('Should create some dirty files', async function () { | 131 | it('Should create some dirty files', async function () { |
124 | for (let i = 0; i < 2; i++) { | 132 | for (let i = 0; i < 2; i++) { |
125 | { | 133 | { |
126 | const base = servers[0].servers.buildDirectory('videos') | 134 | const basePublic = servers[0].servers.buildDirectory('videos') |
135 | const basePrivate = servers[0].servers.buildDirectory(join('videos', 'private')) | ||
127 | 136 | ||
128 | const n1 = buildUUID() + '.mp4' | 137 | const n1 = buildUUID() + '.mp4' |
129 | const n2 = buildUUID() + '.webm' | 138 | const n2 = buildUUID() + '.webm' |
130 | 139 | ||
131 | await createFile(join(base, n1)) | 140 | await createFile(join(basePublic, n1)) |
132 | await createFile(join(base, n2)) | 141 | await createFile(join(basePublic, n2)) |
142 | await createFile(join(basePrivate, n1)) | ||
143 | await createFile(join(basePrivate, n2)) | ||
133 | 144 | ||
134 | badNames['videos'] = [ n1, n2 ] | 145 | badNames['videos'] = [ n1, n2 ] |
135 | } | 146 | } |
@@ -184,10 +195,12 @@ describe('Test prune storage scripts', function () { | |||
184 | 195 | ||
185 | { | 196 | { |
186 | const directory = join('streaming-playlists', 'hls') | 197 | const directory = join('streaming-playlists', 'hls') |
187 | const base = servers[0].servers.buildDirectory(directory) | 198 | const basePublic = servers[0].servers.buildDirectory(directory) |
199 | const basePrivate = servers[0].servers.buildDirectory(join(directory, 'private')) | ||
188 | 200 | ||
189 | const n1 = buildUUID() | 201 | const n1 = buildUUID() |
190 | await createFile(join(base, n1)) | 202 | await createFile(join(basePublic, n1)) |
203 | await createFile(join(basePrivate, n1)) | ||
191 | badNames[directory] = [ n1 ] | 204 | badNames[directory] = [ n1 ] |
192 | } | 205 | } |
193 | } | 206 | } |
diff --git a/server/tests/cli/regenerate-thumbnails.ts b/server/tests/cli/regenerate-thumbnails.ts index f459b11b8..16a8adcda 100644 --- a/server/tests/cli/regenerate-thumbnails.ts +++ b/server/tests/cli/regenerate-thumbnails.ts | |||
@@ -6,7 +6,7 @@ import { | |||
6 | cleanupTests, | 6 | cleanupTests, |
7 | createMultipleServers, | 7 | createMultipleServers, |
8 | doubleFollow, | 8 | doubleFollow, |
9 | makeRawRequest, | 9 | makeGetRequest, |
10 | PeerTubeServer, | 10 | PeerTubeServer, |
11 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
12 | waitJobs | 12 | waitJobs |
@@ -16,8 +16,8 @@ async function testThumbnail (server: PeerTubeServer, videoId: number | string) | |||
16 | const video = await server.videos.get({ id: videoId }) | 16 | const video = await server.videos.get({ id: videoId }) |
17 | 17 | ||
18 | const requests = [ | 18 | const requests = [ |
19 | makeRawRequest(join(server.url, video.thumbnailPath), HttpStatusCode.OK_200), | 19 | makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }), |
20 | makeRawRequest(join(server.url, video.thumbnailPath), HttpStatusCode.OK_200) | 20 | makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) |
21 | ] | 21 | ] |
22 | 22 | ||
23 | for (const req of requests) { | 23 | for (const req of requests) { |
@@ -69,17 +69,17 @@ describe('Test regenerate thumbnails script', function () { | |||
69 | 69 | ||
70 | it('Should have empty thumbnails', async function () { | 70 | it('Should have empty thumbnails', async function () { |
71 | { | 71 | { |
72 | const res = await makeRawRequest(join(servers[0].url, video1.thumbnailPath), HttpStatusCode.OK_200) | 72 | const res = await makeGetRequest({ url: servers[0].url, path: video1.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) |
73 | expect(res.body).to.have.lengthOf(0) | 73 | expect(res.body).to.have.lengthOf(0) |
74 | } | 74 | } |
75 | 75 | ||
76 | { | 76 | { |
77 | const res = await makeRawRequest(join(servers[0].url, video2.thumbnailPath), HttpStatusCode.OK_200) | 77 | const res = await makeGetRequest({ url: servers[0].url, path: video2.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) |
78 | expect(res.body).to.not.have.lengthOf(0) | 78 | expect(res.body).to.not.have.lengthOf(0) |
79 | } | 79 | } |
80 | 80 | ||
81 | { | 81 | { |
82 | const res = await makeRawRequest(join(servers[0].url, remoteVideo.thumbnailPath), HttpStatusCode.OK_200) | 82 | const res = await makeGetRequest({ url: servers[0].url, path: remoteVideo.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) |
83 | expect(res.body).to.have.lengthOf(0) | 83 | expect(res.body).to.have.lengthOf(0) |
84 | } | 84 | } |
85 | }) | 85 | }) |
@@ -94,21 +94,21 @@ describe('Test regenerate thumbnails script', function () { | |||
94 | await testThumbnail(servers[0], video1.uuid) | 94 | await testThumbnail(servers[0], video1.uuid) |
95 | await testThumbnail(servers[0], video2.uuid) | 95 | await testThumbnail(servers[0], video2.uuid) |
96 | 96 | ||
97 | const res = await makeRawRequest(join(servers[0].url, remoteVideo.thumbnailPath), HttpStatusCode.OK_200) | 97 | const res = await makeGetRequest({ url: servers[0].url, path: remoteVideo.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) |
98 | expect(res.body).to.have.lengthOf(0) | 98 | expect(res.body).to.have.lengthOf(0) |
99 | }) | 99 | }) |
100 | 100 | ||
101 | it('Should have deleted old thumbnail files', async function () { | 101 | it('Should have deleted old thumbnail files', async function () { |
102 | { | 102 | { |
103 | await makeRawRequest(join(servers[0].url, video1.thumbnailPath), HttpStatusCode.NOT_FOUND_404) | 103 | await makeGetRequest({ url: servers[0].url, path: video1.thumbnailPath, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) |
104 | } | 104 | } |
105 | 105 | ||
106 | { | 106 | { |
107 | await makeRawRequest(join(servers[0].url, video2.thumbnailPath), HttpStatusCode.NOT_FOUND_404) | 107 | await makeGetRequest({ url: servers[0].url, path: video2.thumbnailPath, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) |
108 | } | 108 | } |
109 | 109 | ||
110 | { | 110 | { |
111 | const res = await makeRawRequest(join(servers[0].url, remoteVideo.thumbnailPath), HttpStatusCode.OK_200) | 111 | const res = await makeGetRequest({ url: servers[0].url, path: remoteVideo.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) |
112 | expect(res.body).to.have.lengthOf(0) | 112 | expect(res.body).to.have.lengthOf(0) |
113 | } | 113 | } |
114 | }) | 114 | }) |
diff --git a/server/tests/external-plugins/akismet.ts b/server/tests/external-plugins/akismet.ts new file mode 100644 index 000000000..974bf0011 --- /dev/null +++ b/server/tests/external-plugins/akismet.ts | |||
@@ -0,0 +1,160 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { HttpStatusCode } from '@shared/models' | ||
5 | import { | ||
6 | cleanupTests, | ||
7 | createMultipleServers, | ||
8 | doubleFollow, | ||
9 | PeerTubeServer, | ||
10 | setAccessTokensToServers, | ||
11 | waitJobs | ||
12 | } from '@shared/server-commands' | ||
13 | |||
14 | describe('Official plugin Akismet', function () { | ||
15 | let servers: PeerTubeServer[] | ||
16 | let videoUUID: string | ||
17 | |||
18 | before(async function () { | ||
19 | this.timeout(30000) | ||
20 | |||
21 | servers = await createMultipleServers(2) | ||
22 | await setAccessTokensToServers(servers) | ||
23 | |||
24 | await servers[0].plugins.install({ | ||
25 | npmName: 'peertube-plugin-akismet' | ||
26 | }) | ||
27 | |||
28 | if (!process.env.AKISMET_KEY) throw new Error('Missing AKISMET_KEY from env') | ||
29 | |||
30 | await servers[0].plugins.updateSettings({ | ||
31 | npmName: 'peertube-plugin-akismet', | ||
32 | settings: { | ||
33 | 'akismet-api-key': process.env.AKISMET_KEY | ||
34 | } | ||
35 | }) | ||
36 | |||
37 | await doubleFollow(servers[0], servers[1]) | ||
38 | }) | ||
39 | |||
40 | describe('Local threads/replies', function () { | ||
41 | |||
42 | before(async function () { | ||
43 | const { uuid } = await servers[0].videos.quickUpload({ name: 'video 1' }) | ||
44 | videoUUID = uuid | ||
45 | }) | ||
46 | |||
47 | it('Should not detect a thread as spam', async function () { | ||
48 | await servers[0].comments.createThread({ videoId: videoUUID, text: 'comment' }) | ||
49 | }) | ||
50 | |||
51 | it('Should not detect a reply as spam', async function () { | ||
52 | await servers[0].comments.addReplyToLastThread({ text: 'reply' }) | ||
53 | }) | ||
54 | |||
55 | it('Should detect a thread as spam', async function () { | ||
56 | await servers[0].comments.createThread({ | ||
57 | videoId: videoUUID, | ||
58 | text: 'akismet-guaranteed-spam', | ||
59 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
60 | }) | ||
61 | }) | ||
62 | |||
63 | it('Should detect a thread as spam', async function () { | ||
64 | await servers[0].comments.createThread({ videoId: videoUUID, text: 'comment' }) | ||
65 | await servers[0].comments.addReplyToLastThread({ text: 'akismet-guaranteed-spam', expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
66 | }) | ||
67 | }) | ||
68 | |||
69 | describe('Remote threads/replies', function () { | ||
70 | |||
71 | before(async function () { | ||
72 | this.timeout(60000) | ||
73 | |||
74 | const { uuid } = await servers[0].videos.quickUpload({ name: 'video 1' }) | ||
75 | videoUUID = uuid | ||
76 | |||
77 | await waitJobs(servers) | ||
78 | }) | ||
79 | |||
80 | it('Should not detect a thread as spam', async function () { | ||
81 | this.timeout(30000) | ||
82 | |||
83 | await servers[1].comments.createThread({ videoId: videoUUID, text: 'remote comment 1' }) | ||
84 | await waitJobs(servers) | ||
85 | |||
86 | const { data } = await servers[0].comments.listThreads({ videoId: videoUUID }) | ||
87 | expect(data).to.have.lengthOf(1) | ||
88 | }) | ||
89 | |||
90 | it('Should not detect a reply as spam', async function () { | ||
91 | this.timeout(30000) | ||
92 | |||
93 | await servers[1].comments.addReplyToLastThread({ text: 'I agree with you' }) | ||
94 | await waitJobs(servers) | ||
95 | |||
96 | const { data } = await servers[0].comments.listThreads({ videoId: videoUUID }) | ||
97 | expect(data).to.have.lengthOf(1) | ||
98 | |||
99 | const tree = await servers[0].comments.getThread({ videoId: videoUUID, threadId: data[0].id }) | ||
100 | expect(tree.children).to.have.lengthOf(1) | ||
101 | }) | ||
102 | |||
103 | it('Should detect a thread as spam', async function () { | ||
104 | this.timeout(30000) | ||
105 | |||
106 | await servers[1].comments.createThread({ videoId: videoUUID, text: 'akismet-guaranteed-spam' }) | ||
107 | await waitJobs(servers) | ||
108 | |||
109 | const { data } = await servers[0].comments.listThreads({ videoId: videoUUID }) | ||
110 | expect(data).to.have.lengthOf(1) | ||
111 | }) | ||
112 | |||
113 | it('Should detect a thread as spam', async function () { | ||
114 | this.timeout(30000) | ||
115 | |||
116 | await servers[1].comments.addReplyToLastThread({ text: 'akismet-guaranteed-spam' }) | ||
117 | await waitJobs(servers) | ||
118 | |||
119 | const { data } = await servers[0].comments.listThreads({ videoId: videoUUID }) | ||
120 | expect(data).to.have.lengthOf(1) | ||
121 | |||
122 | const thread = data[0] | ||
123 | const tree = await servers[0].comments.getThread({ videoId: videoUUID, threadId: thread.id }) | ||
124 | expect(tree.children).to.have.lengthOf(1) | ||
125 | }) | ||
126 | }) | ||
127 | |||
128 | describe('Signup', function () { | ||
129 | |||
130 | before(async function () { | ||
131 | await servers[0].config.updateExistingSubConfig({ | ||
132 | newConfig: { | ||
133 | signup: { | ||
134 | enabled: true | ||
135 | } | ||
136 | } | ||
137 | }) | ||
138 | }) | ||
139 | |||
140 | it('Should allow signup', async function () { | ||
141 | await servers[0].users.register({ | ||
142 | username: 'user1', | ||
143 | displayName: 'user 1' | ||
144 | }) | ||
145 | }) | ||
146 | |||
147 | it('Should detect a signup as SPAM', async function () { | ||
148 | await servers[0].users.register({ | ||
149 | username: 'user2', | ||
150 | displayName: 'user 2', | ||
151 | email: 'akismet-guaranteed-spam@example.com', | ||
152 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
153 | }) | ||
154 | }) | ||
155 | }) | ||
156 | |||
157 | after(async function () { | ||
158 | await cleanupTests(servers) | ||
159 | }) | ||
160 | }) | ||
diff --git a/server/tests/external-plugins/auth-ldap.ts b/server/tests/external-plugins/auth-ldap.ts index d7f155d2a..6f6a574a0 100644 --- a/server/tests/external-plugins/auth-ldap.ts +++ b/server/tests/external-plugins/auth-ldap.ts | |||
@@ -94,6 +94,14 @@ describe('Official plugin auth-ldap', function () { | |||
94 | await server.login.login({ user: { username: 'fry@planetexpress.com', password: 'fry' } }) | 94 | await server.login.login({ user: { username: 'fry@planetexpress.com', password: 'fry' } }) |
95 | }) | 95 | }) |
96 | 96 | ||
97 | it('Should not be able to ask password reset', async function () { | ||
98 | await server.users.askResetPassword({ email: 'fry@planetexpress.com', expectedStatus: HttpStatusCode.CONFLICT_409 }) | ||
99 | }) | ||
100 | |||
101 | it('Should not be able to ask email verification', async function () { | ||
102 | await server.users.askSendVerifyEmail({ email: 'fry@planetexpress.com', expectedStatus: HttpStatusCode.CONFLICT_409 }) | ||
103 | }) | ||
104 | |||
97 | it('Should not login if the plugin is uninstalled', async function () { | 105 | it('Should not login if the plugin is uninstalled', async function () { |
98 | await server.plugins.uninstall({ npmName: 'peertube-plugin-auth-ldap' }) | 106 | await server.plugins.uninstall({ npmName: 'peertube-plugin-auth-ldap' }) |
99 | 107 | ||
diff --git a/server/tests/external-plugins/index.ts b/server/tests/external-plugins/index.ts index 31d818b51..815bbf1da 100644 --- a/server/tests/external-plugins/index.ts +++ b/server/tests/external-plugins/index.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | import './akismet' | ||
1 | import './auth-ldap' | 2 | import './auth-ldap' |
2 | import './auto-block-videos' | 3 | import './auto-block-videos' |
3 | import './auto-mute' | 4 | import './auto-mute' |
diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts index 1d3c03d67..906dab1a3 100644 --- a/server/tests/feeds/feeds.ts +++ b/server/tests/feeds/feeds.ts | |||
@@ -9,6 +9,7 @@ import { | |||
9 | createSingleServer, | 9 | createSingleServer, |
10 | doubleFollow, | 10 | doubleFollow, |
11 | makeGetRequest, | 11 | makeGetRequest, |
12 | makeRawRequest, | ||
12 | PeerTubeServer, | 13 | PeerTubeServer, |
13 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
14 | setDefaultChannelAvatar, | 15 | setDefaultChannelAvatar, |
@@ -306,6 +307,15 @@ describe('Test syndication feeds', () => { | |||
306 | 307 | ||
307 | await stopFfmpeg(ffmpeg) | 308 | await stopFfmpeg(ffmpeg) |
308 | }) | 309 | }) |
310 | |||
311 | it('Should have the channel avatar as feed icon', async function () { | ||
312 | const json = await servers[0].feed.getJSON({ feed: 'videos', query: { videoChannelId: rootChannelId }, ignoreCache: true }) | ||
313 | |||
314 | const jsonObj = JSON.parse(json) | ||
315 | const imageUrl = jsonObj.icon | ||
316 | expect(imageUrl).to.include('/lazy-static/avatars/') | ||
317 | await makeRawRequest({ url: imageUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
318 | }) | ||
309 | }) | 319 | }) |
310 | 320 | ||
311 | describe('Video comments feed', function () { | 321 | describe('Video comments feed', function () { |
diff --git a/server/tests/fixtures/peertube-plugin-test-four/main.js b/server/tests/fixtures/peertube-plugin-test-four/main.js index 5194e3e02..3e848c49e 100644 --- a/server/tests/fixtures/peertube-plugin-test-four/main.js +++ b/server/tests/fixtures/peertube-plugin-test-four/main.js | |||
@@ -128,6 +128,22 @@ async function register ({ | |||
128 | 128 | ||
129 | return res.json(result) | 129 | return res.json(result) |
130 | }) | 130 | }) |
131 | |||
132 | router.post('/send-notification', async (req, res) => { | ||
133 | peertubeHelpers.socket.sendNotification(req.body.userId, { | ||
134 | type: 1, | ||
135 | userId: req.body.userId | ||
136 | }) | ||
137 | |||
138 | return res.sendStatus(201) | ||
139 | }) | ||
140 | |||
141 | router.post('/send-video-live-new-state/:uuid', async (req, res) => { | ||
142 | const video = await peertubeHelpers.videos.loadByIdOrUUID(req.params.uuid) | ||
143 | peertubeHelpers.socket.sendVideoLiveNewState(video) | ||
144 | |||
145 | return res.sendStatus(201) | ||
146 | }) | ||
131 | } | 147 | } |
132 | 148 | ||
133 | } | 149 | } |
diff --git a/server/tests/fixtures/peertube-plugin-test-websocket/main.js b/server/tests/fixtures/peertube-plugin-test-websocket/main.js new file mode 100644 index 000000000..3fde76cfe --- /dev/null +++ b/server/tests/fixtures/peertube-plugin-test-websocket/main.js | |||
@@ -0,0 +1,36 @@ | |||
1 | const WebSocketServer = require('ws').WebSocketServer | ||
2 | |||
3 | async function register ({ | ||
4 | registerWebSocketRoute | ||
5 | }) { | ||
6 | const wss = new WebSocketServer({ noServer: true }) | ||
7 | |||
8 | wss.on('connection', function connection(ws) { | ||
9 | ws.on('message', function message(data) { | ||
10 | if (data.toString() === 'ping') { | ||
11 | ws.send('pong') | ||
12 | } | ||
13 | }) | ||
14 | }) | ||
15 | |||
16 | registerWebSocketRoute({ | ||
17 | route: '/toto', | ||
18 | |||
19 | handler: (request, socket, head) => { | ||
20 | wss.handleUpgrade(request, socket, head, ws => { | ||
21 | wss.emit('connection', ws, request) | ||
22 | }) | ||
23 | } | ||
24 | }) | ||
25 | } | ||
26 | |||
27 | async function unregister () { | ||
28 | return | ||
29 | } | ||
30 | |||
31 | module.exports = { | ||
32 | register, | ||
33 | unregister | ||
34 | } | ||
35 | |||
36 | // ########################################################################### | ||
diff --git a/server/tests/fixtures/peertube-plugin-test-websocket/package.json b/server/tests/fixtures/peertube-plugin-test-websocket/package.json new file mode 100644 index 000000000..89c8baa04 --- /dev/null +++ b/server/tests/fixtures/peertube-plugin-test-websocket/package.json | |||
@@ -0,0 +1,20 @@ | |||
1 | { | ||
2 | "name": "peertube-plugin-test-websocket", | ||
3 | "version": "0.0.1", | ||
4 | "description": "Plugin test websocket", | ||
5 | "engine": { | ||
6 | "peertube": ">=1.3.0" | ||
7 | }, | ||
8 | "keywords": [ | ||
9 | "peertube", | ||
10 | "plugin" | ||
11 | ], | ||
12 | "homepage": "https://github.com/Chocobozzz/PeerTube", | ||
13 | "author": "Chocobozzz", | ||
14 | "bugs": "https://github.com/Chocobozzz/PeerTube/issues", | ||
15 | "library": "./main.js", | ||
16 | "staticDirs": {}, | ||
17 | "css": [], | ||
18 | "clientScripts": [], | ||
19 | "translations": {} | ||
20 | } | ||
diff --git a/server/tests/fixtures/peertube-plugin-test/main.js b/server/tests/fixtures/peertube-plugin-test/main.js index 813482a27..19dccf26e 100644 --- a/server/tests/fixtures/peertube-plugin-test/main.js +++ b/server/tests/fixtures/peertube-plugin-test/main.js | |||
@@ -178,6 +178,8 @@ async function register ({ registerHook, registerSetting, settingsManager, stora | |||
178 | } | 178 | } |
179 | }) | 179 | }) |
180 | 180 | ||
181 | // --------------------------------------------------------------------------- | ||
182 | |||
181 | registerHook({ | 183 | registerHook({ |
182 | target: 'filter:api.video-thread.create.accept.result', | 184 | target: 'filter:api.video-thread.create.accept.result', |
183 | handler: ({ accepted }, { commentBody }) => checkCommentBadWord(accepted, commentBody) | 185 | handler: ({ accepted }, { commentBody }) => checkCommentBadWord(accepted, commentBody) |
@@ -189,6 +191,13 @@ async function register ({ registerHook, registerSetting, settingsManager, stora | |||
189 | }) | 191 | }) |
190 | 192 | ||
191 | registerHook({ | 193 | registerHook({ |
194 | target: 'filter:activity-pub.remote-video-comment.create.accept.result', | ||
195 | handler: ({ accepted }, { comment }) => checkCommentBadWord(accepted, comment) | ||
196 | }) | ||
197 | |||
198 | // --------------------------------------------------------------------------- | ||
199 | |||
200 | registerHook({ | ||
192 | target: 'filter:api.video-threads.list.params', | 201 | target: 'filter:api.video-threads.list.params', |
193 | handler: obj => addToCount(obj) | 202 | handler: obj => addToCount(obj) |
194 | }) | 203 | }) |
diff --git a/server/tests/helpers/crypto.ts b/server/tests/helpers/crypto.ts new file mode 100644 index 000000000..b508c715b --- /dev/null +++ b/server/tests/helpers/crypto.ts | |||
@@ -0,0 +1,33 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { decrypt, encrypt } from '@server/helpers/peertube-crypto' | ||
5 | |||
6 | describe('Encrypt/Descrypt', function () { | ||
7 | |||
8 | it('Should encrypt and decrypt the string', async function () { | ||
9 | const secret = 'my_secret' | ||
10 | const str = 'my super string' | ||
11 | |||
12 | const encrypted = await encrypt(str, secret) | ||
13 | const decrypted = await decrypt(encrypted, secret) | ||
14 | |||
15 | expect(str).to.equal(decrypted) | ||
16 | }) | ||
17 | |||
18 | it('Should not decrypt without the same secret', async function () { | ||
19 | const str = 'my super string' | ||
20 | |||
21 | const encrypted = await encrypt(str, 'my_secret') | ||
22 | |||
23 | let error = false | ||
24 | |||
25 | try { | ||
26 | await decrypt(encrypted, 'my_sicret') | ||
27 | } catch (err) { | ||
28 | error = true | ||
29 | } | ||
30 | |||
31 | expect(error).to.be.true | ||
32 | }) | ||
33 | }) | ||
diff --git a/server/tests/helpers/index.ts b/server/tests/helpers/index.ts index 951208842..1f0e3098a 100644 --- a/server/tests/helpers/index.ts +++ b/server/tests/helpers/index.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import './image' | 1 | import './comment-model' |
2 | import './core-utils' | 2 | import './core-utils' |
3 | import './crypto' | ||
3 | import './dns' | 4 | import './dns' |
4 | import './comment-model' | 5 | import './image' |
5 | import './markdown' | 6 | import './markdown' |
6 | import './request' | 7 | import './request' |
diff --git a/server/tests/misc-endpoints.ts b/server/tests/misc-endpoints.ts index 663ac044a..d2072342e 100644 --- a/server/tests/misc-endpoints.ts +++ b/server/tests/misc-endpoints.ts | |||
@@ -1,18 +1,24 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | 4 | import { writeJson } from 'fs-extra' |
5 | import { join } from 'path' | ||
5 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | 6 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' |
7 | import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | ||
6 | import { expectLogDoesNotContain } from './shared' | 8 | import { expectLogDoesNotContain } from './shared' |
7 | 9 | ||
8 | describe('Test misc endpoints', function () { | 10 | describe('Test misc endpoints', function () { |
9 | let server: PeerTubeServer | 11 | let server: PeerTubeServer |
12 | let wellKnownPath: string | ||
10 | 13 | ||
11 | before(async function () { | 14 | before(async function () { |
12 | this.timeout(120000) | 15 | this.timeout(120000) |
13 | 16 | ||
14 | server = await createSingleServer(1) | 17 | server = await createSingleServer(1) |
18 | |||
15 | await setAccessTokensToServers([ server ]) | 19 | await setAccessTokensToServers([ server ]) |
20 | |||
21 | wellKnownPath = server.getDirectoryPath('well-known') | ||
16 | }) | 22 | }) |
17 | 23 | ||
18 | describe('Test a well known endpoints', function () { | 24 | describe('Test a well known endpoints', function () { |
@@ -93,6 +99,28 @@ describe('Test misc endpoints', function () { | |||
93 | expect(remoteInteract).to.exist | 99 | expect(remoteInteract).to.exist |
94 | expect(remoteInteract.template).to.equal(server.url + '/remote-interaction?uri={uri}') | 100 | expect(remoteInteract.template).to.equal(server.url + '/remote-interaction?uri={uri}') |
95 | }) | 101 | }) |
102 | |||
103 | it('Should return 404 for non-existing files in /.well-known', async function () { | ||
104 | await makeGetRequest({ | ||
105 | url: server.url, | ||
106 | path: '/.well-known/non-existing-file', | ||
107 | expectedStatus: HttpStatusCode.NOT_FOUND_404 | ||
108 | }) | ||
109 | }) | ||
110 | |||
111 | it('Should return custom file from /.well-known', async function () { | ||
112 | const filename = 'existing-file.json' | ||
113 | |||
114 | await writeJson(join(wellKnownPath, filename), { iThink: 'therefore I am' }) | ||
115 | |||
116 | const { body } = await makeGetRequest({ | ||
117 | url: server.url, | ||
118 | path: '/.well-known/' + filename, | ||
119 | expectedStatus: HttpStatusCode.OK_200 | ||
120 | }) | ||
121 | |||
122 | expect(body.iThink).to.equal('therefore I am') | ||
123 | }) | ||
96 | }) | 124 | }) |
97 | 125 | ||
98 | describe('Test classic static endpoints', function () { | 126 | describe('Test classic static endpoints', function () { |
diff --git a/server/tests/plugins/action-hooks.ts b/server/tests/plugins/action-hooks.ts index af65166d9..36f8052c0 100644 --- a/server/tests/plugins/action-hooks.ts +++ b/server/tests/plugins/action-hooks.ts | |||
@@ -21,7 +21,7 @@ describe('Test plugin action hooks', function () { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | before(async function () { | 23 | before(async function () { |
24 | this.timeout(30000) | 24 | this.timeout(120000) |
25 | 25 | ||
26 | servers = await createMultipleServers(2) | 26 | servers = await createMultipleServers(2) |
27 | await setAccessTokensToServers(servers) | 27 | await setAccessTokensToServers(servers) |
diff --git a/server/tests/plugins/external-auth.ts b/server/tests/plugins/external-auth.ts index e08b83791..437777e90 100644 --- a/server/tests/plugins/external-auth.ts +++ b/server/tests/plugins/external-auth.ts | |||
@@ -155,7 +155,7 @@ describe('Test external auth plugins', function () { | |||
155 | expect(body.username).to.equal('cyan') | 155 | expect(body.username).to.equal('cyan') |
156 | expect(body.account.displayName).to.equal('cyan') | 156 | expect(body.account.displayName).to.equal('cyan') |
157 | expect(body.email).to.equal('cyan@example.com') | 157 | expect(body.email).to.equal('cyan@example.com') |
158 | expect(body.role).to.equal(UserRole.USER) | 158 | expect(body.role.id).to.equal(UserRole.USER) |
159 | } | 159 | } |
160 | }) | 160 | }) |
161 | 161 | ||
@@ -177,7 +177,7 @@ describe('Test external auth plugins', function () { | |||
177 | expect(body.username).to.equal('kefka') | 177 | expect(body.username).to.equal('kefka') |
178 | expect(body.account.displayName).to.equal('Kefka Palazzo') | 178 | expect(body.account.displayName).to.equal('Kefka Palazzo') |
179 | expect(body.email).to.equal('kefka@example.com') | 179 | expect(body.email).to.equal('kefka@example.com') |
180 | expect(body.role).to.equal(UserRole.ADMINISTRATOR) | 180 | expect(body.role.id).to.equal(UserRole.ADMINISTRATOR) |
181 | } | 181 | } |
182 | }) | 182 | }) |
183 | 183 | ||
@@ -237,7 +237,7 @@ describe('Test external auth plugins', function () { | |||
237 | expect(body.username).to.equal('cyan') | 237 | expect(body.username).to.equal('cyan') |
238 | expect(body.account.displayName).to.equal('Cyan Garamonde') | 238 | expect(body.account.displayName).to.equal('Cyan Garamonde') |
239 | expect(body.account.description).to.equal('Retainer to the king of Doma') | 239 | expect(body.account.description).to.equal('Retainer to the king of Doma') |
240 | expect(body.role).to.equal(UserRole.USER) | 240 | expect(body.role.id).to.equal(UserRole.USER) |
241 | }) | 241 | }) |
242 | 242 | ||
243 | it('Should not update an external auth email', async function () { | 243 | it('Should not update an external auth email', async function () { |
diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts index 026c7e856..083fd43ca 100644 --- a/server/tests/plugins/filter-hooks.ts +++ b/server/tests/plugins/filter-hooks.ts | |||
@@ -6,6 +6,7 @@ import { | |||
6 | cleanupTests, | 6 | cleanupTests, |
7 | createMultipleServers, | 7 | createMultipleServers, |
8 | doubleFollow, | 8 | doubleFollow, |
9 | makeGetRequest, | ||
9 | makeRawRequest, | 10 | makeRawRequest, |
10 | PeerTubeServer, | 11 | PeerTubeServer, |
11 | PluginsCommand, | 12 | PluginsCommand, |
@@ -64,232 +65,289 @@ describe('Test plugin filter hooks', function () { | |||
64 | }) | 65 | }) |
65 | }) | 66 | }) |
66 | 67 | ||
67 | it('Should run filter:api.videos.list.params', async function () { | 68 | describe('Videos', function () { |
68 | const { data } = await servers[0].videos.list({ start: 0, count: 2 }) | ||
69 | 69 | ||
70 | // 2 plugins do +1 to the count parameter | 70 | it('Should run filter:api.videos.list.params', async function () { |
71 | expect(data).to.have.lengthOf(4) | 71 | const { data } = await servers[0].videos.list({ start: 0, count: 2 }) |
72 | }) | ||
73 | 72 | ||
74 | it('Should run filter:api.videos.list.result', async function () { | 73 | // 2 plugins do +1 to the count parameter |
75 | const { total } = await servers[0].videos.list({ start: 0, count: 0 }) | 74 | expect(data).to.have.lengthOf(4) |
75 | }) | ||
76 | 76 | ||
77 | // Plugin do +1 to the total result | 77 | it('Should run filter:api.videos.list.result', async function () { |
78 | expect(total).to.equal(11) | 78 | const { total } = await servers[0].videos.list({ start: 0, count: 0 }) |
79 | }) | ||
80 | 79 | ||
81 | it('Should run filter:api.video-playlist.videos.list.params', async function () { | 80 | // Plugin do +1 to the total result |
82 | const { data } = await servers[0].playlists.listVideos({ | 81 | expect(total).to.equal(11) |
83 | count: 2, | ||
84 | playlistId: videoPlaylistUUID | ||
85 | }) | 82 | }) |
86 | 83 | ||
87 | // 1 plugin do +1 to the count parameter | 84 | it('Should run filter:api.video-playlist.videos.list.params', async function () { |
88 | expect(data).to.have.lengthOf(3) | 85 | const { data } = await servers[0].playlists.listVideos({ |
89 | }) | 86 | count: 2, |
87 | playlistId: videoPlaylistUUID | ||
88 | }) | ||
90 | 89 | ||
91 | it('Should run filter:api.video-playlist.videos.list.result', async function () { | 90 | // 1 plugin do +1 to the count parameter |
92 | const { total } = await servers[0].playlists.listVideos({ | 91 | expect(data).to.have.lengthOf(3) |
93 | count: 0, | ||
94 | playlistId: videoPlaylistUUID | ||
95 | }) | 92 | }) |
96 | 93 | ||
97 | // Plugin do +1 to the total result | 94 | it('Should run filter:api.video-playlist.videos.list.result', async function () { |
98 | expect(total).to.equal(11) | 95 | const { total } = await servers[0].playlists.listVideos({ |
99 | }) | 96 | count: 0, |
97 | playlistId: videoPlaylistUUID | ||
98 | }) | ||
100 | 99 | ||
101 | it('Should run filter:api.accounts.videos.list.params', async function () { | 100 | // Plugin do +1 to the total result |
102 | const { data } = await servers[0].videos.listByAccount({ handle: 'root', start: 0, count: 2 }) | 101 | expect(total).to.equal(11) |
102 | }) | ||
103 | 103 | ||
104 | // 1 plugin do +1 to the count parameter | 104 | it('Should run filter:api.accounts.videos.list.params', async function () { |
105 | expect(data).to.have.lengthOf(3) | 105 | const { data } = await servers[0].videos.listByAccount({ handle: 'root', start: 0, count: 2 }) |
106 | }) | ||
107 | 106 | ||
108 | it('Should run filter:api.accounts.videos.list.result', async function () { | 107 | // 1 plugin do +1 to the count parameter |
109 | const { total } = await servers[0].videos.listByAccount({ handle: 'root', start: 0, count: 2 }) | 108 | expect(data).to.have.lengthOf(3) |
109 | }) | ||
110 | 110 | ||
111 | // Plugin do +2 to the total result | 111 | it('Should run filter:api.accounts.videos.list.result', async function () { |
112 | expect(total).to.equal(12) | 112 | const { total } = await servers[0].videos.listByAccount({ handle: 'root', start: 0, count: 2 }) |
113 | }) | ||
114 | 113 | ||
115 | it('Should run filter:api.video-channels.videos.list.params', async function () { | 114 | // Plugin do +2 to the total result |
116 | const { data } = await servers[0].videos.listByChannel({ handle: 'root_channel', start: 0, count: 2 }) | 115 | expect(total).to.equal(12) |
116 | }) | ||
117 | 117 | ||
118 | // 1 plugin do +3 to the count parameter | 118 | it('Should run filter:api.video-channels.videos.list.params', async function () { |
119 | expect(data).to.have.lengthOf(5) | 119 | const { data } = await servers[0].videos.listByChannel({ handle: 'root_channel', start: 0, count: 2 }) |
120 | }) | ||
121 | 120 | ||
122 | it('Should run filter:api.video-channels.videos.list.result', async function () { | 121 | // 1 plugin do +3 to the count parameter |
123 | const { total } = await servers[0].videos.listByChannel({ handle: 'root_channel', start: 0, count: 2 }) | 122 | expect(data).to.have.lengthOf(5) |
123 | }) | ||
124 | 124 | ||
125 | // Plugin do +3 to the total result | 125 | it('Should run filter:api.video-channels.videos.list.result', async function () { |
126 | expect(total).to.equal(13) | 126 | const { total } = await servers[0].videos.listByChannel({ handle: 'root_channel', start: 0, count: 2 }) |
127 | }) | ||
128 | 127 | ||
129 | it('Should run filter:api.user.me.videos.list.params', async function () { | 128 | // Plugin do +3 to the total result |
130 | const { data } = await servers[0].videos.listMyVideos({ start: 0, count: 2 }) | 129 | expect(total).to.equal(13) |
130 | }) | ||
131 | 131 | ||
132 | // 1 plugin do +4 to the count parameter | 132 | it('Should run filter:api.user.me.videos.list.params', async function () { |
133 | expect(data).to.have.lengthOf(6) | 133 | const { data } = await servers[0].videos.listMyVideos({ start: 0, count: 2 }) |
134 | }) | ||
135 | 134 | ||
136 | it('Should run filter:api.user.me.videos.list.result', async function () { | 135 | // 1 plugin do +4 to the count parameter |
137 | const { total } = await servers[0].videos.listMyVideos({ start: 0, count: 2 }) | 136 | expect(data).to.have.lengthOf(6) |
137 | }) | ||
138 | 138 | ||
139 | // Plugin do +4 to the total result | 139 | it('Should run filter:api.user.me.videos.list.result', async function () { |
140 | expect(total).to.equal(14) | 140 | const { total } = await servers[0].videos.listMyVideos({ start: 0, count: 2 }) |
141 | }) | ||
142 | 141 | ||
143 | it('Should run filter:api.video.get.result', async function () { | 142 | // Plugin do +4 to the total result |
144 | const video = await servers[0].videos.get({ id: videoUUID }) | 143 | expect(total).to.equal(14) |
145 | expect(video.name).to.contain('<3') | 144 | }) |
146 | }) | ||
147 | 145 | ||
148 | it('Should run filter:api.video.upload.accept.result', async function () { | 146 | it('Should run filter:api.video.get.result', async function () { |
149 | await servers[0].videos.upload({ attributes: { name: 'video with bad word' }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | 147 | const video = await servers[0].videos.get({ id: videoUUID }) |
148 | expect(video.name).to.contain('<3') | ||
149 | }) | ||
150 | }) | 150 | }) |
151 | 151 | ||
152 | it('Should run filter:api.live-video.create.accept.result', async function () { | 152 | describe('Video/live/import accept', function () { |
153 | const attributes = { | ||
154 | name: 'video with bad word', | ||
155 | privacy: VideoPrivacy.PUBLIC, | ||
156 | channelId: servers[0].store.channel.id | ||
157 | } | ||
158 | 153 | ||
159 | await servers[0].live.create({ fields: attributes, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | 154 | it('Should run filter:api.video.upload.accept.result', async function () { |
160 | }) | 155 | await servers[0].videos.upload({ attributes: { name: 'video with bad word' }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) |
161 | 156 | }) | |
162 | it('Should run filter:api.video.pre-import-url.accept.result', async function () { | ||
163 | const attributes = { | ||
164 | name: 'normal title', | ||
165 | privacy: VideoPrivacy.PUBLIC, | ||
166 | channelId: servers[0].store.channel.id, | ||
167 | targetUrl: FIXTURE_URLS.goodVideo + 'bad' | ||
168 | } | ||
169 | await servers[0].imports.importVideo({ attributes, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
170 | }) | ||
171 | 157 | ||
172 | it('Should run filter:api.video.pre-import-torrent.accept.result', async function () { | 158 | it('Should run filter:api.live-video.create.accept.result', async function () { |
173 | const attributes = { | 159 | const attributes = { |
174 | name: 'bad torrent', | 160 | name: 'video with bad word', |
175 | privacy: VideoPrivacy.PUBLIC, | 161 | privacy: VideoPrivacy.PUBLIC, |
176 | channelId: servers[0].store.channel.id, | 162 | channelId: servers[0].store.channel.id |
177 | torrentfile: 'video-720p.torrent' as any | 163 | } |
178 | } | ||
179 | await servers[0].imports.importVideo({ attributes, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
180 | }) | ||
181 | 164 | ||
182 | it('Should run filter:api.video.post-import-url.accept.result', async function () { | 165 | await servers[0].live.create({ fields: attributes, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) |
183 | this.timeout(60000) | 166 | }) |
184 | 167 | ||
185 | let videoImportId: number | 168 | it('Should run filter:api.video.pre-import-url.accept.result', async function () { |
169 | const attributes = { | ||
170 | name: 'normal title', | ||
171 | privacy: VideoPrivacy.PUBLIC, | ||
172 | channelId: servers[0].store.channel.id, | ||
173 | targetUrl: FIXTURE_URLS.goodVideo + 'bad' | ||
174 | } | ||
175 | await servers[0].imports.importVideo({ attributes, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
176 | }) | ||
186 | 177 | ||
187 | { | 178 | it('Should run filter:api.video.pre-import-torrent.accept.result', async function () { |
188 | const attributes = { | 179 | const attributes = { |
189 | name: 'title with bad word', | 180 | name: 'bad torrent', |
190 | privacy: VideoPrivacy.PUBLIC, | 181 | privacy: VideoPrivacy.PUBLIC, |
191 | channelId: servers[0].store.channel.id, | 182 | channelId: servers[0].store.channel.id, |
192 | targetUrl: FIXTURE_URLS.goodVideo | 183 | torrentfile: 'video-720p.torrent' as any |
193 | } | 184 | } |
194 | const body = await servers[0].imports.importVideo({ attributes }) | 185 | await servers[0].imports.importVideo({ attributes, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) |
195 | videoImportId = body.id | 186 | }) |
196 | } | ||
197 | 187 | ||
198 | await waitJobs(servers) | 188 | it('Should run filter:api.video.post-import-url.accept.result', async function () { |
189 | this.timeout(60000) | ||
199 | 190 | ||
200 | { | 191 | let videoImportId: number |
201 | const body = await servers[0].imports.getMyVideoImports() | ||
202 | const videoImports = body.data | ||
203 | 192 | ||
204 | const videoImport = videoImports.find(i => i.id === videoImportId) | 193 | { |
194 | const attributes = { | ||
195 | name: 'title with bad word', | ||
196 | privacy: VideoPrivacy.PUBLIC, | ||
197 | channelId: servers[0].store.channel.id, | ||
198 | targetUrl: FIXTURE_URLS.goodVideo | ||
199 | } | ||
200 | const body = await servers[0].imports.importVideo({ attributes }) | ||
201 | videoImportId = body.id | ||
202 | } | ||
205 | 203 | ||
206 | expect(videoImport.state.id).to.equal(VideoImportState.REJECTED) | 204 | await waitJobs(servers) |
207 | expect(videoImport.state.label).to.equal('Rejected') | ||
208 | } | ||
209 | }) | ||
210 | 205 | ||
211 | it('Should run filter:api.video.post-import-torrent.accept.result', async function () { | 206 | { |
212 | this.timeout(60000) | 207 | const body = await servers[0].imports.getMyVideoImports() |
208 | const videoImports = body.data | ||
213 | 209 | ||
214 | let videoImportId: number | 210 | const videoImport = videoImports.find(i => i.id === videoImportId) |
215 | 211 | ||
216 | { | 212 | expect(videoImport.state.id).to.equal(VideoImportState.REJECTED) |
217 | const attributes = { | 213 | expect(videoImport.state.label).to.equal('Rejected') |
218 | name: 'title with bad word', | ||
219 | privacy: VideoPrivacy.PUBLIC, | ||
220 | channelId: servers[0].store.channel.id, | ||
221 | torrentfile: 'video-720p.torrent' as any | ||
222 | } | 214 | } |
223 | const body = await servers[0].imports.importVideo({ attributes }) | 215 | }) |
224 | videoImportId = body.id | 216 | |
225 | } | 217 | it('Should run filter:api.video.post-import-torrent.accept.result', async function () { |
218 | this.timeout(60000) | ||
226 | 219 | ||
227 | await waitJobs(servers) | 220 | let videoImportId: number |
228 | 221 | ||
229 | { | 222 | { |
230 | const { data: videoImports } = await servers[0].imports.getMyVideoImports() | 223 | const attributes = { |
224 | name: 'title with bad word', | ||
225 | privacy: VideoPrivacy.PUBLIC, | ||
226 | channelId: servers[0].store.channel.id, | ||
227 | torrentfile: 'video-720p.torrent' as any | ||
228 | } | ||
229 | const body = await servers[0].imports.importVideo({ attributes }) | ||
230 | videoImportId = body.id | ||
231 | } | ||
231 | 232 | ||
232 | const videoImport = videoImports.find(i => i.id === videoImportId) | 233 | await waitJobs(servers) |
233 | 234 | ||
234 | expect(videoImport.state.id).to.equal(VideoImportState.REJECTED) | 235 | { |
235 | expect(videoImport.state.label).to.equal('Rejected') | 236 | const { data: videoImports } = await servers[0].imports.getMyVideoImports() |
236 | } | 237 | |
237 | }) | 238 | const videoImport = videoImports.find(i => i.id === videoImportId) |
238 | 239 | ||
239 | it('Should run filter:api.video-thread.create.accept.result', async function () { | 240 | expect(videoImport.state.id).to.equal(VideoImportState.REJECTED) |
240 | await servers[0].comments.createThread({ | 241 | expect(videoImport.state.label).to.equal('Rejected') |
241 | videoId: videoUUID, | 242 | } |
242 | text: 'comment with bad word', | ||
243 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
244 | }) | 243 | }) |
245 | }) | 244 | }) |
246 | 245 | ||
247 | it('Should run filter:api.video-comment-reply.create.accept.result', async function () { | 246 | describe('Video comments accept', function () { |
248 | const created = await servers[0].comments.createThread({ videoId: videoUUID, text: 'thread' }) | ||
249 | threadId = created.id | ||
250 | 247 | ||
251 | await servers[0].comments.addReply({ | 248 | it('Should run filter:api.video-thread.create.accept.result', async function () { |
252 | videoId: videoUUID, | 249 | await servers[0].comments.createThread({ |
253 | toCommentId: threadId, | 250 | videoId: videoUUID, |
254 | text: 'comment with bad word', | 251 | text: 'comment with bad word', |
255 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | 252 | expectedStatus: HttpStatusCode.FORBIDDEN_403 |
253 | }) | ||
256 | }) | 254 | }) |
257 | await servers[0].comments.addReply({ | 255 | |
258 | videoId: videoUUID, | 256 | it('Should run filter:api.video-comment-reply.create.accept.result', async function () { |
259 | toCommentId: threadId, | 257 | const created = await servers[0].comments.createThread({ videoId: videoUUID, text: 'thread' }) |
260 | text: 'comment with good word', | 258 | threadId = created.id |
261 | expectedStatus: HttpStatusCode.OK_200 | 259 | |
260 | await servers[0].comments.addReply({ | ||
261 | videoId: videoUUID, | ||
262 | toCommentId: threadId, | ||
263 | text: 'comment with bad word', | ||
264 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
265 | }) | ||
266 | await servers[0].comments.addReply({ | ||
267 | videoId: videoUUID, | ||
268 | toCommentId: threadId, | ||
269 | text: 'comment with good word', | ||
270 | expectedStatus: HttpStatusCode.OK_200 | ||
271 | }) | ||
262 | }) | 272 | }) |
263 | }) | ||
264 | 273 | ||
265 | it('Should run filter:api.video-threads.list.params', async function () { | 274 | it('Should run filter:activity-pub.remote-video-comment.create.accept.result on a thread creation', async function () { |
266 | const { data } = await servers[0].comments.listThreads({ videoId: videoUUID, start: 0, count: 0 }) | 275 | this.timeout(30000) |
267 | 276 | ||
268 | // our plugin do +1 to the count parameter | 277 | await servers[1].comments.createThread({ videoId: videoUUID, text: 'comment with bad word' }) |
269 | expect(data).to.have.lengthOf(1) | ||
270 | }) | ||
271 | 278 | ||
272 | it('Should run filter:api.video-threads.list.result', async function () { | 279 | await waitJobs(servers) |
273 | const { total } = await servers[0].comments.listThreads({ videoId: videoUUID, start: 0, count: 0 }) | ||
274 | 280 | ||
275 | // Plugin do +1 to the total result | 281 | { |
276 | expect(total).to.equal(2) | 282 | const thread = await servers[0].comments.listThreads({ videoId: videoUUID }) |
277 | }) | 283 | expect(thread.data).to.have.lengthOf(1) |
284 | expect(thread.data[0].text).to.not.include(' bad ') | ||
285 | } | ||
278 | 286 | ||
279 | it('Should run filter:api.video-thread-comments.list.params') | 287 | { |
288 | const thread = await servers[1].comments.listThreads({ videoId: videoUUID }) | ||
289 | expect(thread.data).to.have.lengthOf(2) | ||
290 | } | ||
291 | }) | ||
292 | |||
293 | it('Should run filter:activity-pub.remote-video-comment.create.accept.result on a reply creation', async function () { | ||
294 | this.timeout(30000) | ||
280 | 295 | ||
281 | it('Should run filter:api.video-thread-comments.list.result', async function () { | 296 | const { data } = await servers[1].comments.listThreads({ videoId: videoUUID }) |
282 | const thread = await servers[0].comments.getThread({ videoId: videoUUID, threadId }) | 297 | const threadIdServer2 = data.find(t => t.text === 'thread').id |
283 | 298 | ||
284 | expect(thread.comment.text.endsWith(' <3')).to.be.true | 299 | await servers[1].comments.addReply({ |
300 | videoId: videoUUID, | ||
301 | toCommentId: threadIdServer2, | ||
302 | text: 'comment with bad word' | ||
303 | }) | ||
304 | |||
305 | await waitJobs(servers) | ||
306 | |||
307 | { | ||
308 | const tree = await servers[0].comments.getThread({ videoId: videoUUID, threadId }) | ||
309 | expect(tree.children).to.have.lengthOf(1) | ||
310 | expect(tree.children[0].comment.text).to.not.include(' bad ') | ||
311 | } | ||
312 | |||
313 | { | ||
314 | const tree = await servers[1].comments.getThread({ videoId: videoUUID, threadId: threadIdServer2 }) | ||
315 | expect(tree.children).to.have.lengthOf(2) | ||
316 | } | ||
317 | }) | ||
285 | }) | 318 | }) |
286 | 319 | ||
287 | it('Should run filter:api.overviews.videos.list.{params,result}', async function () { | 320 | describe('Video comments', function () { |
288 | await servers[0].overviews.getVideos({ page: 1 }) | ||
289 | 321 | ||
290 | // 3 because we get 3 samples per page | 322 | it('Should run filter:api.video-threads.list.params', async function () { |
291 | await servers[0].servers.waitUntilLog('Run hook filter:api.overviews.videos.list.params', 3) | 323 | const { data } = await servers[0].comments.listThreads({ videoId: videoUUID, start: 0, count: 0 }) |
292 | await servers[0].servers.waitUntilLog('Run hook filter:api.overviews.videos.list.result', 3) | 324 | |
325 | // our plugin do +1 to the count parameter | ||
326 | expect(data).to.have.lengthOf(1) | ||
327 | }) | ||
328 | |||
329 | it('Should run filter:api.video-threads.list.result', async function () { | ||
330 | const { total } = await servers[0].comments.listThreads({ videoId: videoUUID, start: 0, count: 0 }) | ||
331 | |||
332 | // Plugin do +1 to the total result | ||
333 | expect(total).to.equal(2) | ||
334 | }) | ||
335 | |||
336 | it('Should run filter:api.video-thread-comments.list.params') | ||
337 | |||
338 | it('Should run filter:api.video-thread-comments.list.result', async function () { | ||
339 | const thread = await servers[0].comments.getThread({ videoId: videoUUID, threadId }) | ||
340 | |||
341 | expect(thread.comment.text.endsWith(' <3')).to.be.true | ||
342 | }) | ||
343 | |||
344 | it('Should run filter:api.overviews.videos.list.{params,result}', async function () { | ||
345 | await servers[0].overviews.getVideos({ page: 1 }) | ||
346 | |||
347 | // 3 because we get 3 samples per page | ||
348 | await servers[0].servers.waitUntilLog('Run hook filter:api.overviews.videos.list.params', 3) | ||
349 | await servers[0].servers.waitUntilLog('Run hook filter:api.overviews.videos.list.result', 3) | ||
350 | }) | ||
293 | }) | 351 | }) |
294 | 352 | ||
295 | describe('filter:video.auto-blacklist.result', function () { | 353 | describe('filter:video.auto-blacklist.result', function () { |
@@ -404,30 +462,41 @@ describe('Test plugin filter hooks', function () { | |||
404 | }) | 462 | }) |
405 | 463 | ||
406 | it('Should run filter:api.download.torrent.allowed.result', async function () { | 464 | it('Should run filter:api.download.torrent.allowed.result', async function () { |
407 | const res = await makeRawRequest(downloadVideos[0].files[0].torrentDownloadUrl, 403) | 465 | const res = await makeRawRequest({ url: downloadVideos[0].files[0].torrentDownloadUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) |
408 | expect(res.body.error).to.equal('Liu Bei') | 466 | expect(res.body.error).to.equal('Liu Bei') |
409 | 467 | ||
410 | await makeRawRequest(downloadVideos[1].files[0].torrentDownloadUrl, 200) | 468 | await makeRawRequest({ url: downloadVideos[1].files[0].torrentDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) |
411 | await makeRawRequest(downloadVideos[2].files[0].torrentDownloadUrl, 200) | 469 | await makeRawRequest({ url: downloadVideos[2].files[0].torrentDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) |
412 | }) | 470 | }) |
413 | 471 | ||
414 | it('Should run filter:api.download.video.allowed.result', async function () { | 472 | it('Should run filter:api.download.video.allowed.result', async function () { |
415 | { | 473 | { |
416 | const res = await makeRawRequest(downloadVideos[1].files[0].fileDownloadUrl, 403) | 474 | const res = await makeRawRequest({ url: downloadVideos[1].files[0].fileDownloadUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) |
417 | expect(res.body.error).to.equal('Cao Cao') | 475 | expect(res.body.error).to.equal('Cao Cao') |
418 | 476 | ||
419 | await makeRawRequest(downloadVideos[0].files[0].fileDownloadUrl, 200) | 477 | await makeRawRequest({ url: downloadVideos[0].files[0].fileDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) |
420 | await makeRawRequest(downloadVideos[2].files[0].fileDownloadUrl, 200) | 478 | await makeRawRequest({ url: downloadVideos[2].files[0].fileDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) |
421 | } | 479 | } |
422 | 480 | ||
423 | { | 481 | { |
424 | const res = await makeRawRequest(downloadVideos[2].streamingPlaylists[0].files[0].fileDownloadUrl, 403) | 482 | const res = await makeRawRequest({ |
483 | url: downloadVideos[2].streamingPlaylists[0].files[0].fileDownloadUrl, | ||
484 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
485 | }) | ||
486 | |||
425 | expect(res.body.error).to.equal('Sun Jian') | 487 | expect(res.body.error).to.equal('Sun Jian') |
426 | 488 | ||
427 | await makeRawRequest(downloadVideos[2].files[0].fileDownloadUrl, 200) | 489 | await makeRawRequest({ url: downloadVideos[2].files[0].fileDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) |
490 | |||
491 | await makeRawRequest({ | ||
492 | url: downloadVideos[0].streamingPlaylists[0].files[0].fileDownloadUrl, | ||
493 | expectedStatus: HttpStatusCode.OK_200 | ||
494 | }) | ||
428 | 495 | ||
429 | await makeRawRequest(downloadVideos[0].streamingPlaylists[0].files[0].fileDownloadUrl, 200) | 496 | await makeRawRequest({ |
430 | await makeRawRequest(downloadVideos[1].streamingPlaylists[0].files[0].fileDownloadUrl, 200) | 497 | url: downloadVideos[1].streamingPlaylists[0].files[0].fileDownloadUrl, |
498 | expectedStatus: HttpStatusCode.OK_200 | ||
499 | }) | ||
431 | } | 500 | } |
432 | }) | 501 | }) |
433 | }) | 502 | }) |
@@ -458,12 +527,12 @@ describe('Test plugin filter hooks', function () { | |||
458 | }) | 527 | }) |
459 | 528 | ||
460 | it('Should run filter:html.embed.video.allowed.result', async function () { | 529 | it('Should run filter:html.embed.video.allowed.result', async function () { |
461 | const res = await makeRawRequest(servers[0].url + embedVideos[0].embedPath, 200) | 530 | const res = await makeGetRequest({ url: servers[0].url, path: embedVideos[0].embedPath, expectedStatus: HttpStatusCode.OK_200 }) |
462 | expect(res.text).to.equal('Lu Bu') | 531 | expect(res.text).to.equal('Lu Bu') |
463 | }) | 532 | }) |
464 | 533 | ||
465 | it('Should run filter:html.embed.video-playlist.allowed.result', async function () { | 534 | it('Should run filter:html.embed.video-playlist.allowed.result', async function () { |
466 | const res = await makeRawRequest(servers[0].url + embedPlaylists[0].embedPath, 200) | 535 | const res = await makeGetRequest({ url: servers[0].url, path: embedPlaylists[0].embedPath, expectedStatus: HttpStatusCode.OK_200 }) |
467 | expect(res.text).to.equal('Diao Chan') | 536 | expect(res.text).to.equal('Diao Chan') |
468 | }) | 537 | }) |
469 | }) | 538 | }) |
diff --git a/server/tests/plugins/id-and-pass-auth.ts b/server/tests/plugins/id-and-pass-auth.ts index 85faac5a8..fc24a5656 100644 --- a/server/tests/plugins/id-and-pass-auth.ts +++ b/server/tests/plugins/id-and-pass-auth.ts | |||
@@ -48,7 +48,7 @@ describe('Test id and pass auth plugins', function () { | |||
48 | 48 | ||
49 | expect(body.username).to.equal('spyro') | 49 | expect(body.username).to.equal('spyro') |
50 | expect(body.account.displayName).to.equal('Spyro the Dragon') | 50 | expect(body.account.displayName).to.equal('Spyro the Dragon') |
51 | expect(body.role).to.equal(UserRole.USER) | 51 | expect(body.role.id).to.equal(UserRole.USER) |
52 | }) | 52 | }) |
53 | 53 | ||
54 | it('Should login Crash, create the user and use the token', async function () { | 54 | it('Should login Crash, create the user and use the token', async function () { |
@@ -63,7 +63,7 @@ describe('Test id and pass auth plugins', function () { | |||
63 | 63 | ||
64 | expect(body.username).to.equal('crash') | 64 | expect(body.username).to.equal('crash') |
65 | expect(body.account.displayName).to.equal('Crash Bandicoot') | 65 | expect(body.account.displayName).to.equal('Crash Bandicoot') |
66 | expect(body.role).to.equal(UserRole.MODERATOR) | 66 | expect(body.role.id).to.equal(UserRole.MODERATOR) |
67 | } | 67 | } |
68 | }) | 68 | }) |
69 | 69 | ||
@@ -79,7 +79,7 @@ describe('Test id and pass auth plugins', function () { | |||
79 | 79 | ||
80 | expect(body.username).to.equal('laguna') | 80 | expect(body.username).to.equal('laguna') |
81 | expect(body.account.displayName).to.equal('laguna') | 81 | expect(body.account.displayName).to.equal('laguna') |
82 | expect(body.role).to.equal(UserRole.USER) | 82 | expect(body.role.id).to.equal(UserRole.USER) |
83 | } | 83 | } |
84 | }) | 84 | }) |
85 | 85 | ||
@@ -129,7 +129,7 @@ describe('Test id and pass auth plugins', function () { | |||
129 | expect(body.username).to.equal('crash') | 129 | expect(body.username).to.equal('crash') |
130 | expect(body.account.displayName).to.equal('Beautiful Crash') | 130 | expect(body.account.displayName).to.equal('Beautiful Crash') |
131 | expect(body.account.description).to.equal('Mutant eastern barred bandicoot') | 131 | expect(body.account.description).to.equal('Mutant eastern barred bandicoot') |
132 | expect(body.role).to.equal(UserRole.MODERATOR) | 132 | expect(body.role.id).to.equal(UserRole.MODERATOR) |
133 | }) | 133 | }) |
134 | 134 | ||
135 | it('Should reject token of laguna by the plugin hook', async function () { | 135 | it('Should reject token of laguna by the plugin hook', async function () { |
diff --git a/server/tests/plugins/index.ts b/server/tests/plugins/index.ts index 4534120fd..210af7236 100644 --- a/server/tests/plugins/index.ts +++ b/server/tests/plugins/index.ts | |||
@@ -8,5 +8,6 @@ import './plugin-router' | |||
8 | import './plugin-storage' | 8 | import './plugin-storage' |
9 | import './plugin-transcoding' | 9 | import './plugin-transcoding' |
10 | import './plugin-unloading' | 10 | import './plugin-unloading' |
11 | import './plugin-websocket' | ||
11 | import './translations' | 12 | import './translations' |
12 | import './video-constants' | 13 | import './video-constants' |
diff --git a/server/tests/plugins/plugin-helpers.ts b/server/tests/plugins/plugin-helpers.ts index 955d7ddfd..f2bada4ee 100644 --- a/server/tests/plugins/plugin-helpers.ts +++ b/server/tests/plugins/plugin-helpers.ts | |||
@@ -83,6 +83,33 @@ describe('Test plugin helpers', function () { | |||
83 | }) | 83 | }) |
84 | }) | 84 | }) |
85 | 85 | ||
86 | describe('Socket', function () { | ||
87 | |||
88 | it('Should sendNotification without any exceptions', async () => { | ||
89 | const user = await servers[0].users.create({ username: 'notis_redding', password: 'secret1234?' }) | ||
90 | await makePostBodyRequest({ | ||
91 | url: servers[0].url, | ||
92 | path: '/plugins/test-four/router/send-notification', | ||
93 | fields: { | ||
94 | userId: user.id | ||
95 | }, | ||
96 | expectedStatus: HttpStatusCode.CREATED_201 | ||
97 | }) | ||
98 | }) | ||
99 | |||
100 | it('Should sendVideoLiveNewState without any exceptions', async () => { | ||
101 | const res = await servers[0].videos.quickUpload({ name: 'video server 1' }) | ||
102 | |||
103 | await makePostBodyRequest({ | ||
104 | url: servers[0].url, | ||
105 | path: '/plugins/test-four/router/send-video-live-new-state/' + res.uuid, | ||
106 | expectedStatus: HttpStatusCode.CREATED_201 | ||
107 | }) | ||
108 | |||
109 | await servers[0].videos.remove({ id: res.uuid }) | ||
110 | }) | ||
111 | }) | ||
112 | |||
86 | describe('Plugin', function () { | 113 | describe('Plugin', function () { |
87 | 114 | ||
88 | it('Should get the base static route', async function () { | 115 | it('Should get the base static route', async function () { |
@@ -280,7 +307,7 @@ describe('Test plugin helpers', function () { | |||
280 | expect(file.fps).to.equal(25) | 307 | expect(file.fps).to.equal(25) |
281 | 308 | ||
282 | expect(await pathExists(file.path)).to.be.true | 309 | expect(await pathExists(file.path)).to.be.true |
283 | await makeRawRequest(file.url, HttpStatusCode.OK_200) | 310 | await makeRawRequest({ url: file.url, expectedStatus: HttpStatusCode.OK_200 }) |
284 | } | 311 | } |
285 | } | 312 | } |
286 | 313 | ||
@@ -294,12 +321,12 @@ describe('Test plugin helpers', function () { | |||
294 | const miniature = body.thumbnails.find(t => t.type === ThumbnailType.MINIATURE) | 321 | const miniature = body.thumbnails.find(t => t.type === ThumbnailType.MINIATURE) |
295 | expect(miniature).to.exist | 322 | expect(miniature).to.exist |
296 | expect(await pathExists(miniature.path)).to.be.true | 323 | expect(await pathExists(miniature.path)).to.be.true |
297 | await makeRawRequest(miniature.url, HttpStatusCode.OK_200) | 324 | await makeRawRequest({ url: miniature.url, expectedStatus: HttpStatusCode.OK_200 }) |
298 | 325 | ||
299 | const preview = body.thumbnails.find(t => t.type === ThumbnailType.PREVIEW) | 326 | const preview = body.thumbnails.find(t => t.type === ThumbnailType.PREVIEW) |
300 | expect(preview).to.exist | 327 | expect(preview).to.exist |
301 | expect(await pathExists(preview.path)).to.be.true | 328 | expect(await pathExists(preview.path)).to.be.true |
302 | await makeRawRequest(preview.url, HttpStatusCode.OK_200) | 329 | await makeRawRequest({ url: preview.url, expectedStatus: HttpStatusCode.OK_200 }) |
303 | } | 330 | } |
304 | }) | 331 | }) |
305 | 332 | ||
diff --git a/server/tests/plugins/plugin-websocket.ts b/server/tests/plugins/plugin-websocket.ts new file mode 100644 index 000000000..adaa28b1d --- /dev/null +++ b/server/tests/plugins/plugin-websocket.ts | |||
@@ -0,0 +1,70 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import WebSocket from 'ws' | ||
4 | import { cleanupTests, createSingleServer, PeerTubeServer, PluginsCommand, setAccessTokensToServers } from '@shared/server-commands' | ||
5 | |||
6 | function buildWebSocket (server: PeerTubeServer, path: string) { | ||
7 | return new WebSocket('ws://' + server.host + path) | ||
8 | } | ||
9 | |||
10 | function expectErrorOrTimeout (server: PeerTubeServer, path: string, expectedTimeout: number) { | ||
11 | return new Promise<void>((res, rej) => { | ||
12 | const ws = buildWebSocket(server, path) | ||
13 | ws.on('error', () => res()) | ||
14 | |||
15 | const timeout = setTimeout(() => res(), expectedTimeout) | ||
16 | |||
17 | ws.on('open', () => { | ||
18 | clearTimeout(timeout) | ||
19 | |||
20 | return rej(new Error('Connect did not timeout')) | ||
21 | }) | ||
22 | }) | ||
23 | } | ||
24 | |||
25 | describe('Test plugin websocket', function () { | ||
26 | let server: PeerTubeServer | ||
27 | const basePaths = [ | ||
28 | '/plugins/test-websocket/ws/', | ||
29 | '/plugins/test-websocket/0.0.1/ws/' | ||
30 | ] | ||
31 | |||
32 | before(async function () { | ||
33 | this.timeout(30000) | ||
34 | |||
35 | server = await createSingleServer(1) | ||
36 | await setAccessTokensToServers([ server ]) | ||
37 | |||
38 | await server.plugins.install({ path: PluginsCommand.getPluginTestPath('-websocket') }) | ||
39 | }) | ||
40 | |||
41 | it('Should not connect to the websocket without the appropriate path', async function () { | ||
42 | const paths = [ | ||
43 | '/plugins/unknown/ws/', | ||
44 | '/plugins/unknown/0.0.1/ws/' | ||
45 | ] | ||
46 | |||
47 | for (const path of paths) { | ||
48 | await expectErrorOrTimeout(server, path, 1000) | ||
49 | } | ||
50 | }) | ||
51 | |||
52 | it('Should not connect to the websocket without the appropriate sub path', async function () { | ||
53 | for (const path of basePaths) { | ||
54 | await expectErrorOrTimeout(server, path + '/unknown', 1000) | ||
55 | } | ||
56 | }) | ||
57 | |||
58 | it('Should connect to the websocket and receive pong', function (done) { | ||
59 | const ws = buildWebSocket(server, basePaths[0]) | ||
60 | |||
61 | ws.on('open', () => ws.send('ping')) | ||
62 | ws.on('message', data => { | ||
63 | if (data.toString() === 'pong') return done() | ||
64 | }) | ||
65 | }) | ||
66 | |||
67 | after(async function () { | ||
68 | await cleanupTests([ server ]) | ||
69 | }) | ||
70 | }) | ||
diff --git a/server/tests/shared/actors.ts b/server/tests/shared/actors.ts index f8f4a5137..41fd72e89 100644 --- a/server/tests/shared/actors.ts +++ b/server/tests/shared/actors.ts | |||
@@ -2,8 +2,6 @@ | |||
2 | 2 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { pathExists, readdir } from 'fs-extra' | 4 | import { pathExists, readdir } from 'fs-extra' |
5 | import { join } from 'path' | ||
6 | import { root } from '@shared/core-utils' | ||
7 | import { Account, VideoChannel } from '@shared/models' | 5 | import { Account, VideoChannel } from '@shared/models' |
8 | import { PeerTubeServer } from '@shared/server-commands' | 6 | import { PeerTubeServer } from '@shared/server-commands' |
9 | 7 | ||
@@ -31,11 +29,9 @@ async function expectAccountFollows (options: { | |||
31 | return expectActorFollow({ ...options, data }) | 29 | return expectActorFollow({ ...options, data }) |
32 | } | 30 | } |
33 | 31 | ||
34 | async function checkActorFilesWereRemoved (filename: string, serverNumber: number) { | 32 | async function checkActorFilesWereRemoved (filename: string, server: PeerTubeServer) { |
35 | const testDirectory = 'test' + serverNumber | ||
36 | |||
37 | for (const directory of [ 'avatars' ]) { | 33 | for (const directory of [ 'avatars' ]) { |
38 | const directoryPath = join(root(), testDirectory, directory) | 34 | const directoryPath = server.getDirectoryPath(directory) |
39 | 35 | ||
40 | const directoryExists = await pathExists(directoryPath) | 36 | const directoryExists = await pathExists(directoryPath) |
41 | expect(directoryExists).to.be.true | 37 | expect(directoryExists).to.be.true |
diff --git a/server/tests/shared/directories.ts b/server/tests/shared/directories.ts index c7065a767..90d534a06 100644 --- a/server/tests/shared/directories.ts +++ b/server/tests/shared/directories.ts | |||
@@ -2,22 +2,18 @@ | |||
2 | 2 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { pathExists, readdir } from 'fs-extra' | 4 | import { pathExists, readdir } from 'fs-extra' |
5 | import { join } from 'path' | ||
6 | import { root } from '@shared/core-utils' | ||
7 | import { PeerTubeServer } from '@shared/server-commands' | 5 | import { PeerTubeServer } from '@shared/server-commands' |
8 | 6 | ||
9 | async function checkTmpIsEmpty (server: PeerTubeServer) { | 7 | async function checkTmpIsEmpty (server: PeerTubeServer) { |
10 | await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls', 'resumable-uploads' ]) | 8 | await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls', 'resumable-uploads' ]) |
11 | 9 | ||
12 | if (await pathExists(join('test' + server.internalServerNumber, 'tmp', 'hls'))) { | 10 | if (await pathExists(server.getDirectoryPath('tmp/hls'))) { |
13 | await checkDirectoryIsEmpty(server, 'tmp/hls') | 11 | await checkDirectoryIsEmpty(server, 'tmp/hls') |
14 | } | 12 | } |
15 | } | 13 | } |
16 | 14 | ||
17 | async function checkDirectoryIsEmpty (server: PeerTubeServer, directory: string, exceptions: string[] = []) { | 15 | async function checkDirectoryIsEmpty (server: PeerTubeServer, directory: string, exceptions: string[] = []) { |
18 | const testDirectory = 'test' + server.internalServerNumber | 16 | const directoryPath = server.getDirectoryPath(directory) |
19 | |||
20 | const directoryPath = join(root(), testDirectory, directory) | ||
21 | 17 | ||
22 | const directoryExists = await pathExists(directoryPath) | 18 | const directoryExists = await pathExists(directoryPath) |
23 | expect(directoryExists).to.be.true | 19 | expect(directoryExists).to.be.true |
diff --git a/server/tests/shared/live.ts b/server/tests/shared/live.ts index 4bd4786fc..47e0dc481 100644 --- a/server/tests/shared/live.ts +++ b/server/tests/shared/live.ts | |||
@@ -3,39 +3,118 @@ | |||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { pathExists, readdir } from 'fs-extra' | 4 | import { pathExists, readdir } from 'fs-extra' |
5 | import { join } from 'path' | 5 | import { join } from 'path' |
6 | import { LiveVideo } from '@shared/models' | 6 | import { LiveVideo, VideoStreamingPlaylistType } from '@shared/models' |
7 | import { PeerTubeServer } from '@shared/server-commands' | 7 | import { ObjectStorageCommand, PeerTubeServer } from '@shared/server-commands' |
8 | 8 | import { checkLiveSegmentHash, checkResolutionsInMasterPlaylist } from './streaming-playlists' | |
9 | async function checkLiveCleanup (server: PeerTubeServer, videoUUID: string, savedResolutions: number[] = []) { | 9 | |
10 | let live: LiveVideo | 10 | async function checkLiveCleanup (options: { |
11 | 11 | server: PeerTubeServer | |
12 | try { | 12 | videoUUID: string |
13 | live = await server.live.get({ videoId: videoUUID }) | 13 | permanent: boolean |
14 | } catch {} | 14 | savedResolutions?: number[] |
15 | }) { | ||
16 | const { server, videoUUID, permanent, savedResolutions = [] } = options | ||
15 | 17 | ||
16 | const basePath = server.servers.buildDirectory('streaming-playlists') | 18 | const basePath = server.servers.buildDirectory('streaming-playlists') |
17 | const hlsPath = join(basePath, 'hls', videoUUID) | 19 | const hlsPath = join(basePath, 'hls', videoUUID) |
18 | 20 | ||
19 | if (savedResolutions.length === 0) { | 21 | if (permanent) { |
22 | if (!await pathExists(hlsPath)) return | ||
20 | 23 | ||
21 | if (live?.permanentLive) { | 24 | const files = await readdir(hlsPath) |
22 | expect(await pathExists(hlsPath)).to.be.true | 25 | expect(files).to.have.lengthOf(0) |
26 | return | ||
27 | } | ||
23 | 28 | ||
24 | const hlsFiles = await readdir(hlsPath) | 29 | if (savedResolutions.length === 0) { |
25 | expect(hlsFiles).to.have.lengthOf(1) // Only replays directory | 30 | return checkUnsavedLiveCleanup(server, videoUUID, hlsPath) |
31 | } | ||
26 | 32 | ||
27 | const replayDir = join(hlsPath, 'replay') | 33 | return checkSavedLiveCleanup(hlsPath, savedResolutions) |
28 | expect(await pathExists(replayDir)).to.be.true | 34 | } |
29 | 35 | ||
30 | const replayFiles = await readdir(join(hlsPath, 'replay')) | 36 | // --------------------------------------------------------------------------- |
31 | expect(replayFiles).to.have.lengthOf(0) | 37 | |
32 | } else { | 38 | async function testVideoResolutions (options: { |
33 | expect(await pathExists(hlsPath)).to.be.false | 39 | originServer: PeerTubeServer |
40 | servers: PeerTubeServer[] | ||
41 | liveVideoId: string | ||
42 | resolutions: number[] | ||
43 | transcoded: boolean | ||
44 | objectStorage: boolean | ||
45 | }) { | ||
46 | const { originServer, servers, liveVideoId, resolutions, transcoded, objectStorage } = options | ||
47 | |||
48 | for (const server of servers) { | ||
49 | const { data } = await server.videos.list() | ||
50 | expect(data.find(v => v.uuid === liveVideoId)).to.exist | ||
51 | |||
52 | const video = await server.videos.get({ id: liveVideoId }) | ||
53 | expect(video.streamingPlaylists).to.have.lengthOf(1) | ||
54 | |||
55 | const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS) | ||
56 | expect(hlsPlaylist).to.exist | ||
57 | expect(hlsPlaylist.files).to.have.lengthOf(0) // Only fragmented mp4 files are displayed | ||
58 | |||
59 | await checkResolutionsInMasterPlaylist({ | ||
60 | server, | ||
61 | playlistUrl: hlsPlaylist.playlistUrl, | ||
62 | resolutions, | ||
63 | transcoded, | ||
64 | withRetry: objectStorage | ||
65 | }) | ||
66 | |||
67 | if (objectStorage) { | ||
68 | expect(hlsPlaylist.playlistUrl).to.contain(ObjectStorageCommand.getMockPlaylistBaseUrl()) | ||
34 | } | 69 | } |
35 | 70 | ||
36 | return | 71 | for (let i = 0; i < resolutions.length; i++) { |
72 | const segmentNum = 3 | ||
73 | const segmentName = `${i}-00000${segmentNum}.ts` | ||
74 | await originServer.live.waitUntilSegmentGeneration({ | ||
75 | server: originServer, | ||
76 | videoUUID: video.uuid, | ||
77 | playlistNumber: i, | ||
78 | segment: segmentNum, | ||
79 | objectStorage | ||
80 | }) | ||
81 | |||
82 | const baseUrl = objectStorage | ||
83 | ? ObjectStorageCommand.getMockPlaylistBaseUrl() + 'hls' | ||
84 | : originServer.url + '/static/streaming-playlists/hls' | ||
85 | |||
86 | if (objectStorage) { | ||
87 | expect(hlsPlaylist.segmentsSha256Url).to.contain(ObjectStorageCommand.getMockPlaylistBaseUrl()) | ||
88 | } | ||
89 | |||
90 | const subPlaylist = await originServer.streamingPlaylists.get({ | ||
91 | url: `${baseUrl}/${video.uuid}/${i}.m3u8`, | ||
92 | withRetry: objectStorage // With object storage, the request may fail because of inconsistent data in S3 | ||
93 | }) | ||
94 | |||
95 | expect(subPlaylist).to.contain(segmentName) | ||
96 | |||
97 | await checkLiveSegmentHash({ | ||
98 | server, | ||
99 | baseUrlSegment: baseUrl, | ||
100 | videoUUID: video.uuid, | ||
101 | segmentName, | ||
102 | hlsPlaylist | ||
103 | }) | ||
104 | } | ||
37 | } | 105 | } |
106 | } | ||
107 | |||
108 | // --------------------------------------------------------------------------- | ||
109 | |||
110 | export { | ||
111 | checkLiveCleanup, | ||
112 | testVideoResolutions | ||
113 | } | ||
114 | |||
115 | // --------------------------------------------------------------------------- | ||
38 | 116 | ||
117 | async function checkSavedLiveCleanup (hlsPath: string, savedResolutions: number[] = []) { | ||
39 | const files = await readdir(hlsPath) | 118 | const files = await readdir(hlsPath) |
40 | 119 | ||
41 | // fragmented file and playlist per resolution + master playlist + segments sha256 json file | 120 | // fragmented file and playlist per resolution + master playlist + segments sha256 json file |
@@ -56,6 +135,27 @@ async function checkLiveCleanup (server: PeerTubeServer, videoUUID: string, save | |||
56 | expect(shaFile).to.exist | 135 | expect(shaFile).to.exist |
57 | } | 136 | } |
58 | 137 | ||
59 | export { | 138 | async function checkUnsavedLiveCleanup (server: PeerTubeServer, videoUUID: string, hlsPath: string) { |
60 | checkLiveCleanup | 139 | let live: LiveVideo |
140 | |||
141 | try { | ||
142 | live = await server.live.get({ videoId: videoUUID }) | ||
143 | } catch {} | ||
144 | |||
145 | if (live?.permanentLive) { | ||
146 | expect(await pathExists(hlsPath)).to.be.true | ||
147 | |||
148 | const hlsFiles = await readdir(hlsPath) | ||
149 | expect(hlsFiles).to.have.lengthOf(1) // Only replays directory | ||
150 | |||
151 | const replayDir = join(hlsPath, 'replay') | ||
152 | expect(await pathExists(replayDir)).to.be.true | ||
153 | |||
154 | const replayFiles = await readdir(join(hlsPath, 'replay')) | ||
155 | expect(replayFiles).to.have.lengthOf(0) | ||
156 | |||
157 | return | ||
158 | } | ||
159 | |||
160 | expect(await pathExists(hlsPath)).to.be.false | ||
61 | } | 161 | } |
diff --git a/server/tests/shared/mock-servers/mock-object-storage.ts b/server/tests/shared/mock-servers/mock-object-storage.ts index 99d68e014..8c325bf11 100644 --- a/server/tests/shared/mock-servers/mock-object-storage.ts +++ b/server/tests/shared/mock-servers/mock-object-storage.ts | |||
@@ -12,7 +12,7 @@ export class MockObjectStorage { | |||
12 | const app = express() | 12 | const app = express() |
13 | 13 | ||
14 | app.get('/:bucketName/:path(*)', (req: express.Request, res: express.Response, next: express.NextFunction) => { | 14 | app.get('/:bucketName/:path(*)', (req: express.Request, res: express.Response, next: express.NextFunction) => { |
15 | const url = `http://${req.params.bucketName}.${ObjectStorageCommand.getEndpointHost()}/${req.params.path}` | 15 | const url = `http://${req.params.bucketName}.${ObjectStorageCommand.getMockEndpointHost()}/${req.params.path}` |
16 | 16 | ||
17 | if (process.env.DEBUG) { | 17 | if (process.env.DEBUG) { |
18 | console.log('Receiving request on mocked server %s.', req.url) | 18 | console.log('Receiving request on mocked server %s.', req.url) |
diff --git a/server/tests/shared/playlists.ts b/server/tests/shared/playlists.ts index fdd541d20..8db303fd8 100644 --- a/server/tests/shared/playlists.ts +++ b/server/tests/shared/playlists.ts | |||
@@ -1,17 +1,14 @@ | |||
1 | import { expect } from 'chai' | 1 | import { expect } from 'chai' |
2 | import { readdir } from 'fs-extra' | 2 | import { readdir } from 'fs-extra' |
3 | import { join } from 'path' | 3 | import { PeerTubeServer } from '@shared/server-commands' |
4 | import { root } from '@shared/core-utils' | ||
5 | 4 | ||
6 | async function checkPlaylistFilesWereRemoved ( | 5 | async function checkPlaylistFilesWereRemoved ( |
7 | playlistUUID: string, | 6 | playlistUUID: string, |
8 | internalServerNumber: number, | 7 | server: PeerTubeServer, |
9 | directories = [ 'thumbnails' ] | 8 | directories = [ 'thumbnails' ] |
10 | ) { | 9 | ) { |
11 | const testDirectory = 'test' + internalServerNumber | ||
12 | |||
13 | for (const directory of directories) { | 10 | for (const directory of directories) { |
14 | const directoryPath = join(root(), testDirectory, directory) | 11 | const directoryPath = server.getDirectoryPath(directory) |
15 | 12 | ||
16 | const files = await readdir(directoryPath) | 13 | const files = await readdir(directoryPath) |
17 | for (const file of files) { | 14 | for (const file of files) { |
diff --git a/server/tests/shared/streaming-playlists.ts b/server/tests/shared/streaming-playlists.ts index 4d82b3654..824c3dcef 100644 --- a/server/tests/shared/streaming-playlists.ts +++ b/server/tests/shared/streaming-playlists.ts | |||
@@ -1,9 +1,13 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
1 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
2 | import { basename } from 'path' | 4 | import { basename } from 'path' |
3 | import { removeFragmentedMP4Ext } from '@shared/core-utils' | 5 | import { removeFragmentedMP4Ext, uuidRegex } from '@shared/core-utils' |
4 | import { sha256 } from '@shared/extra-utils' | 6 | import { sha256 } from '@shared/extra-utils' |
5 | import { HttpStatusCode, VideoStreamingPlaylist } from '@shared/models' | 7 | import { HttpStatusCode, VideoStreamingPlaylist, VideoStreamingPlaylistType } from '@shared/models' |
6 | import { PeerTubeServer } from '@shared/server-commands' | 8 | import { makeRawRequest, PeerTubeServer, webtorrentAdd } from '@shared/server-commands' |
9 | import { expectStartWith } from './checks' | ||
10 | import { hlsInfohashExist } from './tracker' | ||
7 | 11 | ||
8 | async function checkSegmentHash (options: { | 12 | async function checkSegmentHash (options: { |
9 | server: PeerTubeServer | 13 | server: PeerTubeServer |
@@ -26,7 +30,7 @@ async function checkSegmentHash (options: { | |||
26 | const offset = parseInt(matches[2], 10) | 30 | const offset = parseInt(matches[2], 10) |
27 | const range = `${offset}-${offset + length - 1}` | 31 | const range = `${offset}-${offset + length - 1}` |
28 | 32 | ||
29 | const segmentBody = await command.getSegment({ | 33 | const segmentBody = await command.getFragmentedSegment({ |
30 | url: `${baseUrlSegment}/${videoName}`, | 34 | url: `${baseUrlSegment}/${videoName}`, |
31 | expectedStatus: HttpStatusCode.PARTIAL_CONTENT_206, | 35 | expectedStatus: HttpStatusCode.PARTIAL_CONTENT_206, |
32 | range: `bytes=${range}` | 36 | range: `bytes=${range}` |
@@ -46,7 +50,7 @@ async function checkLiveSegmentHash (options: { | |||
46 | const { server, baseUrlSegment, videoUUID, segmentName, hlsPlaylist } = options | 50 | const { server, baseUrlSegment, videoUUID, segmentName, hlsPlaylist } = options |
47 | const command = server.streamingPlaylists | 51 | const command = server.streamingPlaylists |
48 | 52 | ||
49 | const segmentBody = await command.getSegment({ url: `${baseUrlSegment}/${videoUUID}/${segmentName}` }) | 53 | const segmentBody = await command.getFragmentedSegment({ url: `${baseUrlSegment}/${videoUUID}/${segmentName}` }) |
50 | const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url }) | 54 | const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url }) |
51 | 55 | ||
52 | expect(sha256(segmentBody)).to.equal(shaBody[segmentName]) | 56 | expect(sha256(segmentBody)).to.equal(shaBody[segmentName]) |
@@ -56,15 +60,17 @@ async function checkResolutionsInMasterPlaylist (options: { | |||
56 | server: PeerTubeServer | 60 | server: PeerTubeServer |
57 | playlistUrl: string | 61 | playlistUrl: string |
58 | resolutions: number[] | 62 | resolutions: number[] |
63 | transcoded?: boolean // default true | ||
64 | withRetry?: boolean // default false | ||
59 | }) { | 65 | }) { |
60 | const { server, playlistUrl, resolutions } = options | 66 | const { server, playlistUrl, resolutions, withRetry = false, transcoded = true } = options |
61 | 67 | ||
62 | const masterPlaylist = await server.streamingPlaylists.get({ url: playlistUrl }) | 68 | const masterPlaylist = await server.streamingPlaylists.get({ url: playlistUrl, withRetry }) |
63 | 69 | ||
64 | for (const resolution of resolutions) { | 70 | for (const resolution of resolutions) { |
65 | const reg = new RegExp( | 71 | const reg = transcoded |
66 | '#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',(FRAME-RATE=\\d+,)?CODECS="avc1.64001f,mp4a.40.2"' | 72 | ? new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',(FRAME-RATE=\\d+,)?CODECS="avc1.64001f,mp4a.40.2"') |
67 | ) | 73 | : new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + '') |
68 | 74 | ||
69 | expect(masterPlaylist).to.match(reg) | 75 | expect(masterPlaylist).to.match(reg) |
70 | } | 76 | } |
@@ -73,8 +79,118 @@ async function checkResolutionsInMasterPlaylist (options: { | |||
73 | expect(playlistsLength).to.have.lengthOf(resolutions.length) | 79 | expect(playlistsLength).to.have.lengthOf(resolutions.length) |
74 | } | 80 | } |
75 | 81 | ||
82 | async function completeCheckHlsPlaylist (options: { | ||
83 | servers: PeerTubeServer[] | ||
84 | videoUUID: string | ||
85 | hlsOnly: boolean | ||
86 | |||
87 | resolutions?: number[] | ||
88 | objectStorageBaseUrl: string | ||
89 | }) { | ||
90 | const { videoUUID, hlsOnly, objectStorageBaseUrl } = options | ||
91 | |||
92 | const resolutions = options.resolutions ?? [ 240, 360, 480, 720 ] | ||
93 | |||
94 | for (const server of options.servers) { | ||
95 | const videoDetails = await server.videos.get({ id: videoUUID }) | ||
96 | const baseUrl = `http://${videoDetails.account.host}` | ||
97 | |||
98 | expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) | ||
99 | |||
100 | const hlsPlaylist = videoDetails.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) | ||
101 | expect(hlsPlaylist).to.not.be.undefined | ||
102 | |||
103 | const hlsFiles = hlsPlaylist.files | ||
104 | expect(hlsFiles).to.have.lengthOf(resolutions.length) | ||
105 | |||
106 | if (hlsOnly) expect(videoDetails.files).to.have.lengthOf(0) | ||
107 | else expect(videoDetails.files).to.have.lengthOf(resolutions.length) | ||
108 | |||
109 | // Check JSON files | ||
110 | for (const resolution of resolutions) { | ||
111 | const file = hlsFiles.find(f => f.resolution.id === resolution) | ||
112 | expect(file).to.not.be.undefined | ||
113 | |||
114 | expect(file.magnetUri).to.have.lengthOf.above(2) | ||
115 | expect(file.torrentUrl).to.match( | ||
116 | new RegExp(`${server.url}/lazy-static/torrents/${uuidRegex}-${file.resolution.id}-hls.torrent`) | ||
117 | ) | ||
118 | |||
119 | if (objectStorageBaseUrl) { | ||
120 | expectStartWith(file.fileUrl, objectStorageBaseUrl) | ||
121 | } else { | ||
122 | expect(file.fileUrl).to.match( | ||
123 | new RegExp(`${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${uuidRegex}-${file.resolution.id}-fragmented.mp4`) | ||
124 | ) | ||
125 | } | ||
126 | |||
127 | expect(file.resolution.label).to.equal(resolution + 'p') | ||
128 | |||
129 | await makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
130 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
131 | |||
132 | const torrent = await webtorrentAdd(file.magnetUri, true) | ||
133 | expect(torrent.files).to.be.an('array') | ||
134 | expect(torrent.files.length).to.equal(1) | ||
135 | expect(torrent.files[0].path).to.exist.and.to.not.equal('') | ||
136 | } | ||
137 | |||
138 | // Check master playlist | ||
139 | { | ||
140 | await checkResolutionsInMasterPlaylist({ server, playlistUrl: hlsPlaylist.playlistUrl, resolutions }) | ||
141 | |||
142 | const masterPlaylist = await server.streamingPlaylists.get({ url: hlsPlaylist.playlistUrl }) | ||
143 | |||
144 | let i = 0 | ||
145 | for (const resolution of resolutions) { | ||
146 | expect(masterPlaylist).to.contain(`${resolution}.m3u8`) | ||
147 | expect(masterPlaylist).to.contain(`${resolution}.m3u8`) | ||
148 | |||
149 | const url = 'http://' + videoDetails.account.host | ||
150 | await hlsInfohashExist(url, hlsPlaylist.playlistUrl, i) | ||
151 | |||
152 | i++ | ||
153 | } | ||
154 | } | ||
155 | |||
156 | // Check resolution playlists | ||
157 | { | ||
158 | for (const resolution of resolutions) { | ||
159 | const file = hlsFiles.find(f => f.resolution.id === resolution) | ||
160 | const playlistName = removeFragmentedMP4Ext(basename(file.fileUrl)) + '.m3u8' | ||
161 | |||
162 | const url = objectStorageBaseUrl | ||
163 | ? `${objectStorageBaseUrl}hls/${videoUUID}/${playlistName}` | ||
164 | : `${baseUrl}/static/streaming-playlists/hls/${videoUUID}/${playlistName}` | ||
165 | |||
166 | const subPlaylist = await server.streamingPlaylists.get({ url }) | ||
167 | |||
168 | expect(subPlaylist).to.match(new RegExp(`${uuidRegex}-${resolution}-fragmented.mp4`)) | ||
169 | expect(subPlaylist).to.contain(basename(file.fileUrl)) | ||
170 | } | ||
171 | } | ||
172 | |||
173 | { | ||
174 | const baseUrlAndPath = objectStorageBaseUrl | ||
175 | ? objectStorageBaseUrl + 'hls/' + videoUUID | ||
176 | : baseUrl + '/static/streaming-playlists/hls/' + videoUUID | ||
177 | |||
178 | for (const resolution of resolutions) { | ||
179 | await checkSegmentHash({ | ||
180 | server, | ||
181 | baseUrlPlaylist: baseUrlAndPath, | ||
182 | baseUrlSegment: baseUrlAndPath, | ||
183 | resolution, | ||
184 | hlsPlaylist | ||
185 | }) | ||
186 | } | ||
187 | } | ||
188 | } | ||
189 | } | ||
190 | |||
76 | export { | 191 | export { |
77 | checkSegmentHash, | 192 | checkSegmentHash, |
78 | checkLiveSegmentHash, | 193 | checkLiveSegmentHash, |
79 | checkResolutionsInMasterPlaylist | 194 | checkResolutionsInMasterPlaylist, |
195 | completeCheckHlsPlaylist | ||
80 | } | 196 | } |
diff --git a/server/tests/shared/videos.ts b/server/tests/shared/videos.ts index e18329e07..c8339584b 100644 --- a/server/tests/shared/videos.ts +++ b/server/tests/shared/videos.ts | |||
@@ -125,9 +125,9 @@ async function completeVideoCheck ( | |||
125 | expect(file.fileDownloadUrl).to.match(new RegExp(`http://${originHost}/download/videos/${uuidRegex}-${file.resolution.id}${extension}`)) | 125 | expect(file.fileDownloadUrl).to.match(new RegExp(`http://${originHost}/download/videos/${uuidRegex}-${file.resolution.id}${extension}`)) |
126 | 126 | ||
127 | await Promise.all([ | 127 | await Promise.all([ |
128 | makeRawRequest(file.torrentUrl, 200), | 128 | makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 }), |
129 | makeRawRequest(file.torrentDownloadUrl, 200), | 129 | makeRawRequest({ url: file.torrentDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }), |
130 | makeRawRequest(file.metadataUrl, 200) | 130 | makeRawRequest({ url: file.metadataUrl, expectedStatus: HttpStatusCode.OK_200 }) |
131 | ]) | 131 | ]) |
132 | 132 | ||
133 | expect(file.resolution.id).to.equal(attributeFile.resolution) | 133 | expect(file.resolution.id).to.equal(attributeFile.resolution) |