From 3545e72c686ff1725bbdfd8d16d693e2f4aa75a3 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 12 Oct 2022 16:09:02 +0200 Subject: Put private videos under a specific subdirectory --- server/tests/api/check-params/index.ts | 1 + server/tests/api/check-params/live.ts | 17 + server/tests/api/check-params/video-files.ts | 217 +++++++----- server/tests/api/check-params/video-token.ts | 44 +++ server/tests/api/live/live-fast-restream.ts | 4 +- server/tests/api/live/live.ts | 13 +- server/tests/api/object-storage/live.ts | 2 +- server/tests/api/object-storage/video-imports.ts | 6 +- server/tests/api/object-storage/videos.ts | 20 +- server/tests/api/redundancy/redundancy.ts | 2 +- server/tests/api/server/open-telemetry.ts | 6 +- server/tests/api/transcoding/create-transcoding.ts | 10 +- server/tests/api/transcoding/hls.ts | 163 ++------- server/tests/api/transcoding/index.ts | 1 + .../api/transcoding/update-while-transcoding.ts | 151 ++++++++ server/tests/api/videos/index.ts | 1 + server/tests/api/videos/video-files.ts | 2 +- .../tests/api/videos/video-static-file-privacy.ts | 389 +++++++++++++++++++++ server/tests/cli/create-import-video-file-job.ts | 2 +- server/tests/cli/create-move-video-storage-job.ts | 4 +- server/tests/cli/create-transcoding-job.ts | 2 +- server/tests/cli/prune-storage.ts | 41 ++- server/tests/cli/regenerate-thumbnails.ts | 20 +- server/tests/feeds/feeds.ts | 2 +- server/tests/plugins/filter-hooks.ts | 36 +- server/tests/plugins/plugin-helpers.ts | 6 +- server/tests/shared/streaming-playlists.ts | 122 ++++++- server/tests/shared/videos.ts | 6 +- 28 files changed, 977 insertions(+), 313 deletions(-) create mode 100644 server/tests/api/check-params/video-token.ts create mode 100644 server/tests/api/transcoding/update-while-transcoding.ts create mode 100644 server/tests/api/videos/video-static-file-privacy.ts (limited to 'server/tests') diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts index 33dc8fb76..961093bb5 100644 --- a/server/tests/api/check-params/index.ts +++ b/server/tests/api/check-params/index.ts @@ -34,6 +34,7 @@ import './video-imports' import './video-playlists' import './video-source' import './video-studio' +import './video-token' import './videos-common-filters' import './videos-history' import './videos-overviews' diff --git a/server/tests/api/check-params/live.ts b/server/tests/api/check-params/live.ts index 3f553c42b..2eff9414b 100644 --- a/server/tests/api/check-params/live.ts +++ b/server/tests/api/check-params/live.ts @@ -502,6 +502,23 @@ describe('Test video lives API validator', function () { await stopFfmpeg(ffmpegCommand) }) + it('Should fail to change live privacy if it has already started', async function () { + this.timeout(40000) + + const live = await command.get({ videoId: video.id }) + + const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) + + await command.waitUntilPublished({ videoId: video.id }) + await server.videos.update({ + id: video.id, + attributes: { privacy: VideoPrivacy.PUBLIC }, + expectedStatus: HttpStatusCode.BAD_REQUEST_400 + }) + + await stopFfmpeg(ffmpegCommand) + }) + it('Should fail to stream twice in the save live', async function () { this.timeout(40000) diff --git a/server/tests/api/check-params/video-files.ts b/server/tests/api/check-params/video-files.ts index aa4de2c83..9dc59a1b5 100644 --- a/server/tests/api/check-params/video-files.ts +++ b/server/tests/api/check-params/video-files.ts @@ -1,10 +1,12 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { HttpStatusCode, UserRole } from '@shared/models' +import { getAllFiles } from '@shared/core-utils' +import { HttpStatusCode, UserRole, VideoDetails, VideoPrivacy } from '@shared/models' import { cleanupTests, createMultipleServers, doubleFollow, + makeRawRequest, PeerTubeServer, setAccessTokensToServers, waitJobs @@ -13,22 +15,9 @@ import { describe('Test videos files', function () { let servers: PeerTubeServer[] - let webtorrentId: string - let hlsId: string - let remoteId: string - let userToken: string let moderatorToken: string - let validId1: string - let validId2: string - - let hlsFileId: number - let webtorrentFileId: number - - let remoteHLSFileId: number - let remoteWebtorrentFileId: number - // --------------------------------------------------------------- before(async function () { @@ -41,117 +30,163 @@ describe('Test videos files', function () { userToken = await servers[0].users.generateUserAndToken('user', UserRole.USER) moderatorToken = await servers[0].users.generateUserAndToken('moderator', UserRole.MODERATOR) + }) - { - const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' }) - await waitJobs(servers) + describe('Getting metadata', function () { + let video: VideoDetails + + before(async function () { + const { uuid } = await servers[0].videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) + video = await servers[0].videos.getWithToken({ id: uuid }) + }) + + it('Should not get metadata of private video without token', async function () { + for (const file of getAllFiles(video)) { + await makeRawRequest({ url: file.metadataUrl, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) + } + }) + + it('Should not get metadata of private video without the appropriate token', async function () { + for (const file of getAllFiles(video)) { + await makeRawRequest({ url: file.metadataUrl, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) + } + }) + + it('Should get metadata of private video with the appropriate token', async function () { + for (const file of getAllFiles(video)) { + await makeRawRequest({ url: file.metadataUrl, token: servers[0].accessToken, expectedStatus: HttpStatusCode.OK_200 }) + } + }) + }) + + describe('Deleting files', function () { + let webtorrentId: string + let hlsId: string + let remoteId: string + + let validId1: string + let validId2: string - const video = await servers[1].videos.get({ id: uuid }) - remoteId = video.uuid - remoteHLSFileId = video.streamingPlaylists[0].files[0].id - remoteWebtorrentFileId = video.files[0].id - } + let hlsFileId: number + let webtorrentFileId: number - { - await servers[0].config.enableTranscoding(true, true) + let remoteHLSFileId: number + let remoteWebtorrentFileId: number + + before(async function () { + this.timeout(300_000) { - const { uuid } = await servers[0].videos.quickUpload({ name: 'both 1' }) + const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' }) await waitJobs(servers) - const video = await servers[0].videos.get({ id: uuid }) - validId1 = video.uuid - hlsFileId = video.streamingPlaylists[0].files[0].id - webtorrentFileId = video.files[0].id + const video = await servers[1].videos.get({ id: uuid }) + remoteId = video.uuid + remoteHLSFileId = video.streamingPlaylists[0].files[0].id + remoteWebtorrentFileId = video.files[0].id } { - const { uuid } = await servers[0].videos.quickUpload({ name: 'both 2' }) - validId2 = uuid + await servers[0].config.enableTranscoding(true, true) + + { + const { uuid } = await servers[0].videos.quickUpload({ name: 'both 1' }) + await waitJobs(servers) + + const video = await servers[0].videos.get({ id: uuid }) + validId1 = video.uuid + hlsFileId = video.streamingPlaylists[0].files[0].id + webtorrentFileId = video.files[0].id + } + + { + const { uuid } = await servers[0].videos.quickUpload({ name: 'both 2' }) + validId2 = uuid + } } - } - await waitJobs(servers) + await waitJobs(servers) - { - await servers[0].config.enableTranscoding(false, true) - const { uuid } = await servers[0].videos.quickUpload({ name: 'hls' }) - hlsId = uuid - } + { + await servers[0].config.enableTranscoding(false, true) + const { uuid } = await servers[0].videos.quickUpload({ name: 'hls' }) + hlsId = uuid + } - await waitJobs(servers) + await waitJobs(servers) - { - await servers[0].config.enableTranscoding(false, true) - const { uuid } = await servers[0].videos.quickUpload({ name: 'webtorrent' }) - webtorrentId = uuid - } + { + await servers[0].config.enableTranscoding(false, true) + const { uuid } = await servers[0].videos.quickUpload({ name: 'webtorrent' }) + webtorrentId = uuid + } - await waitJobs(servers) - }) + await waitJobs(servers) + }) - it('Should not delete files of a unknown video', async function () { - const expectedStatus = HttpStatusCode.NOT_FOUND_404 + it('Should not delete files of a unknown video', async function () { + const expectedStatus = HttpStatusCode.NOT_FOUND_404 - await servers[0].videos.removeHLSPlaylist({ videoId: 404, expectedStatus }) - await servers[0].videos.removeAllWebTorrentFiles({ videoId: 404, expectedStatus }) + await servers[0].videos.removeHLSPlaylist({ videoId: 404, expectedStatus }) + await servers[0].videos.removeAllWebTorrentFiles({ videoId: 404, expectedStatus }) - await servers[0].videos.removeHLSFile({ videoId: 404, fileId: hlsFileId, expectedStatus }) - await servers[0].videos.removeWebTorrentFile({ videoId: 404, fileId: webtorrentFileId, expectedStatus }) - }) + await servers[0].videos.removeHLSFile({ videoId: 404, fileId: hlsFileId, expectedStatus }) + await servers[0].videos.removeWebTorrentFile({ videoId: 404, fileId: webtorrentFileId, expectedStatus }) + }) - it('Should not delete unknown files', async function () { - const expectedStatus = HttpStatusCode.NOT_FOUND_404 + it('Should not delete unknown files', async function () { + const expectedStatus = HttpStatusCode.NOT_FOUND_404 - await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: webtorrentFileId, expectedStatus }) - await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: hlsFileId, expectedStatus }) - }) + await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: webtorrentFileId, expectedStatus }) + await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: hlsFileId, expectedStatus }) + }) - it('Should not delete files of a remote video', async function () { - const expectedStatus = HttpStatusCode.BAD_REQUEST_400 + it('Should not delete files of a remote video', async function () { + const expectedStatus = HttpStatusCode.BAD_REQUEST_400 - await servers[0].videos.removeHLSPlaylist({ videoId: remoteId, expectedStatus }) - await servers[0].videos.removeAllWebTorrentFiles({ videoId: remoteId, expectedStatus }) + await servers[0].videos.removeHLSPlaylist({ videoId: remoteId, expectedStatus }) + await servers[0].videos.removeAllWebTorrentFiles({ videoId: remoteId, expectedStatus }) - await servers[0].videos.removeHLSFile({ videoId: remoteId, fileId: remoteHLSFileId, expectedStatus }) - await servers[0].videos.removeWebTorrentFile({ videoId: remoteId, fileId: remoteWebtorrentFileId, expectedStatus }) - }) + await servers[0].videos.removeHLSFile({ videoId: remoteId, fileId: remoteHLSFileId, expectedStatus }) + await servers[0].videos.removeWebTorrentFile({ videoId: remoteId, fileId: remoteWebtorrentFileId, expectedStatus }) + }) - it('Should not delete files by a non admin user', async function () { - const expectedStatus = HttpStatusCode.FORBIDDEN_403 + it('Should not delete files by a non admin user', async function () { + const expectedStatus = HttpStatusCode.FORBIDDEN_403 - await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: userToken, expectedStatus }) - await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: moderatorToken, expectedStatus }) + await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: userToken, expectedStatus }) + await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: moderatorToken, expectedStatus }) - await servers[0].videos.removeAllWebTorrentFiles({ videoId: validId1, token: userToken, expectedStatus }) - await servers[0].videos.removeAllWebTorrentFiles({ videoId: validId1, token: moderatorToken, expectedStatus }) + await servers[0].videos.removeAllWebTorrentFiles({ videoId: validId1, token: userToken, expectedStatus }) + await servers[0].videos.removeAllWebTorrentFiles({ videoId: validId1, token: moderatorToken, expectedStatus }) - await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: userToken, expectedStatus }) - await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: moderatorToken, expectedStatus }) + await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: userToken, expectedStatus }) + await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: moderatorToken, expectedStatus }) - await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: webtorrentFileId, token: userToken, expectedStatus }) - await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: webtorrentFileId, token: moderatorToken, expectedStatus }) - }) + await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: webtorrentFileId, token: userToken, expectedStatus }) + await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: webtorrentFileId, token: moderatorToken, expectedStatus }) + }) - it('Should not delete files if the files are not available', async function () { - await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await servers[0].videos.removeAllWebTorrentFiles({ videoId: webtorrentId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) + it('Should not delete files if the files are not available', async function () { + await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) + await servers[0].videos.removeAllWebTorrentFiles({ videoId: webtorrentId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await servers[0].videos.removeHLSFile({ videoId: hlsId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await servers[0].videos.removeWebTorrentFile({ videoId: webtorrentId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - }) + await servers[0].videos.removeHLSFile({ videoId: hlsId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) + await servers[0].videos.removeWebTorrentFile({ videoId: webtorrentId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) + }) - it('Should not delete files if no both versions are available', async function () { - await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - await servers[0].videos.removeAllWebTorrentFiles({ videoId: webtorrentId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - }) + it('Should not delete files if no both versions are available', async function () { + await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) + await servers[0].videos.removeAllWebTorrentFiles({ videoId: webtorrentId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) + }) - it('Should delete files if both versions are available', async function () { - await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId }) - await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: webtorrentFileId }) + it('Should delete files if both versions are available', async function () { + await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId }) + await servers[0].videos.removeWebTorrentFile({ videoId: validId1, fileId: webtorrentFileId }) - await servers[0].videos.removeHLSPlaylist({ videoId: validId1 }) - await servers[0].videos.removeAllWebTorrentFiles({ videoId: validId2 }) + await servers[0].videos.removeHLSPlaylist({ videoId: validId1 }) + await servers[0].videos.removeAllWebTorrentFiles({ videoId: validId2 }) + }) }) after(async function () { diff --git a/server/tests/api/check-params/video-token.ts b/server/tests/api/check-params/video-token.ts new file mode 100644 index 000000000..7acb9d580 --- /dev/null +++ b/server/tests/api/check-params/video-token.ts @@ -0,0 +1,44 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import { HttpStatusCode, VideoPrivacy } from '@shared/models' +import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' + +describe('Test video tokens', function () { + let server: PeerTubeServer + let videoId: string + let userToken: string + + // --------------------------------------------------------------- + + before(async function () { + this.timeout(300_000) + + server = await createSingleServer(1) + await setAccessTokensToServers([ server ]) + + const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) + videoId = uuid + + userToken = await server.users.generateUserAndToken('user1') + }) + + it('Should not generate tokens for unauthenticated user', async function () { + await server.videoToken.create({ videoId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) + }) + + it('Should not generate tokens of unknown video', async function () { + await server.videoToken.create({ videoId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) + }) + + it('Should not generate tokens of a non owned video', async function () { + await server.videoToken.create({ videoId, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) + }) + + it('Should generate token', async function () { + await server.videoToken.create({ videoId }) + }) + + after(async function () { + await cleanupTests([ server ]) + }) +}) diff --git a/server/tests/api/live/live-fast-restream.ts b/server/tests/api/live/live-fast-restream.ts index 772ea792d..971df1a61 100644 --- a/server/tests/api/live/live-fast-restream.ts +++ b/server/tests/api/live/live-fast-restream.ts @@ -79,8 +79,8 @@ describe('Fast restream in live', function () { expect(video.streamingPlaylists).to.have.lengthOf(1) await server.live.getSegmentFile({ videoUUID: liveId, segment: 0, playlistNumber: 0 }) - await makeRawRequest(video.streamingPlaylists[0].playlistUrl, HttpStatusCode.OK_200) - await makeRawRequest(video.streamingPlaylists[0].segmentsSha256Url, HttpStatusCode.OK_200) + await makeRawRequest({ url: video.streamingPlaylists[0].playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: video.streamingPlaylists[0].segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) await wait(100) } diff --git a/server/tests/api/live/live.ts b/server/tests/api/live/live.ts index 3f2a304be..003cc934f 100644 --- a/server/tests/api/live/live.ts +++ b/server/tests/api/live/live.ts @@ -21,6 +21,7 @@ import { doubleFollow, killallServers, LiveCommand, + makeGetRequest, makeRawRequest, PeerTubeServer, sendRTMPStream, @@ -157,8 +158,8 @@ describe('Test live', function () { expect(video.privacy.id).to.equal(VideoPrivacy.UNLISTED) expect(video.nsfw).to.be.true - await makeRawRequest(server.url + video.thumbnailPath, HttpStatusCode.OK_200) - await makeRawRequest(server.url + video.previewPath, HttpStatusCode.OK_200) + await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) + await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 }) } }) @@ -532,8 +533,8 @@ describe('Test live', function () { expect(video.files).to.have.lengthOf(0) const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS) - await makeRawRequest(hlsPlaylist.playlistUrl, HttpStatusCode.OK_200) - await makeRawRequest(hlsPlaylist.segmentsSha256Url, HttpStatusCode.OK_200) + await makeRawRequest({ url: hlsPlaylist.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: hlsPlaylist.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) // We should have generated random filenames expect(basename(hlsPlaylist.playlistUrl)).to.not.equal('master.m3u8') @@ -564,8 +565,8 @@ describe('Test live', function () { expect(probe.format.bit_rate).to.be.below(maxBitrateLimits[videoStream.height]) expect(probe.format.bit_rate).to.be.at.least(minBitrateLimits[videoStream.height]) - await makeRawRequest(file.torrentUrl, HttpStatusCode.OK_200) - await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) } } }) diff --git a/server/tests/api/object-storage/live.ts b/server/tests/api/object-storage/live.ts index 7e16b4c89..77f3a8066 100644 --- a/server/tests/api/object-storage/live.ts +++ b/server/tests/api/object-storage/live.ts @@ -48,7 +48,7 @@ async function checkFilesExist (servers: PeerTubeServer[], videoUUID: string, nu for (const file of files) { expectStartWith(file.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl()) - await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) } } } diff --git a/server/tests/api/object-storage/video-imports.ts b/server/tests/api/object-storage/video-imports.ts index f688c7018..90988ea9a 100644 --- a/server/tests/api/object-storage/video-imports.ts +++ b/server/tests/api/object-storage/video-imports.ts @@ -66,7 +66,7 @@ describe('Object storage for video import', function () { const fileUrl = video.files[0].fileUrl expectStartWith(fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) - await makeRawRequest(fileUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: fileUrl, expectedStatus: HttpStatusCode.OK_200 }) }) }) @@ -91,13 +91,13 @@ describe('Object storage for video import', function () { for (const file of video.files) { expectStartWith(file.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) - await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) } for (const file of video.streamingPlaylists[0].files) { expectStartWith(file.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl()) - await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) } }) }) diff --git a/server/tests/api/object-storage/videos.ts b/server/tests/api/object-storage/videos.ts index 3e65e1093..63f5179c7 100644 --- a/server/tests/api/object-storage/videos.ts +++ b/server/tests/api/object-storage/videos.ts @@ -59,11 +59,11 @@ async function checkFiles (options: { expectStartWith(file.fileUrl, start) - const res = await makeRawRequest(file.fileDownloadUrl, HttpStatusCode.FOUND_302) + const res = await makeRawRequest({ url: file.fileDownloadUrl, expectedStatus: HttpStatusCode.FOUND_302 }) const location = res.headers['location'] expectStartWith(location, start) - await makeRawRequest(location, HttpStatusCode.OK_200) + await makeRawRequest({ url: location, expectedStatus: HttpStatusCode.OK_200 }) } const hls = video.streamingPlaylists[0] @@ -81,19 +81,19 @@ async function checkFiles (options: { expectStartWith(hls.playlistUrl, start) expectStartWith(hls.segmentsSha256Url, start) - await makeRawRequest(hls.playlistUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) - const resSha = await makeRawRequest(hls.segmentsSha256Url, HttpStatusCode.OK_200) + const resSha = await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) expect(JSON.stringify(resSha.body)).to.not.throw for (const file of hls.files) { expectStartWith(file.fileUrl, start) - const res = await makeRawRequest(file.fileDownloadUrl, HttpStatusCode.FOUND_302) + const res = await makeRawRequest({ url: file.fileDownloadUrl, expectedStatus: HttpStatusCode.FOUND_302 }) const location = res.headers['location'] expectStartWith(location, start) - await makeRawRequest(location, HttpStatusCode.OK_200) + await makeRawRequest({ url: location, expectedStatus: HttpStatusCode.OK_200 }) } } @@ -104,7 +104,7 @@ async function checkFiles (options: { expect(torrent.files.length).to.equal(1) expect(torrent.files[0].path).to.exist.and.to.not.equal('') - const res = await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) + const res = await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) expect(res.body).to.have.length.above(100) } @@ -220,7 +220,7 @@ function runTestSuite (options: { it('Should fetch correctly all the files', async function () { for (const url of deletedUrls.concat(keptUrls)) { - await makeRawRequest(url, HttpStatusCode.OK_200) + await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) } }) @@ -231,13 +231,13 @@ function runTestSuite (options: { await waitJobs(servers) for (const url of deletedUrls) { - await makeRawRequest(url, HttpStatusCode.NOT_FOUND_404) + await makeRawRequest({ url, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) } }) it('Should have kept other files', async function () { for (const url of keptUrls) { - await makeRawRequest(url, HttpStatusCode.OK_200) + await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) } }) diff --git a/server/tests/api/redundancy/redundancy.ts b/server/tests/api/redundancy/redundancy.ts index f349a7a76..ba6b00e0b 100644 --- a/server/tests/api/redundancy/redundancy.ts +++ b/server/tests/api/redundancy/redundancy.ts @@ -39,7 +39,7 @@ async function checkMagnetWebseeds (file: VideoFile, baseWebseeds: string[], ser expect(parsed.urlList).to.have.lengthOf(baseWebseeds.length) for (const url of parsed.urlList) { - await makeRawRequest(url, HttpStatusCode.OK_200) + await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) } } diff --git a/server/tests/api/server/open-telemetry.ts b/server/tests/api/server/open-telemetry.ts index 43a27cc32..7a294be82 100644 --- a/server/tests/api/server/open-telemetry.ts +++ b/server/tests/api/server/open-telemetry.ts @@ -18,7 +18,7 @@ describe('Open Telemetry', function () { let hasError = false try { - await makeRawRequest(metricsUrl, HttpStatusCode.NOT_FOUND_404) + await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) } catch (err) { hasError = err.message.includes('ECONNREFUSED') } @@ -37,7 +37,7 @@ describe('Open Telemetry', function () { } }) - const res = await makeRawRequest(metricsUrl, HttpStatusCode.OK_200) + const res = await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.OK_200 }) expect(res.text).to.contain('peertube_job_queue_total{') }) @@ -60,7 +60,7 @@ describe('Open Telemetry', function () { } }) - const res = await makeRawRequest(metricsUrl, HttpStatusCode.OK_200) + const res = await makeRawRequest({ url: metricsUrl, expectedStatus: HttpStatusCode.OK_200 }) expect(res.text).to.contain('peertube_playback_http_downloaded_bytes_total{') }) 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 { async function checkFilesInObjectStorage (video: VideoDetails) { for (const file of video.files) { expectStartWith(file.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) - await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) } if (video.streamingPlaylists.length === 0) return @@ -28,14 +28,14 @@ async function checkFilesInObjectStorage (video: VideoDetails) { const hlsPlaylist = video.streamingPlaylists[0] for (const file of hlsPlaylist.files) { expectStartWith(file.fileUrl, ObjectStorageCommand.getPlaylistBaseUrl()) - await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) } expectStartWith(hlsPlaylist.playlistUrl, ObjectStorageCommand.getPlaylistBaseUrl()) - await makeRawRequest(hlsPlaylist.playlistUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: hlsPlaylist.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) expectStartWith(hlsPlaylist.segmentsSha256Url, ObjectStorageCommand.getPlaylistBaseUrl()) - await makeRawRequest(hlsPlaylist.segmentsSha256Url, HttpStatusCode.OK_200) + await makeRawRequest({ url: hlsPlaylist.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) } function runTests (objectStorage: boolean) { @@ -234,7 +234,7 @@ function runTests (objectStorage: boolean) { it('Should have correctly deleted previous files', async function () { for (const fileUrl of shouldBeDeleted) { - await makeRawRequest(fileUrl, HttpStatusCode.NOT_FOUND_404) + await makeRawRequest({ url: fileUrl, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) } }) 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 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { expect } from 'chai' -import { basename, join } from 'path' -import { - checkDirectoryIsEmpty, - checkResolutionsInMasterPlaylist, - checkSegmentHash, - checkTmpIsEmpty, - expectStartWith, - hlsInfohashExist -} from '@server/tests/shared' -import { areObjectStorageTestsDisabled, removeFragmentedMP4Ext, uuidRegex } from '@shared/core-utils' -import { HttpStatusCode, VideoStreamingPlaylistType } from '@shared/models' +import { join } from 'path' +import { checkDirectoryIsEmpty, checkTmpIsEmpty, completeCheckHlsPlaylist } from '@server/tests/shared' +import { areObjectStorageTestsDisabled } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { cleanupTests, createMultipleServers, doubleFollow, - makeRawRequest, ObjectStorageCommand, PeerTubeServer, setAccessTokensToServers, - waitJobs, - webtorrentAdd + waitJobs } from '@shared/server-commands' import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' -async function checkHlsPlaylist (options: { - servers: PeerTubeServer[] - videoUUID: string - hlsOnly: boolean - - resolutions?: number[] - objectStorageBaseUrl: string -}) { - const { videoUUID, hlsOnly, objectStorageBaseUrl } = options - - const resolutions = options.resolutions ?? [ 240, 360, 480, 720 ] - - for (const server of options.servers) { - const videoDetails = await server.videos.get({ id: videoUUID }) - const baseUrl = `http://${videoDetails.account.host}` - - expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) - - const hlsPlaylist = videoDetails.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) - expect(hlsPlaylist).to.not.be.undefined - - const hlsFiles = hlsPlaylist.files - expect(hlsFiles).to.have.lengthOf(resolutions.length) - - if (hlsOnly) expect(videoDetails.files).to.have.lengthOf(0) - else expect(videoDetails.files).to.have.lengthOf(resolutions.length) - - // Check JSON files - for (const resolution of resolutions) { - const file = hlsFiles.find(f => f.resolution.id === resolution) - expect(file).to.not.be.undefined - - expect(file.magnetUri).to.have.lengthOf.above(2) - expect(file.torrentUrl).to.match( - new RegExp(`http://${server.host}/lazy-static/torrents/${uuidRegex}-${file.resolution.id}-hls.torrent`) - ) - - if (objectStorageBaseUrl) { - expectStartWith(file.fileUrl, objectStorageBaseUrl) - } else { - expect(file.fileUrl).to.match( - new RegExp(`${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${uuidRegex}-${file.resolution.id}-fragmented.mp4`) - ) - } - - expect(file.resolution.label).to.equal(resolution + 'p') - - await makeRawRequest(file.torrentUrl, HttpStatusCode.OK_200) - await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) - - const torrent = await webtorrentAdd(file.magnetUri, true) - expect(torrent.files).to.be.an('array') - expect(torrent.files.length).to.equal(1) - expect(torrent.files[0].path).to.exist.and.to.not.equal('') - } - - // Check master playlist - { - await checkResolutionsInMasterPlaylist({ server, playlistUrl: hlsPlaylist.playlistUrl, resolutions }) - - const masterPlaylist = await server.streamingPlaylists.get({ url: hlsPlaylist.playlistUrl }) - - let i = 0 - for (const resolution of resolutions) { - expect(masterPlaylist).to.contain(`${resolution}.m3u8`) - expect(masterPlaylist).to.contain(`${resolution}.m3u8`) - - const url = 'http://' + videoDetails.account.host - await hlsInfohashExist(url, hlsPlaylist.playlistUrl, i) - - i++ - } - } - - // Check resolution playlists - { - for (const resolution of resolutions) { - const file = hlsFiles.find(f => f.resolution.id === resolution) - const playlistName = removeFragmentedMP4Ext(basename(file.fileUrl)) + '.m3u8' - - const url = objectStorageBaseUrl - ? `${objectStorageBaseUrl}hls/${videoUUID}/${playlistName}` - : `${baseUrl}/static/streaming-playlists/hls/${videoUUID}/${playlistName}` - - const subPlaylist = await server.streamingPlaylists.get({ url }) - - expect(subPlaylist).to.match(new RegExp(`${uuidRegex}-${resolution}-fragmented.mp4`)) - expect(subPlaylist).to.contain(basename(file.fileUrl)) - } - } - - { - const baseUrlAndPath = objectStorageBaseUrl - ? objectStorageBaseUrl + 'hls/' + videoUUID - : baseUrl + '/static/streaming-playlists/hls/' + videoUUID - - for (const resolution of resolutions) { - await checkSegmentHash({ - server, - baseUrlPlaylist: baseUrlAndPath, - baseUrlSegment: baseUrlAndPath, - resolution, - hlsPlaylist - }) - } - } - } -} - describe('Test HLS videos', function () { let servers: PeerTubeServer[] = [] - let videoUUID = '' - let videoAudioUUID = '' function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) { + const videoUUIDs: string[] = [] it('Should upload a video and transcode it to HLS', async function () { this.timeout(120000) const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video 1', fixture: 'video_short.webm' } }) - videoUUID = uuid + videoUUIDs.push(uuid) await waitJobs(servers) - await checkHlsPlaylist({ servers, videoUUID, hlsOnly, objectStorageBaseUrl }) + await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) }) it('Should upload an audio file and transcode it to HLS', async function () { this.timeout(120000) const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video audio', fixture: 'sample.ogg' } }) - videoAudioUUID = uuid + videoUUIDs.push(uuid) await waitJobs(servers) - await checkHlsPlaylist({ + await completeCheckHlsPlaylist({ servers, - videoUUID: videoAudioUUID, + videoUUID: uuid, hlsOnly, resolutions: [ DEFAULT_AUDIO_RESOLUTION, 360, 240 ], objectStorageBaseUrl @@ -172,31 +52,36 @@ describe('Test HLS videos', function () { it('Should update the video', async function () { this.timeout(30000) - await servers[0].videos.update({ id: videoUUID, attributes: { name: 'video 1 updated' } }) + await servers[0].videos.update({ id: videoUUIDs[0], attributes: { name: 'video 1 updated' } }) await waitJobs(servers) - await checkHlsPlaylist({ servers, videoUUID, hlsOnly, objectStorageBaseUrl }) + await completeCheckHlsPlaylist({ servers, videoUUID: videoUUIDs[0], hlsOnly, objectStorageBaseUrl }) }) it('Should delete videos', async function () { this.timeout(10000) - await servers[0].videos.remove({ id: videoUUID }) - await servers[0].videos.remove({ id: videoAudioUUID }) + for (const uuid of videoUUIDs) { + await servers[0].videos.remove({ id: uuid }) + } await waitJobs(servers) for (const server of servers) { - await server.videos.get({ id: videoUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) - await server.videos.get({ id: videoAudioUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) + for (const uuid of videoUUIDs) { + await server.videos.get({ id: uuid, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) + } } }) it('Should have the playlists/segment deleted from the disk', async function () { for (const server of servers) { - await checkDirectoryIsEmpty(server, 'videos') - await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls')) + await checkDirectoryIsEmpty(server, 'videos', [ 'private' ]) + await checkDirectoryIsEmpty(server, join('videos', 'private')) + + await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls'), [ 'private' ]) + await checkDirectoryIsEmpty(server, join('streaming-playlists', 'hls', 'private')) } }) 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' export * from './create-transcoding' export * from './hls' export * from './transcoder' +export * from './update-while-transcoding' export * 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 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import { completeCheckHlsPlaylist } from '@server/tests/shared' +import { areObjectStorageTestsDisabled, wait } from '@shared/core-utils' +import { VideoPrivacy } from '@shared/models' +import { + cleanupTests, + createMultipleServers, + doubleFollow, + ObjectStorageCommand, + PeerTubeServer, + setAccessTokensToServers, + waitJobs +} from '@shared/server-commands' + +describe('Test update video privacy while transcoding', function () { + let servers: PeerTubeServer[] = [] + + const videoUUIDs: string[] = [] + + function runTestSuite (hlsOnly: boolean, objectStorageBaseUrl?: string) { + + it('Should not have an error while quickly updating a private video to public after upload #1', async function () { + this.timeout(360_000) + + const attributes = { + name: 'quick update', + privacy: VideoPrivacy.PRIVATE + } + + const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: false }) + await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) + videoUUIDs.push(uuid) + + await waitJobs(servers) + + await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) + }) + + it('Should not have an error while quickly updating a private video to public after upload #2', async function () { + + { + const attributes = { + name: 'quick update 2', + privacy: VideoPrivacy.PRIVATE + } + + const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: true }) + await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) + videoUUIDs.push(uuid) + + await waitJobs(servers) + + await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) + } + }) + + it('Should not have an error while quickly updating a private video to public after upload #3', async function () { + const attributes = { + name: 'quick update 3', + privacy: VideoPrivacy.PRIVATE + } + + const { uuid } = await servers[0].videos.upload({ attributes, waitTorrentGeneration: true }) + await wait(1000) + await servers[0].videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) + videoUUIDs.push(uuid) + + await waitJobs(servers) + + await completeCheckHlsPlaylist({ servers, videoUUID: uuid, hlsOnly, objectStorageBaseUrl }) + }) + } + + before(async function () { + this.timeout(120000) + + const configOverride = { + transcoding: { + enabled: true, + allow_audio_files: true, + hls: { + enabled: true + } + } + } + servers = await createMultipleServers(2, configOverride) + + // Get the access tokens + await setAccessTokensToServers(servers) + + // Server 1 and server 2 follow each other + await doubleFollow(servers[0], servers[1]) + }) + + describe('With WebTorrent & HLS enabled', function () { + runTestSuite(false) + }) + + describe('With only HLS enabled', function () { + + before(async function () { + await servers[0].config.updateCustomSubConfig({ + newConfig: { + transcoding: { + enabled: true, + allowAudioFiles: true, + resolutions: { + '144p': false, + '240p': true, + '360p': true, + '480p': true, + '720p': true, + '1080p': true, + '1440p': true, + '2160p': true + }, + hls: { + enabled: true + }, + webtorrent: { + enabled: false + } + } + } + }) + }) + + runTestSuite(true) + }) + + describe('With object storage enabled', function () { + if (areObjectStorageTestsDisabled()) return + + before(async function () { + this.timeout(120000) + + const configOverride = ObjectStorageCommand.getDefaultConfig() + await ObjectStorageCommand.prepareDefaultBuckets() + + await servers[0].kill() + await servers[0].run(configOverride) + }) + + runTestSuite(true, ObjectStorageCommand.getPlaylistBaseUrl()) + }) + + after(async function () { + await cleanupTests(servers) + }) +}) diff --git a/server/tests/api/videos/index.ts b/server/tests/api/videos/index.ts index 266155297..357c08199 100644 --- a/server/tests/api/videos/index.ts +++ b/server/tests/api/videos/index.ts @@ -19,3 +19,4 @@ import './videos-common-filters' import './videos-history' import './videos-overview' import './video-source' +import './video-static-file-privacy' diff --git a/server/tests/api/videos/video-files.ts b/server/tests/api/videos/video-files.ts index c0b886aad..8c913bf31 100644 --- a/server/tests/api/videos/video-files.ts +++ b/server/tests/api/videos/video-files.ts @@ -153,7 +153,7 @@ describe('Test videos files', function () { expect(video.streamingPlaylists[0].files).to.have.lengthOf(files.length - 1) expect(video.streamingPlaylists[0].files.find(f => f.id === toDelete.id)).to.not.exist - const { text } = await makeRawRequest(video.streamingPlaylists[0].playlistUrl) + const { text } = await makeRawRequest({ url: video.streamingPlaylists[0].playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) expect(text.includes(`-${toDelete.resolution.id}.m3u8`)).to.be.false expect(text.includes(`-${video.streamingPlaylists[0].files[0].resolution.id}.m3u8`)).to.be.true diff --git a/server/tests/api/videos/video-static-file-privacy.ts b/server/tests/api/videos/video-static-file-privacy.ts new file mode 100644 index 000000000..e38fdec6e --- /dev/null +++ b/server/tests/api/videos/video-static-file-privacy.ts @@ -0,0 +1,389 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import { expect } from 'chai' +import { decode } from 'magnet-uri' +import { expectStartWith } from '@server/tests/shared' +import { getAllFiles, wait } from '@shared/core-utils' +import { HttpStatusCode, LiveVideo, VideoDetails, VideoPrivacy } from '@shared/models' +import { + cleanupTests, + createSingleServer, + findExternalSavedVideo, + makeRawRequest, + parseTorrentVideo, + PeerTubeServer, + sendRTMPStream, + setAccessTokensToServers, + setDefaultVideoChannel, + stopFfmpeg, + waitJobs +} from '@shared/server-commands' + +describe('Test video static file privacy', function () { + let server: PeerTubeServer + let userToken: string + + before(async function () { + this.timeout(50000) + + server = await createSingleServer(1) + await setAccessTokensToServers([ server ]) + await setDefaultVideoChannel([ server ]) + + userToken = await server.users.generateUserAndToken('user1') + }) + + describe('VOD static file path', function () { + + function runSuite () { + + async function checkPrivateWebTorrentFiles (uuid: string) { + const video = await server.videos.getWithToken({ id: uuid }) + + for (const file of video.files) { + expect(file.fileDownloadUrl).to.not.include('/private/') + expectStartWith(file.fileUrl, server.url + '/static/webseed/private/') + + const torrent = await parseTorrentVideo(server, file) + expect(torrent.urlList).to.have.lengthOf(0) + + const magnet = decode(file.magnetUri) + expect(magnet.urlList).to.have.lengthOf(0) + + await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) + } + + const hls = video.streamingPlaylists[0] + if (hls) { + expectStartWith(hls.playlistUrl, server.url + '/static/streaming-playlists/hls/private/') + expectStartWith(hls.segmentsSha256Url, server.url + '/static/streaming-playlists/hls/private/') + + await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) + } + } + + async function checkPublicWebTorrentFiles (uuid: string) { + const video = await server.videos.get({ id: uuid }) + + for (const file of getAllFiles(video)) { + expect(file.fileDownloadUrl).to.not.include('/private/') + expect(file.fileUrl).to.not.include('/private/') + + const torrent = await parseTorrentVideo(server, file) + expect(torrent.urlList[0]).to.not.include('private') + + const magnet = decode(file.magnetUri) + expect(magnet.urlList[0]).to.not.include('private') + + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: torrent.urlList[0], expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: magnet.urlList[0], expectedStatus: HttpStatusCode.OK_200 }) + } + + const hls = video.streamingPlaylists[0] + if (hls) { + expect(hls.playlistUrl).to.not.include('private') + expect(hls.segmentsSha256Url).to.not.include('private') + + await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) + } + } + + it('Should upload a private/internal video and have a private static path', async function () { + this.timeout(120000) + + for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) { + const { uuid } = await server.videos.quickUpload({ name: 'video', privacy }) + await waitJobs([ server ]) + + await checkPrivateWebTorrentFiles(uuid) + } + }) + + it('Should upload a public video and update it as private/internal to have a private static path', async function () { + this.timeout(120000) + + for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) { + const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PUBLIC }) + await waitJobs([ server ]) + + await server.videos.update({ id: uuid, attributes: { privacy } }) + await waitJobs([ server ]) + + await checkPrivateWebTorrentFiles(uuid) + } + }) + + it('Should upload a private video and update it to unlisted to have a public static path', async function () { + this.timeout(120000) + + const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) + await waitJobs([ server ]) + + await server.videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.UNLISTED } }) + await waitJobs([ server ]) + + await checkPublicWebTorrentFiles(uuid) + }) + + it('Should upload an internal video and update it to public to have a public static path', async function () { + this.timeout(120000) + + const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.INTERNAL }) + await waitJobs([ server ]) + + await server.videos.update({ id: uuid, attributes: { privacy: VideoPrivacy.PUBLIC } }) + await waitJobs([ server ]) + + await checkPublicWebTorrentFiles(uuid) + }) + + it('Should upload an internal video and schedule a public publish', async function () { + this.timeout(120000) + + const attributes = { + name: 'video', + privacy: VideoPrivacy.PRIVATE, + scheduleUpdate: { + updateAt: new Date(Date.now() + 1000).toISOString(), + privacy: VideoPrivacy.PUBLIC as VideoPrivacy.PUBLIC + } + } + + const { uuid } = await server.videos.upload({ attributes }) + + await waitJobs([ server ]) + await wait(1000) + await server.debug.sendCommand({ body: { command: 'process-update-videos-scheduler' } }) + + await waitJobs([ server ]) + + await checkPublicWebTorrentFiles(uuid) + }) + } + + describe('Without transcoding', function () { + runSuite() + }) + + describe('With transcoding', function () { + + before(async function () { + await server.config.enableMinimumTranscoding() + }) + + runSuite() + }) + }) + + describe('VOD static file right check', function () { + let unrelatedFileToken: string + + async function checkVideoFiles (options: { + id: string + expectedStatus: HttpStatusCode + token: string + videoFileToken: string + }) { + const { id, expectedStatus, token, videoFileToken } = options + + const video = await server.videos.getWithToken({ id }) + + for (const file of getAllFiles(video)) { + await makeRawRequest({ url: file.fileUrl, token, expectedStatus }) + await makeRawRequest({ url: file.fileDownloadUrl, token, expectedStatus }) + + await makeRawRequest({ url: file.fileUrl, query: { videoFileToken }, expectedStatus }) + await makeRawRequest({ url: file.fileDownloadUrl, query: { videoFileToken }, expectedStatus }) + } + + const hls = video.streamingPlaylists[0] + await makeRawRequest({ url: hls.playlistUrl, token, expectedStatus }) + await makeRawRequest({ url: hls.segmentsSha256Url, token, expectedStatus }) + + await makeRawRequest({ url: hls.playlistUrl, query: { videoFileToken }, expectedStatus }) + await makeRawRequest({ url: hls.segmentsSha256Url, query: { videoFileToken }, expectedStatus }) + } + + before(async function () { + await server.config.enableMinimumTranscoding() + + const { uuid } = await server.videos.quickUpload({ name: 'another video' }) + unrelatedFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) + }) + + it('Should not be able to access a private video files without OAuth token and file token', async function () { + this.timeout(120000) + + const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.INTERNAL }) + await waitJobs([ server ]) + + await checkVideoFiles({ id: uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403, token: null, videoFileToken: null }) + }) + + it('Should not be able to access an internal video files without appropriate OAuth token and file token', async function () { + this.timeout(120000) + + const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) + await waitJobs([ server ]) + + await checkVideoFiles({ + id: uuid, + expectedStatus: HttpStatusCode.FORBIDDEN_403, + token: userToken, + videoFileToken: unrelatedFileToken + }) + }) + + it('Should be able to access a private video files with appropriate OAuth token or file token', async function () { + this.timeout(120000) + + const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) + const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) + + await waitJobs([ server ]) + + await checkVideoFiles({ id: uuid, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken, videoFileToken }) + }) + + it('Should be able to access a private video of another user with an admin OAuth token or file token', async function () { + this.timeout(120000) + + const { uuid } = await server.videos.quickUpload({ name: 'video', token: userToken, privacy: VideoPrivacy.PRIVATE }) + const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) + + await waitJobs([ server ]) + + await checkVideoFiles({ id: uuid, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken, videoFileToken }) + }) + }) + + describe('Live static file path and check', function () { + let normalLiveId: string + let normalLive: LiveVideo + + let permanentLiveId: string + let permanentLive: LiveVideo + + let unrelatedFileToken: string + + async function checkLiveFiles (live: LiveVideo, liveId: string) { + const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) + await server.live.waitUntilPublished({ videoId: liveId }) + + const video = await server.videos.getWithToken({ id: liveId }) + const fileToken = await server.videoToken.getVideoFileToken({ videoId: video.uuid }) + + const hls = video.streamingPlaylists[0] + + for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { + expectStartWith(url, server.url + '/static/streaming-playlists/hls/private/') + + await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) + + await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) + await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) + await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) + } + + await stopFfmpeg(ffmpegCommand) + } + + async function checkReplay (replay: VideoDetails) { + const fileToken = await server.videoToken.getVideoFileToken({ videoId: replay.uuid }) + + const hls = replay.streamingPlaylists[0] + expect(hls.files).to.not.have.lengthOf(0) + + for (const file of hls.files) { + await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: file.fileUrl, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) + + await makeRawRequest({ url: file.fileUrl, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) + await makeRawRequest({ + url: file.fileUrl, + query: { videoFileToken: unrelatedFileToken }, + expectedStatus: HttpStatusCode.FORBIDDEN_403 + }) + } + + for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { + expectStartWith(url, server.url + '/static/streaming-playlists/hls/private/') + + await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) + + await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) + await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) + await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) + } + } + + before(async function () { + await server.config.enableMinimumTranscoding() + + const { uuid } = await server.videos.quickUpload({ name: 'another video' }) + unrelatedFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) + + await server.config.enableLive({ + allowReplay: true, + transcoding: true, + resolutions: 'min' + }) + + { + const { video, live } = await server.live.quickCreate({ saveReplay: true, permanentLive: false, privacy: VideoPrivacy.PRIVATE }) + normalLiveId = video.uuid + normalLive = live + } + + { + const { video, live } = await server.live.quickCreate({ saveReplay: true, permanentLive: true, privacy: VideoPrivacy.PRIVATE }) + permanentLiveId = video.uuid + permanentLive = live + } + }) + + it('Should create a private normal live and have a private static path', async function () { + this.timeout(240000) + + await checkLiveFiles(normalLive, normalLiveId) + }) + + it('Should create a private permanent live and have a private static path', async function () { + this.timeout(240000) + + await checkLiveFiles(permanentLive, permanentLiveId) + }) + + it('Should have created a replay of the normal live with a private static path', async function () { + this.timeout(240000) + + await server.live.waitUntilReplacedByReplay({ videoId: normalLiveId }) + + const replay = await server.videos.getWithToken({ id: normalLiveId }) + await checkReplay(replay) + }) + + it('Should have created a replay of the permanent live with a private static path', async function () { + this.timeout(240000) + + await server.live.waitUntilWaiting({ videoId: permanentLiveId }) + await waitJobs([ server ]) + + const live = await server.videos.getWithToken({ id: permanentLiveId }) + const replayFromList = await findExternalSavedVideo(server, live) + const replay = await server.videos.getWithToken({ id: replayFromList.id }) + + await checkReplay(replay) + }) + }) + + after(async function () { + await cleanupTests([ server ]) + }) +}) diff --git a/server/tests/cli/create-import-video-file-job.ts b/server/tests/cli/create-import-video-file-job.ts index 2cf2dd8f8..a4aa5f699 100644 --- a/server/tests/cli/create-import-video-file-job.ts +++ b/server/tests/cli/create-import-video-file-job.ts @@ -29,7 +29,7 @@ async function checkFiles (video: VideoDetails, objectStorage: boolean) { for (const file of video.files) { if (objectStorage) expectStartWith(file.fileUrl, ObjectStorageCommand.getWebTorrentBaseUrl()) - await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) } } diff --git a/server/tests/cli/create-move-video-storage-job.ts b/server/tests/cli/create-move-video-storage-job.ts index 6a12a2c6c..ecdd75b76 100644 --- a/server/tests/cli/create-move-video-storage-job.ts +++ b/server/tests/cli/create-move-video-storage-job.ts @@ -22,7 +22,7 @@ async function checkFiles (origin: PeerTubeServer, video: VideoDetails, inObject expectStartWith(file.fileUrl, start) - await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) } const start = inObjectStorage @@ -36,7 +36,7 @@ async function checkFiles (origin: PeerTubeServer, video: VideoDetails, inObject for (const file of hls.files) { expectStartWith(file.fileUrl, start) - await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) } } diff --git a/server/tests/cli/create-transcoding-job.ts b/server/tests/cli/create-transcoding-job.ts index 8897d8c23..51bf04a80 100644 --- a/server/tests/cli/create-transcoding-job.ts +++ b/server/tests/cli/create-transcoding-job.ts @@ -23,7 +23,7 @@ async function checkFilesInObjectStorage (files: VideoFile[], type: 'webtorrent' expectStartWith(file.fileUrl, shouldStartWith) - await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) } } diff --git a/server/tests/cli/prune-storage.ts b/server/tests/cli/prune-storage.ts index a89e17e3c..ba0fa1f86 100644 --- a/server/tests/cli/prune-storage.ts +++ b/server/tests/cli/prune-storage.ts @@ -5,7 +5,7 @@ import { createFile, readdir } from 'fs-extra' import { join } from 'path' import { wait } from '@shared/core-utils' import { buildUUID } from '@shared/extra-utils' -import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' +import { HttpStatusCode, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' import { cleanupTests, CLICommand, @@ -36,22 +36,28 @@ async function assertNotExists (server: PeerTubeServer, directory: string, subst async function assertCountAreOkay (servers: PeerTubeServer[]) { for (const server of servers) { const videosCount = await countFiles(server, 'videos') - expect(videosCount).to.equal(8) + expect(videosCount).to.equal(9) // 2 videos with 4 resolutions + private directory + + const privateVideosCount = await countFiles(server, 'videos/private') + expect(privateVideosCount).to.equal(4) const torrentsCount = await countFiles(server, 'torrents') - expect(torrentsCount).to.equal(16) + expect(torrentsCount).to.equal(24) const previewsCount = await countFiles(server, 'previews') - expect(previewsCount).to.equal(2) + expect(previewsCount).to.equal(3) const thumbnailsCount = await countFiles(server, 'thumbnails') - expect(thumbnailsCount).to.equal(6) + expect(thumbnailsCount).to.equal(7) // 3 local videos, 1 local playlist, 2 remotes videos and 1 remote playlist const avatarsCount = await countFiles(server, 'avatars') expect(avatarsCount).to.equal(4) - const hlsRootCount = await countFiles(server, 'streaming-playlists/hls') - expect(hlsRootCount).to.equal(2) + const hlsRootCount = await countFiles(server, join('streaming-playlists', 'hls')) + expect(hlsRootCount).to.equal(3) // 2 videos + private directory + + const hlsPrivateRootCount = await countFiles(server, join('streaming-playlists', 'hls', 'private')) + expect(hlsPrivateRootCount).to.equal(1) } } @@ -67,8 +73,10 @@ describe('Test prune storage scripts', function () { await setDefaultVideoChannel(servers) for (const server of servers) { - await server.videos.upload({ attributes: { name: 'video 1' } }) - await server.videos.upload({ attributes: { name: 'video 2' } }) + await server.videos.upload({ attributes: { name: 'video 1', privacy: VideoPrivacy.PUBLIC } }) + await server.videos.upload({ attributes: { name: 'video 2', privacy: VideoPrivacy.PUBLIC } }) + + await server.videos.upload({ attributes: { name: 'video 3', privacy: VideoPrivacy.PRIVATE } }) await server.users.updateMyAvatar({ fixture: 'avatar.png' }) @@ -123,13 +131,16 @@ describe('Test prune storage scripts', function () { it('Should create some dirty files', async function () { for (let i = 0; i < 2; i++) { { - const base = servers[0].servers.buildDirectory('videos') + const basePublic = servers[0].servers.buildDirectory('videos') + const basePrivate = servers[0].servers.buildDirectory(join('videos', 'private')) const n1 = buildUUID() + '.mp4' const n2 = buildUUID() + '.webm' - await createFile(join(base, n1)) - await createFile(join(base, n2)) + await createFile(join(basePublic, n1)) + await createFile(join(basePublic, n2)) + await createFile(join(basePrivate, n1)) + await createFile(join(basePrivate, n2)) badNames['videos'] = [ n1, n2 ] } @@ -184,10 +195,12 @@ describe('Test prune storage scripts', function () { { const directory = join('streaming-playlists', 'hls') - const base = servers[0].servers.buildDirectory(directory) + const basePublic = servers[0].servers.buildDirectory(directory) + const basePrivate = servers[0].servers.buildDirectory(join(directory, 'private')) const n1 = buildUUID() - await createFile(join(base, n1)) + await createFile(join(basePublic, n1)) + await createFile(join(basePrivate, n1)) badNames[directory] = [ n1 ] } } diff --git a/server/tests/cli/regenerate-thumbnails.ts b/server/tests/cli/regenerate-thumbnails.ts index f459b11b8..16a8adcda 100644 --- a/server/tests/cli/regenerate-thumbnails.ts +++ b/server/tests/cli/regenerate-thumbnails.ts @@ -6,7 +6,7 @@ import { cleanupTests, createMultipleServers, doubleFollow, - makeRawRequest, + makeGetRequest, PeerTubeServer, setAccessTokensToServers, waitJobs @@ -16,8 +16,8 @@ async function testThumbnail (server: PeerTubeServer, videoId: number | string) const video = await server.videos.get({ id: videoId }) const requests = [ - makeRawRequest(join(server.url, video.thumbnailPath), HttpStatusCode.OK_200), - makeRawRequest(join(server.url, video.thumbnailPath), HttpStatusCode.OK_200) + makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }), + makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) ] for (const req of requests) { @@ -69,17 +69,17 @@ describe('Test regenerate thumbnails script', function () { it('Should have empty thumbnails', async function () { { - const res = await makeRawRequest(join(servers[0].url, video1.thumbnailPath), HttpStatusCode.OK_200) + const res = await makeGetRequest({ url: servers[0].url, path: video1.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) expect(res.body).to.have.lengthOf(0) } { - const res = await makeRawRequest(join(servers[0].url, video2.thumbnailPath), HttpStatusCode.OK_200) + const res = await makeGetRequest({ url: servers[0].url, path: video2.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) expect(res.body).to.not.have.lengthOf(0) } { - const res = await makeRawRequest(join(servers[0].url, remoteVideo.thumbnailPath), HttpStatusCode.OK_200) + const res = await makeGetRequest({ url: servers[0].url, path: remoteVideo.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) expect(res.body).to.have.lengthOf(0) } }) @@ -94,21 +94,21 @@ describe('Test regenerate thumbnails script', function () { await testThumbnail(servers[0], video1.uuid) await testThumbnail(servers[0], video2.uuid) - const res = await makeRawRequest(join(servers[0].url, remoteVideo.thumbnailPath), HttpStatusCode.OK_200) + const res = await makeGetRequest({ url: servers[0].url, path: remoteVideo.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) expect(res.body).to.have.lengthOf(0) }) it('Should have deleted old thumbnail files', async function () { { - await makeRawRequest(join(servers[0].url, video1.thumbnailPath), HttpStatusCode.NOT_FOUND_404) + await makeGetRequest({ url: servers[0].url, path: video1.thumbnailPath, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) } { - await makeRawRequest(join(servers[0].url, video2.thumbnailPath), HttpStatusCode.NOT_FOUND_404) + await makeGetRequest({ url: servers[0].url, path: video2.thumbnailPath, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) } { - const res = await makeRawRequest(join(servers[0].url, remoteVideo.thumbnailPath), HttpStatusCode.OK_200) + const res = await makeGetRequest({ url: servers[0].url, path: remoteVideo.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) expect(res.body).to.have.lengthOf(0) } }) diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts index 0ddb641e6..c49175d5e 100644 --- a/server/tests/feeds/feeds.ts +++ b/server/tests/feeds/feeds.ts @@ -314,7 +314,7 @@ describe('Test syndication feeds', () => { const jsonObj = JSON.parse(json) const imageUrl = jsonObj.icon expect(imageUrl).to.include('/lazy-static/avatars/') - await makeRawRequest(imageUrl) + await makeRawRequest({ url: imageUrl }) }) }) diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts index ae4b3cf5f..083fd43ca 100644 --- a/server/tests/plugins/filter-hooks.ts +++ b/server/tests/plugins/filter-hooks.ts @@ -6,6 +6,7 @@ import { cleanupTests, createMultipleServers, doubleFollow, + makeGetRequest, makeRawRequest, PeerTubeServer, PluginsCommand, @@ -461,30 +462,41 @@ describe('Test plugin filter hooks', function () { }) it('Should run filter:api.download.torrent.allowed.result', async function () { - const res = await makeRawRequest(downloadVideos[0].files[0].torrentDownloadUrl, 403) + const res = await makeRawRequest({ url: downloadVideos[0].files[0].torrentDownloadUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) expect(res.body.error).to.equal('Liu Bei') - await makeRawRequest(downloadVideos[1].files[0].torrentDownloadUrl, 200) - await makeRawRequest(downloadVideos[2].files[0].torrentDownloadUrl, 200) + await makeRawRequest({ url: downloadVideos[1].files[0].torrentDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: downloadVideos[2].files[0].torrentDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) }) it('Should run filter:api.download.video.allowed.result', async function () { { - const res = await makeRawRequest(downloadVideos[1].files[0].fileDownloadUrl, 403) + const res = await makeRawRequest({ url: downloadVideos[1].files[0].fileDownloadUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) expect(res.body.error).to.equal('Cao Cao') - await makeRawRequest(downloadVideos[0].files[0].fileDownloadUrl, 200) - await makeRawRequest(downloadVideos[2].files[0].fileDownloadUrl, 200) + await makeRawRequest({ url: downloadVideos[0].files[0].fileDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: downloadVideos[2].files[0].fileDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) } { - const res = await makeRawRequest(downloadVideos[2].streamingPlaylists[0].files[0].fileDownloadUrl, 403) + const res = await makeRawRequest({ + url: downloadVideos[2].streamingPlaylists[0].files[0].fileDownloadUrl, + expectedStatus: HttpStatusCode.FORBIDDEN_403 + }) + expect(res.body.error).to.equal('Sun Jian') - await makeRawRequest(downloadVideos[2].files[0].fileDownloadUrl, 200) + await makeRawRequest({ url: downloadVideos[2].files[0].fileDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) + + await makeRawRequest({ + url: downloadVideos[0].streamingPlaylists[0].files[0].fileDownloadUrl, + expectedStatus: HttpStatusCode.OK_200 + }) - await makeRawRequest(downloadVideos[0].streamingPlaylists[0].files[0].fileDownloadUrl, 200) - await makeRawRequest(downloadVideos[1].streamingPlaylists[0].files[0].fileDownloadUrl, 200) + await makeRawRequest({ + url: downloadVideos[1].streamingPlaylists[0].files[0].fileDownloadUrl, + expectedStatus: HttpStatusCode.OK_200 + }) } }) }) @@ -515,12 +527,12 @@ describe('Test plugin filter hooks', function () { }) it('Should run filter:html.embed.video.allowed.result', async function () { - const res = await makeRawRequest(servers[0].url + embedVideos[0].embedPath, 200) + const res = await makeGetRequest({ url: servers[0].url, path: embedVideos[0].embedPath, expectedStatus: HttpStatusCode.OK_200 }) expect(res.text).to.equal('Lu Bu') }) it('Should run filter:html.embed.video-playlist.allowed.result', async function () { - const res = await makeRawRequest(servers[0].url + embedPlaylists[0].embedPath, 200) + const res = await makeGetRequest({ url: servers[0].url, path: embedPlaylists[0].embedPath, expectedStatus: HttpStatusCode.OK_200 }) expect(res.text).to.equal('Diao Chan') }) }) diff --git a/server/tests/plugins/plugin-helpers.ts b/server/tests/plugins/plugin-helpers.ts index 31c18350a..f2bada4ee 100644 --- a/server/tests/plugins/plugin-helpers.ts +++ b/server/tests/plugins/plugin-helpers.ts @@ -307,7 +307,7 @@ describe('Test plugin helpers', function () { expect(file.fps).to.equal(25) expect(await pathExists(file.path)).to.be.true - await makeRawRequest(file.url, HttpStatusCode.OK_200) + await makeRawRequest({ url: file.url, expectedStatus: HttpStatusCode.OK_200 }) } } @@ -321,12 +321,12 @@ describe('Test plugin helpers', function () { const miniature = body.thumbnails.find(t => t.type === ThumbnailType.MINIATURE) expect(miniature).to.exist expect(await pathExists(miniature.path)).to.be.true - await makeRawRequest(miniature.url, HttpStatusCode.OK_200) + await makeRawRequest({ url: miniature.url, expectedStatus: HttpStatusCode.OK_200 }) const preview = body.thumbnails.find(t => t.type === ThumbnailType.PREVIEW) expect(preview).to.exist expect(await pathExists(preview.path)).to.be.true - await makeRawRequest(preview.url, HttpStatusCode.OK_200) + await makeRawRequest({ url: preview.url, expectedStatus: HttpStatusCode.OK_200 }) } }) diff --git a/server/tests/shared/streaming-playlists.ts b/server/tests/shared/streaming-playlists.ts index 74c25e99c..8ee04d921 100644 --- a/server/tests/shared/streaming-playlists.ts +++ b/server/tests/shared/streaming-playlists.ts @@ -1,9 +1,13 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + import { expect } from 'chai' import { basename } from 'path' -import { removeFragmentedMP4Ext } from '@shared/core-utils' +import { removeFragmentedMP4Ext, uuidRegex } from '@shared/core-utils' import { sha256 } from '@shared/extra-utils' -import { HttpStatusCode, VideoStreamingPlaylist } from '@shared/models' -import { PeerTubeServer } from '@shared/server-commands' +import { HttpStatusCode, VideoStreamingPlaylist, VideoStreamingPlaylistType } from '@shared/models' +import { makeRawRequest, PeerTubeServer, webtorrentAdd } from '@shared/server-commands' +import { expectStartWith } from './checks' +import { hlsInfohashExist } from './tracker' async function checkSegmentHash (options: { server: PeerTubeServer @@ -75,8 +79,118 @@ async function checkResolutionsInMasterPlaylist (options: { expect(playlistsLength).to.have.lengthOf(resolutions.length) } +async function completeCheckHlsPlaylist (options: { + servers: PeerTubeServer[] + videoUUID: string + hlsOnly: boolean + + resolutions?: number[] + objectStorageBaseUrl: string +}) { + const { videoUUID, hlsOnly, objectStorageBaseUrl } = options + + const resolutions = options.resolutions ?? [ 240, 360, 480, 720 ] + + for (const server of options.servers) { + const videoDetails = await server.videos.get({ id: videoUUID }) + const baseUrl = `http://${videoDetails.account.host}` + + expect(videoDetails.streamingPlaylists).to.have.lengthOf(1) + + const hlsPlaylist = videoDetails.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) + expect(hlsPlaylist).to.not.be.undefined + + const hlsFiles = hlsPlaylist.files + expect(hlsFiles).to.have.lengthOf(resolutions.length) + + if (hlsOnly) expect(videoDetails.files).to.have.lengthOf(0) + else expect(videoDetails.files).to.have.lengthOf(resolutions.length) + + // Check JSON files + for (const resolution of resolutions) { + const file = hlsFiles.find(f => f.resolution.id === resolution) + expect(file).to.not.be.undefined + + expect(file.magnetUri).to.have.lengthOf.above(2) + expect(file.torrentUrl).to.match( + new RegExp(`http://${server.host}/lazy-static/torrents/${uuidRegex}-${file.resolution.id}-hls.torrent`) + ) + + if (objectStorageBaseUrl) { + expectStartWith(file.fileUrl, objectStorageBaseUrl) + } else { + expect(file.fileUrl).to.match( + new RegExp(`${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${uuidRegex}-${file.resolution.id}-fragmented.mp4`) + ) + } + + expect(file.resolution.label).to.equal(resolution + 'p') + + await makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) + + const torrent = await webtorrentAdd(file.magnetUri, true) + expect(torrent.files).to.be.an('array') + expect(torrent.files.length).to.equal(1) + expect(torrent.files[0].path).to.exist.and.to.not.equal('') + } + + // Check master playlist + { + await checkResolutionsInMasterPlaylist({ server, playlistUrl: hlsPlaylist.playlistUrl, resolutions }) + + const masterPlaylist = await server.streamingPlaylists.get({ url: hlsPlaylist.playlistUrl }) + + let i = 0 + for (const resolution of resolutions) { + expect(masterPlaylist).to.contain(`${resolution}.m3u8`) + expect(masterPlaylist).to.contain(`${resolution}.m3u8`) + + const url = 'http://' + videoDetails.account.host + await hlsInfohashExist(url, hlsPlaylist.playlistUrl, i) + + i++ + } + } + + // Check resolution playlists + { + for (const resolution of resolutions) { + const file = hlsFiles.find(f => f.resolution.id === resolution) + const playlistName = removeFragmentedMP4Ext(basename(file.fileUrl)) + '.m3u8' + + const url = objectStorageBaseUrl + ? `${objectStorageBaseUrl}hls/${videoUUID}/${playlistName}` + : `${baseUrl}/static/streaming-playlists/hls/${videoUUID}/${playlistName}` + + const subPlaylist = await server.streamingPlaylists.get({ url }) + + expect(subPlaylist).to.match(new RegExp(`${uuidRegex}-${resolution}-fragmented.mp4`)) + expect(subPlaylist).to.contain(basename(file.fileUrl)) + } + } + + { + const baseUrlAndPath = objectStorageBaseUrl + ? objectStorageBaseUrl + 'hls/' + videoUUID + : baseUrl + '/static/streaming-playlists/hls/' + videoUUID + + for (const resolution of resolutions) { + await checkSegmentHash({ + server, + baseUrlPlaylist: baseUrlAndPath, + baseUrlSegment: baseUrlAndPath, + resolution, + hlsPlaylist + }) + } + } + } +} + export { checkSegmentHash, checkLiveSegmentHash, - checkResolutionsInMasterPlaylist + checkResolutionsInMasterPlaylist, + completeCheckHlsPlaylist } diff --git a/server/tests/shared/videos.ts b/server/tests/shared/videos.ts index e18329e07..c8339584b 100644 --- a/server/tests/shared/videos.ts +++ b/server/tests/shared/videos.ts @@ -125,9 +125,9 @@ async function completeVideoCheck ( expect(file.fileDownloadUrl).to.match(new RegExp(`http://${originHost}/download/videos/${uuidRegex}-${file.resolution.id}${extension}`)) await Promise.all([ - makeRawRequest(file.torrentUrl, 200), - makeRawRequest(file.torrentDownloadUrl, 200), - makeRawRequest(file.metadataUrl, 200) + makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 }), + makeRawRequest({ url: file.torrentDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }), + makeRawRequest({ url: file.metadataUrl, expectedStatus: HttpStatusCode.OK_200 }) ]) expect(file.resolution.id).to.equal(attributeFile.resolution) -- cgit v1.2.3