]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/api/videos/video-channels.ts
Merge branch 'release/4.3.0' into develop
[github/Chocobozzz/PeerTube.git] / server / tests / api / videos / video-channels.ts
CommitLineData
a1587156 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
5f04dd2f 2
86347717 3import { expect } from 'chai'
84531547 4import { basename } from 'path'
e024fd6a 5import { ACTOR_IMAGES_SIZE } from '@server/initializers/constants'
c55e3d72
C
6import { testFileExistsOrNot, testImage } from '@server/tests/shared'
7import { wait } from '@shared/core-utils'
d0800f76 8import { ActorImageType, User, VideoChannel } from '@shared/models'
4bbfc6c6 9import {
7c3b7976 10 cleanupTests,
254d3579 11 createMultipleServers,
4c7e60bc 12 doubleFollow,
254d3579 13 PeerTubeServer,
7926c5f9 14 setAccessTokensToServers,
d0800f76 15 setDefaultAccountAvatar,
e024fd6a 16 setDefaultVideoChannel,
7926c5f9 17 waitJobs
bf54587a 18} from '@shared/server-commands'
5f04dd2f 19
254d3579 20async function findChannel (server: PeerTubeServer, channelId: number) {
89d241a7 21 const body = await server.channels.list({ sort: '-name' })
213e30ef 22
a5461888 23 return body.data.find(c => c.id === channelId)
213e30ef
C
24}
25
2422c46b 26describe('Test video channels', function () {
254d3579 27 let servers: PeerTubeServer[]
5f04dd2f 28 let userInfo: User
0f320037 29 let secondVideoChannelId: number
e024fd6a 30 let totoChannel: number
0f320037 31 let videoUUID: string
e024fd6a 32 let accountName: string
a37e9e74 33 let secondUserChannelName: string
5f04dd2f 34
06c27593
C
35 const avatarPaths: { [ port: number ]: string } = {}
36 const bannerPaths: { [ port: number ]: string } = {}
37
5f04dd2f 38 before(async function () {
48f07b4a 39 this.timeout(60000)
5f04dd2f 40
254d3579 41 servers = await createMultipleServers(2)
2422c46b
C
42
43 await setAccessTokensToServers(servers)
e024fd6a 44 await setDefaultVideoChannel(servers)
d0800f76 45 await setDefaultAccountAvatar(servers)
48dce1c9 46
e024fd6a 47 await doubleFollow(servers[0], servers[1])
5f04dd2f
C
48 })
49
50 it('Should have one video channel (created with root)', async () => {
89d241a7 51 const body = await servers[0].channels.list({ start: 0, count: 2 })
5f04dd2f 52
a5461888
C
53 expect(body.total).to.equal(1)
54 expect(body.data).to.be.an('array')
55 expect(body.data).to.have.lengthOf(1)
5f04dd2f
C
56 })
57
2422c46b 58 it('Should create another video channel', async function () {
15b43b21 59 this.timeout(30000)
2422c46b 60
0f320037
C
61 {
62 const videoChannel = {
8a19bee1 63 name: 'second_video_channel',
0f320037
C
64 displayName: 'second video channel',
65 description: 'super video channel description',
66 support: 'super video channel support text'
67 }
89d241a7 68 const created = await servers[0].channels.create({ attributes: videoChannel })
a5461888 69 secondVideoChannelId = created.id
5f04dd2f 70 }
2422c46b
C
71
72 // The channel is 1 is propagated to servers 2
0f320037 73 {
d23dd9fb 74 const attributes = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' }
89d241a7 75 const { uuid } = await servers[0].videos.upload({ attributes })
d23dd9fb 76 videoUUID = uuid
0f320037 77 }
2422c46b 78
3cd0734f 79 await waitJobs(servers)
5f04dd2f
C
80 })
81
82 it('Should have two video channels when getting my information', async () => {
89d241a7 83 userInfo = await servers[0].users.getMyInfo()
5f04dd2f
C
84
85 expect(userInfo.videoChannels).to.be.an('array')
86 expect(userInfo.videoChannels).to.have.lengthOf(2)
87
88 const videoChannels = userInfo.videoChannels
8a19bee1
C
89 expect(videoChannels[0].name).to.equal('root_channel')
90 expect(videoChannels[0].displayName).to.equal('Main root channel')
91
92 expect(videoChannels[1].name).to.equal('second_video_channel')
7bc29171 93 expect(videoChannels[1].displayName).to.equal('second video channel')
5f04dd2f 94 expect(videoChannels[1].description).to.equal('super video channel description')
2422c46b 95 expect(videoChannels[1].support).to.equal('super video channel support text')
e024fd6a
C
96
97 accountName = userInfo.account.name + '@' + userInfo.account.host
5f04dd2f
C
98 })
99
2422c46b 100 it('Should have two video channels when getting account channels on server 1', async function () {
89d241a7 101 const body = await servers[0].channels.listByAccount({ accountName })
a5461888 102 expect(body.total).to.equal(2)
91b66319 103
a5461888
C
104 const videoChannels = body.data
105
106 expect(videoChannels).to.be.an('array')
107 expect(videoChannels).to.have.lengthOf(2)
5f04dd2f 108
8a19bee1
C
109 expect(videoChannels[0].name).to.equal('root_channel')
110 expect(videoChannels[0].displayName).to.equal('Main root channel')
111
112 expect(videoChannels[1].name).to.equal('second_video_channel')
7bc29171 113 expect(videoChannels[1].displayName).to.equal('second video channel')
5f04dd2f 114 expect(videoChannels[1].description).to.equal('super video channel description')
2422c46b
C
115 expect(videoChannels[1].support).to.equal('super video channel support text')
116 })
117
91b66319
C
118 it('Should paginate and sort account channels', async function () {
119 {
89d241a7 120 const body = await servers[0].channels.listByAccount({
e024fd6a 121 accountName,
91b66319
C
122 start: 0,
123 count: 1,
124 sort: 'createdAt'
125 })
126
a5461888
C
127 expect(body.total).to.equal(2)
128 expect(body.data).to.have.lengthOf(1)
91b66319 129
a5461888 130 const videoChannel: VideoChannel = body.data[0]
91b66319
C
131 expect(videoChannel.name).to.equal('root_channel')
132 }
133
134 {
89d241a7 135 const body = await servers[0].channels.listByAccount({
e024fd6a 136 accountName,
91b66319
C
137 start: 0,
138 count: 1,
139 sort: '-createdAt'
140 })
141
a5461888
C
142 expect(body.total).to.equal(2)
143 expect(body.data).to.have.lengthOf(1)
144 expect(body.data[0].name).to.equal('second_video_channel')
91b66319
C
145 }
146
147 {
89d241a7 148 const body = await servers[0].channels.listByAccount({
e024fd6a 149 accountName,
91b66319
C
150 start: 1,
151 count: 1,
152 sort: '-createdAt'
153 })
154
a5461888
C
155 expect(body.total).to.equal(2)
156 expect(body.data).to.have.lengthOf(1)
157 expect(body.data[0].name).to.equal('root_channel')
91b66319
C
158 }
159 })
160
2422c46b 161 it('Should have one video channel when getting account channels on server 2', async function () {
89d241a7 162 const body = await servers[1].channels.listByAccount({ accountName })
91b66319 163
a5461888
C
164 expect(body.total).to.equal(1)
165 expect(body.data).to.be.an('array')
166 expect(body.data).to.have.lengthOf(1)
5f04dd2f 167
a5461888
C
168 const videoChannel = body.data[0]
169 expect(videoChannel.name).to.equal('second_video_channel')
170 expect(videoChannel.displayName).to.equal('second video channel')
171 expect(videoChannel.description).to.equal('super video channel description')
172 expect(videoChannel.support).to.equal('super video channel support text')
5f04dd2f
C
173 })
174
2422c46b 175 it('Should list video channels', async function () {
89d241a7 176 const body = await servers[0].channels.list({ start: 1, count: 1, sort: '-name' })
5f04dd2f 177
a5461888
C
178 expect(body.total).to.equal(2)
179 expect(body.data).to.be.an('array')
180 expect(body.data).to.have.lengthOf(1)
181 expect(body.data[0].name).to.equal('root_channel')
182 expect(body.data[0].displayName).to.equal('Main root channel')
5f04dd2f
C
183 })
184
2422c46b 185 it('Should update video channel', async function () {
7d14d4d2 186 this.timeout(15000)
2422c46b 187
5f04dd2f 188 const videoChannelAttributes = {
08c1efbe 189 displayName: 'video channel updated',
2422c46b 190 description: 'video channel description updated',
7d14d4d2 191 support: 'support updated'
5f04dd2f
C
192 }
193
89d241a7 194 await servers[0].channels.update({ channelName: 'second_video_channel', attributes: videoChannelAttributes })
2422c46b 195
3cd0734f 196 await waitJobs(servers)
5f04dd2f
C
197 })
198
2422c46b
C
199 it('Should have video channel updated', async function () {
200 for (const server of servers) {
89d241a7 201 const body = await server.channels.list({ start: 0, count: 1, sort: '-name' })
a5461888
C
202
203 expect(body.total).to.equal(2)
204 expect(body.data).to.be.an('array')
205 expect(body.data).to.have.lengthOf(1)
206
207 expect(body.data[0].name).to.equal('second_video_channel')
208 expect(body.data[0].displayName).to.equal('video channel updated')
209 expect(body.data[0].description).to.equal('video channel description updated')
210 expect(body.data[0].support).to.equal('support updated')
7d14d4d2
C
211 }
212 })
213
214 it('Should not have updated the video support field', async function () {
215 for (const server of servers) {
89d241a7 216 const video = await server.videos.get({ id: videoUUID })
7d14d4d2
C
217 expect(video.support).to.equal('video support field')
218 }
219 })
220
a37e9e74 221 it('Should update another accounts video channel', async function () {
222 this.timeout(15000)
223
224 const result = await servers[0].users.generate('second_user')
225 secondUserChannelName = result.userChannelName
226
227 await servers[0].videos.quickUpload({ name: 'video', token: result.token })
228
229 const videoChannelAttributes = {
230 displayName: 'video channel updated',
231 description: 'video channel description updated',
232 support: 'support updated'
233 }
234
235 await servers[0].channels.update({ channelName: secondUserChannelName, attributes: videoChannelAttributes })
236
237 await waitJobs(servers)
238 })
239
240 it('Should have another accounts video channel updated', async function () {
241 for (const server of servers) {
242 const body = await server.channels.get({ channelName: `${secondUserChannelName}@${servers[0].host}` })
243
244 expect(body.displayName).to.equal('video channel updated')
245 expect(body.description).to.equal('video channel description updated')
246 expect(body.support).to.equal('support updated')
247 }
248 })
249
7d14d4d2
C
250 it('Should update the channel support field and update videos too', async function () {
251 this.timeout(35000)
252
253 const videoChannelAttributes = {
254 support: 'video channel support text updated',
255 bulkVideosSupportUpdate: true
256 }
257
89d241a7 258 await servers[0].channels.update({ channelName: 'second_video_channel', attributes: videoChannelAttributes })
7d14d4d2
C
259
260 await waitJobs(servers)
261
262 for (const server of servers) {
89d241a7 263 const video = await server.videos.get({ id: videoUUID })
7d14d4d2 264 expect(video.support).to.equal(videoChannelAttributes.support)
2422c46b 265 }
5f04dd2f
C
266 })
267
4bbfc6c6 268 it('Should update video channel avatar', async function () {
213e30ef 269 this.timeout(15000)
4bbfc6c6
C
270
271 const fixture = 'avatar.png'
272
89d241a7 273 await servers[0].channels.updateImage({
a5461888 274 channelName: 'second_video_channel',
213e30ef
C
275 fixture,
276 type: 'avatar'
4bbfc6c6
C
277 })
278
279 await waitJobs(servers)
213e30ef
C
280
281 for (const server of servers) {
282 const videoChannel = await findChannel(server, secondVideoChannelId)
d0800f76 283 const expectedSizes = ACTOR_IMAGES_SIZE[ActorImageType.AVATAR]
213e30ef 284
d0800f76 285 expect(videoChannel.avatars.length).to.equal(expectedSizes.length, 'Expected avatars to be generated in all sizes')
84531547 286
d0800f76 287 for (const avatar of videoChannel.avatars) {
288 avatarPaths[server.port] = avatar.path
289 await testImage(server.url, `avatar-resized-${avatar.width}x${avatar.width}`, avatarPaths[server.port], '.png')
290 await testFileExistsOrNot(server, 'avatars', basename(avatarPaths[server.port]), true)
291
292 const row = await server.sql.getActorImage(basename(avatarPaths[server.port]))
293
294 expect(expectedSizes.some(({ height, width }) => row.height === height && row.width === width)).to.equal(true)
295 }
213e30ef 296 }
4bbfc6c6
C
297 })
298
213e30ef
C
299 it('Should update video channel banner', async function () {
300 this.timeout(15000)
301
302 const fixture = 'banner.jpg'
303
89d241a7 304 await servers[0].channels.updateImage({
a5461888 305 channelName: 'second_video_channel',
213e30ef
C
306 fixture,
307 type: 'banner'
308 })
309
310 await waitJobs(servers)
311
4bbfc6c6 312 for (const server of servers) {
89d241a7 313 const videoChannel = await server.channels.get({ channelName: 'second_video_channel@' + servers[0].host })
4bbfc6c6 314
d0800f76 315 bannerPaths[server.port] = videoChannel.banners[0].path
06c27593
C
316 await testImage(server.url, 'banner-resized', bannerPaths[server.port])
317 await testFileExistsOrNot(server, 'avatars', basename(bannerPaths[server.port]), true)
84531547 318
89d241a7 319 const row = await server.sql.getActorImage(basename(bannerPaths[server.port]))
d0800f76 320 expect(row.height).to.equal(ACTOR_IMAGES_SIZE[ActorImageType.BANNER][0].height)
321 expect(row.width).to.equal(ACTOR_IMAGES_SIZE[ActorImageType.BANNER][0].width)
213e30ef
C
322 }
323 })
4bbfc6c6 324
43fc899a
C
325 it('Should still correctly list channels', async function () {
326 {
327 const body = await servers[0].channels.list({ start: 1, count: 1, sort: 'createdAt' })
328
329 expect(body.total).to.equal(3)
330 expect(body.data).to.have.lengthOf(1)
331 expect(body.data[0].name).to.equal('second_video_channel')
332 }
333
334 {
335 const body = await servers[0].channels.listByAccount({ accountName, start: 1, count: 1, sort: 'createdAt' })
336
337 expect(body.total).to.equal(2)
338 expect(body.data).to.have.lengthOf(1)
339 expect(body.data[0].name).to.equal('second_video_channel')
340 }
341 })
342
213e30ef
C
343 it('Should delete the video channel avatar', async function () {
344 this.timeout(15000)
89d241a7 345 await servers[0].channels.deleteImage({ channelName: 'second_video_channel', type: 'avatar' })
213e30ef
C
346
347 await waitJobs(servers)
348
349 for (const server of servers) {
350 const videoChannel = await findChannel(server, secondVideoChannelId)
06c27593 351 await testFileExistsOrNot(server, 'avatars', basename(avatarPaths[server.port]), false)
213e30ef 352
d0800f76 353 expect(videoChannel.avatars).to.be.empty
4bbfc6c6
C
354 }
355 })
356
213e30ef
C
357 it('Should delete the video channel banner', async function () {
358 this.timeout(15000)
359
89d241a7 360 await servers[0].channels.deleteImage({ channelName: 'second_video_channel', type: 'banner' })
5f04dd2f 361
213e30ef
C
362 await waitJobs(servers)
363
364 for (const server of servers) {
365 const videoChannel = await findChannel(server, secondVideoChannelId)
06c27593 366 await testFileExistsOrNot(server, 'avatars', basename(bannerPaths[server.port]), false)
213e30ef 367
d0800f76 368 expect(videoChannel.banners).to.be.empty
213e30ef 369 }
5f04dd2f
C
370 })
371
0f320037 372 it('Should list the second video channel videos', async function () {
6b738c7a
C
373 this.timeout(10000)
374
375 for (const server of servers) {
48f07b4a 376 const channelURI = 'second_video_channel@localhost:' + servers[0].port
c0e8b12e 377 const { total, data } = await server.videos.listByChannel({ handle: channelURI })
d23dd9fb
C
378
379 expect(total).to.equal(1)
380 expect(data).to.be.an('array')
381 expect(data).to.have.lengthOf(1)
382 expect(data[0].name).to.equal('my video name')
0f320037
C
383 }
384 })
385
386 it('Should change the video channel of a video', async function () {
387 this.timeout(10000)
388
89d241a7 389 await servers[0].videos.update({ id: videoUUID, attributes: { channelId: servers[0].store.channel.id } })
0f320037 390
3cd0734f 391 await waitJobs(servers)
0f320037
C
392 })
393
394 it('Should list the first video channel videos', async function () {
395 this.timeout(10000)
396
397 for (const server of servers) {
d23dd9fb
C
398 {
399 const secondChannelURI = 'second_video_channel@localhost:' + servers[0].port
c0e8b12e 400 const { total } = await server.videos.listByChannel({ handle: secondChannelURI })
d23dd9fb
C
401 expect(total).to.equal(0)
402 }
403
404 {
405 const channelURI = 'root_channel@localhost:' + servers[0].port
c0e8b12e 406 const { total, data } = await server.videos.listByChannel({ handle: channelURI })
d23dd9fb
C
407 expect(total).to.equal(1)
408
409 expect(data).to.be.an('array')
410 expect(data).to.have.lengthOf(1)
411 expect(data[0].name).to.equal('my video name')
412 }
6b738c7a
C
413 }
414 })
415
2422c46b 416 it('Should delete video channel', async function () {
89d241a7 417 await servers[0].channels.delete({ channelName: 'second_video_channel' })
5f04dd2f
C
418 })
419
2422c46b 420 it('Should have video channel deleted', async function () {
a37e9e74 421 const body = await servers[0].channels.list({ start: 0, count: 10, sort: 'createdAt' })
5f04dd2f 422
a37e9e74 423 expect(body.total).to.equal(2)
a5461888 424 expect(body.data).to.be.an('array')
a37e9e74 425 expect(body.data).to.have.lengthOf(2)
a5461888 426 expect(body.data[0].displayName).to.equal('Main root channel')
a37e9e74 427 expect(body.data[1].displayName).to.equal('video channel updated')
8a19bee1
C
428 })
429
84992f56 430 it('Should create the main channel with a suffix if there is a conflict', async function () {
8a19bee1
C
431 {
432 const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' }
89d241a7 433 const created = await servers[0].channels.create({ attributes: videoChannel })
a5461888 434 totoChannel = created.id
8a19bee1
C
435 }
436
437 {
89d241a7
C
438 await servers[0].users.create({ username: 'toto', password: 'password' })
439 const accessToken = await servers[0].login.getAccessToken({ username: 'toto', password: 'password' })
8a19bee1 440
89d241a7 441 const { videoChannels } = await servers[0].users.getMyInfo({ token: accessToken })
84992f56 442 expect(videoChannels[0].name).to.equal('toto_channel-1')
8a19bee1 443 }
5f04dd2f
C
444 })
445
1ba471c5 446 it('Should report correct channel views per days', async function () {
5a61ffbb 447 this.timeout(10000)
714bfcc5
RK
448
449 {
89d241a7 450 const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true })
1ba471c5 451
a5461888 452 for (const channel of data) {
714bfcc5
RK
453 expect(channel).to.haveOwnProperty('viewsPerDay')
454 expect(channel.viewsPerDay).to.have.length(30 + 1) // daysPrior + today
1ba471c5
C
455
456 for (const v of channel.viewsPerDay) {
714bfcc5
RK
457 expect(v.date).to.be.an('string')
458 expect(v.views).to.equal(0)
1ba471c5
C
459 }
460 }
714bfcc5
RK
461 }
462
463 {
89d241a7 464 // video has been posted on channel servers[0].store.videoChannel.id since last update
b2111066
C
465 await servers[0].views.simulateView({ id: videoUUID, xForwardedFor: '0.0.0.1,127.0.0.1' })
466 await servers[0].views.simulateView({ id: videoUUID, xForwardedFor: '0.0.0.2,127.0.0.1' })
714bfcc5
RK
467
468 // Wait the repeatable job
469 await wait(8000)
470
89d241a7
C
471 const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true })
472 const channelWithView = data.find(channel => channel.id === servers[0].store.channel.id)
714bfcc5
RK
473 expect(channelWithView.viewsPerDay.slice(-1)[0].views).to.equal(2)
474 }
475 })
476
c6f8ca4d
FC
477 it('Should report correct total views count', async function () {
478 // check if there's the property
479 {
480 const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true })
481
482 for (const channel of data) {
483 expect(channel).to.haveOwnProperty('totalViews')
484 expect(channel.totalViews).to.be.a('number')
485 }
486 }
487
488 // Check if the totalViews count can be updated
489 {
490 const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true })
491 const channelWithView = data.find(channel => channel.id === servers[0].store.channel.id)
492 expect(channelWithView.totalViews).to.equal(2)
493 }
494 })
495
1ba471c5 496 it('Should report correct videos count', async function () {
89d241a7 497 const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true })
1ba471c5 498
a5461888
C
499 const totoChannel = data.find(c => c.name === 'toto_channel')
500 const rootChannel = data.find(c => c.name === 'root_channel')
1ba471c5
C
501
502 expect(rootChannel.videosCount).to.equal(1)
503 expect(totoChannel.videosCount).to.equal(0)
504 })
505
7b390964
RK
506 it('Should search among account video channels', async function () {
507 {
89d241a7 508 const body = await servers[0].channels.listByAccount({ accountName, search: 'root' })
a5461888 509 expect(body.total).to.equal(1)
7b390964 510
a5461888 511 const channels = body.data
7b390964
RK
512 expect(channels).to.have.lengthOf(1)
513 }
514
515 {
89d241a7 516 const body = await servers[0].channels.listByAccount({ accountName, search: 'does not exist' })
a5461888 517 expect(body.total).to.equal(0)
7b390964 518
a5461888 519 const channels = body.data
7b390964
RK
520 expect(channels).to.have.lengthOf(0)
521 }
522 })
523
e024fd6a
C
524 it('Should list channels by updatedAt desc if a video has been uploaded', async function () {
525 this.timeout(30000)
526
89d241a7 527 await servers[0].videos.upload({ attributes: { channelId: totoChannel } })
e024fd6a
C
528 await waitJobs(servers)
529
530 for (const server of servers) {
89d241a7 531 const { data } = await server.channels.listByAccount({ accountName, sort: '-updatedAt' })
e024fd6a 532
a5461888
C
533 expect(data[0].name).to.equal('toto_channel')
534 expect(data[1].name).to.equal('root_channel')
e024fd6a
C
535 }
536
89d241a7 537 await servers[0].videos.upload({ attributes: { channelId: servers[0].store.channel.id } })
e024fd6a
C
538 await waitJobs(servers)
539
540 for (const server of servers) {
89d241a7 541 const { data } = await server.channels.listByAccount({ accountName, sort: '-updatedAt' })
e024fd6a 542
a5461888
C
543 expect(data[0].name).to.equal('root_channel')
544 expect(data[1].name).to.equal('toto_channel')
e024fd6a
C
545 }
546 })
547
7c3b7976
C
548 after(async function () {
549 await cleanupTests(servers)
5f04dd2f
C
550 })
551})