]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tests/api/server/redundancy.ts
Merge branch 'develop' into cli-wrapper
[github/Chocobozzz/PeerTube.git] / server / tests / api / server / redundancy.ts
1 /* tslint:disable:no-unused-expression */
2
3 import * as chai from 'chai'
4 import 'mocha'
5 import { VideoDetails } from '../../../../shared/models/videos'
6 import {
7 doubleFollow,
8 flushAndRunMultipleServers,
9 getFollowingListPaginationAndSort,
10 getVideo,
11 immutableAssign,
12 killallServers,
13 root,
14 ServerInfo,
15 setAccessTokensToServers,
16 uploadVideo,
17 viewVideo,
18 wait
19 } from '../../utils'
20 import { waitJobs } from '../../utils/server/jobs'
21 import * as magnetUtil from 'magnet-uri'
22 import { updateRedundancy } from '../../utils/server/redundancy'
23 import { ActorFollow } from '../../../../shared/models/actors'
24 import { readdir } from 'fs-extra'
25 import { join } from 'path'
26 import { VideoRedundancyStrategy } from '../../../../shared/models/redundancy'
27 import { getStats } from '../../utils/server/stats'
28 import { ServerStats } from '../../../../shared/models/server/server-stats.model'
29
30 const expect = chai.expect
31
32 let servers: ServerInfo[] = []
33 let video1Server2UUID: string
34 let video2Server2UUID: string
35
36 function checkMagnetWebseeds (file: { magnetUri: string, resolution: { id: number } }, baseWebseeds: string[]) {
37 const parsed = magnetUtil.decode(file.magnetUri)
38
39 for (const ws of baseWebseeds) {
40 const found = parsed.urlList.find(url => url === `${ws}-${file.resolution.id}.mp4`)
41 expect(found, `Webseed ${ws} not found in ${file.magnetUri}`).to.not.be.undefined
42 }
43 }
44
45 async function runServers (strategy: VideoRedundancyStrategy, additionalParams: any = {}) {
46 const config = {
47 redundancy: {
48 videos: {
49 check_interval: '5 seconds',
50 strategies: [
51 immutableAssign({
52 strategy: strategy,
53 size: '100KB'
54 }, additionalParams)
55 ]
56 }
57 }
58 }
59 servers = await flushAndRunMultipleServers(3, config)
60
61 // Get the access tokens
62 await setAccessTokensToServers(servers)
63
64 {
65 const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 1 server 2' })
66 video1Server2UUID = res.body.video.uuid
67
68 await viewVideo(servers[ 1 ].url, video1Server2UUID)
69 }
70
71 {
72 const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 2 server 2' })
73 video2Server2UUID = res.body.video.uuid
74 }
75
76 await waitJobs(servers)
77
78 // Server 1 and server 2 follow each other
79 await doubleFollow(servers[ 0 ], servers[ 1 ])
80 // Server 1 and server 3 follow each other
81 await doubleFollow(servers[ 0 ], servers[ 2 ])
82 // Server 2 and server 3 follow each other
83 await doubleFollow(servers[ 1 ], servers[ 2 ])
84
85 await waitJobs(servers)
86 }
87
88 async function check1WebSeed (strategy: VideoRedundancyStrategy) {
89 const webseeds = [
90 'http://localhost:9002/static/webseed/' + video1Server2UUID
91 ]
92
93 for (const server of servers) {
94 {
95 const res = await getVideo(server.url, video1Server2UUID)
96
97 const video: VideoDetails = res.body
98 video.files.forEach(f => checkMagnetWebseeds(f, webseeds))
99 }
100
101 {
102 const res = await getStats(server.url)
103 const data: ServerStats = res.body
104
105 expect(data.videosRedundancy).to.have.lengthOf(1)
106
107 const stat = data.videosRedundancy[0]
108 expect(stat.strategy).to.equal(strategy)
109 expect(stat.totalSize).to.equal(102400)
110 expect(stat.totalUsed).to.equal(0)
111 expect(stat.totalVideoFiles).to.equal(0)
112 expect(stat.totalVideos).to.equal(0)
113 }
114 }
115 }
116
117 async function enableRedundancy () {
118 await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, true)
119
120 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt')
121 const follows: ActorFollow[] = res.body.data
122 const server2 = follows.find(f => f.following.host === 'localhost:9002')
123 const server3 = follows.find(f => f.following.host === 'localhost:9003')
124
125 expect(server3).to.not.be.undefined
126 expect(server3.following.hostRedundancyAllowed).to.be.false
127
128 expect(server2).to.not.be.undefined
129 expect(server2.following.hostRedundancyAllowed).to.be.true
130 }
131
132 async function check2Webseeds (strategy: VideoRedundancyStrategy) {
133 await waitJobs(servers)
134 await wait(15000)
135 await waitJobs(servers)
136
137 const webseeds = [
138 'http://localhost:9001/static/webseed/' + video1Server2UUID,
139 'http://localhost:9002/static/webseed/' + video1Server2UUID
140 ]
141
142 for (const server of servers) {
143 {
144 const res = await getVideo(server.url, video1Server2UUID)
145
146 const video: VideoDetails = res.body
147
148 for (const file of video.files) {
149 checkMagnetWebseeds(file, webseeds)
150 }
151 }
152 }
153
154 const files = await readdir(join(root(), 'test1', 'videos'))
155 expect(files).to.have.lengthOf(4)
156
157 for (const resolution of [ 240, 360, 480, 720 ]) {
158 expect(files.find(f => f === `${video1Server2UUID}-${resolution}.mp4`)).to.not.be.undefined
159 }
160
161 {
162 const res = await getStats(servers[0].url)
163 const data: ServerStats = res.body
164
165 expect(data.videosRedundancy).to.have.lengthOf(1)
166 const stat = data.videosRedundancy[0]
167
168 expect(stat.strategy).to.equal(strategy)
169 expect(stat.totalSize).to.equal(102400)
170 expect(stat.totalUsed).to.be.at.least(1).and.below(102401)
171 expect(stat.totalVideoFiles).to.equal(4)
172 expect(stat.totalVideos).to.equal(1)
173 }
174 }
175
176 async function cleanServers () {
177 killallServers(servers)
178 }
179
180 describe('Test videos redundancy', function () {
181
182 describe('With most-views strategy', function () {
183 const strategy = 'most-views'
184
185 before(function () {
186 this.timeout(120000)
187
188 return runServers(strategy)
189 })
190
191 it('Should have 1 webseed on the first video', function () {
192 return check1WebSeed(strategy)
193 })
194
195 it('Should enable redundancy on server 1', function () {
196 return enableRedundancy()
197 })
198
199 it('Should have 2 webseed on the first video', function () {
200 this.timeout(40000)
201
202 return check2Webseeds(strategy)
203 })
204
205 after(function () {
206 return cleanServers()
207 })
208 })
209
210 describe('With trending strategy', function () {
211 const strategy = 'trending'
212
213 before(function () {
214 this.timeout(120000)
215
216 return runServers(strategy)
217 })
218
219 it('Should have 1 webseed on the first video', function () {
220 return check1WebSeed(strategy)
221 })
222
223 it('Should enable redundancy on server 1', function () {
224 return enableRedundancy()
225 })
226
227 it('Should have 2 webseed on the first video', function () {
228 this.timeout(40000)
229
230 return check2Webseeds(strategy)
231 })
232
233 after(function () {
234 return cleanServers()
235 })
236 })
237
238 describe('With recently added strategy', function () {
239 const strategy = 'recently-added'
240
241 before(function () {
242 this.timeout(120000)
243
244 return runServers(strategy, { minViews: 3 })
245 })
246
247 it('Should have 1 webseed on the first video', function () {
248 return check1WebSeed(strategy)
249 })
250
251 it('Should enable redundancy on server 1', function () {
252 return enableRedundancy()
253 })
254
255 it('Should still have 1 webseed on the first video', async function () {
256 this.timeout(40000)
257
258 await waitJobs(servers)
259 await wait(15000)
260 await waitJobs(servers)
261
262 return check1WebSeed(strategy)
263 })
264
265 it('Should view 2 times the first video', async function () {
266 this.timeout(40000)
267
268 await viewVideo(servers[ 0 ].url, video1Server2UUID)
269 await viewVideo(servers[ 2 ].url, video1Server2UUID)
270
271 await wait(10000)
272 await waitJobs(servers)
273 })
274
275 it('Should have 2 webseed on the first video', function () {
276 this.timeout(40000)
277
278 return check2Webseeds(strategy)
279 })
280
281 after(function () {
282 return cleanServers()
283 })
284 })
285 })