live.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
  2. import { expect } from 'chai'
  3. import { expectStartWith, testVideoResolutions } from '@server/tests/shared'
  4. import { areObjectStorageTestsDisabled } from '@shared/core-utils'
  5. import { HttpStatusCode, LiveVideoCreate, VideoPrivacy } from '@shared/models'
  6. import {
  7. createMultipleServers,
  8. doubleFollow,
  9. findExternalSavedVideo,
  10. killallServers,
  11. makeRawRequest,
  12. ObjectStorageCommand,
  13. PeerTubeServer,
  14. setAccessTokensToServers,
  15. setDefaultVideoChannel,
  16. stopFfmpeg,
  17. waitJobs,
  18. waitUntilLivePublishedOnAllServers,
  19. waitUntilLiveReplacedByReplayOnAllServers,
  20. waitUntilLiveWaitingOnAllServers
  21. } from '@shared/server-commands'
  22. async function createLive (server: PeerTubeServer, permanent: boolean) {
  23. const attributes: LiveVideoCreate = {
  24. channelId: server.store.channel.id,
  25. privacy: VideoPrivacy.PUBLIC,
  26. name: 'my super live',
  27. saveReplay: true,
  28. permanentLive: permanent
  29. }
  30. const { uuid } = await server.live.create({ fields: attributes })
  31. return uuid
  32. }
  33. async function checkFilesExist (servers: PeerTubeServer[], videoUUID: string, numberOfFiles: number) {
  34. for (const server of servers) {
  35. const video = await server.videos.get({ id: videoUUID })
  36. expect(video.files).to.have.lengthOf(0)
  37. expect(video.streamingPlaylists).to.have.lengthOf(1)
  38. const files = video.streamingPlaylists[0].files
  39. expect(files).to.have.lengthOf(numberOfFiles)
  40. for (const file of files) {
  41. expectStartWith(file.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl())
  42. await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 })
  43. }
  44. }
  45. }
  46. async function checkFilesCleanup (server: PeerTubeServer, videoUUID: string, resolutions: number[]) {
  47. const resolutionFiles = resolutions.map((_value, i) => `${i}.m3u8`)
  48. for (const playlistName of [ 'master.m3u8' ].concat(resolutionFiles)) {
  49. await server.live.getPlaylistFile({
  50. videoUUID,
  51. playlistName,
  52. expectedStatus: HttpStatusCode.NOT_FOUND_404,
  53. objectStorage: true
  54. })
  55. }
  56. await server.live.getSegmentFile({
  57. videoUUID,
  58. playlistNumber: 0,
  59. segment: 0,
  60. objectStorage: true,
  61. expectedStatus: HttpStatusCode.NOT_FOUND_404
  62. })
  63. }
  64. describe('Object storage for lives', function () {
  65. if (areObjectStorageTestsDisabled()) return
  66. let servers: PeerTubeServer[]
  67. before(async function () {
  68. this.timeout(120000)
  69. await ObjectStorageCommand.prepareDefaultBuckets()
  70. servers = await createMultipleServers(2, ObjectStorageCommand.getDefaultConfig())
  71. await setAccessTokensToServers(servers)
  72. await setDefaultVideoChannel(servers)
  73. await doubleFollow(servers[0], servers[1])
  74. await servers[0].config.enableTranscoding()
  75. })
  76. describe('Without live transcoding', async function () {
  77. let videoUUID: string
  78. before(async function () {
  79. await servers[0].config.enableLive({ transcoding: false })
  80. videoUUID = await createLive(servers[0], false)
  81. })
  82. it('Should create a live and publish it on object storage', async function () {
  83. this.timeout(220000)
  84. const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUID })
  85. await waitUntilLivePublishedOnAllServers(servers, videoUUID)
  86. await testVideoResolutions({
  87. originServer: servers[0],
  88. servers,
  89. liveVideoId: videoUUID,
  90. resolutions: [ 720 ],
  91. transcoded: false,
  92. objectStorage: true
  93. })
  94. await stopFfmpeg(ffmpegCommand)
  95. })
  96. it('Should have saved the replay on object storage', async function () {
  97. this.timeout(220000)
  98. await waitUntilLiveReplacedByReplayOnAllServers(servers, videoUUID)
  99. await waitJobs(servers)
  100. await checkFilesExist(servers, videoUUID, 1)
  101. })
  102. it('Should have cleaned up live files from object storage', async function () {
  103. await checkFilesCleanup(servers[0], videoUUID, [ 720 ])
  104. })
  105. })
  106. describe('With live transcoding', async function () {
  107. const resolutions = [ 720, 480, 360, 240, 144 ]
  108. before(async function () {
  109. await servers[0].config.enableLive({ transcoding: true })
  110. })
  111. describe('Normal replay', function () {
  112. let videoUUIDNonPermanent: string
  113. before(async function () {
  114. videoUUIDNonPermanent = await createLive(servers[0], false)
  115. })
  116. it('Should create a live and publish it on object storage', async function () {
  117. this.timeout(240000)
  118. const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDNonPermanent })
  119. await waitUntilLivePublishedOnAllServers(servers, videoUUIDNonPermanent)
  120. await testVideoResolutions({
  121. originServer: servers[0],
  122. servers,
  123. liveVideoId: videoUUIDNonPermanent,
  124. resolutions,
  125. transcoded: true,
  126. objectStorage: true
  127. })
  128. await stopFfmpeg(ffmpegCommand)
  129. })
  130. it('Should have saved the replay on object storage', async function () {
  131. this.timeout(220000)
  132. await waitUntilLiveReplacedByReplayOnAllServers(servers, videoUUIDNonPermanent)
  133. await waitJobs(servers)
  134. await checkFilesExist(servers, videoUUIDNonPermanent, 5)
  135. })
  136. it('Should have cleaned up live files from object storage', async function () {
  137. await checkFilesCleanup(servers[0], videoUUIDNonPermanent, resolutions)
  138. })
  139. })
  140. describe('Permanent replay', function () {
  141. let videoUUIDPermanent: string
  142. before(async function () {
  143. videoUUIDPermanent = await createLive(servers[0], true)
  144. })
  145. it('Should create a live and publish it on object storage', async function () {
  146. this.timeout(240000)
  147. const ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: videoUUIDPermanent })
  148. await waitUntilLivePublishedOnAllServers(servers, videoUUIDPermanent)
  149. await testVideoResolutions({
  150. originServer: servers[0],
  151. servers,
  152. liveVideoId: videoUUIDPermanent,
  153. resolutions,
  154. transcoded: true,
  155. objectStorage: true
  156. })
  157. await stopFfmpeg(ffmpegCommand)
  158. })
  159. it('Should have saved the replay on object storage', async function () {
  160. this.timeout(220000)
  161. await waitUntilLiveWaitingOnAllServers(servers, videoUUIDPermanent)
  162. await waitJobs(servers)
  163. const videoLiveDetails = await servers[0].videos.get({ id: videoUUIDPermanent })
  164. const replay = await findExternalSavedVideo(servers[0], videoLiveDetails)
  165. await checkFilesExist(servers, replay.uuid, 5)
  166. })
  167. it('Should have cleaned up live files from object storage', async function () {
  168. await checkFilesCleanup(servers[0], videoUUIDPermanent, resolutions)
  169. })
  170. })
  171. })
  172. after(async function () {
  173. await killallServers(servers)
  174. })
  175. })