diff options
author | Chocobozzz <me@florianbigard.com> | 2023-07-31 14:34:36 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2023-08-11 15:02:33 +0200 |
commit | 3a4992633ee62d5edfbb484d9c6bcb3cf158489d (patch) | |
tree | e4510b39bdac9c318fdb4b47018d08f15368b8f0 /packages/tests/src/api/videos/single-server.ts | |
parent | 04d1da5621d25d59bd5fa1543b725c497bf5d9a8 (diff) | |
download | PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.gz PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.zst PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.zip |
Migrate server to ESM
Sorry for the very big commit that may lead to git log issues and merge
conflicts, but it's a major step forward:
* Server can be faster at startup because imports() are async and we can
easily lazy import big modules
* Angular doesn't seem to support ES import (with .js extension), so we
had to correctly organize peertube into a monorepo:
* Use yarn workspace feature
* Use typescript reference projects for dependencies
* Shared projects have been moved into "packages", each one is now a
node module (with a dedicated package.json/tsconfig.json)
* server/tools have been moved into apps/ and is now a dedicated app
bundled and published on NPM so users don't have to build peertube
cli tools manually
* server/tests have been moved into packages/ so we don't compile
them every time we want to run the server
* Use isolatedModule option:
* Had to move from const enum to const
(https://www.typescriptlang.org/docs/handbook/enums.html#objects-vs-enums)
* Had to explictely specify "type" imports when used in decorators
* Prefer tsx (that uses esbuild under the hood) instead of ts-node to
load typescript files (tests with mocha or scripts):
* To reduce test complexity as esbuild doesn't support decorator
metadata, we only test server files that do not import server
models
* We still build tests files into js files for a faster CI
* Remove unmaintained peertube CLI import script
* Removed some barrels to speed up execution (less imports)
Diffstat (limited to 'packages/tests/src/api/videos/single-server.ts')
-rw-r--r-- | packages/tests/src/api/videos/single-server.ts | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/packages/tests/src/api/videos/single-server.ts b/packages/tests/src/api/videos/single-server.ts new file mode 100644 index 000000000..b87192a57 --- /dev/null +++ b/packages/tests/src/api/videos/single-server.ts | |||
@@ -0,0 +1,461 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { wait } from '@peertube/peertube-core-utils' | ||
5 | import { Video, VideoPrivacy } from '@peertube/peertube-models' | ||
6 | import { checkVideoFilesWereRemoved, completeVideoCheck } from '@tests/shared/videos.js' | ||
7 | import { testImageGeneratedByFFmpeg } from '@tests/shared/checks.js' | ||
8 | import { | ||
9 | cleanupTests, | ||
10 | createSingleServer, | ||
11 | PeerTubeServer, | ||
12 | setAccessTokensToServers, | ||
13 | setDefaultAccountAvatar, | ||
14 | setDefaultChannelAvatar, | ||
15 | waitJobs | ||
16 | } from '@peertube/peertube-server-commands' | ||
17 | |||
18 | describe('Test a single server', function () { | ||
19 | |||
20 | function runSuite (mode: 'legacy' | 'resumable') { | ||
21 | let server: PeerTubeServer = null | ||
22 | let videoId: number | string | ||
23 | let videoId2: string | ||
24 | let videoUUID = '' | ||
25 | let videosListBase: any[] = null | ||
26 | |||
27 | const getCheckAttributes = () => ({ | ||
28 | name: 'my super name', | ||
29 | category: 2, | ||
30 | licence: 6, | ||
31 | language: 'zh', | ||
32 | nsfw: true, | ||
33 | description: 'my super description', | ||
34 | support: 'my super support text', | ||
35 | account: { | ||
36 | name: 'root', | ||
37 | host: server.host | ||
38 | }, | ||
39 | isLocal: true, | ||
40 | duration: 5, | ||
41 | tags: [ 'tag1', 'tag2', 'tag3' ], | ||
42 | privacy: VideoPrivacy.PUBLIC, | ||
43 | commentsEnabled: true, | ||
44 | downloadEnabled: true, | ||
45 | channel: { | ||
46 | displayName: 'Main root channel', | ||
47 | name: 'root_channel', | ||
48 | description: '', | ||
49 | isLocal: true | ||
50 | }, | ||
51 | fixture: 'video_short.webm', | ||
52 | files: [ | ||
53 | { | ||
54 | resolution: 720, | ||
55 | size: 218910 | ||
56 | } | ||
57 | ] | ||
58 | }) | ||
59 | |||
60 | const updateCheckAttributes = () => ({ | ||
61 | name: 'my super video updated', | ||
62 | category: 4, | ||
63 | licence: 2, | ||
64 | language: 'ar', | ||
65 | nsfw: false, | ||
66 | description: 'my super description updated', | ||
67 | support: 'my super support text updated', | ||
68 | account: { | ||
69 | name: 'root', | ||
70 | host: server.host | ||
71 | }, | ||
72 | isLocal: true, | ||
73 | tags: [ 'tagup1', 'tagup2' ], | ||
74 | privacy: VideoPrivacy.PUBLIC, | ||
75 | duration: 5, | ||
76 | commentsEnabled: false, | ||
77 | downloadEnabled: false, | ||
78 | channel: { | ||
79 | name: 'root_channel', | ||
80 | displayName: 'Main root channel', | ||
81 | description: '', | ||
82 | isLocal: true | ||
83 | }, | ||
84 | fixture: 'video_short3.webm', | ||
85 | files: [ | ||
86 | { | ||
87 | resolution: 720, | ||
88 | size: 292677 | ||
89 | } | ||
90 | ] | ||
91 | }) | ||
92 | |||
93 | before(async function () { | ||
94 | this.timeout(30000) | ||
95 | |||
96 | server = await createSingleServer(1, {}) | ||
97 | |||
98 | await setAccessTokensToServers([ server ]) | ||
99 | await setDefaultChannelAvatar(server) | ||
100 | await setDefaultAccountAvatar(server) | ||
101 | }) | ||
102 | |||
103 | it('Should list video categories', async function () { | ||
104 | const categories = await server.videos.getCategories() | ||
105 | expect(Object.keys(categories)).to.have.length.above(10) | ||
106 | |||
107 | expect(categories[11]).to.equal('News & Politics') | ||
108 | }) | ||
109 | |||
110 | it('Should list video licences', async function () { | ||
111 | const licences = await server.videos.getLicences() | ||
112 | expect(Object.keys(licences)).to.have.length.above(5) | ||
113 | |||
114 | expect(licences[3]).to.equal('Attribution - No Derivatives') | ||
115 | }) | ||
116 | |||
117 | it('Should list video languages', async function () { | ||
118 | const languages = await server.videos.getLanguages() | ||
119 | expect(Object.keys(languages)).to.have.length.above(5) | ||
120 | |||
121 | expect(languages['ru']).to.equal('Russian') | ||
122 | }) | ||
123 | |||
124 | it('Should list video privacies', async function () { | ||
125 | const privacies = await server.videos.getPrivacies() | ||
126 | expect(Object.keys(privacies)).to.have.length.at.least(3) | ||
127 | |||
128 | expect(privacies[3]).to.equal('Private') | ||
129 | }) | ||
130 | |||
131 | it('Should not have videos', async function () { | ||
132 | const { data, total } = await server.videos.list() | ||
133 | |||
134 | expect(total).to.equal(0) | ||
135 | expect(data).to.be.an('array') | ||
136 | expect(data.length).to.equal(0) | ||
137 | }) | ||
138 | |||
139 | it('Should upload the video', async function () { | ||
140 | const attributes = { | ||
141 | name: 'my super name', | ||
142 | category: 2, | ||
143 | nsfw: true, | ||
144 | licence: 6, | ||
145 | tags: [ 'tag1', 'tag2', 'tag3' ] | ||
146 | } | ||
147 | const video = await server.videos.upload({ attributes, mode }) | ||
148 | expect(video).to.not.be.undefined | ||
149 | expect(video.id).to.equal(1) | ||
150 | expect(video.uuid).to.have.length.above(5) | ||
151 | |||
152 | videoId = video.id | ||
153 | videoUUID = video.uuid | ||
154 | }) | ||
155 | |||
156 | it('Should get and seed the uploaded video', async function () { | ||
157 | this.timeout(5000) | ||
158 | |||
159 | const { data, total } = await server.videos.list() | ||
160 | |||
161 | expect(total).to.equal(1) | ||
162 | expect(data).to.be.an('array') | ||
163 | expect(data.length).to.equal(1) | ||
164 | |||
165 | const video = data[0] | ||
166 | await completeVideoCheck({ server, originServer: server, videoUUID: video.uuid, attributes: getCheckAttributes() }) | ||
167 | }) | ||
168 | |||
169 | it('Should get the video by UUID', async function () { | ||
170 | this.timeout(5000) | ||
171 | |||
172 | const video = await server.videos.get({ id: videoUUID }) | ||
173 | await completeVideoCheck({ server, originServer: server, videoUUID: video.uuid, attributes: getCheckAttributes() }) | ||
174 | }) | ||
175 | |||
176 | it('Should have the views updated', async function () { | ||
177 | this.timeout(20000) | ||
178 | |||
179 | await server.views.simulateView({ id: videoId }) | ||
180 | await server.views.simulateView({ id: videoId }) | ||
181 | await server.views.simulateView({ id: videoId }) | ||
182 | |||
183 | await wait(1500) | ||
184 | |||
185 | await server.views.simulateView({ id: videoId }) | ||
186 | await server.views.simulateView({ id: videoId }) | ||
187 | |||
188 | await wait(1500) | ||
189 | |||
190 | await server.views.simulateView({ id: videoId }) | ||
191 | await server.views.simulateView({ id: videoId }) | ||
192 | |||
193 | await server.debug.sendCommand({ body: { command: 'process-video-views-buffer' } }) | ||
194 | |||
195 | const video = await server.videos.get({ id: videoId }) | ||
196 | expect(video.views).to.equal(3) | ||
197 | }) | ||
198 | |||
199 | it('Should remove the video', async function () { | ||
200 | const video = await server.videos.get({ id: videoId }) | ||
201 | await server.videos.remove({ id: videoId }) | ||
202 | |||
203 | await checkVideoFilesWereRemoved({ video, server }) | ||
204 | }) | ||
205 | |||
206 | it('Should not have videos', async function () { | ||
207 | const { total, data } = await server.videos.list() | ||
208 | |||
209 | expect(total).to.equal(0) | ||
210 | expect(data).to.be.an('array') | ||
211 | expect(data).to.have.lengthOf(0) | ||
212 | }) | ||
213 | |||
214 | it('Should upload 6 videos', async function () { | ||
215 | this.timeout(120000) | ||
216 | |||
217 | const videos = new Set([ | ||
218 | 'video_short.mp4', 'video_short.ogv', 'video_short.webm', | ||
219 | 'video_short1.webm', 'video_short2.webm', 'video_short3.webm' | ||
220 | ]) | ||
221 | |||
222 | for (const video of videos) { | ||
223 | const attributes = { | ||
224 | name: video + ' name', | ||
225 | description: video + ' description', | ||
226 | category: 2, | ||
227 | licence: 1, | ||
228 | language: 'en', | ||
229 | nsfw: true, | ||
230 | tags: [ 'tag1', 'tag2', 'tag3' ], | ||
231 | fixture: video | ||
232 | } | ||
233 | |||
234 | await server.videos.upload({ attributes, mode }) | ||
235 | } | ||
236 | }) | ||
237 | |||
238 | it('Should have the correct durations', async function () { | ||
239 | const { total, data } = await server.videos.list() | ||
240 | |||
241 | expect(total).to.equal(6) | ||
242 | expect(data).to.be.an('array') | ||
243 | expect(data).to.have.lengthOf(6) | ||
244 | |||
245 | const videosByName: { [ name: string ]: Video } = {} | ||
246 | data.forEach(v => { videosByName[v.name] = v }) | ||
247 | |||
248 | expect(videosByName['video_short.mp4 name'].duration).to.equal(5) | ||
249 | expect(videosByName['video_short.ogv name'].duration).to.equal(5) | ||
250 | expect(videosByName['video_short.webm name'].duration).to.equal(5) | ||
251 | expect(videosByName['video_short1.webm name'].duration).to.equal(10) | ||
252 | expect(videosByName['video_short2.webm name'].duration).to.equal(5) | ||
253 | expect(videosByName['video_short3.webm name'].duration).to.equal(5) | ||
254 | }) | ||
255 | |||
256 | it('Should have the correct thumbnails', async function () { | ||
257 | const { data } = await server.videos.list() | ||
258 | |||
259 | // For the next test | ||
260 | videosListBase = data | ||
261 | |||
262 | for (const video of data) { | ||
263 | const videoName = video.name.replace(' name', '') | ||
264 | await testImageGeneratedByFFmpeg(server.url, videoName, video.thumbnailPath) | ||
265 | } | ||
266 | }) | ||
267 | |||
268 | it('Should list only the two first videos', async function () { | ||
269 | const { total, data } = await server.videos.list({ start: 0, count: 2, sort: 'name' }) | ||
270 | |||
271 | expect(total).to.equal(6) | ||
272 | expect(data.length).to.equal(2) | ||
273 | expect(data[0].name).to.equal(videosListBase[0].name) | ||
274 | expect(data[1].name).to.equal(videosListBase[1].name) | ||
275 | }) | ||
276 | |||
277 | it('Should list only the next three videos', async function () { | ||
278 | const { total, data } = await server.videos.list({ start: 2, count: 3, sort: 'name' }) | ||
279 | |||
280 | expect(total).to.equal(6) | ||
281 | expect(data.length).to.equal(3) | ||
282 | expect(data[0].name).to.equal(videosListBase[2].name) | ||
283 | expect(data[1].name).to.equal(videosListBase[3].name) | ||
284 | expect(data[2].name).to.equal(videosListBase[4].name) | ||
285 | }) | ||
286 | |||
287 | it('Should list the last video', async function () { | ||
288 | const { total, data } = await server.videos.list({ start: 5, count: 6, sort: 'name' }) | ||
289 | |||
290 | expect(total).to.equal(6) | ||
291 | expect(data.length).to.equal(1) | ||
292 | expect(data[0].name).to.equal(videosListBase[5].name) | ||
293 | }) | ||
294 | |||
295 | it('Should not have the total field', async function () { | ||
296 | const { total, data } = await server.videos.list({ start: 5, count: 6, sort: 'name', skipCount: true }) | ||
297 | |||
298 | expect(total).to.not.exist | ||
299 | expect(data.length).to.equal(1) | ||
300 | expect(data[0].name).to.equal(videosListBase[5].name) | ||
301 | }) | ||
302 | |||
303 | it('Should list and sort by name in descending order', async function () { | ||
304 | const { total, data } = await server.videos.list({ sort: '-name' }) | ||
305 | |||
306 | expect(total).to.equal(6) | ||
307 | expect(data.length).to.equal(6) | ||
308 | expect(data[0].name).to.equal('video_short.webm name') | ||
309 | expect(data[1].name).to.equal('video_short.ogv name') | ||
310 | expect(data[2].name).to.equal('video_short.mp4 name') | ||
311 | expect(data[3].name).to.equal('video_short3.webm name') | ||
312 | expect(data[4].name).to.equal('video_short2.webm name') | ||
313 | expect(data[5].name).to.equal('video_short1.webm name') | ||
314 | |||
315 | videoId = data[3].uuid | ||
316 | videoId2 = data[5].uuid | ||
317 | }) | ||
318 | |||
319 | it('Should list and sort by trending in descending order', async function () { | ||
320 | const { total, data } = await server.videos.list({ start: 0, count: 2, sort: '-trending' }) | ||
321 | |||
322 | expect(total).to.equal(6) | ||
323 | expect(data.length).to.equal(2) | ||
324 | }) | ||
325 | |||
326 | it('Should list and sort by hotness in descending order', async function () { | ||
327 | const { total, data } = await server.videos.list({ start: 0, count: 2, sort: '-hot' }) | ||
328 | |||
329 | expect(total).to.equal(6) | ||
330 | expect(data.length).to.equal(2) | ||
331 | }) | ||
332 | |||
333 | it('Should list and sort by best in descending order', async function () { | ||
334 | const { total, data } = await server.videos.list({ start: 0, count: 2, sort: '-best' }) | ||
335 | |||
336 | expect(total).to.equal(6) | ||
337 | expect(data.length).to.equal(2) | ||
338 | }) | ||
339 | |||
340 | it('Should update a video', async function () { | ||
341 | const attributes = { | ||
342 | name: 'my super video updated', | ||
343 | category: 4, | ||
344 | licence: 2, | ||
345 | language: 'ar', | ||
346 | nsfw: false, | ||
347 | description: 'my super description updated', | ||
348 | commentsEnabled: false, | ||
349 | downloadEnabled: false, | ||
350 | tags: [ 'tagup1', 'tagup2' ] | ||
351 | } | ||
352 | await server.videos.update({ id: videoId, attributes }) | ||
353 | }) | ||
354 | |||
355 | it('Should have the video updated', async function () { | ||
356 | this.timeout(60000) | ||
357 | |||
358 | await waitJobs([ server ]) | ||
359 | |||
360 | const video = await server.videos.get({ id: videoId }) | ||
361 | |||
362 | await completeVideoCheck({ server, originServer: server, videoUUID: video.uuid, attributes: updateCheckAttributes() }) | ||
363 | }) | ||
364 | |||
365 | it('Should update only the tags of a video', async function () { | ||
366 | const attributes = { | ||
367 | tags: [ 'supertag', 'tag1', 'tag2' ] | ||
368 | } | ||
369 | await server.videos.update({ id: videoId, attributes }) | ||
370 | |||
371 | const video = await server.videos.get({ id: videoId }) | ||
372 | |||
373 | await completeVideoCheck({ | ||
374 | server, | ||
375 | originServer: server, | ||
376 | videoUUID: video.uuid, | ||
377 | attributes: Object.assign(updateCheckAttributes(), attributes) | ||
378 | }) | ||
379 | }) | ||
380 | |||
381 | it('Should update only the description of a video', async function () { | ||
382 | const attributes = { | ||
383 | description: 'hello everybody' | ||
384 | } | ||
385 | await server.videos.update({ id: videoId, attributes }) | ||
386 | |||
387 | const video = await server.videos.get({ id: videoId }) | ||
388 | |||
389 | await completeVideoCheck({ | ||
390 | server, | ||
391 | originServer: server, | ||
392 | videoUUID: video.uuid, | ||
393 | attributes: Object.assign(updateCheckAttributes(), { tags: [ 'supertag', 'tag1', 'tag2' ] }, attributes) | ||
394 | }) | ||
395 | }) | ||
396 | |||
397 | it('Should like a video', async function () { | ||
398 | await server.videos.rate({ id: videoId, rating: 'like' }) | ||
399 | |||
400 | const video = await server.videos.get({ id: videoId }) | ||
401 | |||
402 | expect(video.likes).to.equal(1) | ||
403 | expect(video.dislikes).to.equal(0) | ||
404 | }) | ||
405 | |||
406 | it('Should dislike the same video', async function () { | ||
407 | await server.videos.rate({ id: videoId, rating: 'dislike' }) | ||
408 | |||
409 | const video = await server.videos.get({ id: videoId }) | ||
410 | |||
411 | expect(video.likes).to.equal(0) | ||
412 | expect(video.dislikes).to.equal(1) | ||
413 | }) | ||
414 | |||
415 | it('Should sort by originallyPublishedAt', async function () { | ||
416 | { | ||
417 | const now = new Date() | ||
418 | const attributes = { originallyPublishedAt: now.toISOString() } | ||
419 | await server.videos.update({ id: videoId, attributes }) | ||
420 | |||
421 | const { data } = await server.videos.list({ sort: '-originallyPublishedAt' }) | ||
422 | const names = data.map(v => v.name) | ||
423 | |||
424 | expect(names[0]).to.equal('my super video updated') | ||
425 | expect(names[1]).to.equal('video_short2.webm name') | ||
426 | expect(names[2]).to.equal('video_short1.webm name') | ||
427 | expect(names[3]).to.equal('video_short.webm name') | ||
428 | expect(names[4]).to.equal('video_short.ogv name') | ||
429 | expect(names[5]).to.equal('video_short.mp4 name') | ||
430 | } | ||
431 | |||
432 | { | ||
433 | const now = new Date() | ||
434 | const attributes = { originallyPublishedAt: now.toISOString() } | ||
435 | await server.videos.update({ id: videoId2, attributes }) | ||
436 | |||
437 | const { data } = await server.videos.list({ sort: '-originallyPublishedAt' }) | ||
438 | const names = data.map(v => v.name) | ||
439 | |||
440 | expect(names[0]).to.equal('video_short1.webm name') | ||
441 | expect(names[1]).to.equal('my super video updated') | ||
442 | expect(names[2]).to.equal('video_short2.webm name') | ||
443 | expect(names[3]).to.equal('video_short.webm name') | ||
444 | expect(names[4]).to.equal('video_short.ogv name') | ||
445 | expect(names[5]).to.equal('video_short.mp4 name') | ||
446 | } | ||
447 | }) | ||
448 | |||
449 | after(async function () { | ||
450 | await cleanupTests([ server ]) | ||
451 | }) | ||
452 | } | ||
453 | |||
454 | describe('Legacy upload', function () { | ||
455 | runSuite('legacy') | ||
456 | }) | ||
457 | |||
458 | describe('Resumable upload', function () { | ||
459 | runSuite('resumable') | ||
460 | }) | ||
461 | }) | ||