]>
Commit | Line | Data |
---|---|---|
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | |
2 | import { expect } from 'chai' | |
3 | import { | |
4 | checkPeerTubeRunnerCacheIsEmpty, | |
5 | expectStartWith, | |
6 | PeerTubeRunnerProcess, | |
7 | SQLCommand, | |
8 | testLiveVideoResolutions | |
9 | } from '@server/tests/shared' | |
10 | import { areMockObjectStorageTestsDisabled, wait } from '@shared/core-utils' | |
11 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | |
12 | import { | |
13 | cleanupTests, | |
14 | createMultipleServers, | |
15 | doubleFollow, | |
16 | findExternalSavedVideo, | |
17 | makeRawRequest, | |
18 | ObjectStorageCommand, | |
19 | PeerTubeServer, | |
20 | setAccessTokensToServers, | |
21 | setDefaultVideoChannel, | |
22 | stopFfmpeg, | |
23 | waitJobs, | |
24 | waitUntilLivePublishedOnAllServers, | |
25 | waitUntilLiveWaitingOnAllServers | |
26 | } from '@shared/server-commands' | |
27 | ||
28 | describe('Test Live transcoding in peertube-runner program', function () { | |
29 | let servers: PeerTubeServer[] = [] | |
30 | let peertubeRunner: PeerTubeRunnerProcess | |
31 | let sqlCommandServer1: SQLCommand | |
32 | ||
33 | function runSuite (options: { | |
34 | objectStorage: boolean | |
35 | }) { | |
36 | const { objectStorage } = options | |
37 | ||
38 | it('Should enable transcoding without additional resolutions', async function () { | |
39 | this.timeout(120000) | |
40 | ||
41 | const { video } = await servers[0].live.quickCreate({ permanentLive: true, saveReplay: false, privacy: VideoPrivacy.PUBLIC }) | |
42 | ||
43 | const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: video.uuid }) | |
44 | await waitUntilLivePublishedOnAllServers(servers, video.uuid) | |
45 | await waitJobs(servers) | |
46 | ||
47 | await testLiveVideoResolutions({ | |
48 | originServer: servers[0], | |
49 | sqlCommand: sqlCommandServer1, | |
50 | servers, | |
51 | liveVideoId: video.uuid, | |
52 | resolutions: [ 720, 480, 360, 240, 144 ], | |
53 | objectStorage, | |
54 | transcoded: true | |
55 | }) | |
56 | ||
57 | await stopFfmpeg(ffmpegCommand) | |
58 | ||
59 | await waitUntilLiveWaitingOnAllServers(servers, video.uuid) | |
60 | await servers[0].videos.remove({ id: video.id }) | |
61 | }) | |
62 | ||
63 | it('Should transcode audio only RTMP stream', async function () { | |
64 | this.timeout(120000) | |
65 | ||
66 | const { video } = await servers[0].live.quickCreate({ permanentLive: true, saveReplay: false, privacy: VideoPrivacy.UNLISTED }) | |
67 | ||
68 | const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: video.uuid, fixtureName: 'video_short_no_audio.mp4' }) | |
69 | await waitUntilLivePublishedOnAllServers(servers, video.uuid) | |
70 | await waitJobs(servers) | |
71 | ||
72 | await stopFfmpeg(ffmpegCommand) | |
73 | ||
74 | await waitUntilLiveWaitingOnAllServers(servers, video.uuid) | |
75 | await servers[0].videos.remove({ id: video.id }) | |
76 | }) | |
77 | ||
78 | it('Should save a replay', async function () { | |
79 | this.timeout(240000) | |
80 | ||
81 | const { video } = await servers[0].live.quickCreate({ permanentLive: true, saveReplay: true }) | |
82 | ||
83 | const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: video.uuid }) | |
84 | await waitUntilLivePublishedOnAllServers(servers, video.uuid) | |
85 | ||
86 | await testLiveVideoResolutions({ | |
87 | originServer: servers[0], | |
88 | sqlCommand: sqlCommandServer1, | |
89 | servers, | |
90 | liveVideoId: video.uuid, | |
91 | resolutions: [ 720, 480, 360, 240, 144 ], | |
92 | objectStorage, | |
93 | transcoded: true | |
94 | }) | |
95 | ||
96 | await stopFfmpeg(ffmpegCommand) | |
97 | ||
98 | await waitUntilLiveWaitingOnAllServers(servers, video.uuid) | |
99 | await waitJobs(servers) | |
100 | ||
101 | const session = await servers[0].live.findLatestSession({ videoId: video.uuid }) | |
102 | expect(session.endingProcessed).to.be.true | |
103 | expect(session.endDate).to.exist | |
104 | expect(session.saveReplay).to.be.true | |
105 | ||
106 | const videoLiveDetails = await servers[0].videos.get({ id: video.uuid }) | |
107 | const replay = await findExternalSavedVideo(servers[0], videoLiveDetails) | |
108 | ||
109 | for (const server of servers) { | |
110 | const video = await server.videos.get({ id: replay.uuid }) | |
111 | ||
112 | expect(video.files).to.have.lengthOf(0) | |
113 | expect(video.streamingPlaylists).to.have.lengthOf(1) | |
114 | ||
115 | const files = video.streamingPlaylists[0].files | |
116 | expect(files).to.have.lengthOf(5) | |
117 | ||
118 | for (const file of files) { | |
119 | if (objectStorage) { | |
120 | expectStartWith(file.fileUrl, ObjectStorageCommand.getMockPlaylistBaseUrl()) | |
121 | } | |
122 | ||
123 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) | |
124 | } | |
125 | } | |
126 | }) | |
127 | } | |
128 | ||
129 | before(async function () { | |
130 | this.timeout(120_000) | |
131 | ||
132 | servers = await createMultipleServers(2) | |
133 | ||
134 | await setAccessTokensToServers(servers) | |
135 | await setDefaultVideoChannel(servers) | |
136 | ||
137 | await doubleFollow(servers[0], servers[1]) | |
138 | ||
139 | sqlCommandServer1 = new SQLCommand(servers[0]) | |
140 | ||
141 | await servers[0].config.enableRemoteTranscoding() | |
142 | await servers[0].config.enableTranscoding(true, true, true) | |
143 | await servers[0].config.enableLive({ allowReplay: true, resolutions: 'max', transcoding: true }) | |
144 | ||
145 | const registrationToken = await servers[0].runnerRegistrationTokens.getFirstRegistrationToken() | |
146 | ||
147 | peertubeRunner = new PeerTubeRunnerProcess(servers[0]) | |
148 | await peertubeRunner.runServer() | |
149 | await peertubeRunner.registerPeerTubeInstance({ registrationToken, runnerName: 'runner' }) | |
150 | }) | |
151 | ||
152 | describe('With lives on local filesystem storage', function () { | |
153 | ||
154 | before(async function () { | |
155 | await servers[0].config.enableTranscoding(true, false, true) | |
156 | }) | |
157 | ||
158 | runSuite({ objectStorage: false }) | |
159 | }) | |
160 | ||
161 | describe('With lives on object storage', function () { | |
162 | if (areMockObjectStorageTestsDisabled()) return | |
163 | ||
164 | before(async function () { | |
165 | await ObjectStorageCommand.prepareDefaultMockBuckets() | |
166 | ||
167 | await servers[0].kill() | |
168 | ||
169 | await servers[0].run(ObjectStorageCommand.getDefaultMockConfig()) | |
170 | ||
171 | // Wait for peertube runner socket reconnection | |
172 | await wait(1500) | |
173 | }) | |
174 | ||
175 | runSuite({ objectStorage: true }) | |
176 | }) | |
177 | ||
178 | describe('Check cleanup', function () { | |
179 | ||
180 | it('Should have an empty cache directory', async function () { | |
181 | await checkPeerTubeRunnerCacheIsEmpty(peertubeRunner) | |
182 | }) | |
183 | }) | |
184 | ||
185 | after(async function () { | |
186 | if (peertubeRunner) { | |
187 | await peertubeRunner.unregisterPeerTubeInstance() | |
188 | peertubeRunner.kill() | |
189 | } | |
190 | ||
191 | if (sqlCommandServer1) await sqlCommandServer1.cleanup() | |
192 | ||
193 | await cleanupTests(servers) | |
194 | }) | |
195 | }) |