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