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/server/follows.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/server/follows.ts')
-rw-r--r-- | packages/tests/src/api/server/follows.ts | 644 |
1 files changed, 644 insertions, 0 deletions
diff --git a/packages/tests/src/api/server/follows.ts b/packages/tests/src/api/server/follows.ts new file mode 100644 index 000000000..fbe2e87da --- /dev/null +++ b/packages/tests/src/api/server/follows.ts | |||
@@ -0,0 +1,644 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { Video, VideoPrivacy } from '@peertube/peertube-models' | ||
5 | import { cleanupTests, createMultipleServers, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@peertube/peertube-server-commands' | ||
6 | import { expectAccountFollows, expectChannelsFollows } from '@tests/shared/actors.js' | ||
7 | import { testCaptionFile } from '@tests/shared/captions.js' | ||
8 | import { dateIsValid } from '@tests/shared/checks.js' | ||
9 | import { completeVideoCheck } from '@tests/shared/videos.js' | ||
10 | |||
11 | describe('Test follows', function () { | ||
12 | |||
13 | describe('Complex follow', function () { | ||
14 | let servers: PeerTubeServer[] = [] | ||
15 | |||
16 | before(async function () { | ||
17 | this.timeout(120000) | ||
18 | |||
19 | servers = await createMultipleServers(3) | ||
20 | |||
21 | // Get the access tokens | ||
22 | await setAccessTokensToServers(servers) | ||
23 | }) | ||
24 | |||
25 | describe('Data propagation after follow', function () { | ||
26 | |||
27 | it('Should not have followers/followings', async function () { | ||
28 | for (const server of servers) { | ||
29 | const bodies = await Promise.all([ | ||
30 | server.follows.getFollowers({ start: 0, count: 5, sort: 'createdAt' }), | ||
31 | server.follows.getFollowings({ start: 0, count: 5, sort: 'createdAt' }) | ||
32 | ]) | ||
33 | |||
34 | for (const body of bodies) { | ||
35 | expect(body.total).to.equal(0) | ||
36 | |||
37 | const follows = body.data | ||
38 | expect(follows).to.be.an('array') | ||
39 | expect(follows).to.have.lengthOf(0) | ||
40 | } | ||
41 | } | ||
42 | }) | ||
43 | |||
44 | it('Should have server 1 following root account of server 2 and server 3', async function () { | ||
45 | this.timeout(30000) | ||
46 | |||
47 | await servers[0].follows.follow({ | ||
48 | hosts: [ servers[2].url ], | ||
49 | handles: [ 'root@' + servers[1].host ] | ||
50 | }) | ||
51 | |||
52 | await waitJobs(servers) | ||
53 | }) | ||
54 | |||
55 | it('Should have 2 followings on server 1', async function () { | ||
56 | const body = await servers[0].follows.getFollowings({ start: 0, count: 1, sort: 'createdAt' }) | ||
57 | expect(body.total).to.equal(2) | ||
58 | |||
59 | let follows = body.data | ||
60 | expect(follows).to.be.an('array') | ||
61 | expect(follows).to.have.lengthOf(1) | ||
62 | |||
63 | const body2 = await servers[0].follows.getFollowings({ start: 1, count: 1, sort: 'createdAt' }) | ||
64 | follows = follows.concat(body2.data) | ||
65 | |||
66 | const server2Follow = follows.find(f => f.following.host === servers[1].host) | ||
67 | const server3Follow = follows.find(f => f.following.host === servers[2].host) | ||
68 | |||
69 | expect(server2Follow).to.not.be.undefined | ||
70 | expect(server2Follow.following.name).to.equal('root') | ||
71 | expect(server2Follow.state).to.equal('accepted') | ||
72 | |||
73 | expect(server3Follow).to.not.be.undefined | ||
74 | expect(server3Follow.following.name).to.equal('peertube') | ||
75 | expect(server3Follow.state).to.equal('accepted') | ||
76 | }) | ||
77 | |||
78 | it('Should have 0 followings on server 2 and 3', async function () { | ||
79 | for (const server of [ servers[1], servers[2] ]) { | ||
80 | const body = await server.follows.getFollowings({ start: 0, count: 5, sort: 'createdAt' }) | ||
81 | expect(body.total).to.equal(0) | ||
82 | |||
83 | const follows = body.data | ||
84 | expect(follows).to.be.an('array') | ||
85 | expect(follows).to.have.lengthOf(0) | ||
86 | } | ||
87 | }) | ||
88 | |||
89 | it('Should have 1 followers on server 3', async function () { | ||
90 | const body = await servers[2].follows.getFollowers({ start: 0, count: 1, sort: 'createdAt' }) | ||
91 | expect(body.total).to.equal(1) | ||
92 | |||
93 | const follows = body.data | ||
94 | expect(follows).to.be.an('array') | ||
95 | expect(follows).to.have.lengthOf(1) | ||
96 | expect(follows[0].follower.host).to.equal(servers[0].host) | ||
97 | }) | ||
98 | |||
99 | it('Should have 0 followers on server 1 and 2', async function () { | ||
100 | for (const server of [ servers[0], servers[1] ]) { | ||
101 | const body = await server.follows.getFollowers({ start: 0, count: 5, sort: 'createdAt' }) | ||
102 | expect(body.total).to.equal(0) | ||
103 | |||
104 | const follows = body.data | ||
105 | expect(follows).to.be.an('array') | ||
106 | expect(follows).to.have.lengthOf(0) | ||
107 | } | ||
108 | }) | ||
109 | |||
110 | it('Should search/filter followings on server 1', async function () { | ||
111 | const sort = 'createdAt' | ||
112 | const start = 0 | ||
113 | const count = 1 | ||
114 | |||
115 | { | ||
116 | const search = ':' + servers[1].port | ||
117 | |||
118 | { | ||
119 | const body = await servers[0].follows.getFollowings({ start, count, sort, search }) | ||
120 | expect(body.total).to.equal(1) | ||
121 | |||
122 | const follows = body.data | ||
123 | expect(follows).to.have.lengthOf(1) | ||
124 | expect(follows[0].following.host).to.equal(servers[1].host) | ||
125 | } | ||
126 | |||
127 | { | ||
128 | const body = await servers[0].follows.getFollowings({ start, count, sort, search, state: 'accepted' }) | ||
129 | expect(body.total).to.equal(1) | ||
130 | expect(body.data).to.have.lengthOf(1) | ||
131 | } | ||
132 | |||
133 | { | ||
134 | const body = await servers[0].follows.getFollowings({ start, count, sort, search, state: 'accepted', actorType: 'Person' }) | ||
135 | expect(body.total).to.equal(1) | ||
136 | expect(body.data).to.have.lengthOf(1) | ||
137 | } | ||
138 | |||
139 | { | ||
140 | const body = await servers[0].follows.getFollowings({ | ||
141 | start, | ||
142 | count, | ||
143 | sort, | ||
144 | search, | ||
145 | state: 'accepted', | ||
146 | actorType: 'Application' | ||
147 | }) | ||
148 | expect(body.total).to.equal(0) | ||
149 | expect(body.data).to.have.lengthOf(0) | ||
150 | } | ||
151 | |||
152 | { | ||
153 | const body = await servers[0].follows.getFollowings({ start, count, sort, search, state: 'pending' }) | ||
154 | expect(body.total).to.equal(0) | ||
155 | expect(body.data).to.have.lengthOf(0) | ||
156 | } | ||
157 | } | ||
158 | |||
159 | { | ||
160 | const body = await servers[0].follows.getFollowings({ start, count, sort, search: 'root' }) | ||
161 | expect(body.total).to.equal(1) | ||
162 | expect(body.data).to.have.lengthOf(1) | ||
163 | } | ||
164 | |||
165 | { | ||
166 | const body = await servers[0].follows.getFollowings({ start, count, sort, search: 'bla' }) | ||
167 | expect(body.total).to.equal(0) | ||
168 | |||
169 | expect(body.data).to.have.lengthOf(0) | ||
170 | } | ||
171 | }) | ||
172 | |||
173 | it('Should search/filter followers on server 2', async function () { | ||
174 | const start = 0 | ||
175 | const count = 5 | ||
176 | const sort = 'createdAt' | ||
177 | |||
178 | { | ||
179 | const search = servers[0].port + '' | ||
180 | |||
181 | { | ||
182 | const body = await servers[2].follows.getFollowers({ start, count, sort, search }) | ||
183 | expect(body.total).to.equal(1) | ||
184 | |||
185 | const follows = body.data | ||
186 | expect(follows).to.have.lengthOf(1) | ||
187 | expect(follows[0].following.host).to.equal(servers[2].host) | ||
188 | } | ||
189 | |||
190 | { | ||
191 | const body = await servers[2].follows.getFollowers({ start, count, sort, search, state: 'accepted' }) | ||
192 | expect(body.total).to.equal(1) | ||
193 | expect(body.data).to.have.lengthOf(1) | ||
194 | } | ||
195 | |||
196 | { | ||
197 | const body = await servers[2].follows.getFollowers({ start, count, sort, search, state: 'accepted', actorType: 'Person' }) | ||
198 | expect(body.total).to.equal(0) | ||
199 | expect(body.data).to.have.lengthOf(0) | ||
200 | } | ||
201 | |||
202 | { | ||
203 | const body = await servers[2].follows.getFollowers({ | ||
204 | start, | ||
205 | count, | ||
206 | sort, | ||
207 | search, | ||
208 | state: 'accepted', | ||
209 | actorType: 'Application' | ||
210 | }) | ||
211 | expect(body.total).to.equal(1) | ||
212 | expect(body.data).to.have.lengthOf(1) | ||
213 | } | ||
214 | |||
215 | { | ||
216 | const body = await servers[2].follows.getFollowers({ start, count, sort, search, state: 'pending' }) | ||
217 | expect(body.total).to.equal(0) | ||
218 | expect(body.data).to.have.lengthOf(0) | ||
219 | } | ||
220 | } | ||
221 | |||
222 | { | ||
223 | const body = await servers[2].follows.getFollowers({ start, count, sort, search: 'bla' }) | ||
224 | expect(body.total).to.equal(0) | ||
225 | |||
226 | const follows = body.data | ||
227 | expect(follows).to.have.lengthOf(0) | ||
228 | } | ||
229 | }) | ||
230 | |||
231 | it('Should have the correct follows counts', async function () { | ||
232 | await expectAccountFollows({ server: servers[0], handle: 'peertube@' + servers[0].host, followers: 0, following: 2 }) | ||
233 | await expectAccountFollows({ server: servers[0], handle: 'root@' + servers[1].host, followers: 1, following: 0 }) | ||
234 | await expectAccountFollows({ server: servers[0], handle: 'peertube@' + servers[2].host, followers: 1, following: 0 }) | ||
235 | |||
236 | // Server 2 and 3 does not know server 1 follow another server (there was not a refresh) | ||
237 | await expectAccountFollows({ server: servers[1], handle: 'peertube@' + servers[0].host, followers: 0, following: 1 }) | ||
238 | await expectAccountFollows({ server: servers[1], handle: 'root@' + servers[1].host, followers: 1, following: 0 }) | ||
239 | await expectAccountFollows({ server: servers[1], handle: 'peertube@' + servers[1].host, followers: 0, following: 0 }) | ||
240 | |||
241 | await expectAccountFollows({ server: servers[2], handle: 'peertube@' + servers[0].host, followers: 0, following: 1 }) | ||
242 | await expectAccountFollows({ server: servers[2], handle: 'peertube@' + servers[2].host, followers: 1, following: 0 }) | ||
243 | }) | ||
244 | |||
245 | it('Should unfollow server 3 on server 1', async function () { | ||
246 | this.timeout(15000) | ||
247 | |||
248 | await servers[0].follows.unfollow({ target: servers[2] }) | ||
249 | |||
250 | await waitJobs(servers) | ||
251 | }) | ||
252 | |||
253 | it('Should not follow server 3 on server 1 anymore', async function () { | ||
254 | const body = await servers[0].follows.getFollowings({ start: 0, count: 2, sort: 'createdAt' }) | ||
255 | expect(body.total).to.equal(1) | ||
256 | |||
257 | const follows = body.data | ||
258 | expect(follows).to.be.an('array') | ||
259 | expect(follows).to.have.lengthOf(1) | ||
260 | |||
261 | expect(follows[0].following.host).to.equal(servers[1].host) | ||
262 | }) | ||
263 | |||
264 | it('Should not have server 1 as follower on server 3 anymore', async function () { | ||
265 | const body = await servers[2].follows.getFollowers({ start: 0, count: 1, sort: 'createdAt' }) | ||
266 | expect(body.total).to.equal(0) | ||
267 | |||
268 | const follows = body.data | ||
269 | expect(follows).to.be.an('array') | ||
270 | expect(follows).to.have.lengthOf(0) | ||
271 | }) | ||
272 | |||
273 | it('Should have the correct follows counts after the unfollow', async function () { | ||
274 | await expectAccountFollows({ server: servers[0], handle: 'peertube@' + servers[0].host, followers: 0, following: 1 }) | ||
275 | await expectAccountFollows({ server: servers[0], handle: 'root@' + servers[1].host, followers: 1, following: 0 }) | ||
276 | await expectAccountFollows({ server: servers[0], handle: 'peertube@' + servers[2].host, followers: 0, following: 0 }) | ||
277 | |||
278 | await expectAccountFollows({ server: servers[1], handle: 'peertube@' + servers[0].host, followers: 0, following: 1 }) | ||
279 | await expectAccountFollows({ server: servers[1], handle: 'root@' + servers[1].host, followers: 1, following: 0 }) | ||
280 | await expectAccountFollows({ server: servers[1], handle: 'peertube@' + servers[1].host, followers: 0, following: 0 }) | ||
281 | |||
282 | await expectAccountFollows({ server: servers[2], handle: 'peertube@' + servers[0].host, followers: 0, following: 0 }) | ||
283 | await expectAccountFollows({ server: servers[2], handle: 'peertube@' + servers[2].host, followers: 0, following: 0 }) | ||
284 | }) | ||
285 | |||
286 | it('Should upload a video on server 2 and 3 and propagate only the video of server 2', async function () { | ||
287 | this.timeout(160000) | ||
288 | |||
289 | await servers[1].videos.upload({ attributes: { name: 'server2' } }) | ||
290 | await servers[2].videos.upload({ attributes: { name: 'server3' } }) | ||
291 | |||
292 | await waitJobs(servers) | ||
293 | |||
294 | { | ||
295 | const { total, data } = await servers[0].videos.list() | ||
296 | expect(total).to.equal(1) | ||
297 | expect(data[0].name).to.equal('server2') | ||
298 | } | ||
299 | |||
300 | { | ||
301 | const { total, data } = await servers[1].videos.list() | ||
302 | expect(total).to.equal(1) | ||
303 | expect(data[0].name).to.equal('server2') | ||
304 | } | ||
305 | |||
306 | { | ||
307 | const { total, data } = await servers[2].videos.list() | ||
308 | expect(total).to.equal(1) | ||
309 | expect(data[0].name).to.equal('server3') | ||
310 | } | ||
311 | }) | ||
312 | |||
313 | it('Should remove account follow', async function () { | ||
314 | this.timeout(15000) | ||
315 | |||
316 | await servers[0].follows.unfollow({ target: 'root@' + servers[1].host }) | ||
317 | |||
318 | await waitJobs(servers) | ||
319 | }) | ||
320 | |||
321 | it('Should have removed the account follow', async function () { | ||
322 | await expectAccountFollows({ server: servers[0], handle: 'root@' + servers[1].host, followers: 0, following: 0 }) | ||
323 | await expectAccountFollows({ server: servers[1], handle: 'root@' + servers[1].host, followers: 0, following: 0 }) | ||
324 | |||
325 | { | ||
326 | const { total, data } = await servers[0].follows.getFollowings() | ||
327 | expect(total).to.equal(0) | ||
328 | expect(data).to.have.lengthOf(0) | ||
329 | } | ||
330 | |||
331 | { | ||
332 | const { total, data } = await servers[0].videos.list() | ||
333 | expect(total).to.equal(0) | ||
334 | expect(data).to.have.lengthOf(0) | ||
335 | } | ||
336 | }) | ||
337 | |||
338 | it('Should follow a channel', async function () { | ||
339 | this.timeout(15000) | ||
340 | |||
341 | await servers[0].follows.follow({ | ||
342 | handles: [ 'root_channel@' + servers[1].host ] | ||
343 | }) | ||
344 | |||
345 | await waitJobs(servers) | ||
346 | |||
347 | await expectChannelsFollows({ server: servers[0], handle: 'root_channel@' + servers[1].host, followers: 1, following: 0 }) | ||
348 | await expectChannelsFollows({ server: servers[1], handle: 'root_channel@' + servers[1].host, followers: 1, following: 0 }) | ||
349 | |||
350 | { | ||
351 | const { total, data } = await servers[0].follows.getFollowings() | ||
352 | expect(total).to.equal(1) | ||
353 | expect(data).to.have.lengthOf(1) | ||
354 | } | ||
355 | |||
356 | { | ||
357 | const { total, data } = await servers[0].videos.list() | ||
358 | expect(total).to.equal(1) | ||
359 | expect(data).to.have.lengthOf(1) | ||
360 | } | ||
361 | }) | ||
362 | }) | ||
363 | |||
364 | describe('Should propagate data on a new server follow', function () { | ||
365 | let video4: Video | ||
366 | |||
367 | before(async function () { | ||
368 | this.timeout(240000) | ||
369 | |||
370 | const video4Attributes = { | ||
371 | name: 'server3-4', | ||
372 | category: 2, | ||
373 | nsfw: true, | ||
374 | licence: 6, | ||
375 | tags: [ 'tag1', 'tag2', 'tag3' ] | ||
376 | } | ||
377 | |||
378 | await servers[2].videos.upload({ attributes: { name: 'server3-2' } }) | ||
379 | await servers[2].videos.upload({ attributes: { name: 'server3-3' } }) | ||
380 | |||
381 | const video4CreateResult = await servers[2].videos.upload({ attributes: video4Attributes }) | ||
382 | |||
383 | await servers[2].videos.upload({ attributes: { name: 'server3-5' } }) | ||
384 | await servers[2].videos.upload({ attributes: { name: 'server3-6' } }) | ||
385 | |||
386 | { | ||
387 | const userAccessToken = await servers[2].users.generateUserAndToken('captain') | ||
388 | |||
389 | await servers[2].videos.rate({ id: video4CreateResult.id, rating: 'like' }) | ||
390 | await servers[2].videos.rate({ token: userAccessToken, id: video4CreateResult.id, rating: 'dislike' }) | ||
391 | } | ||
392 | |||
393 | { | ||
394 | await servers[2].comments.createThread({ videoId: video4CreateResult.id, text: 'my super first comment' }) | ||
395 | |||
396 | await servers[2].comments.addReplyToLastThread({ text: 'my super answer to thread 1' }) | ||
397 | await servers[2].comments.addReplyToLastReply({ text: 'my super answer to answer of thread 1' }) | ||
398 | await servers[2].comments.addReplyToLastThread({ text: 'my second answer to thread 1' }) | ||
399 | } | ||
400 | |||
401 | { | ||
402 | const { id: threadId } = await servers[2].comments.createThread({ videoId: video4CreateResult.id, text: 'will be deleted' }) | ||
403 | await servers[2].comments.addReplyToLastThread({ text: 'answer to deleted' }) | ||
404 | |||
405 | const { id: replyId } = await servers[2].comments.addReplyToLastThread({ text: 'will also be deleted' }) | ||
406 | |||
407 | await servers[2].comments.addReplyToLastReply({ text: 'my second answer to deleted' }) | ||
408 | |||
409 | await servers[2].comments.delete({ videoId: video4CreateResult.id, commentId: threadId }) | ||
410 | await servers[2].comments.delete({ videoId: video4CreateResult.id, commentId: replyId }) | ||
411 | } | ||
412 | |||
413 | await servers[2].captions.add({ | ||
414 | language: 'ar', | ||
415 | videoId: video4CreateResult.id, | ||
416 | fixture: 'subtitle-good2.vtt' | ||
417 | }) | ||
418 | |||
419 | await waitJobs(servers) | ||
420 | |||
421 | // Server 1 follows server 3 | ||
422 | await servers[0].follows.follow({ hosts: [ servers[2].url ] }) | ||
423 | |||
424 | await waitJobs(servers) | ||
425 | }) | ||
426 | |||
427 | it('Should have the correct follows counts', async function () { | ||
428 | await expectAccountFollows({ server: servers[0], handle: 'peertube@' + servers[0].host, followers: 0, following: 2 }) | ||
429 | await expectAccountFollows({ server: servers[0], handle: 'root@' + servers[1].host, followers: 0, following: 0 }) | ||
430 | await expectChannelsFollows({ server: servers[0], handle: 'root_channel@' + servers[1].host, followers: 1, following: 0 }) | ||
431 | await expectAccountFollows({ server: servers[0], handle: 'peertube@' + servers[2].host, followers: 1, following: 0 }) | ||
432 | |||
433 | await expectAccountFollows({ server: servers[1], handle: 'peertube@' + servers[0].host, followers: 0, following: 1 }) | ||
434 | await expectAccountFollows({ server: servers[1], handle: 'peertube@' + servers[1].host, followers: 0, following: 0 }) | ||
435 | await expectAccountFollows({ server: servers[1], handle: 'root@' + servers[1].host, followers: 0, following: 0 }) | ||
436 | await expectChannelsFollows({ server: servers[1], handle: 'root_channel@' + servers[1].host, followers: 1, following: 0 }) | ||
437 | |||
438 | await expectAccountFollows({ server: servers[2], handle: 'peertube@' + servers[0].host, followers: 0, following: 1 }) | ||
439 | await expectAccountFollows({ server: servers[2], handle: 'peertube@' + servers[2].host, followers: 1, following: 0 }) | ||
440 | }) | ||
441 | |||
442 | it('Should have propagated videos', async function () { | ||
443 | const { total, data } = await servers[0].videos.list() | ||
444 | expect(total).to.equal(7) | ||
445 | |||
446 | const video2 = data.find(v => v.name === 'server3-2') | ||
447 | video4 = data.find(v => v.name === 'server3-4') | ||
448 | const video6 = data.find(v => v.name === 'server3-6') | ||
449 | |||
450 | expect(video2).to.not.be.undefined | ||
451 | expect(video4).to.not.be.undefined | ||
452 | expect(video6).to.not.be.undefined | ||
453 | |||
454 | const isLocal = false | ||
455 | const checkAttributes = { | ||
456 | name: 'server3-4', | ||
457 | category: 2, | ||
458 | licence: 6, | ||
459 | language: 'zh', | ||
460 | nsfw: true, | ||
461 | description: 'my super description', | ||
462 | support: 'my super support text', | ||
463 | account: { | ||
464 | name: 'root', | ||
465 | host: servers[2].host | ||
466 | }, | ||
467 | isLocal, | ||
468 | commentsEnabled: true, | ||
469 | downloadEnabled: true, | ||
470 | duration: 5, | ||
471 | tags: [ 'tag1', 'tag2', 'tag3' ], | ||
472 | privacy: VideoPrivacy.PUBLIC, | ||
473 | likes: 1, | ||
474 | dislikes: 1, | ||
475 | channel: { | ||
476 | displayName: 'Main root channel', | ||
477 | name: 'root_channel', | ||
478 | description: '', | ||
479 | isLocal | ||
480 | }, | ||
481 | fixture: 'video_short.webm', | ||
482 | files: [ | ||
483 | { | ||
484 | resolution: 720, | ||
485 | size: 218910 | ||
486 | } | ||
487 | ] | ||
488 | } | ||
489 | await completeVideoCheck({ | ||
490 | server: servers[0], | ||
491 | originServer: servers[2], | ||
492 | videoUUID: video4.uuid, | ||
493 | attributes: checkAttributes | ||
494 | }) | ||
495 | }) | ||
496 | |||
497 | it('Should have propagated comments', async function () { | ||
498 | const { total, data } = await servers[0].comments.listThreads({ videoId: video4.id, sort: 'createdAt' }) | ||
499 | |||
500 | expect(total).to.equal(2) | ||
501 | expect(data).to.be.an('array') | ||
502 | expect(data).to.have.lengthOf(2) | ||
503 | |||
504 | { | ||
505 | const comment = data[0] | ||
506 | expect(comment.inReplyToCommentId).to.be.null | ||
507 | expect(comment.text).equal('my super first comment') | ||
508 | expect(comment.videoId).to.equal(video4.id) | ||
509 | expect(comment.id).to.equal(comment.threadId) | ||
510 | expect(comment.account.name).to.equal('root') | ||
511 | expect(comment.account.host).to.equal(servers[2].host) | ||
512 | expect(comment.totalReplies).to.equal(3) | ||
513 | expect(dateIsValid(comment.createdAt as string)).to.be.true | ||
514 | expect(dateIsValid(comment.updatedAt as string)).to.be.true | ||
515 | |||
516 | const threadId = comment.threadId | ||
517 | |||
518 | const tree = await servers[0].comments.getThread({ videoId: video4.id, threadId }) | ||
519 | expect(tree.comment.text).equal('my super first comment') | ||
520 | expect(tree.children).to.have.lengthOf(2) | ||
521 | |||
522 | const firstChild = tree.children[0] | ||
523 | expect(firstChild.comment.text).to.equal('my super answer to thread 1') | ||
524 | expect(firstChild.children).to.have.lengthOf(1) | ||
525 | |||
526 | const childOfFirstChild = firstChild.children[0] | ||
527 | expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') | ||
528 | expect(childOfFirstChild.children).to.have.lengthOf(0) | ||
529 | |||
530 | const secondChild = tree.children[1] | ||
531 | expect(secondChild.comment.text).to.equal('my second answer to thread 1') | ||
532 | expect(secondChild.children).to.have.lengthOf(0) | ||
533 | } | ||
534 | |||
535 | { | ||
536 | const deletedComment = data[1] | ||
537 | expect(deletedComment).to.not.be.undefined | ||
538 | expect(deletedComment.isDeleted).to.be.true | ||
539 | expect(deletedComment.deletedAt).to.not.be.null | ||
540 | expect(deletedComment.text).to.equal('') | ||
541 | expect(deletedComment.inReplyToCommentId).to.be.null | ||
542 | expect(deletedComment.account).to.be.null | ||
543 | expect(deletedComment.totalReplies).to.equal(2) | ||
544 | expect(dateIsValid(deletedComment.deletedAt as string)).to.be.true | ||
545 | |||
546 | const tree = await servers[0].comments.getThread({ videoId: video4.id, threadId: deletedComment.threadId }) | ||
547 | const [ commentRoot, deletedChildRoot ] = tree.children | ||
548 | |||
549 | expect(deletedChildRoot).to.not.be.undefined | ||
550 | expect(deletedChildRoot.comment.isDeleted).to.be.true | ||
551 | expect(deletedChildRoot.comment.deletedAt).to.not.be.null | ||
552 | expect(deletedChildRoot.comment.text).to.equal('') | ||
553 | expect(deletedChildRoot.comment.inReplyToCommentId).to.equal(deletedComment.id) | ||
554 | expect(deletedChildRoot.comment.account).to.be.null | ||
555 | expect(deletedChildRoot.children).to.have.lengthOf(1) | ||
556 | |||
557 | const answerToDeletedChild = deletedChildRoot.children[0] | ||
558 | expect(answerToDeletedChild.comment).to.not.be.undefined | ||
559 | expect(answerToDeletedChild.comment.inReplyToCommentId).to.equal(deletedChildRoot.comment.id) | ||
560 | expect(answerToDeletedChild.comment.text).to.equal('my second answer to deleted') | ||
561 | expect(answerToDeletedChild.comment.account.name).to.equal('root') | ||
562 | |||
563 | expect(commentRoot.comment).to.not.be.undefined | ||
564 | expect(commentRoot.comment.inReplyToCommentId).to.equal(deletedComment.id) | ||
565 | expect(commentRoot.comment.text).to.equal('answer to deleted') | ||
566 | expect(commentRoot.comment.account.name).to.equal('root') | ||
567 | } | ||
568 | }) | ||
569 | |||
570 | it('Should have propagated captions', async function () { | ||
571 | const body = await servers[0].captions.list({ videoId: video4.id }) | ||
572 | expect(body.total).to.equal(1) | ||
573 | expect(body.data).to.have.lengthOf(1) | ||
574 | |||
575 | const caption1 = body.data[0] | ||
576 | expect(caption1.language.id).to.equal('ar') | ||
577 | expect(caption1.language.label).to.equal('Arabic') | ||
578 | expect(caption1.captionPath).to.match(new RegExp('^/lazy-static/video-captions/.+-ar.vtt$')) | ||
579 | await testCaptionFile(servers[0].url, caption1.captionPath, 'Subtitle good 2.') | ||
580 | }) | ||
581 | |||
582 | it('Should unfollow server 3 on server 1 and does not list server 3 videos', async function () { | ||
583 | this.timeout(5000) | ||
584 | |||
585 | await servers[0].follows.unfollow({ target: servers[2] }) | ||
586 | |||
587 | await waitJobs(servers) | ||
588 | |||
589 | const { total } = await servers[0].videos.list() | ||
590 | expect(total).to.equal(1) | ||
591 | }) | ||
592 | }) | ||
593 | |||
594 | after(async function () { | ||
595 | await cleanupTests(servers) | ||
596 | }) | ||
597 | }) | ||
598 | |||
599 | describe('Simple data propagation propagate data on a new channel follow', function () { | ||
600 | let servers: PeerTubeServer[] = [] | ||
601 | |||
602 | before(async function () { | ||
603 | this.timeout(120000) | ||
604 | |||
605 | servers = await createMultipleServers(3) | ||
606 | await setAccessTokensToServers(servers) | ||
607 | |||
608 | await servers[0].videos.upload({ attributes: { name: 'video to add' } }) | ||
609 | |||
610 | await waitJobs(servers) | ||
611 | |||
612 | for (const server of [ servers[1], servers[2] ]) { | ||
613 | const video = await server.videos.find({ name: 'video to add' }) | ||
614 | expect(video).to.not.exist | ||
615 | } | ||
616 | }) | ||
617 | |||
618 | it('Should have propagated video after new channel follow', async function () { | ||
619 | this.timeout(60000) | ||
620 | |||
621 | await servers[1].follows.follow({ handles: [ 'root_channel@' + servers[0].host ] }) | ||
622 | |||
623 | await waitJobs(servers) | ||
624 | |||
625 | const video = await servers[1].videos.find({ name: 'video to add' }) | ||
626 | expect(video).to.exist | ||
627 | }) | ||
628 | |||
629 | it('Should have propagated video after new account follow', async function () { | ||
630 | this.timeout(60000) | ||
631 | |||
632 | await servers[2].follows.follow({ handles: [ 'root@' + servers[0].host ] }) | ||
633 | |||
634 | await waitJobs(servers) | ||
635 | |||
636 | const video = await servers[2].videos.find({ name: 'video to add' }) | ||
637 | expect(video).to.exist | ||
638 | }) | ||
639 | |||
640 | after(async function () { | ||
641 | await cleanupTests(servers) | ||
642 | }) | ||
643 | }) | ||
644 | }) | ||