1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
4 import * as chai from 'chai'
5 import { FfmpegCommand } from 'fluent-ffmpeg'
6 import { prepareViewsServers, prepareViewsVideos, processViewersStats } from '@server/tests/shared'
7 import { cleanupTests, PeerTubeServer, stopFfmpeg, waitJobs } from '@shared/server-commands'
9 const expect = chai.expect
11 describe('Test views overall stats', function () {
12 let servers: PeerTubeServer[]
14 before(async function () {
17 servers = await prepareViewsServers()
20 describe('Test watch time stats of local videos on live and VOD', function () {
21 let vodVideoId: string
22 let liveVideoId: string
23 let command: FfmpegCommand
25 before(async function () {
28 ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true }))
31 it('Should display overall stats of a video with no viewers', async function () {
32 for (const videoId of [ liveVideoId, vodVideoId ]) {
33 const stats = await servers[0].videoStats.getOverallStats({ videoId })
34 const video = await servers[0].videos.get({ id: videoId })
36 expect(video.views).to.equal(0)
37 expect(stats.averageWatchTime).to.equal(0)
38 expect(stats.totalWatchTime).to.equal(0)
42 it('Should display overall stats with 1 viewer below the watch time limit', async function () {
45 for (const videoId of [ liveVideoId, vodVideoId ]) {
46 await servers[0].views.simulateViewer({ id: videoId, currentTimes: [ 0, 1 ] })
49 await processViewersStats(servers)
51 for (const videoId of [ liveVideoId, vodVideoId ]) {
52 const stats = await servers[0].videoStats.getOverallStats({ videoId })
53 const video = await servers[0].videos.get({ id: videoId })
55 expect(video.views).to.equal(0)
56 expect(stats.averageWatchTime).to.equal(1)
57 expect(stats.totalWatchTime).to.equal(1)
61 it('Should display overall stats with 2 viewers', async function () {
65 await servers[0].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 3 ] })
66 await servers[0].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35, 40 ] })
68 await processViewersStats(servers)
71 const stats = await servers[0].videoStats.getOverallStats({ videoId: vodVideoId })
72 const video = await servers[0].videos.get({ id: vodVideoId })
74 expect(video.views).to.equal(1)
75 expect(stats.averageWatchTime).to.equal(2)
76 expect(stats.totalWatchTime).to.equal(4)
80 const stats = await servers[0].videoStats.getOverallStats({ videoId: liveVideoId })
81 const video = await servers[0].videos.get({ id: liveVideoId })
83 expect(video.views).to.equal(1)
84 expect(stats.averageWatchTime).to.equal(21)
85 expect(stats.totalWatchTime).to.equal(41)
90 it('Should display overall stats with a remote viewer below the watch time limit', async function () {
93 for (const videoId of [ liveVideoId, vodVideoId ]) {
94 await servers[1].views.simulateViewer({ id: videoId, currentTimes: [ 0, 2 ] })
97 await processViewersStats(servers)
100 const stats = await servers[0].videoStats.getOverallStats({ videoId: vodVideoId })
101 const video = await servers[0].videos.get({ id: vodVideoId })
103 expect(video.views).to.equal(1)
104 expect(stats.averageWatchTime).to.equal(2)
105 expect(stats.totalWatchTime).to.equal(6)
109 const stats = await servers[0].videoStats.getOverallStats({ videoId: liveVideoId })
110 const video = await servers[0].videos.get({ id: liveVideoId })
112 expect(video.views).to.equal(1)
113 expect(stats.averageWatchTime).to.equal(14)
114 expect(stats.totalWatchTime).to.equal(43)
118 it('Should display overall stats with a remote viewer above the watch time limit', async function () {
121 await servers[1].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] })
122 await servers[1].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 45 ] })
123 await processViewersStats(servers)
126 const stats = await servers[0].videoStats.getOverallStats({ videoId: vodVideoId })
127 const video = await servers[0].videos.get({ id: vodVideoId })
129 expect(video.views).to.equal(2)
130 expect(stats.averageWatchTime).to.equal(3)
131 expect(stats.totalWatchTime).to.equal(11)
135 const stats = await servers[0].videoStats.getOverallStats({ videoId: liveVideoId })
136 const video = await servers[0].videos.get({ id: liveVideoId })
138 expect(video.views).to.equal(2)
139 expect(stats.averageWatchTime).to.equal(22)
140 expect(stats.totalWatchTime).to.equal(88)
144 after(async function () {
145 await stopFfmpeg(command)
149 describe('Test watchers peak stats of local videos on VOD', function () {
150 let videoUUID: string
152 before(async function () {
153 this.timeout(120000);
155 ({ vodVideoId: videoUUID } = await prepareViewsVideos({ servers, live: true, vod: true }))
158 it('Should not have watchers peak', async function () {
159 const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID })
161 expect(stats.viewersPeak).to.equal(0)
162 expect(stats.viewersPeakDate).to.be.null
165 it('Should have watcher peak with 1 watcher', async function () {
168 const before = new Date()
169 await servers[0].views.simulateViewer({ id: videoUUID, currentTimes: [ 0, 2 ] })
170 const after = new Date()
172 await processViewersStats(servers)
174 const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID })
176 expect(stats.viewersPeak).to.equal(1)
177 expect(new Date(stats.viewersPeakDate)).to.be.above(before).and.below(after)
180 it('Should have watcher peak with 2 watchers', async function () {
183 const before = new Date()
184 await servers[0].views.view({ id: videoUUID, currentTime: 0 })
185 await servers[1].views.view({ id: videoUUID, currentTime: 0 })
186 await servers[0].views.view({ id: videoUUID, currentTime: 2 })
187 await servers[1].views.view({ id: videoUUID, currentTime: 2 })
188 const after = new Date()
190 await processViewersStats(servers)
192 const stats = await servers[0].videoStats.getOverallStats({ videoId: videoUUID })
194 expect(stats.viewersPeak).to.equal(2)
195 expect(new Date(stats.viewersPeakDate)).to.be.above(before).and.below(after)
199 describe('Test countries', function () {
201 it('Should not report countries if geoip is disabled', async function () {
204 const { uuid } = await servers[0].videos.quickUpload({ name: 'video' })
205 await waitJobs(servers)
207 await servers[1].views.view({ id: uuid, xForwardedFor: '8.8.8.8,127.0.0.1', currentTime: 1 })
209 await processViewersStats(servers)
211 const stats = await servers[0].videoStats.getOverallStats({ videoId: uuid })
212 expect(stats.countries).to.have.lengthOf(0)
215 it('Should report countries if geoip is enabled', async function () {
218 const { uuid } = await servers[0].videos.quickUpload({ name: 'video' })
219 await waitJobs(servers)
226 const config = { geo_ip: { enabled: true } }
228 servers[0].run(config),
229 servers[1].run(config)
232 await servers[0].views.view({ id: uuid, xForwardedFor: '8.8.8.8,127.0.0.1', currentTime: 1 })
233 await servers[1].views.view({ id: uuid, xForwardedFor: '8.8.8.4,127.0.0.1', currentTime: 3 })
234 await servers[1].views.view({ id: uuid, xForwardedFor: '80.67.169.12,127.0.0.1', currentTime: 2 })
236 await processViewersStats(servers)
238 const stats = await servers[0].videoStats.getOverallStats({ videoId: uuid })
239 expect(stats.countries).to.have.lengthOf(2)
241 expect(stats.countries[0].isoCode).to.equal('US')
242 expect(stats.countries[0].viewers).to.equal(2)
244 expect(stats.countries[1].isoCode).to.equal('FR')
245 expect(stats.countries[1].viewers).to.equal(1)
249 after(async function () {
250 await cleanupTests(servers)