448 lines
15 KiB
TypeScript
448 lines
15 KiB
TypeScript
import { expect } from 'chai'
|
|
import { expectStartWith } from '@server/tests/shared'
|
|
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
|
import { areMockObjectStorageTestsDisabled, getAllFiles } from '@shared/core-utils'
|
|
import { HttpStatusCode } from '@shared/models'
|
|
import {
|
|
cleanupTests,
|
|
createMultipleServers,
|
|
doubleFollow,
|
|
makeGetRequest,
|
|
makeRawRequest,
|
|
ObjectStorageCommand,
|
|
PeerTubeServer,
|
|
setAccessTokensToServers,
|
|
setDefaultAccountAvatar,
|
|
setDefaultVideoChannel,
|
|
waitJobs
|
|
} from '@shared/server-commands'
|
|
|
|
describe('Test a video file replacement', function () {
|
|
let servers: PeerTubeServer[] = []
|
|
|
|
let replaceDate: Date
|
|
let userToken: string
|
|
let uuid: string
|
|
|
|
before(async function () {
|
|
this.timeout(50000)
|
|
|
|
servers = await createMultipleServers(2)
|
|
|
|
// Get the access tokens
|
|
await setAccessTokensToServers(servers)
|
|
await setDefaultVideoChannel(servers)
|
|
await setDefaultAccountAvatar(servers)
|
|
|
|
await servers[0].config.enableFileUpdate()
|
|
|
|
userToken = await servers[0].users.generateUserAndToken('user1')
|
|
|
|
// Server 1 and server 2 follow each other
|
|
await doubleFollow(servers[0], servers[1])
|
|
})
|
|
|
|
describe('Getting latest video source', () => {
|
|
const fixture = 'video_short.webm'
|
|
const uuids: string[] = []
|
|
|
|
it('Should get the source filename with legacy upload', async function () {
|
|
this.timeout(30000)
|
|
|
|
const { uuid } = await servers[0].videos.upload({ attributes: { name: 'my video', fixture }, mode: 'legacy' })
|
|
uuids.push(uuid)
|
|
|
|
const source = await servers[0].videos.getSource({ id: uuid })
|
|
expect(source.filename).to.equal(fixture)
|
|
})
|
|
|
|
it('Should get the source filename with resumable upload', async function () {
|
|
this.timeout(30000)
|
|
|
|
const { uuid } = await servers[0].videos.upload({ attributes: { name: 'my video', fixture }, mode: 'resumable' })
|
|
uuids.push(uuid)
|
|
|
|
const source = await servers[0].videos.getSource({ id: uuid })
|
|
expect(source.filename).to.equal(fixture)
|
|
})
|
|
|
|
after(async function () {
|
|
this.timeout(60000)
|
|
|
|
for (const uuid of uuids) {
|
|
await servers[0].videos.remove({ id: uuid })
|
|
}
|
|
|
|
await waitJobs(servers)
|
|
})
|
|
})
|
|
|
|
describe('Updating video source', function () {
|
|
|
|
describe('Filesystem', function () {
|
|
|
|
it('Should replace a video file with transcoding disabled', async function () {
|
|
this.timeout(120000)
|
|
|
|
await servers[0].config.disableTranscoding()
|
|
|
|
const { uuid } = await servers[0].videos.quickUpload({ name: 'fs without transcoding', fixture: 'video_short_720p.mp4' })
|
|
await waitJobs(servers)
|
|
|
|
for (const server of servers) {
|
|
const video = await server.videos.get({ id: uuid })
|
|
|
|
const files = getAllFiles(video)
|
|
expect(files).to.have.lengthOf(1)
|
|
expect(files[0].resolution.id).to.equal(720)
|
|
}
|
|
|
|
await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' })
|
|
await waitJobs(servers)
|
|
|
|
for (const server of servers) {
|
|
const video = await server.videos.get({ id: uuid })
|
|
|
|
const files = getAllFiles(video)
|
|
expect(files).to.have.lengthOf(1)
|
|
expect(files[0].resolution.id).to.equal(360)
|
|
}
|
|
})
|
|
|
|
it('Should replace a video file with transcoding enabled', async function () {
|
|
this.timeout(120000)
|
|
|
|
const previousPaths: string[] = []
|
|
|
|
await servers[0].config.enableTranscoding(true, true, true)
|
|
|
|
const { uuid: videoUUID } = await servers[0].videos.quickUpload({ name: 'fs with transcoding', fixture: 'video_short_720p.mp4' })
|
|
uuid = videoUUID
|
|
|
|
await waitJobs(servers)
|
|
|
|
for (const server of servers) {
|
|
const video = await server.videos.get({ id: uuid })
|
|
expect(video.inputFileUpdatedAt).to.be.null
|
|
|
|
const files = getAllFiles(video)
|
|
expect(files).to.have.lengthOf(6 * 2)
|
|
|
|
// Grab old paths to ensure we'll regenerate
|
|
|
|
previousPaths.push(video.previewPath)
|
|
previousPaths.push(video.thumbnailPath)
|
|
|
|
for (const file of files) {
|
|
previousPaths.push(file.fileUrl)
|
|
previousPaths.push(file.torrentUrl)
|
|
previousPaths.push(file.metadataUrl)
|
|
|
|
const metadata = await server.videos.getFileMetadata({ url: file.metadataUrl })
|
|
previousPaths.push(JSON.stringify(metadata))
|
|
}
|
|
|
|
const { storyboards } = await server.storyboard.list({ id: uuid })
|
|
for (const s of storyboards) {
|
|
previousPaths.push(s.storyboardPath)
|
|
}
|
|
}
|
|
|
|
replaceDate = new Date()
|
|
|
|
await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' })
|
|
await waitJobs(servers)
|
|
|
|
for (const server of servers) {
|
|
const video = await server.videos.get({ id: uuid })
|
|
|
|
expect(video.inputFileUpdatedAt).to.not.be.null
|
|
expect(new Date(video.inputFileUpdatedAt)).to.be.above(replaceDate)
|
|
|
|
const files = getAllFiles(video)
|
|
expect(files).to.have.lengthOf(4 * 2)
|
|
|
|
expect(previousPaths).to.not.include(video.previewPath)
|
|
expect(previousPaths).to.not.include(video.thumbnailPath)
|
|
|
|
await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 })
|
|
await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 })
|
|
|
|
for (const file of files) {
|
|
expect(previousPaths).to.not.include(file.fileUrl)
|
|
expect(previousPaths).to.not.include(file.torrentUrl)
|
|
expect(previousPaths).to.not.include(file.metadataUrl)
|
|
|
|
await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 })
|
|
await makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 })
|
|
|
|
const metadata = await server.videos.getFileMetadata({ url: file.metadataUrl })
|
|
expect(previousPaths).to.not.include(JSON.stringify(metadata))
|
|
}
|
|
|
|
const { storyboards } = await server.storyboard.list({ id: uuid })
|
|
for (const s of storyboards) {
|
|
expect(previousPaths).to.not.include(s.storyboardPath)
|
|
|
|
await makeGetRequest({ url: server.url, path: s.storyboardPath, expectedStatus: HttpStatusCode.OK_200 })
|
|
}
|
|
}
|
|
|
|
await servers[0].config.enableMinimumTranscoding()
|
|
})
|
|
|
|
it('Should have cleaned up old files', async function () {
|
|
{
|
|
const count = await servers[0].servers.countFiles('storyboards')
|
|
expect(count).to.equal(2)
|
|
}
|
|
|
|
{
|
|
const count = await servers[0].servers.countFiles('web-videos')
|
|
expect(count).to.equal(5 + 1) // +1 for private directory
|
|
}
|
|
|
|
{
|
|
const count = await servers[0].servers.countFiles('streaming-playlists/hls')
|
|
expect(count).to.equal(1 + 1) // +1 for private directory
|
|
}
|
|
|
|
{
|
|
const count = await servers[0].servers.countFiles('torrents')
|
|
expect(count).to.equal(9)
|
|
}
|
|
})
|
|
|
|
it('Should have the correct source input', async function () {
|
|
const source = await servers[0].videos.getSource({ id: uuid })
|
|
|
|
expect(source.filename).to.equal('video_short_360p.mp4')
|
|
expect(new Date(source.createdAt)).to.be.above(replaceDate)
|
|
})
|
|
|
|
it('Should not have regenerated miniatures that were previously uploaded', async function () {
|
|
this.timeout(120000)
|
|
|
|
const { uuid } = await servers[0].videos.upload({
|
|
attributes: {
|
|
name: 'custom miniatures',
|
|
thumbnailfile: 'custom-thumbnail.jpg',
|
|
previewfile: 'custom-preview.jpg'
|
|
}
|
|
})
|
|
|
|
await waitJobs(servers)
|
|
|
|
const previousPaths: string[] = []
|
|
|
|
for (const server of servers) {
|
|
const video = await server.videos.get({ id: uuid })
|
|
|
|
previousPaths.push(video.previewPath)
|
|
previousPaths.push(video.thumbnailPath)
|
|
|
|
await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 })
|
|
await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 })
|
|
}
|
|
|
|
await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' })
|
|
await waitJobs(servers)
|
|
|
|
for (const server of servers) {
|
|
const video = await server.videos.get({ id: uuid })
|
|
|
|
expect(previousPaths).to.include(video.previewPath)
|
|
expect(previousPaths).to.include(video.thumbnailPath)
|
|
|
|
await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 })
|
|
await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 })
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('Autoblacklist', function () {
|
|
|
|
function updateAutoBlacklist (enabled: boolean) {
|
|
return servers[0].config.updateExistingSubConfig({
|
|
newConfig: {
|
|
autoBlacklist: {
|
|
videos: {
|
|
ofUsers: {
|
|
enabled
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
async function expectBlacklist (uuid: string, value: boolean) {
|
|
const video = await servers[0].videos.getWithToken({ id: uuid })
|
|
|
|
expect(video.blacklisted).to.equal(value)
|
|
}
|
|
|
|
before(async function () {
|
|
await updateAutoBlacklist(true)
|
|
})
|
|
|
|
it('Should auto blacklist an unblacklisted video after file replacement', async function () {
|
|
this.timeout(120000)
|
|
|
|
const { uuid } = await servers[0].videos.quickUpload({ token: userToken, name: 'user video' })
|
|
await waitJobs(servers)
|
|
await expectBlacklist(uuid, true)
|
|
|
|
await servers[0].blacklist.remove({ videoId: uuid })
|
|
await expectBlacklist(uuid, false)
|
|
|
|
await servers[0].videos.replaceSourceFile({ videoId: uuid, token: userToken, fixture: 'video_short_360p.mp4' })
|
|
await waitJobs(servers)
|
|
|
|
await expectBlacklist(uuid, true)
|
|
})
|
|
|
|
it('Should auto blacklist an already blacklisted video after file replacement', async function () {
|
|
this.timeout(120000)
|
|
|
|
const { uuid } = await servers[0].videos.quickUpload({ token: userToken, name: 'user video' })
|
|
await waitJobs(servers)
|
|
await expectBlacklist(uuid, true)
|
|
|
|
await servers[0].videos.replaceSourceFile({ videoId: uuid, token: userToken, fixture: 'video_short_360p.mp4' })
|
|
await waitJobs(servers)
|
|
|
|
await expectBlacklist(uuid, true)
|
|
})
|
|
|
|
it('Should not auto blacklist if auto blacklist has been disabled between the upload and the replacement', async function () {
|
|
this.timeout(120000)
|
|
|
|
const { uuid } = await servers[0].videos.quickUpload({ token: userToken, name: 'user video' })
|
|
await waitJobs(servers)
|
|
await expectBlacklist(uuid, true)
|
|
|
|
await servers[0].blacklist.remove({ videoId: uuid })
|
|
await expectBlacklist(uuid, false)
|
|
|
|
await updateAutoBlacklist(false)
|
|
|
|
await servers[0].videos.replaceSourceFile({ videoId: uuid, token: userToken, fixture: 'video_short1.webm' })
|
|
await waitJobs(servers)
|
|
|
|
await expectBlacklist(uuid, false)
|
|
})
|
|
})
|
|
|
|
describe('With object storage enabled', function () {
|
|
if (areMockObjectStorageTestsDisabled()) return
|
|
|
|
const objectStorage = new ObjectStorageCommand()
|
|
|
|
before(async function () {
|
|
this.timeout(120000)
|
|
|
|
const configOverride = objectStorage.getDefaultMockConfig()
|
|
await objectStorage.prepareDefaultMockBuckets()
|
|
|
|
await servers[0].kill()
|
|
await servers[0].run(configOverride)
|
|
})
|
|
|
|
it('Should replace a video file with transcoding disabled', async function () {
|
|
this.timeout(120000)
|
|
|
|
await servers[0].config.disableTranscoding()
|
|
|
|
const { uuid } = await servers[0].videos.quickUpload({
|
|
name: 'object storage without transcoding',
|
|
fixture: 'video_short_720p.mp4'
|
|
})
|
|
await waitJobs(servers)
|
|
|
|
for (const server of servers) {
|
|
const video = await server.videos.get({ id: uuid })
|
|
|
|
const files = getAllFiles(video)
|
|
expect(files).to.have.lengthOf(1)
|
|
expect(files[0].resolution.id).to.equal(720)
|
|
expectStartWith(files[0].fileUrl, objectStorage.getMockWebVideosBaseUrl())
|
|
}
|
|
|
|
await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_360p.mp4' })
|
|
await waitJobs(servers)
|
|
|
|
for (const server of servers) {
|
|
const video = await server.videos.get({ id: uuid })
|
|
|
|
const files = getAllFiles(video)
|
|
expect(files).to.have.lengthOf(1)
|
|
expect(files[0].resolution.id).to.equal(360)
|
|
expectStartWith(files[0].fileUrl, objectStorage.getMockWebVideosBaseUrl())
|
|
}
|
|
})
|
|
|
|
it('Should replace a video file with transcoding enabled', async function () {
|
|
this.timeout(120000)
|
|
|
|
const previousPaths: string[] = []
|
|
|
|
await servers[0].config.enableTranscoding(true, true, true)
|
|
|
|
const { uuid: videoUUID } = await servers[0].videos.quickUpload({
|
|
name: 'object storage with transcoding',
|
|
fixture: 'video_short_360p.mp4'
|
|
})
|
|
uuid = videoUUID
|
|
|
|
await waitJobs(servers)
|
|
|
|
for (const server of servers) {
|
|
const video = await server.videos.get({ id: uuid })
|
|
|
|
const files = getAllFiles(video)
|
|
expect(files).to.have.lengthOf(4 * 2)
|
|
|
|
for (const file of files) {
|
|
previousPaths.push(file.fileUrl)
|
|
}
|
|
|
|
for (const file of video.files) {
|
|
expectStartWith(file.fileUrl, objectStorage.getMockWebVideosBaseUrl())
|
|
}
|
|
|
|
for (const file of video.streamingPlaylists[0].files) {
|
|
expectStartWith(file.fileUrl, objectStorage.getMockPlaylistBaseUrl())
|
|
}
|
|
}
|
|
|
|
await servers[0].videos.replaceSourceFile({ videoId: uuid, fixture: 'video_short_240p.mp4' })
|
|
await waitJobs(servers)
|
|
|
|
for (const server of servers) {
|
|
const video = await server.videos.get({ id: uuid })
|
|
|
|
const files = getAllFiles(video)
|
|
expect(files).to.have.lengthOf(3 * 2)
|
|
|
|
for (const file of files) {
|
|
expect(previousPaths).to.not.include(file.fileUrl)
|
|
}
|
|
|
|
for (const file of video.files) {
|
|
expectStartWith(file.fileUrl, objectStorage.getMockWebVideosBaseUrl())
|
|
}
|
|
|
|
for (const file of video.streamingPlaylists[0].files) {
|
|
expectStartWith(file.fileUrl, objectStorage.getMockPlaylistBaseUrl())
|
|
}
|
|
}
|
|
})
|
|
})
|
|
})
|
|
|
|
after(async function () {
|
|
await cleanupTests(servers)
|
|
})
|
|
})
|