1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
3 import { expect } from 'chai'
4 import { basename } from 'path'
5 import { ACTOR_IMAGES_SIZE } from '@server/initializers/constants'
6 import { testFileExistsOrNot, testImage } from '@server/tests/shared'
7 import { wait } from '@shared/core-utils'
8 import { ActorImageType, User, VideoChannel } from '@shared/models'
11 createMultipleServers,
14 setAccessTokensToServers,
15 setDefaultAccountAvatar,
16 setDefaultVideoChannel,
18 } from '@shared/server-commands'
20 async function findChannel (server: PeerTubeServer, channelId: number) {
21 const body = await server.channels.list({ sort: '-name' })
23 return body.data.find(c => c.id === channelId)
26 describe('Test video channels', function () {
27 let servers: PeerTubeServer[]
29 let secondVideoChannelId: number
30 let totoChannel: number
32 let accountName: string
33 let secondUserChannelName: string
35 const avatarPaths: { [ port: number ]: string } = {}
36 const bannerPaths: { [ port: number ]: string } = {}
38 before(async function () {
41 servers = await createMultipleServers(2)
43 await setAccessTokensToServers(servers)
44 await setDefaultVideoChannel(servers)
45 await setDefaultAccountAvatar(servers)
47 await doubleFollow(servers[0], servers[1])
50 it('Should have one video channel (created with root)', async () => {
51 const body = await servers[0].channels.list({ start: 0, count: 2 })
53 expect(body.total).to.equal(1)
54 expect(body.data).to.be.an('array')
55 expect(body.data).to.have.lengthOf(1)
58 it('Should create another video channel', async function () {
62 const videoChannel = {
63 name: 'second_video_channel',
64 displayName: 'second video channel',
65 description: 'super video channel description',
66 support: 'super video channel support text'
68 const created = await servers[0].channels.create({ attributes: videoChannel })
69 secondVideoChannelId = created.id
72 // The channel is 1 is propagated to servers 2
74 const attributes = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' }
75 const { uuid } = await servers[0].videos.upload({ attributes })
79 await waitJobs(servers)
82 it('Should have two video channels when getting my information', async () => {
83 userInfo = await servers[0].users.getMyInfo()
85 expect(userInfo.videoChannels).to.be.an('array')
86 expect(userInfo.videoChannels).to.have.lengthOf(2)
88 const videoChannels = userInfo.videoChannels
89 expect(videoChannels[0].name).to.equal('root_channel')
90 expect(videoChannels[0].displayName).to.equal('Main root channel')
92 expect(videoChannels[1].name).to.equal('second_video_channel')
93 expect(videoChannels[1].displayName).to.equal('second video channel')
94 expect(videoChannels[1].description).to.equal('super video channel description')
95 expect(videoChannels[1].support).to.equal('super video channel support text')
97 accountName = userInfo.account.name + '@' + userInfo.account.host
100 it('Should have two video channels when getting account channels on server 1', async function () {
101 const body = await servers[0].channels.listByAccount({ accountName })
102 expect(body.total).to.equal(2)
104 const videoChannels = body.data
106 expect(videoChannels).to.be.an('array')
107 expect(videoChannels).to.have.lengthOf(2)
109 expect(videoChannels[0].name).to.equal('root_channel')
110 expect(videoChannels[0].displayName).to.equal('Main root channel')
112 expect(videoChannels[1].name).to.equal('second_video_channel')
113 expect(videoChannels[1].displayName).to.equal('second video channel')
114 expect(videoChannels[1].description).to.equal('super video channel description')
115 expect(videoChannels[1].support).to.equal('super video channel support text')
118 it('Should paginate and sort account channels', async function () {
120 const body = await servers[0].channels.listByAccount({
127 expect(body.total).to.equal(2)
128 expect(body.data).to.have.lengthOf(1)
130 const videoChannel: VideoChannel = body.data[0]
131 expect(videoChannel.name).to.equal('root_channel')
135 const body = await servers[0].channels.listByAccount({
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')
148 const body = await servers[0].channels.listByAccount({
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')
161 it('Should have one video channel when getting account channels on server 2', async function () {
162 const body = await servers[1].channels.listByAccount({ accountName })
164 expect(body.total).to.equal(1)
165 expect(body.data).to.be.an('array')
166 expect(body.data).to.have.lengthOf(1)
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')
175 it('Should list video channels', async function () {
176 const body = await servers[0].channels.list({ start: 1, count: 1, sort: '-name' })
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')
185 it('Should update video channel', async function () {
188 const videoChannelAttributes = {
189 displayName: 'video channel updated',
190 description: 'video channel description updated',
191 support: 'support updated'
194 await servers[0].channels.update({ channelName: 'second_video_channel', attributes: videoChannelAttributes })
196 await waitJobs(servers)
199 it('Should have video channel updated', async function () {
200 for (const server of servers) {
201 const body = await server.channels.list({ start: 0, count: 1, sort: '-name' })
203 expect(body.total).to.equal(2)
204 expect(body.data).to.be.an('array')
205 expect(body.data).to.have.lengthOf(1)
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')
214 it('Should not have updated the video support field', async function () {
215 for (const server of servers) {
216 const video = await server.videos.get({ id: videoUUID })
217 expect(video.support).to.equal('video support field')
221 it('Should update another accounts video channel', async function () {
224 const result = await servers[0].users.generate('second_user')
225 secondUserChannelName = result.userChannelName
227 await servers[0].videos.quickUpload({ name: 'video', token: result.token })
229 const videoChannelAttributes = {
230 displayName: 'video channel updated',
231 description: 'video channel description updated',
232 support: 'support updated'
235 await servers[0].channels.update({ channelName: secondUserChannelName, attributes: videoChannelAttributes })
237 await waitJobs(servers)
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}` })
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')
250 it('Should update the channel support field and update videos too', async function () {
253 const videoChannelAttributes = {
254 support: 'video channel support text updated',
255 bulkVideosSupportUpdate: true
258 await servers[0].channels.update({ channelName: 'second_video_channel', attributes: videoChannelAttributes })
260 await waitJobs(servers)
262 for (const server of servers) {
263 const video = await server.videos.get({ id: videoUUID })
264 expect(video.support).to.equal(videoChannelAttributes.support)
268 it('Should update video channel avatar', async function () {
271 const fixture = 'avatar.png'
273 await servers[0].channels.updateImage({
274 channelName: 'second_video_channel',
279 await waitJobs(servers)
281 for (const server of servers) {
282 const videoChannel = await findChannel(server, secondVideoChannelId)
283 const expectedSizes = ACTOR_IMAGES_SIZE[ActorImageType.AVATAR]
285 expect(videoChannel.avatars.length).to.equal(expectedSizes.length, 'Expected avatars to be generated in all sizes')
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)
292 const row = await server.sql.getActorImage(basename(avatarPaths[server.port]))
294 expect(expectedSizes.some(({ height, width }) => row.height === height && row.width === width)).to.equal(true)
299 it('Should update video channel banner', async function () {
302 const fixture = 'banner.jpg'
304 await servers[0].channels.updateImage({
305 channelName: 'second_video_channel',
310 await waitJobs(servers)
312 for (const server of servers) {
313 const videoChannel = await server.channels.get({ channelName: 'second_video_channel@' + servers[0].host })
315 bannerPaths[server.port] = videoChannel.banners[0].path
316 await testImage(server.url, 'banner-resized', bannerPaths[server.port])
317 await testFileExistsOrNot(server, 'avatars', basename(bannerPaths[server.port]), true)
319 const row = await server.sql.getActorImage(basename(bannerPaths[server.port]))
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)
325 it('Should still correctly list channels', async function () {
327 const body = await servers[0].channels.list({ start: 1, count: 1, sort: 'createdAt' })
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')
335 const body = await servers[0].channels.listByAccount({ accountName, start: 1, count: 1, sort: 'createdAt' })
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')
343 it('Should delete the video channel avatar', async function () {
345 await servers[0].channels.deleteImage({ channelName: 'second_video_channel', type: 'avatar' })
347 await waitJobs(servers)
349 for (const server of servers) {
350 const videoChannel = await findChannel(server, secondVideoChannelId)
351 await testFileExistsOrNot(server, 'avatars', basename(avatarPaths[server.port]), false)
353 expect(videoChannel.avatars).to.be.empty
357 it('Should delete the video channel banner', async function () {
360 await servers[0].channels.deleteImage({ channelName: 'second_video_channel', type: 'banner' })
362 await waitJobs(servers)
364 for (const server of servers) {
365 const videoChannel = await findChannel(server, secondVideoChannelId)
366 await testFileExistsOrNot(server, 'avatars', basename(bannerPaths[server.port]), false)
368 expect(videoChannel.banners).to.be.empty
372 it('Should list the second video channel videos', async function () {
375 for (const server of servers) {
376 const channelURI = 'second_video_channel@localhost:' + servers[0].port
377 const { total, data } = await server.videos.listByChannel({ handle: channelURI })
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')
386 it('Should change the video channel of a video', async function () {
389 await servers[0].videos.update({ id: videoUUID, attributes: { channelId: servers[0].store.channel.id } })
391 await waitJobs(servers)
394 it('Should list the first video channel videos', async function () {
397 for (const server of servers) {
399 const secondChannelURI = 'second_video_channel@localhost:' + servers[0].port
400 const { total } = await server.videos.listByChannel({ handle: secondChannelURI })
401 expect(total).to.equal(0)
405 const channelURI = 'root_channel@localhost:' + servers[0].port
406 const { total, data } = await server.videos.listByChannel({ handle: channelURI })
407 expect(total).to.equal(1)
409 expect(data).to.be.an('array')
410 expect(data).to.have.lengthOf(1)
411 expect(data[0].name).to.equal('my video name')
416 it('Should delete video channel', async function () {
417 await servers[0].channels.delete({ channelName: 'second_video_channel' })
420 it('Should have video channel deleted', async function () {
421 const body = await servers[0].channels.list({ start: 0, count: 10, sort: 'createdAt' })
423 expect(body.total).to.equal(2)
424 expect(body.data).to.be.an('array')
425 expect(body.data).to.have.lengthOf(2)
426 expect(body.data[0].displayName).to.equal('Main root channel')
427 expect(body.data[1].displayName).to.equal('video channel updated')
430 it('Should create the main channel with a suffix if there is a conflict', async function () {
432 const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' }
433 const created = await servers[0].channels.create({ attributes: videoChannel })
434 totoChannel = created.id
438 await servers[0].users.create({ username: 'toto', password: 'password' })
439 const accessToken = await servers[0].login.getAccessToken({ username: 'toto', password: 'password' })
441 const { videoChannels } = await servers[0].users.getMyInfo({ token: accessToken })
442 expect(videoChannels[0].name).to.equal('toto_channel-1')
446 it('Should report correct channel views per days', async function () {
450 const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true })
452 for (const channel of data) {
453 expect(channel).to.haveOwnProperty('viewsPerDay')
454 expect(channel.viewsPerDay).to.have.length(30 + 1) // daysPrior + today
456 for (const v of channel.viewsPerDay) {
457 expect(v.date).to.be.an('string')
458 expect(v.views).to.equal(0)
464 // video has been posted on channel servers[0].store.videoChannel.id since last update
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' })
468 // Wait the repeatable job
471 const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true })
472 const channelWithView = data.find(channel => channel.id === servers[0].store.channel.id)
473 expect(channelWithView.viewsPerDay.slice(-1)[0].views).to.equal(2)
477 it('Should report correct total views count', async function () {
478 // check if there's the property
480 const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true })
482 for (const channel of data) {
483 expect(channel).to.haveOwnProperty('totalViews')
484 expect(channel.totalViews).to.be.a('number')
488 // Check if the totalViews count can be updated
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)
496 it('Should report correct videos count', async function () {
497 const { data } = await servers[0].channels.listByAccount({ accountName, withStats: true })
499 const totoChannel = data.find(c => c.name === 'toto_channel')
500 const rootChannel = data.find(c => c.name === 'root_channel')
502 expect(rootChannel.videosCount).to.equal(1)
503 expect(totoChannel.videosCount).to.equal(0)
506 it('Should search among account video channels', async function () {
508 const body = await servers[0].channels.listByAccount({ accountName, search: 'root' })
509 expect(body.total).to.equal(1)
511 const channels = body.data
512 expect(channels).to.have.lengthOf(1)
516 const body = await servers[0].channels.listByAccount({ accountName, search: 'does not exist' })
517 expect(body.total).to.equal(0)
519 const channels = body.data
520 expect(channels).to.have.lengthOf(0)
524 it('Should list channels by updatedAt desc if a video has been uploaded', async function () {
527 await servers[0].videos.upload({ attributes: { channelId: totoChannel } })
528 await waitJobs(servers)
530 for (const server of servers) {
531 const { data } = await server.channels.listByAccount({ accountName, sort: '-updatedAt' })
533 expect(data[0].name).to.equal('toto_channel')
534 expect(data[1].name).to.equal('root_channel')
537 await servers[0].videos.upload({ attributes: { channelId: servers[0].store.channel.id } })
538 await waitJobs(servers)
540 for (const server of servers) {
541 const { data } = await server.channels.listByAccount({ accountName, sort: '-updatedAt' })
543 expect(data[0].name).to.equal('root_channel')
544 expect(data[1].name).to.equal('toto_channel')
548 after(async function () {
549 await cleanupTests(servers)