]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/real-world/real-world.js
Add link to wiki for production installation
[github/Chocobozzz/PeerTube.git] / server / tests / real-world / real-world.js
CommitLineData
8f68c31a
C
1'use strict'
2
46132744 3const each = require('async/each')
8f68c31a 4const isEqual = require('lodash/isEqual')
bb0b243c 5const differenceWith = require('lodash/differenceWith')
1a42c9e2
C
6const program = require('commander')
7const series = require('async/series')
8f68c31a
C
8
9process.env.NODE_ENV = 'test'
10const constants = require('../../initializers/constants')
11
46132744
C
12const loginUtils = require('../utils/login')
13const podsUtils = require('../utils/pods')
14const serversUtils = require('../utils/servers')
15const videosUtils = require('../utils/videos')
f148e5ed 16const requestStatsUtils = require('../utils/requests-stats')
8f68c31a
C
17
18program
19 .option('-c, --create [weight]', 'Weight for creating videos')
20 .option('-r, --remove [weight]', 'Weight for removing videos')
f2cdb866 21 .option('-u, --update [weight]', 'Weight for updating videos')
f148e5ed
C
22 .option('-v, --view [weight]', 'Weight for viewing videos')
23 .option('-l, --like [weight]', 'Weight for liking videos')
24 .option('-s --dislike [weight]', 'Weight for disliking videos')
8f68c31a
C
25 .option('-p, --pods [n]', 'Number of pods to run (3 or 6)', /^3|6$/, 3)
26 .option('-a, --action [interval]', 'Interval in ms for an action')
27 .option('-i, --integrity [interval]', 'Interval in ms for an integrity check')
28 .option('-f, --flush', 'Flush datas on exit')
bb0b243c 29 .option('-d, --difference', 'Display difference if integrity is not okay')
8f68c31a
C
30 .parse(process.argv)
31
bb0b243c
C
32const createWeight = program.create !== undefined ? parseInt(program.create) : 5
33const removeWeight = program.remove !== undefined ? parseInt(program.remove) : 4
f2cdb866 34const updateWeight = program.update !== undefined ? parseInt(program.update) : 4
f148e5ed
C
35const viewWeight = program.view !== undefined ? parseInt(program.view) : 4
36const likeWeight = program.like !== undefined ? parseInt(program.like) : 4
37const dislikeWeight = program.dislike !== undefined ? parseInt(program.dislike) : 4
8f68c31a 38const flushAtExit = program.flush || false
bb0b243c 39const actionInterval = program.action !== undefined ? parseInt(program.action) : 500
790e65fc 40const integrityInterval = program.integrity !== undefined ? parseInt(program.integrity) : 60000
bb0b243c 41const displayDiffOnFail = program.integrity || false
8f68c31a
C
42
43const numberOfPods = 6
bb0b243c 44
f148e5ed 45console.log('Create weight: %d, update weight: %d, remove weight: %d, view weight: %d, like weight: %d, dislike weight: %d.', createWeight, updateWeight, removeWeight, viewWeight, likeWeight, dislikeWeight)
8f68c31a
C
46if (flushAtExit) {
47 console.log('Program will flush data on exit.')
48} else {
49 console.log('Program will not flush data on exit.')
50}
bb0b243c
C
51if (displayDiffOnFail) {
52 console.log('Program will display diff on failure.')
53} else {
54 console.log('Program will not display diff on failure')
55}
8f68c31a
C
56console.log('Interval in ms for each action: %d.', actionInterval)
57console.log('Interval in ms for each integrity check: %d.', integrityInterval)
8f68c31a
C
58
59console.log('Run servers...')
60runServers(numberOfPods, function (err, servers) {
61 if (err) throw err
62
63 process.on('exit', function () {
64 exitServers(servers, flushAtExit)
65 })
66 process.on('SIGINT', goodbye)
67 process.on('SIGTERM', goodbye)
68
69 console.log('Servers runned')
f148e5ed 70 initializeRequestsPerServer(servers)
8f68c31a
C
71
72 let checking = false
73
74 setInterval(function () {
75 if (checking === true) return
76
f148e5ed
C
77 const rand = getRandomInt(0, createWeight + updateWeight + removeWeight + viewWeight + likeWeight + dislikeWeight)
78
79 const numServer = getRandomNumServer(servers)
80 servers[numServer].requestsNumber++
8f68c31a
C
81
82 if (rand < createWeight) {
f148e5ed 83 upload(servers, numServer)
f2cdb866 84 } else if (rand < createWeight + updateWeight) {
f148e5ed
C
85 update(servers, numServer)
86 } else if (rand < createWeight + updateWeight + removeWeight) {
87 remove(servers, numServer)
88 } else if (rand < createWeight + updateWeight + removeWeight + viewWeight) {
89 view(servers, numServer)
90 } else if (rand < createWeight + updateWeight + removeWeight + viewWeight + likeWeight) {
91 like(servers, numServer)
8f68c31a 92 } else {
f148e5ed 93 dislike(servers, numServer)
8f68c31a
C
94 }
95 }, actionInterval)
96
f148e5ed 97 // The function will check the consistency between servers (should have the same videos with same attributes...)
8f68c31a 98 setInterval(function () {
bb0b243c
C
99 if (checking === true) return
100
8f68c31a
C
101 console.log('Checking integrity...')
102 checking = true
103
f148e5ed
C
104 const waitingInterval = setInterval(function () {
105 isThereAwaitingRequests(servers, function (res) {
106 if (res === true) {
107 console.log('A server has awaiting requests, waiting...')
108 return
109 }
110
111 checkIntegrity(servers, function () {
112 initializeRequestsPerServer(servers)
113 checking = false
114 clearInterval(waitingInterval)
115 })
8f68c31a 116 })
f148e5ed 117 }, constants.REQUESTS_INTERVAL)
8f68c31a
C
118 }, integrityInterval)
119})
120
121// ----------------------------------------------------------------------------
122
f148e5ed
C
123function initializeRequestsPerServer (servers) {
124 servers.forEach(function (server) {
125 server.requestsNumber = 0
126 })
127}
128
8f68c31a
C
129function getRandomInt (min, max) {
130 return Math.floor(Math.random() * (max - min)) + min
131}
132
133function getRandomNumServer (servers) {
134 return getRandomInt(0, servers.length)
135}
136
137function runServers (numberOfPods, callback) {
138 let servers = null
139
1a42c9e2 140 series([
8f68c31a
C
141 // Run servers
142 function (next) {
46132744 143 serversUtils.flushAndRunMultipleServers(numberOfPods, function (serversRun) {
8f68c31a
C
144 servers = serversRun
145 next()
146 })
147 },
148 // Get the access tokens
149 function (next) {
1a42c9e2 150 each(servers, function (server, callbackEach) {
46132744 151 loginUtils.loginAndGetAccessToken(server, function (err, accessToken) {
8f68c31a
C
152 if (err) return callbackEach(err)
153
154 server.accessToken = accessToken
155 callbackEach()
156 })
157 }, next)
158 },
159 function (next) {
160 const server = servers[1]
46132744 161 podsUtils.makeFriends(server.url, server.accessToken, next)
8f68c31a
C
162 },
163 function (next) {
164 const server = servers[0]
46132744 165 podsUtils.makeFriends(server.url, server.accessToken, next)
8f68c31a
C
166 },
167 function (next) {
168 setTimeout(next, 1000)
169 },
170 function (next) {
171 const server = servers[3]
46132744 172 podsUtils.makeFriends(server.url, server.accessToken, next)
8f68c31a
C
173 },
174 function (next) {
175 const server = servers[5]
46132744 176 podsUtils.makeFriends(server.url, server.accessToken, next)
8f68c31a
C
177 },
178 function (next) {
179 const server = servers[4]
46132744 180 podsUtils.makeFriends(server.url, server.accessToken, next)
8f68c31a
C
181 },
182 function (next) {
183 setTimeout(next, 1000)
184 }
185 ], function (err) {
186 return callback(err, servers)
187 })
188}
189
190function exitServers (servers, callback) {
191 if (!callback) callback = function () {}
192
193 servers.forEach(function (server) {
194 if (server.app) process.kill(-server.app.pid)
195 })
196
46132744 197 if (flushAtExit) serversUtils.flushTests(callback)
8f68c31a
C
198}
199
200function upload (servers, numServer, callback) {
201 if (!callback) callback = function () {}
202
f148e5ed 203 console.log('Uploading video to server ' + numServer)
8f68c31a 204
b4c5ac97
C
205 const videoAttributes = {
206 name: Date.now() + ' name',
207 category: 4,
31b59b47 208 nsfw: false,
6f0c39e2 209 licence: 2,
b4c5ac97
C
210 description: Date.now() + ' description',
211 tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ],
212 fixture: 'video_short1.webm'
213 }
214 videosUtils.uploadVideo(servers[numServer].url, servers[numServer].accessToken, videoAttributes, callback)
8f68c31a
C
215}
216
f2cdb866
C
217function update (servers, numServer, callback) {
218 if (!callback) callback = function () {}
219
220 videosUtils.getVideosList(servers[numServer].url, function (err, res) {
221 if (err) throw err
222
223 const videos = res.body.data.filter(function (video) { return video.isLocal })
224 if (videos.length === 0) return callback()
225
226 const toUpdate = videos[getRandomInt(0, videos.length)].id
b4c5ac97
C
227 const attributes = {
228 name: Date.now() + ' name',
229 description: Date.now() + ' description',
230 tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ]
231 }
f2cdb866
C
232
233 console.log('Updating video of server ' + numServer)
234
b4c5ac97 235 videosUtils.updateVideo(servers[numServer].url, servers[numServer].accessToken, toUpdate, attributes, callback)
f2cdb866
C
236 })
237}
238
8f68c31a
C
239function remove (servers, numServer, callback) {
240 if (!callback) callback = function () {}
241
46132744 242 videosUtils.getVideosList(servers[numServer].url, function (err, res) {
8f68c31a
C
243 if (err) throw err
244
245 const videos = res.body.data
246 if (videos.length === 0) return callback()
247
248 const toRemove = videos[getRandomInt(0, videos.length)].id
249
250 console.log('Removing video from server ' + numServer)
46132744 251 videosUtils.removeVideo(servers[numServer].url, servers[numServer].accessToken, toRemove, callback)
8f68c31a
C
252 })
253}
254
f148e5ed
C
255function view (servers, numServer, callback) {
256 if (!callback) callback = function () {}
257
258 videosUtils.getVideosList(servers[numServer].url, function (err, res) {
259 if (err) throw err
260
261 const videos = res.body.data
262 if (videos.length === 0) return callback()
263
264 const toView = videos[getRandomInt(0, videos.length)].id
265
266 console.log('Viewing video from server ' + numServer)
267 videosUtils.getVideo(servers[numServer].url, toView, callback)
268 })
269}
270
271function like (servers, numServer, callback) {
272 rate(servers, numServer, 'like', callback)
273}
274
275function dislike (servers, numServer, callback) {
276 rate(servers, numServer, 'dislike', callback)
277}
278
279function rate (servers, numServer, rating, callback) {
280 if (!callback) callback = function () {}
281
282 videosUtils.getVideosList(servers[numServer].url, function (err, res) {
283 if (err) throw err
284
285 const videos = res.body.data
286 if (videos.length === 0) return callback()
287
288 const toRate = videos[getRandomInt(0, videos.length)].id
289
290 console.log('Rating (%s) video from server %d', rating, numServer)
291 videosUtils.getVideo(servers[numServer].url, toRate, callback)
292 })
293}
294
8f68c31a
C
295function checkIntegrity (servers, callback) {
296 const videos = []
1a42c9e2 297 each(servers, function (server, callback) {
46132744 298 videosUtils.getAllVideosListBy(server.url, function (err, res) {
8f68c31a
C
299 if (err) throw err
300 const serverVideos = res.body.data
301 for (const serverVideo of serverVideos) {
302 delete serverVideo.id
303 delete serverVideo.isLocal
304 delete serverVideo.thumbnailPath
bb0b243c 305 delete serverVideo.updatedAt
f148e5ed 306 delete serverVideo.views
8f68c31a
C
307 }
308
309 videos.push(serverVideos)
310 callback()
311 })
312 }, function () {
f148e5ed
C
313 let i = 0
314
8f68c31a
C
315 for (const video of videos) {
316 if (!isEqual(video, videos[0])) {
f148e5ed 317 console.error('Integrity not ok with server %d!', i + 1)
56ac84d0 318
bb0b243c
C
319 if (displayDiffOnFail) {
320 console.log(differenceWith(videos[0], video, isEqual))
f148e5ed 321 console.log(differenceWith(video, videos[0], isEqual))
bb0b243c
C
322 }
323
8f68c31a
C
324 process.exit(-1)
325 }
f148e5ed
C
326
327 i++
8f68c31a
C
328 }
329
330 console.log('Integrity ok.')
331 return callback()
332 })
333}
334
335function goodbye () {
336 return process.exit(-1)
337}
f148e5ed
C
338
339function isThereAwaitingRequests (servers, callback) {
340 let noRequests = true
341
342 // Check is each server has awaiting requestq
343 each(servers, function (server, callbackEach) {
344 requestStatsUtils.getRequestsStats(server, server.accessToken, function (err, res) {
345 if (err) throw err
346
347 const stats = res.body
348
349 if (
350 stats.requestScheduler.totalRequests !== 0 ||
351 stats.requestVideoEventScheduler.totalRequests !== 0 ||
352 stats.requestVideoQaduScheduler.totalRequests !== 0
353 ) {
354 noRequests = false
355 }
356
357 callbackEach()
358 })
359 }, function (err) {
360 if (err) throw err
361
362 return callback(noRequests === false)
363 })
364}