diff options
Diffstat (limited to 'server/tests/api/videos/video-source.ts')
-rw-r--r-- | server/tests/api/videos/video-source.ts | 447 |
1 files changed, 429 insertions, 18 deletions
diff --git a/server/tests/api/videos/video-source.ts b/server/tests/api/videos/video-source.ts index 5ecf8316f..8669f342e 100644 --- a/server/tests/api/videos/video-source.ts +++ b/server/tests/api/videos/video-source.ts | |||
@@ -1,36 +1,447 @@ | |||
1 | import { expect } from 'chai' | 1 | import { expect } from 'chai' |
2 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | 2 | import { expectStartWith } from '@server/tests/shared' |
3 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
4 | import { areMockObjectStorageTestsDisabled, getAllFiles } from '@shared/core-utils' | ||
5 | import { HttpStatusCode } from '@shared/models' | ||
6 | import { | ||
7 | cleanupTests, | ||
8 | createMultipleServers, | ||
9 | doubleFollow, | ||
10 | makeGetRequest, | ||
11 | makeRawRequest, | ||
12 | ObjectStorageCommand, | ||
13 | PeerTubeServer, | ||
14 | setAccessTokensToServers, | ||
15 | setDefaultAccountAvatar, | ||
16 | setDefaultVideoChannel, | ||
17 | waitJobs | ||
18 | } from '@shared/server-commands' | ||
3 | 19 | ||
4 | describe('Test video source', () => { | 20 | describe('Test a video file replacement', function () { |
5 | let server: PeerTubeServer = null | 21 | let servers: PeerTubeServer[] = [] |
6 | const fixture = 'video_short.webm' | 22 | |
23 | let replaceDate: Date | ||
24 | let userToken: string | ||
25 | let uuid: string | ||
7 | 26 | ||
8 | before(async function () { | 27 | before(async function () { |
9 | this.timeout(30000) | 28 | this.timeout(50000) |
29 | |||
30 | servers = await createMultipleServers(2) | ||
31 | |||
32 | // Get the access tokens | ||
33 | await setAccessTokensToServers(servers) | ||
34 | await setDefaultVideoChannel(servers) | ||
35 | await setDefaultAccountAvatar(servers) | ||
36 | |||
37 | await servers[0].config.enableFileUpdate() | ||
10 | 38 | ||
11 | server = await createSingleServer(1) | 39 | userToken = await servers[0].users.generateUserAndToken('user1') |
12 | await setAccessTokensToServers([ server ]) | 40 | |
41 | // Server 1 and server 2 follow each other | ||
42 | await doubleFollow(servers[0], servers[1]) | ||
13 | }) | 43 | }) |
14 | 44 | ||
15 | it('Should get the source filename with legacy upload', async function () { | 45 | describe('Getting latest video source', () => { |
16 | this.timeout(30000) | 46 | const fixture = 'video_short.webm' |
47 | const uuids: string[] = [] | ||
48 | |||
49 | it('Should get the source filename with legacy upload', async function () { | ||
50 | this.timeout(30000) | ||
51 | |||
52 | const { uuid } = await servers[0].videos.upload({ attributes: { name: 'my video', fixture }, mode: 'legacy' }) | ||
53 | uuids.push(uuid) | ||
17 | 54 | ||
18 | const { uuid } = await server.videos.upload({ attributes: { name: 'my video', fixture }, mode: 'legacy' }) | 55 | const source = await servers[0].videos.getSource({ id: uuid }) |
56 | expect(source.filename).to.equal(fixture) | ||
57 | }) | ||
19 | 58 | ||
20 | const source = await server.videos.getSource({ id: uuid }) | 59 | it('Should get the source filename with resumable upload', async function () { |
21 | expect(source.filename).to.equal(fixture) | 60 | this.timeout(30000) |
61 | |||
62 | const { uuid } = await servers[0].videos.upload({ attributes: { name: 'my video', fixture }, mode: 'resumable' }) | ||
63 | uuids.push(uuid) | ||
64 | |||
65 | const source = await servers[0].videos.getSource({ id: uuid }) | ||
66 | expect(source.filename).to.equal(fixture) | ||
67 | }) | ||
68 | |||
69 | after(async function () { | ||
70 | this.timeout(60000) | ||
71 | |||
72 | for (const uuid of uuids) { | ||
73 | await servers[0].videos.remove({ id: uuid }) | ||
74 | } | ||
75 | |||
76 | await waitJobs(servers) | ||
77 | }) | ||
22 | }) | 78 | }) |
23 | 79 | ||
24 | it('Should get the source filename with resumable upload', async function () { | 80 | describe('Updating video source', function () { |
25 | this.timeout(30000) | 81 | |
82 | describe('Filesystem', function () { | ||
83 | |||
84 | it('Should replace a video file with transcoding disabled', async function () { | ||
85 | this.timeout(120000) | ||
86 | |||
87 | await servers[0].config.disableTranscoding() | ||
88 | |||
89 | const { uuid } = await servers[0].videos.quickUpload({ name: 'fs without transcoding', fixture: 'video_short_720p.mp4' }) | ||
90 | await waitJobs(servers) | ||
91 | |||
92 | for (const server of servers) { | ||
93 | const video = await server.videos.get({ id: uuid }) | ||
94 | |||
95 | const files = getAllFiles(video) | ||
96 | expect(files).to.have.lengthOf(1) | ||
97 | expect(files[0].resolution.id).to.equal(720) | ||
98 | } | ||
99 | |||
100 | await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' }) | ||
101 | await waitJobs(servers) | ||
102 | |||
103 | for (const server of servers) { | ||
104 | const video = await server.videos.get({ id: uuid }) | ||
105 | |||
106 | const files = getAllFiles(video) | ||
107 | expect(files).to.have.lengthOf(1) | ||
108 | expect(files[0].resolution.id).to.equal(360) | ||
109 | } | ||
110 | }) | ||
111 | |||
112 | it('Should replace a video file with transcoding enabled', async function () { | ||
113 | this.timeout(120000) | ||
114 | |||
115 | const previousPaths: string[] = [] | ||
116 | |||
117 | await servers[0].config.enableTranscoding(true, true, true) | ||
118 | |||
119 | const { uuid: videoUUID } = await servers[0].videos.quickUpload({ name: 'fs with transcoding', fixture: 'video_short_720p.mp4' }) | ||
120 | uuid = videoUUID | ||
121 | |||
122 | await waitJobs(servers) | ||
123 | |||
124 | for (const server of servers) { | ||
125 | const video = await server.videos.get({ id: uuid }) | ||
126 | expect(video.inputFileUpdatedAt).to.be.null | ||
127 | |||
128 | const files = getAllFiles(video) | ||
129 | expect(files).to.have.lengthOf(6 * 2) | ||
130 | |||
131 | // Grab old paths to ensure we'll regenerate | ||
132 | |||
133 | previousPaths.push(video.previewPath) | ||
134 | previousPaths.push(video.thumbnailPath) | ||
135 | |||
136 | for (const file of files) { | ||
137 | previousPaths.push(file.fileUrl) | ||
138 | previousPaths.push(file.torrentUrl) | ||
139 | previousPaths.push(file.metadataUrl) | ||
140 | |||
141 | const metadata = await server.videos.getFileMetadata({ url: file.metadataUrl }) | ||
142 | previousPaths.push(JSON.stringify(metadata)) | ||
143 | } | ||
144 | |||
145 | const { storyboards } = await server.storyboard.list({ id: uuid }) | ||
146 | for (const s of storyboards) { | ||
147 | previousPaths.push(s.storyboardPath) | ||
148 | } | ||
149 | } | ||
150 | |||
151 | replaceDate = new Date() | ||
152 | |||
153 | await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' }) | ||
154 | await waitJobs(servers) | ||
155 | |||
156 | for (const server of servers) { | ||
157 | const video = await server.videos.get({ id: uuid }) | ||
158 | |||
159 | expect(video.inputFileUpdatedAt).to.not.be.null | ||
160 | expect(new Date(video.inputFileUpdatedAt)).to.be.above(replaceDate) | ||
161 | |||
162 | const files = getAllFiles(video) | ||
163 | expect(files).to.have.lengthOf(4 * 2) | ||
164 | |||
165 | expect(previousPaths).to.not.include(video.previewPath) | ||
166 | expect(previousPaths).to.not.include(video.thumbnailPath) | ||
167 | |||
168 | await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 }) | ||
169 | await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) | ||
170 | |||
171 | for (const file of files) { | ||
172 | expect(previousPaths).to.not.include(file.fileUrl) | ||
173 | expect(previousPaths).to.not.include(file.torrentUrl) | ||
174 | expect(previousPaths).to.not.include(file.metadataUrl) | ||
175 | |||
176 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
177 | await makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
178 | |||
179 | const metadata = await server.videos.getFileMetadata({ url: file.metadataUrl }) | ||
180 | expect(previousPaths).to.not.include(JSON.stringify(metadata)) | ||
181 | } | ||
182 | |||
183 | const { storyboards } = await server.storyboard.list({ id: uuid }) | ||
184 | for (const s of storyboards) { | ||
185 | expect(previousPaths).to.not.include(s.storyboardPath) | ||
186 | |||
187 | await makeGetRequest({ url: server.url, path: s.storyboardPath, expectedStatus: HttpStatusCode.OK_200 }) | ||
188 | } | ||
189 | } | ||
190 | |||
191 | await servers[0].config.enableMinimumTranscoding() | ||
192 | }) | ||
193 | |||
194 | it('Should have cleaned up old files', async function () { | ||
195 | { | ||
196 | const count = await servers[0].servers.countFiles('storyboards') | ||
197 | expect(count).to.equal(2) | ||
198 | } | ||
199 | |||
200 | { | ||
201 | const count = await servers[0].servers.countFiles('web-videos') | ||
202 | expect(count).to.equal(5 + 1) // +1 for private directory | ||
203 | } | ||
204 | |||
205 | { | ||
206 | const count = await servers[0].servers.countFiles('streaming-playlists/hls') | ||
207 | expect(count).to.equal(1 + 1) // +1 for private directory | ||
208 | } | ||
209 | |||
210 | { | ||
211 | const count = await servers[0].servers.countFiles('torrents') | ||
212 | expect(count).to.equal(9) | ||
213 | } | ||
214 | }) | ||
215 | |||
216 | it('Should have the correct source input', async function () { | ||
217 | const source = await servers[0].videos.getSource({ id: uuid }) | ||
218 | |||
219 | expect(source.filename).to.equal('video_short_360p.mp4') | ||
220 | expect(new Date(source.createdAt)).to.be.above(replaceDate) | ||
221 | }) | ||
222 | |||
223 | it('Should not have regenerated miniatures that were previously uploaded', async function () { | ||
224 | this.timeout(120000) | ||
225 | |||
226 | const { uuid } = await servers[0].videos.upload({ | ||
227 | attributes: { | ||
228 | name: 'custom miniatures', | ||
229 | thumbnailfile: 'custom-thumbnail.jpg', | ||
230 | previewfile: 'custom-preview.jpg' | ||
231 | } | ||
232 | }) | ||
233 | |||
234 | await waitJobs(servers) | ||
235 | |||
236 | const previousPaths: string[] = [] | ||
237 | |||
238 | for (const server of servers) { | ||
239 | const video = await server.videos.get({ id: uuid }) | ||
240 | |||
241 | previousPaths.push(video.previewPath) | ||
242 | previousPaths.push(video.thumbnailPath) | ||
243 | |||
244 | await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 }) | ||
245 | await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) | ||
246 | } | ||
247 | |||
248 | await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' }) | ||
249 | await waitJobs(servers) | ||
250 | |||
251 | for (const server of servers) { | ||
252 | const video = await server.videos.get({ id: uuid }) | ||
253 | |||
254 | expect(previousPaths).to.include(video.previewPath) | ||
255 | expect(previousPaths).to.include(video.thumbnailPath) | ||
256 | |||
257 | await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 }) | ||
258 | await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) | ||
259 | } | ||
260 | }) | ||
261 | }) | ||
262 | |||
263 | describe('Autoblacklist', function () { | ||
264 | |||
265 | function updateAutoBlacklist (enabled: boolean) { | ||
266 | return servers[0].config.updateExistingSubConfig({ | ||
267 | newConfig: { | ||
268 | autoBlacklist: { | ||
269 | videos: { | ||
270 | ofUsers: { | ||
271 | enabled | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | }) | ||
277 | } | ||
278 | |||
279 | async function expectBlacklist (uuid: string, value: boolean) { | ||
280 | const video = await servers[0].videos.getWithToken({ id: uuid }) | ||
281 | |||
282 | expect(video.blacklisted).to.equal(value) | ||
283 | } | ||
284 | |||
285 | before(async function () { | ||
286 | await updateAutoBlacklist(true) | ||
287 | }) | ||
288 | |||
289 | it('Should auto blacklist an unblacklisted video after file replacement', async function () { | ||
290 | this.timeout(120000) | ||
291 | |||
292 | const { uuid } = await servers[0].videos.quickUpload({ token: userToken, name: 'user video' }) | ||
293 | await waitJobs(servers) | ||
294 | await expectBlacklist(uuid, true) | ||
295 | |||
296 | await servers[0].blacklist.remove({ videoId: uuid }) | ||
297 | await expectBlacklist(uuid, false) | ||
298 | |||
299 | await servers[0].videos.replaceSourceFile({ videoId: uuid, token: userToken, fixture: 'video_short_360p.mp4' }) | ||
300 | await waitJobs(servers) | ||
301 | |||
302 | await expectBlacklist(uuid, true) | ||
303 | }) | ||
304 | |||
305 | it('Should auto blacklist an already blacklisted video after file replacement', async function () { | ||
306 | this.timeout(120000) | ||
307 | |||
308 | const { uuid } = await servers[0].videos.quickUpload({ token: userToken, name: 'user video' }) | ||
309 | await waitJobs(servers) | ||
310 | await expectBlacklist(uuid, true) | ||
311 | |||
312 | await servers[0].videos.replaceSourceFile({ videoId: uuid, token: userToken, fixture: 'video_short_360p.mp4' }) | ||
313 | await waitJobs(servers) | ||
314 | |||
315 | await expectBlacklist(uuid, true) | ||
316 | }) | ||
317 | |||
318 | it('Should not auto blacklist if auto blacklist has been disabled between the upload and the replacement', async function () { | ||
319 | this.timeout(120000) | ||
320 | |||
321 | const { uuid } = await servers[0].videos.quickUpload({ token: userToken, name: 'user video' }) | ||
322 | await waitJobs(servers) | ||
323 | await expectBlacklist(uuid, true) | ||
324 | |||
325 | await servers[0].blacklist.remove({ videoId: uuid }) | ||
326 | await expectBlacklist(uuid, false) | ||
327 | |||
328 | await updateAutoBlacklist(false) | ||
329 | |||
330 | await servers[0].videos.replaceSourceFile({ videoId: uuid, token: userToken, fixture: 'video_short1.webm' }) | ||
331 | await waitJobs(servers) | ||
332 | |||
333 | await expectBlacklist(uuid, false) | ||
334 | }) | ||
335 | }) | ||
336 | |||
337 | describe('With object storage enabled', function () { | ||
338 | if (areMockObjectStorageTestsDisabled()) return | ||
339 | |||
340 | const objectStorage = new ObjectStorageCommand() | ||
341 | |||
342 | before(async function () { | ||
343 | this.timeout(120000) | ||
344 | |||
345 | const configOverride = objectStorage.getDefaultMockConfig() | ||
346 | await objectStorage.prepareDefaultMockBuckets() | ||
347 | |||
348 | await servers[0].kill() | ||
349 | await servers[0].run(configOverride) | ||
350 | }) | ||
351 | |||
352 | it('Should replace a video file with transcoding disabled', async function () { | ||
353 | this.timeout(120000) | ||
354 | |||
355 | await servers[0].config.disableTranscoding() | ||
356 | |||
357 | const { uuid } = await servers[0].videos.quickUpload({ | ||
358 | name: 'object storage without transcoding', | ||
359 | fixture: 'video_short_720p.mp4' | ||
360 | }) | ||
361 | await waitJobs(servers) | ||
362 | |||
363 | for (const server of servers) { | ||
364 | const video = await server.videos.get({ id: uuid }) | ||
365 | |||
366 | const files = getAllFiles(video) | ||
367 | expect(files).to.have.lengthOf(1) | ||
368 | expect(files[0].resolution.id).to.equal(720) | ||
369 | expectStartWith(files[0].fileUrl, objectStorage.getMockWebVideosBaseUrl()) | ||
370 | } | ||
371 | |||
372 | await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' }) | ||
373 | await waitJobs(servers) | ||
374 | |||
375 | for (const server of servers) { | ||
376 | const video = await server.videos.get({ id: uuid }) | ||
377 | |||
378 | const files = getAllFiles(video) | ||
379 | expect(files).to.have.lengthOf(1) | ||
380 | expect(files[0].resolution.id).to.equal(360) | ||
381 | expectStartWith(files[0].fileUrl, objectStorage.getMockWebVideosBaseUrl()) | ||
382 | } | ||
383 | }) | ||
384 | |||
385 | it('Should replace a video file with transcoding enabled', async function () { | ||
386 | this.timeout(120000) | ||
387 | |||
388 | const previousPaths: string[] = [] | ||
389 | |||
390 | await servers[0].config.enableTranscoding(true, true, true) | ||
391 | |||
392 | const { uuid: videoUUID } = await servers[0].videos.quickUpload({ | ||
393 | name: 'object storage with transcoding', | ||
394 | fixture: 'video_short_360p.mp4' | ||
395 | }) | ||
396 | uuid = videoUUID | ||
397 | |||
398 | await waitJobs(servers) | ||
399 | |||
400 | for (const server of servers) { | ||
401 | const video = await server.videos.get({ id: uuid }) | ||
402 | |||
403 | const files = getAllFiles(video) | ||
404 | expect(files).to.have.lengthOf(4 * 2) | ||
405 | |||
406 | for (const file of files) { | ||
407 | previousPaths.push(file.fileUrl) | ||
408 | } | ||
409 | |||
410 | for (const file of video.files) { | ||
411 | expectStartWith(file.fileUrl, objectStorage.getMockWebVideosBaseUrl()) | ||
412 | } | ||
413 | |||
414 | for (const file of video.streamingPlaylists[0].files) { | ||
415 | expectStartWith(file.fileUrl, objectStorage.getMockPlaylistBaseUrl()) | ||
416 | } | ||
417 | } | ||
418 | |||
419 | await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_240p.mp4' }) | ||
420 | await waitJobs(servers) | ||
421 | |||
422 | for (const server of servers) { | ||
423 | const video = await server.videos.get({ id: uuid }) | ||
424 | |||
425 | const files = getAllFiles(video) | ||
426 | expect(files).to.have.lengthOf(3 * 2) | ||
427 | |||
428 | for (const file of files) { | ||
429 | expect(previousPaths).to.not.include(file.fileUrl) | ||
430 | } | ||
26 | 431 | ||
27 | const { uuid } = await server.videos.upload({ attributes: { name: 'my video', fixture }, mode: 'resumable' }) | 432 | for (const file of video.files) { |
433 | expectStartWith(file.fileUrl, objectStorage.getMockWebVideosBaseUrl()) | ||
434 | } | ||
28 | 435 | ||
29 | const source = await server.videos.getSource({ id: uuid }) | 436 | for (const file of video.streamingPlaylists[0].files) { |
30 | expect(source.filename).to.equal(fixture) | 437 | expectStartWith(file.fileUrl, objectStorage.getMockPlaylistBaseUrl()) |
438 | } | ||
439 | } | ||
440 | }) | ||
441 | }) | ||
31 | }) | 442 | }) |
32 | 443 | ||
33 | after(async function () { | 444 | after(async function () { |
34 | await cleanupTests([ server ]) | 445 | await cleanupTests(servers) |
35 | }) | 446 | }) |
36 | }) | 447 | }) |