From 26e3e98ff0e222a9fb9226938ac6902af77921bd Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 3 May 2022 11:38:07 +0200 Subject: Support live session in server --- server/tests/api/check-params/live.ts | 46 +++++++++++++ server/tests/api/live/live-constraints.ts | 52 ++++++++++++--- server/tests/api/live/live-permanent.ts | 17 +++++ server/tests/api/live/live-save-replay.ts | 72 +++++++++++++++++++- server/tests/api/live/live.ts | 8 +++ .../tests/api/notifications/user-notifications.ts | 76 +++++++++++++++++++++- server/tests/shared/notifications.ts | 9 ++- 7 files changed, 264 insertions(+), 16 deletions(-) (limited to 'server/tests') diff --git a/server/tests/api/check-params/live.ts b/server/tests/api/check-params/live.ts index bbd331657..29f847e51 100644 --- a/server/tests/api/check-params/live.ts +++ b/server/tests/api/check-params/live.ts @@ -388,6 +388,52 @@ describe('Test video lives API validator', function () { }) }) + describe('When getting live sessions', function () { + + it('Should fail with a bad access token', async function () { + await command.listSessions({ token: 'toto', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) + }) + + it('Should fail without token', async function () { + await command.listSessions({ token: null, videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) + }) + + it('Should fail with the token of another user', async function () { + await command.listSessions({ token: userAccessToken, videoId: video.id, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) + }) + + it('Should fail with a bad video id', async function () { + await command.listSessions({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) + }) + + it('Should fail with an unknown video id', async function () { + await command.listSessions({ videoId: 454555, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) + }) + + it('Should fail with a non live video', async function () { + await command.listSessions({ videoId: videoIdNotLive, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) + }) + + it('Should succeed with the correct params', async function () { + await command.listSessions({ videoId: video.id }) + }) + }) + + describe('When getting live session of a replay', function () { + + it('Should fail with a bad video id', async function () { + await command.getReplaySession({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) + }) + + it('Should fail with an unknown video id', async function () { + await command.getReplaySession({ videoId: 454555, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) + }) + + it('Should fail with a non replay video', async function () { + await command.getReplaySession({ videoId: videoIdNotLive, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) + }) + }) + describe('When updating live information', async function () { it('Should fail without access token', async function () { diff --git a/server/tests/api/live/live-constraints.ts b/server/tests/api/live/live-constraints.ts index b92dc7b89..b81973395 100644 --- a/server/tests/api/live/live-constraints.ts +++ b/server/tests/api/live/live-constraints.ts @@ -3,7 +3,7 @@ import 'mocha' import * as chai from 'chai' import { wait } from '@shared/core-utils' -import { VideoPrivacy } from '@shared/models' +import { LiveVideoError, VideoPrivacy } from '@shared/models' import { cleanupTests, ConfigCommand, @@ -12,7 +12,8 @@ import { PeerTubeServer, setAccessTokensToServers, setDefaultVideoChannel, - waitJobs + waitJobs, + waitUntilLiveWaitingOnAllServers } from '@shared/server-commands' import { checkLiveCleanup } from '../../shared' @@ -24,12 +25,18 @@ describe('Test live constraints', function () { let userAccessToken: string let userChannelId: number - async function createLiveWrapper (saveReplay: boolean) { + async function createLiveWrapper (options: { + replay: boolean + permanent: boolean + }) { + const { replay, permanent } = options + const liveAttributes = { name: 'user live', channelId: userChannelId, privacy: VideoPrivacy.PUBLIC, - saveReplay + saveReplay: replay, + permanentLive: permanent } const { uuid } = await servers[0].live.create({ token: userAccessToken, fields: liveAttributes }) @@ -97,23 +104,42 @@ describe('Test live constraints', function () { it('Should not have size limit if save replay is disabled', async function () { this.timeout(60000) - const userVideoLiveoId = await createLiveWrapper(false) + const userVideoLiveoId = await createLiveWrapper({ replay: false, permanent: false }) await servers[0].live.runAndTestStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: false }) }) - it('Should have size limit depending on user global quota if save replay is enabled', async function () { + it('Should have size limit depending on user global quota if save replay is enabled on non permanent live', async function () { this.timeout(60000) // Wait for user quota memoize cache invalidation await wait(5000) - const userVideoLiveoId = await createLiveWrapper(true) + const userVideoLiveoId = await createLiveWrapper({ replay: true, permanent: false }) await servers[0].live.runAndTestStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: true }) await waitUntilLivePublishedOnAllServers(userVideoLiveoId) await waitJobs(servers) await checkSaveReplay(userVideoLiveoId) + + const session = await servers[0].live.getReplaySession({ videoId: userVideoLiveoId }) + expect(session.error).to.equal(LiveVideoError.QUOTA_EXCEEDED) + }) + + it('Should have size limit depending on user global quota if save replay is enabled on a permanent live', async function () { + this.timeout(60000) + + // Wait for user quota memoize cache invalidation + await wait(5000) + + const userVideoLiveoId = await createLiveWrapper({ replay: true, permanent: true }) + await servers[0].live.runAndTestStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: true }) + + await waitJobs(servers) + await waitUntilLiveWaitingOnAllServers(servers, userVideoLiveoId) + + const session = await servers[0].live.findLatestSession({ videoId: userVideoLiveoId }) + expect(session.error).to.equal(LiveVideoError.QUOTA_EXCEEDED) }) it('Should have size limit depending on user daily quota if save replay is enabled', async function () { @@ -124,13 +150,16 @@ describe('Test live constraints', function () { await updateQuota({ total: -1, daily: 1 }) - const userVideoLiveoId = await createLiveWrapper(true) + const userVideoLiveoId = await createLiveWrapper({ replay: true, permanent: false }) await servers[0].live.runAndTestStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: true }) await waitUntilLivePublishedOnAllServers(userVideoLiveoId) await waitJobs(servers) await checkSaveReplay(userVideoLiveoId) + + const session = await servers[0].live.getReplaySession({ videoId: userVideoLiveoId }) + expect(session.error).to.equal(LiveVideoError.QUOTA_EXCEEDED) }) it('Should succeed without quota limit', async function () { @@ -141,7 +170,7 @@ describe('Test live constraints', function () { await updateQuota({ total: 10 * 1000 * 1000, daily: -1 }) - const userVideoLiveoId = await createLiveWrapper(true) + const userVideoLiveoId = await createLiveWrapper({ replay: true, permanent: false }) await servers[0].live.runAndTestStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: false }) }) @@ -162,13 +191,16 @@ describe('Test live constraints', function () { } }) - const userVideoLiveoId = await createLiveWrapper(true) + const userVideoLiveoId = await createLiveWrapper({ replay: true, permanent: false }) await servers[0].live.runAndTestStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: true }) await waitUntilLivePublishedOnAllServers(userVideoLiveoId) await waitJobs(servers) await checkSaveReplay(userVideoLiveoId, [ 720, 480, 360, 240, 144 ]) + + const session = await servers[0].live.getReplaySession({ videoId: userVideoLiveoId }) + expect(session.error).to.equal(LiveVideoError.DURATION_EXCEEDED) }) after(async function () { diff --git a/server/tests/api/live/live-permanent.ts b/server/tests/api/live/live-permanent.ts index a88d71dd9..92eac9e5f 100644 --- a/server/tests/api/live/live-permanent.ts +++ b/server/tests/api/live/live-permanent.ts @@ -172,6 +172,23 @@ describe('Permanent live', function () { await stopFfmpeg(ffmpegCommand) }) + it('Should have appropriate sessions', async function () { + this.timeout(60000) + + await servers[0].live.waitUntilWaiting({ videoId: videoUUID }) + + const { data, total } = await servers[0].live.listSessions({ videoId: videoUUID }) + expect(total).to.equal(2) + expect(data).to.have.lengthOf(2) + + for (const session of data) { + expect(session.startDate).to.exist + expect(session.endDate).to.exist + + expect(session.error).to.not.exist + } + }) + after(async function () { await cleanupTests(servers) }) diff --git a/server/tests/api/live/live-save-replay.ts b/server/tests/api/live/live-save-replay.ts index fc6acc624..7ddcb04ef 100644 --- a/server/tests/api/live/live-save-replay.ts +++ b/server/tests/api/live/live-save-replay.ts @@ -5,7 +5,7 @@ import * as chai from 'chai' import { FfmpegCommand } from 'fluent-ffmpeg' import { checkLiveCleanup } from '@server/tests/shared' import { wait } from '@shared/core-utils' -import { HttpStatusCode, LiveVideoCreate, VideoPrivacy, VideoState } from '@shared/models' +import { HttpStatusCode, LiveVideoCreate, LiveVideoError, VideoPrivacy, VideoState } from '@shared/models' import { cleanupTests, ConfigCommand, @@ -143,6 +143,9 @@ describe('Save replay setting', function () { }) describe('With save replay disabled', function () { + let sessionStartDateMin: Date + let sessionStartDateMax: Date + let sessionEndDateMin: Date it('Should correctly create and federate the "waiting for stream" live', async function () { this.timeout(20000) @@ -160,7 +163,9 @@ describe('Save replay setting', function () { ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID }) + sessionStartDateMin = new Date() await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID) + sessionStartDateMax = new Date() await waitJobs(servers) @@ -171,6 +176,7 @@ describe('Save replay setting', function () { it('Should correctly delete the video files after the stream ended', async function () { this.timeout(40000) + sessionEndDateMin = new Date() await stopFfmpeg(ffmpegCommand) for (const server of servers) { @@ -186,6 +192,24 @@ describe('Save replay setting', function () { await checkLiveCleanup(servers[0], liveVideoUUID, []) }) + it('Should have appropriate ended session', async function () { + const { data, total } = await servers[0].live.listSessions({ videoId: liveVideoUUID }) + expect(total).to.equal(1) + expect(data).to.have.lengthOf(1) + + const session = data[0] + + const startDate = new Date(session.startDate) + expect(startDate).to.be.above(sessionStartDateMin) + expect(startDate).to.be.below(sessionStartDateMax) + + expect(session.endDate).to.exist + expect(new Date(session.endDate)).to.be.above(sessionEndDateMin) + + expect(session.error).to.not.exist + expect(session.replayVideo).to.not.exist + }) + it('Should correctly terminate the stream on blacklist and delete the live', async function () { this.timeout(40000) @@ -201,6 +225,15 @@ describe('Save replay setting', function () { await checkLiveCleanup(servers[0], liveVideoUUID, []) }) + it('Should have blacklisted session error', async function () { + const session = await servers[0].live.findLatestSession({ videoId: liveVideoUUID }) + expect(session.startDate).to.exist + expect(session.endDate).to.exist + + expect(session.error).to.equal(LiveVideoError.BLACKLISTED) + expect(session.replayVideo).to.not.exist + }) + it('Should correctly terminate the stream on delete and delete the video', async function () { this.timeout(40000) @@ -249,6 +282,22 @@ describe('Save replay setting', function () { await checkVideoState(liveVideoUUID, VideoState.PUBLISHED) }) + it('Should find the replay live session', async function () { + const session = await servers[0].live.getReplaySession({ videoId: liveVideoUUID }) + + expect(session).to.exist + + expect(session.startDate).to.exist + expect(session.endDate).to.exist + + expect(session.error).to.not.exist + + expect(session.replayVideo).to.exist + expect(session.replayVideo.id).to.exist + expect(session.replayVideo.shortUUID).to.exist + expect(session.replayVideo.uuid).to.equal(liveVideoUUID) + }) + it('Should update the saved live and correctly federate the updated attributes', async function () { this.timeout(30000) @@ -337,6 +386,27 @@ describe('Save replay setting', function () { lastReplayUUID = video.uuid }) + it('Should have appropriate ended session and replay live session', async function () { + const { data, total } = await servers[0].live.listSessions({ videoId: liveVideoUUID }) + expect(total).to.equal(1) + expect(data).to.have.lengthOf(1) + + const sessionFromLive = data[0] + const sessionFromReplay = await servers[0].live.getReplaySession({ videoId: lastReplayUUID }) + + for (const session of [ sessionFromLive, sessionFromReplay ]) { + expect(session.startDate).to.exist + expect(session.endDate).to.exist + + expect(session.error).to.not.exist + + expect(session.replayVideo).to.exist + expect(session.replayVideo.id).to.exist + expect(session.replayVideo.shortUUID).to.exist + expect(session.replayVideo.uuid).to.equal(lastReplayUUID) + } + }) + it('Should have cleaned up the live files', async function () { await checkLiveCleanup(servers[0], liveVideoUUID, []) }) diff --git a/server/tests/api/live/live.ts b/server/tests/api/live/live.ts index ab7251e31..9b8fbe3e2 100644 --- a/server/tests/api/live/live.ts +++ b/server/tests/api/live/live.ts @@ -594,6 +594,8 @@ describe('Test live', function () { let permanentLiveReplayName: string + let beforeServerRestart: Date + async function createLiveWrapper (options: { saveReplay: boolean, permanent: boolean }) { const liveAttributes: LiveVideoCreate = { name: 'live video', @@ -636,6 +638,8 @@ describe('Test live', function () { } await killallServers([ servers[0] ]) + + beforeServerRestart = new Date() await servers[0].run() await wait(5000) @@ -653,6 +657,10 @@ describe('Test live', function () { this.timeout(120000) await commands[0].waitUntilPublished({ videoId: liveVideoReplayId }) + + const session = await commands[0].getReplaySession({ videoId: liveVideoReplayId }) + expect(session.endDate).to.exist + expect(new Date(session.endDate)).to.be.above(beforeServerRestart) }) it('Should have saved a permanent live replay', async function () { diff --git a/server/tests/api/notifications/user-notifications.ts b/server/tests/api/notifications/user-notifications.ts index 47e85a30c..1705fda55 100644 --- a/server/tests/api/notifications/user-notifications.ts +++ b/server/tests/api/notifications/user-notifications.ts @@ -7,8 +7,8 @@ import { checkMyVideoImportIsFinished, checkNewActorFollow, checkNewVideoFromSubscription, - checkVideoStudioEditionIsFinished, checkVideoIsPublished, + checkVideoStudioEditionIsFinished, FIXTURE_URLS, MockSmtpServer, prepareNotificationsTest, @@ -16,8 +16,8 @@ import { } from '@server/tests/shared' import { wait } from '@shared/core-utils' import { buildUUID } from '@shared/extra-utils' -import { UserNotification, UserNotificationType, VideoStudioTask, VideoPrivacy } from '@shared/models' -import { cleanupTests, PeerTubeServer, waitJobs } from '@shared/server-commands' +import { UserNotification, UserNotificationType, VideoPrivacy, VideoStudioTask } from '@shared/models' +import { cleanupTests, findExternalSavedVideo, PeerTubeServer, stopFfmpeg, waitJobs } from '@shared/server-commands' const expect = chai.expect @@ -323,6 +323,76 @@ describe('Test user notifications', function () { }) }) + describe('My live replay is published', function () { + + let baseParams: CheckerBaseParams + + before(() => { + baseParams = { + server: servers[1], + emails, + socketNotifications: adminNotificationsServer2, + token: servers[1].accessToken + } + }) + + it('Should send a notification is a live replay of a non permanent live is published', async function () { + this.timeout(120000) + + const { shortUUID } = await servers[1].live.create({ + fields: { + name: 'non permanent live', + privacy: VideoPrivacy.PUBLIC, + channelId: servers[1].store.channel.id, + saveReplay: true, + permanentLive: false + } + }) + + const ffmpegCommand = await servers[1].live.sendRTMPStreamInVideo({ videoId: shortUUID }) + + await waitJobs(servers) + await servers[1].live.waitUntilPublished({ videoId: shortUUID }) + + await stopFfmpeg(ffmpegCommand) + await servers[1].live.waitUntilReplacedByReplay({ videoId: shortUUID }) + + await waitJobs(servers) + await checkVideoIsPublished({ ...baseParams, videoName: 'non permanent live', shortUUID, checkType: 'presence' }) + }) + + it('Should send a notification is a live replay of a permanent live is published', async function () { + this.timeout(120000) + + const { shortUUID } = await servers[1].live.create({ + fields: { + name: 'permanent live', + privacy: VideoPrivacy.PUBLIC, + channelId: servers[1].store.channel.id, + saveReplay: true, + permanentLive: true + } + }) + + const ffmpegCommand = await servers[1].live.sendRTMPStreamInVideo({ videoId: shortUUID }) + + await waitJobs(servers) + await servers[1].live.waitUntilPublished({ videoId: shortUUID }) + + const liveDetails = await servers[1].videos.get({ id: shortUUID }) + + await stopFfmpeg(ffmpegCommand) + + await servers[1].live.waitUntilWaiting({ videoId: shortUUID }) + await waitJobs(servers) + + const video = await findExternalSavedVideo(servers[1], liveDetails) + expect(video).to.exist + + await checkVideoIsPublished({ ...baseParams, videoName: video.name, shortUUID: video.shortUUID, checkType: 'presence' }) + }) + }) + describe('Video studio', function () { let baseParams: CheckerBaseParams diff --git a/server/tests/shared/notifications.ts b/server/tests/shared/notifications.ts index 58d79d3aa..a62410880 100644 --- a/server/tests/shared/notifications.ts +++ b/server/tests/shared/notifications.ts @@ -16,7 +16,8 @@ import { PeerTubeServer, setAccessTokensToServers, setDefaultAccountAvatar, - setDefaultChannelAvatar + setDefaultChannelAvatar, + setDefaultVideoChannel } from '@shared/server-commands' import { MockSmtpServer } from './mock-servers' @@ -682,10 +683,14 @@ async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: an const servers = await createMultipleServers(serversCount, Object.assign(overrideConfig, overrideConfigArg)) await setAccessTokensToServers(servers) + await setDefaultVideoChannel(servers) await setDefaultChannelAvatar(servers) await setDefaultAccountAvatar(servers) - if (servers[1]) await servers[1].config.enableStudio() + if (servers[1]) { + await servers[1].config.enableStudio() + await servers[1].config.enableLive({ allowReplay: true, transcoding: false }) + } if (serversCount > 1) { await doubleFollow(servers[0], servers[1]) -- cgit v1.2.3