PeerTube/scripts/benchmark.ts

324 lines
8.0 KiB
TypeScript
Raw Normal View History

2021-08-30 14:22:33 +02:00
import autocannon, { printResult } from 'autocannon'
2022-02-28 15:19:44 +01:00
import { program } from 'commander'
import { writeJson } from 'fs-extra/esm'
import { Video, VideoPrivacy } from '@peertube/peertube-models'
import {
createMultipleServers,
doubleFollow,
killallServers,
PeerTubeServer,
setAccessTokensToServers
} from '@peertube/peertube-server-commands'
2021-02-22 15:34:32 +01:00
let servers: PeerTubeServer[]
// First server
2021-07-16 09:47:51 +02:00
let server: PeerTubeServer
2021-02-22 15:34:32 +01:00
let video: Video
let threadId: number
2022-02-28 15:19:44 +01: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 15:34:32 +01:00
run()
.catch(err => console.error(err))
.finally(() => {
if (servers) return killallServers(servers)
2021-02-22 15:34:32 +01:00
})
function buildAuthorizationHeader () {
return {
Authorization: 'Bearer ' + server.accessToken
}
}
2021-02-25 16:23:30 +01:00
function buildAPHeader () {
return {
Accept: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
}
}
function buildJSONHeader () {
return {
'Content-Type': 'application/json'
}
}
2021-02-22 15:34:32 +01:00
async function run () {
console.log('Preparing server...')
await prepare()
const tests = [
2021-02-25 16:23:30 +01:00
{
title: 'AP - account peertube',
path: '/accounts/peertube',
headers: buildAPHeader(),
2021-03-30 08:57:17 +02:00
expecter: (body, status) => {
2022-03-24 13:42:12 +01:00
return status === 200 && body.startsWith('{"@context":')
2021-02-25 16:23:30 +01:00
}
},
{
title: 'AP - video',
path: '/videos/watch/' + video.uuid,
headers: buildAPHeader(),
2021-03-30 08:57:17 +02:00
expecter: (body, status) => {
2022-03-24 13:42:12 +01:00
return status === 200 && body.startsWith('{"@context":')
2021-02-25 16:23:30 +01:00
}
},
{
title: 'Misc - webfinger peertube',
path: '/.well-known/webfinger?resource=acct:peertube@' + server.host,
2021-03-30 08:57:17 +02:00
expecter: (body, status) => {
return status === 200 && body.startsWith('{"subject":')
2021-02-25 16:23:30 +01:00
}
},
2021-02-22 15:34:32 +01:00
{
title: 'API - unread notifications',
path: '/api/v1/users/me/notifications?start=0&count=0&unread=true',
headers: buildAuthorizationHeader(),
2021-03-30 08:57:17 +02:00
expecter: (_body, status) => {
return status === 200
2021-02-22 15:34:32 +01:00
}
},
{
title: 'API - me',
path: '/api/v1/users/me',
headers: buildAuthorizationHeader(),
2021-03-30 08:57:17 +02:00
expecter: (body, status) => {
return status === 200 && body.startsWith('{"id":')
2021-02-22 15:34:32 +01:00
}
},
{
title: 'API - videos list',
path: '/api/v1/videos',
2021-03-30 08:57:17 +02:00
expecter: (body, status) => {
return status === 200 && body.startsWith('{"total":10')
2021-02-22 15:34:32 +01:00
}
},
{
title: 'API - video get',
path: '/api/v1/videos/' + video.uuid,
2021-03-30 08:57:17 +02:00
expecter: (body, status) => {
return status === 200 && body.startsWith('{"id":')
2021-02-22 15:34:32 +01:00
}
},
{
title: 'API - video captions',
path: '/api/v1/videos/' + video.uuid + '/captions',
2021-03-30 08:57:17 +02:00
expecter: (body, status) => {
return status === 200 && body.startsWith('{"total":4')
2021-02-22 15:34:32 +01:00
}
},
{
title: 'API - video threads',
path: '/api/v1/videos/' + video.uuid + '/comment-threads',
2021-03-30 08:57:17 +02:00
expecter: (body, status) => {
return status === 200 && body.startsWith('{"total":10')
2021-02-22 15:34:32 +01:00
}
},
{
title: 'API - video replies',
path: '/api/v1/videos/' + video.uuid + '/comment-threads/' + threadId,
2021-03-30 08:57:17 +02:00
expecter: (body, status) => {
return status === 200 && body.startsWith('{"comment":{')
2021-02-22 15:34:32 +01:00
}
},
{
title: 'HTML - video watch',
path: '/videos/watch/' + video.uuid,
2021-03-30 08:57:17 +02:00
expecter: (body, status) => {
return status === 200 && body.includes('<title>my super')
2021-02-22 15:34:32 +01:00
}
},
2021-02-25 16:23:30 +01:00
{
title: 'HTML - video embed',
path: '/videos/embed/' + video.uuid,
2021-03-30 08:57:17 +02:00
expecter: (body, status) => {
return status === 200 && body.includes('embed')
2021-02-25 16:23:30 +01:00
}
},
2021-02-22 15:34:32 +01:00
{
title: 'HTML - homepage',
path: '/',
2021-03-30 08:57:17 +02:00
expecter: (_body, status) => {
return status === 200
2021-02-22 15:34:32 +01:00
}
},
{
title: 'API - config',
path: '/api/v1/config',
2021-03-30 08:57:17 +02:00
expecter: (body, status) => {
2021-10-14 11:35:43 +02:00
return status === 200 && body.startsWith('{"client":')
2021-02-22 15:34:32 +01:00
}
},
{
title: 'API - views with token',
method: 'PUT',
headers: {
...buildAuthorizationHeader(),
...buildJSONHeader()
},
body: JSON.stringify({ currentTime: 2 }),
path: '/api/v1/videos/' + video.uuid + '/views',
expecter: (body, status) => {
return status === 204
}
},
{
title: 'API - views without token',
method: 'POST',
headers: buildJSONHeader(),
body: JSON.stringify({ currentTime: 2 }),
path: '/api/v1/videos/' + video.uuid + '/views',
expecter: (body, status) => {
return status === 204
}
2021-02-22 15:34:32 +01:00
}
2022-02-28 15:19:44 +01:00
].filter(t => {
if (!options.grep) return true
return t.title.includes(options.grep)
})
2021-02-22 15:34:32 +01: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 14:22:33 +02:00
console.log(printResult(testResult))
2021-02-22 15:34:32 +01:00
}
if (outfile) await writeJson(outfile, finalResult)
}
function runBenchmark (options: {
path: string
method?: string
body?: string
2021-02-22 15:34:32 +01:00
headers?: { [ id: string ]: string }
expecter: Function
}) {
2022-03-21 08:24:07 +01:00
const { method = 'GET', path, body, expecter, headers } = options
2021-02-22 15:34:32 +01:00
return new Promise((res, rej) => {
2021-03-30 08:57:17 +02:00
autocannon({
2021-02-22 15:34:32 +01:00
url: server.url + path,
2022-07-13 11:58:01 +02:00
method,
body,
2021-02-22 15:34:32 +01:00
connections: 20,
headers,
pipelining: 1,
2021-03-30 08:57:17 +02: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 15:34:32 +01:00
}, (err, result) => {
if (err) return rej(err)
return res(result)
})
})
}
async function prepare () {
servers = await createMultipleServers(3, {
2021-02-22 15:34:32 +01:00
rates_limit: {
api: {
max: 5_000_000
2023-07-27 14:18:59 +02:00
},
login: {
max: 5_000_000
},
signup: {
max: 5_000_000
},
ask_send_email: {
max: 5_000_000
},
receive_client_log: {
max: 5_000_000
},
plugins: {
max: 5_000_000
},
well_known: {
max: 5_000_000
},
feeds: {
max: 5_000_000
},
activity_pub: {
max: 5_000_000
},
client: {
max: 5_000_000
2021-02-22 15:34:32 +01:00
}
}
})
server = servers[0]
await setAccessTokensToServers(servers)
await doubleFollow(servers[0], servers[1])
await doubleFollow(servers[0], servers[2])
2021-02-22 15:34:32 +01:00
2021-07-15 10:02:54 +02:00
const attributes = {
2021-02-22 15:34:32 +01:00
name: 'my super video',
category: 2,
nsfw: true,
licence: 6,
language: 'fr',
privacy: VideoPrivacy.PUBLIC,
support: 'please give me a coffee',
2022-03-08 11:34:15 +01:00
description: 'my super description\n'.repeat(10) + ' * list1\n * list 2\n * list 3',
2021-02-22 15:34:32 +01:00
tags: [ 'tag1', 'tag2', 'tag3' ]
}
for (let i = 0; i < 10; i++) {
2021-07-16 09:04:35 +02:00
await server.videos.upload({ attributes: { ...attributes, name: 'my super video ' + i } })
2021-02-22 15:34:32 +01:00
}
2021-07-16 09:04:35 +02:00
const { data } = await server.videos.list()
2021-07-15 10:02:54 +02:00
video = data.find(v => v.name === 'my super video 1')
2021-02-22 15:34:32 +01:00
for (let i = 0; i < 10; i++) {
const text = 'my super first comment'
2021-07-16 09:04:35 +02:00
const created = await server.comments.createThread({ videoId: video.id, text })
2021-07-09 14:15:11 +02:00
threadId = created.id
2021-02-22 15:34:32 +01:00
const text1 = 'my super answer to thread 1'
2021-07-16 09:04:35 +02:00
const child = await server.comments.addReply({ videoId: video.id, toCommentId: threadId, text: text1 })
2021-02-22 15:34:32 +01:00
const text2 = 'my super answer to answer of thread 1'
2021-07-16 09:04:35 +02:00
await server.comments.addReply({ videoId: video.id, toCommentId: child.id, text: text2 })
2021-02-22 15:34:32 +01:00
const text3 = 'my second answer to thread 1'
2021-07-16 09:04:35 +02:00
await server.comments.addReply({ videoId: video.id, toCommentId: threadId, text: text3 })
2021-02-22 15:34:32 +01:00
}
for (const caption of [ 'ar', 'fr', 'en', 'zh' ]) {
2021-07-21 13:58:35 +02:00
await server.captions.add({
2021-02-22 15:34:32 +01:00
language: caption,
videoId: video.id,
fixture: 'subtitle-good2.vtt'
})
}
}