]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/utils/videos/videos.ts
Add new name/terms/description config options
[github/Chocobozzz/PeerTube.git] / server / tests / utils / videos / videos.ts
CommitLineData
a20399c9
C
1/* tslint:disable:no-unused-expression */
2
3import { expect } from 'chai'
f05a1c30 4import { existsSync, readFile } from 'fs'
fdbda9e3 5import * as parseTorrent from 'parse-torrent'
b1f5b93e 6import { extname, isAbsolute, join } from 'path'
c5d31dba 7import * as request from 'supertest'
9ee83eb9 8import { getMyUserInformation, makeGetRequest, root, ServerInfo, testImage } from '../'
c5d31dba 9import { VideoPrivacy } from '../../../../shared/models/videos'
5e1c08eb 10import { readdirPromise } from '../../../helpers/core-utils'
a20399c9
C
11import { VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../initializers'
12import { dateIsValid, webtorrentAdd } from '../index'
0e1dc3e7
C
13
14type VideoAttributes = {
15 name?: string
16 category?: number
17 licence?: number
18 language?: number
19 nsfw?: boolean
47564bbe 20 commentsEnabled?: boolean
0e1dc3e7
C
21 description?: string
22 tags?: string[]
5f04dd2f 23 channelId?: number
11474c3c 24 privacy?: VideoPrivacy
0e1dc3e7
C
25 fixture?: string
26}
27
28function getVideoCategories (url: string) {
29 const path = '/api/v1/videos/categories'
30
eec63bbc
C
31 return makeGetRequest({
32 url,
59651eee
C
33 path,
34 statusCodeExpected: 200
eec63bbc 35 })
0e1dc3e7
C
36}
37
38function getVideoLicences (url: string) {
39 const path = '/api/v1/videos/licences'
40
eec63bbc
C
41 return makeGetRequest({
42 url,
59651eee
C
43 path,
44 statusCodeExpected: 200
eec63bbc 45 })
0e1dc3e7
C
46}
47
48function getVideoLanguages (url: string) {
49 const path = '/api/v1/videos/languages'
50
eec63bbc
C
51 return makeGetRequest({
52 url,
59651eee
C
53 path,
54 statusCodeExpected: 200
eec63bbc 55 })
0e1dc3e7
C
56}
57
11474c3c
C
58function getVideoPrivacies (url: string) {
59 const path = '/api/v1/videos/privacies'
60
eec63bbc
C
61 return makeGetRequest({
62 url,
59651eee
C
63 path,
64 statusCodeExpected: 200
eec63bbc 65 })
11474c3c
C
66}
67
11474c3c 68function getVideo (url: string, id: number | string, expectedStatus = 200) {
0e1dc3e7
C
69 const path = '/api/v1/videos/' + id
70
71 return request(url)
72 .get(path)
73 .set('Accept', 'application/json')
11474c3c
C
74 .expect(expectedStatus)
75}
76
1f3e9fec
C
77function 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
11474c3c
C
86function 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)
0e1dc3e7
C
94}
95
9567011b
C
96function 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
0e1dc3e7
C
104function 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
11474c3c
C
115function 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
0e1dc3e7
C
131function 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
146function 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
11ba2ab3 157function removeVideo (url: string, token: string, id: number | string, expectedStatus = 204) {
0e1dc3e7
C
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
f3aaa9a9 167function searchVideo (url: string, search: string) {
0e1dc3e7
C
168 const path = '/api/v1/videos'
169 const req = request(url)
f3aaa9a9
C
170 .get(path + '/search')
171 .query({ search })
172 .set('Accept', 'application/json')
0e1dc3e7
C
173
174 return req.expect(200)
f3aaa9a9 175 .expect('Content-Type', /json/)
0e1dc3e7
C
176}
177
f3aaa9a9 178function searchVideoWithPagination (url: string, search: string, start: number, count: number, sort?: string) {
0e1dc3e7
C
179 const path = '/api/v1/videos'
180
181 const req = request(url)
f3aaa9a9 182 .get(path + '/search')
0e1dc3e7 183 .query({ start })
f3aaa9a9 184 .query({ search })
0e1dc3e7 185 .query({ count })
0e1dc3e7
C
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
194function searchVideoWithSort (url: string, search: string, sort: string) {
195 const path = '/api/v1/videos'
196
197 return request(url)
f3aaa9a9
C
198 .get(path + '/search')
199 .query({ search })
0e1dc3e7
C
200 .query({ sort })
201 .set('Accept', 'application/json')
202 .expect(200)
203 .expect('Content-Type', /json/)
204}
205
f05a1c30
C
206async 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
e11f68a3 222async function uploadVideo (url: string, accessToken: string, videoAttributesArg: VideoAttributes, specialStatus = 200) {
e95561cd 223 const path = '/api/v1/videos/upload'
5f04dd2f
C
224 let defaultChannelId = '1'
225
226 try {
227 const res = await getMyUserInformation(url, accessToken)
228 defaultChannelId = res.body.videoChannels[0].id
229 } catch (e) { /* empty */ }
0e1dc3e7
C
230
231 // Default attributes
232 let attributes = {
233 name: 'my super video',
234 category: 5,
235 licence: 4,
236 language: 3,
5f04dd2f 237 channelId: defaultChannelId,
0e1dc3e7
C
238 nsfw: true,
239 description: 'my super description',
240 tags: [ 'tag' ],
11474c3c 241 privacy: VideoPrivacy.PUBLIC,
47564bbe 242 commentsEnabled: true,
0e1dc3e7
C
243 fixture: 'video_short.webm'
244 }
245 attributes = Object.assign(attributes, videoAttributesArg)
246
247 const req = request(url)
248 .post(path)
249 .set('Accept', 'application/json')
250 .set('Authorization', 'Bearer ' + accessToken)
251 .field('name', attributes.name)
252 .field('category', attributes.category.toString())
253 .field('licence', attributes.licence.toString())
0e1dc3e7 254 .field('nsfw', JSON.stringify(attributes.nsfw))
47564bbe 255 .field('commentsEnabled', JSON.stringify(attributes.commentsEnabled))
0e1dc3e7 256 .field('description', attributes.description)
11474c3c 257 .field('privacy', attributes.privacy.toString())
5f04dd2f 258 .field('channelId', attributes.channelId)
0e1dc3e7 259
8df87ce7
C
260 if (attributes.language !== undefined) {
261 req.field('language', attributes.language.toString())
262 }
263
0e1dc3e7
C
264 for (let i = 0; i < attributes.tags.length; i++) {
265 req.field('tags[' + i + ']', attributes.tags[i])
266 }
267
14d3270f 268 let filePath = ''
0e1dc3e7 269 if (isAbsolute(attributes.fixture)) {
14d3270f 270 filePath = attributes.fixture
0e1dc3e7 271 } else {
331128ed 272 filePath = join(__dirname, '..', '..', 'api', 'fixtures', attributes.fixture)
0e1dc3e7
C
273 }
274
14d3270f 275 return req.attach('videofile', filePath)
0e1dc3e7
C
276 .expect(specialStatus)
277}
278
47564bbe 279function updateVideo (url: string, accessToken: string, id: number | string, attributes: VideoAttributes, specialStatus = 204) {
0e1dc3e7
C
280 const path = '/api/v1/videos/' + id
281 const body = {}
282
283 if (attributes.name) body['name'] = attributes.name
284 if (attributes.category) body['category'] = attributes.category
285 if (attributes.licence) body['licence'] = attributes.licence
286 if (attributes.language) body['language'] = attributes.language
47564bbe
C
287 if (attributes.nsfw !== undefined) body['nsfw'] = JSON.stringify(attributes.nsfw)
288 if (attributes.commentsEnabled !== undefined) body['commentsEnabled'] = JSON.stringify(attributes.commentsEnabled)
0e1dc3e7
C
289 if (attributes.description) body['description'] = attributes.description
290 if (attributes.tags) body['tags'] = attributes.tags
11474c3c 291 if (attributes.privacy) body['privacy'] = attributes.privacy
0e1dc3e7
C
292
293 return request(url)
294 .put(path)
295 .send(body)
296 .set('Accept', 'application/json')
297 .set('Authorization', 'Bearer ' + accessToken)
298 .expect(specialStatus)
299}
300
301function rateVideo (url: string, accessToken: string, id: number, rating: string, specialStatus = 204) {
302 const path = '/api/v1/videos/' + id + '/rate'
303
304 return request(url)
305 .put(path)
306 .set('Accept', 'application/json')
307 .set('Authorization', 'Bearer ' + accessToken)
308 .send({ rating })
309 .expect(specialStatus)
310}
311
14d3270f 312function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) {
fdbda9e3 313 return new Promise<any>((res, rej) => {
14d3270f 314 const torrentName = videoUUID + '-' + resolution + '.torrent'
331128ed 315 const torrentPath = join(__dirname, '..', '..', '..', '..', 'test' + server.serverNumber, 'torrents', torrentName)
fdbda9e3
C
316 readFile(torrentPath, (err, data) => {
317 if (err) return rej(err)
318
319 return res(parseTorrent(data))
320 })
321 })
322}
323
a20399c9
C
324async function completeVideoCheck (
325 url: string,
326 video: any,
327 attributes: {
328 name: string
329 category: number
330 licence: number
331 language: number
332 nsfw: boolean
47564bbe 333 commentsEnabled: boolean
a20399c9
C
334 description: string
335 host: string
336 account: string
337 isLocal: boolean,
338 tags: string[],
339 privacy: number,
b1f5b93e
C
340 likes?: number,
341 dislikes?: number,
342 duration: number,
a20399c9
C
343 channel: {
344 name: string,
b1f5b93e 345 description
a20399c9
C
346 isLocal: boolean
347 }
348 fixture: string,
349 files: {
350 resolution: number
351 size: number
352 }[]
353 }
354) {
b1f5b93e
C
355 if (!attributes.likes) attributes.likes = 0
356 if (!attributes.dislikes) attributes.dislikes = 0
357
a20399c9
C
358 expect(video.name).to.equal(attributes.name)
359 expect(video.category).to.equal(attributes.category)
b1f5b93e 360 expect(video.categoryLabel).to.equal(VIDEO_CATEGORIES[attributes.category] || 'Misc')
a20399c9 361 expect(video.licence).to.equal(attributes.licence)
b1f5b93e 362 expect(video.licenceLabel).to.equal(VIDEO_LICENCES[attributes.licence] || 'Unknown')
a20399c9 363 expect(video.language).to.equal(attributes.language)
b1f5b93e 364 expect(video.languageLabel).to.equal(VIDEO_LANGUAGES[attributes.language] || 'Unknown')
a20399c9
C
365 expect(video.nsfw).to.equal(attributes.nsfw)
366 expect(video.description).to.equal(attributes.description)
367 expect(video.serverHost).to.equal(attributes.host)
368 expect(video.accountName).to.equal(attributes.account)
b1f5b93e
C
369 expect(video.likes).to.equal(attributes.likes)
370 expect(video.dislikes).to.equal(attributes.dislikes)
a20399c9 371 expect(video.isLocal).to.equal(attributes.isLocal)
b1f5b93e 372 expect(video.duration).to.equal(attributes.duration)
a20399c9
C
373 expect(dateIsValid(video.createdAt)).to.be.true
374 expect(dateIsValid(video.updatedAt)).to.be.true
375
66b16caf 376 const res = await getVideo(url, video.uuid)
a20399c9
C
377 const videoDetails = res.body
378
379 expect(videoDetails.files).to.have.lengthOf(attributes.files.length)
380 expect(videoDetails.tags).to.deep.equal(attributes.tags)
381 expect(videoDetails.privacy).to.deep.equal(attributes.privacy)
382 expect(videoDetails.privacyLabel).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy])
383 expect(videoDetails.account.name).to.equal(attributes.account)
47564bbe 384 expect(videoDetails.commentsEnabled).to.equal(attributes.commentsEnabled)
a20399c9 385
7bc29171
C
386 expect(videoDetails.channel.displayName).to.equal(attributes.channel.name)
387 expect(videoDetails.channel.name).to.have.lengthOf(36)
a20399c9
C
388 expect(videoDetails.channel.isLocal).to.equal(attributes.channel.isLocal)
389 expect(dateIsValid(videoDetails.channel.createdAt)).to.be.true
390 expect(dateIsValid(videoDetails.channel.updatedAt)).to.be.true
391
392 for (const attributeFile of attributes.files) {
393 const file = videoDetails.files.find(f => f.resolution === attributeFile.resolution)
394 expect(file).not.to.be.undefined
395
b1f5b93e
C
396 let extension = extname(attributes.fixture)
397 // Transcoding enabled on server 2, extension will always be .mp4
398 if (attributes.host === 'localhost:9002') extension = '.mp4'
399
a20399c9
C
400 const magnetUri = file.magnetUri
401 expect(file.magnetUri).to.have.lengthOf.above(2)
b1f5b93e
C
402 expect(file.torrentUrl).to.equal(`http://${attributes.host}/static/torrents/${videoDetails.uuid}-${file.resolution}.torrent`)
403 expect(file.fileUrl).to.equal(`http://${attributes.host}/static/webseed/${videoDetails.uuid}-${file.resolution}${extension}`)
a20399c9
C
404 expect(file.resolution).to.equal(attributeFile.resolution)
405 expect(file.resolutionLabel).to.equal(attributeFile.resolution + 'p')
b1f5b93e
C
406
407 const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
408 const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
409 expect(file.size).to.be.above(minSize).and.below(maxSize)
a20399c9 410
f05a1c30 411 const test = await testImage(url, attributes.fixture, videoDetails.thumbnailPath)
a20399c9
C
412 expect(test).to.equal(true)
413
414 const torrent = await webtorrentAdd(magnetUri, true)
415 expect(torrent.files).to.be.an('array')
416 expect(torrent.files.length).to.equal(1)
417 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
418 }
419}
420
0e1dc3e7
C
421// ---------------------------------------------------------------------------
422
423export {
9567011b 424 getVideoDescription,
0e1dc3e7
C
425 getVideoCategories,
426 getVideoLicences,
11474c3c 427 getVideoPrivacies,
0e1dc3e7 428 getVideoLanguages,
11474c3c 429 getMyVideos,
0e1dc3e7 430 getVideo,
11474c3c 431 getVideoWithToken,
0e1dc3e7
C
432 getVideosList,
433 getVideosListPagination,
434 getVideosListSort,
435 removeVideo,
436 searchVideo,
437 searchVideoWithPagination,
438 searchVideoWithSort,
0e1dc3e7
C
439 uploadVideo,
440 updateVideo,
fdbda9e3 441 rateVideo,
1f3e9fec 442 viewVideo,
a20399c9 443 parseTorrentVideo,
f05a1c30
C
444 completeVideoCheck,
445 checkVideoFilesWereRemoved
0e1dc3e7 446}