diff options
Diffstat (limited to 'server/tests/api/videos')
-rw-r--r-- | server/tests/api/videos/video-hls.ts | 191 |
1 files changed, 125 insertions, 66 deletions
diff --git a/server/tests/api/videos/video-hls.ts b/server/tests/api/videos/video-hls.ts index 39178bb1a..289209177 100644 --- a/server/tests/api/videos/video-hls.ts +++ b/server/tests/api/videos/video-hls.ts | |||
@@ -10,13 +10,13 @@ import { | |||
10 | doubleFollow, | 10 | doubleFollow, |
11 | flushAndRunMultipleServers, | 11 | flushAndRunMultipleServers, |
12 | getPlaylist, | 12 | getPlaylist, |
13 | getVideo, | 13 | getVideo, makeGetRequest, makeRawRequest, |
14 | removeVideo, | 14 | removeVideo, |
15 | ServerInfo, | 15 | ServerInfo, |
16 | setAccessTokensToServers, | 16 | setAccessTokensToServers, updateCustomSubConfig, |
17 | updateVideo, | 17 | updateVideo, |
18 | uploadVideo, | 18 | uploadVideo, |
19 | waitJobs | 19 | waitJobs, webtorrentAdd |
20 | } from '../../../../shared/extra-utils' | 20 | } from '../../../../shared/extra-utils' |
21 | import { VideoDetails } from '../../../../shared/models/videos' | 21 | import { VideoDetails } from '../../../../shared/models/videos' |
22 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' | 22 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' |
@@ -25,20 +25,45 @@ import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' | |||
25 | 25 | ||
26 | const expect = chai.expect | 26 | const expect = chai.expect |
27 | 27 | ||
28 | async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, resolutions = [ 240, 360, 480, 720 ]) { | 28 | async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, hlsOnly: boolean, resolutions = [ 240, 360, 480, 720 ]) { |
29 | for (const server of servers) { | 29 | for (const server of servers) { |
30 | const res = await getVideo(server.url, videoUUID) | 30 | const resVideoDetails = await getVideo(server.url, videoUUID) |
31 | const videoDetails: VideoDetails = res.body | 31 | const videoDetails: VideoDetails = resVideoDetails.body |
32 | const baseUrl = `http://${videoDetails.account.host}` | ||
32 | 33 | ||
33 | expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) | 34 | expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) |
34 | 35 | ||
35 | const hlsPlaylist = videoDetails.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) | 36 | const hlsPlaylist = videoDetails.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) |
36 | expect(hlsPlaylist).to.not.be.undefined | 37 | expect(hlsPlaylist).to.not.be.undefined |
37 | 38 | ||
39 | const hlsFiles = hlsPlaylist.files | ||
40 | expect(hlsFiles).to.have.lengthOf(resolutions.length) | ||
41 | |||
42 | if (hlsOnly) expect(videoDetails.files).to.have.lengthOf(0) | ||
43 | else expect(videoDetails.files).to.have.lengthOf(resolutions.length) | ||
44 | |||
45 | for (const resolution of resolutions) { | ||
46 | const file = hlsFiles.find(f => f.resolution.id === resolution) | ||
47 | expect(file).to.not.be.undefined | ||
48 | |||
49 | expect(file.magnetUri).to.have.lengthOf.above(2) | ||
50 | expect(file.torrentUrl).to.equal(`${baseUrl}/static/torrents/${videoDetails.uuid}-${file.resolution.id}-hls.torrent`) | ||
51 | expect(file.fileUrl).to.equal(`${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${videoDetails.uuid}-${file.resolution.id}-fragmented.mp4`) | ||
52 | expect(file.resolution.label).to.equal(resolution + 'p') | ||
53 | |||
54 | await makeRawRequest(file.torrentUrl, 200) | ||
55 | await makeRawRequest(file.fileUrl, 200) | ||
56 | |||
57 | const torrent = await webtorrentAdd(file.magnetUri, true) | ||
58 | expect(torrent.files).to.be.an('array') | ||
59 | expect(torrent.files.length).to.equal(1) | ||
60 | expect(torrent.files[0].path).to.exist.and.to.not.equal('') | ||
61 | } | ||
62 | |||
38 | { | 63 | { |
39 | const res2 = await getPlaylist(hlsPlaylist.playlistUrl) | 64 | const res = await getPlaylist(hlsPlaylist.playlistUrl) |
40 | 65 | ||
41 | const masterPlaylist = res2.text | 66 | const masterPlaylist = res.text |
42 | 67 | ||
43 | for (const resolution of resolutions) { | 68 | for (const resolution of resolutions) { |
44 | expect(masterPlaylist).to.match(new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+')) | 69 | expect(masterPlaylist).to.match(new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+')) |
@@ -48,18 +73,18 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, resol | |||
48 | 73 | ||
49 | { | 74 | { |
50 | for (const resolution of resolutions) { | 75 | for (const resolution of resolutions) { |
51 | const res2 = await getPlaylist(`http://localhost:${servers[0].port}/static/streaming-playlists/hls/${videoUUID}/${resolution}.m3u8`) | 76 | const res = await getPlaylist(`${baseUrl}/static/streaming-playlists/hls/${videoUUID}/${resolution}.m3u8`) |
52 | 77 | ||
53 | const subPlaylist = res2.text | 78 | const subPlaylist = res.text |
54 | expect(subPlaylist).to.contain(`${videoUUID}-${resolution}-fragmented.mp4`) | 79 | expect(subPlaylist).to.contain(`${videoUUID}-${resolution}-fragmented.mp4`) |
55 | } | 80 | } |
56 | } | 81 | } |
57 | 82 | ||
58 | { | 83 | { |
59 | const baseUrl = 'http://localhost:' + servers[0].port + '/static/streaming-playlists/hls' | 84 | const baseUrlAndPath = baseUrl + '/static/streaming-playlists/hls' |
60 | 85 | ||
61 | for (const resolution of resolutions) { | 86 | for (const resolution of resolutions) { |
62 | await checkSegmentHash(baseUrl, baseUrl, videoUUID, resolution, hlsPlaylist) | 87 | await checkSegmentHash(baseUrlAndPath, baseUrlAndPath, videoUUID, resolution, hlsPlaylist) |
63 | } | 88 | } |
64 | } | 89 | } |
65 | } | 90 | } |
@@ -70,84 +95,118 @@ describe('Test HLS videos', function () { | |||
70 | let videoUUID = '' | 95 | let videoUUID = '' |
71 | let videoAudioUUID = '' | 96 | let videoAudioUUID = '' |
72 | 97 | ||
73 | before(async function () { | 98 | function runTestSuite (hlsOnly: boolean) { |
74 | this.timeout(120000) | 99 | it('Should upload a video and transcode it to HLS', async function () { |
100 | this.timeout(120000) | ||
75 | 101 | ||
76 | const configOverride = { | 102 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1', fixture: 'video_short.webm' }) |
77 | transcoding: { | 103 | videoUUID = res.body.video.uuid |
78 | enabled: true, | ||
79 | allow_audio_files: true, | ||
80 | hls: { | ||
81 | enabled: true | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | servers = await flushAndRunMultipleServers(2, configOverride) | ||
86 | 104 | ||
87 | // Get the access tokens | 105 | await waitJobs(servers) |
88 | await setAccessTokensToServers(servers) | ||
89 | 106 | ||
90 | // Server 1 and server 2 follow each other | 107 | await checkHlsPlaylist(servers, videoUUID, hlsOnly) |
91 | await doubleFollow(servers[0], servers[1]) | 108 | }) |
92 | }) | ||
93 | 109 | ||
94 | it('Should upload a video and transcode it to HLS', async function () { | 110 | it('Should upload an audio file and transcode it to HLS', async function () { |
95 | this.timeout(120000) | 111 | this.timeout(120000) |
96 | 112 | ||
97 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1', fixture: 'video_short.webm' }) | 113 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video audio', fixture: 'sample.ogg' }) |
98 | videoUUID = res.body.video.uuid | 114 | videoAudioUUID = res.body.video.uuid |
99 | 115 | ||
100 | await waitJobs(servers) | 116 | await waitJobs(servers) |
101 | 117 | ||
102 | await checkHlsPlaylist(servers, videoUUID) | 118 | await checkHlsPlaylist(servers, videoAudioUUID, hlsOnly, [ DEFAULT_AUDIO_RESOLUTION ]) |
103 | }) | 119 | }) |
104 | 120 | ||
105 | it('Should upload an audio file and transcode it to HLS', async function () { | 121 | it('Should update the video', async function () { |
106 | this.timeout(120000) | 122 | this.timeout(10000) |
107 | 123 | ||
108 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video audio', fixture: 'sample.ogg' }) | 124 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, { name: 'video 1 updated' }) |
109 | videoAudioUUID = res.body.video.uuid | ||
110 | 125 | ||
111 | await waitJobs(servers) | 126 | await waitJobs(servers) |
112 | 127 | ||
113 | await checkHlsPlaylist(servers, videoAudioUUID, [ DEFAULT_AUDIO_RESOLUTION ]) | 128 | await checkHlsPlaylist(servers, videoUUID, hlsOnly) |
114 | }) | 129 | }) |
115 | 130 | ||
116 | it('Should update the video', async function () { | 131 | it('Should delete videos', async function () { |
117 | this.timeout(10000) | 132 | this.timeout(10000) |
118 | 133 | ||
119 | await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { name: 'video 1 updated' }) | 134 | await removeVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID) |
135 | await removeVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAudioUUID) | ||
120 | 136 | ||
121 | await waitJobs(servers) | 137 | await waitJobs(servers) |
122 | 138 | ||
123 | await checkHlsPlaylist(servers, videoUUID) | 139 | for (const server of servers) { |
124 | }) | 140 | await getVideo(server.url, videoUUID, 404) |
141 | await getVideo(server.url, videoAudioUUID, 404) | ||
142 | } | ||
143 | }) | ||
125 | 144 | ||
126 | it('Should delete videos', async function () { | 145 | it('Should have the playlists/segment deleted from the disk', async function () { |
127 | this.timeout(10000) | 146 | for (const server of servers) { |
147 | await checkDirectoryIsEmpty(server, 'videos') | ||
148 | await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls')) | ||
149 | } | ||
150 | }) | ||
128 | 151 | ||
129 | await removeVideo(servers[0].url, servers[0].accessToken, videoUUID) | 152 | it('Should have an empty tmp directory', async function () { |
130 | await removeVideo(servers[0].url, servers[0].accessToken, videoAudioUUID) | 153 | for (const server of servers) { |
154 | await checkTmpIsEmpty(server) | ||
155 | } | ||
156 | }) | ||
157 | } | ||
131 | 158 | ||
132 | await waitJobs(servers) | 159 | before(async function () { |
160 | this.timeout(120000) | ||
133 | 161 | ||
134 | for (const server of servers) { | 162 | const configOverride = { |
135 | await getVideo(server.url, videoUUID, 404) | 163 | transcoding: { |
136 | await getVideo(server.url, videoAudioUUID, 404) | 164 | enabled: true, |
165 | allow_audio_files: true, | ||
166 | hls: { | ||
167 | enabled: true | ||
168 | } | ||
169 | } | ||
137 | } | 170 | } |
171 | servers = await flushAndRunMultipleServers(2, configOverride) | ||
172 | |||
173 | // Get the access tokens | ||
174 | await setAccessTokensToServers(servers) | ||
175 | |||
176 | // Server 1 and server 2 follow each other | ||
177 | await doubleFollow(servers[0], servers[1]) | ||
138 | }) | 178 | }) |
139 | 179 | ||
140 | it('Should have the playlists/segment deleted from the disk', async function () { | 180 | describe('With WebTorrent & HLS enabled', function () { |
141 | for (const server of servers) { | 181 | runTestSuite(false) |
142 | await checkDirectoryIsEmpty(server, 'videos') | ||
143 | await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls')) | ||
144 | } | ||
145 | }) | 182 | }) |
146 | 183 | ||
147 | it('Should have an empty tmp directory', async function () { | 184 | describe('With only HLS enabled', function () { |
148 | for (const server of servers) { | 185 | |
149 | await checkTmpIsEmpty(server) | 186 | before(async function () { |
150 | } | 187 | await updateCustomSubConfig(servers[0].url, servers[0].accessToken, { |
188 | transcoding: { | ||
189 | enabled: true, | ||
190 | allowAudioFiles: true, | ||
191 | resolutions: { | ||
192 | '240p': true, | ||
193 | '360p': true, | ||
194 | '480p': true, | ||
195 | '720p': true, | ||
196 | '1080p': true, | ||
197 | '2160p': true | ||
198 | }, | ||
199 | hls: { | ||
200 | enabled: true | ||
201 | }, | ||
202 | webtorrent: { | ||
203 | enabled: false | ||
204 | } | ||
205 | } | ||
206 | }) | ||
207 | }) | ||
208 | |||
209 | runTestSuite(true) | ||
151 | }) | 210 | }) |
152 | 211 | ||
153 | after(async function () { | 212 | after(async function () { |