]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tests/api/views/video-views-overall-stats.ts
Merge branch 'release/4.3.0' into develop
[github/Chocobozzz/PeerTube.git] / server / tests / api / views / video-views-overall-stats.ts
1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3 import { expect } from 'chai'
4 import { FfmpegCommand } from 'fluent-ffmpeg'
5 import { prepareViewsServers, prepareViewsVideos, processViewersStats } from '@server/tests/shared'
6 import { cleanupTests, PeerTubeServer, stopFfmpeg, waitJobs } from '@shared/server-commands'
7
8 describe('Test views overall stats', function () {
9 let servers: PeerTubeServer[]
10
11 before(async function () {
12 this.timeout(120000)
13
14 servers = await prepareViewsServers()
15 })
16
17 describe('Test watch time stats of local videos on live and VOD', function () {
18 let vodVideoId: string
19 let liveVideoId: string
20 let command: FfmpegCommand
21
22 before(async function () {
23 this.timeout(240000);
24
25 ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true }))
26 })
27
28 it('Should display overall stats of a video with no viewers', async function () {
29 for (const videoId of [ liveVideoId, vodVideoId ]) {
30 const stats = await servers[0].videoStats.getOverallStats({ videoId })
31 const video = await servers[0].videos.get({ id: videoId })
32
33 expect(video.views).to.equal(0)
34 expect(stats.averageWatchTime).to.equal(0)
35 expect(stats.totalWatchTime).to.equal(0)
36 expect(stats.totalViewers).to.equal(0)
37 }
38 })
39
40 it('Should display overall stats with 1 viewer below the watch time limit', async function () {
41 this.timeout(60000)
42
43 for (const videoId of [ liveVideoId, vodVideoId ]) {
44 await servers[0].views.simulateViewer({ id: videoId, currentTimes: [ 0, 1 ] })
45 }
46
47 await processViewersStats(servers)
48
49 for (const videoId of [ liveVideoId, vodVideoId ]) {
50 const stats = await servers[0].videoStats.getOverallStats({ videoId })
51 const video = await servers[0].videos.get({ id: videoId })
52
53 expect(video.views).to.equal(0)
54 expect(stats.averageWatchTime).to.equal(1)
55 expect(stats.totalWatchTime).to.equal(1)
56 expect(stats.totalViewers).to.equal(1)
57 }
58 })
59
60 it('Should display overall stats with 2 viewers', async function () {
61 this.timeout(60000)
62
63 {
64 await servers[0].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 3 ] })
65 await servers[0].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35, 40 ] })
66
67 await processViewersStats(servers)
68
69 {
70 const stats = await servers[0].videoStats.getOverallStats({ videoId: vodVideoId })
71 const video = await servers[0].videos.get({ id: vodVideoId })
72
73 expect(video.views).to.equal(1)
74 expect(stats.averageWatchTime).to.equal(2)
75 expect(stats.totalWatchTime).to.equal(4)
76 expect(stats.totalViewers).to.equal(2)
77 }
78
79 {
80 const stats = await servers[0].videoStats.getOverallStats({ videoId: liveVideoId })
81 const video = await servers[0].videos.get({ id: liveVideoId })
82
83 expect(video.views).to.equal(1)
84 expect(stats.averageWatchTime).to.equal(21)
85 expect(stats.totalWatchTime).to.equal(41)
86 expect(stats.totalViewers).to.equal(2)
87 }
88 }
89 })
90
91 it('Should display overall stats with a remote viewer below the watch time limit', async function () {
92 this.timeout(60000)
93
94 for (const videoId of [ liveVideoId, vodVideoId ]) {
95 await servers[1].views.simulateViewer({ id: videoId, currentTimes: [ 0, 2 ] })
96 }
97
98 await processViewersStats(servers)
99
100 {
101 const stats = await servers[0].videoStats.getOverallStats({ videoId: vodVideoId })
102 const video = await servers[0].videos.get({ id: vodVideoId })
103
104 expect(video.views).to.equal(1)
105 expect(stats.averageWatchTime).to.equal(2)
106 expect(stats.totalWatchTime).to.equal(6)
107 expect(stats.totalViewers).to.equal(3)
108 }
109
110 {
111 const stats = await servers[0].videoStats.getOverallStats({ videoId: liveVideoId })
112 const video = await servers[0].videos.get({ id: liveVideoId })
113
114 expect(video.views).to.equal(1)
115 expect(stats.averageWatchTime).to.equal(14)
116 expect(stats.totalWatchTime).to.equal(43)
117 expect(stats.totalViewers).to.equal(3)
118 }
119 })
120
121 it('Should display overall stats with a remote viewer above the watch time limit', async function () {
122 this.timeout(60000)
123
124 await servers[1].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] })
125 await servers[1].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 45 ] })
126 await processViewersStats(servers)
127
128 {
129 const stats = await servers[0].videoStats.getOverallStats({ videoId: vodVideoId })
130 const video = await servers[0].videos.get({ id: vodVideoId })
131
132 expect(video.views).to.equal(2)
133 expect(stats.averageWatchTime).to.equal(3)
134 expect(stats.totalWatchTime).to.equal(11)
135 expect(stats.totalViewers).to.equal(4)
136 }
137
138 {
139 const stats = await servers[0].videoStats.getOverallStats({ videoId: liveVideoId })
140 const video = await servers[0].videos.get({ id: liveVideoId })
141
142 expect(video.views).to.equal(2)
143 expect(stats.averageWatchTime).to.equal(22)
144 expect(stats.totalWatchTime).to.equal(88)
145 expect(stats.totalViewers).to.equal(4)
146 }
147 })
148
149 it('Should filter overall stats by date', async function () {
150 this.timeout(60000)
151
152 const beforeView = new Date()
153
154 await servers[0].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 3 ] })
155 await processViewersStats(servers)
156
157 {
158 const stats = await servers[0].videoStats.getOverallStats({ videoId: vodVideoId, startDate: beforeView.toISOString() })
159 expect(stats.averageWatchTime).to.equal(3)
160 expect(stats.totalWatchTime).to.equal(3)
161 expect(stats.totalViewers).to.equal(1)
162 }
163
164 {
165 const stats = await servers[0].videoStats.getOverallStats({ videoId: liveVideoId, endDate: beforeView.toISOString() })
166 expect(stats.averageWatchTime).to.equal(22)
167 expect(stats.totalWatchTime).to.equal(88)
168 expect(stats.totalViewers).to.equal(4)
169 }
170 })
171
172 after(async function () {
173 await stopFfmpeg(command)
174 })
175 })
176
177 describe('Test watchers peak stats of local videos on VOD', function () {
178 let videoUUID: string
179 let before2Watchers: Date
180
181 before(async function () {
182 this.timeout(240000);
183
184 ({ vodVideoId: videoUUID } = await prepareViewsVideos({ servers, live: true, vod: true }))
185 })
186
187 it('Should not have watchers peak', async function () {
188 const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID })
189
190 expect(stats.viewersPeak).to.equal(0)
191 expect(stats.viewersPeakDate).to.be.null
192 })
193
194 it('Should have watcher peak with 1 watcher', async function () {
195 this.timeout(60000)
196
197 const before = new Date()
198 await servers[0].views.simulateViewer({ id: videoUUID, currentTimes: [ 0, 2 ] })
199 const after = new Date()
200
201 await processViewersStats(servers)
202
203 const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID })
204
205 expect(stats.viewersPeak).to.equal(1)
206 expect(new Date(stats.viewersPeakDate)).to.be.above(before).and.below(after)
207 })
208
209 it('Should have watcher peak with 2 watchers', async function () {
210 this.timeout(60000)
211
212 before2Watchers = new Date()
213 await servers[0].views.view({ id: videoUUID, currentTime: 0 })
214 await servers[1].views.view({ id: videoUUID, currentTime: 0 })
215 await servers[0].views.view({ id: videoUUID, currentTime: 2 })
216 await servers[1].views.view({ id: videoUUID, currentTime: 2 })
217 const after = new Date()
218
219 await processViewersStats(servers)
220
221 const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID })
222
223 expect(stats.viewersPeak).to.equal(2)
224 expect(new Date(stats.viewersPeakDate)).to.be.above(before2Watchers).and.below(after)
225 })
226
227 it('Should filter peak viewers stats by date', async function () {
228 {
229 const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID, startDate: new Date().toISOString() })
230 expect(stats.viewersPeak).to.equal(0)
231 expect(stats.viewersPeakDate).to.not.exist
232 }
233
234 {
235 const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID, endDate: before2Watchers.toISOString() })
236 expect(stats.viewersPeak).to.equal(1)
237 expect(new Date(stats.viewersPeakDate)).to.be.below(before2Watchers)
238 }
239 })
240 })
241
242 describe('Test countries', function () {
243 let videoUUID: string
244
245 it('Should not report countries if geoip is disabled', async function () {
246 this.timeout(120000)
247
248 const { uuid } = await servers[0].videos.quickUpload({ name: 'video' })
249 await waitJobs(servers)
250
251 await servers[1].views.view({ id: uuid, xForwardedFor: '8.8.8.8,127.0.0.1', currentTime: 1 })
252
253 await processViewersStats(servers)
254
255 const stats = await servers[0].videoStats.getOverallStats({ videoId: uuid })
256 expect(stats.countries).to.have.lengthOf(0)
257 })
258
259 it('Should report countries if geoip is enabled', async function () {
260 this.timeout(240000)
261
262 const { uuid } = await servers[0].videos.quickUpload({ name: 'video' })
263 videoUUID = uuid
264 await waitJobs(servers)
265
266 await Promise.all([
267 servers[0].kill(),
268 servers[1].kill()
269 ])
270
271 const config = { geo_ip: { enabled: true } }
272 await Promise.all([
273 servers[0].run(config),
274 servers[1].run(config)
275 ])
276
277 await servers[0].views.view({ id: uuid, xForwardedFor: '8.8.8.8,127.0.0.1', currentTime: 1 })
278 await servers[1].views.view({ id: uuid, xForwardedFor: '8.8.8.4,127.0.0.1', currentTime: 3 })
279 await servers[1].views.view({ id: uuid, xForwardedFor: '80.67.169.12,127.0.0.1', currentTime: 2 })
280
281 await processViewersStats(servers)
282
283 const stats = await servers[0].videoStats.getOverallStats({ videoId: uuid })
284 expect(stats.countries).to.have.lengthOf(2)
285
286 expect(stats.countries[0].isoCode).to.equal('US')
287 expect(stats.countries[0].viewers).to.equal(2)
288
289 expect(stats.countries[1].isoCode).to.equal('FR')
290 expect(stats.countries[1].viewers).to.equal(1)
291 })
292
293 it('Should filter countries stats by date', async function () {
294 const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID, startDate: new Date().toISOString() })
295 expect(stats.countries).to.have.lengthOf(0)
296 })
297 })
298
299 after(async function () {
300 await cleanupTests(servers)
301 })
302 })