Add tests regarding video import
authorChocobozzz <me@florianbigard.com>
Fri, 3 Aug 2018 14:23:45 +0000 (16:23 +0200)
committerChocobozzz <me@florianbigard.com>
Mon, 6 Aug 2018 09:19:16 +0000 (11:19 +0200)
12 files changed:
server/controllers/api/videos/import.ts
server/helpers/youtube-dl.ts
server/lib/job-queue/handlers/video-import.ts
server/models/video/video-import.ts
server/tests/api/check-params/video-imports.ts
server/tests/api/index-slow.ts
server/tests/api/videos/video-imports.ts [new file with mode: 0644]
server/tests/client.ts
server/tests/utils/server/config.ts
server/tests/utils/videos/video-imports.ts [new file with mode: 0644]
shared/models/videos/index.ts
shared/models/videos/video-import-update.model.ts [deleted file]

index ee11b0741ded6fcacfa56e6e376857167ba1e7a2..30a7d816c48ff6342e4c8615f37ab146048090c3 100644 (file)
@@ -62,7 +62,7 @@ async function addVideoImport (req: express.Request, res: express.Response) {
     remote: false,
     category: body.category || youtubeDLInfo.category,
     licence: body.licence || youtubeDLInfo.licence,
-    language: undefined,
+    language: body.language || undefined,
     commentsEnabled: body.commentsEnabled || true,
     waitTranscoding: body.waitTranscoding || false,
     state: VideoState.TO_IMPORT,
@@ -102,8 +102,9 @@ async function addVideoImport (req: express.Request, res: express.Response) {
     videoCreated.VideoChannel = res.locals.videoChannel
 
     // Set tags to the video
-    if (youtubeDLInfo.tags !== undefined) {
-      const tagInstances = await TagModel.findOrCreateTags(youtubeDLInfo.tags, t)
+    const tags = body.tags ? body.tags : youtubeDLInfo.tags
+    if (tags !== undefined) {
+      const tagInstances = await TagModel.findOrCreateTags(tags, t)
 
       await videoCreated.$set('Tags', tagInstances, sequelizeOptions)
       videoCreated.Tags = tagInstances
@@ -133,5 +134,5 @@ async function addVideoImport (req: express.Request, res: express.Response) {
 
   auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new VideoImportAuditView(videoImport.toFormattedJSON()))
 
-  return res.json(videoImport.toFormattedJSON())
+  return res.json(videoImport.toFormattedJSON()).end()
 }
index ff1fbf59fe1eb422f4424699c75df8f9819ef994..c59ab9de072ef74ef3bbdb09a14055c51cd20ec2 100644 (file)
@@ -120,7 +120,7 @@ function getTags (tags: any) {
 function getLicence (licence: string) {
   if (!licence) return undefined
 
-  if (licence.indexOf('Creative Commons Attribution licence') !== -1) return 1
+  if (licence.indexOf('Creative Commons Attribution') !== -1) return 1
 
   return undefined
 }
index 3b9d08d3b74ebd1a16f9d59b2c25484ee05b8ffa..cdfe412cc6936f74c554e7ae5d89557089339b10 100644 (file)
@@ -98,8 +98,9 @@ async function processVideoImport (job: Bull.Job) {
       video.state = CONFIG.TRANSCODING.ENABLED ? VideoState.TO_TRANSCODE : VideoState.PUBLISHED
       const videoUpdated = await video.save({ transaction: t })
 
-      // Now we can federate the video
-      await federateVideoIfNeeded(video, true, t)
+      // Now we can federate the video (reload from database, we need more attributes)
+      const videoForFederation = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(video.uuid, t)
+      await federateVideoIfNeeded(videoForFederation, true, t)
 
       // Update video import object
       videoImport.state = VideoImportState.SUCCESS
index c2e55509c128fb75ab0645525afd50092f030c15..eca87163dbe5a392122a6ba49f0957684b9d875c 100644 (file)
@@ -39,8 +39,7 @@ import { TagModel } from './tag'
           ]
         },
         {
-          model: () => TagModel,
-          required: false
+          model: () => TagModel
         }
       ]
     }
@@ -106,6 +105,7 @@ export class VideoImportModel extends Model<VideoImportModel> {
 
   static listUserVideoImportsForApi (accountId: number, start: number, count: number, sort: string) {
     const query = {
+      distinct: true,
       offset: start,
       limit: count,
       order: getSort(sort),
index 7f58efb744ff1965cfba8d46d1916b62ba113cde..0ead34a47148f556086d9fec689776188c617a68 100644 (file)
@@ -16,9 +16,11 @@ import {
   runServer,
   ServerInfo,
   setAccessTokensToServers,
+  updateCustomSubConfig,
   userLogin
 } from '../../utils'
 import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '../../utils/requests/check-api-params'
+import { getYoutubeVideoUrl } from '../../utils/videos/video-imports'
 
 describe('Test video imports API validator', function () {
   const path = '/api/v1/videos/imports'
@@ -77,7 +79,7 @@ describe('Test video imports API validator', function () {
 
     before(function () {
       baseCorrectParams = {
-        targetUrl: 'https://youtu.be/msX3jv1XdvM',
+        targetUrl: getYoutubeVideoUrl(),
         name: 'my super name',
         category: 5,
         licence: 1,
@@ -98,6 +100,17 @@ describe('Test video imports API validator', function () {
       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
     })
 
+    it('Should fail without a target url', async function () {
+      const fields = omit(baseCorrectParams, 'targetUrl')
+      await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, statusCodeExpected: 400 })
+    })
+
+    it('Should fail with a bad target url', async function () {
+      const fields = immutableAssign(baseCorrectParams, { targetUrl: 'htt://hello' })
+
+      await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
+    })
+
     it('Should fail with a long name', async function () {
       const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) })
 
@@ -219,20 +232,36 @@ describe('Test video imports API validator', function () {
     it('Should succeed with the correct parameters', async function () {
       this.timeout(10000)
 
-      const fields = baseCorrectParams
-
       {
         await makePostBodyRequest({
           url: server.url,
           path,
           token: server.accessToken,
-          fields,
+          fields: baseCorrectParams,
           statusCodeExpected: 200
         })
       }
     })
 
-    it('Should forbid importing')
+    it('Should forbid to import videos', async function () {
+      await updateCustomSubConfig(server.url, server.accessToken, {
+        import: {
+          videos: {
+            http: {
+              enabled: false
+            }
+          }
+        }
+      })
+
+      await makePostBodyRequest({
+        url: server.url,
+        path,
+        token: server.accessToken,
+        fields: baseCorrectParams,
+        statusCodeExpected: 409
+      })
+    })
   })
 
   after(async function () {
index d987442b3684bbe700c7ebb581fed4f301b984a2..243c941cb5a0c9b99061c9af6d99cc21235dde43 100644 (file)
@@ -1,4 +1,5 @@
 // Order of the tests we want to execute
+import './videos/video-channels'
 import './videos/video-transcoder'
 import './videos/multiple-servers'
 import './server/follows'
@@ -7,3 +8,4 @@ import './videos/video-comments'
 import './users/users-multiple-servers'
 import './server/handle-down'
 import './videos/video-schedule-update'
+import './videos/video-imports'
diff --git a/server/tests/api/videos/video-imports.ts b/server/tests/api/videos/video-imports.ts
new file mode 100644 (file)
index 0000000..f21ade5
--- /dev/null
@@ -0,0 +1,161 @@
+/* tslint:disable:no-unused-expression */
+
+import * as chai from 'chai'
+import 'mocha'
+import { VideoDetails, VideoPrivacy } from '../../../../shared/models/videos'
+import {
+  doubleFollow,
+  flushAndRunMultipleServers,
+  getMyUserInformation,
+  getMyVideos,
+  getVideo,
+  getVideosList,
+  killallServers,
+  ServerInfo,
+  setAccessTokensToServers
+} from '../../utils'
+import { waitJobs } from '../../utils/server/jobs'
+import { getMyVideoImports, getYoutubeVideoUrl, importVideo } from '../../utils/videos/video-imports'
+
+const expect = chai.expect
+
+describe('Test video imports', function () {
+  let servers: ServerInfo[] = []
+  let channelIdServer1: number
+  let channelIdServer2: number
+
+  async function checkVideoServer1 (url: string, id: number | string) {
+    const res = await getVideo(url, id)
+    const video: VideoDetails = res.body
+
+    expect(video.name).to.equal('small video - youtube')
+    expect(video.category.label).to.equal('News')
+    expect(video.licence.label).to.equal('Attribution')
+    expect(video.language.label).to.equal('Unknown')
+    expect(video.nsfw).to.be.false
+    expect(video.description).to.equal('this is a super description')
+    expect(video.tags).to.deep.equal([ 'tag1', 'tag2' ])
+
+    expect(video.files).to.have.lengthOf(1)
+  }
+
+  async function checkVideoServer2 (url: string, id: number | string) {
+    const res = await getVideo(url, id)
+    const video = res.body
+
+    expect(video.name).to.equal('my super name')
+    expect(video.category.label).to.equal('Entertainment')
+    expect(video.licence.label).to.equal('Public Domain Dedication')
+    expect(video.language.label).to.equal('English')
+    expect(video.nsfw).to.be.false
+    expect(video.description).to.equal('my super description')
+    expect(video.tags).to.deep.equal([ 'supertag1', 'supertag2' ])
+
+    expect(video.files).to.have.lengthOf(1)
+  }
+
+  before(async function () {
+    this.timeout(30000)
+
+    // Run servers
+    servers = await flushAndRunMultipleServers(2)
+
+    await setAccessTokensToServers(servers)
+
+    {
+      const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
+      channelIdServer1 = res.body.videoChannels[ 0 ].id
+    }
+
+    {
+      const res = await getMyUserInformation(servers[1].url, servers[1].accessToken)
+      channelIdServer2 = res.body.videoChannels[ 0 ].id
+    }
+
+    await doubleFollow(servers[0], servers[1])
+  })
+
+  it('Should import a video on server 1', async function () {
+    this.timeout(60000)
+
+    const attributes = {
+      targetUrl: getYoutubeVideoUrl(),
+      channelId: channelIdServer1,
+      privacy: VideoPrivacy.PUBLIC
+    }
+    const res = await importVideo(servers[0].url, servers[0].accessToken, attributes)
+    expect(res.body.video.name).to.equal('small video - youtube')
+  })
+
+  it('Should list the video to import in my videos on server 1', async function () {
+    const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 5)
+
+    expect(res.body.total).to.equal(1)
+
+    const videos = res.body.data
+    expect(videos).to.have.lengthOf(1)
+    expect(videos[0].name).to.equal('small video - youtube')
+  })
+
+  it('Should list the video to import in my imports on server 1', async function () {
+    const res = await getMyVideoImports(servers[0].url, servers[0].accessToken)
+
+    expect(res.body.total).to.equal(1)
+    const videoImports = res.body.data
+    expect(videoImports).to.have.lengthOf(1)
+
+    expect(videoImports[0].targetUrl).to.equal(getYoutubeVideoUrl())
+    expect(videoImports[0].video.name).to.equal('small video - youtube')
+  })
+
+  it('Should have the video listed on the two instances1', async function () {
+    this.timeout(120000)
+
+    await waitJobs(servers)
+
+    for (const server of servers) {
+      const res = await getVideosList(server.url)
+      expect(res.body.total).to.equal(1)
+      expect(res.body.data).to.have.lengthOf(1)
+
+      await checkVideoServer1(server.url, res.body.data[0].uuid)
+    }
+  })
+
+  it('Should import a video on server 2 with some fields', async function () {
+    this.timeout(60000)
+
+    const attributes = {
+      targetUrl: getYoutubeVideoUrl(),
+      channelId: channelIdServer1,
+      privacy: VideoPrivacy.PUBLIC,
+      category: 10,
+      licence: 7,
+      language: 'en',
+      name: 'my super name',
+      description: 'my super description',
+      tags: [ 'supertag1', 'supertag2' ]
+    }
+    const res = await importVideo(servers[1].url, servers[1].accessToken, attributes)
+    expect(res.body.video.name).to.equal('my super name')
+  })
+
+  it('Should have the video listed on the two instances', async function () {
+    this.timeout(120000)
+
+    await waitJobs(servers)
+
+    for (const server of servers) {
+      const res = await getVideosList(server.url)
+      expect(res.body.total).to.equal(2)
+      expect(res.body.data).to.have.lengthOf(2)
+
+      await checkVideoServer2(server.url, res.body.data[0].uuid)
+      await checkVideoServer1(server.url, res.body.data[1].uuid)
+    }
+  })
+
+  after(async function () {
+    killallServers(servers)
+  })
+})
index 129b40cdf926b643fb6499c1d1a6ce0ac8e3f0b6..48f2ee4fcefc4b57a4acaf08985f94e49dcf16c0 100644 (file)
@@ -3,17 +3,21 @@
 import 'mocha'
 import * as chai from 'chai'
 import * as request from 'supertest'
-const expect = chai.expect
-
 import {
-  ServerInfo,
   flushTests,
+  getCustomConfig,
+  getVideosList,
+  killallServers,
+  makeHTMLRequest,
   runServer,
+  ServerInfo,
   serverLogin,
-  uploadVideo,
-  getVideosList, updateCustomConfig, getCustomConfig, killallServers, makeHTMLRequest
+  updateCustomConfig,
+  updateCustomSubConfig,
+  uploadVideo
 } from './utils'
-import { CustomConfig } from '../../shared/models/server/custom-config.model'
+
+const expect = chai.expect
 
 function checkIndexTags (html: string, title: string, description: string, css: string) {
   expect(html).to.contain('<title>' + title + '</title>')
@@ -117,63 +121,14 @@ describe('Test a client controllers', function () {
   })
 
   it('Should update the customized configuration and have the correct index html tags', async function () {
-    const newCustomConfig: CustomConfig = {
+    await updateCustomSubConfig(server.url, server.accessToken, {
       instance: {
-        name: 'PeerTube updated',
-        shortDescription: 'my short description',
-        description: 'my super description',
-        terms: 'my super terms',
-        defaultClientRoute: '/videos/recently-added',
-        defaultNSFWPolicy: 'blur' as 'blur',
         customizations: {
           javascript: 'alert("coucou")',
           css: 'body { background-color: red; }'
         }
-      },
-      services: {
-        twitter: {
-          username: '@Kuja',
-          whitelisted: true
-        }
-      },
-      cache: {
-        previews: {
-          size: 2
-        },
-        captions: {
-          size: 3
-        }
-      },
-      signup: {
-        enabled: false,
-        limit: 5
-      },
-      admin: {
-        email: 'superadmin1@example.com'
-      },
-      user: {
-        videoQuota: 5242881
-      },
-      transcoding: {
-        enabled: true,
-        threads: 1,
-        resolutions: {
-          '240p': false,
-          '360p': true,
-          '480p': true,
-          '720p': false,
-          '1080p': false
-        }
-      },
-      import: {
-        videos: {
-          http: {
-            enabled: false
-          }
-        }
       }
-    }
-    await updateCustomConfig(server.url, server.accessToken, newCustomConfig)
+    })
 
     const res = await makeHTMLRequest(server.url, '/videos/trending')
 
index 57f95a6033aa08376d2110a5d69f32849fc968e2..e21614282b95ad04fd097f5ea0c44c70852fae60 100644 (file)
@@ -44,6 +44,69 @@ function updateCustomConfig (url: string, token: string, newCustomConfig: Custom
   })
 }
 
+function updateCustomSubConfig (url: string, token: string, newConfig: any) {
+  const updateParams: CustomConfig = {
+    instance: {
+      name: 'PeerTube updated',
+      shortDescription: 'my short description',
+      description: 'my super description',
+      terms: 'my super terms',
+      defaultClientRoute: '/videos/recently-added',
+      defaultNSFWPolicy: 'blur',
+      customizations: {
+        javascript: 'alert("coucou")',
+        css: 'body { background-color: red; }'
+      }
+    },
+    services: {
+      twitter: {
+        username: '@MySuperUsername',
+        whitelisted: true
+      }
+    },
+    cache: {
+      previews: {
+        size: 2
+      },
+      captions: {
+        size: 3
+      }
+    },
+    signup: {
+      enabled: false,
+      limit: 5
+    },
+    admin: {
+      email: 'superadmin1@example.com'
+    },
+    user: {
+      videoQuota: 5242881
+    },
+    transcoding: {
+      enabled: true,
+      threads: 1,
+      resolutions: {
+        '240p': false,
+        '360p': true,
+        '480p': true,
+        '720p': false,
+        '1080p': false
+      }
+    },
+    import: {
+      videos: {
+        http: {
+          enabled: false
+        }
+      }
+    }
+  }
+
+  Object.assign(updateParams, newConfig)
+
+  return updateCustomConfig(url, token, updateParams)
+}
+
 function deleteCustomConfig (url: string, token: string, statusCodeExpected = 200) {
   const path = '/api/v1/config/custom'
 
@@ -62,5 +125,6 @@ export {
   getCustomConfig,
   updateCustomConfig,
   getAbout,
-  deleteCustomConfig
+  deleteCustomConfig,
+  updateCustomSubConfig
 }
diff --git a/server/tests/utils/videos/video-imports.ts b/server/tests/utils/videos/video-imports.ts
new file mode 100644 (file)
index 0000000..e0f9169
--- /dev/null
@@ -0,0 +1,37 @@
+import { VideoImportCreate } from '../../../../shared/models/videos'
+import { makeGetRequest, makePostBodyRequest } from '..'
+
+function getYoutubeVideoUrl () {
+  return 'https://youtu.be/msX3jv1XdvM'
+}
+
+function importVideo (url: string, token: string, attributes: VideoImportCreate) {
+  const path = '/api/v1/videos/imports'
+
+  return makePostBodyRequest({
+    url,
+    path,
+    token,
+    fields: attributes,
+    statusCodeExpected: 200
+  })
+}
+
+function getMyVideoImports (url: string, token: string) {
+  const path = '/api/v1/users/me/videos/imports'
+
+  return makeGetRequest({
+    url,
+    path,
+    token,
+    statusCodeExpected: 200
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getYoutubeVideoUrl,
+  importVideo,
+  getMyVideoImports
+}
index 1b135e26ac82e4c168d8316fa291401bf6b47423..17cf8be24883441dbb59fc1e5645d750822b3d98 100644 (file)
@@ -16,7 +16,6 @@ export * from './video.model'
 export * from './video-state.enum'
 export * from './video-caption-update.model'
 export * from './video-import-create.model'
-export * from './video-import-update.model'
 export * from './video-import-state.enum'
 export * from './video-import.model'
 export { VideoConstant } from './video-constant.model'
diff --git a/shared/models/videos/video-import-update.model.ts b/shared/models/videos/video-import-update.model.ts
deleted file mode 100644 (file)
index 5ae2446..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-import { VideoUpdate } from './video-update.model'
-
-export interface VideoImportUpdate extends VideoUpdate {
-  targetUrl: string
-}