create-transcoding.ts 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
  2. import { expect } from 'chai'
  3. import { checkResolutionsInMasterPlaylist, expectStartWith } from '@server/tests/shared'
  4. import { areMockObjectStorageTestsDisabled } from '@shared/core-utils'
  5. import { HttpStatusCode, VideoDetails } from '@shared/models'
  6. import {
  7. cleanupTests,
  8. ConfigCommand,
  9. createMultipleServers,
  10. doubleFollow,
  11. expectNoFailedTranscodingJob,
  12. makeRawRequest,
  13. ObjectStorageCommand,
  14. PeerTubeServer,
  15. setAccessTokensToServers,
  16. waitJobs
  17. } from '@shared/server-commands'
  18. async function checkFilesInObjectStorage (video: VideoDetails) {
  19. for (const file of video.files) {
  20. expectStartWith(file.fileUrl, ObjectStorageCommand.getMockWebTorrentBaseUrl())
  21. await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 })
  22. }
  23. if (video.streamingPlaylists.length === 0) return
  24. const hlsPlaylist = video.streamingPlaylists[0]
  25. for (const file of hlsPlaylist.files) {
  26. expectStartWith(file.fileUrl, ObjectStorageCommand.getMockPlaylistBaseUrl())
  27. await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 })
  28. }
  29. expectStartWith(hlsPlaylist.playlistUrl, ObjectStorageCommand.getMockPlaylistBaseUrl())
  30. await makeRawRequest({ url: hlsPlaylist.playlistUrl, expectedStatus: HttpStatusCode.OK_200 })
  31. expectStartWith(hlsPlaylist.segmentsSha256Url, ObjectStorageCommand.getMockPlaylistBaseUrl())
  32. await makeRawRequest({ url: hlsPlaylist.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 })
  33. }
  34. function runTests (objectStorage: boolean) {
  35. let servers: PeerTubeServer[] = []
  36. let videoUUID: string
  37. let publishedAt: string
  38. let shouldBeDeleted: string[]
  39. before(async function () {
  40. this.timeout(120000)
  41. const config = objectStorage
  42. ? ObjectStorageCommand.getDefaultMockConfig()
  43. : {}
  44. // Run server 2 to have transcoding enabled
  45. servers = await createMultipleServers(2, config)
  46. await setAccessTokensToServers(servers)
  47. await servers[0].config.disableTranscoding()
  48. await doubleFollow(servers[0], servers[1])
  49. if (objectStorage) await ObjectStorageCommand.prepareDefaultMockBuckets()
  50. const { shortUUID } = await servers[0].videos.quickUpload({ name: 'video' })
  51. videoUUID = shortUUID
  52. await waitJobs(servers)
  53. const video = await servers[0].videos.get({ id: videoUUID })
  54. publishedAt = video.publishedAt as string
  55. await servers[0].config.enableTranscoding()
  56. })
  57. it('Should generate HLS', async function () {
  58. this.timeout(60000)
  59. await servers[0].videos.runTranscoding({
  60. videoId: videoUUID,
  61. transcodingType: 'hls'
  62. })
  63. await waitJobs(servers)
  64. await expectNoFailedTranscodingJob(servers[0])
  65. for (const server of servers) {
  66. const videoDetails = await server.videos.get({ id: videoUUID })
  67. expect(videoDetails.files).to.have.lengthOf(1)
  68. expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
  69. expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5)
  70. if (objectStorage) await checkFilesInObjectStorage(videoDetails)
  71. }
  72. })
  73. it('Should generate WebTorrent', async function () {
  74. this.timeout(60000)
  75. await servers[0].videos.runTranscoding({
  76. videoId: videoUUID,
  77. transcodingType: 'webtorrent'
  78. })
  79. await waitJobs(servers)
  80. for (const server of servers) {
  81. const videoDetails = await server.videos.get({ id: videoUUID })
  82. expect(videoDetails.files).to.have.lengthOf(5)
  83. expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
  84. expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5)
  85. if (objectStorage) await checkFilesInObjectStorage(videoDetails)
  86. }
  87. })
  88. it('Should generate WebTorrent from HLS only video', async function () {
  89. this.timeout(60000)
  90. await servers[0].videos.removeAllWebTorrentFiles({ videoId: videoUUID })
  91. await waitJobs(servers)
  92. await servers[0].videos.runTranscoding({ videoId: videoUUID, transcodingType: 'webtorrent' })
  93. await waitJobs(servers)
  94. for (const server of servers) {
  95. const videoDetails = await server.videos.get({ id: videoUUID })
  96. expect(videoDetails.files).to.have.lengthOf(5)
  97. expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
  98. expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5)
  99. if (objectStorage) await checkFilesInObjectStorage(videoDetails)
  100. }
  101. })
  102. it('Should only generate WebTorrent', async function () {
  103. this.timeout(60000)
  104. await servers[0].videos.removeHLSPlaylist({ videoId: videoUUID })
  105. await waitJobs(servers)
  106. await servers[0].videos.runTranscoding({ videoId: videoUUID, transcodingType: 'webtorrent' })
  107. await waitJobs(servers)
  108. for (const server of servers) {
  109. const videoDetails = await server.videos.get({ id: videoUUID })
  110. expect(videoDetails.files).to.have.lengthOf(5)
  111. expect(videoDetails.streamingPlaylists).to.have.lengthOf(0)
  112. if (objectStorage) await checkFilesInObjectStorage(videoDetails)
  113. }
  114. })
  115. it('Should correctly update HLS playlist on resolution change', async function () {
  116. this.timeout(120000)
  117. await servers[0].config.updateExistingSubConfig({
  118. newConfig: {
  119. transcoding: {
  120. enabled: true,
  121. resolutions: ConfigCommand.getCustomConfigResolutions(false),
  122. webtorrent: {
  123. enabled: true
  124. },
  125. hls: {
  126. enabled: true
  127. }
  128. }
  129. }
  130. })
  131. const { uuid } = await servers[0].videos.quickUpload({ name: 'quick' })
  132. await waitJobs(servers)
  133. for (const server of servers) {
  134. const videoDetails = await server.videos.get({ id: uuid })
  135. expect(videoDetails.files).to.have.lengthOf(1)
  136. expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
  137. expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(1)
  138. if (objectStorage) await checkFilesInObjectStorage(videoDetails)
  139. shouldBeDeleted = [
  140. videoDetails.streamingPlaylists[0].files[0].fileUrl,
  141. videoDetails.streamingPlaylists[0].playlistUrl,
  142. videoDetails.streamingPlaylists[0].segmentsSha256Url
  143. ]
  144. }
  145. await servers[0].config.updateExistingSubConfig({
  146. newConfig: {
  147. transcoding: {
  148. enabled: true,
  149. resolutions: ConfigCommand.getCustomConfigResolutions(true),
  150. webtorrent: {
  151. enabled: true
  152. },
  153. hls: {
  154. enabled: true
  155. }
  156. }
  157. }
  158. })
  159. await servers[0].videos.runTranscoding({ videoId: uuid, transcodingType: 'hls' })
  160. await waitJobs(servers)
  161. for (const server of servers) {
  162. const videoDetails = await server.videos.get({ id: uuid })
  163. expect(videoDetails.streamingPlaylists).to.have.lengthOf(1)
  164. expect(videoDetails.streamingPlaylists[0].files).to.have.lengthOf(5)
  165. if (objectStorage) {
  166. await checkFilesInObjectStorage(videoDetails)
  167. const hlsPlaylist = videoDetails.streamingPlaylists[0]
  168. const resolutions = hlsPlaylist.files.map(f => f.resolution.id)
  169. await checkResolutionsInMasterPlaylist({ server: servers[0], playlistUrl: hlsPlaylist.playlistUrl, resolutions })
  170. const shaBody = await servers[0].streamingPlaylists.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url })
  171. expect(Object.keys(shaBody)).to.have.lengthOf(5)
  172. }
  173. }
  174. })
  175. it('Should have correctly deleted previous files', async function () {
  176. for (const fileUrl of shouldBeDeleted) {
  177. await makeRawRequest({ url: fileUrl, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
  178. }
  179. })
  180. it('Should not have updated published at attributes', async function () {
  181. const video = await servers[0].videos.get({ id: videoUUID })
  182. expect(video.publishedAt).to.equal(publishedAt)
  183. })
  184. after(async function () {
  185. await cleanupTests(servers)
  186. })
  187. }
  188. describe('Test create transcoding jobs from API', function () {
  189. describe('On filesystem', function () {
  190. runTests(false)
  191. })
  192. describe('On object storage', function () {
  193. if (areMockObjectStorageTestsDisabled()) return
  194. runTests(true)
  195. })
  196. })