diff options
author | Chocobozzz <me@florianbigard.com> | 2022-03-24 13:36:47 +0100 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2022-04-15 09:49:35 +0200 |
commit | b211106695bb82f6c32e53306081b5262c3d109d (patch) | |
tree | fa187de1c33b0956665f5362e29af6b0f6d8bb57 /server/tests/api/views/video-views-counter.ts | |
parent | 69d48ee30c9d47cddf0c3c047dc99a99dcb6e894 (diff) | |
download | PeerTube-b211106695bb82f6c32e53306081b5262c3d109d.tar.gz PeerTube-b211106695bb82f6c32e53306081b5262c3d109d.tar.zst PeerTube-b211106695bb82f6c32e53306081b5262c3d109d.zip |
Support video views/viewers stats in server
* Add "currentTime" and "event" body params to view endpoint
* Merge watching and view endpoints
* Introduce WatchAction AP activity
* Add tables to store viewer information of local videos
* Add endpoints to fetch video views/viewers stats of local videos
* Refactor views/viewers handlers
* Support "views" and "viewers" counters for both VOD and live videos
Diffstat (limited to 'server/tests/api/views/video-views-counter.ts')
-rw-r--r-- | server/tests/api/views/video-views-counter.ts | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/server/tests/api/views/video-views-counter.ts b/server/tests/api/views/video-views-counter.ts new file mode 100644 index 000000000..b68aaa350 --- /dev/null +++ b/server/tests/api/views/video-views-counter.ts | |||
@@ -0,0 +1,155 @@ | |||
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, processViewsBuffer } from '@server/tests/shared' | ||
7 | import { wait } from '@shared/core-utils' | ||
8 | import { cleanupTests, PeerTubeServer, stopFfmpeg, waitJobs } from '@shared/server-commands' | ||
9 | |||
10 | const expect = chai.expect | ||
11 | |||
12 | describe('Test video views/viewers counters', function () { | ||
13 | let servers: PeerTubeServer[] | ||
14 | |||
15 | async function checkCounter (field: 'views' | 'viewers', id: string, expected: number) { | ||
16 | for (const server of servers) { | ||
17 | const video = await server.videos.get({ id }) | ||
18 | |||
19 | const messageSuffix = video.isLive | ||
20 | ? 'live video' | ||
21 | : 'vod video' | ||
22 | |||
23 | expect(video[field]).to.equal(expected, `${field} not valid on server ${server.serverNumber} for ${messageSuffix} ${video.uuid}`) | ||
24 | } | ||
25 | } | ||
26 | |||
27 | before(async function () { | ||
28 | this.timeout(120000) | ||
29 | |||
30 | servers = await prepareViewsServers() | ||
31 | }) | ||
32 | |||
33 | describe('Test views counter on VOD', function () { | ||
34 | let videoUUID: string | ||
35 | |||
36 | before(async function () { | ||
37 | this.timeout(30000) | ||
38 | |||
39 | const { uuid } = await servers[0].videos.quickUpload({ name: 'video' }) | ||
40 | videoUUID = uuid | ||
41 | |||
42 | await waitJobs(servers) | ||
43 | }) | ||
44 | |||
45 | it('Should not view a video if watch time is below the threshold', async function () { | ||
46 | await servers[0].views.simulateViewer({ id: videoUUID, currentTimes: [ 1, 2 ] }) | ||
47 | await processViewsBuffer(servers) | ||
48 | |||
49 | await checkCounter('views', videoUUID, 0) | ||
50 | }) | ||
51 | |||
52 | it('Should view a video if watch time is above the threshold', async function () { | ||
53 | await servers[0].views.simulateViewer({ id: videoUUID, currentTimes: [ 1, 4 ] }) | ||
54 | await processViewsBuffer(servers) | ||
55 | |||
56 | await checkCounter('views', videoUUID, 1) | ||
57 | }) | ||
58 | |||
59 | it('Should not view again this video with the same IP', async function () { | ||
60 | await servers[0].views.simulateViewer({ id: videoUUID, currentTimes: [ 1, 4 ] }) | ||
61 | await processViewsBuffer(servers) | ||
62 | |||
63 | await checkCounter('views', videoUUID, 1) | ||
64 | }) | ||
65 | |||
66 | it('Should view the video from server 2 and send the event', async function () { | ||
67 | await servers[1].views.simulateViewer({ id: videoUUID, currentTimes: [ 1, 4 ] }) | ||
68 | await waitJobs(servers) | ||
69 | await processViewsBuffer(servers) | ||
70 | |||
71 | await checkCounter('views', videoUUID, 2) | ||
72 | }) | ||
73 | }) | ||
74 | |||
75 | describe('Test views and viewers counters on live and VOD', function () { | ||
76 | let liveVideoId: string | ||
77 | let vodVideoId: string | ||
78 | let command: FfmpegCommand | ||
79 | |||
80 | before(async function () { | ||
81 | this.timeout(60000); | ||
82 | |||
83 | ({ vodVideoId, liveVideoId, ffmpegCommand: command } = await prepareViewsVideos({ servers, live: true, vod: true })) | ||
84 | }) | ||
85 | |||
86 | it('Should display no views and viewers', async function () { | ||
87 | await checkCounter('views', liveVideoId, 0) | ||
88 | await checkCounter('viewers', liveVideoId, 0) | ||
89 | |||
90 | await checkCounter('views', vodVideoId, 0) | ||
91 | await checkCounter('viewers', vodVideoId, 0) | ||
92 | }) | ||
93 | |||
94 | it('Should view twice and display 1 view/viewer', async function () { | ||
95 | this.timeout(30000) | ||
96 | |||
97 | await servers[0].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35 ] }) | ||
98 | await servers[0].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35 ] }) | ||
99 | await servers[0].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] }) | ||
100 | await servers[0].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] }) | ||
101 | |||
102 | await waitJobs(servers) | ||
103 | await checkCounter('viewers', liveVideoId, 1) | ||
104 | await checkCounter('viewers', vodVideoId, 1) | ||
105 | |||
106 | await processViewsBuffer(servers) | ||
107 | |||
108 | await checkCounter('views', liveVideoId, 1) | ||
109 | await checkCounter('views', vodVideoId, 1) | ||
110 | }) | ||
111 | |||
112 | it('Should wait and display 0 viewers but still have 1 view', async function () { | ||
113 | this.timeout(30000) | ||
114 | |||
115 | await wait(12000) | ||
116 | await waitJobs(servers) | ||
117 | |||
118 | await checkCounter('views', liveVideoId, 1) | ||
119 | await checkCounter('viewers', liveVideoId, 0) | ||
120 | |||
121 | await checkCounter('views', vodVideoId, 1) | ||
122 | await checkCounter('viewers', vodVideoId, 0) | ||
123 | }) | ||
124 | |||
125 | it('Should view on a remote and on local and display 2 viewers and 3 views', async function () { | ||
126 | this.timeout(30000) | ||
127 | |||
128 | await servers[0].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] }) | ||
129 | await servers[1].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] }) | ||
130 | await servers[1].views.simulateViewer({ id: vodVideoId, currentTimes: [ 0, 5 ] }) | ||
131 | |||
132 | await servers[0].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35 ] }) | ||
133 | await servers[1].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35 ] }) | ||
134 | await servers[1].views.simulateViewer({ id: liveVideoId, currentTimes: [ 0, 35 ] }) | ||
135 | |||
136 | await waitJobs(servers) | ||
137 | |||
138 | await checkCounter('viewers', liveVideoId, 2) | ||
139 | await checkCounter('viewers', vodVideoId, 2) | ||
140 | |||
141 | await processViewsBuffer(servers) | ||
142 | |||
143 | await checkCounter('views', liveVideoId, 3) | ||
144 | await checkCounter('views', vodVideoId, 3) | ||
145 | }) | ||
146 | |||
147 | after(async function () { | ||
148 | await stopFfmpeg(command) | ||
149 | }) | ||
150 | }) | ||
151 | |||
152 | after(async function () { | ||
153 | await cleanupTests(servers) | ||
154 | }) | ||
155 | }) | ||