]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/api/object-storage/live.ts
Bumped to version v5.2.1
[github/Chocobozzz/PeerTube.git] / server / tests / api / object-storage / live.ts
CommitLineData
0305db28
JB
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
86347717 3import { expect } from 'chai'
d102de1b 4import { expectStartWith, MockObjectStorageProxy, SQLCommand, testLiveVideoResolutions } from '@server/tests/shared'
9ab330b9 5import { areMockObjectStorageTestsDisabled } from '@shared/core-utils'
cfd57d2c 6import { HttpStatusCode, LiveVideoCreate, VideoPrivacy } from '@shared/models'
0305db28 7import {
644391be 8 cleanupTests,
0305db28
JB
9 createMultipleServers,
10 doubleFollow,
4ec52d04 11 findExternalSavedVideo,
0305db28
JB
12 makeRawRequest,
13 ObjectStorageCommand,
14 PeerTubeServer,
15 setAccessTokensToServers,
16 setDefaultVideoChannel,
17 stopFfmpeg,
18 waitJobs,
19 waitUntilLivePublishedOnAllServers,
4ec52d04
C
20 waitUntilLiveReplacedByReplayOnAllServers,
21 waitUntilLiveWaitingOnAllServers
bf54587a 22} from '@shared/server-commands'
0305db28 23
4ec52d04 24async function createLive (server: PeerTubeServer, permanent: boolean) {
0305db28
JB
25 const attributes: LiveVideoCreate = {
26 channelId: server.store.channel.id,
27 privacy: VideoPrivacy.PUBLIC,
28 name: 'my super live',
4ec52d04 29 saveReplay: true,
05a60d85 30 replaySettings: { privacy: VideoPrivacy.PUBLIC },
4ec52d04 31 permanentLive: permanent
0305db28
JB
32 }
33
34 const { uuid } = await server.live.create({ fields: attributes })
35
36 return uuid
37}
38
f8918990
C
39async function checkFilesExist (options: {
40 servers: PeerTubeServer[]
41 videoUUID: string
42 numberOfFiles: number
43 objectStorage: ObjectStorageCommand
44}) {
45 const { servers, videoUUID, numberOfFiles, objectStorage } = options
46
cfd57d2c
C
47 for (const server of servers) {
48 const video = await server.videos.get({ id: videoUUID })
0305db28 49
cfd57d2c
C
50 expect(video.files).to.have.lengthOf(0)
51 expect(video.streamingPlaylists).to.have.lengthOf(1)
0305db28 52
cfd57d2c
C
53 const files = video.streamingPlaylists[0].files
54 expect(files).to.have.lengthOf(numberOfFiles)
4ec52d04 55
cfd57d2c 56 for (const file of files) {
f8918990 57 expectStartWith(file.fileUrl, objectStorage.getMockPlaylistBaseUrl())
4ec52d04 58
3545e72c 59 await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 })
cfd57d2c
C
60 }
61 }
4ec52d04
C
62}
63
f8918990
C
64async function checkFilesCleanup (options: {
65 server: PeerTubeServer
66 videoUUID: string
67 resolutions: number[]
68 objectStorage: ObjectStorageCommand
69}) {
70 const { server, videoUUID, resolutions, objectStorage } = options
71
cfd57d2c 72 const resolutionFiles = resolutions.map((_value, i) => `${i}.m3u8`)
4ec52d04 73
cfd57d2c
C
74 for (const playlistName of [ 'master.m3u8' ].concat(resolutionFiles)) {
75 await server.live.getPlaylistFile({
76 videoUUID,
77 playlistName,
78 expectedStatus: HttpStatusCode.NOT_FOUND_404,
f8918990 79 objectStorage
cfd57d2c 80 })
4ec52d04
C
81 }
82
cfd57d2c
C
83 await server.live.getSegmentFile({
84 videoUUID,
85 playlistNumber: 0,
86 segment: 0,
f8918990 87 objectStorage,
cfd57d2c
C
88 expectedStatus: HttpStatusCode.NOT_FOUND_404
89 })
4ec52d04
C
90}
91
0305db28 92describe('Object storage for lives', function () {
9ab330b9 93 if (areMockObjectStorageTestsDisabled()) return
0305db28 94
0305db28 95 let servers: PeerTubeServer[]
d102de1b 96 let sqlCommandServer1: SQLCommand
f8918990 97 const objectStorage = new ObjectStorageCommand()
0305db28
JB
98
99 before(async function () {
100 this.timeout(120000)
101
f8918990
C
102 await objectStorage.prepareDefaultMockBuckets()
103 servers = await createMultipleServers(2, objectStorage.getDefaultMockConfig())
0305db28
JB
104
105 await setAccessTokensToServers(servers)
106 await setDefaultVideoChannel(servers)
107 await doubleFollow(servers[0], servers[1])
108
109 await servers[0].config.enableTranscoding()
d102de1b
C
110
111 sqlCommandServer1 = new SQLCommand(servers[0])
0305db28
JB
112 })
113
8059e050 114 describe('Without live transcoding', function () {
4ec52d04 115 let videoUUID: string
0305db28
JB
116
117 before(async function () {
118 await servers[0].config.enableLive({ transcoding: false })
119
4ec52d04 120 videoUUID = await createLive(servers[0], false)
0305db28
JB
121 })
122
cfd57d2c
C
123 it('Should create a live and publish it on object storage', async function () {
124 this.timeout(220000)
125
126 const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUID })
127 await waitUntilLivePublishedOnAllServers(servers, videoUUID)
128
d102de1b 129 await testLiveVideoResolutions({
cfd57d2c 130 originServer: servers[0],
d102de1b 131 sqlCommand: sqlCommandServer1,
cfd57d2c
C
132 servers,
133 liveVideoId: videoUUID,
134 resolutions: [ 720 ],
135 transcoded: false,
f8918990 136 objectStorage
cfd57d2c
C
137 })
138
139 await stopFfmpeg(ffmpegCommand)
140 })
141
142 it('Should have saved the replay on object storage', async function () {
0305db28
JB
143 this.timeout(220000)
144
cfd57d2c
C
145 await waitUntilLiveReplacedByReplayOnAllServers(servers, videoUUID)
146 await waitJobs(servers)
0305db28 147
f8918990 148 await checkFilesExist({ servers, videoUUID, numberOfFiles: 1, objectStorage })
cfd57d2c 149 })
0305db28 150
cfd57d2c 151 it('Should have cleaned up live files from object storage', async function () {
f8918990 152 await checkFilesCleanup({ server: servers[0], videoUUID, resolutions: [ 720 ], objectStorage })
0305db28
JB
153 })
154 })
155
8059e050 156 describe('With live transcoding', function () {
cfd57d2c 157 const resolutions = [ 720, 480, 360, 240, 144 ]
0305db28
JB
158
159 before(async function () {
160 await servers[0].config.enableLive({ transcoding: true })
0305db28
JB
161 })
162
cfd57d2c
C
163 describe('Normal replay', function () {
164 let videoUUIDNonPermanent: string
165
166 before(async function () {
167 videoUUIDNonPermanent = await createLive(servers[0], false)
168 })
169
170 it('Should create a live and publish it on object storage', async function () {
171 this.timeout(240000)
172
173 const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDNonPermanent })
174 await waitUntilLivePublishedOnAllServers(servers, videoUUIDNonPermanent)
175
d102de1b 176 await testLiveVideoResolutions({
cfd57d2c 177 originServer: servers[0],
d102de1b 178 sqlCommand: sqlCommandServer1,
cfd57d2c
C
179 servers,
180 liveVideoId: videoUUIDNonPermanent,
181 resolutions,
182 transcoded: true,
f8918990 183 objectStorage
cfd57d2c
C
184 })
185
186 await stopFfmpeg(ffmpegCommand)
187 })
0305db28 188
cfd57d2c
C
189 it('Should have saved the replay on object storage', async function () {
190 this.timeout(220000)
0305db28 191
cfd57d2c
C
192 await waitUntilLiveReplacedByReplayOnAllServers(servers, videoUUIDNonPermanent)
193 await waitJobs(servers)
0305db28 194
f8918990 195 await checkFilesExist({ servers, videoUUID: videoUUIDNonPermanent, numberOfFiles: 5, objectStorage })
cfd57d2c
C
196 })
197
198 it('Should have cleaned up live files from object storage', async function () {
f8918990 199 await checkFilesCleanup({ server: servers[0], videoUUID: videoUUIDNonPermanent, resolutions, objectStorage })
cfd57d2c 200 })
4ec52d04 201 })
0305db28 202
cfd57d2c
C
203 describe('Permanent replay', function () {
204 let videoUUIDPermanent: string
205
206 before(async function () {
207 videoUUIDPermanent = await createLive(servers[0], true)
208 })
209
210 it('Should create a live and publish it on object storage', async function () {
211 this.timeout(240000)
212
213 const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDPermanent })
214 await waitUntilLivePublishedOnAllServers(servers, videoUUIDPermanent)
215
d102de1b 216 await testLiveVideoResolutions({
cfd57d2c 217 originServer: servers[0],
d102de1b 218 sqlCommand: sqlCommandServer1,
cfd57d2c
C
219 servers,
220 liveVideoId: videoUUIDPermanent,
221 resolutions,
222 transcoded: true,
f8918990 223 objectStorage
cfd57d2c
C
224 })
225
226 await stopFfmpeg(ffmpegCommand)
227 })
228
229 it('Should have saved the replay on object storage', async function () {
230 this.timeout(220000)
4ec52d04 231
cfd57d2c
C
232 await waitUntilLiveWaitingOnAllServers(servers, videoUUIDPermanent)
233 await waitJobs(servers)
0305db28 234
cfd57d2c
C
235 const videoLiveDetails = await servers[0].videos.get({ id: videoUUIDPermanent })
236 const replay = await findExternalSavedVideo(servers[0], videoLiveDetails)
0305db28 237
f8918990 238 await checkFilesExist({ servers, videoUUID: replay.uuid, numberOfFiles: 5, objectStorage })
cfd57d2c 239 })
0305db28 240
cfd57d2c 241 it('Should have cleaned up live files from object storage', async function () {
f8918990 242 await checkFilesCleanup({ server: servers[0], videoUUID: videoUUIDPermanent, resolutions, objectStorage })
cfd57d2c 243 })
0305db28
JB
244 })
245 })
246
8059e050
C
247 describe('With object storage base url', function () {
248 const mockObjectStorageProxy = new MockObjectStorageProxy()
249 let baseMockUrl: string
250
251 before(async function () {
252 this.timeout(120000)
253
254 const port = await mockObjectStorageProxy.initialize()
f8918990
C
255 const bucketName = objectStorage.getMockStreamingPlaylistsBucketName()
256 baseMockUrl = `http://127.0.0.1:${port}/${bucketName}`
8059e050 257
f8918990 258 await objectStorage.prepareDefaultMockBuckets()
8059e050
C
259
260 const config = {
261 object_storage: {
262 enabled: true,
263 endpoint: 'http://' + ObjectStorageCommand.getMockEndpointHost(),
264 region: ObjectStorageCommand.getMockRegion(),
265
266 credentials: ObjectStorageCommand.getMockCredentialsConfig(),
267
268 streaming_playlists: {
f8918990 269 bucket_name: bucketName,
8059e050
C
270 prefix: '',
271 base_url: baseMockUrl
272 }
273 }
274 }
275
276 await servers[0].kill()
277 await servers[0].run(config)
278
279 await servers[0].config.enableLive({ transcoding: true, resolutions: 'min' })
280 })
281
282 it('Should publish a live and replace the base url', async function () {
283 this.timeout(240000)
284
285 const videoUUIDPermanent = await createLive(servers[0], true)
286
287 const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDPermanent })
288 await waitUntilLivePublishedOnAllServers(servers, videoUUIDPermanent)
289
d102de1b 290 await testLiveVideoResolutions({
8059e050 291 originServer: servers[0],
d102de1b 292 sqlCommand: sqlCommandServer1,
8059e050
C
293 servers,
294 liveVideoId: videoUUIDPermanent,
295 resolutions: [ 720 ],
296 transcoded: true,
f8918990 297 objectStorage,
8059e050
C
298 objectStorageBaseUrl: baseMockUrl
299 })
300
301 await stopFfmpeg(ffmpegCommand)
302 })
303 })
304
0305db28 305 after(async function () {
d102de1b 306 await sqlCommandServer1.cleanup()
f8918990 307 await objectStorage.cleanupMock()
d102de1b 308
644391be 309 await cleanupTests(servers)
0305db28
JB
310 })
311})