|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- import autocannon, { printResult } from 'autocannon'
- 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'
-
- let servers: PeerTubeServer[]
- // First server
- let server: PeerTubeServer
- let video: Video
- let threadId: number
-
- 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
-
- run()
- .catch(err => console.error(err))
- .finally(() => {
- if (servers) return killallServers(servers)
- })
-
- function buildAuthorizationHeader () {
- return {
- Authorization: 'Bearer ' + server.accessToken
- }
- }
-
- function buildAPHeader () {
- return {
- Accept: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
- }
- }
-
- function buildJSONHeader () {
- return {
- 'Content-Type': 'application/json'
- }
- }
-
- async function run () {
- console.log('Preparing server...')
-
- await prepare()
-
- const tests = [
- {
- title: 'AP - account peertube',
- path: '/accounts/peertube',
- headers: buildAPHeader(),
- expecter: (body, status) => {
- return status === 200 && body.startsWith('{"@context":')
- }
- },
- {
- title: 'AP - video',
- path: '/videos/watch/' + video.uuid,
- headers: buildAPHeader(),
- expecter: (body, status) => {
- return status === 200 && body.startsWith('{"@context":')
- }
- },
- {
- title: 'Misc - webfinger peertube',
- path: '/.well-known/webfinger?resource=acct:peertube@' + server.host,
- expecter: (body, status) => {
- return status === 200 && body.startsWith('{"subject":')
- }
- },
- {
- title: 'API - unread notifications',
- path: '/api/v1/users/me/notifications?start=0&count=0&unread=true',
- headers: buildAuthorizationHeader(),
- expecter: (_body, status) => {
- return status === 200
- }
- },
- {
- title: 'API - me',
- path: '/api/v1/users/me',
- headers: buildAuthorizationHeader(),
- expecter: (body, status) => {
- return status === 200 && body.startsWith('{"id":')
- }
- },
- {
- title: 'API - videos list',
- path: '/api/v1/videos',
- expecter: (body, status) => {
- return status === 200 && body.startsWith('{"total":10')
- }
- },
- {
- title: 'API - video get',
- path: '/api/v1/videos/' + video.uuid,
- expecter: (body, status) => {
- return status === 200 && body.startsWith('{"id":')
- }
- },
- {
- title: 'API - video captions',
- path: '/api/v1/videos/' + video.uuid + '/captions',
- expecter: (body, status) => {
- return status === 200 && body.startsWith('{"total":4')
- }
- },
- {
- title: 'API - video threads',
- path: '/api/v1/videos/' + video.uuid + '/comment-threads',
- expecter: (body, status) => {
- return status === 200 && body.startsWith('{"total":10')
- }
- },
- {
- title: 'API - video replies',
- path: '/api/v1/videos/' + video.uuid + '/comment-threads/' + threadId,
- expecter: (body, status) => {
- return status === 200 && body.startsWith('{"comment":{')
- }
- },
- {
- title: 'HTML - video watch',
- path: '/videos/watch/' + video.uuid,
- expecter: (body, status) => {
- return status === 200 && body.includes('<title>my super')
- }
- },
- {
- title: 'HTML - video embed',
- path: '/videos/embed/' + video.uuid,
- expecter: (body, status) => {
- return status === 200 && body.includes('embed')
- }
- },
- {
- title: 'HTML - homepage',
- path: '/',
- expecter: (_body, status) => {
- return status === 200
- }
- },
- {
- title: 'API - config',
- path: '/api/v1/config',
- expecter: (body, status) => {
- return status === 200 && body.startsWith('{"client":')
- }
- },
- {
- 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
- }
- }
- ].filter(t => {
- if (!options.grep) return true
-
- return t.title.includes(options.grep)
- })
-
- 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)
-
- console.log(printResult(testResult))
- }
-
- if (outfile) await writeJson(outfile, finalResult)
- }
-
- function runBenchmark (options: {
- path: string
- method?: string
- body?: string
- headers?: { [ id: string ]: string }
- expecter: Function
- }) {
- const { method = 'GET', path, body, expecter, headers } = options
-
- return new Promise((res, rej) => {
- autocannon({
- url: server.url + path,
- method,
- body,
- connections: 20,
- headers,
- pipelining: 1,
- duration: 10,
- requests: [
- {
- onResponse: (status, body) => {
- if (expecter(body, status) !== true) {
- console.error('Expected result failed.', { body, status })
- throw new Error('Invalid expectation')
- }
- }
- }
- ]
- }, (err, result) => {
- if (err) return rej(err)
-
- return res(result)
- })
- })
- }
-
- async function prepare () {
- servers = await createMultipleServers(3, {
- rates_limit: {
- api: {
- max: 5_000_000
- },
- 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
- }
- }
- }, { nodeArgs: [ '--inspect' ] })
- server = servers[0]
-
- await setAccessTokensToServers(servers)
- await doubleFollow(servers[0], servers[1])
- await doubleFollow(servers[0], servers[2])
-
- const attributes = {
- 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\n'.repeat(10) + ' * list1\n * list 2\n * list 3',
- tags: [ 'tag1', 'tag2', 'tag3' ]
- }
-
- for (let i = 0; i < 10; i++) {
- await server.videos.upload({ attributes: { ...attributes, name: 'my super video ' + i } })
- }
-
- const { data } = await server.videos.list()
- video = data.find(v => v.name === 'my super video 1')
-
- for (let i = 0; i < 10; i++) {
- const text = 'my super first comment'
- const created = await server.comments.createThread({ videoId: video.id, text })
- threadId = created.id
-
- const text1 = 'my super answer to thread 1'
- const child = await server.comments.addReply({ videoId: video.id, toCommentId: threadId, text: text1 })
-
- const text2 = 'my super answer to answer of thread 1'
- await server.comments.addReply({ videoId: video.id, toCommentId: child.id, text: text2 })
-
- const text3 = 'my second answer to thread 1'
- await server.comments.addReply({ videoId: video.id, toCommentId: threadId, text: text3 })
- }
-
- for (const caption of [ 'ar', 'fr', 'en', 'zh' ]) {
- await server.captions.add({
- language: caption,
- videoId: video.id,
- fixture: 'subtitle-good2.vtt'
- })
- }
- }
|