]>
Commit | Line | Data |
---|---|---|
0305db28 JB |
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | ||
86347717 | 3 | import { expect } from 'chai' |
cfd57d2c | 4 | import { expectStartWith, testVideoResolutions } from '@server/tests/shared' |
c55e3d72 | 5 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' |
cfd57d2c | 6 | import { HttpStatusCode, LiveVideoCreate, VideoPrivacy } from '@shared/models' |
0305db28 | 7 | import { |
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 | 24 | async 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 C |
29 | saveReplay: true, |
30 | permanentLive: permanent | |
0305db28 JB |
31 | } |
32 | ||
33 | const { uuid } = await server.live.create({ fields: attributes }) | |
34 | ||
35 | return uuid | |
36 | } | |
37 | ||
cfd57d2c C |
38 | async function checkFilesExist (servers: PeerTubeServer[], videoUUID: string, numberOfFiles: number) { |
39 | for (const server of servers) { | |
40 | const video = await server.videos.get({ id: videoUUID }) | |
0305db28 | 41 | |
cfd57d2c C |
42 | expect(video.files).to.have.lengthOf(0) |
43 | expect(video.streamingPlaylists).to.have.lengthOf(1) | |
0305db28 | 44 | |
cfd57d2c C |
45 | const files = video.streamingPlaylists[0].files |
46 | expect(files).to.have.lengthOf(numberOfFiles) | |
4ec52d04 | 47 | |
cfd57d2c C |
48 | for (const file of files) { |
49 | expectStartWith(file.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl()) | |
4ec52d04 | 50 | |
3545e72c | 51 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) |
cfd57d2c C |
52 | } |
53 | } | |
4ec52d04 C |
54 | } |
55 | ||
cfd57d2c C |
56 | async function checkFilesCleanup (server: PeerTubeServer, videoUUID: string, resolutions: number[]) { |
57 | const resolutionFiles = resolutions.map((_value, i) => `${i}.m3u8`) | |
4ec52d04 | 58 | |
cfd57d2c C |
59 | for (const playlistName of [ 'master.m3u8' ].concat(resolutionFiles)) { |
60 | await server.live.getPlaylistFile({ | |
61 | videoUUID, | |
62 | playlistName, | |
63 | expectedStatus: HttpStatusCode.NOT_FOUND_404, | |
64 | objectStorage: true | |
65 | }) | |
4ec52d04 C |
66 | } |
67 | ||
cfd57d2c C |
68 | await server.live.getSegmentFile({ |
69 | videoUUID, | |
70 | playlistNumber: 0, | |
71 | segment: 0, | |
72 | objectStorage: true, | |
73 | expectedStatus: HttpStatusCode.NOT_FOUND_404 | |
74 | }) | |
4ec52d04 C |
75 | } |
76 | ||
0305db28 JB |
77 | describe('Object storage for lives', function () { |
78 | if (areObjectStorageTestsDisabled()) return | |
79 | ||
0305db28 | 80 | let servers: PeerTubeServer[] |
0305db28 JB |
81 | |
82 | before(async function () { | |
83 | this.timeout(120000) | |
84 | ||
85 | await ObjectStorageCommand.prepareDefaultBuckets() | |
86 | ||
87 | servers = await createMultipleServers(2, ObjectStorageCommand.getDefaultConfig()) | |
88 | ||
89 | await setAccessTokensToServers(servers) | |
90 | await setDefaultVideoChannel(servers) | |
91 | await doubleFollow(servers[0], servers[1]) | |
92 | ||
93 | await servers[0].config.enableTranscoding() | |
94 | }) | |
95 | ||
96 | describe('Without live transcoding', async function () { | |
4ec52d04 | 97 | let videoUUID: string |
0305db28 JB |
98 | |
99 | before(async function () { | |
100 | await servers[0].config.enableLive({ transcoding: false }) | |
101 | ||
4ec52d04 | 102 | videoUUID = await createLive(servers[0], false) |
0305db28 JB |
103 | }) |
104 | ||
cfd57d2c C |
105 | it('Should create a live and publish it on object storage', async function () { |
106 | this.timeout(220000) | |
107 | ||
108 | const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUID }) | |
109 | await waitUntilLivePublishedOnAllServers(servers, videoUUID) | |
110 | ||
111 | await testVideoResolutions({ | |
112 | originServer: servers[0], | |
113 | servers, | |
114 | liveVideoId: videoUUID, | |
115 | resolutions: [ 720 ], | |
116 | transcoded: false, | |
117 | objectStorage: true | |
118 | }) | |
119 | ||
120 | await stopFfmpeg(ffmpegCommand) | |
121 | }) | |
122 | ||
123 | it('Should have saved the replay on object storage', async function () { | |
0305db28 JB |
124 | this.timeout(220000) |
125 | ||
cfd57d2c C |
126 | await waitUntilLiveReplacedByReplayOnAllServers(servers, videoUUID) |
127 | await waitJobs(servers) | |
0305db28 | 128 | |
cfd57d2c C |
129 | await checkFilesExist(servers, videoUUID, 1) |
130 | }) | |
0305db28 | 131 | |
cfd57d2c C |
132 | it('Should have cleaned up live files from object storage', async function () { |
133 | await checkFilesCleanup(servers[0], videoUUID, [ 720 ]) | |
0305db28 JB |
134 | }) |
135 | }) | |
136 | ||
137 | describe('With live transcoding', async function () { | |
cfd57d2c | 138 | const resolutions = [ 720, 480, 360, 240, 144 ] |
0305db28 JB |
139 | |
140 | before(async function () { | |
141 | await servers[0].config.enableLive({ transcoding: true }) | |
0305db28 JB |
142 | }) |
143 | ||
cfd57d2c C |
144 | describe('Normal replay', function () { |
145 | let videoUUIDNonPermanent: string | |
146 | ||
147 | before(async function () { | |
148 | videoUUIDNonPermanent = await createLive(servers[0], false) | |
149 | }) | |
150 | ||
151 | it('Should create a live and publish it on object storage', async function () { | |
152 | this.timeout(240000) | |
153 | ||
154 | const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDNonPermanent }) | |
155 | await waitUntilLivePublishedOnAllServers(servers, videoUUIDNonPermanent) | |
156 | ||
157 | await testVideoResolutions({ | |
158 | originServer: servers[0], | |
159 | servers, | |
160 | liveVideoId: videoUUIDNonPermanent, | |
161 | resolutions, | |
162 | transcoded: true, | |
163 | objectStorage: true | |
164 | }) | |
165 | ||
166 | await stopFfmpeg(ffmpegCommand) | |
167 | }) | |
0305db28 | 168 | |
cfd57d2c C |
169 | it('Should have saved the replay on object storage', async function () { |
170 | this.timeout(220000) | |
0305db28 | 171 | |
cfd57d2c C |
172 | await waitUntilLiveReplacedByReplayOnAllServers(servers, videoUUIDNonPermanent) |
173 | await waitJobs(servers) | |
0305db28 | 174 | |
cfd57d2c C |
175 | await checkFilesExist(servers, videoUUIDNonPermanent, 5) |
176 | }) | |
177 | ||
178 | it('Should have cleaned up live files from object storage', async function () { | |
179 | await checkFilesCleanup(servers[0], videoUUIDNonPermanent, resolutions) | |
180 | }) | |
4ec52d04 | 181 | }) |
0305db28 | 182 | |
cfd57d2c C |
183 | describe('Permanent replay', function () { |
184 | let videoUUIDPermanent: string | |
185 | ||
186 | before(async function () { | |
187 | videoUUIDPermanent = await createLive(servers[0], true) | |
188 | }) | |
189 | ||
190 | it('Should create a live and publish it on object storage', async function () { | |
191 | this.timeout(240000) | |
192 | ||
193 | const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDPermanent }) | |
194 | await waitUntilLivePublishedOnAllServers(servers, videoUUIDPermanent) | |
195 | ||
196 | await testVideoResolutions({ | |
197 | originServer: servers[0], | |
198 | servers, | |
199 | liveVideoId: videoUUIDPermanent, | |
200 | resolutions, | |
201 | transcoded: true, | |
202 | objectStorage: true | |
203 | }) | |
204 | ||
205 | await stopFfmpeg(ffmpegCommand) | |
206 | }) | |
207 | ||
208 | it('Should have saved the replay on object storage', async function () { | |
209 | this.timeout(220000) | |
4ec52d04 | 210 | |
cfd57d2c C |
211 | await waitUntilLiveWaitingOnAllServers(servers, videoUUIDPermanent) |
212 | await waitJobs(servers) | |
0305db28 | 213 | |
cfd57d2c C |
214 | const videoLiveDetails = await servers[0].videos.get({ id: videoUUIDPermanent }) |
215 | const replay = await findExternalSavedVideo(servers[0], videoLiveDetails) | |
0305db28 | 216 | |
cfd57d2c C |
217 | await checkFilesExist(servers, replay.uuid, 5) |
218 | }) | |
0305db28 | 219 | |
cfd57d2c C |
220 | it('Should have cleaned up live files from object storage', async function () { |
221 | await checkFilesCleanup(servers[0], videoUUIDPermanent, resolutions) | |
222 | }) | |
0305db28 JB |
223 | }) |
224 | }) | |
225 | ||
226 | after(async function () { | |
227 | await killallServers(servers) | |
228 | }) | |
229 | }) |