]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/tests/utils/videos/videos.ts
Add ability to choose what policy we have for NSFW videos
[github/Chocobozzz/PeerTube.git] / server / tests / utils / videos / videos.ts
index 7393942534b831be1da5fa0b5a5edb050ef2eedf..df9071c292fa8957082f69910da24755a040907b 100644 (file)
@@ -1,9 +1,24 @@
-import { readFile } from 'fs'
+/* tslint:disable:no-unused-expression */
+
+import { expect } from 'chai'
+import { existsSync, readFile } from 'fs'
 import * as parseTorrent from 'parse-torrent'
-import { isAbsolute, join } from 'path'
+import { extname, join } from 'path'
 import * as request from 'supertest'
-import { getMyUserInformation, makeGetRequest, readFilePromise, ServerInfo } from '../'
+import {
+  buildAbsoluteFixturePath,
+  getMyUserInformation,
+  makeGetRequest,
+  makePutBodyRequest,
+  makeUploadRequest,
+  root,
+  ServerInfo,
+  testImage
+} from '../'
 import { VideoPrivacy } from '../../../../shared/models/videos'
+import { readdirPromise } from '../../../helpers/core-utils'
+import { VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../initializers'
+import { dateIsValid, webtorrentAdd } from '../index'
 
 type VideoAttributes = {
   name?: string
@@ -11,11 +26,14 @@ type VideoAttributes = {
   licence?: number
   language?: number
   nsfw?: boolean
+  commentsEnabled?: boolean
   description?: string
   tags?: string[]
   channelId?: number
   privacy?: VideoPrivacy
   fixture?: string
+  thumbnailfile?: string
+  previewfile?: string
 }
 
 function getVideoCategories (url: string) {
@@ -67,13 +85,18 @@ function getVideo (url: string, id: number | string, expectedStatus = 200) {
           .expect(expectedStatus)
 }
 
-function viewVideo (url: string, id: number | string, expectedStatus = 204) {
+function viewVideo (url: string, id: number | string, expectedStatus = 204, xForwardedFor?: string) {
   const path = '/api/v1/videos/' + id + '/views'
 
-  return request(url)
+  const req = request(url)
     .post(path)
     .set('Accept', 'application/json')
-    .expect(expectedStatus)
+
+  if (xForwardedFor) {
+    req.set('X-Forwarded-For', xForwardedFor)
+  }
+
+  return req.expect(expectedStatus)
 }
 
 function getVideoWithToken (url: string, token: string, id: number | string, expectedStatus = 200) {
@@ -105,6 +128,29 @@ function getVideosList (url: string) {
           .expect('Content-Type', /json/)
 }
 
+function getVideosListWithToken (url: string, token: string) {
+  const path = '/api/v1/videos'
+
+  return request(url)
+    .get(path)
+    .set('Authorization', 'Bearer ' + token)
+    .query({ sort: 'name' })
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function getLocalVideos (url: string) {
+  const path = '/api/v1/videos'
+
+  return request(url)
+    .get(path)
+    .query({ sort: 'name', filter: 'local' })
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
 function getMyVideos (url: string, accessToken: string, start: number, count: number, sort?: string) {
   const path = '/api/v1/users/me/videos'
 
@@ -168,6 +214,18 @@ function searchVideo (url: string, search: string) {
     .expect('Content-Type', /json/)
 }
 
+function searchVideoWithToken (url: string, search: string, token: string) {
+  const path = '/api/v1/videos'
+  const req = request(url)
+    .get(path + '/search')
+    .set('Authorization', 'Bearer ' + token)
+    .query({ search })
+    .set('Accept', 'application/json')
+
+  return req.expect(200)
+            .expect('Content-Type', /json/)
+}
+
 function searchVideoWithPagination (url: string, search: string, start: number, count: number, sort?: string) {
   const path = '/api/v1/videos'
 
@@ -196,20 +254,19 @@ function searchVideoWithSort (url: string, search: string, sort: string) {
           .expect('Content-Type', /json/)
 }
 
-async function testVideoImage (url: string, imageName: string, imagePath: string) {
-  // Don't test images if the node env is not set
-  // Because we need a special ffmpeg version for this test
-  if (process.env['NODE_TEST_IMAGE']) {
-    const res = await request(url)
-                        .get(imagePath)
-                        .expect(200)
+async function checkVideoFilesWereRemoved (videoUUID: string, serverNumber: number) {
+  const testDirectory = 'test' + serverNumber
 
-    const data = await readFilePromise(join(__dirname, '..', '..', 'api', 'fixtures', imageName + '.jpg'))
+  for (const directory of [ 'videos', 'thumbnails', 'torrents', 'previews' ]) {
+    const directoryPath = join(root(), testDirectory, directory)
 
-    return data.equals(res.body)
-  } else {
-    console.log('Do not test images. Enable it by setting NODE_TEST_IMAGE env variable.')
-    return true
+    const directoryExists = existsSync(directoryPath)
+    expect(directoryExists).to.be.true
+
+    const files = await readdirPromise(directoryPath)
+    for (const file of files) {
+      expect(file).to.not.contain(videoUUID)
+    }
   }
 }
 
@@ -222,8 +279,8 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg
     defaultChannelId = res.body.videoChannels[0].id
   } catch (e) { /* empty */ }
 
-  // Default attributes
-  let attributes = {
+  // Override default attributes
+  const attributes = Object.assign({
     name: 'my super video',
     category: 5,
     licence: 4,
@@ -231,44 +288,52 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg
     channelId: defaultChannelId,
     nsfw: true,
     description: 'my super description',
+    support: 'my super support text',
     tags: [ 'tag' ],
     privacy: VideoPrivacy.PUBLIC,
+    commentsEnabled: true,
     fixture: 'video_short.webm'
-  }
-  attributes = Object.assign(attributes, videoAttributesArg)
+  }, videoAttributesArg)
 
   const req = request(url)
               .post(path)
               .set('Accept', 'application/json')
               .set('Authorization', 'Bearer ' + accessToken)
               .field('name', attributes.name)
-              .field('category', attributes.category.toString())
-              .field('licence', attributes.licence.toString())
               .field('nsfw', JSON.stringify(attributes.nsfw))
-              .field('description', attributes.description)
+              .field('commentsEnabled', JSON.stringify(attributes.commentsEnabled))
               .field('privacy', attributes.privacy.toString())
               .field('channelId', attributes.channelId)
 
+  if (attributes.description !== undefined) {
+    req.field('description', attributes.description)
+  }
   if (attributes.language !== undefined) {
     req.field('language', attributes.language.toString())
   }
+  if (attributes.category !== undefined) {
+    req.field('category', attributes.category.toString())
+  }
+  if (attributes.licence !== undefined) {
+    req.field('licence', attributes.licence.toString())
+  }
 
   for (let i = 0; i < attributes.tags.length; i++) {
     req.field('tags[' + i + ']', attributes.tags[i])
   }
 
-  let filePath = ''
-  if (isAbsolute(attributes.fixture)) {
-    filePath = attributes.fixture
-  } else {
-    filePath = join(__dirname, '..', '..', 'api', 'fixtures', attributes.fixture)
+  if (attributes.thumbnailfile !== undefined) {
+    req.attach('thumbnailfile', buildAbsoluteFixturePath(attributes.thumbnailfile))
+  }
+  if (attributes.previewfile !== undefined) {
+    req.attach('previewfile', buildAbsoluteFixturePath(attributes.previewfile))
   }
 
-  return req.attach('videofile', filePath)
+  return req.attach('videofile', buildAbsoluteFixturePath(attributes.fixture))
             .expect(specialStatus)
 }
 
-function updateVideo (url: string, accessToken: string, id: number, attributes: VideoAttributes, specialStatus = 204) {
+function updateVideo (url: string, accessToken: string, id: number | string, attributes: VideoAttributes, statusCodeExpected = 204) {
   const path = '/api/v1/videos/' + id
   const body = {}
 
@@ -276,17 +341,36 @@ function updateVideo (url: string, accessToken: string, id: number, attributes:
   if (attributes.category) body['category'] = attributes.category
   if (attributes.licence) body['licence'] = attributes.licence
   if (attributes.language) body['language'] = attributes.language
-  if (attributes.nsfw) body['nsfw'] = attributes.nsfw
+  if (attributes.nsfw !== undefined) body['nsfw'] = JSON.stringify(attributes.nsfw)
+  if (attributes.commentsEnabled !== undefined) body['commentsEnabled'] = JSON.stringify(attributes.commentsEnabled)
   if (attributes.description) body['description'] = attributes.description
   if (attributes.tags) body['tags'] = attributes.tags
   if (attributes.privacy) body['privacy'] = attributes.privacy
 
-  return request(url)
-          .put(path)
-          .send(body)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + accessToken)
-          .expect(specialStatus)
+  // Upload request
+  if (attributes.thumbnailfile || attributes.previewfile) {
+    const attaches: any = {}
+    if (attributes.thumbnailfile) attaches.thumbnailfile = attributes.thumbnailfile
+    if (attributes.previewfile) attaches.previewfile = attributes.previewfile
+
+    return makeUploadRequest({
+      url,
+      method: 'PUT',
+      path,
+      token: accessToken,
+      fields: body,
+      attaches,
+      statusCodeExpected
+    })
+  }
+
+  return makePutBodyRequest({
+    url,
+    path,
+    fields: body,
+    token: accessToken,
+    statusCodeExpected
+  })
 }
 
 function rateVideo (url: string, accessToken: string, id: number, rating: string, specialStatus = 204) {
@@ -312,6 +396,115 @@ function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: n
   })
 }
 
+async function completeVideoCheck (
+  url: string,
+  video: any,
+  attributes: {
+    name: string
+    category: number
+    licence: number
+    language: number
+    nsfw: boolean
+    commentsEnabled: boolean
+    description: string
+    support: string
+    account: {
+      name: string
+      host: string
+    }
+    isLocal: boolean,
+    tags: string[],
+    privacy: number,
+    likes?: number,
+    dislikes?: number,
+    duration: number,
+    channel: {
+      name: string,
+      description
+      isLocal: boolean
+    }
+    fixture: string,
+    files: {
+      resolution: number
+      size: number
+    }[],
+    thumbnailfile?: string
+    previewfile?: string
+  }
+) {
+  if (!attributes.likes) attributes.likes = 0
+  if (!attributes.dislikes) attributes.dislikes = 0
+
+  expect(video.name).to.equal(attributes.name)
+  expect(video.category.id).to.equal(attributes.category)
+  expect(video.category.label).to.equal(VIDEO_CATEGORIES[attributes.category] || 'Misc')
+  expect(video.licence.id).to.equal(attributes.licence)
+  expect(video.licence.label).to.equal(VIDEO_LICENCES[attributes.licence] || 'Unknown')
+  expect(video.language.id).to.equal(attributes.language)
+  expect(video.language.label).to.equal(VIDEO_LANGUAGES[attributes.language] || 'Unknown')
+  expect(video.nsfw).to.equal(attributes.nsfw)
+  expect(video.description).to.equal(attributes.description)
+  expect(video.account.host).to.equal(attributes.account.host)
+  expect(video.account.name).to.equal(attributes.account.name)
+  expect(video.likes).to.equal(attributes.likes)
+  expect(video.dislikes).to.equal(attributes.dislikes)
+  expect(video.isLocal).to.equal(attributes.isLocal)
+  expect(video.duration).to.equal(attributes.duration)
+  expect(dateIsValid(video.createdAt)).to.be.true
+  expect(dateIsValid(video.publishedAt)).to.be.true
+  expect(dateIsValid(video.updatedAt)).to.be.true
+
+  const res = await getVideo(url, video.uuid)
+  const videoDetails = res.body
+
+  expect(videoDetails.files).to.have.lengthOf(attributes.files.length)
+  expect(videoDetails.tags).to.deep.equal(attributes.tags)
+  expect(videoDetails.privacy.id).to.deep.equal(attributes.privacy)
+  expect(videoDetails.privacy.label).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy])
+  expect(videoDetails.account.name).to.equal(attributes.account.name)
+  expect(videoDetails.account.host).to.equal(attributes.account.host)
+  expect(videoDetails.commentsEnabled).to.equal(attributes.commentsEnabled)
+
+  expect(videoDetails.channel.displayName).to.equal(attributes.channel.name)
+  expect(videoDetails.channel.name).to.have.lengthOf(36)
+  expect(videoDetails.channel.isLocal).to.equal(attributes.channel.isLocal)
+  expect(dateIsValid(videoDetails.channel.createdAt)).to.be.true
+  expect(dateIsValid(videoDetails.channel.updatedAt)).to.be.true
+
+  for (const attributeFile of attributes.files) {
+    const file = videoDetails.files.find(f => f.resolution.id === attributeFile.resolution)
+    expect(file).not.to.be.undefined
+
+    let extension = extname(attributes.fixture)
+    // Transcoding enabled on server 2, extension will always be .mp4
+    if (attributes.account.host === 'localhost:9002') extension = '.mp4'
+
+    const magnetUri = file.magnetUri
+    expect(file.magnetUri).to.have.lengthOf.above(2)
+    expect(file.torrentUrl).to.equal(`http://${attributes.account.host}/static/torrents/${videoDetails.uuid}-${file.resolution.id}.torrent`)
+    expect(file.fileUrl).to.equal(`http://${attributes.account.host}/static/webseed/${videoDetails.uuid}-${file.resolution.id}${extension}`)
+    expect(file.resolution.id).to.equal(attributeFile.resolution)
+    expect(file.resolution.label).to.equal(attributeFile.resolution + 'p')
+
+    const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
+    const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
+    expect(file.size).to.be.above(minSize).and.below(maxSize)
+
+    {
+      await testImage(url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath)
+    }
+
+    if (attributes.previewfile) {
+      await testImage(url, attributes.previewfile, videoDetails.previewPath)
+    }
+
+    const torrent = await webtorrentAdd(magnetUri, true)
+    expect(torrent.files).to.be.an('array')
+    expect(torrent.files.length).to.equal(1)
+    expect(torrent.files[0].path).to.exist.and.to.not.equal('')
+  }
+}
+
 // ---------------------------------------------------------------------------
 
 export {
@@ -321,6 +514,7 @@ export {
   getVideoPrivacies,
   getVideoLanguages,
   getMyVideos,
+  searchVideoWithToken,
   getVideo,
   getVideoWithToken,
   getVideosList,
@@ -330,10 +524,13 @@ export {
   searchVideo,
   searchVideoWithPagination,
   searchVideoWithSort,
-  testVideoImage,
+  getVideosListWithToken,
   uploadVideo,
   updateVideo,
   rateVideo,
   viewVideo,
-  parseTorrentVideo
+  parseTorrentVideo,
+  getLocalVideos,
+  completeVideoCheck,
+  checkVideoFilesWereRemoved
 }