aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/api/transcoding
diff options
context:
space:
mode:
Diffstat (limited to 'server/tests/api/transcoding')
-rw-r--r--server/tests/api/transcoding/create-transcoding.ts10
-rw-r--r--server/tests/api/transcoding/hls.ts163
-rw-r--r--server/tests/api/transcoding/index.ts1
-rw-r--r--server/tests/api/transcoding/update-while-transcoding.ts151
4 files changed, 181 insertions, 144 deletions
diff --git a/server/tests/api/transcoding/create-transcoding.ts b/server/tests/api/transcoding/create-transcoding.ts
index a50bf7654..372f5332a 100644
--- a/server/tests/api/transcoding/create-transcoding.ts
+++ b/server/tests/api/transcoding/create-transcoding.ts
@@ -20,7 +20,7 @@ import {
20async function checkFilesInObjectStorage (video: VideoDetails) { 20async function checkFilesInObjectStorage (video: VideoDetails) {
21 for (const file of video.files) { 21 for (const file of video.files) {
22 expectStartWith(file.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) 22 expectStartWith(file.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl())
23 await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) 23 await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 })
24 } 24 }
25 25
26 if (video.streamingPlaylists.length === 0) return 26 if (video.streamingPlaylists.length === 0) return
@@ -28,14 +28,14 @@ async function checkFilesInObjectStorage (video: VideoDetails) {
28 const hlsPlaylist = video.streamingPlaylists[0] 28 const hlsPlaylist = video.streamingPlaylists[0]
29 for (const file of hlsPlaylist.files) { 29 for (const file of hlsPlaylist.files) {
30 expectStartWith(file.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl()) 30 expectStartWith(file.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl())
31 await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) 31 await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 })
32 } 32 }
33 33
34 expectStartWith(hlsPlaylist.playlistUrl, ObjectStorageCommand.getPlaylistBaseUrl()) 34 expectStartWith(hlsPlaylist.playlistUrl, ObjectStorageCommand.getPlaylistBaseUrl())
35 await makeRawRequest(hlsPlaylist.playlistUrl, HttpStatusCode.OK_200) 35 await makeRawRequest({ url: hlsPlaylist.playlistUrl, expectedStatus: HttpStatusCode.OK_200 })
36 36
37 expectStartWith(hlsPlaylist.segmentsSha256Url, ObjectStorageCommand.getPlaylistBaseUrl()) 37 expectStartWith(hlsPlaylist.segmentsSha256Url, ObjectStorageCommand.getPlaylistBaseUrl())
38 await makeRawRequest(hlsPlaylist.segmentsSha256Url, HttpStatusCode.OK_200) 38 await makeRawRequest({ url: hlsPlaylist.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 })
39} 39}
40 40
41function runTests (objectStorage: boolean) { 41function runTests (objectStorage: boolean) {
@@ -234,7 +234,7 @@ function runTests (objectStorage: boolean) {
234 234
235 it('Should have correctly deleted previous files', async function () { 235 it('Should have correctly deleted previous files', async function () {
236 for (const fileUrl of shouldBeDeleted) { 236 for (const fileUrl of shouldBeDeleted) {
237 await makeRawRequest(fileUrl, HttpStatusCode.NOT_FOUND_404) 237 await makeRawRequest({ url: fileUrl, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
238 } 238 }
239 }) 239 })
240 240
diff --git a/server/tests/api/transcoding/hls.ts b/server/tests/api/transcoding/hls.ts
index 252422e5d..7b5492cd4 100644
--- a/server/tests/api/transcoding/hls.ts
+++ b/server/tests/api/transcoding/hls.ts
@@ -1,168 +1,48 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { expect } from 'chai' 3import { join } from 'path'
4import { basename, join } from 'path' 4import { checkDirectoryIsEmpty, checkTmpIsEmpty, completeCheckHlsPlaylist } from '@server/tests/shared'
5import { 5import { areObjectStorageTestsDisabled } from '@shared/core-utils'
6 checkDirectoryIsEmpty, 6import { HttpStatusCode } from '@shared/models'
7 checkResolutionsInMasterPlaylist,
8 checkSegmentHash,
9 checkTmpIsEmpty,
10 expectStartWith,
11 hlsInfohashExist
12} from '@server/tests/shared'
13import { areObjectStorageTestsDisabled, removeFragmentedMP4Ext, uuidRegex } from '@shared/core-utils'
14import { HttpStatusCode, VideoStreamingPlaylistType } from '@shared/models'
15import { 7import {
16 cleanupTests, 8 cleanupTests,
17 createMultipleServers, 9 createMultipleServers,
18 doubleFollow, 10 doubleFollow,
19 makeRawRequest,
20 ObjectStorageCommand, 11 ObjectStorageCommand,
21 PeerTubeServer, 12 PeerTubeServer,
22 setAccessTokensToServers, 13 setAccessTokensToServers,
23 waitJobs, 14 waitJobs
24 webtorrentAdd
25} from '@shared/server-commands' 15} from '@shared/server-commands'
26import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' 16import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants'
27 17
28async function checkHlsPlaylist (options: {
29 servers: PeerTubeServer[]
30 videoUUID: string
31 hlsOnly: boolean
32
33 resolutions?: number[]
34 objectStorageBaseUrl: string
35}) {
36 const { videoUUID, hlsOnly, objectStorageBaseUrl } = options
37
38 const resolutions = options.resolutions ?? [ 240, 360, 480, 720 ]
39
40 for (const server of options.servers) {
41 const videoDetails = await server.videos.get({ id: videoUUID })
42 const baseUrl = `http://${videoDetails.account.host}`
43
44 expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
45
46 const hlsPlaylist = videoDetails.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS)
47 expect(hlsPlaylist).to.not.be.undefined
48
49 const hlsFiles = hlsPlaylist.files
50 expect(hlsFiles).to.have.lengthOf(resolutions.length)
51
52 if (hlsOnly) expect(videoDetails.files).to.have.lengthOf(0)
53 else expect(videoDetails.files).to.have.lengthOf(resolutions.length)
54
55 // Check JSON files
56 for (const resolution of resolutions) {
57 const file = hlsFiles.find(f => f.resolution.id === resolution)
58 expect(file).to.not.be.undefined
59
60 expect(file.magnetUri).to.have.lengthOf.above(2)
61 expect(file.torrentUrl).to.match(
62 new RegExp(`http://${server.host}/lazy-static/torrents/${uuidRegex}-${file.resolution.id}-hls.torrent`)
63 )
64
65 if (objectStorageBaseUrl) {
66 expectStartWith(file.fileUrl, objectStorageBaseUrl)
67 } else {
68 expect(file.fileUrl).to.match(
69 new RegExp(`${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${uuidRegex}-${file.resolution.id}-fragmented.mp4`)
70 )
71 }
72
73 expect(file.resolution.label).to.equal(resolution + 'p')
74
75 await makeRawRequest(file.torrentUrl, HttpStatusCode.OK_200)
76 await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200)
77
78 const torrent = await webtorrentAdd(file.magnetUri, true)
79 expect(torrent.files).to.be.an('array')
80 expect(torrent.files.length).to.equal(1)
81 expect(torrent.files[0].path).to.exist.and.to.not.equal('')
82 }
83
84 // Check master playlist
85 {
86 await checkResolutionsInMasterPlaylist({ server, playlistUrl: hlsPlaylist.playlistUrl, resolutions })
87
88 const masterPlaylist = await server.streamingPlaylists.get({ url: hlsPlaylist.playlistUrl })
89
90 let i = 0
91 for (const resolution of resolutions) {
92 expect(masterPlaylist).to.contain(`${resolution}.m3u8`)
93 expect(masterPlaylist).to.contain(`${resolution}.m3u8`)
94
95 const url = 'http://' + videoDetails.account.host
96 await hlsInfohashExist(url, hlsPlaylist.playlistUrl, i)
97
98 i++
99 }
100 }
101
102 // Check resolution playlists
103 {
104 for (const resolution of resolutions) {
105 const file = hlsFiles.find(f => f.resolution.id === resolution)
106 const playlistName = removeFragmentedMP4Ext(basename(file.fileUrl)) + '.m3u8'
107
108 const url = objectStorageBaseUrl
109 ? `${objectStorageBaseUrl}hls/${videoUUID}/${playlistName}`
110 : `${baseUrl}/static/streaming-playlists/hls/${videoUUID}/${playlistName}`
111
112 const subPlaylist = await server.streamingPlaylists.get({ url })
113
114 expect(subPlaylist).to.match(new RegExp(`${uuidRegex}-${resolution}-fragmented.mp4`))
115 expect(subPlaylist).to.contain(basename(file.fileUrl))
116 }
117 }
118
119 {
120 const baseUrlAndPath = objectStorageBaseUrl
121 ? objectStorageBaseUrl + 'hls/' + videoUUID
122 : baseUrl + '/static/streaming-playlists/hls/' + videoUUID
123
124 for (const resolution of resolutions) {
125 await checkSegmentHash({
126 server,
127 baseUrlPlaylist: baseUrlAndPath,
128 baseUrlSegment: baseUrlAndPath,
129 resolution,
130 hlsPlaylist
131 })
132 }
133 }
134 }
135}
136
137describe('Test HLS videos', function () { 18describe('Test HLS videos', function () {
138 let servers: PeerTubeServer[] = [] 19 let servers: PeerTubeServer[] = []
139 let videoUUID = ''
140 let videoAudioUUID = ''
141 20
142 function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) { 21 function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) {
22 const videoUUIDs: string[] = []
143 23
144 it('Should upload a video and transcode it to HLS', async function () { 24 it('Should upload a video and transcode it to HLS', async function () {
145 this.timeout(120000) 25 this.timeout(120000)
146 26
147 const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video 1', fixture: 'video_short.webm' } }) 27 const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video 1', fixture: 'video_short.webm' } })
148 videoUUID = uuid 28 videoUUIDs.push(uuid)
149 29
150 await waitJobs(servers) 30 await waitJobs(servers)
151 31
152 await checkHlsPlaylist({ servers, videoUUID, hlsOnly, objectStorageBaseUrl }) 32 await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl })
153 }) 33 })
154 34
155 it('Should upload an audio file and transcode it to HLS', async function () { 35 it('Should upload an audio file and transcode it to HLS', async function () {
156 this.timeout(120000) 36 this.timeout(120000)
157 37
158 const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video audio', fixture: 'sample.ogg' } }) 38 const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video audio', fixture: 'sample.ogg' } })
159 videoAudioUUID = uuid 39 videoUUIDs.push(uuid)
160 40
161 await waitJobs(servers) 41 await waitJobs(servers)
162 42
163 await checkHlsPlaylist({ 43 await completeCheckHlsPlaylist({
164 servers, 44 servers,
165 videoUUID: videoAudioUUID, 45 videoUUID: uuid,
166 hlsOnly, 46 hlsOnly,
167 resolutions: [ DEFAULT_AUDIO_RESOLUTION, 360, 240 ], 47 resolutions: [ DEFAULT_AUDIO_RESOLUTION, 360, 240 ],
168 objectStorageBaseUrl 48 objectStorageBaseUrl
@@ -172,31 +52,36 @@ describe('Test HLS videos', function () {
172 it('Should update the video', async function () { 52 it('Should update the video', async function () {
173 this.timeout(30000) 53 this.timeout(30000)
174 54
175 await servers[0].videos.update({ id: videoUUID, attributes: { name: 'video 1 updated' } }) 55 await servers[0].videos.update({ id: videoUUIDs[0], attributes: { name: 'video 1 updated' } })
176 56
177 await waitJobs(servers) 57 await waitJobs(servers)
178 58
179 await checkHlsPlaylist({ servers, videoUUID, hlsOnly, objectStorageBaseUrl }) 59 await completeCheckHlsPlaylist({ servers, videoUUID: videoUUIDs[0], hlsOnly, objectStorageBaseUrl })
180 }) 60 })
181 61
182 it('Should delete videos', async function () { 62 it('Should delete videos', async function () {
183 this.timeout(10000) 63 this.timeout(10000)
184 64
185 await servers[0].videos.remove({ id: videoUUID }) 65 for (const uuid of videoUUIDs) {
186 await servers[0].videos.remove({ id: videoAudioUUID }) 66 await servers[0].videos.remove({ id: uuid })
67 }
187 68
188 await waitJobs(servers) 69 await waitJobs(servers)
189 70
190 for (const server of servers) { 71 for (const server of servers) {
191 await server.videos.get({ id: videoUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) 72 for (const uuid of videoUUIDs) {
192 await server.videos.get({ id: videoAudioUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) 73 await server.videos.get({ id: uuid, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
74 }
193 } 75 }
194 }) 76 })
195 77
196 it('Should have the playlists/segment deleted from the disk', async function () { 78 it('Should have the playlists/segment deleted from the disk', async function () {
197 for (const server of servers) { 79 for (const server of servers) {
198 await checkDirectoryIsEmpty(server, 'videos') 80 await checkDirectoryIsEmpty(server, 'videos', [ 'private' ])
199 await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls')) 81 await checkDirectoryIsEmpty(server, join('videos', 'private'))
82
83 await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls'), [ 'private' ])
84 await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls', 'private'))
200 } 85 }
201 }) 86 })
202 87
diff --git a/server/tests/api/transcoding/index.ts b/server/tests/api/transcoding/index.ts
index 0cc28b4a4..9866418d6 100644
--- a/server/tests/api/transcoding/index.ts
+++ b/server/tests/api/transcoding/index.ts
@@ -2,4 +2,5 @@ export * from './audio-only'
2export * from './create-transcoding' 2export * from './create-transcoding'
3export * from './hls' 3export * from './hls'
4export * from './transcoder' 4export * from './transcoder'
5export * from './update-while-transcoding'
5export * from './video-studio' 6export * from './video-studio'
diff --git a/server/tests/api/transcoding/update-while-transcoding.ts b/server/tests/api/transcoding/update-while-transcoding.ts
new file mode 100644
index 000000000..5ca923392
--- /dev/null
+++ b/server/tests/api/transcoding/update-while-transcoding.ts
@@ -0,0 +1,151 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { completeCheckHlsPlaylist } from '@server/tests/shared'
4import { areObjectStorageTestsDisabled, wait } from '@shared/core-utils'
5import { VideoPrivacy } from '@shared/models'
6import {
7 cleanupTests,
8 createMultipleServers,
9 doubleFollow,
10 ObjectStorageCommand,
11 PeerTubeServer,
12 setAccessTokensToServers,
13 waitJobs
14} from '@shared/server-commands'
15
16describe('Test update video privacy while transcoding', function () {
17 let servers: PeerTubeServer[] = []
18
19 const videoUUIDs: string[] = []
20
21 function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) {
22
23 it('Should not have an error while quickly updating a private video to public after upload #1', async function () {
24 this.timeout(360_000)
25
26 const attributes = {
27 name: 'quick update',
28 privacy: VideoPrivacy.PRIVATE
29 }
30
31 const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: false })
32 await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } })
33 videoUUIDs.push(uuid)
34
35 await waitJobs(servers)
36
37 await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl })
38 })
39
40 it('Should not have an error while quickly updating a private video to public after upload #2', async function () {
41
42 {
43 const attributes = {
44 name: 'quick update 2',
45 privacy: VideoPrivacy.PRIVATE
46 }
47
48 const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: true })
49 await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } })
50 videoUUIDs.push(uuid)
51
52 await waitJobs(servers)
53
54 await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl })
55 }
56 })
57
58 it('Should not have an error while quickly updating a private video to public after upload #3', async function () {
59 const attributes = {
60 name: 'quick update 3',
61 privacy: VideoPrivacy.PRIVATE
62 }
63
64 const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: true })
65 await wait(1000)
66 await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } })
67 videoUUIDs.push(uuid)
68
69 await waitJobs(servers)
70
71 await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl })
72 })
73 }
74
75 before(async function () {
76 this.timeout(120000)
77
78 const configOverride = {
79 transcoding: {
80 enabled: true,
81 allow_audio_files: true,
82 hls: {
83 enabled: true
84 }
85 }
86 }
87 servers = await createMultipleServers(2, configOverride)
88
89 // Get the access tokens
90 await setAccessTokensToServers(servers)
91
92 // Server 1 and server 2 follow each other
93 await doubleFollow(servers[0], servers[1])
94 })
95
96 describe('With WebTorrent & HLS enabled', function () {
97 runTestSuite(false)
98 })
99
100 describe('With only HLS enabled', function () {
101
102 before(async function () {
103 await servers[0].config.updateCustomSubConfig({
104 newConfig: {
105 transcoding: {
106 enabled: true,
107 allowAudioFiles: true,
108 resolutions: {
109 '144p': false,
110 '240p': true,
111 '360p': true,
112 '480p': true,
113 '720p': true,
114 '1080p': true,
115 '1440p': true,
116 '2160p': true
117 },
118 hls: {
119 enabled: true
120 },
121 webtorrent: {
122 enabled: false
123 }
124 }
125 }
126 })
127 })
128
129 runTestSuite(true)
130 })
131
132 describe('With object storage enabled', function () {
133 if (areObjectStorageTestsDisabled()) return
134
135 before(async function () {
136 this.timeout(120000)
137
138 const configOverride = ObjectStorageCommand.getDefaultConfig()
139 await ObjectStorageCommand.prepareDefaultBuckets()
140
141 await servers[0].kill()
142 await servers[0].run(configOverride)
143 })
144
145 runTestSuite(true, ObjectStorageCommand.getPlaylistBaseUrl())
146 })
147
148 after(async function () {
149 await cleanupTests(servers)
150 })
151})