Optimize signature verification

pull/128/head
Chocobozzz 2017-11-17 15:20:42 +01:00
parent 975e6e0e44
commit 9a27cdc27c
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
29 changed files with 444 additions and 584 deletions

View 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))
}

View File

@ -25,7 +25,7 @@ serverFollowsRouter.get('/following',
asyncMiddleware(listFollowing)
)
serverFollowsRouter.post('/follow',
serverFollowsRouter.post('/following',
authenticate,
ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
followValidator,

View 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
}
}

View File

@ -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 }

View 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)))
)
}

View 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...')

View 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,

View 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

View 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

View 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)

View 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
}

View 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()
}

View 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',

View File

@ -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()
}
})
})

View 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'

View File

@ -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()
}
})
})

View File

@ -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()
}
})
})

View File

@ -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()
}
})
})

View 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')
})

View 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'

View File

@ -1,3 +1,3 @@
// Order of the tests we want to execute
import './multiple-pods'
import './multiple-servers'
import './video-transcoder'

View File

@ -10,7 +10,6 @@ import {
getVideo,
getVideosList,
killallServers,
makeFriends,
rateVideo,
removeVideo,
ServerInfo,
@ -22,13 +21,14 @@ import {
webtorrentAdd,
addVideoChannel,
getVideoChannelsList,
getUserAccessToken
getUserAccessToken,
doubleFollow
} from '../utils'
import { createUser } from '../utils/users'
const expect = chai.expect
describe('Test multiple pods', function () {
describe('Test multiple servers', function () {
let servers: ServerInfo[] = []
const toRemove = []
let videoUUID = ''
@ -50,17 +50,15 @@ describe('Test multiple pods', function () {
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)
// 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 pods', async function () {
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
@ -69,18 +67,18 @@ describe('Test multiple pods', function () {
}
})
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
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 pod 1',
name: 'my super name for server 1',
category: 5,
licence: 4,
language: 9,
nsfw: true,
description: 'my super description for pod 1',
description: 'my super description for server 1',
tags: [ 'tag1p1', 'tag2p1' ],
channelId: videoChannelId,
fixture: 'video_short1.webm'
@ -89,7 +87,7 @@ describe('Test multiple pods', function () {
await wait(11000)
// All pods should have this video
// All servers should have this video
for (const server of servers) {
let baseMagnet = null
@ -99,7 +97,7 @@ describe('Test multiple pods', function () {
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.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)
@ -107,8 +105,8 @@ describe('Test multiple pods', function () {
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.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
@ -127,8 +125,9 @@ describe('Test multiple pods', function () {
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.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)
@ -141,7 +140,7 @@ describe('Test multiple pods', function () {
expect(videoDetails.channel.isLocal).to.be.true
}
// All pods should have the same magnet Uri
// All servers should have the same magnet Uri
if (baseMagnet === null) {
baseMagnet = magnetUri
} else {
@ -153,7 +152,7 @@ describe('Test multiple pods', function () {
}
})
it('Should upload the video on pod 2 and propagate on each pod', async function () {
it('Should upload the video on server 2 and propagate on each server', async function () {
this.timeout(120000)
const user = {
@ -164,12 +163,12 @@ describe('Test multiple pods', function () {
const userAccessToken = await getUserAccessToken(servers[1], user)
const videoAttributes = {
name: 'my super name for pod 2',
name: 'my super name for server 2',
category: 4,
licence: 3,
language: 11,
nsfw: true,
description: 'my super description for pod 2',
description: 'my super description for server 2',
tags: [ 'tag1p2', 'tag2p2', 'tag3p2' ],
fixture: 'video_short2.webm'
}
@ -178,7 +177,7 @@ describe('Test multiple pods', function () {
// Transcoding, so wait more than 22000
await wait(60000)
// All pods should have this video
// All servers should have this video
for (const server of servers) {
let baseMagnet = {}
@ -188,7 +187,7 @@ describe('Test multiple pods', function () {
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.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)
@ -196,8 +195,8 @@ describe('Test multiple pods', function () {
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.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
@ -223,7 +222,7 @@ describe('Test multiple pods', function () {
for (const file of videoDetails.files) {
expect(file.magnetUri).to.have.lengthOf.above(2)
// All pods should have the same magnet Uri
// All servers should have the same magnet Uri
if (baseMagnet[file.resolution] === undefined) {
baseMagnet[file.resolution] = file.magnet
} else {
@ -256,28 +255,28 @@ describe('Test multiple pods', function () {
}
})
it('Should upload two videos on pod 3 and propagate on each pod', async function () {
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 pod 3',
name: 'my super name for server 3',
category: 6,
licence: 5,
language: 11,
nsfw: true,
description: 'my super description for pod 3',
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 pod 3-2',
name: 'my super name for server 3-2',
category: 7,
licence: 6,
language: 12,
nsfw: false,
description: 'my super description for pod 3-2',
description: 'my super description for server 3-2',
tags: [ 'tag2p3', 'tag3p3', 'tag4p3' ],
fixture: 'video_short.webm'
}
@ -286,7 +285,7 @@ describe('Test multiple pods', function () {
await wait(33000)
let baseMagnet = null
// All pods should have this video
// All servers should have this video
for (const server of servers) {
const res = await getVideosList(server.url)
@ -297,7 +296,7 @@ describe('Test multiple pods', function () {
// 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') {
if (videos[2].name === 'my super name for server 3') {
video1 = videos[2]
video2 = videos[3]
} else {
@ -305,7 +304,7 @@ describe('Test multiple pods', function () {
video2 = videos[2]
}
expect(video1.name).to.equal('my super name for pod 3')
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)
@ -313,8 +312,8 @@ describe('Test multiple pods', function () {
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.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')
@ -331,7 +330,7 @@ describe('Test multiple pods', function () {
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.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)
@ -339,8 +338,8 @@ describe('Test multiple pods', function () {
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.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')
@ -367,7 +366,7 @@ describe('Test multiple pods', function () {
expect(video2.isLocal).to.be.true
}
// All pods should have the same magnet Uri
// All servers should have the same magnet Uri
if (baseMagnet === null) {
baseMagnet = magnetUri2
} else {
@ -384,7 +383,7 @@ describe('Test multiple pods', function () {
})
describe('Should seed the uploaded video', function () {
it('Should add the file 1 by asking pod 3', async function () {
it('Should add the file 1 by asking server 3', async function () {
// Yes, this could be long
this.timeout(200000)
@ -403,7 +402,7 @@ describe('Test multiple pods', function () {
expect(torrent.files[0].path).to.exist.and.to.not.equal('')
})
it('Should add the file 2 by asking pod 1', async function () {
it('Should add the file 2 by asking server 1', async function () {
// Yes, this could be long
this.timeout(200000)
@ -419,7 +418,7 @@ describe('Test multiple pods', function () {
expect(torrent.files[0].path).to.exist.and.to.not.equal('')
})
it('Should add the file 3 by asking pod 2', async function () {
it('Should add the file 3 by asking server 2', async function () {
// Yes, this could be long
this.timeout(200000)
@ -435,7 +434,7 @@ describe('Test multiple pods', function () {
expect(torrent.files[0].path).to.exist.and.to.not.equal('')
})
it('Should add the file 3-2 by asking pod 1', async function () {
it('Should add the file 3-2 by asking server 1', async function () {
// Yes, this could be long
this.timeout(200000)
@ -451,13 +450,13 @@ describe('Test multiple pods', function () {
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 () {
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 pod 2')
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
@ -472,31 +471,31 @@ describe('Test multiple pods', function () {
})
describe('Should update video views, likes and dislikes', function () {
let localVideosPod3 = []
let remoteVideosPod1 = []
let remoteVideosPod2 = []
let remoteVideosPod3 = []
let localVideosServer3 = []
let remoteVideosServer1 = []
let remoteVideosServer2 = []
let remoteVideosServer3 = []
before(async function () {
const res1 = await getVideosList(servers[0].url)
remoteVideosPod1 = res1.body.data.filter(video => video.isLocal === false).map(video => video.uuid)
remoteVideosServer1 = 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)
remoteVideosServer2 = 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)
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, 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]))
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)
@ -506,8 +505,8 @@ describe('Test multiple pods', function () {
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])
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)
@ -518,16 +517,16 @@ describe('Test multiple pods', 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]))
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)
@ -557,13 +556,13 @@ describe('Test multiple pods', 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'))
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)
@ -591,7 +590,7 @@ describe('Test multiple pods', function () {
})
describe('Should manipulate these videos', function () {
it('Should update the video 3 by asking pod 3', async function () {
it('Should update the video 3 by asking server 3', async function () {
this.timeout(15000)
const attributes = {
@ -609,7 +608,7 @@ describe('Test multiple pods', function () {
await wait(11000)
})
it('Should have the video 3 updated on each pod', async function () {
it('Should have the video 3 updated on each server', async function () {
this.timeout(200000)
for (const server of servers) {
@ -651,7 +650,7 @@ describe('Test multiple pods', function () {
}
})
it('Should remove the videos 3 and 3-2 by asking pod 3', async function () {
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)
@ -660,7 +659,7 @@ describe('Test multiple pods', function () {
await wait(11000)
})
it('Should have videos 1 and 3 on each pod', async function () {
it('Should have videos 1 and 3 on each server', async function () {
for (const server of servers) {
const res = await getVideosList(server.url)
@ -673,11 +672,11 @@ describe('Test multiple pods', function () {
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
videoUUID = videos.find(video => video.name === 'my super name for server 1').uuid
}
})
it('Should get the same video by UUID on each pod', async function () {
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)
@ -701,7 +700,7 @@ describe('Test multiple pods', function () {
}
})
it('Should get the preview from each pod', async function () {
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

View 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

View File

@ -34,7 +34,7 @@ import {
updateVideo
} from '../utils'
describe('Test a single pod', function () {
describe('Test a single server', function () {
let server: ServerInfo = null
let videoId = -1
let videoUUID = ''

View 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)

View 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 () {

View 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,
getVideosList,
updateVideo,
removeVideo,
getVideo,
getAllVideosListBy,
getRequestsStats
getRequestsStats,
getVideo,
getVideosList,
killallServers,
removeVideo,
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)
for (let i = 0; i < numberOfServers; i++) {
for (let j = 0; j < numberOfServers; j++) {
if (i === j) continue
await makeFriends(servers[3].url, servers[3].accessToken)
await makeFriends(servers[5].url, servers[5].accessToken)
await makeFriends(servers[4].url, servers[4].accessToken)
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)

View 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)

View File

@ -12,6 +12,7 @@ export interface BaseActivity {
'@context'?: any[]
id: string
to?: string[]
cc?: string[]
actor: string
type: ActivityType
signature?: ActivityPubSignature