Optimize signature verification
authorChocobozzz <florian.bigard@gmail.com>
Fri, 17 Nov 2017 14:20:42 +0000 (15:20 +0100)
committerChocobozzz <florian.bigard@gmail.com>
Mon, 27 Nov 2017 18:40:52 +0000 (19:40 +0100)
31 files changed:
client/src/app/+admin/follows/shared/follow.service.ts
server/controllers/api/server/follows.ts
server/helpers/activitypub.ts
server/helpers/custom-jsonld-signature.ts [new file with mode: 0644]
server/helpers/custom-validators/activitypub/misc.ts
server/helpers/peertube-crypto.ts
server/initializers/constants.ts
server/lib/activitypub/misc.ts
server/lib/activitypub/process-add.ts
server/lib/activitypub/process-update.ts
server/lib/activitypub/send-request.ts
server/middlewares/activitypub.ts
server/models/video/video.ts
server/tests/api/check-params/follows.ts [new file with mode: 0644]
server/tests/api/check-params/index.ts
server/tests/api/check-params/pods.ts [deleted file]
server/tests/api/check-params/remotes.ts [deleted file]
server/tests/api/check-params/request-schedulers.ts [deleted file]
server/tests/api/check-params/videos.ts
server/tests/api/index-fast.ts
server/tests/api/index-slow.ts
server/tests/api/multiple-pods.ts [deleted file]
server/tests/api/multiple-servers.ts [new file with mode: 0644]
server/tests/api/services.ts
server/tests/api/single-pod.ts [deleted file]
server/tests/api/single-server.ts [new file with mode: 0644]
server/tests/api/video-privacy.ts
server/tests/client.ts
server/tests/real-world/real-world.ts
server/tests/utils/follows.ts
shared/models/activitypub/activity.ts

index d64361ee31e39de12ee3c279fe8e62531f0899b2..f66ed477df662d10fbc68e990c5c8b3148c68ad8 100644 (file)
@@ -42,7 +42,7 @@ export class FollowService {
       hosts: notEmptyHosts
     }
 
-    return this.authHttp.post(FollowService.BASE_APPLICATION_URL + '/follow', body)
+    return this.authHttp.post(FollowService.BASE_APPLICATION_URL + '/following', body)
                         .map(this.restExtractor.extractDataBool)
                         .catch(res => this.restExtractor.handleError(res))
   }
index 520d4d858536fa534e13dfcf5c2fd5c0fcb134c8..3d184ec1f8dce4d3f28e3ef80a17ff71b97075f0 100644 (file)
@@ -25,7 +25,7 @@ serverFollowsRouter.get('/following',
   asyncMiddleware(listFollowing)
 )
 
