]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tests/api/views/video-views-timeserie-stats.ts
We don't need to import mocha
[github/Chocobozzz/PeerTube.git] / server / tests / api / views / video-views-timeserie-stats.ts
1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3 import * as chai from 'chai'
4 import { FfmpegCommand } from 'fluent-ffmpeg'
5 import { prepareViewsServers, prepareViewsVideos, processViewersStats } from '@server/tests/shared'
6 import { VideoStatsTimeserie, VideoStatsTimeserieMetric } from '@shared/models'
7 import { cleanupTests, PeerTubeServer, stopFfmpeg } from '@shared/server-commands'
8
9 const expect = chai.expect
10
11 function buildOneMonthAgo () {
12 const monthAgo = new Date()
13 monthAgo.setHours(0, 0, 0, 0)
14
15 monthAgo.setDate(monthAgo.getDate() - 29)
16
17 return monthAgo
18 }
19
20 describe('Test views timeserie stats', function () {
21 const availableMetrics: VideoStatsTimeserieMetric[] = [ 'viewers' ]
22
23 let servers: PeerTubeServer[]
24
25 before(async function () {
26 this.timeout(120000)
27
28 servers = await prepareViewsServers()
29 })
30
31 describe('Common metric tests', function () {
32 let vodVideoId: string
33
34 before(async function () {
35 this.timeout(120000);
36
37 ({ vodVideoId } = await prepareViewsVideos({ servers, live: false, vod: true }))
38 })
39
40 it('Should display empty metric stats', async function () {
41 for (const metric of availableMetrics) {
42 const { data } = await servers[0].videoStats.getTimeserieStats({ videoId: vodVideoId, metric })
43
44 expect(data).to.have.length.at.least(1)
45
46 for (const d of data) {
47 expect(d.value).to.equal(0)
48 }
49 }
50 })
51 })
52
53 describe('Test viewer and watch time metrics on live and VOD', function () {
54 let vodVideoId: string
55 let liveVideoId: string
56 let command: FfmpegCommand
57
58 function expectTodayLastValue (result: VideoStatsTimeserie, lastValue?: number) {
59 const { data } = result
60
61 const last = data[data.length - 1]
62 const today = new Date().getDate()
63 expect(new Date(last.date).getDate()).to.equal(today)
64
65 if (lastValue) expect(last.value).to.equal(lastValue)
66 }
67
68 function expectTimeserieData (result: VideoStatsTimeserie, lastValue: number) {
69 const { data } = result
70 expect(data).to.have.length.at.least(25)
71
72 expectTodayLastValue(result, lastValue)
73
74 for (let i = 0; i < data.length - 2; i++) {
75 expect(data[i].value).to.equal(0)
76 }
77 }
78
79 function expectInterval (result: VideoStatsTimeserie, intervalMs: number) {
80 const first = result.data[0]
81 const second = result.data[1]
82 expect(new Date(second.date).getTime() - new Date(first.date).getTime()).to.equal(intervalMs)
83 }
84
85 before(async function () {
86 this.timeout(120000);
87
88 ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true }))
89 })
90
91 it('Should display appropriate viewers metrics', async function () {
92 for (const videoId of [ vodVideoId, liveVideoId ]) {
93 await servers[0].views.simulateViewer({ id: videoId, currentTimes: [ 0, 3 ] })
94 await servers[1].views.simulateViewer({ id: videoId, currentTimes: [ 0, 5 ] })
95 }
96
97 await processViewersStats(servers)
98
99 for (const videoId of [ vodVideoId, liveVideoId ]) {
100 const result = await servers[0].videoStats.getTimeserieStats({
101 videoId,
102 startDate: buildOneMonthAgo(),
103 endDate: new Date(),
104 metric: 'viewers'
105 })
106 expectTimeserieData(result, 2)
107 }
108 })
109
110 it('Should display appropriate watch time metrics', async function () {
111 for (const videoId of [ vodVideoId, liveVideoId ]) {
112 const result = await servers[0].videoStats.getTimeserieStats({
113 videoId,
114 startDate: buildOneMonthAgo(),
115 endDate: new Date(),
116 metric: 'aggregateWatchTime'
117 })
118 expectTimeserieData(result, 8)
119
120 await servers[1].views.simulateViewer({ id: videoId, currentTimes: [ 0, 1 ] })
121 }
122
123 await processViewersStats(servers)
124
125 for (const videoId of [ vodVideoId, liveVideoId ]) {
126 const result = await servers[0].videoStats.getTimeserieStats({
127 videoId,
128 startDate: buildOneMonthAgo(),
129 endDate: new Date(),
130 metric: 'aggregateWatchTime'
131 })
132 expectTimeserieData(result, 9)
133 }
134 })
135
136 it('Should use a custom start/end date', async function () {
137 const now = new Date()
138 const twentyDaysAgo = new Date()
139 twentyDaysAgo.setDate(twentyDaysAgo.getDate() - 19)
140
141 const result = await servers[0].videoStats.getTimeserieStats({
142 videoId: vodVideoId,
143 metric: 'aggregateWatchTime',
144 startDate: twentyDaysAgo,
145 endDate: now
146 })
147
148 expect(result.groupInterval).to.equal('1 day')
149 expect(result.data).to.have.lengthOf(20)
150
151 const first = result.data[0]
152 expect(new Date(first.date).toLocaleDateString()).to.equal(twentyDaysAgo.toLocaleDateString())
153
154 expectInterval(result, 24 * 3600 * 1000)
155 expectTodayLastValue(result, 9)
156 })
157
158 it('Should automatically group by months', async function () {
159 const now = new Date()
160 const heightYearsAgo = new Date()
161 heightYearsAgo.setFullYear(heightYearsAgo.getFullYear() - 7)
162
163 const result = await servers[0].videoStats.getTimeserieStats({
164 videoId: vodVideoId,
165 metric: 'aggregateWatchTime',
166 startDate: heightYearsAgo,
167 endDate: now
168 })
169
170 expect(result.groupInterval).to.equal('6 months')
171 expect(result.data).to.have.length.above(10).and.below(200)
172 })
173
174 it('Should automatically group by days', async function () {
175 const now = new Date()
176 const threeMonthsAgo = new Date()
177 threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3)
178
179 const result = await servers[0].videoStats.getTimeserieStats({
180 videoId: vodVideoId,
181 metric: 'aggregateWatchTime',
182 startDate: threeMonthsAgo,
183 endDate: now
184 })
185
186 expect(result.groupInterval).to.equal('2 days')
187 expect(result.data).to.have.length.above(10).and.below(200)
188 })
189
190 it('Should automatically group by hours', async function () {
191 const now = new Date()
192 const twoDaysAgo = new Date()
193 twoDaysAgo.setDate(twoDaysAgo.getDate() - 1)
194
195 const result = await servers[0].videoStats.getTimeserieStats({
196 videoId: vodVideoId,
197 metric: 'aggregateWatchTime',
198 startDate: twoDaysAgo,
199 endDate: now
200 })
201
202 expect(result.groupInterval).to.equal('1 hour')
203 expect(result.data).to.have.length.above(24).and.below(50)
204
205 expectInterval(result, 3600 * 1000)
206 expectTodayLastValue(result, 9)
207 })
208
209 it('Should automatically group by ten minutes', async function () {
210 const now = new Date()
211 const twoHoursAgo = new Date()
212 twoHoursAgo.setHours(twoHoursAgo.getHours() - 4)
213
214 const result = await servers[0].videoStats.getTimeserieStats({
215 videoId: vodVideoId,
216 metric: 'aggregateWatchTime',
217 startDate: twoHoursAgo,
218 endDate: now
219 })
220
221 expect(result.groupInterval).to.equal('10 minutes')
222 expect(result.data).to.have.length.above(20).and.below(30)
223
224 expectInterval(result, 60 * 10 * 1000)
225 expectTodayLastValue(result)
226 })
227
228 it('Should automatically group by one minute', async function () {
229 const now = new Date()
230 const thirtyAgo = new Date()
231 thirtyAgo.setMinutes(thirtyAgo.getMinutes() - 30)
232
233 const result = await servers[0].videoStats.getTimeserieStats({
234 videoId: vodVideoId,
235 metric: 'aggregateWatchTime',
236 startDate: thirtyAgo,
237 endDate: now
238 })
239
240 expect(result.groupInterval).to.equal('1 minute')
241 expect(result.data).to.have.length.above(20).and.below(40)
242
243 expectInterval(result, 60 * 1000)
244 expectTodayLastValue(result)
245 })
246
247 after(async function () {
248 await stopFfmpeg(command)
249 })
250 })
251
252 after(async function () {
253 await cleanupTests(servers)
254 })
255 })