Introduce live command

pull/4271/head
Chocobozzz 2021-07-08 10:18:40 +02:00
parent 2c27e70471
commit 4f2199144e
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
20 changed files with 370 additions and 338 deletions

View File

@ -2,27 +2,24 @@
import 'mocha' import 'mocha'
import { omit } from 'lodash' import { omit } from 'lodash'
import { LiveVideo, VideoCreateResult, VideoPrivacy } from '@shared/models' import { VideoCreateResult, VideoPrivacy } from '@shared/models'
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
import { import {
buildAbsoluteFixturePath, buildAbsoluteFixturePath,
cleanupTests, cleanupTests,
createUser, createUser,
flushAndRunServer, flushAndRunServer,
getLive,
getMyUserInformation, getMyUserInformation,
immutableAssign, immutableAssign,
LiveCommand,
makePostBodyRequest, makePostBodyRequest,
makeUploadRequest, makeUploadRequest,
runAndTestFfmpegStreamError,
sendRTMPStream, sendRTMPStream,
ServerInfo, ServerInfo,
setAccessTokensToServers, setAccessTokensToServers,
stopFfmpeg, stopFfmpeg,
updateLive,
uploadVideoAndGetId, uploadVideoAndGetId,
userLogin, userLogin
waitUntilLivePublished
} from '../../../../shared/extra-utils' } from '../../../../shared/extra-utils'
describe('Test video lives API validator', function () { describe('Test video lives API validator', function () {
@ -32,6 +29,7 @@ describe('Test video lives API validator', function () {
let channelId: number let channelId: number
let video: VideoCreateResult let video: VideoCreateResult
let videoIdNotLive: number let videoIdNotLive: number
let command: LiveCommand
// --------------------------------------------------------------- // ---------------------------------------------------------------
@ -66,6 +64,8 @@ describe('Test video lives API validator', function () {
{ {
videoIdNotLive = (await uploadVideoAndGetId({ server, videoName: 'not live' })).id videoIdNotLive = (await uploadVideoAndGetId({ server, videoName: 'not live' })).id
} }
command = server.liveCommand
}) })
describe('When creating a live', function () { describe('When creating a live', function () {
@ -337,70 +337,72 @@ describe('Test video lives API validator', function () {
describe('When getting live information', function () { describe('When getting live information', function () {
it('Should fail without access token', async function () { it('Should fail without access token', async function () {
await getLive(server.url, '', video.id, HttpStatusCode.UNAUTHORIZED_401) await command.getLive({ token: '', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
}) })
it('Should fail with a bad access token', async function () { it('Should fail with a bad access token', async function () {
await getLive(server.url, 'toto', video.id, HttpStatusCode.UNAUTHORIZED_401) await command.getLive({ token: 'toto', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
}) })
it('Should fail with access token of another user', async function () { it('Should fail with access token of another user', async function () {
await getLive(server.url, userAccessToken, video.id, HttpStatusCode.FORBIDDEN_403) await command.getLive({ token: userAccessToken, videoId: video.id, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
}) })
it('Should fail with a bad video id', async function () { it('Should fail with a bad video id', async function () {
await getLive(server.url, server.accessToken, 'toto', HttpStatusCode.BAD_REQUEST_400) await command.getLive({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
}) })
it('Should fail with an unknown video id', async function () { it('Should fail with an unknown video id', async function () {
await getLive(server.url, server.accessToken, 454555, HttpStatusCode.NOT_FOUND_404) await command.getLive({ videoId: 454555, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
}) })
it('Should fail with a non live video', async function () { it('Should fail with a non live video', async function () {
await getLive(server.url, server.accessToken, videoIdNotLive, HttpStatusCode.NOT_FOUND_404) await command.getLive({ videoId: videoIdNotLive, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
}) })
it('Should succeed with the correct params', async function () { it('Should succeed with the correct params', async function () {
await getLive(server.url, server.accessToken, video.id) await command.getLive({ videoId: video.id })
await getLive(server.url, server.accessToken, video.shortUUID) await command.getLive({ videoId: video.uuid })
await command.getLive({ videoId: video.shortUUID })
}) })
}) })
describe('When updating live information', async function () { describe('When updating live information', async function () {
it('Should fail without access token', async function () { it('Should fail without access token', async function () {
await updateLive(server.url, '', video.id, {}, HttpStatusCode.UNAUTHORIZED_401) await command.updateLive({ token: '', videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
}) })
it('Should fail with a bad access token', async function () { it('Should fail with a bad access token', async function () {
await updateLive(server.url, 'toto', video.id, {}, HttpStatusCode.UNAUTHORIZED_401) await command.updateLive({ token: 'toto', videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
}) })
it('Should fail with access token of another user', async function () { it('Should fail with access token of another user', async function () {
await updateLive(server.url, userAccessToken, video.id, {}, HttpStatusCode.FORBIDDEN_403) await command.updateLive({ token: userAccessToken, videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
}) })
it('Should fail with a bad video id', async function () { it('Should fail with a bad video id', async function () {
await updateLive(server.url, server.accessToken, 'toto', {}, HttpStatusCode.BAD_REQUEST_400) await command.updateLive({ videoId: 'toto', fields: {}, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
}) })
it('Should fail with an unknown video id', async function () { it('Should fail with an unknown video id', async function () {
await updateLive(server.url, server.accessToken, 454555, {}, HttpStatusCode.NOT_FOUND_404) await command.updateLive({ videoId: 454555, fields: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
}) })
it('Should fail with a non live video', async function () { it('Should fail with a non live video', async function () {
await updateLive(server.url, server.accessToken, videoIdNotLive, {}, HttpStatusCode.NOT_FOUND_404) await command.updateLive({ videoId: videoIdNotLive, fields: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
}) })
it('Should fail with save replay and permanent live set to true', async function () { it('Should fail with save replay and permanent live set to true', async function () {
const fields = { saveReplay: true, permanentLive: true } const fields = { saveReplay: true, permanentLive: true }
await updateLive(server.url, server.accessToken, video.id, fields, HttpStatusCode.BAD_REQUEST_400) await command.updateLive({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
}) })
it('Should succeed with the correct params', async function () { it('Should succeed with the correct params', async function () {
await updateLive(server.url, server.accessToken, video.id, { saveReplay: false }) await command.updateLive({ videoId: video.id, fields: { saveReplay: false } })
await updateLive(server.url, server.accessToken, video.shortUUID, { saveReplay: false }) await command.updateLive({ videoId: video.uuid, fields: { saveReplay: false } })
await command.updateLive({ videoId: video.shortUUID, fields: { saveReplay: false } })
}) })
it('Should fail to update replay status if replay is not allowed on the instance', async function () { it('Should fail to update replay status if replay is not allowed on the instance', async function () {
@ -413,36 +415,34 @@ describe('Test video lives API validator', function () {
} }
}) })
await updateLive(server.url, server.accessToken, video.id, { saveReplay: true }, HttpStatusCode.FORBIDDEN_403) await command.updateLive({ videoId: video.id, fields: { saveReplay: true }, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
}) })
it('Should fail to update a live if it has already started', async function () { it('Should fail to update a live if it has already started', async function () {
this.timeout(40000) this.timeout(40000)
const resLive = await getLive(server.url, server.accessToken, video.id) const live = await command.getLive({ videoId: video.id })
const live: LiveVideo = resLive.body
const command = sendRTMPStream(live.rtmpUrl, live.streamKey) const ffmpegCommand = sendRTMPStream(live.rtmpUrl, live.streamKey)
await waitUntilLivePublished(server.url, server.accessToken, video.id) await command.waitUntilLivePublished({ videoId: video.id })
await updateLive(server.url, server.accessToken, video.id, {}, HttpStatusCode.BAD_REQUEST_400) await command.updateLive({ videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
await stopFfmpeg(command) await stopFfmpeg(ffmpegCommand)
}) })
it('Should fail to stream twice in the save live', async function () { it('Should fail to stream twice in the save live', async function () {
this.timeout(40000) this.timeout(40000)
const resLive = await getLive(server.url, server.accessToken, video.id) const live = await command.getLive({ videoId: video.id })
const live: LiveVideo = resLive.body
const command = sendRTMPStream(live.rtmpUrl, live.streamKey) const ffmpegCommand = sendRTMPStream(live.rtmpUrl, live.streamKey)
await waitUntilLivePublished(server.url, server.accessToken, video.id) await command.waitUntilLivePublished({ videoId: video.id })
await runAndTestFfmpegStreamError(server.url, server.accessToken, video.id, true) await command.runAndTestFfmpegStreamError({ videoId: video.id, shouldHaveError: true })
await stopFfmpeg(command) await stopFfmpeg(ffmpegCommand)
}) })
}) })

View File

@ -7,19 +7,16 @@ import {
checkLiveCleanup, checkLiveCleanup,
cleanupTests, cleanupTests,
ConfigCommand, ConfigCommand,
createLive,
doubleFollow, doubleFollow,
flushAndRunMultipleServers, flushAndRunMultipleServers,
generateUser, generateUser,
getVideo, getVideo,
runAndTestFfmpegStreamError,
ServerInfo, ServerInfo,
setAccessTokensToServers, setAccessTokensToServers,
setDefaultVideoChannel, setDefaultVideoChannel,
updateUser, updateUser,
wait, wait,
waitJobs, waitJobs
waitUntilLivePublished
} from '../../../../shared/extra-utils' } from '../../../../shared/extra-utils'
const expect = chai.expect const expect = chai.expect
@ -38,8 +35,8 @@ describe('Test live constraints', function () {
saveReplay saveReplay
} }
const res = await createLive(servers[0].url, userAccessToken, liveAttributes) const { uuid } = await servers[0].liveCommand.createLive({ token: userAccessToken, fields: liveAttributes })
return res.body.video.uuid as string return uuid
} }
async function checkSaveReplay (videoId: string, resolutions = [ 720 ]) { async function checkSaveReplay (videoId: string, resolutions = [ 720 ]) {
@ -56,7 +53,7 @@ describe('Test live constraints', function () {
async function waitUntilLivePublishedOnAllServers (videoId: string) { async function waitUntilLivePublishedOnAllServers (videoId: string) {
for (const server of servers) { for (const server of servers) {
await waitUntilLivePublished(server.url, server.accessToken, videoId) await server.liveCommand.waitUntilLivePublished({ videoId })
} }
} }
@ -108,7 +105,7 @@ describe('Test live constraints', function () {
this.timeout(60000) this.timeout(60000)
const userVideoLiveoId = await createLiveWrapper(false) const userVideoLiveoId = await createLiveWrapper(false)
await runAndTestFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, false) await servers[0].liveCommand.runAndTestFfmpegStreamError({ 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', async function () {
@ -118,7 +115,7 @@ describe('Test live constraints', function () {
await wait(5000) await wait(5000)
const userVideoLiveoId = await createLiveWrapper(true) const userVideoLiveoId = await createLiveWrapper(true)
await runAndTestFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, true) await servers[0].liveCommand.runAndTestFfmpegStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: true })
await waitUntilLivePublishedOnAllServers(userVideoLiveoId) await waitUntilLivePublishedOnAllServers(userVideoLiveoId)
await waitJobs(servers) await waitJobs(servers)
@ -135,7 +132,7 @@ describe('Test live constraints', function () {
await updateQuota({ total: -1, daily: 1 }) await updateQuota({ total: -1, daily: 1 })
const userVideoLiveoId = await createLiveWrapper(true) const userVideoLiveoId = await createLiveWrapper(true)
await runAndTestFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, true) await servers[0].liveCommand.runAndTestFfmpegStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: true })
await waitUntilLivePublishedOnAllServers(userVideoLiveoId) await waitUntilLivePublishedOnAllServers(userVideoLiveoId)
await waitJobs(servers) await waitJobs(servers)
@ -152,7 +149,7 @@ describe('Test live constraints', function () {
await updateQuota({ total: 10 * 1000 * 1000, daily: -1 }) await updateQuota({ total: 10 * 1000 * 1000, daily: -1 })
const userVideoLiveoId = await createLiveWrapper(true) const userVideoLiveoId = await createLiveWrapper(true)
await runAndTestFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, false) await servers[0].liveCommand.runAndTestFfmpegStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: false })
}) })
it('Should have max duration limit', async function () { it('Should have max duration limit', async function () {
@ -173,7 +170,7 @@ describe('Test live constraints', function () {
}) })
const userVideoLiveoId = await createLiveWrapper(true) const userVideoLiveoId = await createLiveWrapper(true)
await runAndTestFfmpegStreamError(servers[0].url, userAccessToken, userVideoLiveoId, true) await servers[0].liveCommand.runAndTestFfmpegStreamError({ token: userAccessToken, videoId: userVideoLiveoId, shouldHaveError: true })
await waitUntilLivePublishedOnAllServers(userVideoLiveoId) await waitUntilLivePublishedOnAllServers(userVideoLiveoId)
await waitJobs(servers) await waitJobs(servers)

View File

@ -6,22 +6,15 @@ import { LiveVideoCreate, VideoDetails, VideoPrivacy, VideoState } from '@shared
import { import {
cleanupTests, cleanupTests,
ConfigCommand, ConfigCommand,
createLive,
doubleFollow, doubleFollow,
flushAndRunMultipleServers, flushAndRunMultipleServers,
getLive,
getPlaylistsCount,
getVideo, getVideo,
sendRTMPStreamInVideo,
ServerInfo, ServerInfo,
setAccessTokensToServers, setAccessTokensToServers,
setDefaultVideoChannel, setDefaultVideoChannel,
stopFfmpeg, stopFfmpeg,
updateLive,
wait, wait,
waitJobs, waitJobs
waitUntilLivePublished,
waitUntilLiveWaiting
} from '../../../../shared/extra-utils' } from '../../../../shared/extra-utils'
const expect = chai.expect const expect = chai.expect
@ -39,8 +32,8 @@ describe('Permanent live', function () {
permanentLive permanentLive
} }
const res = await createLive(servers[0].url, servers[0].accessToken, attributes) const { uuid } = await servers[0].liveCommand.createLive({ fields: attributes })
return res.body.video.uuid return uuid
} }
async function checkVideoState (videoId: string, state: VideoState) { async function checkVideoState (videoId: string, state: VideoState) {
@ -83,15 +76,15 @@ describe('Permanent live', function () {
const videoUUID = await createLiveWrapper(false) const videoUUID = await createLiveWrapper(false)
{ {
const res = await getLive(servers[0].url, servers[0].accessToken, videoUUID) const live = await servers[0].liveCommand.getLive({ videoId: videoUUID })
expect(res.body.permanentLive).to.be.false expect(live.permanentLive).to.be.false
} }
await updateLive(servers[0].url, servers[0].accessToken, videoUUID, { permanentLive: true }) await servers[0].liveCommand.updateLive({ videoId: videoUUID, fields: { permanentLive: true } })
{ {
const res = await getLive(servers[0].url, servers[0].accessToken, videoUUID) const live = await servers[0].liveCommand.getLive({ videoId: videoUUID })
expect(res.body.permanentLive).to.be.true expect(live.permanentLive).to.be.true
} }
}) })
@ -100,8 +93,8 @@ describe('Permanent live', function () {
videoUUID = await createLiveWrapper(true) videoUUID = await createLiveWrapper(true)
const res = await getLive(servers[0].url, servers[0].accessToken, videoUUID) const live = await servers[0].liveCommand.getLive({ videoId: videoUUID })
expect(res.body.permanentLive).to.be.true expect(live.permanentLive).to.be.true
await waitJobs(servers) await waitJobs(servers)
}) })
@ -109,16 +102,16 @@ describe('Permanent live', function () {
it('Should stream into this permanent live', async function () { it('Should stream into this permanent live', async function () {
this.timeout(120000) this.timeout(120000)
const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, videoUUID) const ffmpegCommand = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: videoUUID })
for (const server of servers) { for (const server of servers) {
await waitUntilLivePublished(server.url, server.accessToken, videoUUID) await server.liveCommand.waitUntilLivePublished({ videoId: videoUUID })
} }
await checkVideoState(videoUUID, VideoState.PUBLISHED) await checkVideoState(videoUUID, VideoState.PUBLISHED)
await stopFfmpeg(command) await stopFfmpeg(ffmpegCommand)
await waitUntilLiveWaiting(servers[0].url, servers[0].accessToken, videoUUID) await servers[0].liveCommand.waitUntilLiveWaiting({ videoId: videoUUID })
await waitJobs(servers) await waitJobs(servers)
}) })
@ -160,19 +153,19 @@ describe('Permanent live', function () {
} }
}) })
const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, videoUUID) const ffmpegCommand = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: videoUUID })
for (const server of servers) { for (const server of servers) {
await waitUntilLivePublished(server.url, server.accessToken, videoUUID) await server.liveCommand.waitUntilLivePublished({ videoId: videoUUID })
} }
await checkVideoState(videoUUID, VideoState.PUBLISHED) await checkVideoState(videoUUID, VideoState.PUBLISHED)
const count = await getPlaylistsCount(servers[0], videoUUID) const count = await servers[0].liveCommand.getPlaylistsCount({ videoUUID })
// master playlist and 720p playlist // master playlist and 720p playlist
expect(count).to.equal(2) expect(count).to.equal(2)
await stopFfmpeg(command) await stopFfmpeg(ffmpegCommand)
}) })
after(async function () { after(async function () {

View File

@ -10,13 +10,11 @@ import {
checkLiveCleanup, checkLiveCleanup,
cleanupTests, cleanupTests,
ConfigCommand, ConfigCommand,
createLive,
doubleFollow, doubleFollow,
flushAndRunMultipleServers, flushAndRunMultipleServers,
getVideo, getVideo,
getVideosList, getVideosList,
removeVideo, removeVideo,
sendRTMPStreamInVideo,
ServerInfo, ServerInfo,
setAccessTokensToServers, setAccessTokensToServers,
setDefaultVideoChannel, setDefaultVideoChannel,
@ -24,10 +22,7 @@ import {
testFfmpegStreamError, testFfmpegStreamError,
updateVideo, updateVideo,
wait, wait,
waitJobs, waitJobs
waitUntilLiveEnded,
waitUntilLivePublished,
waitUntilLiveSaved
} from '../../../../shared/extra-utils' } from '../../../../shared/extra-utils'
const expect = chai.expect const expect = chai.expect
@ -52,8 +47,8 @@ describe('Save replay setting', function () {
saveReplay saveReplay
} }
const res = await createLive(servers[0].url, servers[0].accessToken, attributes) const { uuid } = await servers[0].liveCommand.createLive({ fields: attributes })
return res.body.video.uuid return uuid
} }
async function checkVideosExist (videoId: string, existsInList: boolean, getStatus?: number) { async function checkVideosExist (videoId: string, existsInList: boolean, getStatus?: number) {
@ -79,13 +74,13 @@ describe('Save replay setting', function () {
async function waitUntilLivePublishedOnAllServers (videoId: string) { async function waitUntilLivePublishedOnAllServers (videoId: string) {
for (const server of servers) { for (const server of servers) {
await waitUntilLivePublished(server.url, server.accessToken, videoId) await server.liveCommand.waitUntilLivePublished({ videoId })
} }
} }
async function waitUntilLiveSavedOnAllServers (videoId: string) { async function waitUntilLiveSavedOnAllServers (videoId: string) {
for (const server of servers) { for (const server of servers) {
await waitUntilLiveSaved(server.url, server.accessToken, videoId) await server.liveCommand.waitUntilLiveSaved({ videoId })
} }
} }
@ -136,7 +131,7 @@ describe('Save replay setting', function () {
it('Should correctly have updated the live and federated it when streaming in the live', async function () { it('Should correctly have updated the live and federated it when streaming in the live', async function () {
this.timeout(30000) this.timeout(30000)
ffmpegCommand = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID) ffmpegCommand = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
await waitUntilLivePublishedOnAllServers(liveVideoUUID) await waitUntilLivePublishedOnAllServers(liveVideoUUID)
@ -152,7 +147,7 @@ describe('Save replay setting', function () {
await stopFfmpeg(ffmpegCommand) await stopFfmpeg(ffmpegCommand)
for (const server of servers) { for (const server of servers) {
await waitUntilLiveEnded(server.url, server.accessToken, liveVideoUUID) await server.liveCommand.waitUntilLiveEnded({ videoId: liveVideoUUID })
} }
await waitJobs(servers) await waitJobs(servers)
@ -169,7 +164,7 @@ describe('Save replay setting', function () {
liveVideoUUID = await createLiveWrapper(false) liveVideoUUID = await createLiveWrapper(false)
ffmpegCommand = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID) ffmpegCommand = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
await waitUntilLivePublishedOnAllServers(liveVideoUUID) await waitUntilLivePublishedOnAllServers(liveVideoUUID)
@ -198,7 +193,7 @@ describe('Save replay setting', function () {
liveVideoUUID = await createLiveWrapper(false) liveVideoUUID = await createLiveWrapper(false)
ffmpegCommand = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID) ffmpegCommand = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
await waitUntilLivePublishedOnAllServers(liveVideoUUID) await waitUntilLivePublishedOnAllServers(liveVideoUUID)
@ -234,7 +229,7 @@ describe('Save replay setting', function () {
it('Should correctly have updated the live and federated it when streaming in the live', async function () { it('Should correctly have updated the live and federated it when streaming in the live', async function () {
this.timeout(20000) this.timeout(20000)
ffmpegCommand = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID) ffmpegCommand = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
await waitUntilLivePublishedOnAllServers(liveVideoUUID) await waitUntilLivePublishedOnAllServers(liveVideoUUID)
await waitJobs(servers) await waitJobs(servers)
@ -278,7 +273,7 @@ describe('Save replay setting', function () {
liveVideoUUID = await createLiveWrapper(true) liveVideoUUID = await createLiveWrapper(true)
ffmpegCommand = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID) ffmpegCommand = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
await waitUntilLivePublishedOnAllServers(liveVideoUUID) await waitUntilLivePublishedOnAllServers(liveVideoUUID)
await waitJobs(servers) await waitJobs(servers)
@ -306,7 +301,7 @@ describe('Save replay setting', function () {
liveVideoUUID = await createLiveWrapper(true) liveVideoUUID = await createLiveWrapper(true)
ffmpegCommand = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID) ffmpegCommand = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
await waitUntilLivePublishedOnAllServers(liveVideoUUID) await waitUntilLivePublishedOnAllServers(liveVideoUUID)
await waitJobs(servers) await waitJobs(servers)

View File

@ -5,11 +5,9 @@ import * as chai from 'chai'
import { VideoPrivacy, VideoState } from '@shared/models' import { VideoPrivacy, VideoState } from '@shared/models'
import { import {
cleanupTests, cleanupTests,
createLive,
doubleFollow, doubleFollow,
flushAndRunMultipleServers, flushAndRunMultipleServers,
getVideoIdFromUUID, getVideoIdFromUUID,
sendRTMPStreamInVideo,
ServerInfo, ServerInfo,
setAccessTokensToServers, setAccessTokensToServers,
setDefaultVideoChannel, setDefaultVideoChannel,
@ -17,7 +15,6 @@ import {
viewVideo, viewVideo,
wait, wait,
waitJobs, waitJobs,
waitUntilLiveEnded,
waitUntilLivePublishedOnAllServers waitUntilLivePublishedOnAllServers
} from '../../../../shared/extra-utils' } from '../../../../shared/extra-utils'
@ -60,8 +57,8 @@ describe('Test live', function () {
privacy: VideoPrivacy.PUBLIC privacy: VideoPrivacy.PUBLIC
} }
const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes) const { uuid } = await servers[0].liveCommand.createLive({ fields: liveAttributes })
return res.body.video.uuid return uuid
} }
it('Should correctly send a message when the live starts and ends', async function () { it('Should correctly send a message when the live starts and ends', async function () {
@ -89,7 +86,7 @@ describe('Test live', function () {
remoteSocket.emit('subscribe', { videoId }) remoteSocket.emit('subscribe', { videoId })
} }
const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID) const ffmpegCommand = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID) await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
await waitJobs(servers) await waitJobs(servers)
@ -99,10 +96,10 @@ describe('Test live', function () {
expect(stateChanges[stateChanges.length - 1]).to.equal(VideoState.PUBLISHED) expect(stateChanges[stateChanges.length - 1]).to.equal(VideoState.PUBLISHED)
} }
await stopFfmpeg(command) await stopFfmpeg(ffmpegCommand)
for (const server of servers) { for (const server of servers) {
await waitUntilLiveEnded(server.url, server.accessToken, liveVideoUUID) await server.liveCommand.waitUntilLiveEnded({ videoId: liveVideoUUID })
} }
await waitJobs(servers) await waitJobs(servers)
@ -137,7 +134,7 @@ describe('Test live', function () {
remoteSocket.emit('subscribe', { videoId }) remoteSocket.emit('subscribe', { videoId })
} }
const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID) const ffmpegCommand = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID) await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
await waitJobs(servers) await waitJobs(servers)
@ -155,7 +152,7 @@ describe('Test live', function () {
expect(localLastVideoViews).to.equal(2) expect(localLastVideoViews).to.equal(2)
expect(remoteLastVideoViews).to.equal(2) expect(remoteLastVideoViews).to.equal(2)
await stopFfmpeg(command) await stopFfmpeg(ffmpegCommand)
}) })
it('Should not receive a notification after unsubscribe', async function () { it('Should not receive a notification after unsubscribe', async function () {
@ -172,7 +169,7 @@ describe('Test live', function () {
socket.on('state-change', data => stateChanges.push(data.state)) socket.on('state-change', data => stateChanges.push(data.state))
socket.emit('subscribe', { videoId }) socket.emit('subscribe', { videoId })
const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID) const command = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID) await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
await waitJobs(servers) await waitJobs(servers)

View File

@ -6,11 +6,9 @@ import { FfmpegCommand } from 'fluent-ffmpeg'
import { VideoDetails, VideoPrivacy } from '@shared/models' import { VideoDetails, VideoPrivacy } from '@shared/models'
import { import {
cleanupTests, cleanupTests,
createLive,
doubleFollow, doubleFollow,
flushAndRunMultipleServers, flushAndRunMultipleServers,
getVideo, getVideo,
sendRTMPStreamInVideo,
ServerInfo, ServerInfo,
setAccessTokensToServers, setAccessTokensToServers,
setDefaultVideoChannel, setDefaultVideoChannel,
@ -73,10 +71,10 @@ describe('Test live', function () {
privacy: VideoPrivacy.PUBLIC privacy: VideoPrivacy.PUBLIC
} }
const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes) const live = await servers[0].liveCommand.createLive({ fields: liveAttributes })
liveVideoId = res.body.video.uuid liveVideoId = live.uuid
command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId) command = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoId })
await waitUntilLivePublishedOnAllServers(servers, liveVideoId) await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
await waitJobs(servers) await waitJobs(servers)
}) })

View File

@ -13,41 +13,36 @@ import {
checkLiveSegmentHash, checkLiveSegmentHash,
checkResolutionsInMasterPlaylist, checkResolutionsInMasterPlaylist,
cleanupTests, cleanupTests,
createLive,
doubleFollow, doubleFollow,
flushAndRunMultipleServers, flushAndRunMultipleServers,
getLive,
getMyVideosWithFilter, getMyVideosWithFilter,
getPlaylist, getPlaylist,
getVideo, getVideo,
getVideosList, getVideosList,
getVideosWithFilters, getVideosWithFilters,
killallServers, killallServers,
LiveCommand,
makeRawRequest, makeRawRequest,
removeVideo, removeVideo,
reRunServer, reRunServer,
sendRTMPStream, sendRTMPStream,
sendRTMPStreamInVideo,
ServerInfo, ServerInfo,
setAccessTokensToServers, setAccessTokensToServers,
setDefaultVideoChannel, setDefaultVideoChannel,
stopFfmpeg, stopFfmpeg,
testFfmpegStreamError, testFfmpegStreamError,
testImage, testImage,
updateLive,
uploadVideoAndGetId, uploadVideoAndGetId,
wait, wait,
waitJobs, waitJobs,
waitUntilLiveEnded, waitUntilLivePublishedOnAllServers
waitUntilLivePublished,
waitUntilLivePublishedOnAllServers,
waitUntilLiveSegmentGeneration
} from '../../../../shared/extra-utils' } from '../../../../shared/extra-utils'
const expect = chai.expect const expect = chai.expect
describe('Test live', function () { describe('Test live', function () {
let servers: ServerInfo[] = [] let servers: ServerInfo[] = []
let commands: LiveCommand[]
before(async function () { before(async function () {
this.timeout(120000) this.timeout(120000)
@ -72,6 +67,8 @@ describe('Test live', function () {
// Server 1 and server 2 follow each other // Server 1 and server 2 follow each other
await doubleFollow(servers[0], servers[1]) await doubleFollow(servers[0], servers[1])
commands = servers.map(s => s.liveCommand)
}) })
describe('Live creation, update and delete', function () { describe('Live creation, update and delete', function () {
@ -99,8 +96,8 @@ describe('Test live', function () {
thumbnailfile: 'video_short1.webm.jpg' thumbnailfile: 'video_short1.webm.jpg'
} }
const res = await createLive(servers[0].url, servers[0].accessToken, attributes) const live = await commands[0].createLive({ fields: attributes })
liveVideoUUID = res.body.video.uuid liveVideoUUID = live.uuid
await waitJobs(servers) await waitJobs(servers)
@ -130,8 +127,7 @@ describe('Test live', function () {
await testImage(server.url, 'video_short1-preview.webm', video.previewPath) await testImage(server.url, 'video_short1-preview.webm', video.previewPath)
await testImage(server.url, 'video_short1.webm', video.thumbnailPath) await testImage(server.url, 'video_short1.webm', video.thumbnailPath)
const resLive = await getLive(server.url, server.accessToken, liveVideoUUID) const live = await server.liveCommand.getLive({ videoId: liveVideoUUID })
const live: LiveVideo = resLive.body
if (server.url === servers[0].url) { if (server.url === servers[0].url) {
expect(live.rtmpUrl).to.equal('rtmp://' + server.hostname + ':' + servers[0].rtmpPort + '/live') expect(live.rtmpUrl).to.equal('rtmp://' + server.hostname + ':' + servers[0].rtmpPort + '/live')
@ -155,8 +151,8 @@ describe('Test live', function () {
nsfw: true nsfw: true
} }
const res = await createLive(servers[0].url, servers[0].accessToken, attributes) const live = await commands[0].createLive({ fields: attributes })
const videoId = res.body.video.uuid const videoId = live.uuid
await waitJobs(servers) await waitJobs(servers)
@ -182,20 +178,19 @@ describe('Test live', function () {
}) })
it('Should not be able to update a live of another server', async function () { it('Should not be able to update a live of another server', async function () {
await updateLive(servers[1].url, servers[1].accessToken, liveVideoUUID, { saveReplay: false }, HttpStatusCode.FORBIDDEN_403) await commands[1].updateLive({ videoId: liveVideoUUID, fields: { saveReplay: false }, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
}) })
it('Should update the live', async function () { it('Should update the live', async function () {
this.timeout(10000) this.timeout(10000)
await updateLive(servers[0].url, servers[0].accessToken, liveVideoUUID, { saveReplay: false }) await commands[0].updateLive({ videoId: liveVideoUUID, fields: { saveReplay: false } })
await waitJobs(servers) await waitJobs(servers)
}) })
it('Have the live updated', async function () { it('Have the live updated', async function () {
for (const server of servers) { for (const server of servers) {
const res = await getLive(server.url, server.accessToken, liveVideoUUID) const live = await server.liveCommand.getLive({ videoId: liveVideoUUID })
const live: LiveVideo = res.body
if (server.url === servers[0].url) { if (server.url === servers[0].url) {
expect(live.rtmpUrl).to.equal('rtmp://' + server.hostname + ':' + servers[0].rtmpPort + '/live') expect(live.rtmpUrl).to.equal('rtmp://' + server.hostname + ':' + servers[0].rtmpPort + '/live')
@ -219,13 +214,13 @@ describe('Test live', function () {
it('Should have the live deleted', async function () { it('Should have the live deleted', async function () {
for (const server of servers) { for (const server of servers) {
await getVideo(server.url, liveVideoUUID, HttpStatusCode.NOT_FOUND_404) await getVideo(server.url, liveVideoUUID, HttpStatusCode.NOT_FOUND_404)
await getLive(server.url, server.accessToken, liveVideoUUID, HttpStatusCode.NOT_FOUND_404) await server.liveCommand.getLive({ videoId: liveVideoUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
} }
}) })
}) })
describe('Live filters', function () { describe('Live filters', function () {
let command: any let ffmpegCommand: any
let liveVideoId: string let liveVideoId: string
let vodVideoId: string let vodVideoId: string
@ -235,10 +230,10 @@ describe('Test live', function () {
vodVideoId = (await uploadVideoAndGetId({ server: servers[0], videoName: 'vod video' })).uuid vodVideoId = (await uploadVideoAndGetId({ server: servers[0], videoName: 'vod video' })).uuid
const liveOptions = { name: 'live', privacy: VideoPrivacy.PUBLIC, channelId: servers[0].videoChannel.id } const liveOptions = { name: 'live', privacy: VideoPrivacy.PUBLIC, channelId: servers[0].videoChannel.id }
const resLive = await createLive(servers[0].url, servers[0].accessToken, liveOptions) const live = await commands[0].createLive({ fields: liveOptions })
liveVideoId = resLive.body.video.uuid liveVideoId = live.uuid
command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId) ffmpegCommand = await servers[0].liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoId })
await waitUntilLivePublishedOnAllServers(servers, liveVideoId) await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
await waitJobs(servers) await waitJobs(servers)
}) })
@ -262,7 +257,7 @@ describe('Test live', function () {
it('Should display my lives', async function () { it('Should display my lives', async function () {
this.timeout(60000) this.timeout(60000)
await stopFfmpeg(command) await stopFfmpeg(ffmpegCommand)
await waitJobs(servers) await waitJobs(servers)
const res = await getMyVideosWithFilter(servers[0].url, servers[0].accessToken, { isLive: true }) const res = await getMyVideosWithFilter(servers[0].url, servers[0].accessToken, { isLive: true })
@ -302,13 +297,12 @@ describe('Test live', function () {
saveReplay: false saveReplay: false
} }
const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes) const { uuid } = await commands[0].createLive({ fields: liveAttributes })
const uuid = res.body.video.uuid
const resLive = await getLive(servers[0].url, servers[0].accessToken, uuid) const live = await commands[0].getLive({ videoId: uuid })
const resVideo = await getVideo(servers[0].url, uuid) const resVideo = await getVideo(servers[0].url, uuid)
return Object.assign(resVideo.body, resLive.body) as LiveVideo & VideoDetails return Object.assign(resVideo.body as VideoDetails, live)
} }
it('Should not allow a stream without the appropriate path', async function () { it('Should not allow a stream without the appropriate path', async function () {
@ -382,8 +376,8 @@ describe('Test live', function () {
saveReplay saveReplay
} }
const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes) const { uuid } = await commands[0].createLive({ fields: liveAttributes })
return res.body.video.uuid return uuid
} }
async function testVideoResolutions (liveVideoId: string, resolutions: number[]) { async function testVideoResolutions (liveVideoId: string, resolutions: number[]) {
@ -409,7 +403,7 @@ describe('Test live', function () {
for (let i = 0; i < resolutions.length; i++) { for (let i = 0; i < resolutions.length; i++) {
const segmentNum = 3 const segmentNum = 3
const segmentName = `${i}-00000${segmentNum}.ts` const segmentName = `${i}-00000${segmentNum}.ts`
await waitUntilLiveSegmentGeneration(servers[0], video.uuid, i, segmentNum) await commands[0].waitUntilLiveSegmentGeneration({ videoUUID: video.uuid, resolution: i, segment: segmentNum })
const res = await getPlaylist(`${servers[0].url}/static/streaming-playlists/hls/${video.uuid}/${i}.m3u8`) const res = await getPlaylist(`${servers[0].url}/static/streaming-playlists/hls/${video.uuid}/${i}.m3u8`)
const subPlaylist = res.text const subPlaylist = res.text
@ -454,13 +448,13 @@ describe('Test live', function () {
liveVideoId = await createLiveWrapper(false) liveVideoId = await createLiveWrapper(false)
const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId) const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId })
await waitUntilLivePublishedOnAllServers(servers, liveVideoId) await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
await waitJobs(servers) await waitJobs(servers)
await testVideoResolutions(liveVideoId, [ 720 ]) await testVideoResolutions(liveVideoId, [ 720 ])
await stopFfmpeg(command) await stopFfmpeg(ffmpegCommand)
}) })
it('Should enable transcoding with some resolutions', async function () { it('Should enable transcoding with some resolutions', async function () {
@ -470,13 +464,13 @@ describe('Test live', function () {
await updateConf(resolutions) await updateConf(resolutions)
liveVideoId = await createLiveWrapper(false) liveVideoId = await createLiveWrapper(false)
const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId) const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId })
await waitUntilLivePublishedOnAllServers(servers, liveVideoId) await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
await waitJobs(servers) await waitJobs(servers)
await testVideoResolutions(liveVideoId, resolutions) await testVideoResolutions(liveVideoId, resolutions)
await stopFfmpeg(command) await stopFfmpeg(ffmpegCommand)
}) })
it('Should enable transcoding with some resolutions and correctly save them', async function () { it('Should enable transcoding with some resolutions and correctly save them', async function () {
@ -487,14 +481,14 @@ describe('Test live', function () {
await updateConf(resolutions) await updateConf(resolutions)
liveVideoId = await createLiveWrapper(true) liveVideoId = await createLiveWrapper(true)
const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId, 'video_short2.webm') const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
await waitUntilLivePublishedOnAllServers(servers, liveVideoId) await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
await waitJobs(servers) await waitJobs(servers)
await testVideoResolutions(liveVideoId, resolutions) await testVideoResolutions(liveVideoId, resolutions)
await stopFfmpeg(command) await stopFfmpeg(ffmpegCommand)
await waitUntilLiveEnded(servers[0].url, servers[0].accessToken, liveVideoId) await commands[0].waitUntilLiveEnded({ videoId: liveVideoId })
await waitJobs(servers) await waitJobs(servers)
@ -565,8 +559,8 @@ describe('Test live', function () {
saveReplay saveReplay
} }
const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes) const { uuid } = await commands[0].createLive({ fields: liveAttributes })
return res.body.video.uuid return uuid
} }
before(async function () { before(async function () {
@ -576,17 +570,17 @@ describe('Test live', function () {
liveVideoReplayId = await createLiveWrapper(true) liveVideoReplayId = await createLiveWrapper(true)
await Promise.all([ await Promise.all([
sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId), commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId }),
sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoReplayId) commands[0].sendRTMPStreamInVideo({ videoId: liveVideoReplayId })
]) ])
await Promise.all([ await Promise.all([
waitUntilLivePublished(servers[0].url, servers[0].accessToken, liveVideoId), commands[0].waitUntilLivePublished({ videoId: liveVideoId }),
waitUntilLivePublished(servers[0].url, servers[0].accessToken, liveVideoReplayId) commands[0].waitUntilLivePublished({ videoId: liveVideoReplayId })
]) ])
await waitUntilLiveSegmentGeneration(servers[0], liveVideoId, 0, 2) await commands[0].waitUntilLiveSegmentGeneration({ videoUUID: liveVideoId, resolution: 0, segment: 2 })
await waitUntilLiveSegmentGeneration(servers[0], liveVideoReplayId, 0, 2) await commands[0].waitUntilLiveSegmentGeneration({ videoUUID: liveVideoReplayId, resolution: 0, segment: 2 })
await killallServers([ servers[0] ]) await killallServers([ servers[0] ])
await reRunServer(servers[0]) await reRunServer(servers[0])
@ -597,13 +591,13 @@ describe('Test live', function () {
it('Should cleanup lives', async function () { it('Should cleanup lives', async function () {
this.timeout(60000) this.timeout(60000)
await waitUntilLiveEnded(servers[0].url, servers[0].accessToken, liveVideoId) await commands[0].waitUntilLiveEnded({ videoId: liveVideoId })
}) })
it('Should save a live replay', async function () { it('Should save a live replay', async function () {
this.timeout(120000) this.timeout(120000)
await waitUntilLivePublished(servers[0].url, servers[0].accessToken, liveVideoReplayId) await commands[0].waitUntilLivePublished({ videoId: liveVideoReplayId })
}) })
}) })

View File

@ -2,23 +2,20 @@
import 'mocha' import 'mocha'
import * as chai from 'chai' import * as chai from 'chai'
import { VideoPrivacy } from '@shared/models'
import { import {
cleanupTests, cleanupTests,
createLive, createVideoCaption,
flushAndRunServer, flushAndRunServer,
immutableAssign, immutableAssign,
SearchCommand, SearchCommand,
sendRTMPStreamInVideo,
ServerInfo, ServerInfo,
setAccessTokensToServers, setAccessTokensToServers,
setDefaultVideoChannel, setDefaultVideoChannel,
stopFfmpeg, stopFfmpeg,
uploadVideo, uploadVideo,
wait, wait
waitUntilLivePublished } from '@shared/extra-utils'
} from '../../../../shared/extra-utils' import { VideoPrivacy } from '@shared/models'
import { createVideoCaption } from '../../../../shared/extra-utils/videos/video-captions'
const expect = chai.expect const expect = chai.expect
@ -502,12 +499,13 @@ describe('Test videos search', function () {
} }
{ {
const liveOptions = { name: 'live', privacy: VideoPrivacy.PUBLIC, channelId: server.videoChannel.id } const liveCommand = server.liveCommand
const resLive = await createLive(server.url, server.accessToken, liveOptions)
const liveVideoId = resLive.body.video.uuid
const ffmpegCommand = await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId) const liveAttributes = { name: 'live', privacy: VideoPrivacy.PUBLIC, channelId: server.videoChannel.id }
await waitUntilLivePublished(server.url, server.accessToken, liveVideoId) const live = await liveCommand.createLive({ fields: liveAttributes })
const ffmpegCommand = await liveCommand.sendRTMPStreamInVideo({ videoId: live.id })
await liveCommand.waitUntilLivePublished({ videoId: live.id })
const body = await command.advancedVideoSearch({ search: { isLive: true } }) const body = await command.advancedVideoSearch({ search: { isLive: true } })

View File

@ -7,7 +7,6 @@ import {
acceptChangeOwnership, acceptChangeOwnership,
changeVideoOwnership, changeVideoOwnership,
cleanupTests, cleanupTests,
createLive,
createUser, createUser,
doubleFollow, doubleFollow,
flushAndRunMultipleServers, flushAndRunMultipleServers,
@ -112,9 +111,9 @@ describe('Test video change ownership - nominal', function () {
{ {
const attributes = { name: 'live', channelId: firstUserChannelId, privacy: VideoPrivacy.PUBLIC } const attributes = { name: 'live', channelId: firstUserChannelId, privacy: VideoPrivacy.PUBLIC }
const res = await createLive(servers[0].url, firstUserAccessToken, attributes) const video = await servers[0].liveCommand.createLive({ token: firstUserAccessToken, fields: attributes })
liveId = res.body.video.id liveId = video.id
} }
await doubleFollow(servers[0], servers[1]) await doubleFollow(servers[0], servers[1])

View File

@ -7,7 +7,6 @@ import {
addVideoCommentThread, addVideoCommentThread,
addVideoInPlaylist, addVideoInPlaylist,
blockUser, blockUser,
createLive,
createUser, createUser,
createVideoPlaylist, createVideoPlaylist,
deleteVideoComment, deleteVideoComment,
@ -96,7 +95,7 @@ describe('Test plugin action hooks', function () {
channelId: servers[0].videoChannel.id channelId: servers[0].videoChannel.id
} }
await createLive(servers[0].url, servers[0].accessToken, attributes) await servers[0].liveCommand.createLive({ fields: attributes })
await checkHook('action:api.live-video.created') await checkHook('action:api.live-video.created')
}) })

View File

@ -7,7 +7,6 @@ import {
addVideoCommentReply, addVideoCommentReply,
addVideoCommentThread, addVideoCommentThread,
cleanupTests, cleanupTests,
createLive,
createVideoPlaylist, createVideoPlaylist,
doubleFollow, doubleFollow,
flushAndRunMultipleServers, flushAndRunMultipleServers,
@ -156,7 +155,7 @@ describe('Test plugin filter hooks', function () {
channelId: servers[0].videoChannel.id channelId: servers[0].videoChannel.id
} }
await createLive(servers[0].url, servers[0].accessToken, attributes, HttpStatusCode.FORBIDDEN_403) await servers[0].liveCommand.createLive({ fields: attributes, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
}) })
it('Should run filter:api.video.pre-import-url.accept.result', async function () { it('Should run filter:api.video.pre-import-url.accept.result', async function () {

View File

@ -7,18 +7,15 @@ import { getAudioStream, getVideoFileFPS, getVideoStreamFromFile } from '@server
import { import {
buildServerDirectory, buildServerDirectory,
cleanupTests, cleanupTests,
createLive,
flushAndRunServer, flushAndRunServer,
getVideo, getVideo,
PluginsCommand, PluginsCommand,
sendRTMPStreamInVideo,
ServerInfo, ServerInfo,
setAccessTokensToServers, setAccessTokensToServers,
setDefaultVideoChannel, setDefaultVideoChannel,
testFfmpegStreamError, testFfmpegStreamError,
uploadVideoAndGetId, uploadVideoAndGetId,
waitJobs, waitJobs
waitUntilLivePublished
} from '@shared/extra-utils' } from '@shared/extra-utils'
import { VideoDetails, VideoPrivacy } from '@shared/models' import { VideoDetails, VideoPrivacy } from '@shared/models'
@ -29,8 +26,9 @@ async function createLiveWrapper (server: ServerInfo) {
privacy: VideoPrivacy.PUBLIC privacy: VideoPrivacy.PUBLIC
} }
const res = await createLive(server.url, server.accessToken, liveAttributes) const { uuid } = await server.liveCommand.createLive({ fields: liveAttributes })
return res.body.video.uuid
return uuid
} }
function updateConf (server: ServerInfo, vodProfile: string, liveProfile: string) { function updateConf (server: ServerInfo, vodProfile: string, liveProfile: string) {
@ -171,8 +169,8 @@ describe('Test transcoding plugins', function () {
const liveVideoId = await createLiveWrapper(server) const liveVideoId = await createLiveWrapper(server)
await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm') await server.liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
await waitUntilLivePublished(server.url, server.accessToken, liveVideoId) await server.liveCommand.waitUntilLivePublished({ videoId: liveVideoId })
await waitJobs([ server ]) await waitJobs([ server ])
await checkLiveFPS(liveVideoId, 'above', 20) await checkLiveFPS(liveVideoId, 'above', 20)
@ -185,8 +183,8 @@ describe('Test transcoding plugins', function () {
const liveVideoId = await createLiveWrapper(server) const liveVideoId = await createLiveWrapper(server)
await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm') await server.liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
await waitUntilLivePublished(server.url, server.accessToken, liveVideoId) await server.liveCommand.waitUntilLivePublished({ videoId: liveVideoId })
await waitJobs([ server ]) await waitJobs([ server ])
await checkLiveFPS(liveVideoId, 'below', 12) await checkLiveFPS(liveVideoId, 'below', 12)
@ -199,8 +197,8 @@ describe('Test transcoding plugins', function () {
const liveVideoId = await createLiveWrapper(server) const liveVideoId = await createLiveWrapper(server)
await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm') await server.liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
await waitUntilLivePublished(server.url, server.accessToken, liveVideoId) await server.liveCommand.waitUntilLivePublished({ videoId: liveVideoId })
await waitJobs([ server ]) await waitJobs([ server ])
await checkLiveFPS(liveVideoId, 'below', 6) await checkLiveFPS(liveVideoId, 'below', 6)
@ -213,7 +211,7 @@ describe('Test transcoding plugins', function () {
const liveVideoId = await createLiveWrapper(server) const liveVideoId = await createLiveWrapper(server)
const command = await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm') const command = await server.liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
await testFfmpegStreamError(command, true) await testFfmpegStreamError(command, true)
}) })
@ -262,8 +260,8 @@ describe('Test transcoding plugins', function () {
const liveVideoId = await createLiveWrapper(server) const liveVideoId = await createLiveWrapper(server)
await sendRTMPStreamInVideo(server.url, server.accessToken, liveVideoId, 'video_short2.webm') await server.liveCommand.sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
await waitUntilLivePublished(server.url, server.accessToken, liveVideoId) await server.liveCommand.waitUntilLivePublished({ videoId: liveVideoId })
await waitJobs([ server ]) await waitJobs([ server ])
const playlistUrl = `${server.url}/static/streaming-playlists/hls/${liveVideoId}/0.m3u8` const playlistUrl = `${server.url}/static/streaming-playlists/hls/${liveVideoId}/0.m3u8`

View File

@ -7,21 +7,9 @@ export * from './miscs'
export * from './mock-servers' export * from './mock-servers'
export * from './moderation' export * from './moderation'
export * from './overviews' export * from './overviews'
export * from './requests'
export * from './search' export * from './search'
export * from './server' export * from './server'
export * from './socket' export * from './socket'
export * from './users' export * from './users'
export * from './videos'
export * from './requests/check-api-params'
export * from './requests/requests'
export * from './videos/live'
export * from './videos/services'
export * from './videos/video-blacklist'
export * from './videos/video-captions'
export * from './videos/video-change-ownership'
export * from './videos/video-channels'
export * from './videos/video-comments'
export * from './videos/video-playlists'
export * from './videos/video-streaming-playlists'
export * from './videos/videos'

View File

@ -0,0 +1,3 @@
// Don't include activitypub that import stuff from server
export * from './check-api-params'
export * from './requests'

View File

@ -18,6 +18,7 @@ import { makeGetRequest } from '../requests/requests'
import { SearchCommand } from '../search' import { SearchCommand } from '../search'
import { SocketIOCommand } from '../socket' import { SocketIOCommand } from '../socket'
import { AccountsCommand, BlocklistCommand, SubscriptionsCommand } from '../users' import { AccountsCommand, BlocklistCommand, SubscriptionsCommand } from '../users'
import { LiveCommand } from '../videos'
import { ConfigCommand } from './config-command' import { ConfigCommand } from './config-command'
import { ContactFormCommand } from './contact-form-command' import { ContactFormCommand } from './contact-form-command'
import { DebugCommand } from './debug-command' import { DebugCommand } from './debug-command'
@ -99,6 +100,7 @@ interface ServerInfo {
accountsCommand?: AccountsCommand accountsCommand?: AccountsCommand
blocklistCommand?: BlocklistCommand blocklistCommand?: BlocklistCommand
subscriptionsCommand?: SubscriptionsCommand subscriptionsCommand?: SubscriptionsCommand
liveCommand?: LiveCommand
} }
function parallelTests () { function parallelTests () {
@ -324,6 +326,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = []
server.accountsCommand = new AccountsCommand(server) server.accountsCommand = new AccountsCommand(server)
server.blocklistCommand = new BlocklistCommand(server) server.blocklistCommand = new BlocklistCommand(server)
server.subscriptionsCommand = new SubscriptionsCommand(server) server.subscriptionsCommand = new SubscriptionsCommand(server)
server.liveCommand = new LiveCommand(server)
res(server) res(server)
}) })

View File

@ -1,5 +1,5 @@
import { HttpStatusCode } from '@shared/core-utils' import { HttpStatusCode } from '@shared/core-utils'
import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest, unwrapBody, unwrapText } from '../requests/requests' import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest, makeUploadRequest, unwrapBody, unwrapText } from '../requests/requests'
import { ServerInfo } from '../server/servers' import { ServerInfo } from '../server/servers'
export interface OverrideCommandOptions { export interface OverrideCommandOptions {
@ -86,6 +86,36 @@ abstract class AbstractCommand {
}) })
} }
protected postUploadRequest (options: CommonCommandOptions & {
fields?: { [ fieldName: string ]: any }
attaches?: any
}) {
const { fields, attaches } = options
return makeUploadRequest({
...this.buildCommonRequestOptions(options),
method: 'POST',
fields,
attaches
})
}
protected putUploadRequest (options: CommonCommandOptions & {
fields?: { [ fieldName: string ]: any }
attaches?: any
}) {
const { fields, attaches } = options
return makeUploadRequest({
...this.buildCommonRequestOptions(options),
method: 'PUT',
fields,
attaches
})
}
private buildCommonRequestOptions (options: CommonCommandOptions) { private buildCommonRequestOptions (options: CommonCommandOptions) {
const { token, expectedStatus, defaultExpectedStatus, path } = options const { token, expectedStatus, defaultExpectedStatus, path } = options

View File

@ -1,7 +1,6 @@
export * from './accounts-command' export * from './accounts-command'
export * from './accounts' export * from './accounts'
export * from './blocklist-command' export * from './blocklist-command'
export * from './login' export * from './login'
export * from './user-notifications' export * from './user-notifications'
export * from './subscriptions-command' export * from './subscriptions-command'

View File

@ -0,0 +1,13 @@
export * from './live-command'
export * from './live'
export * from './services'
export * from './video-blacklist'
export * from './video-captions'
export * from './video-change-ownership'
export * from './video-channels'
export * from './video-comments'
export * from './video-history'
export * from './video-imports'
export * from './video-playlists'
export * from './video-streaming-playlists'
export * from './videos'

View File

@ -0,0 +1,156 @@
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import { readdir } from 'fs-extra'
import { omit } from 'lodash'
import { join } from 'path'
import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, VideoCreateResult, VideoDetails, VideoState } from '@shared/models'
import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes'
import { buildServerDirectory, wait } from '../miscs/miscs'
import { unwrapBody } from '../requests'
import { waitUntilLog } from '../server/servers'
import { AbstractCommand, OverrideCommandOptions } from '../shared'
import { sendRTMPStream, testFfmpegStreamError } from './live'
import { getVideoWithToken } from './videos'
export class LiveCommand extends AbstractCommand {
getLive (options: OverrideCommandOptions & {
videoId: number | string
}) {
const path = '/api/v1/videos/live'
return this.getRequestBody<LiveVideo>({
...options,
path: path + '/' + options.videoId,
defaultExpectedStatus: HttpStatusCode.OK_200
})
}
updateLive (options: OverrideCommandOptions & {
videoId: number | string
fields: LiveVideoUpdate
}) {
const { videoId, fields } = options
const path = '/api/v1/videos/live'
return this.putBodyRequest({
...options,
path: path + '/' + videoId,
fields,
defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
})
}
async createLive (options: OverrideCommandOptions & {
fields: LiveVideoCreate
}) {
const { fields } = options
const path = '/api/v1/videos/live'
const attaches: any = {}
if (fields.thumbnailfile) attaches.thumbnailfile = fields.thumbnailfile
if (fields.previewfile) attaches.previewfile = fields.previewfile
const body = await unwrapBody<{ video: VideoCreateResult }>(this.postUploadRequest({
...options,
path,
attaches,
fields: omit(fields, 'thumbnailfile', 'previewfile'),
defaultExpectedStatus: HttpStatusCode.OK_200
}))
return body.video
}
async sendRTMPStreamInVideo (options: OverrideCommandOptions & {
videoId: number | string
fixtureName?: string
}) {
const { videoId, fixtureName } = options
const videoLive = await this.getLive({ videoId })
return sendRTMPStream(videoLive.rtmpUrl, videoLive.streamKey, fixtureName)
}
async runAndTestFfmpegStreamError (options: OverrideCommandOptions & {
videoId: number | string
shouldHaveError: boolean
}) {
const command = await this.sendRTMPStreamInVideo(options)
return testFfmpegStreamError(command, options.shouldHaveError)
}
waitUntilLivePublished (options: OverrideCommandOptions & {
videoId: number | string
}) {
const { videoId } = options
return this.waitUntilLiveState({ videoId, state: VideoState.PUBLISHED })
}
waitUntilLiveWaiting (options: OverrideCommandOptions & {
videoId: number | string
}) {
const { videoId } = options
return this.waitUntilLiveState({ videoId, state: VideoState.WAITING_FOR_LIVE })
}
waitUntilLiveEnded (options: OverrideCommandOptions & {
videoId: number | string
}) {
const { videoId } = options
return this.waitUntilLiveState({ videoId, state: VideoState.LIVE_ENDED })
}
waitUntilLiveSegmentGeneration (options: OverrideCommandOptions & {
videoUUID: string
resolution: number
segment: number
}) {
const { resolution, segment, videoUUID } = options
const segmentName = `${resolution}-00000${segment}.ts`
return waitUntilLog(this.server, `${videoUUID}/${segmentName}`, 2, false)
}
async waitUntilLiveSaved (options: OverrideCommandOptions & {
videoId: number | string
}) {
let video: VideoDetails
do {
const res = await getVideoWithToken(this.server.url, options.token ?? this.server.accessToken, options.videoId)
video = res.body
await wait(500)
} while (video.isLive === true && video.state.id !== VideoState.PUBLISHED)
}
async getPlaylistsCount (options: OverrideCommandOptions & {
videoUUID: string
}) {
const basePath = buildServerDirectory(this.server, 'streaming-playlists')
const hlsPath = join(basePath, 'hls', options.videoUUID)
const files = await readdir(hlsPath)
return files.filter(f => f.endsWith('.m3u8')).length
}
private async waitUntilLiveState (options: OverrideCommandOptions & {
videoId: number | string
state: VideoState
}) {
let video: VideoDetails
do {
const res = await getVideoWithToken(this.server.url, options.token ?? this.server.accessToken, options.videoId)
video = res.body
await wait(500)
} while (video.state.id !== options.state)
}
}

View File

@ -3,69 +3,9 @@
import { expect } from 'chai' import { expect } from 'chai'
import * as ffmpeg from 'fluent-ffmpeg' import * as ffmpeg from 'fluent-ffmpeg'
import { pathExists, readdir } from 'fs-extra' import { pathExists, readdir } from 'fs-extra'
import { omit } from 'lodash'
import { join } from 'path' import { join } from 'path'
import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, VideoDetails, VideoState } from '@shared/models'
import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
import { buildAbsoluteFixturePath, buildServerDirectory, wait } from '../miscs/miscs' import { buildAbsoluteFixturePath, buildServerDirectory, wait } from '../miscs/miscs'
import { makeGetRequest, makePutBodyRequest, makeUploadRequest } from '../requests/requests' import { ServerInfo } from '../server/servers'
import { ServerInfo, waitUntilLog } from '../server/servers'
import { getVideoWithToken } from './videos'
function getLive (url: string, token: string, videoId: number | string, statusCodeExpected = HttpStatusCode.OK_200) {
const path = '/api/v1/videos/live'
return makeGetRequest({
url,
token,
path: path + '/' + videoId,
statusCodeExpected
})
}
function updateLive (
url: string,
token: string,
videoId: number | string,
fields: LiveVideoUpdate,
statusCodeExpected = HttpStatusCode.NO_CONTENT_204
) {
const path = '/api/v1/videos/live'
return makePutBodyRequest({
url,
token,
path: path + '/' + videoId,
fields,
statusCodeExpected
})
}
function createLive (url: string, token: string, fields: LiveVideoCreate, statusCodeExpected = HttpStatusCode.OK_200) {
const path = '/api/v1/videos/live'
const attaches: any = {}
if (fields.thumbnailfile) attaches.thumbnailfile = fields.thumbnailfile
if (fields.previewfile) attaches.previewfile = fields.previewfile
const updatedFields = omit(fields, 'thumbnailfile', 'previewfile')
return makeUploadRequest({
url,
path,
token,
attaches,
fields: updatedFields,
statusCodeExpected
})
}
async function sendRTMPStreamInVideo (url: string, token: string, videoId: number | string, fixtureName?: string) {
const res = await getLive(url, token, videoId)
const videoLive = res.body as LiveVideo
return sendRTMPStream(videoLive.rtmpUrl, videoLive.streamKey, fixtureName)
}
function sendRTMPStream (rtmpBaseUrl: string, streamKey: string, fixtureName = 'video_short.mp4') { function sendRTMPStream (rtmpBaseUrl: string, streamKey: string, fixtureName = 'video_short.mp4') {
const fixture = buildAbsoluteFixturePath(fixtureName) const fixture = buildAbsoluteFixturePath(fixtureName)
@ -109,12 +49,6 @@ function waitFfmpegUntilError (command: ffmpeg.FfmpegCommand, successAfterMS = 1
}) })
} }
async function runAndTestFfmpegStreamError (url: string, token: string, videoId: number | string, shouldHaveError: boolean) {
const command = await sendRTMPStreamInVideo(url, token, videoId)
return testFfmpegStreamError(command, shouldHaveError)
}
async function testFfmpegStreamError (command: ffmpeg.FfmpegCommand, shouldHaveError: boolean) { async function testFfmpegStreamError (command: ffmpeg.FfmpegCommand, shouldHaveError: boolean) {
let error: Error let error: Error
@ -136,48 +70,9 @@ async function stopFfmpeg (command: ffmpeg.FfmpegCommand) {
await wait(500) await wait(500)
} }
function waitUntilLivePublished (url: string, token: string, videoId: number | string) {
return waitUntilLiveState(url, token, videoId, VideoState.PUBLISHED)
}
function waitUntilLiveWaiting (url: string, token: string, videoId: number | string) {
return waitUntilLiveState(url, token, videoId, VideoState.WAITING_FOR_LIVE)
}
function waitUntilLiveEnded (url: string, token: string, videoId: number | string) {
return waitUntilLiveState(url, token, videoId, VideoState.LIVE_ENDED)
}
function waitUntilLiveSegmentGeneration (server: ServerInfo, videoUUID: string, resolutionNum: number, segmentNum: number) {
const segmentName = `${resolutionNum}-00000${segmentNum}.ts`
return waitUntilLog(server, `${videoUUID}/${segmentName}`, 2, false)
}
async function waitUntilLiveState (url: string, token: string, videoId: number | string, state: VideoState) {
let video: VideoDetails
do {
const res = await getVideoWithToken(url, token, videoId)
video = res.body
await wait(500)
} while (video.state.id !== state)
}
async function waitUntilLiveSaved (url: string, token: string, videoId: number | string) {
let video: VideoDetails
do {
const res = await getVideoWithToken(url, token, videoId)
video = res.body
await wait(500)
} while (video.isLive === true && video.state.id !== VideoState.PUBLISHED)
}
async function waitUntilLivePublishedOnAllServers (servers: ServerInfo[], videoId: string) { async function waitUntilLivePublishedOnAllServers (servers: ServerInfo[], videoId: string) {
for (const server of servers) { for (const server of servers) {
await waitUntilLivePublished(server.url, server.accessToken, videoId) await server.liveCommand.waitUntilLivePublished({ videoId })
} }
} }
@ -206,33 +101,11 @@ async function checkLiveCleanup (server: ServerInfo, videoUUID: string, resoluti
expect(files).to.contain('segments-sha256.json') expect(files).to.contain('segments-sha256.json')
} }
async function getPlaylistsCount (server: ServerInfo, videoUUID: string) {
const basePath = buildServerDirectory(server, 'streaming-playlists')
const hlsPath = join(basePath, 'hls', videoUUID)
const files = await readdir(hlsPath)
return files.filter(f => f.endsWith('.m3u8')).length
}
// ---------------------------------------------------------------------------
export { export {
getLive,
getPlaylistsCount,
waitUntilLiveSaved,
waitUntilLivePublished,
updateLive,
createLive,
runAndTestFfmpegStreamError,
checkLiveCleanup,
waitUntilLiveSegmentGeneration,
stopFfmpeg,
waitUntilLiveWaiting,
sendRTMPStreamInVideo,
waitUntilLiveEnded,
waitFfmpegUntilError,
waitUntilLivePublishedOnAllServers,
sendRTMPStream, sendRTMPStream,
testFfmpegStreamError waitFfmpegUntilError,
testFfmpegStreamError,
stopFfmpeg,
waitUntilLivePublishedOnAllServers,
checkLiveCleanup
} }