]>
Commit | Line | Data |
---|---|---|
68e70a74 C |
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' | |
d23dd9fb | 6 | import { HttpStatusCode } from '@shared/core-utils' |
68e70a74 | 7 | import { |
68e70a74 C |
8 | checkLiveCleanup, |
9 | cleanupTests, | |
65e6e260 | 10 | ConfigCommand, |
68e70a74 C |
11 | doubleFollow, |
12 | flushAndRunMultipleServers, | |
68e70a74 C |
13 | ServerInfo, |
14 | setAccessTokensToServers, | |
15 | setDefaultVideoChannel, | |
16 | stopFfmpeg, | |
17 | testFfmpegStreamError, | |
94d721ef | 18 | wait, |
4f219914 | 19 | waitJobs |
d23dd9fb C |
20 | } from '@shared/extra-utils' |
21 | import { LiveVideoCreate, VideoPrivacy, VideoState } from '@shared/models' | |
68e70a74 C |
22 | |
23 | const expect = chai.expect | |
24 | ||
25 | describe('Save replay setting', function () { | |
26 | let servers: ServerInfo[] = [] | |
27 | let liveVideoUUID: string | |
28 | let ffmpegCommand: FfmpegCommand | |
29 | ||
30 | async function createLiveWrapper (saveReplay: boolean) { | |
31 | if (liveVideoUUID) { | |
32 | try { | |
89d241a7 | 33 | await servers[0].videos.remove({ id: liveVideoUUID }) |
68e70a74 C |
34 | await waitJobs(servers) |
35 | } catch {} | |
36 | } | |
37 | ||
38 | const attributes: LiveVideoCreate = { | |
89d241a7 | 39 | channelId: servers[0].store.channel.id, |
68e70a74 C |
40 | privacy: VideoPrivacy.PUBLIC, |
41 | name: 'my super live', | |
42 | saveReplay | |
43 | } | |
44 | ||
89d241a7 | 45 | const { uuid } = await servers[0].live.create({ fields: attributes }) |
4f219914 | 46 | return uuid |
68e70a74 C |
47 | } |
48 | ||
d23dd9fb | 49 | async function checkVideosExist (videoId: string, existsInList: boolean, expectedStatus?: number) { |
68e70a74 C |
50 | for (const server of servers) { |
51 | const length = existsInList ? 1 : 0 | |
52 | ||
89d241a7 | 53 | const { data, total } = await server.videos.list() |
d23dd9fb C |
54 | expect(data).to.have.lengthOf(length) |
55 | expect(total).to.equal(length) | |
68e70a74 | 56 | |
d23dd9fb | 57 | if (expectedStatus) { |
89d241a7 | 58 | await server.videos.get({ id: videoId, expectedStatus }) |
68e70a74 C |
59 | } |
60 | } | |
61 | } | |
62 | ||
63 | async function checkVideoState (videoId: string, state: VideoState) { | |
64 | for (const server of servers) { | |
89d241a7 | 65 | const video = await server.videos.get({ id: videoId }) |
d23dd9fb | 66 | expect(video.state.id).to.equal(state) |
68e70a74 C |
67 | } |
68 | } | |
69 | ||
fae6e4da C |
70 | async function waitUntilLivePublishedOnAllServers (videoId: string) { |
71 | for (const server of servers) { | |
89d241a7 | 72 | await server.live.waitUntilPublished({ videoId }) |
fae6e4da C |
73 | } |
74 | } | |
75 | ||
94d721ef C |
76 | async function waitUntilLiveSavedOnAllServers (videoId: string) { |
77 | for (const server of servers) { | |
89d241a7 | 78 | await server.live.waitUntilSaved({ videoId }) |
94d721ef C |
79 | } |
80 | } | |
81 | ||
68e70a74 C |
82 | before(async function () { |
83 | this.timeout(120000) | |
84 | ||
85 | servers = await flushAndRunMultipleServers(2) | |
86 | ||
87 | // Get the access tokens | |
88 | await setAccessTokensToServers(servers) | |
89 | await setDefaultVideoChannel(servers) | |
90 | ||
91 | // Server 1 and server 2 follow each other | |
92 | await doubleFollow(servers[0], servers[1]) | |
93 | ||
89d241a7 | 94 | await servers[0].config.updateCustomSubConfig({ |
65e6e260 C |
95 | newConfig: { |
96 | live: { | |
97 | enabled: true, | |
98 | allowReplay: true, | |
99 | maxDuration: -1, | |
100 | transcoding: { | |
101 | enabled: false, | |
102 | resolutions: ConfigCommand.getCustomConfigResolutions(true) | |
103 | } | |
68e70a74 C |
104 | } |
105 | } | |
106 | }) | |
107 | }) | |
108 | ||
109 | describe('With save replay disabled', function () { | |
110 | ||
111 | before(async function () { | |
112 | this.timeout(10000) | |
113 | }) | |
114 | ||
115 | it('Should correctly create and federate the "waiting for stream" live', async function () { | |
116 | this.timeout(20000) | |
117 | ||
118 | liveVideoUUID = await createLiveWrapper(false) | |
119 | ||
120 | await waitJobs(servers) | |
121 | ||
f2eb23cd | 122 | await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200) |
68e70a74 C |
123 | await checkVideoState(liveVideoUUID, VideoState.WAITING_FOR_LIVE) |
124 | }) | |
125 | ||
126 | it('Should correctly have updated the live and federated it when streaming in the live', async function () { | |
fae6e4da | 127 | this.timeout(30000) |
68e70a74 | 128 | |
89d241a7 | 129 | ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) |
fae6e4da C |
130 | |
131 | await waitUntilLivePublishedOnAllServers(liveVideoUUID) | |
68e70a74 C |
132 | |
133 | await waitJobs(servers) | |
134 | ||
f2eb23cd | 135 | await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) |
68e70a74 C |
136 | await checkVideoState(liveVideoUUID, VideoState.PUBLISHED) |
137 | }) | |
138 | ||
139 | it('Should correctly delete the video files after the stream ended', async function () { | |
59fd824c | 140 | this.timeout(40000) |
68e70a74 C |
141 | |
142 | await stopFfmpeg(ffmpegCommand) | |
143 | ||
fae6e4da | 144 | for (const server of servers) { |
89d241a7 | 145 | await server.live.waitUntilEnded({ videoId: liveVideoUUID }) |
fae6e4da | 146 | } |
68e70a74 C |
147 | await waitJobs(servers) |
148 | ||
149 | // Live still exist, but cannot be played anymore | |
f2eb23cd | 150 | await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200) |
68e70a74 C |
151 | await checkVideoState(liveVideoUUID, VideoState.LIVE_ENDED) |
152 | ||
153 | // No resolutions saved since we did not save replay | |
154 | await checkLiveCleanup(servers[0], liveVideoUUID, []) | |
155 | }) | |
156 | ||
157 | it('Should correctly terminate the stream on blacklist and delete the live', async function () { | |
158 | this.timeout(40000) | |
159 | ||
160 | liveVideoUUID = await createLiveWrapper(false) | |
161 | ||
89d241a7 | 162 | ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) |
fae6e4da C |
163 | |
164 | await waitUntilLivePublishedOnAllServers(liveVideoUUID) | |
68e70a74 C |
165 | |
166 | await waitJobs(servers) | |
f2eb23cd | 167 | await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) |
68e70a74 C |
168 | |
169 | await Promise.all([ | |
89d241a7 | 170 | servers[0].blacklist.add({ videoId: liveVideoUUID, reason: 'bad live', unfederate: true }), |
68e70a74 C |
171 | testFfmpegStreamError(ffmpegCommand, true) |
172 | ]) | |
173 | ||
174 | await waitJobs(servers) | |
175 | ||
176 | await checkVideosExist(liveVideoUUID, false) | |
177 | ||
89d241a7 C |
178 | await servers[0].videos.get({ id: liveVideoUUID, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) |
179 | await servers[1].videos.get({ id: liveVideoUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | |
68e70a74 | 180 | |
94d721ef C |
181 | await wait(5000) |
182 | await waitJobs(servers) | |
68e70a74 C |
183 | await checkLiveCleanup(servers[0], liveVideoUUID, []) |
184 | }) | |
185 | ||
186 | it('Should correctly terminate the stream on delete and delete the video', async function () { | |
187 | this.timeout(40000) | |
188 | ||
189 | liveVideoUUID = await createLiveWrapper(false) | |
190 | ||
89d241a7 | 191 | ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) |
fae6e4da C |
192 | |
193 | await waitUntilLivePublishedOnAllServers(liveVideoUUID) | |
68e70a74 C |
194 | |
195 | await waitJobs(servers) | |
f2eb23cd | 196 | await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) |
68e70a74 C |
197 | |
198 | await Promise.all([ | |
199 | testFfmpegStreamError(ffmpegCommand, true), | |
89d241a7 | 200 | servers[0].videos.remove({ id: liveVideoUUID }) |
68e70a74 C |
201 | ]) |
202 | ||
94d721ef | 203 | await wait(5000) |
68e70a74 C |
204 | await waitJobs(servers) |
205 | ||
f2eb23cd | 206 | await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) |
68e70a74 C |
207 | await checkLiveCleanup(servers[0], liveVideoUUID, []) |
208 | }) | |
209 | }) | |
210 | ||
211 | describe('With save replay enabled', function () { | |
212 | ||
213 | it('Should correctly create and federate the "waiting for stream" live', async function () { | |
214 | this.timeout(20000) | |
215 | ||
216 | liveVideoUUID = await createLiveWrapper(true) | |
217 | ||
218 | await waitJobs(servers) | |
219 | ||
f2eb23cd | 220 | await checkVideosExist(liveVideoUUID, false, HttpStatusCode.OK_200) |
68e70a74 C |
221 | await checkVideoState(liveVideoUUID, VideoState.WAITING_FOR_LIVE) |
222 | }) | |
223 | ||
224 | it('Should correctly have updated the live and federated it when streaming in the live', async function () { | |
225 | this.timeout(20000) | |
226 | ||
89d241a7 | 227 | ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) |
fae6e4da | 228 | await waitUntilLivePublishedOnAllServers(liveVideoUUID) |
68e70a74 C |
229 | |
230 | await waitJobs(servers) | |
231 | ||
f2eb23cd | 232 | await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) |
68e70a74 C |
233 | await checkVideoState(liveVideoUUID, VideoState.PUBLISHED) |
234 | }) | |
235 | ||
236 | it('Should correctly have saved the live and federated it after the streaming', async function () { | |
237 | this.timeout(30000) | |
238 | ||
239 | await stopFfmpeg(ffmpegCommand) | |
240 | ||
94d721ef | 241 | await waitUntilLiveSavedOnAllServers(liveVideoUUID) |
68e70a74 C |
242 | await waitJobs(servers) |
243 | ||
244 | // Live has been transcoded | |
f2eb23cd | 245 | await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) |
68e70a74 C |
246 | await checkVideoState(liveVideoUUID, VideoState.PUBLISHED) |
247 | }) | |
248 | ||
249 | it('Should update the saved live and correctly federate the updated attributes', async function () { | |
250 | this.timeout(30000) | |
251 | ||
89d241a7 | 252 | await servers[0].videos.update({ id: liveVideoUUID, attributes: { name: 'video updated' } }) |
68e70a74 C |
253 | await waitJobs(servers) |
254 | ||
255 | for (const server of servers) { | |
89d241a7 | 256 | const video = await server.videos.get({ id: liveVideoUUID }) |
d23dd9fb C |
257 | expect(video.name).to.equal('video updated') |
258 | expect(video.isLive).to.be.false | |
68e70a74 C |
259 | } |
260 | }) | |
261 | ||
262 | it('Should have cleaned up the live files', async function () { | |
263 | await checkLiveCleanup(servers[0], liveVideoUUID, [ 720 ]) | |
264 | }) | |
265 | ||
266 | it('Should correctly terminate the stream on blacklist and blacklist the saved replay video', async function () { | |
267 | this.timeout(40000) | |
268 | ||
269 | liveVideoUUID = await createLiveWrapper(true) | |
270 | ||
89d241a7 | 271 | ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) |
fae6e4da | 272 | await waitUntilLivePublishedOnAllServers(liveVideoUUID) |
68e70a74 C |
273 | |
274 | await waitJobs(servers) | |
f2eb23cd | 275 | await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) |
68e70a74 C |
276 | |
277 | await Promise.all([ | |
89d241a7 | 278 | servers[0].blacklist.add({ videoId: liveVideoUUID, reason: 'bad live', unfederate: true }), |
68e70a74 C |
279 | testFfmpegStreamError(ffmpegCommand, true) |
280 | ]) | |
281 | ||
282 | await waitJobs(servers) | |
283 | ||
284 | await checkVideosExist(liveVideoUUID, false) | |
285 | ||
89d241a7 C |
286 | await servers[0].videos.get({ id: liveVideoUUID, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) |
287 | await servers[1].videos.get({ id: liveVideoUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | |
68e70a74 | 288 | |
94d721ef C |
289 | await wait(5000) |
290 | await waitJobs(servers) | |
68e70a74 C |
291 | await checkLiveCleanup(servers[0], liveVideoUUID, [ 720 ]) |
292 | }) | |
293 | ||
294 | it('Should correctly terminate the stream on delete and delete the video', async function () { | |
295 | this.timeout(40000) | |
296 | ||
297 | liveVideoUUID = await createLiveWrapper(true) | |
298 | ||
89d241a7 | 299 | ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) |
fae6e4da | 300 | await waitUntilLivePublishedOnAllServers(liveVideoUUID) |
68e70a74 C |
301 | |
302 | await waitJobs(servers) | |
f2eb23cd | 303 | await checkVideosExist(liveVideoUUID, true, HttpStatusCode.OK_200) |
68e70a74 C |
304 | |
305 | await Promise.all([ | |
89d241a7 | 306 | servers[0].videos.remove({ id: liveVideoUUID }), |
68e70a74 C |
307 | testFfmpegStreamError(ffmpegCommand, true) |
308 | ]) | |
309 | ||
94d721ef | 310 | await wait(5000) |
68e70a74 C |
311 | await waitJobs(servers) |
312 | ||
f2eb23cd | 313 | await checkVideosExist(liveVideoUUID, false, HttpStatusCode.NOT_FOUND_404) |
68e70a74 C |
314 | await checkLiveCleanup(servers[0], liveVideoUUID, []) |
315 | }) | |
316 | }) | |
317 | ||
318 | after(async function () { | |
319 | await cleanupTests(servers) | |
320 | }) | |
321 | }) |