diff options
Diffstat (limited to 'server/tests/api')
45 files changed, 2190 insertions, 485 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..c0bb8d529 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 | } |
@@ -111,7 +130,7 @@ describe('Fast restream in live', function () { | |||
111 | }) | 130 | }) |
112 | 131 | ||
113 | it('Should correctly fast reastream in a permanent live with and without save replay', async function () { | 132 | it('Should correctly fast reastream in a permanent live with and without save replay', async function () { |
114 | this.timeout(240000) | 133 | this.timeout(480000) |
115 | 134 | ||
116 | // A test can take a long time, so prefer to run them in parallel | 135 | // A test can take a long time, so prefer to run them in parallel |
117 | await Promise.all([ | 136 | await Promise.all([ |
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/audio-only.ts b/server/tests/api/transcoding/audio-only.ts index 1897c6d6d..b72f5fdbe 100644 --- a/server/tests/api/transcoding/audio-only.ts +++ b/server/tests/api/transcoding/audio-only.ts | |||
@@ -89,7 +89,12 @@ describe('Test audio only video transcoding', function () { | |||
89 | expect(audioStream['bit_rate']).to.be.at.most(384 * 8000) | 89 | expect(audioStream['bit_rate']).to.be.at.most(384 * 8000) |
90 | 90 | ||
91 | const size = await getVideoStreamDimensionsInfo(path) | 91 | const size = await getVideoStreamDimensionsInfo(path) |
92 | expect(size).to.not.exist | 92 | |
93 | expect(size.height).to.equal(0) | ||
94 | expect(size.width).to.equal(0) | ||
95 | expect(size.isPortraitMode).to.be.false | ||
96 | expect(size.ratio).to.equal(0) | ||
97 | expect(size.resolution).to.equal(0) | ||
93 | } | 98 | } |
94 | }) | 99 | }) |
95 | 100 | ||
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/api/views/video-views-counter.ts b/server/tests/api/views/video-views-counter.ts index ca33ff9cd..0c1b7859c 100644 --- a/server/tests/api/views/video-views-counter.ts +++ b/server/tests/api/views/video-views-counter.ts | |||
@@ -76,7 +76,7 @@ describe('Test video views/viewers counters', function () { | |||
76 | let command: FfmpegCommand | 76 | let command: FfmpegCommand |
77 | 77 | ||
78 | before(async function () { | 78 | before(async function () { |
79 | this.timeout(120000); | 79 | this.timeout(240000); |
80 | 80 | ||
81 | ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true })) | 81 | ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true })) |
82 | }) | 82 | }) |
diff --git a/server/tests/api/views/video-views-overall-stats.ts b/server/tests/api/views/video-views-overall-stats.ts index bb00684ef..3aadc9689 100644 --- a/server/tests/api/views/video-views-overall-stats.ts +++ b/server/tests/api/views/video-views-overall-stats.ts | |||
@@ -20,7 +20,7 @@ describe('Test views overall stats', function () { | |||
20 | let command: FfmpegCommand | 20 | let command: FfmpegCommand |
21 | 21 | ||
22 | before(async function () { | 22 | before(async function () { |
23 | this.timeout(120000); | 23 | this.timeout(240000); |
24 | 24 | ||
25 | ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true })) | 25 | ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true })) |
26 | }) | 26 | }) |
@@ -179,7 +179,7 @@ describe('Test views overall stats', function () { | |||
179 | let before2Watchers: Date | 179 | let before2Watchers: Date |
180 | 180 | ||
181 | before(async function () { | 181 | before(async function () { |
182 | this.timeout(120000); | 182 | this.timeout(240000); |
183 | 183 | ||
184 | ({ vodVideoId: videoUUID } = await prepareViewsVideos({ servers, live: true, vod: true })) | 184 | ({ vodVideoId: videoUUID } = await prepareViewsVideos({ servers, live: true, vod: true })) |
185 | }) | 185 | }) |
diff --git a/server/tests/api/views/video-views-retention-stats.ts b/server/tests/api/views/video-views-retention-stats.ts index 621b05110..5b9ce4c92 100644 --- a/server/tests/api/views/video-views-retention-stats.ts +++ b/server/tests/api/views/video-views-retention-stats.ts | |||
@@ -17,7 +17,7 @@ describe('Test views retention stats', function () { | |||
17 | let vodVideoId: string | 17 | let vodVideoId: string |
18 | 18 | ||
19 | before(async function () { | 19 | before(async function () { |
20 | this.timeout(120000); | 20 | this.timeout(240000); |
21 | 21 | ||
22 | ({ vodVideoId } = await prepareViewsVideos({ servers, live: false, vod: true })) | 22 | ({ vodVideoId } = await prepareViewsVideos({ servers, live: false, vod: true })) |
23 | }) | 23 | }) |
diff --git a/server/tests/api/views/video-views-timeserie-stats.ts b/server/tests/api/views/video-views-timeserie-stats.ts index e8cb34ad6..2d991d7ea 100644 --- a/server/tests/api/views/video-views-timeserie-stats.ts +++ b/server/tests/api/views/video-views-timeserie-stats.ts | |||
@@ -30,7 +30,7 @@ describe('Test views timeserie stats', function () { | |||
30 | let vodVideoId: string | 30 | let vodVideoId: string |
31 | 31 | ||
32 | before(async function () { | 32 | before(async function () { |
33 | this.timeout(120000); | 33 | this.timeout(240000); |
34 | 34 | ||
35 | ({ vodVideoId } = await prepareViewsVideos({ servers, live: false, vod: true })) | 35 | ({ vodVideoId } = await prepareViewsVideos({ servers, live: false, vod: true })) |
36 | }) | 36 | }) |
@@ -81,7 +81,7 @@ describe('Test views timeserie stats', function () { | |||
81 | } | 81 | } |
82 | 82 | ||
83 | before(async function () { | 83 | before(async function () { |
84 | this.timeout(120000); | 84 | this.timeout(240000); |
85 | 85 | ||
86 | ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true })) | 86 | ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true })) |
87 | }) | 87 | }) |