]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tests/utils/videos/videos.ts
Don't show videos of remote instance after unfollow
[github/Chocobozzz/PeerTube.git] / server / tests / utils / videos / videos.ts
1 /* tslint:disable:no-unused-expression */
2
3 import { expect } from 'chai'
4 import { existsSync, readFile } from 'fs'
5 import * as parseTorrent from 'parse-torrent'
6 import { extname, isAbsolute, join } from 'path'
7 import * as request from 'supertest'
8 import { getMyUserInformation, makeGetRequest, root, ServerInfo } from '../'
9 import { VideoPrivacy } from '../../../../shared/models/videos'
10 import { readdirPromise, readFileBufferPromise } from '../../../helpers/core-utils'
11 import { VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../initializers'
12 import { dateIsValid, webtorrentAdd } from '../index'
13
14 type VideoAttributes = {
15 name?: string
16 category?: number
17 licence?: number
18 language?: number
19 nsfw?: boolean
20 commentsEnabled?: boolean
21 description?: string
22 tags?: string[]
23 channelId?: number
24 privacy?: VideoPrivacy
25 fixture?: string
26 }
27
28 function getVideoCategories (url: string) {
29 const path = '/api/v1/videos/categories'
30
31 return makeGetRequest({
32 url,
33 path,
34 statusCodeExpected: 200
35 })
36 }
37
38 function getVideoLicences (url: string) {
39 const path = '/api/v1/videos/licences'
40
41 return makeGetRequest({
42 url,
43 path,
44 statusCodeExpected: 200
45 })
46 }
47
48 function getVideoLanguages (url: string) {
49 const path = '/api/v1/videos/languages'
50
51 return makeGetRequest({
52 url,
53 path,
54 statusCodeExpected: 200
55 })
56 }
57
58 function getVideoPrivacies (url: string) {
59 const path = '/api/v1/videos/privacies'
60
61 return makeGetRequest({
62 url,
63 path,
64 statusCodeExpected: 200
65 })
66 }
67
68 function getVideo (url: string, id: number | string, expectedStatus = 200) {
69 const path = '/api/v1/videos/' + id
70
71 return request(url)
72 .get(path)
73 .set('Accept', 'application/json')
74 .expect(expectedStatus)
75 }
76
77 function viewVideo (url: string, id: number | string, expectedStatus = 204) {
78 const path = '/api/v1/videos/' + id + '/views'
79
80 return request(url)
81 .post(path)
82 .set('Accept', 'application/json')
83 .expect(expectedStatus)
84 }
85
86 function getVideoWithToken (url: string, token: string, id: number | string, expectedStatus = 200) {
87 const path = '/api/v1/videos/' + id
88
89 return request(url)
90 .get(path)
91 .set('Authorization', 'Bearer ' + token)
92 .set('Accept', 'application/json')
93 .expect(expectedStatus)
94 }
95
96 function getVideoDescription (url: string, descriptionPath: string) {
97 return request(url)
98 .get(descriptionPath)
99 .set('Accept', 'application/json')
100 .expect(200)
101 .expect('Content-Type', /json/)
102 }
103
104 function getVideosList (url: string) {
105 const path = '/api/v1/videos'
106
107 return request(url)
108 .get(path)
109 .query({ sort: 'name' })
110 .set('Accept', 'application/json')
111 .expect(200)
112 .expect('Content-Type', /json/)
113 }
114
115 function getMyVideos (url: string, accessToken: string, start: number, count: number, sort?: string) {
116 const path = '/api/v1/users/me/videos'
117
118 const req = request(url)
119 .get(path)
120 .query({ start: start })
121 .query({ count: count })
122
123 if (sort) req.query({ sort })
124
125 return req.set('Accept', 'application/json')
126 .set('Authorization', 'Bearer ' + accessToken)
127 .expect(200)
128 .expect('Content-Type', /json/)
129 }
130
131 function getVideosListPagination (url: string, start: number, count: number, sort?: string) {
132 const path = '/api/v1/videos'
133
134 const req = request(url)
135 .get(path)
136 .query({ start: start })
137 .query({ count: count })
138
139 if (sort) req.query({ sort })
140
141 return req.set('Accept', 'application/json')
142 .expect(200)
143 .expect('Content-Type', /json/)
144 }
145
146 function getVideosListSort (url: string, sort: string) {
147 const path = '/api/v1/videos'
148
149 return request(url)
150 .get(path)
151 .query({ sort: sort })
152 .set('Accept', 'application/json')
153 .expect(200)
154 .expect('Content-Type', /json/)
155 }
156
157 function removeVideo (url: string, token: string, id: number | string, expectedStatus = 204) {
158 const path = '/api/v1/videos'
159
160 return request(url)
161 .delete(path + '/' + id)
162 .set('Accept', 'application/json')
163 .set('Authorization', 'Bearer ' + token)
164 .expect(expectedStatus)
165 }
166
167 function searchVideo (url: string, search: string) {
168 const path = '/api/v1/videos'
169 const req = request(url)
170 .get(path + '/search')
171 .query({ search })
172 .set('Accept', 'application/json')
173
174 return req.expect(200)
175 .expect('Content-Type', /json/)
176 }
177
178 function searchVideoWithPagination (url: string, search: string, start: number, count: number, sort?: string) {
179 const path = '/api/v1/videos'
180
181 const req = request(url)
182 .get(path + '/search')
183 .query({ start })
184 .query({ search })
185 .query({ count })
186
187 if (sort) req.query({ sort })
188
189 return req.set('Accept', 'application/json')
190 .expect(200)
191 .expect('Content-Type', /json/)
192 }
193
194 function searchVideoWithSort (url: string, search: string, sort: string) {
195 const path = '/api/v1/videos'
196
197 return request(url)
198 .get(path + '/search')
199 .query({ search })
200 .query({ sort })
201 .set('Accept', 'application/json')
202 .expect(200)
203 .expect('Content-Type', /json/)
204 }
205
206 async function checkVideoFilesWereRemoved (videoUUID: string, serverNumber: number) {
207 const testDirectory = 'test' + serverNumber
208
209 for (const directory of [ 'videos', 'thumbnails', 'torrents', 'previews' ]) {
210 const directoryPath = join(root(), testDirectory, directory)
211
212 const directoryExists = existsSync(directoryPath)
213 expect(directoryExists).to.be.true
214
215 const files = await readdirPromise(directoryPath)
216 for (const file of files) {
217 expect(file).to.not.contain(videoUUID)
218 }
219 }
220 }
221
222 async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') {
223 // Don't test images if the node env is not set
224 // Because we need a special ffmpeg version for this test
225 if (process.env['NODE_TEST_IMAGE']) {
226 const res = await request(url)
227 .get(imagePath)
228 .expect(200)
229
230 const data = await readFileBufferPromise(join(__dirname, '..', '..', 'api', 'fixtures', imageName + extension))
231
232 return data.equals(res.body)
233 } else {
234 console.log('Do not test images. Enable it by setting NODE_TEST_IMAGE env variable.')
235 return true
236 }
237 }
238
239 async function uploadVideo (url: string, accessToken: string, videoAttributesArg: VideoAttributes, specialStatus = 200) {
240 const path = '/api/v1/videos/upload'
241 let defaultChannelId = '1'
242
243 try {
244 const res = await getMyUserInformation(url, accessToken)
245 defaultChannelId = res.body.videoChannels[0].id
246 } catch (e) { /* empty */ }
247
248 // Default attributes
249 let attributes = {
250 name: 'my super video',
251 category: 5,
252 licence: 4,
253 language: 3,
254 channelId: defaultChannelId,
255 nsfw: true,
256 description: 'my super description',
257 tags: [ 'tag' ],
258 privacy: VideoPrivacy.PUBLIC,
259 commentsEnabled: true,
260 fixture: 'video_short.webm'
261 }
262 attributes = Object.assign(attributes, videoAttributesArg)
263
264 const req = request(url)
265 .post(path)
266 .set('Accept', 'application/json')
267 .set('Authorization', 'Bearer ' + accessToken)
268 .field('name', attributes.name)
269 .field('category', attributes.category.toString())
270 .field('licence', attributes.licence.toString())
271 .field('nsfw', JSON.stringify(attributes.nsfw))
272 .field('commentsEnabled', JSON.stringify(attributes.commentsEnabled))
273 .field('description', attributes.description)
274 .field('privacy', attributes.privacy.toString())
275 .field('channelId', attributes.channelId)
276
277 if (attributes.language !== undefined) {
278 req.field('language', attributes.language.toString())
279 }
280
281 for (let i = 0; i < attributes.tags.length; i++) {
282 req.field('tags[' + i + ']', attributes.tags[i])
283 }
284
285 let filePath = ''
286 if (isAbsolute(attributes.fixture)) {
287 filePath = attributes.fixture
288 } else {
289 filePath = join(__dirname, '..', '..', 'api', 'fixtures', attributes.fixture)
290 }
291
292 return req.attach('videofile', filePath)
293 .expect(specialStatus)
294 }
295
296 function updateVideo (url: string, accessToken: string, id: number | string, attributes: VideoAttributes, specialStatus = 204) {
297 const path = '/api/v1/videos/' + id
298 const body = {}
299
300 if (attributes.name) body['name'] = attributes.name
301 if (attributes.category) body['category'] = attributes.category
302 if (attributes.licence) body['licence'] = attributes.licence
303 if (attributes.language) body['language'] = attributes.language
304 if (attributes.nsfw !== undefined) body['nsfw'] = JSON.stringify(attributes.nsfw)
305 if (attributes.commentsEnabled !== undefined) body['commentsEnabled'] = JSON.stringify(attributes.commentsEnabled)
306 if (attributes.description) body['description'] = attributes.description
307 if (attributes.tags) body['tags'] = attributes.tags
308 if (attributes.privacy) body['privacy'] = attributes.privacy
309
310 return request(url)
311 .put(path)
312 .send(body)
313 .set('Accept', 'application/json')
314 .set('Authorization', 'Bearer ' + accessToken)
315 .expect(specialStatus)
316 }
317
318 function rateVideo (url: string, accessToken: string, id: number, rating: string, specialStatus = 204) {
319 const path = '/api/v1/videos/' + id + '/rate'
320
321 return request(url)
322 .put(path)
323 .set('Accept', 'application/json')
324 .set('Authorization', 'Bearer ' + accessToken)
325 .send({ rating })
326 .expect(specialStatus)
327 }
328
329 function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) {
330 return new Promise<any>((res, rej) => {
331 const torrentName = videoUUID + '-' + resolution + '.torrent'
332 const torrentPath = join(__dirname, '..', '..', '..', '..', 'test' + server.serverNumber, 'torrents', torrentName)
333 readFile(torrentPath, (err, data) => {
334 if (err) return rej(err)
335
336 return res(parseTorrent(data))
337 })
338 })
339 }
340
341 async function completeVideoCheck (
342 url: string,
343 video: any,
344 attributes: {
345 name: string
346 category: number
347 licence: number
348 language: number
349 nsfw: boolean
350 commentsEnabled: boolean
351 description: string
352 host: string
353 account: string
354 isLocal: boolean,
355 tags: string[],
356 privacy: number,
357 likes?: number,
358 dislikes?: number,
359 duration: number,
360 channel: {
361 name: string,
362 description
363 isLocal: boolean
364 }
365 fixture: string,
366 files: {
367 resolution: number
368 size: number
369 }[]
370 }
371 ) {
372 if (!attributes.likes) attributes.likes = 0
373 if (!attributes.dislikes) attributes.dislikes = 0
374
375 expect(video.name).to.equal(attributes.name)
376 expect(video.category).to.equal(attributes.category)
377 expect(video.categoryLabel).to.equal(VIDEO_CATEGORIES[attributes.category] || 'Misc')
378 expect(video.licence).to.equal(attributes.licence)
379 expect(video.licenceLabel).to.equal(VIDEO_LICENCES[attributes.licence] || 'Unknown')
380 expect(video.language).to.equal(attributes.language)
381 expect(video.languageLabel).to.equal(VIDEO_LANGUAGES[attributes.language] || 'Unknown')
382 expect(video.nsfw).to.equal(attributes.nsfw)
383 expect(video.description).to.equal(attributes.description)
384 expect(video.serverHost).to.equal(attributes.host)
385 expect(video.accountName).to.equal(attributes.account)
386 expect(video.likes).to.equal(attributes.likes)
387 expect(video.dislikes).to.equal(attributes.dislikes)
388 expect(video.isLocal).to.equal(attributes.isLocal)
389 expect(video.duration).to.equal(attributes.duration)
390 expect(dateIsValid(video.createdAt)).to.be.true
391 expect(dateIsValid(video.updatedAt)).to.be.true
392
393 const res = await getVideo(url, video.id)
394 const videoDetails = res.body
395
396 expect(videoDetails.files).to.have.lengthOf(attributes.files.length)
397 expect(videoDetails.tags).to.deep.equal(attributes.tags)
398 expect(videoDetails.privacy).to.deep.equal(attributes.privacy)
399 expect(videoDetails.privacyLabel).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy])
400 expect(videoDetails.account.name).to.equal(attributes.account)
401 expect(videoDetails.commentsEnabled).to.equal(attributes.commentsEnabled)
402
403 expect(videoDetails.channel.displayName).to.equal(attributes.channel.name)
404 expect(videoDetails.channel.name).to.have.lengthOf(36)
405 expect(videoDetails.channel.isLocal).to.equal(attributes.channel.isLocal)
406 expect(dateIsValid(videoDetails.channel.createdAt)).to.be.true
407 expect(dateIsValid(videoDetails.channel.updatedAt)).to.be.true
408
409 for (const attributeFile of attributes.files) {
410 const file = videoDetails.files.find(f => f.resolution === attributeFile.resolution)
411 expect(file).not.to.be.undefined
412
413 let extension = extname(attributes.fixture)
414 // Transcoding enabled on server 2, extension will always be .mp4
415 if (attributes.host === 'localhost:9002') extension = '.mp4'
416
417 const magnetUri = file.magnetUri
418 expect(file.magnetUri).to.have.lengthOf.above(2)
419 expect(file.torrentUrl).to.equal(`http://${attributes.host}/static/torrents/${videoDetails.uuid}-${file.resolution}.torrent`)
420 expect(file.fileUrl).to.equal(`http://${attributes.host}/static/webseed/${videoDetails.uuid}-${file.resolution}${extension}`)
421 expect(file.resolution).to.equal(attributeFile.resolution)
422 expect(file.resolutionLabel).to.equal(attributeFile.resolution + 'p')
423
424 const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
425 const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
426 expect(file.size).to.be.above(minSize).and.below(maxSize)
427
428 const test = await testImage(url, attributes.fixture, videoDetails.thumbnailPath)
429 expect(test).to.equal(true)
430
431 const torrent = await webtorrentAdd(magnetUri, true)
432 expect(torrent.files).to.be.an('array')
433 expect(torrent.files.length).to.equal(1)
434 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
435 }
436 }
437
438 // ---------------------------------------------------------------------------
439
440 export {
441 getVideoDescription,
442 getVideoCategories,
443 getVideoLicences,
444 getVideoPrivacies,
445 getVideoLanguages,
446 getMyVideos,
447 getVideo,
448 getVideoWithToken,
449 getVideosList,
450 getVideosListPagination,
451 getVideosListSort,
452 removeVideo,
453 searchVideo,
454 searchVideoWithPagination,
455 searchVideoWithSort,
456 testImage,
457 uploadVideo,
458 updateVideo,
459 rateVideo,
460 viewVideo,
461 parseTorrentVideo,
462 completeVideoCheck,
463 checkVideoFilesWereRemoved
464 }