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