]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - scripts/benchmark.ts
Trigger test build for any branch
[github/Chocobozzz/PeerTube.git] / scripts / benchmark.ts
1 import { registerTSPaths } from '../server/helpers/register-ts-paths'
2 registerTSPaths()
3
4 import * as autocannon from 'autocannon'
5 import {
6 addVideoCommentReply,
7 addVideoCommentThread,
8 flushAndRunServer,
9 getVideosList,
10 killallServers,
11 ServerInfo,
12 setAccessTokensToServers,
13 uploadVideo
14 } from '@shared/extra-utils'
15 import { Video, VideoPrivacy } from '@shared/models'
16 import { writeJson } from 'fs-extra'
17
18 let server: ServerInfo
19 let video: Video
20 let threadId: number
21
22 const outfile = process.argv[2]
23
24 run()
25 .catch(err => console.error(err))
26 .finally(() => {
27 if (server) killallServers([ server ])
28 })
29
30 function buildAuthorizationHeader () {
31 return {
32 Authorization: 'Bearer ' + server.accessToken
33 }
34 }
35
36 function buildAPHeader () {
37 return {
38 Accept: 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
39 }
40 }
41
42 async function run () {
43 console.log('Preparing server...')
44
45 await prepare()
46
47 const tests = [
48 {
49 title: 'AP - account peertube',
50 path: '/accounts/peertube',
51 headers: buildAPHeader(),
52 expecter: (body, status) => {
53 return status === 200 && body.startsWith('{"type":')
54 }
55 },
56 {
57 title: 'AP - video',
58 path: '/videos/watch/' + video.uuid,
59 headers: buildAPHeader(),
60 expecter: (body, status) => {
61 return status === 200 && body.startsWith('{"type":"Video"')
62 }
63 },
64 {
65 title: 'Misc - webfinger peertube',
66 path: '/.well-known/webfinger?resource=acct:peertube@' + server.host,
67 expecter: (body, status) => {
68 return status === 200 && body.startsWith('{"subject":')
69 }
70 },
71 {
72 title: 'API - unread notifications',
73 path: '/api/v1/users/me/notifications?start=0&count=0&unread=true',
74 headers: buildAuthorizationHeader(),
75 expecter: (_body, status) => {
76 return status === 200
77 }
78 },
79 {
80 title: 'API - me',
81 path: '/api/v1/users/me',
82 headers: buildAuthorizationHeader(),
83 expecter: (body, status) => {
84 return status === 200 && body.startsWith('{"id":')
85 }
86 },
87 {
88 title: 'API - videos list',
89 path: '/api/v1/videos',
90 expecter: (body, status) => {
91 return status === 200 && body.startsWith('{"total":10')
92 }
93 },
94 {
95 title: 'API - video get',
96 path: '/api/v1/videos/' + video.uuid,
97 expecter: (body, status) => {
98 return status === 200 && body.startsWith('{"id":')
99 }
100 },
101 {
102 title: 'API - video captions',
103 path: '/api/v1/videos/' + video.uuid + '/captions',
104 expecter: (body, status) => {
105 return status === 200 && body.startsWith('{"total":4')
106 }
107 },
108 {
109 title: 'API - video threads',
110 path: '/api/v1/videos/' + video.uuid + '/comment-threads',
111 expecter: (body, status) => {
112 return status === 200 && body.startsWith('{"total":10')
113 }
114 },
115 {
116 title: 'API - video replies',
117 path: '/api/v1/videos/' + video.uuid + '/comment-threads/' + threadId,
118 expecter: (body, status) => {
119 return status === 200 && body.startsWith('{"comment":{')
120 }
121 },
122 {
123 title: 'HTML - video watch',
124 path: '/videos/watch/' + video.uuid,
125 expecter: (body, status) => {
126 return status === 200 && body.includes('<title>my super')
127 }
128 },
129 {
130 title: 'HTML - video embed',
131 path: '/videos/embed/' + video.uuid,
132 expecter: (body, status) => {
133 return status === 200 && body.includes('embed')
134 }
135 },
136 {
137 title: 'HTML - homepage',
138 path: '/',
139 expecter: (_body, status) => {
140 return status === 200
141 }
142 },
143 {
144 title: 'API - config',
145 path: '/api/v1/config',
146 expecter: (body, status) => {
147 return status === 200 && body.startsWith('{"instance":')
148 }
149 }
150 ]
151
152 const finalResult: any[] = []
153
154 for (const test of tests) {
155 console.log('Running against %s.', test.path)
156 const testResult = await runBenchmark(test)
157
158 Object.assign(testResult, { title: test.title, path: test.path })
159 finalResult.push(testResult)
160
161 console.log(autocannon.printResult(testResult))
162 }
163
164 if (outfile) await writeJson(outfile, finalResult)
165 }
166
167 function runBenchmark (options: {
168 path: string
169 headers?: { [ id: string ]: string }
170 expecter: Function
171 }) {
172 const { path, expecter, headers } = options
173
174 return new Promise((res, rej) => {
175 autocannon({
176 url: server.url + path,
177 connections: 20,
178 headers,
179 pipelining: 1,
180 duration: 10,
181 requests: [
182 {
183 onResponse: (status, body) => {
184 if (expecter(body, status) !== true) {
185 console.error('Expected result failed.', { body, status })
186 throw new Error('Invalid expectation')
187 }
188 }
189 }
190 ]
191 }, (err, result) => {
192 if (err) return rej(err)
193
194 return res(result)
195 })
196 })
197 }
198
199 async function prepare () {
200 server = await flushAndRunServer(1, {
201 rates_limit: {
202 api: {
203 max: 5_000_000
204 }
205 }
206 })
207 await setAccessTokensToServers([ server ])
208
209 const videoAttributes = {
210 name: 'my super video',
211 category: 2,
212 nsfw: true,
213 licence: 6,
214 language: 'fr',
215 privacy: VideoPrivacy.PUBLIC,
216 support: 'please give me a coffee',
217 description: 'my super description'.repeat(10),
218 tags: [ 'tag1', 'tag2', 'tag3' ]
219 }
220
221 for (let i = 0; i < 10; i++) {
222 Object.assign(videoAttributes, { name: 'my super video ' + i })
223 await uploadVideo(server.url, server.accessToken, videoAttributes)
224 }
225
226 const resVideos = await getVideosList(server.url)
227 video = resVideos.body.data.find(v => v.name === 'my super video 1')
228
229 for (let i = 0; i < 10; i++) {
230 const text = 'my super first comment'
231 const res = await addVideoCommentThread(server.url, server.accessToken, video.id, text)
232 threadId = res.body.comment.id
233
234 const text1 = 'my super answer to thread 1'
235 const childCommentRes = await addVideoCommentReply(server.url, server.accessToken, video.id, threadId, text1)
236 const childCommentId = childCommentRes.body.comment.id
237
238 const text2 = 'my super answer to answer of thread 1'
239 await addVideoCommentReply(server.url, server.accessToken, video.id, childCommentId, text2)
240
241 const text3 = 'my second answer to thread 1'
242 await addVideoCommentReply(server.url, server.accessToken, video.id, threadId, text3)
243 }
244
245 for (const caption of [ 'ar', 'fr', 'en', 'zh' ]) {
246 await server.captionsCommand.createVideoCaption({
247 language: caption,
248 videoId: video.id,
249 fixture: 'subtitle-good2.vtt'
250 })
251 }
252
253 return { server, video, threadId }
254 }