]>
Commit | Line | Data |
---|---|---|
09664156 | 1 | import * as program from 'commander' |
09664156 C |
2 | |
3 | // /!\ Before imports /!\ | |
4 | process.env.NODE_ENV = 'test' | |
5 | ||
6 | import { REQUESTS_INTERVAL } from '../../initializers/constants' | |
6d33593a | 7 | import { Video, VideoRateType, VideoFile } from '../../../shared' |
09664156 C |
8 | import { |
9 | ServerInfo as DefaultServerInfo, | |
10 | flushAndRunMultipleServers, | |
11 | setAccessTokensToServers, | |
12 | makeFriends, | |
13 | wait, | |
14 | killallServers, | |
15 | flushTests, | |
16 | uploadVideo, | |
17 | getVideosList, | |
18 | updateVideo, | |
19 | removeVideo, | |
20 | getVideo, | |
21 | getAllVideosListBy, | |
22 | getRequestsStats | |
23 | } from '../utils' | |
24 | ||
25 | interface ServerInfo extends DefaultServerInfo { | |
26 | requestsNumber: number | |
27 | } | |
28 | ||
29 | program | |
30 | .option('-c, --create [weight]', 'Weight for creating videos') | |
31 | .option('-r, --remove [weight]', 'Weight for removing videos') | |
32 | .option('-u, --update [weight]', 'Weight for updating videos') | |
33 | .option('-v, --view [weight]', 'Weight for viewing videos') | |
34 | .option('-l, --like [weight]', 'Weight for liking videos') | |
35 | .option('-s, --dislike [weight]', 'Weight for disliking videos') | |
36 | .option('-p, --pods [n]', 'Number of pods to run (3 or 6)', /^3|6$/, 3) | |
37 | .option('-i, --interval-action [interval]', 'Interval in ms for an action') | |
38 | .option('-I, --interval-integrity [interval]', 'Interval in ms for an integrity check') | |
39 | .option('-f, --flush', 'Flush datas on exit') | |
40 | .option('-d, --difference', 'Display difference if integrity is not okay') | |
41 | .parse(process.argv) | |
42 | ||
43 | const createWeight = program['create'] !== undefined ? parseInt(program['create'], 10) : 5 | |
44 | const removeWeight = program['remove'] !== undefined ? parseInt(program['remove'], 10) : 4 | |
45 | const updateWeight = program['update'] !== undefined ? parseInt(program['update'], 10) : 4 | |
46 | const viewWeight = program['view'] !== undefined ? parseInt(program['view'], 10) : 4 | |
47 | const likeWeight = program['like'] !== undefined ? parseInt(program['like'], 10) : 4 | |
48 | const dislikeWeight = program['dislike'] !== undefined ? parseInt(program['dislike'], 10) : 4 | |
49 | const flushAtExit = program['flush'] || false | |
50 | const actionInterval = program['intervalAction'] !== undefined ? parseInt(program['intervalAction'], 10) : 500 | |
51 | const integrityInterval = program['intervalIntegrity'] !== undefined ? parseInt(program['intervalIntegrity'], 10) : 60000 | |
52 | const displayDiffOnFail = program['difference'] || false | |
53 | ||
54 | const numberOfPods = 6 | |
55 | ||
56 | console.log( | |
57 | 'Create weight: %d, update weight: %d, remove weight: %d, view weight: %d, like weight: %d, dislike weight: %d.', | |
58 | createWeight, updateWeight, removeWeight, viewWeight, likeWeight, dislikeWeight | |
59 | ) | |
60 | ||
61 | if (flushAtExit) { | |
62 | console.log('Program will flush data on exit.') | |
63 | } else { | |
64 | console.log('Program will not flush data on exit.') | |
65 | } | |
66 | if (displayDiffOnFail) { | |
67 | console.log('Program will display diff on failure.') | |
68 | } else { | |
69 | console.log('Program will not display diff on failure') | |
70 | } | |
71 | console.log('Interval in ms for each action: %d.', actionInterval) | |
72 | console.log('Interval in ms for each integrity check: %d.', integrityInterval) | |
73 | ||
74 | console.log('Run servers...') | |
75 | ||
76 | start() | |
77 | ||
78 | // ---------------------------------------------------------------------------- | |
79 | ||
80 | async function start () { | |
81 | const servers = await runServers(numberOfPods) | |
82 | ||
83 | process.on('exit', async () => await exitServers(servers, flushAtExit)) | |
84 | process.on('SIGINT', goodbye) | |
85 | process.on('SIGTERM', goodbye) | |
86 | ||
87 | console.log('Servers runned') | |
88 | initializeRequestsPerServer(servers) | |
89 | ||
90 | let checking = false | |
91 | ||
92 | setInterval(async () => { | |
93 | if (checking === true) return | |
94 | ||
95 | const rand = getRandomInt(0, createWeight + updateWeight + removeWeight + viewWeight + likeWeight + dislikeWeight) | |
96 | ||
97 | const numServer = getRandomNumServer(servers) | |
98 | servers[numServer].requestsNumber++ | |
99 | ||
100 | if (rand < createWeight) { | |
101 | await upload(servers, numServer) | |
102 | } else if (rand < createWeight + updateWeight) { | |
103 | await update(servers, numServer) | |
104 | } else if (rand < createWeight + updateWeight + removeWeight) { | |
105 | await remove(servers, numServer) | |
106 | } else if (rand < createWeight + updateWeight + removeWeight + viewWeight) { | |
107 | await view(servers, numServer) | |
108 | } else if (rand < createWeight + updateWeight + removeWeight + viewWeight + likeWeight) { | |
109 | await like(servers, numServer) | |
110 | } else { | |
111 | await dislike(servers, numServer) | |
112 | } | |
113 | }, actionInterval) | |
114 | ||
115 | // The function will check the consistency between servers (should have the same videos with same attributes...) | |
116 | setInterval(function () { | |
117 | if (checking === true) return | |
118 | ||
119 | console.log('Checking integrity...') | |
120 | checking = true | |
121 | ||
122 | const waitingInterval = setInterval(async () => { | |
6d33593a C |
123 | const pendingRequests = await isTherePendingRequests(servers) |
124 | if (pendingRequests === true) { | |
125 | console.log('A server has pending requests, waiting...') | |
09664156 C |
126 | return |
127 | } | |
128 | ||
6d33593a C |
129 | // Even if there are no pending request, wait some potential processes |
130 | await wait(2000) | |
09664156 C |
131 | await checkIntegrity(servers) |
132 | ||
133 | initializeRequestsPerServer(servers) | |
134 | checking = false | |
135 | clearInterval(waitingInterval) | |
136 | }, REQUESTS_INTERVAL) | |
137 | }, integrityInterval) | |
138 | } | |
139 | ||
140 | function initializeRequestsPerServer (servers: ServerInfo[]) { | |
141 | servers.forEach(server => server.requestsNumber = 0) | |
142 | } | |
143 | ||
144 | function getRandomInt (min, max) { | |
145 | return Math.floor(Math.random() * (max - min)) + min | |
146 | } | |
147 | ||
148 | function getRandomNumServer (servers) { | |
149 | return getRandomInt(0, servers.length) | |
150 | } | |
151 | ||
152 | async function runServers (numberOfPods: number) { | |
153 | let servers = null | |
154 | ||
155 | // Run servers | |
156 | servers = await flushAndRunMultipleServers(numberOfPods) | |
157 | ||
158 | // Get the access tokens | |
159 | await setAccessTokensToServers(servers) | |
160 | ||
161 | await makeFriends(servers[1].url, servers[1].accessToken) | |
162 | await makeFriends(servers[0].url, servers[0].accessToken) | |
163 | await wait(1000) | |
164 | ||
165 | await makeFriends(servers[3].url, servers[3].accessToken) | |
166 | await makeFriends(servers[5].url, servers[5].accessToken) | |
167 | await makeFriends(servers[4].url, servers[4].accessToken) | |
168 | ||
169 | await wait(1000) | |
170 | ||
171 | return servers | |
172 | } | |
173 | ||
174 | async function exitServers (servers: ServerInfo[], flushAtExit: boolean) { | |
175 | killallServers(servers) | |
176 | ||
177 | if (flushAtExit) await flushTests() | |
178 | } | |
179 | ||
180 | function upload (servers: ServerInfo[], numServer: number) { | |
181 | console.log('Uploading video to server ' + numServer) | |
182 | ||
183 | const videoAttributes = { | |
184 | name: Date.now() + ' name', | |
185 | category: 4, | |
186 | nsfw: false, | |
187 | licence: 2, | |
188 | language: 1, | |
189 | description: Date.now() + ' description', | |
190 | tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ], | |
191 | fixture: 'video_short1.webm' | |
192 | } | |
193 | return uploadVideo(servers[numServer].url, servers[numServer].accessToken, videoAttributes) | |
194 | } | |
195 | ||
196 | async function update (servers: ServerInfo[], numServer: number) { | |
197 | const res = await getVideosList(servers[numServer].url) | |
198 | ||
199 | const videos = res.body.data.filter(video => video.isLocal === true) | |
200 | if (videos.length === 0) return undefined | |
201 | ||
202 | const toUpdate = videos[getRandomInt(0, videos.length)].id | |
203 | const attributes = { | |
204 | name: Date.now() + ' name', | |
205 | description: Date.now() + ' description', | |
206 | tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ] | |
207 | } | |
208 | ||
209 | console.log('Updating video of server ' + numServer) | |
210 | ||
211 | return updateVideo(servers[numServer].url, servers[numServer].accessToken, toUpdate, attributes) | |
212 | } | |
213 | ||
214 | async function remove (servers: ServerInfo[], numServer: number) { | |
215 | const res = await getVideosList(servers[numServer].url) | |
6d33593a | 216 | const videos = res.body.data.filter(video => video.isLocal === true) |
09664156 C |
217 | if (videos.length === 0) return undefined |
218 | ||
219 | const toRemove = videos[getRandomInt(0, videos.length)].id | |
220 | ||
221 | console.log('Removing video from server ' + numServer) | |
222 | return removeVideo(servers[numServer].url, servers[numServer].accessToken, toRemove) | |
223 | } | |
224 | ||
225 | async function view (servers: ServerInfo[], numServer: number) { | |
226 | const res = await getVideosList(servers[numServer].url) | |
227 | ||
228 | const videos = res.body.data | |
229 | if (videos.length === 0) return undefined | |
230 | ||
231 | const toView = videos[getRandomInt(0, videos.length)].id | |
232 | ||
233 | console.log('Viewing video from server ' + numServer) | |
234 | return getVideo(servers[numServer].url, toView) | |
235 | } | |
236 | ||
237 | function like (servers: ServerInfo[], numServer: number) { | |
238 | return rate(servers, numServer, 'like') | |
239 | } | |
240 | ||
241 | function dislike (servers: ServerInfo[], numServer: number) { | |
242 | return rate(servers, numServer, 'dislike') | |
243 | } | |
244 | ||
245 | async function rate (servers: ServerInfo[], numServer: number, rating: VideoRateType) { | |
246 | const res = await getVideosList(servers[numServer].url) | |
247 | ||
248 | const videos = res.body.data | |
249 | if (videos.length === 0) return undefined | |
250 | ||
251 | const toRate = videos[getRandomInt(0, videos.length)].id | |
252 | ||
253 | console.log('Rating (%s) video from server %d', rating, numServer) | |
254 | return getVideo(servers[numServer].url, toRate) | |
255 | } | |
256 | ||
257 | async function checkIntegrity (servers: ServerInfo[]) { | |
258 | const videos: Video[][] = [] | |
259 | const tasks: Promise<any>[] = [] | |
260 | ||
261 | // Fetch all videos and remove some fields that can differ between pods | |
262 | for (const server of servers) { | |
6d33593a | 263 | const p = getAllVideosListBy(server.url).then(res => videos.push(res.body.data)) |
09664156 C |
264 | tasks.push(p) |
265 | } | |
266 | ||
267 | await Promise.all(tasks) | |
268 | ||
269 | let i = 0 | |
270 | for (const video of videos) { | |
6d33593a C |
271 | const differences = areDifferences(video, videos[0]) |
272 | if (differences !== undefined) { | |
09664156 C |
273 | console.error('Integrity not ok with server %d!', i + 1) |
274 | ||
275 | if (displayDiffOnFail) { | |
6d33593a | 276 | console.log(differences) |
09664156 C |
277 | } |
278 | ||
279 | process.exit(-1) | |
280 | } | |
281 | ||
282 | i++ | |
283 | } | |
284 | ||
285 | console.log('Integrity ok.') | |
286 | } | |
287 | ||
6d33593a C |
288 | function areDifferences (videos1: Video[], videos2: Video[]) { |
289 | // Remove some keys we don't want to compare | |
290 | videos1.concat(videos2).forEach(video => { | |
291 | delete video.id | |
292 | delete video.isLocal | |
293 | delete video.thumbnailPath | |
294 | delete video.updatedAt | |
295 | delete video.views | |
296 | }) | |
297 | ||
298 | if (videos1.length !== videos2.length) { | |
299 | return `Videos length are different (${videos1.length}/${videos2.length}).` | |
300 | } | |
301 | ||
302 | for (const video1 of videos1) { | |
303 | const video2 = videos2.find(video => video.uuid === video1.uuid) | |
304 | ||
305 | if (!video2) return 'Video ' + video1.uuid + ' is missing.' | |
306 | ||
307 | for (const videoKey of Object.keys(video1)) { | |
308 | const attribute1 = video1[videoKey] | |
309 | const attribute2 = video2[videoKey] | |
310 | ||
311 | if (videoKey === 'tags') { | |
312 | if (attribute1.length !== attribute2.length) { | |
313 | return 'Tags are different.' | |
314 | } | |
315 | ||
316 | attribute1.forEach(tag1 => { | |
317 | if (attribute2.indexOf(tag1) === -1) { | |
318 | return 'Tag ' + tag1 + ' is missing.' | |
319 | } | |
320 | }) | |
321 | } else if (videoKey === 'files') { | |
322 | if (attribute1.length !== attribute2.length) { | |
323 | return 'Video files are different.' | |
324 | } | |
325 | ||
326 | attribute1.forEach((videoFile1: VideoFile) => { | |
327 | const videoFile2: VideoFile = attribute2.find(videoFile => videoFile.magnetUri === videoFile1.magnetUri) | |
328 | if (!videoFile2) { | |
329 | return `Video ${video1.uuid} has missing video file ${videoFile1.magnetUri}.` | |
330 | } | |
331 | ||
332 | if (videoFile1.size !== videoFile2.size || videoFile1.resolutionLabel !== videoFile2.resolutionLabel) { | |
333 | return `Video ${video1.uuid} has different video file ${videoFile1.magnetUri}.` | |
334 | } | |
335 | }) | |
336 | } else { | |
337 | if (attribute1 !== attribute2) { | |
338 | return `Video ${video1.uuid} has different value for attribute ${videoKey}.` | |
339 | } | |
340 | } | |
341 | } | |
342 | } | |
343 | ||
344 | return undefined | |
345 | } | |
346 | ||
09664156 C |
347 | function goodbye () { |
348 | return process.exit(-1) | |
349 | } | |
350 | ||
6d33593a | 351 | async function isTherePendingRequests (servers: ServerInfo[]) { |
09664156 | 352 | const tasks: Promise<any>[] = [] |
6d33593a | 353 | let pendingRequests = false |
09664156 | 354 | |
6d33593a | 355 | // Check if each server has pending request |
09664156 C |
356 | for (const server of servers) { |
357 | const p = getRequestsStats(server).then(res => { | |
358 | const stats = res.body | |
359 | ||
360 | if ( | |
361 | stats.requestScheduler.totalRequests !== 0 || | |
362 | stats.requestVideoEventScheduler.totalRequests !== 0 || | |
363 | stats.requestVideoQaduScheduler.totalRequests !== 0 | |
364 | ) { | |
6d33593a | 365 | pendingRequests = true |
09664156 C |
366 | } |
367 | }) | |
368 | ||
369 | tasks.push(p) | |
370 | } | |
371 | ||
372 | await Promise.all(tasks) | |
373 | ||
6d33593a | 374 | return pendingRequests |
09664156 | 375 | } |