]>
Commit | Line | Data |
---|---|---|
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 | describe('Test views timeserie stats', function () { | |
13 | const availableMetrics: VideoStatsTimeserieMetric[] = [ 'viewers' ] | |
14 | ||
15 | let servers: PeerTubeServer[] | |
16 | ||
17 | before(async function () { | |
18 | this.timeout(120000) | |
19 | ||
20 | servers = await prepareViewsServers() | |
21 | }) | |
22 | ||
23 | describe('Common metric tests', function () { | |
24 | let vodVideoId: string | |
25 | ||
26 | before(async function () { | |
27 | this.timeout(120000); | |
28 | ||
29 | ({ vodVideoId } = await prepareViewsVideos({ servers, live: false, vod: true })) | |
30 | }) | |
31 | ||
32 | it('Should display empty metric stats', async function () { | |
33 | for (const metric of availableMetrics) { | |
34 | const { data } = await servers[0].videoStats.getTimeserieStats({ videoId: vodVideoId, metric }) | |
35 | ||
36 | expect(data).to.have.lengthOf(30) | |
37 | ||
38 | for (const d of data) { | |
39 | expect(d.value).to.equal(0) | |
40 | } | |
41 | } | |
42 | }) | |
43 | }) | |
44 | ||
45 | describe('Test viewer and watch time metrics on live and VOD', function () { | |
46 | let vodVideoId: string | |
47 | let liveVideoId: string | |
48 | let command: FfmpegCommand | |
49 | ||
50 | function expectTodayLastValue (result: VideoStatsTimeserie, lastValue: number) { | |
51 | const { data } = result | |
52 | ||
53 | const last = data[data.length - 1] | |
54 | const today = new Date().getDate() | |
55 | expect(new Date(last.date).getDate()).to.equal(today) | |
56 | } | |
57 | ||
58 | function expectTimeserieData (result: VideoStatsTimeserie, lastValue: number) { | |
59 | const { data } = result | |
60 | expect(data).to.have.lengthOf(30) | |
61 | ||
62 | expectTodayLastValue(result, lastValue) | |
63 | ||
64 | for (let i = 0; i < data.length - 2; i++) { | |
65 | expect(data[i].value).to.equal(0) | |
66 | } | |
67 | } | |
68 | ||
69 | function expectInterval (result: VideoStatsTimeserie, intervalMs: number) { | |
70 | const first = result.data[0] | |
71 | const second = result.data[1] | |
72 | expect(new Date(second.date).getTime() - new Date(first.date).getTime()).to.equal(intervalMs) | |
73 | } | |
74 | ||
75 | before(async function () { | |
76 | this.timeout(120000); | |
77 | ||
78 | ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true })) | |
79 | }) | |
80 | ||
81 | it('Should display appropriate viewers metrics', async function () { | |
82 | for (const videoId of [ vodVideoId, liveVideoId ]) { | |
83 | await servers[0].views.simulateViewer({ id: videoId, currentTimes: [ 0, 3 ] }) | |
84 | await servers[1].views.simulateViewer({ id: videoId, currentTimes: [ 0, 5 ] }) | |
85 | } | |
86 | ||
87 | await processViewersStats(servers) | |
88 | ||
89 | for (const videoId of [ vodVideoId, liveVideoId ]) { | |
90 | const result = await servers[0].videoStats.getTimeserieStats({ videoId, metric: 'viewers' }) | |
91 | expectTimeserieData(result, 2) | |
92 | } | |
93 | }) | |
94 | ||
95 | it('Should display appropriate watch time metrics', async function () { | |
96 | for (const videoId of [ vodVideoId, liveVideoId ]) { | |
97 | const result = await servers[0].videoStats.getTimeserieStats({ videoId, metric: 'aggregateWatchTime' }) | |
98 | expectTimeserieData(result, 8) | |
99 | ||
100 | await servers[1].views.simulateViewer({ id: videoId, currentTimes: [ 0, 1 ] }) | |
101 | } | |
102 | ||
103 | await processViewersStats(servers) | |
104 | ||
105 | for (const videoId of [ vodVideoId, liveVideoId ]) { | |
106 | const result = await servers[0].videoStats.getTimeserieStats({ videoId, metric: 'aggregateWatchTime' }) | |
107 | expectTimeserieData(result, 9) | |
108 | } | |
109 | }) | |
110 | ||
111 | it('Should use a custom start/end date', async function () { | |
112 | const now = new Date() | |
113 | const tenDaysAgo = new Date() | |
114 | tenDaysAgo.setDate(tenDaysAgo.getDate() - 9) | |
115 | ||
116 | const result = await servers[0].videoStats.getTimeserieStats({ | |
117 | videoId: vodVideoId, | |
118 | metric: 'aggregateWatchTime', | |
119 | startDate: tenDaysAgo, | |
120 | endDate: now | |
121 | }) | |
122 | ||
123 | expect(result.groupInterval).to.equal('one_day') | |
124 | expect(result.data).to.have.lengthOf(10) | |
125 | ||
126 | const first = result.data[0] | |
127 | expect(new Date(first.date).toLocaleDateString()).to.equal(tenDaysAgo.toLocaleDateString()) | |
128 | ||
129 | expectInterval(result, 24 * 3600 * 1000) | |
130 | expectTodayLastValue(result, 9) | |
131 | }) | |
132 | ||
133 | it('Should automatically group by hours', async function () { | |
134 | const now = new Date() | |
135 | const twoDaysAgo = new Date() | |
136 | twoDaysAgo.setDate(twoDaysAgo.getDate() - 1) | |
137 | ||
138 | const result = await servers[0].videoStats.getTimeserieStats({ | |
139 | videoId: vodVideoId, | |
140 | metric: 'aggregateWatchTime', | |
141 | startDate: twoDaysAgo, | |
142 | endDate: now | |
143 | }) | |
144 | ||
145 | expect(result.groupInterval).to.equal('one_hour') | |
146 | expect(result.data).to.have.length.above(24).and.below(50) | |
147 | ||
148 | expectInterval(result, 3600 * 1000) | |
149 | expectTodayLastValue(result, 9) | |
150 | }) | |
151 | ||
152 | it('Should automatically group by ten minutes', async function () { | |
153 | const now = new Date() | |
154 | const twoHoursAgo = new Date() | |
155 | twoHoursAgo.setHours(twoHoursAgo.getHours() - 1) | |
156 | ||
157 | const result = await servers[0].videoStats.getTimeserieStats({ | |
158 | videoId: vodVideoId, | |
159 | metric: 'aggregateWatchTime', | |
160 | startDate: twoHoursAgo, | |
161 | endDate: now | |
162 | }) | |
163 | ||
164 | expect(result.groupInterval).to.equal('ten_minutes') | |
165 | expect(result.data).to.have.length.above(6).and.below(18) | |
166 | ||
167 | expectInterval(result, 60 * 10 * 1000) | |
168 | expectTodayLastValue(result, 9) | |
169 | }) | |
170 | ||
171 | it('Should automatically group by one minute', async function () { | |
172 | const now = new Date() | |
173 | const thirtyAgo = new Date() | |
174 | thirtyAgo.setMinutes(thirtyAgo.getMinutes() - 30) | |
175 | ||
176 | const result = await servers[0].videoStats.getTimeserieStats({ | |
177 | videoId: vodVideoId, | |
178 | metric: 'aggregateWatchTime', | |
179 | startDate: thirtyAgo, | |
180 | endDate: now | |
181 | }) | |
182 | ||
183 | expect(result.groupInterval).to.equal('one_minute') | |
184 | expect(result.data).to.have.length.above(20).and.below(40) | |
185 | ||
186 | expectInterval(result, 60 * 1000) | |
187 | expectTodayLastValue(result, 9) | |
188 | }) | |
189 | ||
190 | after(async function () { | |
191 | await stopFfmpeg(command) | |
192 | }) | |
193 | }) | |
194 | ||
195 | after(async function () { | |
196 | await cleanupTests(servers) | |
197 | }) | |
198 | }) |