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