]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/api/object-storage/live.ts
Feature/Add replay privacy (#5692)
[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'
8059e050 4import { expectStartWith, MockObjectStorageProxy, testVideoResolutions } from '@server/tests/shared'
9ab330b9 5import { areMockObjectStorageTestsDisabled } from '@shared/core-utils'
cfd57d2c 6import { HttpStatusCode, LiveVideoCreate, VideoPrivacy } from '@shared/models'
0305db28 7import {
0305db28
JB
8 createMultipleServers,
9 doubleFollow,
4ec52d04 10 findExternalSavedVideo,
0305db28
JB
11 killallServers,
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
cfd57d2c
C
39async function checkFilesExist (servers: PeerTubeServer[], videoUUID: string, numberOfFiles: number) {
40 for (const server of servers) {
41 const video = await server.videos.get({ id: videoUUID })
0305db28 42
cfd57d2c
C
43 expect(video.files).to.have.lengthOf(0)
44 expect(video.streamingPlaylists).to.have.lengthOf(1)
0305db28 45
cfd57d2c
C
46 const files = video.streamingPlaylists[0].files
47 expect(files).to.have.lengthOf(numberOfFiles)
4ec52d04 48
cfd57d2c 49 for (const file of files) {
9ab330b9 50 expectStartWith(file.fileUrl, ObjectStorageCommand.getMockPlaylistBaseUrl())
4ec52d04 51
3545e72c 52 await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 })
cfd57d2c
C
53 }
54 }
4ec52d04
C
55}
56
cfd57d2c
C
57async function checkFilesCleanup (server: PeerTubeServer, videoUUID: string, resolutions: number[]) {
58 const resolutionFiles = resolutions.map((_value, i) => `${i}.m3u8`)
4ec52d04 59
cfd57d2c
C
60 for (const playlistName of [ 'master.m3u8' ].concat(resolutionFiles)) {
61 await server.live.getPlaylistFile({
62 videoUUID,
63 playlistName,
64 expectedStatus: HttpStatusCode.NOT_FOUND_404,
65 objectStorage: true
66 })
4ec52d04
C
67 }
68
cfd57d2c
C
69 await server.live.getSegmentFile({
70 videoUUID,
71 playlistNumber: 0,
72 segment: 0,
73 objectStorage: true,
74 expectedStatus: HttpStatusCode.NOT_FOUND_404
75 })
4ec52d04
C
76}
77
0305db28 78describe('Object storage for lives', function () {
9ab330b9 79 if (areMockObjectStorageTestsDisabled()) return
0305db28 80
0305db28 81 let servers: PeerTubeServer[]
0305db28
JB
82
83 before(async function () {
84 this.timeout(120000)
85
9ab330b9 86 await ObjectStorageCommand.prepareDefaultMockBuckets()
0305db28 87
9ab330b9 88 servers = await createMultipleServers(2, ObjectStorageCommand.getDefaultMockConfig())
0305db28
JB
89
90 await setAccessTokensToServers(servers)
91 await setDefaultVideoChannel(servers)
92 await doubleFollow(servers[0], servers[1])
93
94 await servers[0].config.enableTranscoding()
95 })
96
8059e050 97 describe('Without live transcoding', function () {
4ec52d04 98 let videoUUID: string
0305db28
JB
99
100 before(async function () {
101 await servers[0].config.enableLive({ transcoding: false })
102
4ec52d04 103 videoUUID = await createLive(servers[0], false)
0305db28
JB
104 })
105
cfd57d2c
C
106 it('Should create a live and publish it on object storage', async function () {
107 this.timeout(220000)
108
109 const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUID })
110 await waitUntilLivePublishedOnAllServers(servers, videoUUID)
111
112 await testVideoResolutions({
113 originServer: servers[0],
114 servers,
115 liveVideoId: videoUUID,
116 resolutions: [ 720 ],
117 transcoded: false,
118 objectStorage: true
119 })
120
121 await stopFfmpeg(ffmpegCommand)
122 })
123
124 it('Should have saved the replay on object storage', async function () {
0305db28
JB
125 this.timeout(220000)
126
cfd57d2c
C
127 await waitUntilLiveReplacedByReplayOnAllServers(servers, videoUUID)
128 await waitJobs(servers)
0305db28 129
cfd57d2c
C
130 await checkFilesExist(servers, videoUUID, 1)
131 })
0305db28 132
cfd57d2c
C
133 it('Should have cleaned up live files from object storage', async function () {
134 await checkFilesCleanup(servers[0], videoUUID, [ 720 ])
0305db28
JB
135 })
136 })
137
8059e050 138 describe('With live transcoding', function () {
cfd57d2c 139 const resolutions = [ 720, 480, 360, 240, 144 ]
0305db28
JB
140
141 before(async function () {
142 await servers[0].config.enableLive({ transcoding: true })
0305db28
JB
143 })
144
cfd57d2c
C
145 describe('Normal replay', function () {
146 let videoUUIDNonPermanent: string
147
148 before(async function () {
149 videoUUIDNonPermanent = await createLive(servers[0], false)
150 })
151
152 it('Should create a live and publish it on object storage', async function () {
153 this.timeout(240000)
154
155 const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDNonPermanent })
156 await waitUntilLivePublishedOnAllServers(servers, videoUUIDNonPermanent)
157
158 await testVideoResolutions({
159 originServer: servers[0],
160 servers,
161 liveVideoId: videoUUIDNonPermanent,
162 resolutions,
163 transcoded: true,
164 objectStorage: true
165 })
166
167 await stopFfmpeg(ffmpegCommand)
168 })
0305db28 169
cfd57d2c
C
170 it('Should have saved the replay on object storage', async function () {
171 this.timeout(220000)
0305db28 172
cfd57d2c
C
173 await waitUntilLiveReplacedByReplayOnAllServers(servers, videoUUIDNonPermanent)
174 await waitJobs(servers)
0305db28 175
cfd57d2c
C
176 await checkFilesExist(servers, videoUUIDNonPermanent, 5)
177 })
178
179 it('Should have cleaned up live files from object storage', async function () {
180 await checkFilesCleanup(servers[0], videoUUIDNonPermanent, resolutions)
181 })
4ec52d04 182 })
0305db28 183
cfd57d2c
C
184 describe('Permanent replay', function () {
185 let videoUUIDPermanent: string
186
187 before(async function () {
188 videoUUIDPermanent = await createLive(servers[0], true)
189 })
190
191 it('Should create a live and publish it on object storage', async function () {
192 this.timeout(240000)
193
194 const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDPermanent })
195 await waitUntilLivePublishedOnAllServers(servers, videoUUIDPermanent)
196
197 await testVideoResolutions({
198 originServer: servers[0],
199 servers,
200 liveVideoId: videoUUIDPermanent,
201 resolutions,
202 transcoded: true,
203 objectStorage: true
204 })
205
206 await stopFfmpeg(ffmpegCommand)
207 })
208
209 it('Should have saved the replay on object storage', async function () {
210 this.timeout(220000)
4ec52d04 211
cfd57d2c
C
212 await waitUntilLiveWaitingOnAllServers(servers, videoUUIDPermanent)
213 await waitJobs(servers)
0305db28 214
cfd57d2c
C
215 const videoLiveDetails = await servers[0].videos.get({ id: videoUUIDPermanent })
216 const replay = await findExternalSavedVideo(servers[0], videoLiveDetails)
0305db28 217
cfd57d2c
C
218 await checkFilesExist(servers, replay.uuid, 5)
219 })
0305db28 220
cfd57d2c
C
221 it('Should have cleaned up live files from object storage', async function () {
222 await checkFilesCleanup(servers[0], videoUUIDPermanent, resolutions)
223 })
0305db28
JB
224 })
225 })
226
8059e050
C
227 describe('With object storage base url', function () {
228 const mockObjectStorageProxy = new MockObjectStorageProxy()
229 let baseMockUrl: string
230
231 before(async function () {
232 this.timeout(120000)
233
234 const port = await mockObjectStorageProxy.initialize()
235 baseMockUrl = `http://127.0.0.1:${port}/streaming-playlists`
236
237 await ObjectStorageCommand.createMockBucket('streaming-playlists')
238
239 const config = {
240 object_storage: {
241 enabled: true,
242 endpoint: 'http://' + ObjectStorageCommand.getMockEndpointHost(),
243 region: ObjectStorageCommand.getMockRegion(),
244
245 credentials: ObjectStorageCommand.getMockCredentialsConfig(),
246
247 streaming_playlists: {
248 bucket_name: 'streaming-playlists',
249 prefix: '',
250 base_url: baseMockUrl
251 }
252 }
253 }
254
255 await servers[0].kill()
256 await servers[0].run(config)
257
258 await servers[0].config.enableLive({ transcoding: true, resolutions: 'min' })
259 })
260
261 it('Should publish a live and replace the base url', async function () {
262 this.timeout(240000)
263
264 const videoUUIDPermanent = await createLive(servers[0], true)
265
266 const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDPermanent })
267 await waitUntilLivePublishedOnAllServers(servers, videoUUIDPermanent)
268
269 await testVideoResolutions({
270 originServer: servers[0],
271 servers,
272 liveVideoId: videoUUIDPermanent,
273 resolutions: [ 720 ],
274 transcoded: true,
275 objectStorage: true,
276 objectStorageBaseUrl: baseMockUrl
277 })
278
279 await stopFfmpeg(ffmpegCommand)
280 })
281 })
282
0305db28
JB
283 after(async function () {
284 await killallServers(servers)
285 })
286})