2021-08-30 07:22:33 -05:00
|
|
|
import autocannon, { printResult } from 'autocannon'
|
2022-02-28 08:19:44 -06:00
|
|
|
import { program } from 'commander'
|
2021-02-22 08:34:32 -06:00
|
|
|
import { writeJson } from 'fs-extra'
|
2021-07-09 07:15:11 -05:00
|
|
|
import { Video, VideoPrivacy } from '@shared/models'
|
2022-01-03 10:13:11 -06:00
|
|
|
import { createSingleServer, killallServers, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
|
2021-02-22 08:34:32 -06:00
|
|
|
|
2021-07-16 02:47:51 -05:00
|
|
|
let server: PeerTubeServer
|
2021-02-22 08:34:32 -06:00
|
|
|
let video: Video
|
|
|
|
let threadId: number
|
|
|
|
|
2022-02-28 08:19:44 -06:00
|
|
|
program
|
|
|
|
.option('-o, --outfile [outfile]', 'Outfile')
|
|
|
|
.option('--grep [string]', 'Filter tests you want to execute')
|
|
|
|
.description('Run API REST benchmark')
|
|
|
|
.parse(process.argv)
|
|
|
|
|
|
|
|
const options = program.opts()
|
|
|
|
|
|
|
|
const outfile = options.outfile
|
2021-02-22 08:34:32 -06:00
|
|
|
|
|
|
|
run()
|
|
|
|
.catch(err => console.error(err))
|
|
|
|
.finally(() => {
|
2021-07-09 08:37:43 -05:00
|
|
|
if (server) return killallServers([ server ])
|
2021-02-22 08:34:32 -06:00
|
|
|
})
|
|
|
|
|
|
|
|
function buildAuthorizationHeader () {
|
|
|
|
return {
|
|
|
|
Authorization: 'Bearer ' + server.accessToken
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-25 09:23:30 -06:00
|
|
|
function buildAPHeader () {
|
|
|
|
return {
|
|
|
|
Accept: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-22 08:34:32 -06:00
|
|
|
async function run () {
|
|
|
|
console.log('Preparing server...')
|
|
|
|
|
|
|
|
await prepare()
|
|
|
|
|
|
|
|
const tests = [
|
2021-02-25 09:23:30 -06:00
|
|
|
{
|
|
|
|
title: 'AP - account peertube',
|
|
|
|
path: '/accounts/peertube',
|
|
|
|
headers: buildAPHeader(),
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (body, status) => {
|
|
|
|
return status === 200 && body.startsWith('{"type":')
|
2021-02-25 09:23:30 -06:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'AP - video',
|
|
|
|
path: '/videos/watch/' + video.uuid,
|
|
|
|
headers: buildAPHeader(),
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (body, status) => {
|
|
|
|
return status === 200 && body.startsWith('{"type":"Video"')
|
2021-02-25 09:23:30 -06:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'Misc - webfinger peertube',
|
|
|
|
path: '/.well-known/webfinger?resource=acct:peertube@' + server.host,
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (body, status) => {
|
|
|
|
return status === 200 && body.startsWith('{"subject":')
|
2021-02-25 09:23:30 -06:00
|
|
|
}
|
|
|
|
},
|
2021-02-22 08:34:32 -06:00
|
|
|
{
|
|
|
|
title: 'API - unread notifications',
|
|
|
|
path: '/api/v1/users/me/notifications?start=0&count=0&unread=true',
|
|
|
|
headers: buildAuthorizationHeader(),
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (_body, status) => {
|
|
|
|
return status === 200
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'API - me',
|
|
|
|
path: '/api/v1/users/me',
|
|
|
|
headers: buildAuthorizationHeader(),
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (body, status) => {
|
|
|
|
return status === 200 && body.startsWith('{"id":')
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'API - videos list',
|
|
|
|
path: '/api/v1/videos',
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (body, status) => {
|
|
|
|
return status === 200 && body.startsWith('{"total":10')
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'API - video get',
|
|
|
|
path: '/api/v1/videos/' + video.uuid,
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (body, status) => {
|
|
|
|
return status === 200 && body.startsWith('{"id":')
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'API - video captions',
|
|
|
|
path: '/api/v1/videos/' + video.uuid + '/captions',
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (body, status) => {
|
|
|
|
return status === 200 && body.startsWith('{"total":4')
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'API - video threads',
|
|
|
|
path: '/api/v1/videos/' + video.uuid + '/comment-threads',
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (body, status) => {
|
|
|
|
return status === 200 && body.startsWith('{"total":10')
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'API - video replies',
|
|
|
|
path: '/api/v1/videos/' + video.uuid + '/comment-threads/' + threadId,
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (body, status) => {
|
|
|
|
return status === 200 && body.startsWith('{"comment":{')
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'HTML - video watch',
|
|
|
|
path: '/videos/watch/' + video.uuid,
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (body, status) => {
|
|
|
|
return status === 200 && body.includes('<title>my super')
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
},
|
2021-02-25 09:23:30 -06:00
|
|
|
{
|
|
|
|
title: 'HTML - video embed',
|
|
|
|
path: '/videos/embed/' + video.uuid,
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (body, status) => {
|
|
|
|
return status === 200 && body.includes('embed')
|
2021-02-25 09:23:30 -06:00
|
|
|
}
|
|
|
|
},
|
2021-02-22 08:34:32 -06:00
|
|
|
{
|
|
|
|
title: 'HTML - homepage',
|
|
|
|
path: '/',
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (_body, status) => {
|
|
|
|
return status === 200
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
title: 'API - config',
|
|
|
|
path: '/api/v1/config',
|
2021-03-30 01:57:17 -05:00
|
|
|
expecter: (body, status) => {
|
2021-10-14 04:35:43 -05:00
|
|
|
return status === 200 && body.startsWith('{"client":')
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
}
|
2022-02-28 08:19:44 -06:00
|
|
|
].filter(t => {
|
|
|
|
if (!options.grep) return true
|
|
|
|
|
|
|
|
return t.title.includes(options.grep)
|
|
|
|
})
|
2021-02-22 08:34:32 -06:00
|
|
|
|
|
|
|
const finalResult: any[] = []
|
|
|
|
|
|
|
|
for (const test of tests) {
|
|
|
|
console.log('Running against %s.', test.path)
|
|
|
|
const testResult = await runBenchmark(test)
|
|
|
|
|
|
|
|
Object.assign(testResult, { title: test.title, path: test.path })
|
|
|
|
finalResult.push(testResult)
|
|
|
|
|
2021-08-30 07:22:33 -05:00
|
|
|
console.log(printResult(testResult))
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (outfile) await writeJson(outfile, finalResult)
|
|
|
|
}
|
|
|
|
|
|
|
|
function runBenchmark (options: {
|
|
|
|
path: string
|
|
|
|
headers?: { [ id: string ]: string }
|
|
|
|
expecter: Function
|
|
|
|
}) {
|
|
|
|
const { path, expecter, headers } = options
|
|
|
|
|
|
|
|
return new Promise((res, rej) => {
|
2021-03-30 01:57:17 -05:00
|
|
|
autocannon({
|
2021-02-22 08:34:32 -06:00
|
|
|
url: server.url + path,
|
|
|
|
connections: 20,
|
|
|
|
headers,
|
|
|
|
pipelining: 1,
|
2021-03-30 01:57:17 -05:00
|
|
|
duration: 10,
|
|
|
|
requests: [
|
|
|
|
{
|
|
|
|
onResponse: (status, body) => {
|
|
|
|
if (expecter(body, status) !== true) {
|
|
|
|
console.error('Expected result failed.', { body, status })
|
|
|
|
throw new Error('Invalid expectation')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
2021-02-22 08:34:32 -06:00
|
|
|
}, (err, result) => {
|
|
|
|
if (err) return rej(err)
|
|
|
|
|
|
|
|
return res(result)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
async function prepare () {
|
2021-07-16 02:47:51 -05:00
|
|
|
server = await createSingleServer(1, {
|
2021-02-22 08:34:32 -06:00
|
|
|
rates_limit: {
|
|
|
|
api: {
|
|
|
|
max: 5_000_000
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
await setAccessTokensToServers([ server ])
|
|
|
|
|
2021-07-15 03:02:54 -05:00
|
|
|
const attributes = {
|
2021-02-22 08:34:32 -06:00
|
|
|
name: 'my super video',
|
|
|
|
category: 2,
|
|
|
|
nsfw: true,
|
|
|
|
licence: 6,
|
|
|
|
language: 'fr',
|
|
|
|
privacy: VideoPrivacy.PUBLIC,
|
|
|
|
support: 'please give me a coffee',
|
|
|
|
description: 'my super description'.repeat(10),
|
|
|
|
tags: [ 'tag1', 'tag2', 'tag3' ]
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < 10; i++) {
|
2021-07-16 02:04:35 -05:00
|
|
|
await server.videos.upload({ attributes: { ...attributes, name: 'my super video ' + i } })
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
|
2021-07-16 02:04:35 -05:00
|
|
|
const { data } = await server.videos.list()
|
2021-07-15 03:02:54 -05:00
|
|
|
video = data.find(v => v.name === 'my super video 1')
|
2021-02-22 08:34:32 -06:00
|
|
|
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
|
|
const text = 'my super first comment'
|
2021-07-16 02:04:35 -05:00
|
|
|
const created = await server.comments.createThread({ videoId: video.id, text })
|
2021-07-09 07:15:11 -05:00
|
|
|
threadId = created.id
|
2021-02-22 08:34:32 -06:00
|
|
|
|
|
|
|
const text1 = 'my super answer to thread 1'
|
2021-07-16 02:04:35 -05:00
|
|
|
const child = await server.comments.addReply({ videoId: video.id, toCommentId: threadId, text: text1 })
|
2021-02-22 08:34:32 -06:00
|
|
|
|
|
|
|
const text2 = 'my super answer to answer of thread 1'
|
2021-07-16 02:04:35 -05:00
|
|
|
await server.comments.addReply({ videoId: video.id, toCommentId: child.id, text: text2 })
|
2021-02-22 08:34:32 -06:00
|
|
|
|
|
|
|
const text3 = 'my second answer to thread 1'
|
2021-07-16 02:04:35 -05:00
|
|
|
await server.comments.addReply({ videoId: video.id, toCommentId: threadId, text: text3 })
|
2021-02-22 08:34:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
for (const caption of [ 'ar', 'fr', 'en', 'zh' ]) {
|
2021-07-21 06:58:35 -05:00
|
|
|
await server.captions.add({
|
2021-02-22 08:34:32 -06:00
|
|
|
language: caption,
|
|
|
|
videoId: video.id,
|
|
|
|
fixture: 'subtitle-good2.vtt'
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return { server, video, threadId }
|
|
|
|
}
|