-serverFollowsRouter.post('/follow',
+serverFollowsRouter.post('/following',
   authenticate,
   ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
   followValidator,
index 6f216e106a3fb0ddda70e2635f0431e8419a2a5f..aff58515a0e42b79f7b8c051753bdb6394cecf41 100644 (file)
@@ -8,7 +8,7 @@ import { ActivityPubActor } from '../../shared/models/activitypub/activitypub-ac
 import { VideoChannelObject } from '../../shared/models/activitypub/objects/video-channel-object'
 import { ResultList } from '../../shared/models/result-list.model'
 import { database as db, REMOTE_SCHEME } from '../initializers'
-import { ACTIVITY_PUB_ACCEPT_HEADER, CONFIG, STATIC_PATHS } from '../initializers/constants'
+import { ACTIVITY_PUB, CONFIG, STATIC_PATHS } from '../initializers/constants'
 import { videoChannelActivityObjectToDBAttributes } from '../lib/activitypub/misc'
 import { sendVideoAnnounce } from '../lib/activitypub/send-request'
 import { sendVideoChannelAnnounce } from '../lib/index'
@@ -99,7 +99,7 @@ async function fetchRemoteAccountAndCreateServer (accountUrl: string) {
     uri: accountUrl,
     method: 'GET',
     headers: {
-      'Accept': ACTIVITY_PUB_ACCEPT_HEADER
+      'Accept': ACTIVITY_PUB.ACCEPT_HEADER
     }
   }
 
@@ -157,7 +157,7 @@ async function fetchRemoteVideoChannel (ownerAccount: AccountInstance, videoChan
     uri: videoChannelUrl,
     method: 'GET',
     headers: {
-      'Accept': ACTIVITY_PUB_ACCEPT_HEADER
+      'Accept': ACTIVITY_PUB.ACCEPT_HEADER
     }
   }
 
diff --git a/server/helpers/custom-jsonld-signature.ts b/server/helpers/custom-jsonld-signature.ts
new file mode 100644 (file)
index 0000000..afb9606
--- /dev/null
@@ -0,0 +1,20 @@
+import * as AsyncLRU from 'async-lru'
+import * as jsonld from 'jsonld'
+import * as jsig from 'jsonld-signatures'
+
+jsig.use('jsonld', jsonld)
+
+const nodeDocumentLoader = jsonld.documentLoaders.node()
+
+const lru = new AsyncLRU({
+  max: 10,
+  load: (key, cb) => {
+    nodeDocumentLoader(key, cb)
+  }
+})
+
+jsonld.documentLoader = (url, cb) => {
+  lru.get(url, cb)
+}
+
+export { jsig }
index f09a764b6701c4e6f6bf57929d987f00886fda2b..1bbfd0fc473c053428e0f49c447bb3bc896d65cc 100644 (file)
@@ -28,6 +28,10 @@ function isBaseActivityValid (activity: any, type: string) {
     (
       activity.to === undefined ||
       (Array.isArray(activity.to) && activity.to.every(t => isActivityPubUrlValid(t)))
+    ) &&
+    (
+      activity.cc === undefined ||
+      (Array.isArray(activity.cc) && activity.cc.every(t => isActivityPubUrlValid(t)))
     )
 }
 
index 04a8d5681d6be87cc97746a35efff993b5f59413..c61abfa8e70f43fd23c1965ae4b005054f149d35 100644 (file)
@@ -1,7 +1,3 @@
-import * as jsonld from 'jsonld'
-import * as jsig from 'jsonld-signatures'
-jsig.use('jsonld', jsonld)
-
 import {
   PRIVATE_RSA_KEY_SIZE,
   BCRYPT_SALT_SIZE
@@ -15,6 +11,7 @@ import {
 } from './core-utils'
 import { logger } from './logger'
 import { AccountInstance } from '../models/account/account-interface'
+import { jsig } from './custom-jsonld-signature'
 
 async function createPrivateAndPublicKeys () {
   logger.info('Generating a RSA key...')
index 48d7b5b986ea5e8fbde774d67dad1e04cc8e3513..9c7c31a61d14f40a6db759ac35c24dcc20da77e0 100644 (file)
@@ -223,9 +223,10 @@ const FRIEND_SCORE = {
 }
 
 const SERVER_ACCOUNT_NAME = 'peertube'
-const ACTIVITY_PUB_ACCEPT_HEADER = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
 
 const ACTIVITY_PUB = {
+  ACCEPT_HEADER: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
+  PUBLIC: 'https://www.w3.org/ns/activitystreams#Public',
   COLLECTION_ITEMS_PER_PAGE: 10,
   URL_MIME_TYPES: {
     VIDEO: [ 'video/mp4', 'video/webm', 'video/ogg' ], // TODO: Merge with VIDEO_MIMETYPE_EXT
@@ -349,7 +350,6 @@ export {
   SERVERS_SCORE,
   PREVIEWS_SIZE,
   REMOTE_SCHEME,
-  ACTIVITY_PUB_ACCEPT_HEADER,
   FOLLOW_STATES,
   SEARCHABLE_COLUMNS,
   SERVER_ACCOUNT_NAME,
index c07d9f654466274ce08bee0e9de6ea8d0f240882..4c210eb104af8426461911d08df6db72f6814515 100644 (file)
@@ -2,11 +2,12 @@ import * as magnetUtil from 'magnet-uri'
 import { VideoTorrentObject } from '../../../shared'
 import { VideoChannelObject } from '../../../shared/models/activitypub/objects/video-channel-object'
 import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos'
-import { VIDEO_MIMETYPE_EXT } from '../../initializers/constants'
+import { ACTIVITY_PUB, VIDEO_MIMETYPE_EXT } from '../../initializers/constants'
 import { AccountInstance } from '../../models/account/account-interface'
 import { VideoChannelInstance } from '../../models/video/video-channel-interface'
 import { VideoFileAttributes } from '../../models/video/video-file-interface'
 import { VideoAttributes, VideoInstance } from '../../models/video/video-interface'
+import { VideoPrivacy } from '../../../shared/models/videos/video-privacy.enum'
 
 function videoChannelActivityObjectToDBAttributes (videoChannelObject: VideoChannelObject, account: AccountInstance) {
   return {
@@ -23,8 +24,14 @@ function videoChannelActivityObjectToDBAttributes (videoChannelObject: VideoChan
 
 async function videoActivityObjectToDBAttributes (
   videoChannel: VideoChannelInstance,
-  videoObject: VideoTorrentObject
+  videoObject: VideoTorrentObject,
+  to: string[] = [],
+  cc: string[] = []
 ) {
+  let privacy = VideoPrivacy.PRIVATE
+  if (to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1) privacy = VideoPrivacy.PUBLIC
+  else if (cc.indexOf(ACTIVITY_PUB.PUBLIC) !== -1) privacy = VideoPrivacy.UNLISTED
+
   const duration = videoObject.duration.replace(/[^\d]+/, '')
   const videoData: VideoAttributes = {
     name: videoObject.name,
@@ -43,11 +50,8 @@ async function videoActivityObjectToDBAttributes (
     views: videoObject.views,
     likes: 0,
     dislikes: 0,
-    // likes: videoToCreateData.likes,
-    // dislikes: videoToCreateData.dislikes,
     remote: true,
-    privacy: 1
-    // privacy: videoToCreateData.privacy
+    privacy
   }
 
   return videoData
index 72c5b19325bd00592097b694c83eba3cadb8b77a..c83d9e98ec9be30ba40005338c1b7b4f810e6184 100644 (file)
@@ -17,7 +17,7 @@ async function processAddActivity (activity: ActivityAdd) {
     const videoChannelUrl = activity.target
     const videoChannel = await getOrCreateVideoChannel(account, videoChannelUrl)
 
-    return processAddVideo(account, videoChannel, activityObject as VideoTorrentObject)
+    return processAddVideo(account, activity, videoChannel, activityObject as VideoTorrentObject)
   }
 
   logger.warn('Unknown activity object type %s when creating activity.', activityType, { activity: activity.id })
@@ -32,16 +32,21 @@ export {
 
 // ---------------------------------------------------------------------------
 
-function processAddVideo (account: AccountInstance, videoChannel: VideoChannelInstance, video: VideoTorrentObject) {
+function processAddVideo (account: AccountInstance, activity: ActivityAdd, videoChannel: VideoChannelInstance, video: VideoTorrentObject) {
   const options = {
-    arguments: [ account, videoChannel, video ],
+    arguments: [ account, activity, videoChannel, video ],
     errorMessage: 'Cannot insert the remote video with many retries.'
   }
 
   return retryTransactionWrapper(addRemoteVideo, options)
 }
 
-function addRemoteVideo (account: AccountInstance, videoChannel: VideoChannelInstance, videoToCreateData: VideoTorrentObject) {
+function addRemoteVideo (
+  account: AccountInstance,
+  activity: ActivityAdd,
+  videoChannel: VideoChannelInstance,
+  videoToCreateData: VideoTorrentObject
+) {
   logger.debug('Adding remote video %s.', videoToCreateData.url)
 
   return db.sequelize.transaction(async t => {
@@ -54,7 +59,7 @@ function addRemoteVideo (account: AccountInstance, videoChannel: VideoChannelIns
     const videoFromDatabase = await db.Video.loadByUUIDOrURL(videoToCreateData.uuid, videoToCreateData.id, t)
     if (videoFromDatabase) throw new Error('Video with this UUID/Url already exists.')
 
-    const videoData = await videoActivityObjectToDBAttributes(videoChannel, videoToCreateData)
+    const videoData = await videoActivityObjectToDBAttributes(videoChannel, videoToCreateData, activity.to, activity.cc)
     const video = db.Video.build(videoData)
 
     // Don't block on request
index 4aefd1b9b550268cc51a2751d50b083f12a115ee..b732fce33ad174cdaaf38274c09f78acbe7e93d8 100644 (file)
@@ -70,7 +70,6 @@ async function updateRemoteVideo (account: AccountInstance, videoAttributesToUpd
       videoInstance.set('views', videoData.views)
       // videoInstance.set('likes', videoData.likes)
       // videoInstance.set('dislikes', videoData.dislikes)
-      // videoInstance.set('privacy', videoData.privacy)
 
       await videoInstance.save(sequelizeOptions)
 
index 8d013fa87646f72f231b10b2fb77c2336a04f931..68a631a3685803f22d1c4c5d663971ebdcf071d9 100644 (file)
@@ -13,6 +13,8 @@ import { database as db } from '../../initializers'
 import { AccountInstance, VideoChannelInstance, VideoInstance } from '../../models'
 import { VideoAbuseInstance } from '../../models/video/video-abuse-interface'
 import { activitypubHttpJobScheduler } from '../jobs'
+import { ACTIVITY_PUB } from '../../initializers/constants'
+import { VideoPrivacy } from '../../../shared/models/videos/video-privacy.enum'
 
 async function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) {
   const byAccount = videoChannel.Account
@@ -50,7 +52,7 @@ async function sendAddVideo (video: VideoInstance, t: Transaction) {
   const byAccount = video.VideoChannel.Account
 
   const videoObject = video.toActivityPubObject()
-  const data = await addActivityData(video.url, byAccount, video.VideoChannel.url, videoObject)
+  const data = await addActivityData(video.url, byAccount, video, video.VideoChannel.url, videoObject)
 
   return broadcastToFollowers(data, byAccount, [ byAccount ], t)
 }
@@ -96,7 +98,7 @@ async function sendVideoAnnounce (byAccount: AccountInstance, video: VideoInstan
   const url = getActivityPubUrl('video', video.uuid) + '#announce'
 
   const videoChannel = video.VideoChannel
-  const announcedActivity = await addActivityData(url, videoChannel.Account, videoChannel.url, video.toActivityPubObject())
+  const announcedActivity = await addActivityData(url, videoChannel.Account, video, videoChannel.url, video.toActivityPubObject())
 
   const data = await announceActivityData(url, byAccount, announcedActivity)
   return broadcastToFollowers(data, byAccount, [ byAccount ], t)
@@ -167,19 +169,32 @@ async function unicastTo (data: any, byAccount: AccountInstance, toAccountUrl: s
   return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpUnicastHandler', jobPayload)
 }
 
-async function getPublicActivityTo (account: AccountInstance) {
-  const inboxUrls = await account.getFollowerSharedInboxUrls()
+async function getAudience (accountSender: AccountInstance, isPublic = true) {
+  const followerInboxUrls = await accountSender.getFollowerSharedInboxUrls()
 
-  return inboxUrls.concat('https://www.w3.org/ns/activitystreams#Public')
+  // Thanks Mastodon: https://github.com/tootsuite/mastodon/blob/master/app/lib/activitypub/tag_manager.rb#L47
+  let to = []
+  let cc = []
+
+  if (isPublic) {
+    to = [ ACTIVITY_PUB.PUBLIC ]
+    cc = followerInboxUrls
+  } else { // Unlisted
+    to = followerInboxUrls
+    cc = [ ACTIVITY_PUB.PUBLIC ]
+  }
+
+  return { to, cc }
 }
 
 async function createActivityData (url: string, byAccount: AccountInstance, object: any) {
-  const to = await getPublicActivityTo(byAccount)
+  const { to, cc } = await getAudience(byAccount)
   const activity: ActivityCreate = {
     type: 'Create',
     id: url,
     actor: byAccount.url,
     to,
+    cc,
     object
   }
 
@@ -187,12 +202,13 @@ async function createActivityData (url: string, byAccount: AccountInstance, obje
 }
 
 async function updateActivityData (url: string, byAccount: AccountInstance, object: any) {
-  const to = await getPublicActivityTo(byAccount)
+  const { to, cc } = await getAudience(byAccount)
   const activity: ActivityUpdate = {
     type: 'Update',
     id: url,
     actor: byAccount.url,
     to,
+    cc,
     object
   }
 
@@ -209,13 +225,16 @@ async function deleteActivityData (url: string, byAccount: AccountInstance) {
   return activity
 }
 
-async function addActivityData (url: string, byAccount: AccountInstance, target: string, object: any) {
-  const to = await getPublicActivityTo(byAccount)
+async function addActivityData (url: string, byAccount: AccountInstance, video: VideoInstance, target: string, object: any) {
+  const videoPublic = video.privacy === VideoPrivacy.PUBLIC
+
+  const { to, cc } = await getAudience(byAccount, videoPublic)
   const activity: ActivityAdd = {
     type: 'Add',
     id: url,
     actor: byAccount.url,
     to,
+    cc,
     object,
     target
   }
index 0ea522e5c3738fd2e3d2c044cd1f910414073dee..8e8a3961b3c5f70c7ef077dac7b54b546cad5022 100644 (file)
@@ -1,9 +1,10 @@
-import { NextFunction, Request, Response, RequestHandler } from 'express'
+import { eachSeries } from 'async'
+import { NextFunction, Request, RequestHandler, Response } from 'express'
 import { ActivityPubSignature } from '../../shared'
 import { isSignatureVerified, logger } from '../helpers'
 import { fetchRemoteAccountAndCreateServer } from '../helpers/activitypub'
-import { database as db, ACTIVITY_PUB_ACCEPT_HEADER } from '../initializers'
-import { each, eachSeries, waterfall } from 'async'
+import { database as db } from '../initializers'
+import { ACTIVITY_PUB } from '../initializers/constants'
 
 async function checkSignature (req: Request, res: Response, next: NextFunction) {
   const signatureObject: ActivityPubSignature = req.body.signature
@@ -37,7 +38,7 @@ async function checkSignature (req: Request, res: Response, next: NextFunction)
 
 function executeIfActivityPub (fun: RequestHandler | RequestHandler[]) {
   return (req: Request, res: Response, next: NextFunction) => {
-    if (req.header('Accept') !== ACTIVITY_PUB_ACCEPT_HEADER) {
+    if (req.header('Accept') !== ACTIVITY_PUB.ACCEPT_HEADER) {
       return next()
     }
 
index 5fb254b2d8f43ec7acd31868dbb310fe15d917a0..dc10aca1a7a5ab00796fe49d474742e1f8a4ca89 100644 (file)
@@ -550,6 +550,7 @@ toFormattedDetailsJSON = function (this: VideoInstance) {
 
 toActivityPubObject = function (this: VideoInstance) {
   const { baseUrlHttp, baseUrlWs } = getBaseUrls(this)
+  if (!this.Tags) this.Tags = []
 
   const tag = this.Tags.map(t => ({
     type: 'Hashtag' as 'Hashtag',
diff --git a/server/tests/api/check-params/follows.ts b/server/tests/api/check-params/follows.ts
new file mode 100644 (file)
index 0000000..d742200
--- /dev/null
@@ -0,0 +1,222 @@
+/* tslint:disable:no-unused-expression */
+
+import * as request from 'supertest'
+import 'mocha'
+
+import {
+  ServerInfo,
+  flushTests,
+  runServer,
+  createUser,
+  loginAndGetAccessToken,
+  setAccessTokensToServers,
+  killallServers,
+  makePostBodyRequest
+} from '../../utils'
+
+describe('Test server follows API validators', function () {
+  let server: ServerInfo
+
+  // ---------------------------------------------------------------
+
+  before(async function () {
+    this.timeout(45000)
+
+    await flushTests()
+    server = await runServer(1)
+
+    await setAccessTokensToServers([ server ])
+  })
+
+  describe('When managing following', function () {
+    let userAccessToken = null
+
+    before(async function () {
+      await createUser(server.url, server.accessToken, 'user1', 'password')
+      server.user = {
+        username: 'user1',
+        password: 'password'
+      }
+
+      userAccessToken = await loginAndGetAccessToken(server)
+    })
+
+    describe('When adding follows', function () {
+      const path = '/api/v1/server/following'
+      const body = {
+        hosts: [ 'localhost:9002' ]
+      }
+
+      it('Should fail without hosts', async function () {
+        await request(server.url)
+                .post(path)
+                .set('Authorization', 'Bearer ' + server.accessToken)
+                .set('Accept', 'application/json')
+                .expect(400)
+      })
+
+      it('Should fail if hosts is not an array', async function () {
+        await request(server.url)
+                .post(path)
+                .send({ hosts: 'localhost:9002' })
+                .set('Authorization', 'Bearer ' + server.accessToken)
+                .set('Accept', 'application/json')
+                .expect(400)
+      })
+
+      it('Should fail if the array is not composed by hosts', async function () {
+        await request(server.url)
+                .post(path)
+                .send({ hosts: [ 'localhost:9002', 'localhost:coucou' ] })
+                .set('Authorization', 'Bearer ' + server.accessToken)
+                .set('Accept', 'application/json')
+                .expect(400)
+      })
+
+      it('Should fail if the array is composed with http schemes', async function () {
+        await request(server.url)
+                .post(path)
+                .send({ hosts: [ 'localhost:9002', 'http://localhost:9003' ] })
+                .set('Authorization', 'Bearer ' + server.accessToken)
+                .set('Accept', 'application/json')
+                .expect(400)
+      })
+
+      it('Should fail if hosts are not unique', async function () {
+        await request(server.url)
+                .post(path)
+                .send({ urls: [ 'localhost:9002', 'localhost:9002' ] })
+                .set('Authorization', 'Bearer ' + server.accessToken)
+                .set('Accept', 'application/json')
+                .expect(400)
+      })
+
+      it('Should fail with an invalid token', async function () {
+        await request(server.url)
+                .post(path)
+                .send(body)
+                .set('Authorization', 'Bearer fake_token')
+                .set('Accept', 'application/json')
+                .expect(401)
+      })
+
+      it('Should fail if the user is not an administrator', async function () {
+        await request(server.url)
+                .post(path)
+                .send(body)
+                .set('Authorization', 'Bearer ' + userAccessToken)
+                .set('Accept', 'application/json')
+                .expect(403)
+      })
+    })
+
+    describe('When listing followings', function () {
+      const path = '/api/v1/server/following'
+
+      it('Should fail with a bad start pagination', async function () {
+        await request(server.url)
+          .get(path)
+          .query({ start: 'hello' })
+          .set('Accept', 'application/json')
+          .expect(400)
+      })
+
+      it('Should fail with a bad count pagination', async function () {
+        await request(server.url)
+          .get(path)
+          .query({ count: 'hello' })
+          .set('Accept', 'application/json')
+          .expect(400)
+      })
+
+      it('Should fail with an incorrect sort', async function () {
+        await request(server.url)
+          .get(path)
+          .query({ sort: 'hello' })
+          .set('Accept', 'application/json')
+          .expect(400)
+      })
+    })
+
+    describe('When listing followers', function () {
+      const path = '/api/v1/server/followers'
+
+      it('Should fail with a bad start pagination', async function () {
+        await request(server.url)
+          .get(path)
+          .query({ start: 'hello' })
+          .set('Accept', 'application/json')
+          .expect(400)
+      })
+
+      it('Should fail with a bad count pagination', async function () {
+        await request(server.url)
+          .get(path)
+          .query({ count: 'hello' })
+          .set('Accept', 'application/json')
+          .expect(400)
+      })
+
+      it('Should fail with an incorrect sort', async function () {
+        await request(server.url)
+          .get(path)
+          .query({ sort: 'hello' })
+          .set('Accept', 'application/json')
+          .expect(400)
+      })
+    })
+
+    describe('When removing following', function () {
+      // it('Should fail with an invalid token', async function () {
+      //       await request(server.url)
+      //           .delete(path + '/1')
+      //           .set('Authorization', 'Bearer faketoken')
+      //           .set('Accept', 'application/json')
+      //           .expect(401)
+      // })
+      //
+      // it('Should fail if the user is not an administrator', async function () {
+      //       await request(server.url)
+      //           .delete(path + '/1')
+      //           .set('Authorization', 'Bearer ' + userAccessToken)
+      //           .set('Accept', 'application/json')
+      //           .expect(403)
+      // })
+      //
+      // it('Should fail with an undefined id', async function () {
+      //   await request(server.url)
+      //           .delete(path + '/' + undefined)
+      //           .set('Authorization', 'Bearer ' + server.accessToken)
+      //           .set('Accept', 'application/json')
+      //           .expect(400)
+      // })
+      //
+      // it('Should fail with an invalid id', async function () {
+            //  await request(server.url)
+      //           .delete(path + '/foobar')
+      //           .set('Authorization', 'Bearer ' + server.accessToken)
+      //           .set('Accept', 'application/json')
+      //           .expect(400)
+      // })
+      //
+      // it('Should fail we do not follow this server', async function () {
+            //  await request(server.url)
+      //           .delete(path + '/-1')
+      //           .set('Authorization', 'Bearer ' + server.accessToken)
+      //           .set('Accept', 'application/json')
+      //           .expect(404)
+      // })
+      //
+      // it('Should succeed with the correct parameters')
+    })
+  })
+
+  after(async function () {
+    killallServers([ server ])
+
+    // Keep the logs if the test failed
+    if (this['ok']) {
+      await flushTests()
+    }
+  })
+})
index 954b206e916a4d0b8ed6bb5fd852ad15171d911e..287480808fdfc2e507a5b39d2aebb36fd8212828 100644 (file)
@@ -1,8 +1,6 @@
 // Order of the tests we want to execute
-import './pods'
-import './remotes'
+import './follows'
 import './users'
-import './request-schedulers'
 import './services'
 import './videos'
 import './video-abuses'
diff --git a/server/tests/api/check-params/pods.ts b/server/tests/api/check-params/pods.ts
deleted file mode 100644 (file)
index 9f9c2e4..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/* tslint:disable:no-unused-expression */
-
-import * as request from 'supertest'
-import 'mocha'
-
-import {
-  ServerInfo,
-  flushTests,
-  runServer,
-  createUser,
-  loginAndGetAccessToken,
-  setAccessTokensToServers,
-  killallServers,
-  makePostBodyRequest
-} from '../../utils'
-
-describe('Test pods API validators', function () {
-  let server: ServerInfo
-
-  // ---------------------------------------------------------------
-
-  before(async function () {
-    this.timeout(45000)
-
-    await flushTests()
-    server = await runServer(1)
-
-    await setAccessTokensToServers([ server ])
-  })
-
-  describe('When managing friends', function () {
-    const path = '/api/v1/pods/'
-    let userAccessToken = null
-
-    before(async function () {
-      await createUser(server.url, server.accessToken, 'user1', 'password')
-      server.user = {
-        username: 'user1',
-        password: 'password'
-      }
-
-      userAccessToken = await loginAndGetAccessToken(server)
-    })
-
-    describe('When making friends', function () {
-      const body = {
-        hosts: [ 'localhost:9002' ]
-      }
-
-      it('Should fail without hosts', async function () {
-        await request(server.url)
-                .post(path + '/make-friends')
-                .set('Authorization', 'Bearer ' + server.accessToken)
-                .set('Accept', 'application/json')
-                .expect(400)
-      })
-
-      it('Should fail if hosts is not an array', async function () {
-        await request(server.url)
-                .post(path + '/make-friends')
-                .send({ hosts: 'localhost:9002' })
-                .set('Authorization', 'Bearer ' + server.accessToken)
-                .set('Accept', 'application/json')
-                .expect(400)
-      })
-
-      it('Should fail if the array is not composed by hosts', async function () {
-        await request(server.url)
-                .post(path + '/make-friends')
-                .send({ hosts: [ 'localhost:9002', 'localhost:coucou' ] })
-                .set('Authorization', 'Bearer ' + server.accessToken)
-                .set('Accept', 'application/json')
-                .expect(400)
-      })
-
-      it('Should fail if the array is composed with http schemes', async function () {
-        await request(server.url)
-                .post(path + '/make-friends')
-                .send({ hosts: [ 'localhost:9002', 'http://localhost:9003' ] })
-                .set('Authorization', 'Bearer ' + server.accessToken)
-                .set('Accept', 'application/json')
-                .expect(400)
-      })
-
-      it('Should fail if hosts are not unique', async function () {
-        await request(server.url)
-                .post(path + '/make-friends')
-                .send({ urls: [ 'localhost:9002', 'localhost:9002' ] })
-                .set('Authorization', 'Bearer ' + server.accessToken)
-                .set('Accept', 'application/json')
-                .expect(400)
-      })
-
-      it('Should fail with an invalid token', async function () {
-        await request(server.url)
-                .post(path + '/make-friends')
-                .send(body)
-                .set('Authorization', 'Bearer fake_token')
-                .set('Accept', 'application/json')
-                .expect(401)
-      })
-
-      it('Should fail if the user is not an administrator', async function () {
-        await request(server.url)
-                .post(path + '/make-friends')
-                .send(body)
-                .set('Authorization', 'Bearer ' + userAccessToken)
-                .set('Accept', 'application/json')
-                .expect(403)
-      })
-    })
-
-    describe('When listing friends', function () {
-      it('Should fail with a bad start pagination', async function () {
-        await request(server.url)
-          .get(path)
-          .query({ start: 'hello' })
-          .set('Accept', 'application/json')
-          .expect(400)
-      })
-
-      it('Should fail with a bad count pagination', async function () {
-        await request(server.url)
-          .get(path)
-          .query({ count: 'hello' })
-          .set('Accept', 'application/json')
-          .expect(400)
-      })
-
-      it('Should fail with an incorrect sort', async function () {
-        await request(server.url)
-          .get(path)
-          .query({ sort: 'hello' })
-          .set('Accept', 'application/json')
-          .expect(400)
-      })
-    })
-
-    describe('When quitting friends', function () {
-      it('Should fail with an invalid token', async function () {
-        await request(server.url)
-                .get(path + '/quit-friends')
-                .query({ start: 'hello' })
-                .set('Authorization', 'Bearer faketoken')
-                .set('Accept', 'application/json')
-                .expect(401)
-      })
-
-      it('Should fail if the user is not an administrator', async function () {
-        await request(server.url)
-                .get(path + '/quit-friends')
-                .query({ start: 'hello' })
-                .set('Authorization', 'Bearer ' + userAccessToken)
-                .set('Accept', 'application/json')
-                .expect(403)
-      })
-    })
-
-    describe('When removing one friend', function () {
-      it('Should fail with an invalid token', async function () {
-       await request(server.url)
-                .delete(path + '/1')
-                .set('Authorization', 'Bearer faketoken')
-                .set('Accept', 'application/json')
-                .expect(401)
-      })
-
-      it('Should fail if the user is not an administrator', async function () {
-       await request(server.url)
-                .delete(path + '/1')
-                .set('Authorization', 'Bearer ' + userAccessToken)
-                .set('Accept', 'application/json')
-                .expect(403)
-      })
-
-      it('Should fail with an undefined id', async function () {
-        await request(server.url)
-                .delete(path + '/' + undefined)
-                .set('Authorization', 'Bearer ' + server.accessToken)
-                .set('Accept', 'application/json')
-                .expect(400)
-      })
-
-      it('Should fail with an invalid id', async function () {
-             await request(server.url)
-                .delete(path + '/foobar')
-                .set('Authorization', 'Bearer ' + server.accessToken)
-                .set('Accept', 'application/json')
-                .expect(400)
-      })
-
-      it('Should fail if the pod is not a friend', async function () {
-             await request(server.url)
-                .delete(path + '/-1')
-                .set('Authorization', 'Bearer ' + server.accessToken)
-                .set('Accept', 'application/json')
-                .expect(404)
-      })
-
-      it('Should succeed with the correct parameters')
-    })
-  })
-
-  describe('When adding a pod from remote', function () {
-    const path = '/api/v1/remote/pods/add'
-
-    it('Should fail with nothing', async function () {
-      const fields = {}
-      await makePostBodyRequest({ url: server.url, path, fields })
-    })
-
-    it('Should fail without public key', async function () {
-      const fields = {
-        email: 'test.example.com',
-        host: 'coucou.com'
-      }
-      await makePostBodyRequest({ url: server.url, path, fields })
-    })
-
-    it('Should fail without an email', async function () {
-      const fields = {
-        host: 'coucou.com',
-        publicKey: 'my super public key'
-      }
-      await makePostBodyRequest({ url: server.url, path, fields })
-    })
-
-    it('Should fail without an invalid email', async function () {
-      const fields = {
-        host: 'coucou.com',
-        email: 'test.example.com',
-        publicKey: 'my super public key'
-      }
-      await makePostBodyRequest({ url: server.url, path, fields })
-    })
-
-    it('Should fail without a host', async function () {
-      const fields = {
-        email: 'test.example.com',
-        publicKey: 'my super public key'
-      }
-      await makePostBodyRequest({ url: server.url, path, fields })
-    })
-
-    it('Should fail with an incorrect host', async function () {
-      const fields = {
-        host: 'http://coucou.com',
-        email: 'test.example.com',
-        publicKey: 'my super public key'
-      }
-      await makePostBodyRequest({ url: server.url, path, fields })
-
-      fields.host = 'http://coucou'
-      await makePostBodyRequest({ url: server.url, path, fields })
-
-      fields.host = 'coucou'
-      await makePostBodyRequest({ url: server.url, path, fields })
-    })
-
-    it('Should succeed with the correct parameters', async function () {
-      const fields = {
-        host: 'coucou.com',
-        email: 'test@example.com',
-        publicKey: 'my super public key'
-      }
-      await makePostBodyRequest({ url: server.url, path, fields, statusCodeExpected: 200 })
-    })
-
-    it('Should fail with a host that already exists', async function () {
-      const fields = {
-        host: 'coucou.com',
-        email: 'test@example.com',
-        publicKey: 'my super public key'
-      }
-      await makePostBodyRequest({ url: server.url, path, fields, statusCodeExpected: 409 })
-    })
-  })
-
-  after(async function () {
-    killallServers([ server ])
-
-    // Keep the logs if the test failed
-    if (this['ok']) {
-      await flushTests()
-    }
-  })
-})
diff --git a/server/tests/api/check-params/remotes.ts b/server/tests/api/check-params/remotes.ts
deleted file mode 100644 (file)
index 6d17474..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* tslint:disable:no-unused-expression */
-
-import 'mocha'
-
-import {
-  ServerInfo,
-  flushTests,
-  runServer,
-  setAccessTokensToServers,
-  killallServers
-} from '../../utils'
-
-describe('Test remote videos API validators', function () {
-  let server: ServerInfo
-
-  // ---------------------------------------------------------------
-
-  before(async function () {
-    this.timeout(60000)
-
-    await flushTests()
-
-    server = await runServer(1)
-
-    await setAccessTokensToServers([ server ])
-  })
-
-  describe('When making a secure request', async function () {
-    it('Should check a secure request')
-  })
-
-  describe('When adding a video', async function () {
-    it('Should check when adding a video')
-
-    it('Should not add an existing uuid')
-  })
-
-  describe('When removing a video', async function () {
-    it('Should check when removing a video')
-  })
-
-  describe('When reporting abuse on a video', async function () {
-    it('Should check when reporting a video abuse')
-  })
-
-  after(async function () {
-    killallServers([ server ])
-
-    // Keep the logs if the test failed
-    if (this['ok']) {
-      await flushTests()
-    }
-  })
-})
diff --git a/server/tests/api/check-params/request-schedulers.ts b/server/tests/api/check-params/request-schedulers.ts
deleted file mode 100644 (file)
index 01a54ff..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/* tslint:disable:no-unused-expression */
-
-import * as request from 'supertest'
-import 'mocha'
-
-import {
-  flushTests,
-  runServer,
-  createUser,
-  setAccessTokensToServers,
-  killallServers,
-  getUserAccessToken
-} from '../../utils'
-
-describe('Test request schedulers stats API validators', function () {
-  const path = '/api/v1/request-schedulers/stats'
-  let server = null
-  let userAccessToken = null
-
-  // ---------------------------------------------------------------
-
-  before(async function () {
-    this.timeout(60000)
-
-    await flushTests()
-
-    server = await runServer(1)
-    await setAccessTokensToServers([ server ])
-
-    const username = 'user'
-    const password = 'my super password'
-    await createUser(server.url, server.accessToken, username, password)
-
-    const user = {
-      username: 'user',
-      password: 'my super password'
-    }
-
-    userAccessToken = await getUserAccessToken(server, user)
-  })
-
-  it('Should fail with an non authenticated user', async function () {
-    await request(server.url)
-            .get(path)
-            .set('Accept', 'application/json')
-            .expect(401)
-  })
-
-  it('Should fail with a non admin user', async function () {
-    await request(server.url)
-            .get(path)
-            .set('Authorization', 'Bearer ' + userAccessToken)
-            .set('Accept', 'application/json')
-            .expect(403)
-  })
-
-  after(async function () {
-    killallServers([ server ])
-
-    // Keep the logs if the test failed
-    if (this['ok']) {
-      await flushTests()
-    }
-  })
-})
index 5860e91951bd6d719308073fce768fbc475aa4ba..7f5609784cfbdb75ddb4462fa1c21047f1676ad9 100644 (file)
@@ -473,7 +473,7 @@ describe('Test videos API validator', function () {
 
     it('Should fail with a video of another user')
 
-    it('Should fail with a video of another pod')
+    it('Should fail with a video of another server')
 
     it('Should succeed with the correct parameters', async function () {
       const fields = getCompleteVideoUpdateAttributes()
@@ -584,7 +584,7 @@ describe('Test videos API validator', function () {
 
     it('Should fail with a video of another user')
 
-    it('Should fail with a video of another pod')
+    it('Should fail with a video of another server')
 
     it('Should succeed with the correct parameters')
   })
index 590b0d51c6dbaf3026e0c548f1411ef130349e38..35b414383739c5c435c8cd1b9e7303542fd2e7d3 100644 (file)
@@ -2,7 +2,7 @@
 import './config'
 import './check-params'
 import './users'
-import './single-pod'
+import './single-server'
 import './video-abuse'
 import './video-blacklist'
 import './video-blacklist-management'
index a2faf8d0f656606496ca0013b7aa96520b7bbf67..e554c25f893d30c77f327b5d8754fd4cb9b21115 100644 (file)
@@ -1,3 +1,3 @@
 // Order of the tests we want to execute
-import './multiple-pods'
+import './multiple-servers'
 import './video-transcoder'
diff --git a/server/tests/api/multiple-pods.ts b/server/tests/api/multiple-pods.ts
deleted file mode 100644 (file)
index 3c6b3f6..0000000
+++ /dev/null
@@ -1,723 +0,0 @@
-/* tslint:disable:no-unused-expression */
-
-import 'mocha'
-import * as chai from 'chai'
-
-import {
-  dateIsValid,
-  flushAndRunMultipleServers,
-  flushTests,
-  getVideo,
-  getVideosList,
-  killallServers,
-  makeFriends,
-  rateVideo,
-  removeVideo,
-  ServerInfo,
-  setAccessTokensToServers,
-  testVideoImage,
-  updateVideo,
-  uploadVideo,
-  wait,
-  webtorrentAdd,
-  addVideoChannel,
-  getVideoChannelsList,
-  getUserAccessToken
-} from '../utils'
-import { createUser } from '../utils/users'
-
-const expect = chai.expect
-
-describe('Test multiple pods', function () {
-  let servers: ServerInfo[] = []
-  const toRemove = []
-  let videoUUID = ''
-  let videoChannelId: number
-
-  before(async function () {
-    this.timeout(120000)
-
-    servers = await flushAndRunMultipleServers(3)
-
-    // Get the access tokens
-    await setAccessTokensToServers(servers)
-
-    const videoChannel = {
-      name: 'my channel',
-      description: 'super channel'
-    }
-    await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
-    const channelRes = await getVideoChannelsList(servers[0].url, 0, 1)
-    videoChannelId = channelRes.body.data[0].id
-
-    // The second pod make friend with the third
-    await makeFriends(servers[1].url, servers[1].accessToken)
-
-    // Wait for the request between pods
-    await wait(10000)
-
-    // Pod 1 make friends too
-    await makeFriends(servers[0].url, servers[0].accessToken)
-  })
-
-  it('Should not have videos for all pods', async function () {
-    for (const server of servers) {
-      const res = await getVideosList(server.url)
-      const videos = res.body.data
-      expect(videos).to.be.an('array')
-      expect(videos.length).to.equal(0)
-    }
-  })
-
-  describe('Should upload the video and propagate on each pod', function () {
-    it('Should upload the video on pod 1 and propagate on each pod', async function () {
-      // Pod 1 has video transcoding activated
-      this.timeout(15000)
-
-      const videoAttributes = {
-        name: 'my super name for pod 1',
-        category: 5,
-        licence: 4,
-        language: 9,
-        nsfw: true,
-        description: 'my super description for pod 1',
-        tags: [ 'tag1p1', 'tag2p1' ],
-        channelId: videoChannelId,
-        fixture: 'video_short1.webm'
-      }
-      await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
-
-      await wait(11000)
-
-      // All pods should have this video
-      for (const server of servers) {
-        let baseMagnet = null
-
-        const res = await getVideosList(server.url)
-
-        const videos = res.body.data
-        expect(videos).to.be.an('array')
-        expect(videos.length).to.equal(1)
-        const video = videos[0]
-        expect(video.name).to.equal('my super name for pod 1')
-        expect(video.category).to.equal(5)
-        expect(video.categoryLabel).to.equal('Sports')
-        expect(video.licence).to.equal(4)
-        expect(video.licenceLabel).to.equal('Attribution - Non Commercial')
-        expect(video.language).to.equal(9)
-        expect(video.languageLabel).to.equal('Japanese')
-        expect(video.nsfw).to.be.ok
-        expect(video.description).to.equal('my super description for pod 1')
-        expect(video.podHost).to.equal('localhost:9001')
-        expect(video.duration).to.equal(10)
-        expect(video.tags).to.deep.equal([ 'tag1p1', 'tag2p1' ])
-        expect(dateIsValid(video.createdAt)).to.be.true
-        expect(dateIsValid(video.updatedAt)).to.be.true
-        expect(video.account).to.equal('root')
-
-        const res2 = await getVideo(server.url, video.uuid)
-        const videoDetails = res2.body
-
-        expect(videoDetails.channel.name).to.equal('my channel')
-        expect(videoDetails.channel.description).to.equal('super channel')
-        expect(dateIsValid(videoDetails.channel.createdAt)).to.be.true
-        expect(dateIsValid(videoDetails.channel.updatedAt)).to.be.true
-        expect(videoDetails.files).to.have.lengthOf(1)
-
-        const file = videoDetails.files[0]
-        const magnetUri = file.magnetUri
-        expect(file.magnetUri).to.have.lengthOf.above(2)
-        expect(file.torrentUrl).to.equal(`http://${videoDetails.podHost}/static/torrents/${videoDetails.uuid}-${file.resolution}.torrent`)
-        expect(file.fileUrl).to.equal(`http://${videoDetails.podHost}/static/webseed/${videoDetails.uuid}-${file.resolution}.webm`)
-        expect(file.resolution).to.equal(720)
-        expect(file.resolutionLabel).to.equal('720p')
-        expect(file.size).to.equal(572456)
-
-        if (server.url !== 'http://localhost:9001') {
-          expect(video.isLocal).to.be.false
-          expect(videoDetails.channel.isLocal).to.be.false
-        } else {
-          expect(video.isLocal).to.be.true
-          expect(videoDetails.channel.isLocal).to.be.true
-        }
-
-        // All pods should have the same magnet Uri
-        if (baseMagnet === null) {
-          baseMagnet = magnetUri
-        } else {
-          expect(baseMagnet).to.equal(magnetUri)
-        }
-
-        const test = await testVideoImage(server.url, 'video_short1.webm', video.thumbnailPath)
-        expect(test).to.equal(true)
-      }
-    })
-
-    it('Should upload the video on pod 2 and propagate on each pod', async function () {
-      this.timeout(120000)
-
-      const user = {
-        username: 'user1',
-        password: 'super_password'
-      }
-      await createUser(servers[1].url, servers[1].accessToken, user.username, user.password)
-      const userAccessToken = await getUserAccessToken(servers[1], user)
-
-      const videoAttributes = {
-        name: 'my super name for pod 2',
-        category: 4,
-        licence: 3,
-        language: 11,
-        nsfw: true,
-        description: 'my super description for pod 2',
-        tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
-        fixture: 'video_short2.webm'
-      }
-      await uploadVideo(servers[1].url, userAccessToken, videoAttributes)
-
-      // Transcoding, so wait more than 22000
-      await wait(60000)
-
-      // All pods should have this video
-      for (const server of servers) {
-        let baseMagnet = {}
-
-        const res = await getVideosList(server.url)
-
-        const videos = res.body.data
-        expect(videos).to.be.an('array')
-        expect(videos.length).to.equal(2)
-        const video = videos[1]
-        expect(video.name).to.equal('my super name for pod 2')
-        expect(video.category).to.equal(4)
-        expect(video.categoryLabel).to.equal('Art')
-        expect(video.licence).to.equal(3)
-        expect(video.licenceLabel).to.equal('Attribution - No Derivatives')
-        expect(video.language).to.equal(11)
-        expect(video.languageLabel).to.equal('German')
-        expect(video.nsfw).to.be.true
-        expect(video.description).to.equal('my super description for pod 2')
-        expect(video.podHost).to.equal('localhost:9002')
-        expect(video.duration).to.equal(5)
-        expect(video.tags).to.deep.equal([ 'tag1p2', 'tag2p2', 'tag3p2' ])
-        expect(dateIsValid(video.createdAt)).to.be.true
-        expect(dateIsValid(video.updatedAt)).to.be.true
-        expect(video.account).to.equal('user1')
-
-        if (server.url !== 'http://localhost:9002') {
-          expect(video.isLocal).to.be.false
-        } else {
-          expect(video.isLocal).to.be.true
-        }
-
-        const res2 = await getVideo(server.url, video.uuid)
-        const videoDetails = res2.body
-
-        expect(videoDetails.channel.name).to.equal('Default user1 channel')
-        expect(dateIsValid(videoDetails.channel.createdAt)).to.be.true
-        expect(dateIsValid(videoDetails.channel.updatedAt)).to.be.true
-
-        expect(videoDetails.files).to.have.lengthOf(4)
-
-        // Check common attributes
-        for (const file of videoDetails.files) {
-          expect(file.magnetUri).to.have.lengthOf.above(2)
-
-          // All pods should have the same magnet Uri
-          if (baseMagnet[file.resolution] === undefined) {
-            baseMagnet[file.resolution] = file.magnet
-          } else {
-            expect(baseMagnet[file.resolution]).to.equal(file.magnet)
-          }
-        }
-
-        const file240p = videoDetails.files.find(f => f.resolution === 240)
-        expect(file240p).not.to.be.undefined
-        expect(file240p.resolutionLabel).to.equal('240p')
-        expect(file240p.size).to.be.above(180000).and.below(200000)
-
-        const file360p = videoDetails.files.find(f => f.resolution === 360)
-        expect(file360p).not.to.be.undefined
-        expect(file360p.resolutionLabel).to.equal('360p')
-        expect(file360p.size).to.be.above(270000).and.below(290000)
-
-        const file480p = videoDetails.files.find(f => f.resolution === 480)
-        expect(file480p).not.to.be.undefined
-        expect(file480p.resolutionLabel).to.equal('480p')
-        expect(file480p.size).to.be.above(380000).and.below(400000)
-
-        const file720p = videoDetails.files.find(f => f.resolution === 720)
-        expect(file720p).not.to.be.undefined
-        expect(file720p.resolutionLabel).to.equal('720p')
-        expect(file720p.size).to.be.above(700000).and.below(7200000)
-
-        const test = await testVideoImage(server.url, 'video_short2.webm', videoDetails.thumbnailPath)
-        expect(test).to.equal(true)
-      }
-    })
-
-    it('Should upload two videos on pod 3 and propagate on each pod', async function () {
-      this.timeout(45000)
-
-      const videoAttributes1 = {
-        name: 'my super name for pod 3',
-        category: 6,
-        licence: 5,
-        language: 11,
-        nsfw: true,
-        description: 'my super description for pod 3',
-        tags: [ 'tag1p3' ],
-        fixture: 'video_short3.webm'
-      }
-      await uploadVideo(servers[2].url, servers[2].accessToken, videoAttributes1)
-
-      const videoAttributes2 = {
-        name: 'my super name for pod 3-2',
-        category: 7,
-        licence: 6,
-        language: 12,
-        nsfw: false,
-        description: 'my super description for pod 3-2',
-        tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
-        fixture: 'video_short.webm'
-      }
-      await uploadVideo(servers[2].url, servers[2].accessToken, videoAttributes2)
-
-      await wait(33000)
-
-      let baseMagnet = null
-      // All pods should have this video
-      for (const server of servers) {
-        const res = await getVideosList(server.url)
-
-        const videos = res.body.data
-        expect(videos).to.be.an('array')
-        expect(videos.length).to.equal(4)
-
-        // We not sure about the order of the two last uploads
-        let video1 = null
-        let video2 = null
-        if (videos[2].name === 'my super name for pod 3') {
-          video1 = videos[2]
-          video2 = videos[3]
-        } else {
-          video1 = videos[3]
-          video2 = videos[2]
-        }
-
-        expect(video1.name).to.equal('my super name for pod 3')
-        expect(video1.category).to.equal(6)
-        expect(video1.categoryLabel).to.equal('Travels')
-        expect(video1.licence).to.equal(5)
-        expect(video1.licenceLabel).to.equal('Attribution - Non Commercial - Share Alike')
-        expect(video1.language).to.equal(11)
-        expect(video1.languageLabel).to.equal('German')
-        expect(video1.nsfw).to.be.ok
-        expect(video1.description).to.equal('my super description for pod 3')
-        expect(video1.podHost).to.equal('localhost:9003')
-        expect(video1.duration).to.equal(5)
-        expect(video1.tags).to.deep.equal([ 'tag1p3' ])
-        expect(video1.author).to.equal('root')
-        expect(dateIsValid(video1.createdAt)).to.be.true
-        expect(dateIsValid(video1.updatedAt)).to.be.true
-
-        const res2 = await getVideo(server.url, video1.id)
-        const video1Details = res2.body
-        expect(video1Details.files).to.have.lengthOf(1)
-
-        const file1 = video1Details.files[0]
-        expect(file1.magnetUri).to.have.lengthOf.above(2)
-        expect(file1.resolution).to.equal(720)
-        expect(file1.resolutionLabel).to.equal('720p')
-        expect(file1.size).to.equal(292677)
-
-        expect(video2.name).to.equal('my super name for pod 3-2')
-        expect(video2.category).to.equal(7)
-        expect(video2.categoryLabel).to.equal('Gaming')
-        expect(video2.licence).to.equal(6)
-        expect(video2.licenceLabel).to.equal('Attribution - Non Commercial - No Derivatives')
-        expect(video2.language).to.equal(12)
-        expect(video2.languageLabel).to.equal('Korean')
-        expect(video2.nsfw).to.be.false
-        expect(video2.description).to.equal('my super description for pod 3-2')
-        expect(video2.podHost).to.equal('localhost:9003')
-        expect(video2.duration).to.equal(5)
-        expect(video2.tags).to.deep.equal([ 'tag2p3', 'tag3p3', 'tag4p3' ])
-        expect(video2.author).to.equal('root')
-        expect(dateIsValid(video2.createdAt)).to.be.true
-        expect(dateIsValid(video2.updatedAt)).to.be.true
-
-        const res3 = await getVideo(server.url, video2.id)
-        const video2Details = res3.body
-
-        expect(video2Details.files).to.have.lengthOf(1)
-
-        const file2 = video2Details.files[0]
-        const magnetUri2 = file2.magnetUri
-        expect(file2.magnetUri).to.have.lengthOf.above(2)
-        expect(file2.resolution).to.equal(720)
-        expect(file2.resolutionLabel).to.equal('720p')
-        expect(file2.size).to.equal(218910)
-
-        if (server.url !== 'http://localhost:9003') {
-          expect(video1.isLocal).to.be.false
-          expect(video2.isLocal).to.be.false
-        } else {
-          expect(video1.isLocal).to.be.true
-          expect(video2.isLocal).to.be.true
-        }
-
-        // All pods should have the same magnet Uri
-        if (baseMagnet === null) {
-          baseMagnet = magnetUri2
-        } else {
-          expect(baseMagnet).to.equal(magnetUri2)
-        }
-
-        const test1 = await testVideoImage(server.url, 'video_short3.webm', video1.thumbnailPath)
-        expect(test1).to.equal(true)
-
-        const test2 = await testVideoImage(server.url, 'video_short.webm', video2.thumbnailPath)
-        expect(test2).to.equal(true)
-      }
-    })
-  })
-
-  describe('Should seed the uploaded video', function () {
-    it('Should add the file 1 by asking pod 3', async function () {
-      // Yes, this could be long
-      this.timeout(200000)
-
-      const res = await getVideosList(servers[2].url)
-
-      const video = res.body.data[0]
-      toRemove.push(res.body.data[2])
-      toRemove.push(res.body.data[3])
-
-      const res2 = await getVideo(servers[2].url, video.id)
-      const videoDetails = res2.body
-
-      const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri)
-      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('')
-    })
-
-    it('Should add the file 2 by asking pod 1', async function () {
-      // Yes, this could be long
-      this.timeout(200000)
-
-      const res = await getVideosList(servers[0].url)
-
-      const video = res.body.data[1]
-      const res2 = await getVideo(servers[0].url, video.id)
-      const videoDetails = res2.body
-
-      const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri)
-      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('')
-    })
-
-    it('Should add the file 3 by asking pod 2', async function () {
-      // Yes, this could be long
-      this.timeout(200000)
-
-      const res = await getVideosList(servers[1].url)
-
-      const video = res.body.data[2]
-      const res2 = await getVideo(servers[1].url, video.id)
-      const videoDetails = res2.body
-
-      const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri)
-      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('')
-    })
-
-    it('Should add the file 3-2 by asking pod 1', async function () {
-      // Yes, this could be long
-      this.timeout(200000)
-
-      const res = await getVideosList(servers[0].url)
-
-      const video = res.body.data[3]
-      const res2 = await getVideo(servers[0].url, video.id)
-      const videoDetails = res2.body
-
-      const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri)
-      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('')
-    })
-
-    it('Should add the file 2 in 360p by asking pod 1', async function () {
-      // Yes, this could be long
-      this.timeout(200000)
-
-      const res = await getVideosList(servers[0].url)
-
-      const video = res.body.data.find(v => v.name === 'my super name for pod 2')
-      const res2 = await getVideo(servers[0].url, video.id)
-      const videoDetails = res2.body
-
-      const file = videoDetails.files.find(f => f.resolution === 360)
-      expect(file).not.to.be.undefined
-
-      const torrent = await webtorrentAdd(file.magnetUri)
-      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('')
-    })
-  })
-
-  describe('Should update video views, likes and dislikes', function () {
-    let localVideosPod3 = []
-    let remoteVideosPod1 = []
-    let remoteVideosPod2 = []
-    let remoteVideosPod3 = []
-
-    before(async function () {
-      const res1 = await getVideosList(servers[0].url)
-      remoteVideosPod1 = res1.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
-
-      const res2 = await getVideosList(servers[1].url)
-      remoteVideosPod2 = res2.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
-
-      const res3 = await getVideosList(servers[2].url)
-      localVideosPod3 = res3.body.data.filter(video => video.isLocal === true).map(video => video.uuid)
-      remoteVideosPod3 = res3.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
-    })
-
-    it('Should view multiple videos on owned servers', async function () {
-      this.timeout(30000)
-
-      const tasks: Promise<any>[] = []
-      tasks.push(getVideo(servers[2].url, localVideosPod3[0]))
-      tasks.push(getVideo(servers[2].url, localVideosPod3[0]))
-      tasks.push(getVideo(servers[2].url, localVideosPod3[0]))
-      tasks.push(getVideo(servers[2].url, localVideosPod3[1]))
-
-      await Promise.all(tasks)
-
-      await wait(22000)
-
-      for (const server of servers) {
-        const res = await getVideosList(server.url)
-
-        const videos = res.body.data
-        const video0 = videos.find(v => v.uuid === localVideosPod3[0])
-        const video1 = videos.find(v => v.uuid === localVideosPod3[1])
-
-        expect(video0.views).to.equal(7)
-        expect(video1.views).to.equal(5)
-      }
-    })
-
-    it('Should view multiple videos on each servers', async function () {
-      this.timeout(30000)
-
-      const tasks: Promise<any>[] = []
-      tasks.push(getVideo(servers[0].url, remoteVideosPod1[0]))
-      tasks.push(getVideo(servers[1].url, remoteVideosPod2[0]))
-      tasks.push(getVideo(servers[1].url, remoteVideosPod2[0]))
-      tasks.push(getVideo(servers[2].url, remoteVideosPod3[0]))
-      tasks.push(getVideo(servers[2].url, remoteVideosPod3[1]))
-      tasks.push(getVideo(servers[2].url, remoteVideosPod3[1]))
-      tasks.push(getVideo(servers[2].url, remoteVideosPod3[1]))
-      tasks.push(getVideo(servers[2].url, localVideosPod3[1]))
-      tasks.push(getVideo(servers[2].url, localVideosPod3[1]))
-      tasks.push(getVideo(servers[2].url, localVideosPod3[1]))
-
-      await Promise.all(tasks)
-
-      await wait(22000)
-
-      let baseVideos = null
-
-      for (const server of servers) {
-        const res = await getVideosList(server.url)
-
-        const videos = res.body.data
-
-        // Initialize base videos for future comparisons
-        if (baseVideos === null) {
-          baseVideos = videos
-          return
-        }
-
-        for (const baseVideo of baseVideos) {
-          const sameVideo = videos.find(video => video.name === baseVideo.name)
-          expect(baseVideo.views).to.equal(sameVideo.views)
-        }
-      }
-    })
-
-    it('Should like and dislikes videos on different services', async function () {
-      this.timeout(30000)
-
-      const tasks: Promise<any>[] = []
-      tasks.push(rateVideo(servers[0].url, servers[0].accessToken, remoteVideosPod1[0], 'like'))
-      tasks.push(rateVideo(servers[0].url, servers[0].accessToken, remoteVideosPod1[0], 'dislike'))
-      tasks.push(rateVideo(servers[0].url, servers[0].accessToken, remoteVideosPod1[0], 'like'))
-      tasks.push(rateVideo(servers[2].url, servers[2].accessToken, localVideosPod3[1], 'like'))
-      tasks.push(rateVideo(servers[2].url, servers[2].accessToken, localVideosPod3[1], 'dislike'))
-      tasks.push(rateVideo(servers[2].url, servers[2].accessToken, remoteVideosPod3[1], 'dislike'))
-      tasks.push(rateVideo(servers[2].url, servers[2].accessToken, remoteVideosPod3[0], 'like'))
-
-      await Promise.all(tasks)
-
-      await wait(22000)
-
-      let baseVideos = null
-      for (const server of servers) {
-        const res = await getVideosList(server.url)
-
-        const videos = res.body.data
-
-        // Initialize base videos for future comparisons
-        if (baseVideos === null) {
-          baseVideos = videos
-          return
-        }
-
-        baseVideos.forEach(baseVideo => {
-          const sameVideo = videos.find(video => video.name === baseVideo.name)
-          expect(baseVideo.likes).to.equal(sameVideo.likes)
-          expect(baseVideo.dislikes).to.equal(sameVideo.dislikes)
-        })
-      }
-    })
-  })
-
-  describe('Should manipulate these videos', function () {
-    it('Should update the video 3 by asking pod 3', async function () {
-      this.timeout(15000)
-
-      const attributes = {
-        name: 'my super video updated',
-        category: 10,
-        licence: 7,
-        language: 13,
-        nsfw: true,
-        description: 'my super description updated',
-        tags: [ 'tag_up_1', 'tag_up_2' ]
-      }
-
-      await updateVideo(servers[2].url, servers[2].accessToken, toRemove[0].id, attributes)
-
-      await wait(11000)
-    })
-
-    it('Should have the video 3 updated on each pod', async function () {
-      this.timeout(200000)
-
-      for (const server of servers) {
-        const res = await getVideosList(server.url)
-
-        const videos = res.body.data
-        const videoUpdated = videos.find(video => video.name === 'my super video updated')
-
-        expect(!!videoUpdated).to.be.true
-        expect(videoUpdated.category).to.equal(10)
-        expect(videoUpdated.categoryLabel).to.equal('Entertainment')
-        expect(videoUpdated.licence).to.equal(7)
-        expect(videoUpdated.licenceLabel).to.equal('Public Domain Dedication')
-        expect(videoUpdated.language).to.equal(13)
-        expect(videoUpdated.languageLabel).to.equal('French')
-        expect(videoUpdated.nsfw).to.be.ok
-        expect(videoUpdated.description).to.equal('my super description updated')
-        expect(videoUpdated.tags).to.deep.equal([ 'tag_up_1', 'tag_up_2' ])
-        expect(dateIsValid(videoUpdated.updatedAt, 20000)).to.be.true
-
-        const res2 = await getVideo(server.url, videoUpdated.uuid)
-        const videoUpdatedDetails = res2.body
-
-        const file = videoUpdatedDetails .files[0]
-        expect(file.magnetUri).to.have.lengthOf.above(2)
-        expect(file.resolution).to.equal(720)
-        expect(file.resolutionLabel).to.equal('720p')
-        expect(file.size).to.equal(292677)
-
-        const test = await testVideoImage(server.url, 'video_short3.webm', videoUpdated.thumbnailPath)
-        expect(test).to.equal(true)
-
-        // Avoid "duplicate torrent" errors
-        const refreshWebTorrent = true
-        const torrent = await webtorrentAdd(videoUpdatedDetails .files[0].magnetUri, refreshWebTorrent)
-        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('')
-      }
-    })
-
-    it('Should remove the videos 3 and 3-2 by asking pod 3', async function () {
-      this.timeout(15000)
-
-      await removeVideo(servers[2].url, servers[2].accessToken, toRemove[0].id)
-      await removeVideo(servers[2].url, servers[2].accessToken, toRemove[1].id)
-
-      await wait(11000)
-    })
-
-    it('Should have videos 1 and 3 on each pod', async function () {
-      for (const server of servers) {
-        const res = await getVideosList(server.url)
-
-        const videos = res.body.data
-        expect(videos).to.be.an('array')
-        expect(videos.length).to.equal(2)
-        expect(videos[0].name).not.to.equal(videos[1].name)
-        expect(videos[0].name).not.to.equal(toRemove[0].name)
-        expect(videos[1].name).not.to.equal(toRemove[0].name)
-        expect(videos[0].name).not.to.equal(toRemove[1].name)
-        expect(videos[1].name).not.to.equal(toRemove[1].name)
-
-        videoUUID = videos.find(video => video.name === 'my super name for pod 1').uuid
-      }
-    })
-
-    it('Should get the same video by UUID on each pod', async function () {
-      let baseVideo = null
-      for (const server of servers) {
-        const res = await getVideo(server.url, videoUUID)
-
-        const video = res.body
-
-        if (baseVideo === null) {
-          baseVideo = video
-          return
-        }
-
-        expect(baseVideo.name).to.equal(video.name)
-        expect(baseVideo.uuid).to.equal(video.uuid)
-        expect(baseVideo.category).to.equal(video.category)
-        expect(baseVideo.language).to.equal(video.language)
-        expect(baseVideo.licence).to.equal(video.licence)
-        expect(baseVideo.category).to.equal(video.category)
-        expect(baseVideo.nsfw).to.equal(video.nsfw)
-        expect(baseVideo.author).to.equal(video.account)
-        expect(baseVideo.tags).to.deep.equal(video.tags)
-      }
-    })
-
-    it('Should get the preview from each pod', async function () {
-      for (const server of servers) {
-        const res = await getVideo(server.url, videoUUID)
-        const video = res.body
-
-        const test = await testVideoImage(server.url, 'video_short1-preview.webm', video.previewPath)
-        expect(test).to.equal(true)
-      }
-    })
-  })
-
-  after(async function () {
-    killallServers(servers)
-
-    // Keep the logs if the test failed
-    if (this['ok']) {
-      await flushTests()
-    }
-  })
-})
diff --git a/server/tests/api/multiple-servers.ts b/server/tests/api/multiple-servers.ts
new file mode 100644 (file)
index 0000000..7377709
--- /dev/null
@@ -0,0 +1,722 @@
+/* tslint:disable:no-unused-expression */
+
+import 'mocha'
+import * as chai from 'chai'
+
+import {
+  dateIsValid,
+  flushAndRunMultipleServers,
+  flushTests,
+  getVideo,
+  getVideosList,
+  killallServers,
+  rateVideo,
+  removeVideo,
+  ServerInfo,
+  setAccessTokensToServers,
+  testVideoImage,
+  updateVideo,
+  uploadVideo,
+  wait,
+  webtorrentAdd,
+  addVideoChannel,
+  getVideoChannelsList,
+  getUserAccessToken,
+  doubleFollow
+} from '../utils'
+import { createUser } from '../utils/users'
+
+const expect = chai.expect
+
+describe('Test multiple servers', function () {
+  let servers: ServerInfo[] = []
+  const toRemove = []
+  let videoUUID = ''
+  let videoChannelId: number
+
+  before(async function () {
+    this.timeout(120000)
+
+    servers = await flushAndRunMultipleServers(3)
+
+    // Get the access tokens
+    await setAccessTokensToServers(servers)
+
+    const videoChannel = {
+      name: 'my channel',
+      description: 'super channel'
+    }
+    await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
+    const channelRes = await getVideoChannelsList(servers[0].url, 0, 1)
+    videoChannelId = channelRes.body.data[0].id
+
+    // Server 1 and server 2 follow each other
+    await doubleFollow(servers[0], servers[1])
+    // Server 1 and server 3 follow each other
+    await doubleFollow(servers[0], servers[2])
+    // Server 2 and server 3 follow each other
+    await doubleFollow(servers[1], servers[2])
+  })
+
+  it('Should not have videos for all servers', async function () {
+    for (const server of servers) {
+      const res = await getVideosList(server.url)
+      const videos = res.body.data
+      expect(videos).to.be.an('array')
+      expect(videos.length).to.equal(0)
+    }
+  })
+
+  describe('Should upload the video and propagate on each server', function () {
+    it('Should upload the video on server 1 and propagate on each server', async function () {
+      // Server 1 has video transcoding activated
+      this.timeout(15000)
+
+      const videoAttributes = {
+        name: 'my super name for server 1',
+        category: 5,
+        licence: 4,
+        language: 9,
+        nsfw: true,
+        description: 'my super description for server 1',
+        tags: [ 'tag1p1', 'tag2p1' ],
+        channelId: videoChannelId,
+        fixture: 'video_short1.webm'
+      }
+      await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
+
+      await wait(11000)
+
+      // All servers should have this video
+      for (const server of servers) {
+        let baseMagnet = null
+
+        const res = await getVideosList(server.url)
+
+        const videos = res.body.data
+        expect(videos).to.be.an('array')
+        expect(videos.length).to.equal(1)
+        const video = videos[0]
+        expect(video.name).to.equal('my super name for server 1')
+        expect(video.category).to.equal(5)
+        expect(video.categoryLabel).to.equal('Sports')
+        expect(video.licence).to.equal(4)
+        expect(video.licenceLabel).to.equal('Attribution - Non Commercial')
+        expect(video.language).to.equal(9)
+        expect(video.languageLabel).to.equal('Japanese')
+        expect(video.nsfw).to.be.ok
+        expect(video.description).to.equal('my super description for server 1')
+        expect(video.serverHost).to.equal('localhost:9001')
+        expect(video.duration).to.equal(10)
+        expect(video.tags).to.deep.equal([ 'tag1p1', 'tag2p1' ])
+        expect(dateIsValid(video.createdAt)).to.be.true
+        expect(dateIsValid(video.updatedAt)).to.be.true
+        expect(video.account).to.equal('root')
+
+        const res2 = await getVideo(server.url, video.uuid)
+        const videoDetails = res2.body
+
+        expect(videoDetails.channel.name).to.equal('my channel')
+        expect(videoDetails.channel.description).to.equal('super channel')
+        expect(dateIsValid(videoDetails.channel.createdAt)).to.be.true
+        expect(dateIsValid(videoDetails.channel.updatedAt)).to.be.true
+        expect(videoDetails.files).to.have.lengthOf(1)
+
+        const file = videoDetails.files[0]
+        const magnetUri = file.magnetUri
+        expect(file.magnetUri).to.have.lengthOf.above(2)
+        expect(file.torrentUrl).to
+          .equal(`http://${videoDetails.serverHost}/static/torrents/${videoDetails.uuid}-${file.resolution}.torrent`)
+        expect(file.fileUrl).to.equal(`http://${videoDetails.serverHost}/static/webseed/${videoDetails.uuid}-${file.resolution}.webm`)
+        expect(file.resolution).to.equal(720)
+        expect(file.resolutionLabel).to.equal('720p')
+        expect(file.size).to.equal(572456)
+
+        if (server.url !== 'http://localhost:9001') {
+          expect(video.isLocal).to.be.false
+          expect(videoDetails.channel.isLocal).to.be.false
+        } else {
+          expect(video.isLocal).to.be.true
+          expect(videoDetails.channel.isLocal).to.be.true
+        }
+
+        // All servers should have the same magnet Uri
+        if (baseMagnet === null) {
+          baseMagnet = magnetUri
+        } else {
+          expect(baseMagnet).to.equal(magnetUri)
+        }
+
+        const test = await testVideoImage(server.url, 'video_short1.webm', video.thumbnailPath)
+        expect(test).to.equal(true)
+      }
+    })
+
+    it('Should upload the video on server 2 and propagate on each server', async function () {
+      this.timeout(120000)
+
+      const user = {
+        username: 'user1',
+        password: 'super_password'
+      }
+      await createUser(servers[1].url, servers[1].accessToken, user.username, user.password)
+      const userAccessToken = await getUserAccessToken(servers[1], user)
+
+      const videoAttributes = {
+        name: 'my super name for server 2',
+        category: 4,
+        licence: 3,
+        language: 11,
+        nsfw: true,
+        description: 'my super description for server 2',
+        tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
+        fixture: 'video_short2.webm'
+      }
+      await uploadVideo(servers[1].url, userAccessToken, videoAttributes)
+
+      // Transcoding, so wait more than 22000
+      await wait(60000)
+
+      // All servers should have this video
+      for (const server of servers) {
+        let baseMagnet = {}
+
+        const res = await getVideosList(server.url)
+
+        const videos = res.body.data
+        expect(videos).to.be.an('array')
+        expect(videos.length).to.equal(2)
+        const video = videos[1]
+        expect(video.name).to.equal('my super name for server 2')
+        expect(video.category).to.equal(4)
+        expect(video.categoryLabel).to.equal('Art')
+        expect(video.licence).to.equal(3)
+        expect(video.licenceLabel).to.equal('Attribution - No Derivatives')
+        expect(video.language).to.equal(11)
+        expect(video.languageLabel).to.equal('German')
+        expect(video.nsfw).to.be.true
+        expect(video.description).to.equal('my super description for server 2')
+        expect(video.serverHost).to.equal('localhost:9002')
+        expect(video.duration).to.equal(5)
+        expect(video.tags).to.deep.equal([ 'tag1p2', 'tag2p2', 'tag3p2' ])
+        expect(dateIsValid(video.createdAt)).to.be.true
+        expect(dateIsValid(video.updatedAt)).to.be.true
+        expect(video.account).to.equal('user1')
+
+        if (server.url !== 'http://localhost:9002') {
+          expect(video.isLocal).to.be.false
+        } else {
+          expect(video.isLocal).to.be.true
+        }
+
+        const res2 = await getVideo(server.url, video.uuid)
+        const videoDetails = res2.body
+
+        expect(videoDetails.channel.name).to.equal('Default user1 channel')
+        expect(dateIsValid(videoDetails.channel.createdAt)).to.be.true
+        expect(dateIsValid(videoDetails.channel.updatedAt)).to.be.true
+
+        expect(videoDetails.files).to.have.lengthOf(4)
+
+        // Check common attributes
+        for (const file of videoDetails.files) {
+          expect(file.magnetUri).to.have.lengthOf.above(2)
+
+          // All servers should have the same magnet Uri
+          if (baseMagnet[file.resolution] === undefined) {
+            baseMagnet[file.resolution] = file.magnet
+          } else {
+            expect(baseMagnet[file.resolution]).to.equal(file.magnet)
+          }
+        }
+
+        const file240p = videoDetails.files.find(f => f.resolution === 240)
+        expect(file240p).not.to.be.undefined
+        expect(file240p.resolutionLabel).to.equal('240p')
+        expect(file240p.size).to.be.above(180000).and.below(200000)
+
+        const file360p = videoDetails.files.find(f => f.resolution === 360)
+        expect(file360p).not.to.be.undefined
+        expect(file360p.resolutionLabel).to.equal('360p')
+        expect(file360p.size).to.be.above(270000).and.below(290000)
+
+        const file480p = videoDetails.files.find(f => f.resolution === 480)
+        expect(file480p).not.to.be.undefined
+        expect(file480p.resolutionLabel).to.equal('480p')
+        expect(file480p.size).to.be.above(380000).and.below(400000)
+
+        const file720p = videoDetails.files.find(f => f.resolution === 720)
+        expect(file720p).not.to.be.undefined
+        expect(file720p.resolutionLabel).to.equal('720p')
+        expect(file720p.size).to.be.above(700000).and.below(7200000)
+
+        const test = await testVideoImage(server.url, 'video_short2.webm', videoDetails.thumbnailPath)
+        expect(test).to.equal(true)
+      }
+    })
+
+    it('Should upload two videos on server 3 and propagate on each server', async function () {
+      this.timeout(45000)
+
+      const videoAttributes1 = {
+        name: 'my super name for server 3',
+        category: 6,
+        licence: 5,
+        language: 11,
+        nsfw: true,
+        description: 'my super description for server 3',
+        tags: [ 'tag1p3' ],
+        fixture: 'video_short3.webm'
+      }
+      await uploadVideo(servers[2].url, servers[2].accessToken, videoAttributes1)
+
+      const videoAttributes2 = {
+        name: 'my super name for server 3-2',
+        category: 7,
+        licence: 6,
+        language: 12,
+        nsfw: false,
+        description: 'my super description for server 3-2',
+        tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
+        fixture: 'video_short.webm'
+      }
+      await uploadVideo(servers[2].url, servers[2].accessToken, videoAttributes2)
+
+      await wait(33000)
+
+      let baseMagnet = null
+      // All servers should have this video
+      for (const server of servers) {
+        const res = await getVideosList(server.url)
+
+        const videos = res.body.data
+        expect(videos).to.be.an('array')
+        expect(videos.length).to.equal(4)
+
+        // We not sure about the order of the two last uploads
+        let video1 = null
+        let video2 = null
+        if (videos[2].name === 'my super name for server 3') {
+          video1 = videos[2]
+          video2 = videos[3]
+        } else {
+          video1 = videos[3]
+          video2 = videos[2]
+        }
+
+        expect(video1.name).to.equal('my super name for server 3')
+        expect(video1.category).to.equal(6)
+        expect(video1.categoryLabel).to.equal('Travels')
+        expect(video1.licence).to.equal(5)
+        expect(video1.licenceLabel).to.equal('Attribution - Non Commercial - Share Alike')
+        expect(video1.language).to.equal(11)
+        expect(video1.languageLabel).to.equal('German')
+        expect(video1.nsfw).to.be.ok
+        expect(video1.description).to.equal('my super description for server 3')
+        expect(video1.serverHost).to.equal('localhost:9003')
+        expect(video1.duration).to.equal(5)
+        expect(video1.tags).to.deep.equal([ 'tag1p3' ])
+        expect(video1.author).to.equal('root')
+        expect(dateIsValid(video1.createdAt)).to.be.true
+        expect(dateIsValid(video1.updatedAt)).to.be.true
+
+        const res2 = await getVideo(server.url, video1.id)
+        const video1Details = res2.body
+        expect(video1Details.files).to.have.lengthOf(1)
+
+        const file1 = video1Details.files[0]
+        expect(file1.magnetUri).to.have.lengthOf.above(2)
+        expect(file1.resolution).to.equal(720)
+        expect(file1.resolutionLabel).to.equal('720p')
+        expect(file1.size).to.equal(292677)
+
+        expect(video2.name).to.equal('my super name for server 3-2')
+        expect(video2.category).to.equal(7)
+        expect(video2.categoryLabel).to.equal('Gaming')
+        expect(video2.licence).to.equal(6)
+        expect(video2.licenceLabel).to.equal('Attribution - Non Commercial - No Derivatives')
+        expect(video2.language).to.equal(12)
+        expect(video2.languageLabel).to.equal('Korean')
+        expect(video2.nsfw).to.be.false
+        expect(video2.description).to.equal('my super description for server 3-2')
+        expect(video2.serverHost).to.equal('localhost:9003')
+        expect(video2.duration).to.equal(5)
+        expect(video2.tags).to.deep.equal([ 'tag2p3', 'tag3p3', 'tag4p3' ])
+        expect(video2.author).to.equal('root')
+        expect(dateIsValid(video2.createdAt)).to.be.true
+        expect(dateIsValid(video2.updatedAt)).to.be.true
+
+        const res3 = await getVideo(server.url, video2.id)
+        const video2Details = res3.body
+
+        expect(video2Details.files).to.have.lengthOf(1)
+
+        const file2 = video2Details.files[0]
+        const magnetUri2 = file2.magnetUri
+        expect(file2.magnetUri).to.have.lengthOf.above(2)
+        expect(file2.resolution).to.equal(720)
+        expect(file2.resolutionLabel).to.equal('720p')
+        expect(file2.size).to.equal(218910)
+
+        if (server.url !== 'http://localhost:9003') {
+          expect(video1.isLocal).to.be.false
+          expect(video2.isLocal).to.be.false
+        } else {
+          expect(video1.isLocal).to.be.true
+          expect(video2.isLocal).to.be.true
+        }
+
+        // All servers should have the same magnet Uri
+        if (baseMagnet === null) {
+          baseMagnet = magnetUri2
+        } else {
+          expect(baseMagnet).to.equal(magnetUri2)
+        }
+
+        const test1 = await testVideoImage(server.url, 'video_short3.webm', video1.thumbnailPath)
+        expect(test1).to.equal(true)
+
+        const test2 = await testVideoImage(server.url, 'video_short.webm', video2.thumbnailPath)
+        expect(test2).to.equal(true)
+      }
+    })
+  })
+
+  describe('Should seed the uploaded video', function () {
+    it('Should add the file 1 by asking server 3', async function () {
+      // Yes, this could be long
+      this.timeout(200000)
+
+      const res = await getVideosList(servers[2].url)
+
+      const video = res.body.data[0]
+      toRemove.push(res.body.data[2])
+      toRemove.push(res.body.data[3])
+
+      const res2 = await getVideo(servers[2].url, video.id)
+      const videoDetails = res2.body
+
+      const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri)
+      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('')
+    })
+
+    it('Should add the file 2 by asking server 1', async function () {
+      // Yes, this could be long
+      this.timeout(200000)
+
+      const res = await getVideosList(servers[0].url)
+
+      const video = res.body.data[1]
+      const res2 = await getVideo(servers[0].url, video.id)
+      const videoDetails = res2.body
+
+      const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri)
+      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('')
+    })
+
+    it('Should add the file 3 by asking server 2', async function () {
+      // Yes, this could be long
+      this.timeout(200000)
+
+      const res = await getVideosList(servers[1].url)
+
+      const video = res.body.data[2]
+      const res2 = await getVideo(servers[1].url, video.id)
+      const videoDetails = res2.body
+
+      const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri)
+      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('')
+    })
+
+    it('Should add the file 3-2 by asking server 1', async function () {
+      // Yes, this could be long
+      this.timeout(200000)
+
+      const res = await getVideosList(servers[0].url)
+
+      const video = res.body.data[3]
+      const res2 = await getVideo(servers[0].url, video.id)
+      const videoDetails = res2.body
+
+      const torrent = await webtorrentAdd(videoDetails.files[0].magnetUri)
+      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('')
+    })
+
+    it('Should add the file 2 in 360p by asking server 1', async function () {
+      // Yes, this could be long
+      this.timeout(200000)
+
+      const res = await getVideosList(servers[0].url)
+
+      const video = res.body.data.find(v => v.name === 'my super name for server 2')
+      const res2 = await getVideo(servers[0].url, video.id)
+      const videoDetails = res2.body
+
+      const file = videoDetails.files.find(f => f.resolution === 360)
+      expect(file).not.to.be.undefined
+
+      const torrent = await webtorrentAdd(file.magnetUri)
+      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('')
+    })
+  })
+
+  describe('Should update video views, likes and dislikes', function () {
+    let localVideosServer3 = []
+    let remoteVideosServer1 = []
+    let remoteVideosServer2 = []
+    let remoteVideosServer3 = []
+
+    before(async function () {
+      const res1 = await getVideosList(servers[0].url)
+      remoteVideosServer1 = res1.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
+
+      const res2 = await getVideosList(servers[1].url)
+      remoteVideosServer2 = res2.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
+
+      const res3 = await getVideosList(servers[2].url)
+      localVideosServer3 = res3.body.data.filter(video => video.isLocal === true).map(video => video.uuid)
+      remoteVideosServer3 = res3.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
+    })
+
+    it('Should view multiple videos on owned servers', async function () {
+      this.timeout(30000)
+
+      const tasks: Promise<any>[] = []
+      tasks.push(getVideo(servers[2].url, localVideosServer3[0]))
+      tasks.push(getVideo(servers[2].url, localVideosServer3[0]))
+      tasks.push(getVideo(servers[2].url, localVideosServer3[0]))
+      tasks.push(getVideo(servers[2].url, localVideosServer3[1]))
+
+      await Promise.all(tasks)
+
+      await wait(22000)
+
+      for (const server of servers) {
+        const res = await getVideosList(server.url)
+
+        const videos = res.body.data
+        const video0 = videos.find(v => v.uuid === localVideosServer3[0])
+        const video1 = videos.find(v => v.uuid === localVideosServer3[1])
+
+        expect(video0.views).to.equal(7)
+        expect(video1.views).to.equal(5)
+      }
+    })
+
+    it('Should view multiple videos on each servers', async function () {
+      this.timeout(30000)
+
+      const tasks: Promise<any>[] = []
+      tasks.push(getVideo(servers[0].url, remoteVideosServer1[0]))
+      tasks.push(getVideo(servers[1].url, remoteVideosServer2[0]))
+      tasks.push(getVideo(servers[1].url, remoteVideosServer2[0]))
+      tasks.push(getVideo(servers[2].url, remoteVideosServer3[0]))
+      tasks.push(getVideo(servers[2].url, remoteVideosServer3[1]))
+      tasks.push(getVideo(servers[2].url, remoteVideosServer3[1]))
+      tasks.push(getVideo(servers[2].url, remoteVideosServer3[1]))
+      tasks.push(getVideo(servers[2].url, localVideosServer3[1]))
+      tasks.push(getVideo(servers[2].url, localVideosServer3[1]))
+      tasks.push(getVideo(servers[2].url, localVideosServer3[1]))
+
+      await Promise.all(tasks)
+
+      await wait(22000)
+
+      let baseVideos = null
+
+      for (const server of servers) {
+        const res = await getVideosList(server.url)
+
+        const videos = res.body.data
+
+        // Initialize base videos for future comparisons
+        if (baseVideos === null) {
+          baseVideos = videos
+          return
+        }
+
+        for (const baseVideo of baseVideos) {
+          const sameVideo = videos.find(video => video.name === baseVideo.name)
+          expect(baseVideo.views).to.equal(sameVideo.views)
+        }
+      }
+    })
+
+    it('Should like and dislikes videos on different services', async function () {
+      this.timeout(30000)
+
+      const tasks: Promise<any>[] = []
+      tasks.push(rateVideo(servers[0].url, servers[0].accessToken, remoteVideosServer1[0], 'like'))
+      tasks.push(rateVideo(servers[0].url, servers[0].accessToken, remoteVideosServer1[0], 'dislike'))
+      tasks.push(rateVideo(servers[0].url, servers[0].accessToken, remoteVideosServer1[0], 'like'))
+      tasks.push(rateVideo(servers[2].url, servers[2].accessToken, localVideosServer3[1], 'like'))
+      tasks.push(rateVideo(servers[2].url, servers[2].accessToken, localVideosServer3[1], 'dislike'))
+      tasks.push(rateVideo(servers[2].url, servers[2].accessToken, remoteVideosServer3[1], 'dislike'))
+      tasks.push(rateVideo(servers[2].url, servers[2].accessToken, remoteVideosServer3[0], 'like'))
+
+      await Promise.all(tasks)
+
+      await wait(22000)
+
+      let baseVideos = null
+      for (const server of servers) {
+        const res = await getVideosList(server.url)
+
+        const videos = res.body.data
+
+        // Initialize base videos for future comparisons
+        if (baseVideos === null) {
+          baseVideos = videos
+          return
+        }
+
+        baseVideos.forEach(baseVideo => {
+          const sameVideo = videos.find(video => video.name === baseVideo.name)
+          expect(baseVideo.likes).to.equal(sameVideo.likes)
+          expect(baseVideo.dislikes).to.equal(sameVideo.dislikes)
+        })
+      }
+    })
+  })
+
+  describe('Should manipulate these videos', function () {
+    it('Should update the video 3 by asking server 3', async function () {
+      this.timeout(15000)
+
+      const attributes = {
+        name: 'my super video updated',
+        category: 10,
+        licence: 7,
+        language: 13,
+        nsfw: true,
+        description: 'my super description updated',
+        tags: [ 'tag_up_1', 'tag_up_2' ]
+      }
+
+      await updateVideo(servers[2].url, servers[2].accessToken, toRemove[0].id, attributes)
+
+      await wait(11000)
+    })
+
+    it('Should have the video 3 updated on each server', async function () {
+      this.timeout(200000)
+
+      for (const server of servers) {
+        const res = await getVideosList(server.url)
+
+        const videos = res.body.data
+        const videoUpdated = videos.find(video => video.name === 'my super video updated')
+
+        expect(!!videoUpdated).to.be.true
+        expect(videoUpdated.category).to.equal(10)
+        expect(videoUpdated.categoryLabel).to.equal('Entertainment')
+        expect(videoUpdated.licence).to.equal(7)
+        expect(videoUpdated.licenceLabel).to.equal('Public Domain Dedication')
+        expect(videoUpdated.language).to.equal(13)
+        expect(videoUpdated.languageLabel).to.equal('French')
+        expect(videoUpdated.nsfw).to.be.ok
+        expect(videoUpdated.description).to.equal('my super description updated')
+        expect(videoUpdated.tags).to.deep.equal([ 'tag_up_1', 'tag_up_2' ])
+        expect(dateIsValid(videoUpdated.updatedAt, 20000)).to.be.true
+
+        const res2 = await getVideo(server.url, videoUpdated.uuid)
+        const videoUpdatedDetails = res2.body
+
+        const file = videoUpdatedDetails .files[0]
+        expect(file.magnetUri).to.have.lengthOf.above(2)
+        expect(file.resolution).to.equal(720)
+        expect(file.resolutionLabel).to.equal('720p')
+        expect(file.size).to.equal(292677)
+
+        const test = await testVideoImage(server.url, 'video_short3.webm', videoUpdated.thumbnailPath)
+        expect(test).to.equal(true)
+
+        // Avoid "duplicate torrent" errors
+        const refreshWebTorrent = true
+        const torrent = await webtorrentAdd(videoUpdatedDetails .files[0].magnetUri, refreshWebTorrent)
+        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('')
+      }
+    })
+
+    it('Should remove the videos 3 and 3-2 by asking server 3', async function () {
+      this.timeout(15000)
+
+      await removeVideo(servers[2].url, servers[2].accessToken, toRemove[0].id)
+      await removeVideo(servers[2].url, servers[2].accessToken, toRemove[1].id)
+
+      await wait(11000)
+    })
+
+    it('Should have videos 1 and 3 on each server', async function () {
+      for (const server of servers) {
+        const res = await getVideosList(server.url)
+
+        const videos = res.body.data
+        expect(videos).to.be.an('array')
+        expect(videos.length).to.equal(2)
+        expect(videos[0].name).not.to.equal(videos[1].name)
+        expect(videos[0].name).not.to.equal(toRemove[0].name)
+        expect(videos[1].name).not.to.equal(toRemove[0].name)
+        expect(videos[0].name).not.to.equal(toRemove[1].name)
+        expect(videos[1].name).not.to.equal(toRemove[1].name)
+
+        videoUUID = videos.find(video => video.name === 'my super name for server 1').uuid
+      }
+    })
+
+    it('Should get the same video by UUID on each server', async function () {
+      let baseVideo = null
+      for (const server of servers) {
+        const res = await getVideo(server.url, videoUUID)
+
+        const video = res.body
+
+        if (baseVideo === null) {
+          baseVideo = video
+          return
+        }
+
+        expect(baseVideo.name).to.equal(video.name)
+        expect(baseVideo.uuid).to.equal(video.uuid)
+        expect(baseVideo.category).to.equal(video.category)
+        expect(baseVideo.language).to.equal(video.language)
+        expect(baseVideo.licence).to.equal(video.licence)
+        expect(baseVideo.category).to.equal(video.category)
+        expect(baseVideo.nsfw).to.equal(video.nsfw)
+        expect(baseVideo.author).to.equal(video.account)
+        expect(baseVideo.tags).to.deep.equal(video.tags)
+      }
+    })
+
+    it('Should get the preview from each server', async function () {
+      for (const server of servers) {
+        const res = await getVideo(server.url, videoUUID)
+        const video = res.body
+
+        const test = await testVideoImage(server.url, 'video_short1-preview.webm', video.previewPath)
+        expect(test).to.equal(true)
+      }
+    })
+  })
+
+  after(async function () {
+    killallServers(servers)
+
+    // Keep the logs if the test failed
+    if (this['ok']) {
+      await flushTests()
+    }
+  })
+})
index c34c51f66c5a52c0bb8f08f6ce7db6d8df56c5cd..3e6506de4fa13cb4a284fb2137228079f9f9db55 100644 (file)
@@ -14,7 +14,6 @@ import {
   getOEmbed
 } from '../utils'
 import { runServer } from '../utils/servers'
-import { Video } from '../../../client/src/app/videos/shared/video.model'
 
 describe('Test services', function () {
   let server: ServerInfo = null
diff --git a/server/tests/api/single-pod.ts b/server/tests/api/single-pod.ts
deleted file mode 100644 (file)
index 0a917f2..0000000
+++ /dev/null
@@ -1,694 +0,0 @@
-/* tslint:disable:no-unused-expression */
-
-import { keyBy } from 'lodash'
-import { join } from 'path'
-import 'mocha'
-import * as chai from 'chai'
-const expect = chai.expect
-
-import {
-  ServerInfo,
-  flushTests,
-  runServer,
-  uploadVideo,
-  getVideosList,
-  rateVideo,
-  removeVideo,
-  wait,
-  setAccessTokensToServers,
-  searchVideo,
-  killallServers,
-  dateIsValid,
-  getVideoCategories,
-  getVideoLicences,
-  getVideoLanguages,
-  getVideoPrivacies,
-  testVideoImage,
-  webtorrentAdd,
-  getVideo,
-  readdirPromise,
-  getVideosListPagination,
-  searchVideoWithPagination,
-  getVideosListSort,
-  searchVideoWithSort,
-  updateVideo
-} from '../utils'
-
-describe('Test a single pod', function () {
-  let server: ServerInfo = null
-  let videoId = -1
-  let videoUUID = ''
-  let videosListBase: any[] = null
-
-  before(async function () {
-    this.timeout(120000)
-
-    await flushTests()
-
-    server = await runServer(1)
-
-    await setAccessTokensToServers([ server ])
-  })
-
-  it('Should list video categories', async function () {
-    const res = await getVideoCategories(server.url)
-
-    const categories = res.body
-    expect(Object.keys(categories)).to.have.length.above(10)
-
-    expect(categories[11]).to.equal('News')
-  })
-
-  it('Should list video licences', async function () {
-    const res = await getVideoLicences(server.url)
-
-    const licences = res.body
-    expect(Object.keys(licences)).to.have.length.above(5)
-
-    expect(licences[3]).to.equal('Attribution - No Derivatives')
-  })
-
-  it('Should list video languages', async function () {
-    const res = await getVideoLanguages(server.url)
-
-    const languages = res.body
-    expect(Object.keys(languages)).to.have.length.above(5)
-
-    expect(languages[3]).to.equal('Mandarin')
-  })
-
-  it('Should list video privacies', async function () {
-    const res = await getVideoPrivacies(server.url)
-
-    const privacies = res.body
-    expect(Object.keys(privacies)).to.have.length.at.least(3)
-
-    expect(privacies[3]).to.equal('Private')
-  })
-
-  it('Should not have videos', async function () {
-    const res = await getVideosList(server.url)
-
-    expect(res.body.total).to.equal(0)
-    expect(res.body.data).to.be.an('array')
-    expect(res.body.data.length).to.equal(0)
-  })
-
-  it('Should upload the video', async function () {
-    const videoAttributes = {
-      name: 'my super name',
-      category: 2,
-      nsfw: true,
-      licence: 6,
-      tags: [ 'tag1', 'tag2', 'tag3' ]
-    }
-    await uploadVideo(server.url, server.accessToken, videoAttributes)
-  })
-
-  it('Should seed the uploaded video', async function () {
-    // Yes, this could be long
-    this.timeout(60000)
-
-    const res = await getVideosList(server.url)
-
-    expect(res.body.total).to.equal(1)
-    expect(res.body.data).to.be.an('array')
-    expect(res.body.data.length).to.equal(1)
-
-    const video = res.body.data[0]
-    expect(video.name).to.equal('my super name')
-    expect(video.category).to.equal(2)
-    expect(video.categoryLabel).to.equal('Films')
-    expect(video.licence).to.equal(6)
-    expect(video.licenceLabel).to.equal('Attribution - Non Commercial - No Derivatives')
-    expect(video.language).to.equal(3)
-    expect(video.languageLabel).to.equal('Mandarin')
-    expect(video.nsfw).to.be.ok
-    expect(video.description).to.equal('my super description')
-    expect(video.serverHost).to.equal('localhost:9001')
-    expect(video.account).to.equal('root')
-    expect(video.isLocal).to.be.true
-    expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
-    expect(dateIsValid(video.createdAt)).to.be.true
-    expect(dateIsValid(video.updatedAt)).to.be.true
-
-    const res2 = await getVideo(server.url, res.body.data[0].id)
-    const videoDetails = res2.body
-
-    expect(videoDetails.files).to.have.lengthOf(1)
-
-    const file = videoDetails.files[0]
-    const magnetUri = file.magnetUri
-    expect(file.magnetUri).to.have.lengthOf.above(2)
-    expect(file.torrentUrl).to.equal(`${server.url}/static/torrents/${videoDetails.uuid}-${file.resolution}.torrent`)
-    expect(file.fileUrl).to.equal(`${server.url}/static/webseed/${videoDetails.uuid}-${file.resolution}.webm`)
-    expect(file.resolution).to.equal(720)
-    expect(file.resolutionLabel).to.equal('720p')
-    expect(file.size).to.equal(218910)
-
-    const test = await testVideoImage(server.url, 'video_short.webm', videoDetails.thumbnailPath)
-    expect(test).to.equal(true)
-
-    videoId = videoDetails.id
-    videoUUID = videoDetails.uuid
-
-    const torrent = await webtorrentAdd(magnetUri)
-    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('')
-  })
-
-  it('Should get the video', async function () {
-    // Yes, this could be long
-    this.timeout(60000)
-
-    const res = await getVideo(server.url, videoId)
-
-    const video = res.body
-    expect(video.name).to.equal('my super name')
-    expect(video.category).to.equal(2)
-    expect(video.categoryLabel).to.equal('Films')
-    expect(video.licence).to.equal(6)
-    expect(video.licenceLabel).to.equal('Attribution - Non Commercial - No Derivatives')
-    expect(video.language).to.equal(3)
-    expect(video.languageLabel).to.equal('Mandarin')
-    expect(video.nsfw).to.be.ok
-    expect(video.description).to.equal('my super description')
-    expect(video.serverHost).to.equal('localhost:9001')
-    expect(video.account).to.equal('root')
-    expect(video.isLocal).to.be.true
-    expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
-    expect(dateIsValid(video.createdAt)).to.be.true
-    expect(dateIsValid(video.updatedAt)).to.be.true
-    expect(video.channel.name).to.equal('Default root channel')
-    expect(video.channel.isLocal).to.be.true
-    expect(dateIsValid(video.channel.createdAt)).to.be.true
-    expect(dateIsValid(video.channel.updatedAt)).to.be.true
-
-    expect(video.files).to.have.lengthOf(1)
-
-    const file = video.files[0]
-    expect(file.magnetUri).to.have.lengthOf.above(2)
-    expect(file.resolution).to.equal(720)
-    expect(file.resolutionLabel).to.equal('720p')
-    expect(file.size).to.equal(218910)
-
-    const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
-    expect(test).to.equal(true)
-
-    // Wait the async views increment
-    await wait(500)
-  })
-
-  it('Should get the video by UUID', async function () {
-    // Yes, this could be long
-    this.timeout(60000)
-
-    const res = await getVideo(server.url, videoUUID)
-
-    const video = res.body
-    expect(video.name).to.equal('my super name')
-
-    // Wait the async views increment
-    await wait(500)
-  })
-
-  it('Should have the views updated', async function () {
-    const res = await getVideo(server.url, videoId)
-
-    const video = res.body
-    expect(video.views).to.equal(3)
-  })
-
-  it('Should search the video by name by default', async function () {
-    const res = await searchVideo(server.url, 'my')
-
-    expect(res.body.total).to.equal(1)
-    expect(res.body.data).to.be.an('array')
-    expect(res.body.data.length).to.equal(1)
-
-    const video = res.body.data[0]
-    expect(video.name).to.equal('my super name')
-    expect(video.category).to.equal(2)
-    expect(video.categoryLabel).to.equal('Films')
-    expect(video.licence).to.equal(6)
-    expect(video.licenceLabel).to.equal('Attribution - Non Commercial - No Derivatives')
-    expect(video.language).to.equal(3)
-    expect(video.languageLabel).to.equal('Mandarin')
-    expect(video.nsfw).to.be.ok
-    expect(video.description).to.equal('my super description')
-    expect(video.serverHost).to.equal('localhost:9001')
-    expect(video.account).to.equal('root')
-    expect(video.isLocal).to.be.true
-    expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
-    expect(dateIsValid(video.createdAt)).to.be.true
-    expect(dateIsValid(video.updatedAt)).to.be.true
-
-    const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
-    expect(test).to.equal(true)
-  })
-
-  // Not implemented yet
-  // it('Should search the video by serverHost', async function () {
-  //     const res = await   videosUtils.searchVideo(server.url, '9001', 'host')
-
-  //     expect(res.body.total).to.equal(1)
-  //     expect(res.body.data).to.be.an('array')
-  //     expect(res.body.data.length).to.equal(1)
-
-  //     const video = res.body.data[0]
-  //     expect(video.name).to.equal('my super name')
-  //     expect(video.description).to.equal('my super description')
-  //     expect(video.serverHost).to.equal('localhost:9001')
-  //     expect(video.author).to.equal('root')
-  //     expect(video.isLocal).to.be.true
-  //     expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
-  //     expect(dateIsValid(video.createdAt)).to.be.true
-  //     expect(dateIsValid(video.updatedAt)).to.be.true
-
-  //     const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
-  //       expect(test).to.equal(true)
-
-  //       done()
-  //     })
-  //   })
-  // })
-
-  it('Should search the video by tag', async function () {
-    const res = await searchVideo(server.url, 'tag1', 'tags')
-
-    expect(res.body.total).to.equal(1)
-    expect(res.body.data).to.be.an('array')
-    expect(res.body.data.length).to.equal(1)
-
-    const video = res.body.data[0]
-    expect(video.name).to.equal('my super name')
-    expect(video.category).to.equal(2)
-    expect(video.categoryLabel).to.equal('Films')
-    expect(video.licence).to.equal(6)
-    expect(video.licenceLabel).to.equal('Attribution - Non Commercial - No Derivatives')
-    expect(video.language).to.equal(3)
-    expect(video.languageLabel).to.equal('Mandarin')
-    expect(video.nsfw).to.be.ok
-    expect(video.description).to.equal('my super description')
-    expect(video.serverHost).to.equal('localhost:9001')
-    expect(video.account).to.equal('root')
-    expect(video.isLocal).to.be.true
-    expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
-    expect(dateIsValid(video.createdAt)).to.be.true
-    expect(dateIsValid(video.updatedAt)).to.be.true
-
-    const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
-    expect(test).to.equal(true)
-  })
-
-  it('Should not find a search by name by default', async function () {
-    const res = await searchVideo(server.url, 'hello')
-
-    expect(res.body.total).to.equal(0)
-    expect(res.body.data).to.be.an('array')
-    expect(res.body.data.length).to.equal(0)
-  })
-
-  it('Should not find a search by author', async function () {
-    const res = await searchVideo(server.url, 'hello', 'account')
-
-    expect(res.body.total).to.equal(0)
-    expect(res.body.data).to.be.an('array')
-    expect(res.body.data.length).to.equal(0)
-  })
-
-  it('Should not find a search by tag', async function () {
-    const res = await searchVideo(server.url, 'hello', 'tags')
-
-    expect(res.body.total).to.equal(0)
-    expect(res.body.data).to.be.an('array')
-    expect(res.body.data.length).to.equal(0)
-  })
-
-  it('Should remove the video', async function () {
-    await removeVideo(server.url, server.accessToken, videoId)
-
-    const files1 = await readdirPromise(join(__dirname, '..', '..', '..', 'test1/videos/'))
-    expect(files1).to.have.lengthOf(0)
-
-    const files2 = await readdirPromise(join(__dirname, '..', '..', '..', 'test1/thumbnails/'))
-    expect(files2).to.have.lengthOf(0)
-  })
-
-  it('Should not have videos', async function () {
-    const res = await getVideosList(server.url)
-
-    expect(res.body.total).to.equal(0)
-    expect(res.body.data).to.be.an('array')
-    expect(res.body.data).to.have.lengthOf(0)
-  })
-
-  it('Should upload 6 videos', async function () {
-    this.timeout(25000)
-
-    const videos = [
-      'video_short.mp4', 'video_short.ogv', 'video_short.webm',
-      'video_short1.webm', 'video_short2.webm', 'video_short3.webm'
-    ]
-
-    // const tasks: Promise<any>[] = []
-    for (const video of videos) {
-      const videoAttributes = {
-        name: video + ' name',
-        description: video + ' description',
-        category: 2,
-        licence: 1,
-        language: 1,
-        nsfw: true,
-        tags: [ 'tag1', 'tag2', 'tag3' ],
-        fixture: video
-      }
-
-      const p = uploadVideo(server.url, server.accessToken, videoAttributes)
-      await p
-    }
-    // FIXME: concurrent uploads does not work :(
-    //   tasks.push(p)
-    // }
-    //
-    // await Promise.all(tasks)
-  })
-
-  it('Should have the correct durations', async function () {
-    const res = await getVideosList(server.url)
-
-    expect(res.body.total).to.equal(6)
-    const videos = res.body.data
-    expect(videos).to.be.an('array')
-    expect(videos).to.have.lengthOf(6)
-
-    const videosByName = keyBy<{ duration: number }>(videos, 'name')
-    expect(videosByName['video_short.mp4 name'].duration).to.equal(5)
-    expect(videosByName['video_short.ogv name'].duration).to.equal(5)
-    expect(videosByName['video_short.webm name'].duration).to.equal(5)
-    expect(videosByName['video_short1.webm name'].duration).to.equal(10)
-    expect(videosByName['video_short2.webm name'].duration).to.equal(5)
-    expect(videosByName['video_short3.webm name'].duration).to.equal(5)
-  })
-
-  it('Should have the correct thumbnails', async function () {
-    const res = await getVideosList(server.url)
-
-    const videos = res.body.data
-    // For the next test
-    videosListBase = videos
-
-    for (const video of videos) {
-      const videoName = video.name.replace(' name', '')
-      const test = await testVideoImage(server.url, videoName, video.thumbnailPath)
-
-      expect(test).to.equal(true)
-    }
-  })
-
-  it('Should list only the two first videos', async function () {
-    const res = await getVideosListPagination(server.url, 0, 2, 'name')
-
-    const videos = res.body.data
-    expect(res.body.total).to.equal(6)
-    expect(videos.length).to.equal(2)
-    expect(videos[0].name).to.equal(videosListBase[0].name)
-    expect(videos[1].name).to.equal(videosListBase[1].name)
-  })
-
-  it('Should list only the next three videos', async function () {
-    const res = await getVideosListPagination(server.url, 2, 3, 'name')
-
-    const videos = res.body.data
-    expect(res.body.total).to.equal(6)
-    expect(videos.length).to.equal(3)
-    expect(videos[0].name).to.equal(videosListBase[2].name)
-    expect(videos[1].name).to.equal(videosListBase[3].name)
-    expect(videos[2].name).to.equal(videosListBase[4].name)
-  })
-
-  it('Should list the last video', async function () {
-    const res = await getVideosListPagination(server.url, 5, 6, 'name')
-
-    const videos = res.body.data
-    expect(res.body.total).to.equal(6)
-    expect(videos.length).to.equal(1)
-    expect(videos[0].name).to.equal(videosListBase[5].name)
-  })
-
-  it('Should search the first video', async function () {
-    const res = await searchVideoWithPagination(server.url, 'webm', 'name', 0, 1, 'name')
-
-    const videos = res.body.data
-    expect(res.body.total).to.equal(4)
-    expect(videos.length).to.equal(1)
-    expect(videos[0].name).to.equal('video_short1.webm name')
-  })
-
-  it('Should search the last two videos', async function () {
-    const res = await searchVideoWithPagination(server.url, 'webm', 'name', 2, 2, 'name')
-
-    const videos = res.body.data
-    expect(res.body.total).to.equal(4)
-    expect(videos.length).to.equal(2)
-    expect(videos[0].name).to.equal('video_short3.webm name')
-    expect(videos[1].name).to.equal('video_short.webm name')
-  })
-
-  it('Should search all the webm videos', async function () {
-    const res = await searchVideoWithPagination(server.url, 'webm', 'name', 0, 15)
-
-    const videos = res.body.data
-    expect(res.body.total).to.equal(4)
-    expect(videos.length).to.equal(4)
-  })
-
-  it('Should search all the root author videos', async function () {
-    const res = await searchVideoWithPagination(server.url, 'root', 'account', 0, 15)
-
-    const videos = res.body.data
-    expect(res.body.total).to.equal(6)
-    expect(videos.length).to.equal(6)
-  })
-
-  // Not implemented yet
-  // it('Should search all the 9001 port videos', async function () {
-  // const res = await   videosUtils.searchVideoWithPagination(server.url, '9001', 'host', 0, 15)
-
-  //     const videos = res.body.data
-  //     expect(res.body.total).to.equal(6)
-  //     expect(videos.length).to.equal(6)
-
-  //     done()
-  //   })
-  // })
-
-  // it('Should search all the localhost videos', async function () {
-  // const res = await   videosUtils.searchVideoWithPagination(server.url, 'localhost', 'host', 0, 15)
-
-  //     const videos = res.body.data
-  //     expect(res.body.total).to.equal(6)
-  //     expect(videos.length).to.equal(6)
-
-  //     done()
-  //   })
-  // })
-
-  it('Should list and sort by name in descending order', async function () {
-    const res = await getVideosListSort(server.url, '-name')
-
-    const videos = res.body.data
-    expect(res.body.total).to.equal(6)
-    expect(videos.length).to.equal(6)
-    expect(videos[0].name).to.equal('video_short.webm name')
-    expect(videos[1].name).to.equal('video_short.ogv name')
-    expect(videos[2].name).to.equal('video_short.mp4 name')
-    expect(videos[3].name).to.equal('video_short3.webm name')
-    expect(videos[4].name).to.equal('video_short2.webm name')
-    expect(videos[5].name).to.equal('video_short1.webm name')
-  })
-
-  it('Should search and sort by name in ascending order', async function () {
-    const res = await searchVideoWithSort(server.url, 'webm', 'name')
-
-    const videos = res.body.data
-    expect(res.body.total).to.equal(4)
-    expect(videos.length).to.equal(4)
-
-    expect(videos[0].name).to.equal('video_short1.webm name')
-    expect(videos[1].name).to.equal('video_short2.webm name')
-    expect(videos[2].name).to.equal('video_short3.webm name')
-    expect(videos[3].name).to.equal('video_short.webm name')
-
-    videoId = videos[2].id
-  })
-
-  it('Should update a video', async function () {
-    const attributes = {
-      name: 'my super video updated',
-      category: 4,
-      licence: 2,
-      language: 5,
-      nsfw: false,
-      description: 'my super description updated',
-      tags: [ 'tagup1', 'tagup2' ]
-    }
-    await updateVideo(server.url, server.accessToken, videoId, attributes)
-  })
-
-  it('Should have the video updated', async function () {
-    this.timeout(60000)
-
-    const res = await getVideo(server.url, videoId)
-
-    const video = res.body
-
-    expect(video.name).to.equal('my super video updated')
-    expect(video.category).to.equal(4)
-    expect(video.categoryLabel).to.equal('Art')
-    expect(video.licence).to.equal(2)
-    expect(video.licenceLabel).to.equal('Attribution - Share Alike')
-    expect(video.language).to.equal(5)
-    expect(video.languageLabel).to.equal('Arabic')
-    expect(video.nsfw).to.be.ok
-    expect(video.description).to.equal('my super description updated')
-    expect(video.serverHost).to.equal('localhost:9001')
-    expect(video.account).to.equal('root')
-    expect(video.isLocal).to.be.true
-    expect(video.tags).to.deep.equal([ 'tagup1', 'tagup2' ])
-    expect(dateIsValid(video.createdAt)).to.be.true
-    expect(dateIsValid(video.updatedAt)).to.be.true
-
-    expect(video.channel.name).to.equal('Default root channel')
-    expect(video.channel.isLocal).to.be.true
-    expect(dateIsValid(video.channel.createdAt)).to.be.true
-    expect(dateIsValid(video.channel.updatedAt)).to.be.true
-
-    expect(video.files).to.have.lengthOf(1)
-
-    const file = video.files[0]
-    const magnetUri = file.magnetUri
-    expect(file.magnetUri).to.have.lengthOf.above(2)
-    expect(file.resolution).to.equal(720)
-    expect(file.resolutionLabel).to.equal('720p')
-    expect(file.size).to.equal(292677)
-
-    const test = await testVideoImage(server.url, 'video_short3.webm', video.thumbnailPath)
-    expect(test).to.equal(true)
-
-    const torrent = await webtorrentAdd(magnetUri)
-    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('')
-  })
-
-  it('Should update only the tags of a video', async function () {
-    const attributes = {
-      tags: [ 'tag1', 'tag2', 'supertag' ]
-    }
-
-    await updateVideo(server.url, server.accessToken, videoId, attributes)
-
-    const res = await getVideo(server.url, videoId)
-    const video = res.body
-
-    expect(video.name).to.equal('my super video updated')
-    expect(video.category).to.equal(4)
-    expect(video.categoryLabel).to.equal('Art')
-    expect(video.licence).to.equal(2)
-    expect(video.licenceLabel).to.equal('Attribution - Share Alike')
-    expect(video.language).to.equal(5)
-    expect(video.languageLabel).to.equal('Arabic')
-    expect(video.nsfw).to.be.ok
-    expect(video.description).to.equal('my super description updated')
-    expect(video.serverHost).to.equal('localhost:9001')
-    expect(video.account).to.equal('root')
-    expect(video.isLocal).to.be.true
-    expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'supertag' ])
-    expect(dateIsValid(video.createdAt)).to.be.true
-    expect(dateIsValid(video.updatedAt)).to.be.true
-
-    expect(video.channel.name).to.equal('Default root channel')
-    expect(video.channel.isLocal).to.be.true
-    expect(dateIsValid(video.channel.createdAt)).to.be.true
-    expect(dateIsValid(video.channel.updatedAt)).to.be.true
-
-    expect(video.files).to.have.lengthOf(1)
-
-    const file = video.files[0]
-    expect(file.magnetUri).to.have.lengthOf.above(2)
-    expect(file.resolution).to.equal(720)
-    expect(file.resolutionLabel).to.equal('720p')
-    expect(file.size).to.equal(292677)
-  })
-
-  it('Should update only the description of a video', async function () {
-    const attributes = {
-      description: 'hello everybody'
-    }
-
-    await updateVideo(server.url, server.accessToken, videoId, attributes)
-
-    const res = await getVideo(server.url, videoId)
-    const video = res.body
-
-    expect(video.name).to.equal('my super video updated')
-    expect(video.category).to.equal(4)
-    expect(video.categoryLabel).to.equal('Art')
-    expect(video.licence).to.equal(2)
-    expect(video.licenceLabel).to.equal('Attribution - Share Alike')
-    expect(video.language).to.equal(5)
-    expect(video.languageLabel).to.equal('Arabic')
-    expect(video.nsfw).to.be.ok
-    expect(video.description).to.equal('hello everybody')
-    expect(video.serverHost).to.equal('localhost:9001')
-    expect(video.account).to.equal('root')
-    expect(video.isLocal).to.be.true
-    expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'supertag' ])
-    expect(dateIsValid(video.createdAt)).to.be.true
-    expect(dateIsValid(video.updatedAt)).to.be.true
-
-    expect(video.channel.name).to.equal('Default root channel')
-    expect(video.channel.isLocal).to.be.true
-    expect(dateIsValid(video.channel.createdAt)).to.be.true
-    expect(dateIsValid(video.channel.updatedAt)).to.be.true
-
-    expect(video.files).to.have.lengthOf(1)
-
-    const file = video.files[0]
-    expect(file.magnetUri).to.have.lengthOf.above(2)
-    expect(file.resolution).to.equal(720)
-    expect(file.resolutionLabel).to.equal('720p')
-    expect(file.size).to.equal(292677)
-  })
-
-  it('Should like a video', async function () {
-    await rateVideo(server.url, server.accessToken, videoId, 'like')
-
-    const res = await getVideo(server.url, videoId)
-    const video = res.body
-
-    expect(video.likes).to.equal(1)
-    expect(video.dislikes).to.equal(0)
-  })
-
-  it('Should dislike the same video', async function () {
-    await rateVideo(server.url, server.accessToken, videoId, 'dislike')
-
-    const res = await getVideo(server.url, videoId)
-    const video = res.body
-
-    expect(video.likes).to.equal(0)
-    expect(video.dislikes).to.equal(1)
-  })
-
-  after(async function () {
-    killallServers([ server ])
-
-    // Keep the logs if the test failed
-    if (this['ok']) {
-      await flushTests()
-    }
-  })
-})
diff --git a/server/tests/api/single-server.ts b/server/tests/api/single-server.ts
new file mode 100644 (file)
index 0000000..82ecc68
--- /dev/null
@@ -0,0 +1,694 @@
+/* tslint:disable:no-unused-expression */
+
+import { keyBy } from 'lodash'
+import { join } from 'path'
+import 'mocha'
+import * as chai from 'chai'
+const expect = chai.expect
+
+import {
+  ServerInfo,
+  flushTests,
+  runServer,
+  uploadVideo,
+  getVideosList,
+  rateVideo,
+  removeVideo,
+  wait,
+  setAccessTokensToServers,
+  searchVideo,
+  killallServers,
+  dateIsValid,
+  getVideoCategories,
+  getVideoLicences,
+  getVideoLanguages,
+  getVideoPrivacies,
+  testVideoImage,
+  webtorrentAdd,
+  getVideo,
+  readdirPromise,
+  getVideosListPagination,
+  searchVideoWithPagination,
+  getVideosListSort,
+  searchVideoWithSort,
+  updateVideo
+} from '../utils'
+
+describe('Test a single server', function () {
+  let server: ServerInfo = null
+  let videoId = -1
+  let videoUUID = ''
+  let videosListBase: any[] = null
+
+  before(async function () {
+    this.timeout(120000)
+
+    await flushTests()
+
+    server = await runServer(1)
+
+    await setAccessTokensToServers([ server ])
+  })
+
+  it('Should list video categories', async function () {
+    const res = await getVideoCategories(server.url)
+
+    const categories = res.body
+    expect(Object.keys(categories)).to.have.length.above(10)
+
+    expect(categories[11]).to.equal('News')
+  })
+
+  it('Should list video licences', async function () {
+    const res = await getVideoLicences(server.url)
+
+    const licences = res.body
+    expect(Object.keys(licences)).to.have.length.above(5)
+
+    expect(licences[3]).to.equal('Attribution - No Derivatives')
+  })
+
+  it('Should list video languages', async function () {
+    const res = await getVideoLanguages(server.url)
+
+    const languages = res.body
+    expect(Object.keys(languages)).to.have.length.above(5)
+
+    expect(languages[3]).to.equal('Mandarin')
+  })
+
+  it('Should list video privacies', async function () {
+    const res = await getVideoPrivacies(server.url)
+
+    const privacies = res.body
+    expect(Object.keys(privacies)).to.have.length.at.least(3)
+
+    expect(privacies[3]).to.equal('Private')
+  })
+
+  it('Should not have videos', async function () {
+    const res = await getVideosList(server.url)
+
+    expect(res.body.total).to.equal(0)
+    expect(res.body.data).to.be.an('array')
+    expect(res.body.data.length).to.equal(0)
+  })
+
+  it('Should upload the video', async function () {
+    const videoAttributes = {
+      name: 'my super name',
+      category: 2,
+      nsfw: true,
+      licence: 6,
+      tags: [ 'tag1', 'tag2', 'tag3' ]
+    }
+    await uploadVideo(server.url, server.accessToken, videoAttributes)
+  })
+
+  it('Should seed the uploaded video', async function () {
+    // Yes, this could be long
+    this.timeout(60000)
+
+    const res = await getVideosList(server.url)
+
+    expect(res.body.total).to.equal(1)
+    expect(res.body.data).to.be.an('array')
+    expect(res.body.data.length).to.equal(1)
+
+    const video = res.body.data[0]
+    expect(video.name).to.equal('my super name')
+    expect(video.category).to.equal(2)
+    expect(video.categoryLabel).to.equal('Films')
+    expect(video.licence).to.equal(6)
+    expect(video.licenceLabel).to.equal('Attribution - Non Commercial - No Derivatives')
+    expect(video.language).to.equal(3)
+    expect(video.languageLabel).to.equal('Mandarin')
+    expect(video.nsfw).to.be.ok
+    expect(video.description).to.equal('my super description')
+    expect(video.serverHost).to.equal('localhost:9001')
+    expect(video.account).to.equal('root')
+    expect(video.isLocal).to.be.true
+    expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
+    expect(dateIsValid(video.createdAt)).to.be.true
+    expect(dateIsValid(video.updatedAt)).to.be.true
+
+    const res2 = await getVideo(server.url, res.body.data[0].id)
+    const videoDetails = res2.body
+
+    expect(videoDetails.files).to.have.lengthOf(1)
+
+    const file = videoDetails.files[0]
+    const magnetUri = file.magnetUri
+    expect(file.magnetUri).to.have.lengthOf.above(2)
+    expect(file.torrentUrl).to.equal(`${server.url}/static/torrents/${videoDetails.uuid}-${file.resolution}.torrent`)
+    expect(file.fileUrl).to.equal(`${server.url}/static/webseed/${videoDetails.uuid}-${file.resolution}.webm`)
+    expect(file.resolution).to.equal(720)
+    expect(file.resolutionLabel).to.equal('720p')
+    expect(file.size).to.equal(218910)
+
+    const test = await testVideoImage(server.url, 'video_short.webm', videoDetails.thumbnailPath)
+    expect(test).to.equal(true)
+
+    videoId = videoDetails.id
+    videoUUID = videoDetails.uuid
+
+    const torrent = await webtorrentAdd(magnetUri)
+    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('')
+  })
+
+  it('Should get the video', async function () {
+    // Yes, this could be long
+    this.timeout(60000)
+
+    const res = await getVideo(server.url, videoId)
+
+    const video = res.body
+    expect(video.name).to.equal('my super name')
+    expect(video.category).to.equal(2)
+    expect(video.categoryLabel).to.equal('Films')
+    expect(video.licence).to.equal(6)
+    expect(video.licenceLabel).to.equal('Attribution - Non Commercial - No Derivatives')
+    expect(video.language).to.equal(3)
+    expect(video.languageLabel).to.equal('Mandarin')
+    expect(video.nsfw).to.be.ok
+    expect(video.description).to.equal('my super description')
+    expect(video.serverHost).to.equal('localhost:9001')
+    expect(video.account).to.equal('root')
+    expect(video.isLocal).to.be.true
+    expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
+    expect(dateIsValid(video.createdAt)).to.be.true
+    expect(dateIsValid(video.updatedAt)).to.be.true
+    expect(video.channel.name).to.equal('Default root channel')
+    expect(video.channel.isLocal).to.be.true
+    expect(dateIsValid(video.channel.createdAt)).to.be.true
+    expect(dateIsValid(video.channel.updatedAt)).to.be.true
+
+    expect(video.files).to.have.lengthOf(1)
+
+    const file = video.files[0]
+    expect(file.magnetUri).to.have.lengthOf.above(2)
+    expect(file.resolution).to.equal(720)
+    expect(file.resolutionLabel).to.equal('720p')
+    expect(file.size).to.equal(218910)
+
+    const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
+    expect(test).to.equal(true)
+
+    // Wait the async views increment
+    await wait(500)
+  })
+
+  it('Should get the video by UUID', async function () {
+    // Yes, this could be long
+    this.timeout(60000)
+
+    const res = await getVideo(server.url, videoUUID)
+
+    const video = res.body
+    expect(video.name).to.equal('my super name')
+
+    // Wait the async views increment
+    await wait(500)
+  })
+
+  it('Should have the views updated', async function () {
+    const res = await getVideo(server.url, videoId)
+
+    const video = res.body
+    expect(video.views).to.equal(3)
+  })
+
+  it('Should search the video by name by default', async function () {
+    const res = await searchVideo(server.url, 'my')
+
+    expect(res.body.total).to.equal(1)
+    expect(res.body.data).to.be.an('array')
+    expect(res.body.data.length).to.equal(1)
+
+    const video = res.body.data[0]
+    expect(video.name).to.equal('my super name')
+    expect(video.category).to.equal(2)
+    expect(video.categoryLabel).to.equal('Films')
+    expect(video.licence).to.equal(6)
+    expect(video.licenceLabel).to.equal('Attribution - Non Commercial - No Derivatives')
+    expect(video.language).to.equal(3)
+    expect(video.languageLabel).to.equal('Mandarin')
+    expect(video.nsfw).to.be.ok
+    expect(video.description).to.equal('my super description')
+    expect(video.serverHost).to.equal('localhost:9001')
+    expect(video.account).to.equal('root')
+    expect(video.isLocal).to.be.true
+    expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
+    expect(dateIsValid(video.createdAt)).to.be.true
+    expect(dateIsValid(video.updatedAt)).to.be.true
+
+    const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
+    expect(test).to.equal(true)
+  })
+
+  // Not implemented yet
+  // it('Should search the video by serverHost', async function () {
+  //     const res = await   videosUtils.searchVideo(server.url, '9001', 'host')
+
+  //     expect(res.body.total).to.equal(1)
+  //     expect(res.body.data).to.be.an('array')
+  //     expect(res.body.data.length).to.equal(1)
+
+  //     const video = res.body.data[0]
+  //     expect(video.name).to.equal('my super name')
+  //     expect(video.description).to.equal('my super description')
+  //     expect(video.serverHost).to.equal('localhost:9001')
+  //     expect(video.author).to.equal('root')
+  //     expect(video.isLocal).to.be.true
+  //     expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
+  //     expect(dateIsValid(video.createdAt)).to.be.true
+  //     expect(dateIsValid(video.updatedAt)).to.be.true
+
+  //     const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
+  //       expect(test).to.equal(true)
+
+  //       done()
+  //     })
+  //   })
+  // })
+
+  it('Should search the video by tag', async function () {
+    const res = await searchVideo(server.url, 'tag1', 'tags')
+
+    expect(res.body.total).to.equal(1)
+    expect(res.body.data).to.be.an('array')
+    expect(res.body.data.length).to.equal(1)
+
+    const video = res.body.data[0]
+    expect(video.name).to.equal('my super name')
+    expect(video.category).to.equal(2)
+    expect(video.categoryLabel).to.equal('Films')
+    expect(video.licence).to.equal(6)
+    expect(video.licenceLabel).to.equal('Attribution - Non Commercial - No Derivatives')
+    expect(video.language).to.equal(3)
+    expect(video.languageLabel).to.equal('Mandarin')
+    expect(video.nsfw).to.be.ok
+    expect(video.description).to.equal('my super description')
+    expect(video.serverHost).to.equal('localhost:9001')
+    expect(video.account).to.equal('root')
+    expect(video.isLocal).to.be.true
+    expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
+    expect(dateIsValid(video.createdAt)).to.be.true
+    expect(dateIsValid(video.updatedAt)).to.be.true
+
+    const test = await testVideoImage(server.url, 'video_short.webm', video.thumbnailPath)
+    expect(test).to.equal(true)
+  })
+
+  it('Should not find a search by name by default', async function () {
+    const res = await searchVideo(server.url, 'hello')
+
+    expect(res.body.total).to.equal(0)
+    expect(res.body.data).to.be.an('array')
+    expect(res.body.data.length).to.equal(0)
+  })
+
+  it('Should not find a search by author', async function () {
+    const res = await searchVideo(server.url, 'hello', 'account')
+
+    expect(res.body.total).to.equal(0)
+    expect(res.body.data).to.be.an('array')
+    expect(res.body.data.length).to.equal(0)
+  })
+
+  it('Should not find a search by tag', async function () {
+    const res = await searchVideo(server.url, 'hello', 'tags')
+
+    expect(res.body.total).to.equal(0)
+    expect(res.body.data).to.be.an('array')
+    expect(res.body.data.length).to.equal(0)
+  })
+
+  it('Should remove the video', async function () {
+    await removeVideo(server.url, server.accessToken, videoId)
+
+    const files1 = await readdirPromise(join(__dirname, '..', '..', '..', 'test1/videos/'))
+    expect(files1).to.have.lengthOf(0)
+
+    const files2 = await readdirPromise(join(__dirname, '..', '..', '..', 'test1/thumbnails/'))
+    expect(files2).to.have.lengthOf(0)
+  })
+
+  it('Should not have videos', async function () {
+    const res = await getVideosList(server.url)
+
+    expect(res.body.total).to.equal(0)
+    expect(res.body.data).to.be.an('array')
+    expect(res.body.data).to.have.lengthOf(0)
+  })
+
+  it('Should upload 6 videos', async function () {
+    this.timeout(25000)
+
+    const videos = [
+      'video_short.mp4', 'video_short.ogv', 'video_short.webm',
+      'video_short1.webm', 'video_short2.webm', 'video_short3.webm'
+    ]
+
+    // const tasks: Promise<any>[] = []
+    for (const video of videos) {
+      const videoAttributes = {
+        name: video + ' name',
+        description: video + ' description',
+        category: 2,
+        licence: 1,
+        language: 1,
+        nsfw: true,
+        tags: [ 'tag1', 'tag2', 'tag3' ],
+        fixture: video
+      }
+
+      const p = uploadVideo(server.url, server.accessToken, videoAttributes)
+      await p
+    }
+    // FIXME: concurrent uploads does not work :(
+    //   tasks.push(p)
+    // }
+    //
+    // await Promise.all(tasks)
+  })
+
+  it('Should have the correct durations', async function () {
+    const res = await getVideosList(server.url)
+
+    expect(res.body.total).to.equal(6)
+    const videos = res.body.data
+    expect(videos).to.be.an('array')
+    expect(videos).to.have.lengthOf(6)
+
+    const videosByName = keyBy<{ duration: number }>(videos, 'name')
+    expect(videosByName['video_short.mp4 name'].duration).to.equal(5)
+    expect(videosByName['video_short.ogv name'].duration).to.equal(5)
+    expect(videosByName['video_short.webm name'].duration).to.equal(5)
+    expect(videosByName['video_short1.webm name'].duration).to.equal(10)
+    expect(videosByName['video_short2.webm name'].duration).to.equal(5)
+    expect(videosByName['video_short3.webm name'].duration).to.equal(5)
+  })
+
+  it('Should have the correct thumbnails', async function () {
+    const res = await getVideosList(server.url)
+
+    const videos = res.body.data
+    // For the next test
+    videosListBase = videos
+
+    for (const video of videos) {
+      const videoName = video.name.replace(' name', '')
+      const test = await testVideoImage(server.url, videoName, video.thumbnailPath)
+
+      expect(test).to.equal(true)
+    }
+  })
+
+  it('Should list only the two first videos', async function () {
+    const res = await getVideosListPagination(server.url, 0, 2, 'name')
+
+    const videos = res.body.data
+    expect(res.body.total).to.equal(6)
+    expect(videos.length).to.equal(2)
+    expect(videos[0].name).to.equal(videosListBase[0].name)
+    expect(videos[1].name).to.equal(videosListBase[1].name)
+  })
+
+  it('Should list only the next three videos', async function () {
+    const res = await getVideosListPagination(server.url, 2, 3, 'name')
+
+    const videos = res.body.data
+    expect(res.body.total).to.equal(6)
+    expect(videos.length).to.equal(3)
+    expect(videos[0].name).to.equal(videosListBase[2].name)
+    expect(videos[1].name).to.equal(videosListBase[3].name)
+    expect(videos[2].name).to.equal(videosListBase[4].name)
+  })
+
+  it('Should list the last video', async function () {
+    const res = await getVideosListPagination(server.url, 5, 6, 'name')
+
+    const videos = res.body.data
+    expect(res.body.total).to.equal(6)
+    expect(videos.length).to.equal(1)
+    expect(videos[0].name).to.equal(videosListBase[5].name)
+  })
+
+  it('Should search the first video', async function () {
+    const res = await searchVideoWithPagination(server.url, 'webm', 'name', 0, 1, 'name')
+
+    const videos = res.body.data
+    expect(res.body.total).to.equal(4)
+    expect(videos.length).to.equal(1)
+    expect(videos[0].name).to.equal('video_short1.webm name')
+  })
+
+  it('Should search the last two videos', async function () {
+    const res = await searchVideoWithPagination(server.url, 'webm', 'name', 2, 2, 'name')
+
+    const videos = res.body.data
+    expect(res.body.total).to.equal(4)
+    expect(videos.length).to.equal(2)
+    expect(videos[0].name).to.equal('video_short3.webm name')
+    expect(videos[1].name).to.equal('video_short.webm name')
+  })
+
+  it('Should search all the webm videos', async function () {
+    const res = await searchVideoWithPagination(server.url, 'webm', 'name', 0, 15)
+
+    const videos = res.body.data
+    expect(res.body.total).to.equal(4)
+    expect(videos.length).to.equal(4)
+  })
+
+  it('Should search all the root author videos', async function () {
+    const res = await searchVideoWithPagination(server.url, 'root', 'account', 0, 15)
+
+    const videos = res.body.data
+    expect(res.body.total).to.equal(6)
+    expect(videos.length).to.equal(6)
+  })
+
+  // Not implemented yet
+  // it('Should search all the 9001 port videos', async function () {
+  // const res = await   videosUtils.searchVideoWithPagination(server.url, '9001', 'host', 0, 15)
+
+  //     const videos = res.body.data
+  //     expect(res.body.total).to.equal(6)
+  //     expect(videos.length).to.equal(6)
+
+  //     done()
+  //   })
+  // })
+
+  // it('Should search all the localhost videos', async function () {
+  // const res = await   videosUtils.searchVideoWithPagination(server.url, 'localhost', 'host', 0, 15)
+
+  //     const videos = res.body.data
+  //     expect(res.body.total).to.equal(6)
+  //     expect(videos.length).to.equal(6)
+
+  //     done()
+  //   })
+  // })
+
+  it('Should list and sort by name in descending order', async function () {
+    const res = await getVideosListSort(server.url, '-name')
+
+    const videos = res.body.data
+    expect(res.body.total).to.equal(6)
+    expect(videos.length).to.equal(6)
+    expect(videos[0].name).to.equal('video_short.webm name')
+    expect(videos[1].name).to.equal('video_short.ogv name')
+    expect(videos[2].name).to.equal('video_short.mp4 name')
+    expect(videos[3].name).to.equal('video_short3.webm name')
+    expect(videos[4].name).to.equal('video_short2.webm name')
+    expect(videos[5].name).to.equal('video_short1.webm name')
+  })
+
+  it('Should search and sort by name in ascending order', async function () {
+    const res = await searchVideoWithSort(server.url, 'webm', 'name')
+
+    const videos = res.body.data
+    expect(res.body.total).to.equal(4)
+    expect(videos.length).to.equal(4)
+
+    expect(videos[0].name).to.equal('video_short1.webm name')
+    expect(videos[1].name).to.equal('video_short2.webm name')
+    expect(videos[2].name).to.equal('video_short3.webm name')
+    expect(videos[3].name).to.equal('video_short.webm name')
+
+    videoId = videos[2].id
+  })
+
+  it('Should update a video', async function () {
+    const attributes = {
+      name: 'my super video updated',
+      category: 4,
+      licence: 2,
+      language: 5,
+      nsfw: false,
+      description: 'my super description updated',
+      tags: [ 'tagup1', 'tagup2' ]
+    }
+    await updateVideo(server.url, server.accessToken, videoId, attributes)
+  })
+
+  it('Should have the video updated', async function () {
+    this.timeout(60000)
+
+    const res = await getVideo(server.url, videoId)
+
+    const video = res.body
+
+    expect(video.name).to.equal('my super video updated')
+    expect(video.category).to.equal(4)
+    expect(video.categoryLabel).to.equal('Art')
+    expect(video.licence).to.equal(2)
+    expect(video.licenceLabel).to.equal('Attribution - Share Alike')
+    expect(video.language).to.equal(5)
+    expect(video.languageLabel).to.equal('Arabic')
+    expect(video.nsfw).to.be.ok
+    expect(video.description).to.equal('my super description updated')
+    expect(video.serverHost).to.equal('localhost:9001')
+    expect(video.account).to.equal('root')
+    expect(video.isLocal).to.be.true
+    expect(video.tags).to.deep.equal([ 'tagup1', 'tagup2' ])
+    expect(dateIsValid(video.createdAt)).to.be.true
+    expect(dateIsValid(video.updatedAt)).to.be.true
+
+    expect(video.channel.name).to.equal('Default root channel')
+    expect(video.channel.isLocal).to.be.true
+    expect(dateIsValid(video.channel.createdAt)).to.be.true
+    expect(dateIsValid(video.channel.updatedAt)).to.be.true
+
+    expect(video.files).to.have.lengthOf(1)
+
+    const file = video.files[0]
+    const magnetUri = file.magnetUri
+    expect(file.magnetUri).to.have.lengthOf.above(2)
+    expect(file.resolution).to.equal(720)
+    expect(file.resolutionLabel).to.equal('720p')
+    expect(file.size).to.equal(292677)
+
+    const test = await testVideoImage(server.url, 'video_short3.webm', video.thumbnailPath)
+    expect(test).to.equal(true)
+
+    const torrent = await webtorrentAdd(magnetUri)
+    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('')
+  })
+
+  it('Should update only the tags of a video', async function () {
+    const attributes = {
+      tags: [ 'tag1', 'tag2', 'supertag' ]
+    }
+
+    await updateVideo(server.url, server.accessToken, videoId, attributes)
+
+    const res = await getVideo(server.url, videoId)
+    const video = res.body
+
+    expect(video.name).to.equal('my super video updated')
+    expect(video.category).to.equal(4)
+    expect(video.categoryLabel).to.equal('Art')
+    expect(video.licence).to.equal(2)
+    expect(video.licenceLabel).to.equal('Attribution - Share Alike')
+    expect(video.language).to.equal(5)
+    expect(video.languageLabel).to.equal('Arabic')
+    expect(video.nsfw).to.be.ok
+    expect(video.description).to.equal('my super description updated')
+    expect(video.serverHost).to.equal('localhost:9001')
+    expect(video.account).to.equal('root')
+    expect(video.isLocal).to.be.true
+    expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'supertag' ])
+    expect(dateIsValid(video.createdAt)).to.be.true
+    expect(dateIsValid(video.updatedAt)).to.be.true
+
+    expect(video.channel.name).to.equal('Default root channel')
+    expect(video.channel.isLocal).to.be.true
+    expect(dateIsValid(video.channel.createdAt)).to.be.true
+    expect(dateIsValid(video.channel.updatedAt)).to.be.true
+
+    expect(video.files).to.have.lengthOf(1)
+
+    const file = video.files[0]
+    expect(file.magnetUri).to.have.lengthOf.above(2)
+    expect(file.resolution).to.equal(720)
+    expect(file.resolutionLabel).to.equal('720p')
+    expect(file.size).to.equal(292677)
+  })
+
+  it('Should update only the description of a video', async function () {
+    const attributes = {
+      description: 'hello everybody'
+    }
+
+    await updateVideo(server.url, server.accessToken, videoId, attributes)
+
+    const res = await getVideo(server.url, videoId)
+    const video = res.body
+
+    expect(video.name).to.equal('my super video updated')
+    expect(video.category).to.equal(4)
+    expect(video.categoryLabel).to.equal('Art')
+    expect(video.licence).to.equal(2)
+    expect(video.licenceLabel).to.equal('Attribution - Share Alike')
+    expect(video.language).to.equal(5)
+    expect(video.languageLabel).to.equal('Arabic')
+    expect(video.nsfw).to.be.ok
+    expect(video.description).to.equal('hello everybody')
+    expect(video.serverHost).to.equal('localhost:9001')
+    expect(video.account).to.equal('root')
+    expect(video.isLocal).to.be.true
+    expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'supertag' ])
+    expect(dateIsValid(video.createdAt)).to.be.true
+    expect(dateIsValid(video.updatedAt)).to.be.true
+
+    expect(video.channel.name).to.equal('Default root channel')
+    expect(video.channel.isLocal).to.be.true
+    expect(dateIsValid(video.channel.createdAt)).to.be.true
+    expect(dateIsValid(video.channel.updatedAt)).to.be.true
+
+    expect(video.files).to.have.lengthOf(1)
+
+    const file = video.files[0]
+    expect(file.magnetUri).to.have.lengthOf.above(2)
+    expect(file.resolution).to.equal(720)
+    expect(file.resolutionLabel).to.equal('720p')
+    expect(file.size).to.equal(292677)
+  })
+
+  it('Should like a video', async function () {
+    await rateVideo(server.url, server.accessToken, videoId, 'like')
+
+    const res = await getVideo(server.url, videoId)
+    const video = res.body
+
+    expect(video.likes).to.equal(1)
+    expect(video.dislikes).to.equal(0)
+  })
+
+  it('Should dislike the same video', async function () {
+    await rateVideo(server.url, server.accessToken, videoId, 'dislike')
+
+    const res = await getVideo(server.url, videoId)
+    const video = res.body
+
+    expect(video.likes).to.equal(0)
+    expect(video.dislikes).to.equal(1)
+  })
+
+  after(async function () {
+    killallServers([ server ])
+
+    // Keep the logs if the test failed
+    if (this['ok']) {
+      await flushTests()
+    }
+  })
+})
index eb1e4f8736463db56fefbe9eb1f2c2a3c5eb86fe..bf91ead2e91c38cfcda6715b5ae902da9102d117 100644 (file)
@@ -40,14 +40,14 @@ describe('Test video privacy', function () {
   })
 
   it('Should upload a private video on server 1', async function () {
-    this.timeout(15000)
+    this.timeout(25000)
 
     const attributes = {
       privacy: VideoPrivacy.PRIVATE
     }
     await uploadVideo(servers[0].url, servers[0].accessToken, attributes)
 
-    await wait(11000)
+    await wait(15000)
   })
 
   it('Should not have this private video on server 2', async function () {
@@ -86,8 +86,8 @@ describe('Test video privacy', function () {
     await getVideoWithToken(servers[0].url, servers[0].accessToken, privateVideoUUID)
   })
 
-  it('Should upload a unlisted video on server 2', async function () {
-    this.timeout(30000)
+  it('Should upload an unlisted video on server 2', async function () {
+    this.timeout(50000)
 
     const attributes = {
       name: 'unlisted video',
@@ -95,7 +95,7 @@ describe('Test video privacy', function () {
     }
     await uploadVideo(servers[1].url, servers[1].accessToken, attributes)
 
-    await wait(22000)
+    await wait(40000)
   })
 
   it('Should not have this unlisted video listed on server 1 and 2', async function () {
@@ -125,7 +125,7 @@ describe('Test video privacy', function () {
   })
 
   it('Should update the private video to public on server 1', async function () {
-    this.timeout(15000)
+    this.timeout(40000)
 
     const attribute = {
       name: 'super video public',
@@ -134,10 +134,10 @@ describe('Test video privacy', function () {
 
     await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, attribute)
 
-    await wait(11000)
+    await wait(30000)
   })
 
-  it('Should not have this new unlisted video listed on server 1 and 2', async function () {
+  it('Should have this new public video listed on server 1 and 2', async function () {
     for (const server of servers) {
       const res = await getVideosList(server.url)
 
index 5f947ed2b98e632fa9520d59ce598d0a911847c1..0d70e345199f9ff4433d208a4bd6ae4a58ad620d 100644 (file)
@@ -26,8 +26,8 @@ describe('Test a client controllers', function () {
     server.accessToken = await loginAndGetAccessToken(server)
 
     const videoAttributes = {
-      name: 'my super name for pod 1',
-      description: 'my super description for pod 1'
+      name: 'my super name for server 1',
+      description: 'my super description for server 1'
     }
     await uploadVideo(server.url, server.accessToken, videoAttributes)
 
@@ -44,8 +44,8 @@ describe('Test a client controllers', function () {
                         .get('/videos/watch/' + server.video.id)
                         .expect(200)
 
-    expect(res.text).to.contain('<meta property="og:title" content="my super name for pod 1" />')
-    expect(res.text).to.contain('<meta property="og:description" content="my super description for pod 1" />')
+    expect(res.text).to.contain('<meta property="og:title" content="my super name for server 1" />')
+    expect(res.text).to.contain('<meta property="og:description" content="my super description for server 1" />')
   })
 
   it('Should have valid Open Graph tags on the watch page with video uuid', async function () {
@@ -53,8 +53,8 @@ describe('Test a client controllers', function () {
                         .get('/videos/watch/' + server.video.uuid)
                         .expect(200)
 
-    expect(res.text).to.contain('<meta property="og:title" content="my super name for pod 1" />')
-    expect(res.text).to.contain('<meta property="og:description" content="my super description for pod 1" />')
+    expect(res.text).to.contain('<meta property="og:title" content="my super name for server 1" />')
+    expect(res.text).to.contain('<meta property="og:description" content="my super description for server 1" />')
   })
 
   it('Should have valid oEmbed discovery tags', async function () {
index c79ad38ffd83dcb0031f2bb52530e47c2a2d43a9..ac83d64a6b3cb964958f0c748be8200247d78ce5 100644 (file)
@@ -1,25 +1,24 @@
-import * as program from 'commander'
-
 // /!\ Before imports /!\
 process.env.NODE_ENV = 'test'
 
-import { Video, VideoRateType, VideoFile } from '../../../shared'
+import * as program from 'commander'
+import { Video, VideoFile, VideoRateType } from '../../../shared'
 import {
-  ServerInfo as DefaultServerInfo,
   flushAndRunMultipleServers,
-  setAccessTokensToServers,
-  makeFriends,
-  wait,
-  killallServers,
   flushTests,
-  uploadVideo,
+  getAllVideosListBy,
+  getRequestsStats,
+  getVideo,
   getVideosList,
-  updateVideo,
+  killallServers,
   removeVideo,
-  getVideo,
-  getAllVideosListBy,
-  getRequestsStats
+  ServerInfo as DefaultServerInfo,
+  setAccessTokensToServers,
+  updateVideo,
+  uploadVideo,
+  wait
 } from '../utils'
+import { follow } from '../utils/follows'
 
 interface ServerInfo extends DefaultServerInfo {
   requestsNumber: number
@@ -32,7 +31,7 @@ program
   .option('-v, --view [weight]', 'Weight for viewing videos')
   .option('-l, --like [weight]', 'Weight for liking videos')
   .option('-s, --dislike [weight]', 'Weight for disliking videos')
-  .option('-p, --pods [n]', 'Number of pods to run (3 or 6)', /^3|6$/, 3)
+  .option('-p, --servers [n]', 'Number of servers to run (3 or 6)', /^3|6$/, 3)
   .option('-i, --interval-action [interval]', 'Interval in ms for an action')
   .option('-I, --interval-integrity [interval]', 'Interval in ms for an integrity check')
   .option('-f, --flush', 'Flush datas on exit')
@@ -50,7 +49,7 @@ const actionInterval = program['intervalAction'] !== undefined ? parseInt(progra
 const integrityInterval = program['intervalIntegrity'] !== undefined ? parseInt(program['intervalIntegrity'], 10) : 60000
 const displayDiffOnFail = program['difference'] || false
 
-const numberOfPods = 6
+const numberOfServers = 6
 
 console.log(
   'Create weight: %d, update weight: %d, remove weight: %d, view weight: %d, like weight: %d, dislike weight: %d.',
@@ -77,7 +76,7 @@ start()
 // ----------------------------------------------------------------------------
 
 async function start () {
-  const servers = await runServers(numberOfPods)
+  const servers = await runServers(numberOfServers)
 
   process.on('exit', async () => {
     await exitServers(servers, flushAtExit)
@@ -152,22 +151,20 @@ function getRandomNumServer (servers) {
   return getRandomInt(0, servers.length)
 }
 
-async function runServers (numberOfPods: number) {
-  const servers: ServerInfo[] = (await flushAndRunMultipleServers(numberOfPods))
+async function runServers (numberOfServers: number) {
+  const servers: ServerInfo[] = (await flushAndRunMultipleServers(numberOfServers))
     .map(s => Object.assign({ requestsNumber: 0 }, s))
 
   // Get the access tokens
   await setAccessTokensToServers(servers)
 
-  await makeFriends(servers[1].url, servers[1].accessToken)
-  await makeFriends(servers[0].url, servers[0].accessToken)
-  await wait(1000)
-
-  await makeFriends(servers[3].url, servers[3].accessToken)
-  await makeFriends(servers[5].url, servers[5].accessToken)
-  await makeFriends(servers[4].url, servers[4].accessToken)
+  for (let i = 0; i < numberOfServers; i++) {
+    for (let j = 0; j < numberOfServers; j++) {
+      if (i === j) continue
 
-  await wait(1000)
+      await follow(servers[i].url, [ servers[j].url ], servers[i].accessToken)
+    }
+  }
 
   return servers
 }
@@ -259,7 +256,7 @@ async function checkIntegrity (servers: ServerInfo[]) {
   const videos: Video[][] = []
   const tasks: Promise<any>[] = []
 
-  // Fetch all videos and remove some fields that can differ between pods
+  // Fetch all videos and remove some fields that can differ between servers
   for (const server of servers) {
     const p = getAllVideosListBy(server.url).then(res => videos.push(res.body.data))
     tasks.push(p)
index b454fe2f8f3a1f303f675cbf585e9a13c60807a7..cffc1648fac0ccd4a8a48eee2a67a12e32ca5bec 100644 (file)
@@ -29,7 +29,7 @@ function getFollowingListPaginationAndSort (url: string, start: number, count: n
 }
 
 async function follow (follower: string, following: string[], accessToken: string, expectedStatus = 204) {
-  const path = '/api/v1/server/follow'
+  const path = '/api/v1/server/following'
 
   const followingHosts = following.map(f => f.replace(/^http:\/\//, ''))
   const res = await request(follower)
index 6a05a1c399618001f08cd7d96a171d43c06e29c9..2e6feeb16f9fe995b5e304ff1e764e1b32d09b8f 100644 (file)
@@ -12,6 +12,7 @@ export interface BaseActivity {
   '@context'?: any[]
   id: string
   to?: string[]
+  cc?: string[]
   actor: string
   type: ActivityType
   signature?: ActivityPubSignature