はじまりの大地
このコミットが含まれているのは:
@@ -0,0 +1,438 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { AbuseCreate, AbuseState, HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
AbusesCommand,
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
doubleFollow,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test abuses API validators', function () {
|
||||
const basePath = '/api/v1/abuses/'
|
||||
|
||||
let server: PeerTubeServer
|
||||
|
||||
let userToken = ''
|
||||
let userToken2 = ''
|
||||
let abuseId: number
|
||||
let messageId: number
|
||||
|
||||
let command: AbusesCommand
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
userToken = await server.users.generateUserAndToken('user_1')
|
||||
userToken2 = await server.users.generateUserAndToken('user_2')
|
||||
|
||||
server.store.videoCreated = await server.videos.upload()
|
||||
|
||||
command = server.abuses
|
||||
})
|
||||
|
||||
describe('When listing abuses for admins', function () {
|
||||
const path = basePath
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad id filter', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { id: 'toto' } })
|
||||
})
|
||||
|
||||
it('Should fail with a bad filter', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { filter: 'toto' } })
|
||||
await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { filter: 'videos' } })
|
||||
})
|
||||
|
||||
it('Should fail with bad predefined reason', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { predefinedReason: 'violentOrRepulsives' } })
|
||||
})
|
||||
|
||||
it('Should fail with a bad state filter', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { state: 'toto' } })
|
||||
await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { state: 0 } })
|
||||
})
|
||||
|
||||
it('Should fail with a bad videoIs filter', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { videoIs: 'toto' } })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const query = {
|
||||
id: 13,
|
||||
predefinedReason: 'violentOrRepulsive',
|
||||
filter: 'comment',
|
||||
state: 2,
|
||||
videoIs: 'deleted'
|
||||
}
|
||||
|
||||
await makeGetRequest({ url: server.url, path, token: server.accessToken, query, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing abuses for users', function () {
|
||||
const path = '/api/v1/users/me/abuses'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, userToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, userToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, userToken)
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad id filter', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: userToken, query: { id: 'toto' } })
|
||||
})
|
||||
|
||||
it('Should fail with a bad state filter', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: userToken, query: { state: 'toto' } })
|
||||
await makeGetRequest({ url: server.url, path, token: userToken, query: { state: 0 } })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const query = {
|
||||
id: 13,
|
||||
state: 2
|
||||
}
|
||||
|
||||
await makeGetRequest({ url: server.url, path, token: userToken, query, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When reporting an abuse', function () {
|
||||
const path = basePath
|
||||
|
||||
it('Should fail with nothing', async function () {
|
||||
const fields = {}
|
||||
await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a wrong video', async function () {
|
||||
const fields = { video: { id: 'blabla' }, reason: 'my super reason' }
|
||||
await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown video', async function () {
|
||||
const fields = { video: { id: 42 }, reason: 'my super reason' }
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a wrong comment', async function () {
|
||||
const fields = { comment: { id: 'blabla' }, reason: 'my super reason' }
|
||||
await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown comment', async function () {
|
||||
const fields = { comment: { id: 42 }, reason: 'my super reason' }
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a wrong account', async function () {
|
||||
const fields = { account: { id: 'blabla' }, reason: 'my super reason' }
|
||||
await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown account', async function () {
|
||||
const fields = { account: { id: 42 }, reason: 'my super reason' }
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with not account, comment or video', async function () {
|
||||
const fields = { reason: 'my super reason' }
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
const fields = { video: { id: server.store.videoCreated.id }, reason: 'my super reason' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: 'hello', fields, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a reason too short', async function () {
|
||||
const fields = { video: { id: server.store.videoCreated.id }, reason: 'h' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a too big reason', async function () {
|
||||
const fields = { video: { id: server.store.videoCreated.id }, reason: 'super'.repeat(605) }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters (basic)', async function () {
|
||||
const fields: AbuseCreate = { video: { id: server.store.videoCreated.shortUUID }, reason: 'my super reason' }
|
||||
|
||||
const res = await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
abuseId = res.body.abuse.id
|
||||
})
|
||||
|
||||
it('Should fail with a wrong predefined reason', async function () {
|
||||
const fields = { video: server.store.videoCreated, reason: 'my super reason', predefinedReasons: [ 'wrongPredefinedReason' ] }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with negative timestamps', async function () {
|
||||
const fields = { video: { id: server.store.videoCreated.id, startAt: -1 }, reason: 'my super reason' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail mith misordered startAt/endAt', async function () {
|
||||
const fields = { video: { id: server.store.videoCreated.id, startAt: 5, endAt: 1 }, reason: 'my super reason' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters (advanced)', async function () {
|
||||
const fields: AbuseCreate = {
|
||||
video: {
|
||||
id: server.store.videoCreated.id,
|
||||
startAt: 1,
|
||||
endAt: 5
|
||||
},
|
||||
reason: 'my super reason',
|
||||
predefinedReasons: [ 'serverRules' ]
|
||||
}
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: userToken, fields, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating an abuse', function () {
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await command.update({ token: 'blabla', abuseId, body: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
await command.update({ token: userToken, abuseId, body: {}, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad abuse id', async function () {
|
||||
await command.update({ abuseId: 45, body: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad state', async function () {
|
||||
const body = { state: 5 as any }
|
||||
await command.update({ abuseId, body, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad moderation comment', async function () {
|
||||
const body = { moderationComment: 'b'.repeat(3001) }
|
||||
await command.update({ abuseId, body, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const body = { state: AbuseState.ACCEPTED }
|
||||
await command.update({ abuseId, body })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When creating an abuse message', function () {
|
||||
const message = 'my super message'
|
||||
|
||||
it('Should fail with an invalid abuse id', async function () {
|
||||
await command.addMessage({ token: userToken2, abuseId: 888, message, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await command.addMessage({ token: 'fake_token', abuseId, message, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid logged in user', async function () {
|
||||
await command.addMessage({ token: userToken2, abuseId, message, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid message', async function () {
|
||||
await command.addMessage({ token: userToken, abuseId, message: 'a'.repeat(5000), expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const res = await command.addMessage({ token: userToken, abuseId, message })
|
||||
messageId = res.body.abuseMessage.id
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing abuse messages', function () {
|
||||
|
||||
it('Should fail with an invalid abuse id', async function () {
|
||||
await command.listMessages({ token: userToken, abuseId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await command.listMessages({ token: 'fake_token', abuseId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid logged in user', async function () {
|
||||
await command.listMessages({ token: userToken2, abuseId, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await command.listMessages({ token: userToken, abuseId })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When deleting an abuse message', function () {
|
||||
it('Should fail with an invalid abuse id', async function () {
|
||||
await command.deleteMessage({ token: userToken, abuseId: 888, messageId, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid message id', async function () {
|
||||
await command.deleteMessage({ token: userToken, abuseId, messageId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await command.deleteMessage({ token: 'fake_token', abuseId, messageId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid logged in user', async function () {
|
||||
await command.deleteMessage({ token: userToken2, abuseId, messageId, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await command.deleteMessage({ token: userToken, abuseId, messageId })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When deleting a video abuse', function () {
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await command.delete({ token: 'blabla', abuseId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
await command.delete({ token: userToken, abuseId, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad abuse id', async function () {
|
||||
await command.delete({ abuseId: 45, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await command.delete({ abuseId })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When trying to manage messages of a remote abuse', function () {
|
||||
let remoteAbuseId: number
|
||||
let anotherServer: PeerTubeServer
|
||||
|
||||
before(async function () {
|
||||
this.timeout(50000)
|
||||
|
||||
anotherServer = await createSingleServer(2)
|
||||
await setAccessTokensToServers([ anotherServer ])
|
||||
|
||||
await doubleFollow(anotherServer, server)
|
||||
|
||||
const server2VideoId = await anotherServer.videos.getId({ uuid: server.store.videoCreated.uuid })
|
||||
await anotherServer.abuses.report({ reason: 'remote server', videoId: server2VideoId })
|
||||
|
||||
await waitJobs([ server, anotherServer ])
|
||||
|
||||
const body = await command.getAdminList({ sort: '-createdAt' })
|
||||
remoteAbuseId = body.data[0].id
|
||||
})
|
||||
|
||||
it('Should fail when listing abuse messages of a remote abuse', async function () {
|
||||
await command.listMessages({ abuseId: remoteAbuseId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail when creating abuse message of a remote abuse', async function () {
|
||||
await command.addMessage({ abuseId: remoteAbuseId, message: 'message', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ anotherServer ])
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,43 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import { cleanupTests, createSingleServer, PeerTubeServer } from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test accounts API validators', function () {
|
||||
const path = '/api/v1/accounts/'
|
||||
let server: PeerTubeServer
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
})
|
||||
|
||||
describe('When listing accounts', function () {
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting an account', function () {
|
||||
|
||||
it('Should return 404 with a non existing name', async function () {
|
||||
await server.accounts.get({ accountName: 'arfaze', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,137 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
PeerTubeServer,
|
||||
cleanupTests,
|
||||
createSingleServer, setAccessTokensToServers,
|
||||
setDefaultVideoChannel
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test auto tag policies API validator', function () {
|
||||
let server: PeerTubeServer
|
||||
|
||||
let userToken: string
|
||||
let userToken2: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultVideoChannel([ server ])
|
||||
|
||||
userToken = await server.users.generateUserAndToken('user1')
|
||||
userToken2 = await server.users.generateUserAndToken('user2')
|
||||
})
|
||||
|
||||
describe('When getting available account auto tags', function () {
|
||||
const baseParams = () => ({ accountName: 'user1', token: userToken })
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await server.autoTags.getAccountAvailable({ ...baseParams(), token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a user that cannot manage account', async function () {
|
||||
await server.autoTags.getAccountAvailable({ ...baseParams(), token: userToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown account', async function () {
|
||||
await server.autoTags.getAccountAvailable({ ...baseParams(), accountName: 'user42', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.autoTags.getAccountAvailable(baseParams())
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting available server auto tags', function () {
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await server.autoTags.getServerAvailable({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a user that that does not have enought rights', async function () {
|
||||
await server.autoTags.getServerAvailable({ token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.autoTags.getServerAvailable()
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting auto tag policies', function () {
|
||||
const baseParams = () => ({ accountName: 'user1', token: userToken })
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await server.autoTags.getCommentPolicies({ ...baseParams(), token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a user that cannot manage account', async function () {
|
||||
await server.autoTags.getCommentPolicies({ ...baseParams(), token: userToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown account', async function () {
|
||||
await server.autoTags.getCommentPolicies({ ...baseParams(), accountName: 'user42', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.autoTags.getCommentPolicies(baseParams())
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating auto tag policies', function () {
|
||||
const baseParams = () => ({ accountName: 'user1', review: [ 'external-link' ], token: userToken })
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await server.autoTags.updateCommentPolicies({
|
||||
...baseParams(),
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a user that cannot manage account', async function () {
|
||||
await server.autoTags.updateCommentPolicies({
|
||||
...baseParams(),
|
||||
token: userToken2,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown account', async function () {
|
||||
await server.autoTags.updateCommentPolicies({
|
||||
...baseParams(),
|
||||
accountName: 'user42',
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with invalid review array', async function () {
|
||||
await server.autoTags.updateCommentPolicies({
|
||||
...baseParams(),
|
||||
review: 'toto' as any,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with review array that does not contain available tags', async function () {
|
||||
await server.autoTags.updateCommentPolicies({
|
||||
...baseParams(),
|
||||
review: [ 'toto' ],
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.autoTags.updateCommentPolicies(baseParams())
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,556 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createMultipleServers,
|
||||
doubleFollow,
|
||||
makeDeleteRequest,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test blocklist API validators', function () {
|
||||
let servers: PeerTubeServer[]
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken: string
|
||||
|
||||
before(async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
servers = await createMultipleServers(2)
|
||||
await setAccessTokensToServers(servers)
|
||||
|
||||
server = servers[0]
|
||||
|
||||
const user = { username: 'user1', password: 'password' }
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
|
||||
userAccessToken = await server.login.getAccessToken(user)
|
||||
|
||||
await doubleFollow(servers[0], servers[1])
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
describe('When managing user blocklist', function () {
|
||||
|
||||
describe('When managing user accounts blocklist', function () {
|
||||
const path = '/api/v1/users/me/blocklist/accounts'
|
||||
|
||||
describe('When listing blocked accounts', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
})
|
||||
|
||||
describe('When blocking an account', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { accountName: 'user1' },
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown account', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { accountName: 'user2' },
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to block ourselves', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { accountName: 'root' },
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { accountName: 'user1' },
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When unblocking an account', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/user1',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown account block', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/user2',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/user1',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When managing user servers blocklist', function () {
|
||||
const path = '/api/v1/users/me/blocklist/servers'
|
||||
|
||||
describe('When listing blocked servers', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
})
|
||||
|
||||
describe('When blocking a server', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { host: '127.0.0.1:9002' },
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with an unknown server', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { host: '127.0.0.1:9003' },
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with our own server', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { host: server.host },
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { host: servers[1].host },
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When unblocking a server', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/' + servers[1].host,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown server block', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/127.0.0.1:9004',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/' + servers[1].host,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When managing server blocklist', function () {
|
||||
|
||||
describe('When managing server accounts blocklist', function () {
|
||||
const path = '/api/v1/server/blocklist/accounts'
|
||||
|
||||
describe('When listing blocked accounts', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a user without the appropriate rights', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: userAccessToken,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
})
|
||||
|
||||
describe('When blocking an account', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { accountName: 'user1' },
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a user without the appropriate rights', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: userAccessToken,
|
||||
path,
|
||||
fields: { accountName: 'user1' },
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown account', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { accountName: 'user2' },
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to block ourselves', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { accountName: 'root' },
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { accountName: 'user1' },
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When unblocking an account', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/user1',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a user without the appropriate rights', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/user1',
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown account block', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/user2',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/user1',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When managing server servers blocklist', function () {
|
||||
const path = '/api/v1/server/blocklist/servers'
|
||||
|
||||
describe('When listing blocked servers', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a user without the appropriate rights', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: userAccessToken,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
})
|
||||
|
||||
describe('When blocking a server', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { host: servers[1].host },
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a user without the appropriate rights', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: userAccessToken,
|
||||
path,
|
||||
fields: { host: servers[1].host },
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with an unknown server', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { host: '127.0.0.1:9003' },
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with our own server', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { host: server.host },
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { host: servers[1].host },
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When unblocking a server', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/' + servers[1].host,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a user without the appropriate rights', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/' + servers[1].host,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown server block', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/127.0.0.1:9004',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/' + servers[1].host,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting blocklist status', function () {
|
||||
const path = '/api/v1/blocklist/status'
|
||||
|
||||
it('Should fail with a bad token', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: 'false',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad accounts field', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: {
|
||||
accounts: 1
|
||||
},
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: {
|
||||
accounts: [ 1 ]
|
||||
},
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad hosts field', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: {
|
||||
hosts: 1
|
||||
},
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: {
|
||||
hosts: [ 1 ]
|
||||
},
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: {},
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: {
|
||||
hosts: [ 'example.com' ],
|
||||
accounts: [ 'john@example.com' ]
|
||||
},
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests(servers)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,86 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makePostBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test bulk API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
const user = { username: 'user1', password: 'password' }
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
|
||||
userAccessToken = await server.login.getAccessToken(user)
|
||||
})
|
||||
|
||||
describe('When removing comments of', function () {
|
||||
const path = '/api/v1/bulk/remove-comments-of'
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { accountName: 'user1', scope: 'my-videos' },
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown account', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { accountName: 'user2', scope: 'my-videos' },
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid scope', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { accountName: 'user1', scope: 'my-videoss' },
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to delete comments of the instance without the appropriate rights', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: userAccessToken,
|
||||
path,
|
||||
fields: { accountName: 'user1', scope: 'instance' },
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
fields: { accountName: 'user1', scope: 'instance' },
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,209 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { FIXTURE_URLS } from '@tests/shared/fixture-urls.js'
|
||||
import { areHttpImportTestsDisabled } from '@peertube/peertube-node-utils'
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
ChannelsCommand,
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
setDefaultVideoChannel
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test videos import in a channel API validator', function () {
|
||||
let server: PeerTubeServer
|
||||
const userInfo = {
|
||||
accessToken: '',
|
||||
channelName: 'fake_channel',
|
||||
channelId: -1,
|
||||
id: -1,
|
||||
videoQuota: -1,
|
||||
videoQuotaDaily: -1,
|
||||
channelSyncId: -1
|
||||
}
|
||||
let command: ChannelsCommand
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultVideoChannel([ server ])
|
||||
|
||||
await server.config.enableVideoImports()
|
||||
await server.config.enableChannelSync()
|
||||
|
||||
const userCreds = {
|
||||
username: 'fake',
|
||||
password: 'fake_password'
|
||||
}
|
||||
|
||||
{
|
||||
const user = await server.users.create({ username: userCreds.username, password: userCreds.password })
|
||||
userInfo.id = user.id
|
||||
userInfo.accessToken = await server.login.getAccessToken(userCreds)
|
||||
|
||||
const info = await server.users.getMyInfo({ token: userInfo.accessToken })
|
||||
userInfo.channelId = info.videoChannels[0].id
|
||||
}
|
||||
|
||||
{
|
||||
const { videoChannelSync } = await server.channelSyncs.create({
|
||||
token: userInfo.accessToken,
|
||||
attributes: {
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel,
|
||||
videoChannelId: userInfo.channelId
|
||||
}
|
||||
})
|
||||
userInfo.channelSyncId = videoChannelSync.id
|
||||
}
|
||||
|
||||
command = server.channels
|
||||
})
|
||||
|
||||
it('Should fail when HTTP upload is disabled', async function () {
|
||||
await server.config.disableChannelSync()
|
||||
await server.config.disableVideoImports()
|
||||
|
||||
await command.importVideos({
|
||||
channelName: server.store.channel.name,
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
|
||||
await server.config.enableVideoImports()
|
||||
})
|
||||
|
||||
it('Should fail when externalChannelUrl is not provided', async function () {
|
||||
await command.importVideos({
|
||||
channelName: server.store.channel.name,
|
||||
externalChannelUrl: null,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail when externalChannelUrl is malformed', async function () {
|
||||
await command.importVideos({
|
||||
channelName: server.store.channel.name,
|
||||
externalChannelUrl: 'not-a-url',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad sync id', async function () {
|
||||
await command.importVideos({
|
||||
channelName: server.store.channel.name,
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel,
|
||||
videoChannelSyncId: 'toto' as any,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a unknown sync id', async function () {
|
||||
await command.importVideos({
|
||||
channelName: server.store.channel.name,
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel,
|
||||
videoChannelSyncId: 42,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a sync id of another channel', async function () {
|
||||
await command.importVideos({
|
||||
channelName: server.store.channel.name,
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel,
|
||||
videoChannelSyncId: userInfo.channelSyncId,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with no authentication', async function () {
|
||||
await command.importVideos({
|
||||
channelName: server.store.channel.name,
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel,
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail when sync is not owned by the user', async function () {
|
||||
await command.importVideos({
|
||||
channelName: server.store.channel.name,
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel,
|
||||
token: userInfo.accessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail when the user has no quota', async function () {
|
||||
await server.users.update({
|
||||
userId: userInfo.id,
|
||||
videoQuota: 0
|
||||
})
|
||||
|
||||
await command.importVideos({
|
||||
channelName: 'fake_channel',
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel,
|
||||
token: userInfo.accessToken,
|
||||
expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413
|
||||
})
|
||||
|
||||
await server.users.update({
|
||||
userId: userInfo.id,
|
||||
videoQuota: userInfo.videoQuota
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail when the user has no daily quota', async function () {
|
||||
await server.users.update({
|
||||
userId: userInfo.id,
|
||||
videoQuotaDaily: 0
|
||||
})
|
||||
|
||||
await command.importVideos({
|
||||
channelName: 'fake_channel',
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel,
|
||||
token: userInfo.accessToken,
|
||||
expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413
|
||||
})
|
||||
|
||||
await server.users.update({
|
||||
userId: userInfo.id,
|
||||
videoQuotaDaily: userInfo.videoQuotaDaily
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed when sync is run by its owner', async function () {
|
||||
if (!areHttpImportTestsDisabled()) return
|
||||
|
||||
await command.importVideos({
|
||||
channelName: 'fake_channel',
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel,
|
||||
token: userInfo.accessToken
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed when sync is run with root and for another user\'s channel', async function () {
|
||||
if (!areHttpImportTestsDisabled()) return
|
||||
|
||||
await command.importVideos({
|
||||
channelName: 'fake_channel',
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,305 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
import merge from 'lodash-es/merge.js'
|
||||
import { omit } from '@peertube/peertube-core-utils'
|
||||
import { ActorImageType, CustomConfig, HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeDeleteRequest,
|
||||
makeGetRequest,
|
||||
makePutBodyRequest,
|
||||
makeUploadRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
|
||||
|
||||
describe('Test config API validators', function () {
|
||||
const path = '/api/v1/config/custom'
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken: string
|
||||
|
||||
let updateParams: CustomConfig
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
updateParams = await server.config.getCustomConfig()
|
||||
|
||||
const user = {
|
||||
username: 'user1',
|
||||
password: 'password'
|
||||
}
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
userAccessToken = await server.login.getAccessToken(user)
|
||||
})
|
||||
|
||||
describe('When getting the configuration', function () {
|
||||
it('Should fail without token', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating the configuration', function () {
|
||||
it('Should fail without token', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: updateParams,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: updateParams,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if it misses a key', async function () {
|
||||
const newUpdateParams = { ...updateParams, admin: omit(updateParams.admin, [ 'email' ]) }
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: newUpdateParams,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad default NSFW policy', async function () {
|
||||
const newUpdateParams = {
|
||||
...updateParams,
|
||||
|
||||
instance: {
|
||||
defaultNSFWPolicy: 'hello'
|
||||
}
|
||||
}
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: newUpdateParams,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if email disabled and signup requires email verification', async function () {
|
||||
// opposite scenario - success when enable enabled - covered via tests/api/users/user-verification.ts
|
||||
const newUpdateParams = {
|
||||
...updateParams,
|
||||
|
||||
signup: {
|
||||
enabled: true,
|
||||
limit: 5,
|
||||
requiresApproval: true,
|
||||
requiresEmailVerification: true
|
||||
}
|
||||
}
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: newUpdateParams,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a disabled web videos & hls transcoding', async function () {
|
||||
const newUpdateParams = {
|
||||
...updateParams,
|
||||
|
||||
transcoding: {
|
||||
hls: {
|
||||
enabled: false
|
||||
},
|
||||
web_videos: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: newUpdateParams,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a disabled http upload & enabled sync', async function () {
|
||||
const newUpdateParams: CustomConfig = merge({}, updateParams, {
|
||||
import: {
|
||||
videos: {
|
||||
http: { enabled: false }
|
||||
},
|
||||
videoChannelSynchronization: { enabled: true }
|
||||
}
|
||||
})
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: newUpdateParams,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: updateParams,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When deleting the configuration', function () {
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Updating instance image', function () {
|
||||
const toTest = [
|
||||
{ path: '/api/v1/config/instance-banner/pick', attachName: 'bannerfile' },
|
||||
{ path: '/api/v1/config/instance-avatar/pick', attachName: 'avatarfile' }
|
||||
]
|
||||
|
||||
it('Should fail with an incorrect input file', async function () {
|
||||
for (const { attachName, path } of toTest) {
|
||||
const attaches = { [attachName]: buildAbsoluteFixturePath('video_short.mp4') }
|
||||
|
||||
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields: {}, attaches })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with a big file', async function () {
|
||||
for (const { attachName, path } of toTest) {
|
||||
const attaches = { [attachName]: buildAbsoluteFixturePath('avatar-big.png') }
|
||||
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: {},
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
for (const { attachName, path } of toTest) {
|
||||
const attaches = { [attachName]: buildAbsoluteFixturePath('avatar.png') }
|
||||
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: {},
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail without the appropriate rights', async function () {
|
||||
for (const { attachName, path } of toTest) {
|
||||
const attaches = { [attachName]: buildAbsoluteFixturePath('avatar.png') }
|
||||
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userAccessToken,
|
||||
fields: {},
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
for (const { attachName, path } of toTest) {
|
||||
const attaches = { [attachName]: buildAbsoluteFixturePath('avatar.png') }
|
||||
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: {},
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Deleting instance image', function () {
|
||||
const types = [ ActorImageType.BANNER, ActorImageType.AVATAR ]
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
for (const type of types) {
|
||||
await server.config.deleteInstanceImage({ type, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail without the appropriate rights', async function () {
|
||||
for (const type of types) {
|
||||
await server.config.deleteInstanceImage({ type, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
for (const type of types) {
|
||||
await server.config.deleteInstanceImage({ type })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,86 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { MockSmtpServer } from '@tests/shared/mock-servers/index.js'
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
ConfigCommand,
|
||||
ContactFormCommand,
|
||||
createSingleServer,
|
||||
killallServers,
|
||||
PeerTubeServer
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test contact form API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
const emails: object[] = []
|
||||
const defaultBody = {
|
||||
fromName: 'super name',
|
||||
fromEmail: 'toto@example.com',
|
||||
subject: 'my subject',
|
||||
body: 'Hello, how are you?'
|
||||
}
|
||||
let emailPort: number
|
||||
let command: ContactFormCommand
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
emailPort = await MockSmtpServer.Instance.collectEmails(emails)
|
||||
|
||||
// Email is disabled
|
||||
server = await createSingleServer(1)
|
||||
command = server.contactForm
|
||||
})
|
||||
|
||||
it('Should not accept a contact form if emails are disabled', async function () {
|
||||
await command.send({ ...defaultBody, expectedStatus: HttpStatusCode.CONFLICT_409 })
|
||||
})
|
||||
|
||||
it('Should not accept a contact form if it is disabled in the configuration', async function () {
|
||||
this.timeout(25000)
|
||||
|
||||
await killallServers([ server ])
|
||||
|
||||
// Contact form is disabled
|
||||
await server.run({ ...ConfigCommand.getEmailOverrideConfig(emailPort), contact_form: { enabled: false } })
|
||||
await command.send({ ...defaultBody, expectedStatus: HttpStatusCode.CONFLICT_409 })
|
||||
})
|
||||
|
||||
it('Should not accept a contact form if from email is invalid', async function () {
|
||||
this.timeout(25000)
|
||||
|
||||
await killallServers([ server ])
|
||||
|
||||
// Email & contact form enabled
|
||||
await server.run(ConfigCommand.getEmailOverrideConfig(emailPort))
|
||||
|
||||
await command.send({ ...defaultBody, fromEmail: 'badEmail', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await command.send({ ...defaultBody, fromEmail: 'badEmail@', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await command.send({ ...defaultBody, fromEmail: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should not accept a contact form if from name is invalid', async function () {
|
||||
await command.send({ ...defaultBody, fromName: 'name'.repeat(100), expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await command.send({ ...defaultBody, fromName: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await command.send({ ...defaultBody, fromName: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should not accept a contact form if body is invalid', async function () {
|
||||
await command.send({ ...defaultBody, body: 'body'.repeat(5000), expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await command.send({ ...defaultBody, body: 'a', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await command.send({ ...defaultBody, body: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should accept a contact form with the correct parameters', async function () {
|
||||
await command.send(defaultBody)
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
MockSmtpServer.Instance.kill()
|
||||
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,79 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
makePutBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test custom pages validators', function () {
|
||||
const path = '/api/v1/custom-pages/homepage/instance'
|
||||
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
const user = { username: 'user1', password: 'password' }
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
|
||||
userAccessToken = await server.login.getAccessToken(user)
|
||||
})
|
||||
|
||||
describe('When updating instance homepage', function () {
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { content: 'super content' },
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userAccessToken,
|
||||
fields: { content: 'super content' },
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: { content: 'super content' },
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting instance homapage', function () {
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,67 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test debug API validators', function () {
|
||||
const path = '/api/v1/server/debug'
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken = ''
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
const user = {
|
||||
username: 'user1',
|
||||
password: 'my super password'
|
||||
}
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
userAccessToken = await server.login.getAccessToken(user)
|
||||
})
|
||||
|
||||
describe('When getting debug endpoint', function () {
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
query: { startDate: new Date().toISOString() },
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,369 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeDeleteRequest,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test server follows API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
})
|
||||
|
||||
describe('When managing following', function () {
|
||||
let userAccessToken = null
|
||||
|
||||
before(async function () {
|
||||
userAccessToken = await server.users.generateUserAndToken('user1')
|
||||
})
|
||||
|
||||
describe('When adding follows', function () {
|
||||
const path = '/api/v1/server/following'
|
||||
|
||||
it('Should fail with nothing', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if hosts is not composed by hosts', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { hosts: [ '127.0.0.1:9002', '127.0.0.1:coucou' ] },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if hosts is composed with http schemes', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { hosts: [ '127.0.0.1:9002', 'http://127.0.0.1:9003' ] },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if hosts are not unique', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { urls: [ '127.0.0.1:9002', '127.0.0.1:9002' ] },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if handles is not composed by handles', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { handles: [ 'hello@example.com', '127.0.0.1:9001' ] },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if handles are not unique', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { urls: [ 'hello@example.com', 'hello@example.com' ] },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { hosts: [ '127.0.0.1:9002' ] },
|
||||
token: 'fake_token',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { hosts: [ '127.0.0.1:9002' ] },
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing followings', function () {
|
||||
const path = '/api/v1/server/following'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect state', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: {
|
||||
state: 'blabla'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect actor type', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: {
|
||||
actorType: 'blabla'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail succeed with the correct params', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.OK_200,
|
||||
query: {
|
||||
state: 'accepted',
|
||||
actorType: 'Application'
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing followers', function () {
|
||||
const path = '/api/v1/server/followers'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect actor type', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: {
|
||||
actorType: 'blabla'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect state', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: {
|
||||
state: 'blabla',
|
||||
actorType: 'Application'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail succeed with the correct params', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.OK_200,
|
||||
query: {
|
||||
state: 'accepted'
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When removing a follower', function () {
|
||||
const path = '/api/v1/server/followers'
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/toto@127.0.0.1:9002',
|
||||
token: 'fake_token',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/toto@127.0.0.1:9002',
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid follower', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/toto',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown follower', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/toto@127.0.0.1:9003',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When accepting a follower', function () {
|
||||
const path = '/api/v1/server/followers'
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + '/toto@127.0.0.1:9002/accept',
|
||||
token: 'fake_token',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + '/toto@127.0.0.1:9002/accept',
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid follower', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + '/toto/accept',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown follower', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + '/toto@127.0.0.1:9003/accept',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When rejecting a follower', function () {
|
||||
const path = '/api/v1/server/followers'
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + '/toto@127.0.0.1:9002/reject',
|
||||
token: 'fake_token',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + '/toto@127.0.0.1:9002/reject',
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid follower', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + '/toto/reject',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown follower', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + '/toto@127.0.0.1:9003/reject',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When removing following', function () {
|
||||
const path = '/api/v1/server/following'
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/127.0.0.1:9002',
|
||||
token: 'fake_token',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/127.0.0.1:9002',
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if we do not follow this server', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/example.com',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,51 @@
|
||||
import './abuses.js'
|
||||
import './accounts.js'
|
||||
import './auto-tags.js'
|
||||
import './blocklist.js'
|
||||
import './bulk.js'
|
||||
import './channel-import-videos.js'
|
||||
import './config.js'
|
||||
import './contact-form.js'
|
||||
import './custom-pages.js'
|
||||
import './debug.js'
|
||||
import './follows.js'
|
||||
import './jobs.js'
|
||||
import './live.js'
|
||||
import './logs.js'
|
||||
import './metrics.js'
|
||||
import './my-user.js'
|
||||
import './plugins.js'
|
||||
import './redundancy.js'
|
||||
import './registrations.js'
|
||||
import './runners.js'
|
||||
import './search.js'
|
||||
import './services.js'
|
||||
import './transcoding.js'
|
||||
import './two-factor.js'
|
||||
import './upload-quota.js'
|
||||
import './user-export.js'
|
||||
import './user-import.js'
|
||||
import './user-notifications.js'
|
||||
import './user-subscriptions.js'
|
||||
import './users-admin.js'
|
||||
import './users-emails.js'
|
||||
import './video-blacklist.js'
|
||||
import './video-captions.js'
|
||||
import './video-channel-syncs.js'
|
||||
import './video-channels.js'
|
||||
import './video-chapters.js'
|
||||
import './video-comments.js'
|
||||
import './video-files.js'
|
||||
import './video-imports.js'
|
||||
import './video-playlists.js'
|
||||
import './video-source.js'
|
||||
import './video-storyboards.js'
|
||||
import './video-studio.js'
|
||||
import './video-token.js'
|
||||
import './video-transcription.js'
|
||||
import './videos-common-filters.js'
|
||||
import './videos-history.js'
|
||||
import './videos-overviews.js'
|
||||
import './videos.js'
|
||||
import './views.js'
|
||||
import './watched-words.js'
|
||||
@@ -0,0 +1,125 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test jobs API validators', function () {
|
||||
const path = '/api/v1/jobs/failed'
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken = ''
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
const user = {
|
||||
username: 'user1',
|
||||
password: 'my super password'
|
||||
}
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
userAccessToken = await server.login.getAccessToken(user)
|
||||
})
|
||||
|
||||
describe('When listing jobs', function () {
|
||||
|
||||
it('Should fail with a bad state', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path: path + 'ade'
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect job type', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
query: {
|
||||
jobType: 'toto'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When pausing/resuming the job queue', async function () {
|
||||
const commands = [ 'pause', 'resume' ]
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
for (const command of commands) {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: '/api/v1/jobs/' + command,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
for (const command of commands) {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: '/api/v1/jobs/' + command,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
for (const command of commands) {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: '/api/v1/jobs/' + command,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,576 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { omit } from '@peertube/peertube-core-utils'
|
||||
import {
|
||||
HttpStatusCode,
|
||||
LiveVideoCreate,
|
||||
LiveVideoLatencyMode,
|
||||
VideoCommentPolicy,
|
||||
VideoCreateResult,
|
||||
VideoPrivacy
|
||||
} from '@peertube/peertube-models'
|
||||
import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
|
||||
import {
|
||||
LiveCommand,
|
||||
PeerTubeServer,
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makePostBodyRequest,
|
||||
makeUploadRequest,
|
||||
sendRTMPStream,
|
||||
setAccessTokensToServers,
|
||||
stopFfmpeg
|
||||
} from '@peertube/peertube-server-commands'
|
||||
import { expect } from 'chai'
|
||||
|
||||
describe('Test video lives API validator', function () {
|
||||
const path = '/api/v1/videos/live'
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken = ''
|
||||
let channelId: number
|
||||
let video: VideoCreateResult
|
||||
let videoIdNotLive: number
|
||||
let command: LiveCommand
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
await server.config.enableMinimumTranscoding()
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
live: {
|
||||
enabled: true,
|
||||
latencySetting: {
|
||||
enabled: false
|
||||
},
|
||||
maxInstanceLives: 20,
|
||||
maxUserLives: 20,
|
||||
allowReplay: true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const username = 'user1'
|
||||
const password = 'my super password'
|
||||
await server.users.create({ username, password })
|
||||
userAccessToken = await server.login.getAccessToken({ username, password })
|
||||
|
||||
{
|
||||
const { videoChannels } = await server.users.getMyInfo()
|
||||
channelId = videoChannels[0].id
|
||||
}
|
||||
|
||||
{
|
||||
videoIdNotLive = (await server.videos.quickUpload({ name: 'not live' })).id
|
||||
}
|
||||
|
||||
command = server.live
|
||||
})
|
||||
|
||||
describe('When creating a live', function () {
|
||||
let baseCorrectParams: LiveVideoCreate
|
||||
|
||||
before(function () {
|
||||
baseCorrectParams = {
|
||||
name: 'my super name',
|
||||
category: 5,
|
||||
licence: 1,
|
||||
language: 'pt',
|
||||
nsfw: false,
|
||||
commentsPolicy: VideoCommentPolicy.ENABLED,
|
||||
downloadEnabled: true,
|
||||
waitTranscoding: true,
|
||||
description: 'my super description',
|
||||
support: 'my super support text',
|
||||
tags: [ 'tag1', 'tag2' ],
|
||||
privacy: VideoPrivacy.PUBLIC,
|
||||
channelId,
|
||||
saveReplay: false,
|
||||
replaySettings: undefined,
|
||||
permanentLive: true,
|
||||
latencyMode: LiveVideoLatencyMode.DEFAULT
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with nothing', async function () {
|
||||
const fields = {}
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long name', async function () {
|
||||
const fields = { ...baseCorrectParams, name: 'super'.repeat(65) }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad category', async function () {
|
||||
const fields = { ...baseCorrectParams, category: 125 }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad licence', async function () {
|
||||
const fields = { ...baseCorrectParams, licence: 125 }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad language', async function () {
|
||||
const fields = { ...baseCorrectParams, language: 'a'.repeat(15) }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with bad comments policy', async function () {
|
||||
const fields = { ...baseCorrectParams, commentsPolicy: 42 }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long description', async function () {
|
||||
const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long support text', async function () {
|
||||
const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail without a channel', async function () {
|
||||
const fields = omit(baseCorrectParams, [ 'channelId' ])
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad channel', async function () {
|
||||
const fields = { ...baseCorrectParams, channelId: 545454 }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad privacy for replay settings', async function () {
|
||||
const fields = { ...baseCorrectParams, saveReplay: true, replaySettings: { privacy: 999 } }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with another user channel', async function () {
|
||||
const user = {
|
||||
username: 'fake',
|
||||
password: 'fake_password'
|
||||
}
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
|
||||
const accessTokenUser = await server.login.getAccessToken(user)
|
||||
const { videoChannels } = await server.users.getMyInfo({ token: accessTokenUser })
|
||||
const customChannelId = videoChannels[0].id
|
||||
|
||||
const fields = { ...baseCorrectParams, channelId: customChannelId }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with too many tags', async function () {
|
||||
const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a tag length too low', async function () {
|
||||
const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a tag length too big', async function () {
|
||||
const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect thumbnail file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
thumbnailfile: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
|
||||
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
|
||||
})
|
||||
|
||||
it('Should fail with a big thumbnail file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
thumbnailfile: buildAbsoluteFixturePath('custom-preview-big.png')
|
||||
}
|
||||
|
||||
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect preview file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
previewfile: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
|
||||
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
|
||||
})
|
||||
|
||||
it('Should fail with a big preview file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
previewfile: buildAbsoluteFixturePath('custom-preview-big.png')
|
||||
}
|
||||
|
||||
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
|
||||
})
|
||||
|
||||
it('Should fail with bad latency setting', async function () {
|
||||
const fields = { ...baseCorrectParams, latencyMode: 42 }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail to set latency if the server does not allow it', async function () {
|
||||
const fields = { ...baseCorrectParams, latencyMode: LiveVideoLatencyMode.HIGH_LATENCY }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
const res = await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
|
||||
video = res.body.video
|
||||
})
|
||||
|
||||
it('Should forbid if live is disabled', async function () {
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
live: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should forbid to save replay if not enabled by the admin', async function () {
|
||||
const fields = { ...baseCorrectParams, saveReplay: true, replaySettings: { privacy: VideoPrivacy.PUBLIC } }
|
||||
|
||||
await server.config.enableLive({ allowReplay: false, transcoding: false })
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should allow to save replay if enabled by the admin', async function () {
|
||||
const fields = { ...baseCorrectParams, saveReplay: true, replaySettings: { privacy: VideoPrivacy.PUBLIC } }
|
||||
|
||||
await server.config.enableLive({ allowReplay: true, transcoding: false })
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
|
||||
it('Should not allow live if max instance lives is reached', async function () {
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
live: {
|
||||
enabled: true,
|
||||
maxInstanceLives: 1
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should not allow live if max user lives is reached', async function () {
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
live: {
|
||||
enabled: true,
|
||||
maxInstanceLives: 20,
|
||||
maxUserLives: 1
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting live information', function () {
|
||||
|
||||
it('Should fail with a bad access token', async function () {
|
||||
await command.get({ token: 'toto', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should not display private information without access token', async function () {
|
||||
const live = await command.get({ token: '', videoId: video.id })
|
||||
|
||||
expect(live.rtmpUrl).to.not.exist
|
||||
expect(live.streamKey).to.not.exist
|
||||
expect(live.latencyMode).to.exist
|
||||
})
|
||||
|
||||
it('Should not display private information with token of another user', async function () {
|
||||
const live = await command.get({ token: userAccessToken, videoId: video.id })
|
||||
|
||||
expect(live.rtmpUrl).to.not.exist
|
||||
expect(live.streamKey).to.not.exist
|
||||
expect(live.latencyMode).to.exist
|
||||
})
|
||||
|
||||
it('Should display private information with appropriate token', async function () {
|
||||
const live = await command.get({ videoId: video.id })
|
||||
|
||||
expect(live.rtmpUrl).to.exist
|
||||
expect(live.streamKey).to.exist
|
||||
expect(live.latencyMode).to.exist
|
||||
})
|
||||
|
||||
it('Should fail with a bad video id', async function () {
|
||||
await command.get({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown video id', async function () {
|
||||
await command.get({ videoId: 454555, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a non live video', async function () {
|
||||
await command.get({ videoId: videoIdNotLive, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await command.get({ videoId: video.id })
|
||||
await command.get({ videoId: video.uuid })
|
||||
await command.get({ videoId: video.shortUUID })
|
||||
})
|
||||
})
|
||||
|
||||
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 () {
|
||||
await command.update({ token: '', videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad access token', async function () {
|
||||
await command.update({ token: 'toto', videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with access token of another user', async function () {
|
||||
await command.update({ token: userAccessToken, videoId: video.id, fields: {}, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad video id', async function () {
|
||||
await command.update({ videoId: 'toto', fields: {}, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown video id', async function () {
|
||||
await command.update({ videoId: 454555, fields: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a non live video', async function () {
|
||||
await command.update({ videoId: videoIdNotLive, fields: {}, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with bad latency setting', async function () {
|
||||
const fields = { latencyMode: 42 as any }
|
||||
|
||||
await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad privacy for replay settings', async function () {
|
||||
const fields = { saveReplay: true, replaySettings: { privacy: 999 as any } }
|
||||
|
||||
await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with save replay enabled but without replay settings', async function () {
|
||||
await server.config.enableLive({ allowReplay: true, transcoding: false })
|
||||
|
||||
const fields = { saveReplay: true }
|
||||
|
||||
await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with save replay disabled and replay settings', async function () {
|
||||
const fields = { saveReplay: false, replaySettings: { privacy: VideoPrivacy.INTERNAL } }
|
||||
|
||||
await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with only replay settings when save replay is disabled', async function () {
|
||||
const fields = { replaySettings: { privacy: VideoPrivacy.INTERNAL } }
|
||||
|
||||
await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail to set latency if the server does not allow it', async function () {
|
||||
const fields = { latencyMode: LiveVideoLatencyMode.HIGH_LATENCY }
|
||||
|
||||
await command.update({ videoId: video.id, fields, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await command.update({ videoId: video.id, fields: { saveReplay: false } })
|
||||
await command.update({ videoId: video.uuid, fields: { saveReplay: false } })
|
||||
await command.update({ videoId: video.shortUUID, fields: { saveReplay: false } })
|
||||
|
||||
await command.update({ videoId: video.id, fields: { saveReplay: true, replaySettings: { privacy: VideoPrivacy.PUBLIC } } })
|
||||
|
||||
})
|
||||
|
||||
it('Should fail to update replay status if replay is not allowed on the instance', async function () {
|
||||
await server.config.enableLive({ allowReplay: false, transcoding: false })
|
||||
|
||||
await command.update({ videoId: video.id, fields: { saveReplay: true }, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed to live attributes if it has already started', async function () {
|
||||
this.timeout(40000)
|
||||
|
||||
const live = await command.get({ videoId: video.id })
|
||||
|
||||
const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey })
|
||||
|
||||
await command.waitUntilPublished({ videoId: video.id })
|
||||
await command.update({ videoId: video.id, fields: { permanentLive: false }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
await stopFfmpeg(ffmpegCommand)
|
||||
})
|
||||
|
||||
it('Should fail to change live privacy if it has already started', async function () {
|
||||
this.timeout(40000)
|
||||
|
||||
const live = await command.get({ videoId: video.id })
|
||||
|
||||
const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey })
|
||||
|
||||
await command.waitUntilPublished({ videoId: video.id })
|
||||
|
||||
await server.videos.update({
|
||||
id: video.id,
|
||||
attributes: { privacy: VideoPrivacy.PUBLIC } // Same privacy, it's fine
|
||||
})
|
||||
|
||||
await server.videos.update({
|
||||
id: video.id,
|
||||
attributes: { privacy: VideoPrivacy.UNLISTED },
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await stopFfmpeg(ffmpegCommand)
|
||||
})
|
||||
|
||||
it('Should fail to stream twice in the save live', async function () {
|
||||
this.timeout(40000)
|
||||
|
||||
const live = await command.get({ videoId: video.id })
|
||||
|
||||
const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey })
|
||||
|
||||
await command.waitUntilPublished({ videoId: video.id })
|
||||
|
||||
await command.runAndTestStreamError({ videoId: video.id, shouldHaveError: true })
|
||||
|
||||
await stopFfmpeg(ffmpegCommand)
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,163 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { expect } from 'chai'
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test logs API validators', function () {
|
||||
const path = '/api/v1/server/logs'
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken = ''
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
const user = {
|
||||
username: 'user1',
|
||||
password: 'my super password'
|
||||
}
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
userAccessToken = await server.login.getAccessToken(user)
|
||||
})
|
||||
|
||||
describe('When getting logs', function () {
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a missing startDate query', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad startDate query', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
query: { startDate: 'toto' },
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad endDate query', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
query: { startDate: new Date().toISOString(), endDate: 'toto' },
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad level parameter', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
query: { startDate: new Date().toISOString(), level: 'toto' },
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
query: { startDate: new Date().toISOString() },
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When creating client logs', function () {
|
||||
const base = {
|
||||
level: 'warn' as 'warn',
|
||||
message: 'my super message',
|
||||
url: 'https://example.com/toto'
|
||||
}
|
||||
const expectedStatus = HttpStatusCode.BAD_REQUEST_400
|
||||
|
||||
it('Should fail with an invalid level', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, level: '' as any }, expectedStatus })
|
||||
await server.logs.createLogClient({ payload: { ...base, level: undefined }, expectedStatus })
|
||||
await server.logs.createLogClient({ payload: { ...base, level: 'toto' as any }, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid message', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, message: undefined }, expectedStatus })
|
||||
await server.logs.createLogClient({ payload: { ...base, message: '' }, expectedStatus })
|
||||
await server.logs.createLogClient({ payload: { ...base, message: 'm'.repeat(2500) }, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid url', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, url: undefined }, expectedStatus })
|
||||
await server.logs.createLogClient({ payload: { ...base, url: 'toto' }, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid stackTrace', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, stackTrace: 's'.repeat(20000) }, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid userAgent', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, userAgent: 's'.repeat(500) }, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid meta', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, meta: 's'.repeat(20000) }, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.logs.createLogClient({ payload: { ...base, stackTrace: 'stackTrace', meta: '{toto}', userAgent: 'userAgent' } })
|
||||
})
|
||||
|
||||
it('Should rate limit log creation', async function () {
|
||||
let fail = false
|
||||
|
||||
for (let i = 0; i < 100; i++) {
|
||||
try {
|
||||
await server.logs.createLogClient({ token: null, payload: base })
|
||||
} catch {
|
||||
fail = true
|
||||
}
|
||||
}
|
||||
|
||||
expect(fail).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,214 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { omit } from '@peertube/peertube-core-utils'
|
||||
import { HttpStatusCode, PlaybackMetricCreate, VideoResolution } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makePostBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test metrics API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
let videoUUID: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1, {
|
||||
open_telemetry: {
|
||||
metrics: {
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
const { uuid } = await server.videos.quickUpload({ name: 'video' })
|
||||
videoUUID = uuid
|
||||
})
|
||||
|
||||
describe('When adding playback metrics', function () {
|
||||
const path = '/api/v1/metrics/playback'
|
||||
let baseParams: PlaybackMetricCreate
|
||||
|
||||
before(function () {
|
||||
baseParams = {
|
||||
playerMode: 'p2p-media-loader',
|
||||
resolution: VideoResolution.H_1080P,
|
||||
fps: 30,
|
||||
resolutionChanges: 1,
|
||||
errors: 2,
|
||||
p2pEnabled: true,
|
||||
downloadedBytesP2P: 0,
|
||||
downloadedBytesHTTP: 0,
|
||||
uploadedBytesP2P: 0,
|
||||
videoId: videoUUID
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an invalid resolution', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, resolution: 'toto' }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid fps', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, fps: 'toto' }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a missing/invalid player mode', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: omit(baseParams, [ 'playerMode' ])
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, playerMode: 'toto' }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an missing/invalid resolution changes', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: omit(baseParams, [ 'resolutionChanges' ])
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, resolutionChanges: 'toto' }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an missing/invalid errors', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: omit(baseParams, [ 'errors' ])
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, errors: 'toto' }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an missing/invalid downloadedBytesP2P', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: omit(baseParams, [ 'downloadedBytesP2P' ])
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, downloadedBytesP2P: 'toto' }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an missing/invalid downloadedBytesHTTP', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: omit(baseParams, [ 'downloadedBytesHTTP' ])
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, downloadedBytesHTTP: 'toto' }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an missing/invalid uploadedBytesP2P', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: omit(baseParams, [ 'uploadedBytesP2P' ])
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, uploadedBytesP2P: 'toto' }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a missing/invalid p2pEnabled', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: omit(baseParams, [ 'p2pEnabled' ])
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, p2pEnabled: 'toto' }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid totalPeers', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, p2pPeers: 'toto' }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad video id', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, videoId: 'toto' }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown video', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, videoId: 42 },
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: baseParams,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { ...baseParams, p2pEnabled: false, totalPeers: 32 },
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,492 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { MockSmtpServer } from '@tests/shared/mock-servers/index.js'
|
||||
import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
|
||||
import { HttpStatusCode, UserRole, VideoCreateResult } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
makePutBodyRequest,
|
||||
makeUploadRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
UsersCommand
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test my user API validators', function () {
|
||||
const path = '/api/v1/users/'
|
||||
let userId: number
|
||||
let rootId: number
|
||||
let moderatorId: number
|
||||
let video: VideoCreateResult
|
||||
let server: PeerTubeServer
|
||||
let userToken = ''
|
||||
let moderatorToken = ''
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
{
|
||||
server = await createSingleServer(1)
|
||||
await setAccessTokensToServers([ server ])
|
||||
}
|
||||
|
||||
{
|
||||
const result = await server.users.generate('user1')
|
||||
userToken = result.token
|
||||
userId = result.userId
|
||||
}
|
||||
|
||||
{
|
||||
const result = await server.users.generate('moderator1', UserRole.MODERATOR)
|
||||
moderatorToken = result.token
|
||||
}
|
||||
|
||||
{
|
||||
const result = await server.users.generate('moderator2', UserRole.MODERATOR)
|
||||
moderatorId = result.userId
|
||||
}
|
||||
|
||||
{
|
||||
video = await server.videos.upload()
|
||||
}
|
||||
})
|
||||
|
||||
describe('When updating my account', function () {
|
||||
|
||||
it('Should fail with an invalid email attribute', async function () {
|
||||
const fields = {
|
||||
email: 'blabla'
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a too small password', async function () {
|
||||
const fields = {
|
||||
currentPassword: 'password',
|
||||
password: 'bla'
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a too long password', async function () {
|
||||
const fields = {
|
||||
currentPassword: 'password',
|
||||
password: 'super'.repeat(61)
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail without the current password', async function () {
|
||||
const fields = {
|
||||
currentPassword: 'password',
|
||||
password: 'super'.repeat(61)
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid current password', async function () {
|
||||
const fields = {
|
||||
currentPassword: 'my super password fail',
|
||||
password: 'super'.repeat(61)
|
||||
}
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + 'me',
|
||||
token: userToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid NSFW policy attribute', async function () {
|
||||
const fields = {
|
||||
nsfwPolicy: 'hello'
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid autoPlayVideo attribute', async function () {
|
||||
const fields = {
|
||||
autoPlayVideo: -1
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid autoPlayNextVideo attribute', async function () {
|
||||
const fields = {
|
||||
autoPlayNextVideo: -1
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid videosHistoryEnabled attribute', async function () {
|
||||
const fields = {
|
||||
videosHistoryEnabled: -1
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an non authenticated user', async function () {
|
||||
const fields = {
|
||||
currentPassword: 'password',
|
||||
password: 'my super password'
|
||||
}
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + 'me',
|
||||
token: 'supertoken',
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a too long description', async function () {
|
||||
const fields = {
|
||||
description: 'super'.repeat(201)
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid videoLanguages attribute', async function () {
|
||||
{
|
||||
const fields = {
|
||||
videoLanguages: 'toto'
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
}
|
||||
|
||||
{
|
||||
const languages = []
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
languages.push('fr')
|
||||
}
|
||||
|
||||
const fields = {
|
||||
videoLanguages: languages
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an invalid theme', async function () {
|
||||
const fields = { theme: 'invalid' }
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown theme', async function () {
|
||||
const fields = { theme: 'peertube-theme-unknown' }
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with invalid no modal attributes', async function () {
|
||||
const keys = [
|
||||
'noInstanceConfigWarningModal',
|
||||
'noAccountSetupWarningModal',
|
||||
'noWelcomeModal'
|
||||
]
|
||||
|
||||
for (const key of keys) {
|
||||
const fields = {
|
||||
[key]: -1
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userToken, fields })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed to change password with the correct params', async function () {
|
||||
const fields = {
|
||||
currentPassword: 'password',
|
||||
password: 'my super password',
|
||||
nsfwPolicy: 'blur',
|
||||
autoPlayVideo: false,
|
||||
email: 'super_email@example.com',
|
||||
theme: 'default',
|
||||
noInstanceConfigWarningModal: true,
|
||||
noWelcomeModal: true,
|
||||
noAccountSetupWarningModal: true
|
||||
}
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + 'me',
|
||||
token: userToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed without password change with the correct params', async function () {
|
||||
const fields = {
|
||||
nsfwPolicy: 'blur',
|
||||
autoPlayVideo: false
|
||||
}
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + 'me',
|
||||
token: userToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating my avatar', function () {
|
||||
it('Should fail without an incorrect input file', async function () {
|
||||
const fields = {}
|
||||
const attaches = {
|
||||
avatarfile: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
|
||||
})
|
||||
|
||||
it('Should fail with a big file', async function () {
|
||||
const fields = {}
|
||||
const attaches = {
|
||||
avatarfile: buildAbsoluteFixturePath('avatar-big.png')
|
||||
}
|
||||
await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
|
||||
})
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
const fields = {}
|
||||
const attaches = {
|
||||
avatarfile: buildAbsoluteFixturePath('avatar.png')
|
||||
}
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
path: path + '/me/avatar/pick',
|
||||
fields,
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const fields = {}
|
||||
const attaches = {
|
||||
avatarfile: buildAbsoluteFixturePath('avatar.png')
|
||||
}
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
path: path + '/me/avatar/pick',
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When managing my scoped tokens', function () {
|
||||
|
||||
it('Should fail to get my scoped tokens with an non authenticated user', async function () {
|
||||
await server.users.getMyScopedTokens({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail to get my scoped tokens with a bad token', async function () {
|
||||
await server.users.getMyScopedTokens({ token: 'bad', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
|
||||
})
|
||||
|
||||
it('Should succeed to get my scoped tokens', async function () {
|
||||
await server.users.getMyScopedTokens()
|
||||
})
|
||||
|
||||
it('Should fail to renew my scoped tokens with an non authenticated user', async function () {
|
||||
await server.users.renewMyScopedTokens({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail to renew my scoped tokens with a bad token', async function () {
|
||||
await server.users.renewMyScopedTokens({ token: 'bad', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should succeed to renew my scoped tokens', async function () {
|
||||
await server.users.renewMyScopedTokens()
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting my information', function () {
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await server.users.getMyInfo({ token: 'fake_token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await server.users.getMyInfo({ token: userToken })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting my video rating', function () {
|
||||
let command: UsersCommand
|
||||
|
||||
before(function () {
|
||||
command = server.users
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await command.getMyRating({ token: 'fake_token', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect video uuid', async function () {
|
||||
await command.getMyRating({ videoId: 'blabla', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown video', async function () {
|
||||
await command.getMyRating({ videoId: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await command.getMyRating({ videoId: video.id })
|
||||
await command.getMyRating({ videoId: video.uuid })
|
||||
await command.getMyRating({ videoId: video.shortUUID })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When retrieving my global ratings', function () {
|
||||
const path = '/api/v1/accounts/user1/ratings'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, userToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, userToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, userToken)
|
||||
})
|
||||
|
||||
it('Should fail with a unauthenticated user', async function () {
|
||||
await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a another user', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad type', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userToken,
|
||||
query: { rating: 'toto ' },
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: userToken, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting my global followers', function () {
|
||||
const path = '/api/v1/accounts/user1/followers'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, userToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, userToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, userToken)
|
||||
})
|
||||
|
||||
it('Should fail with a unauthenticated user', async function () {
|
||||
await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a another user', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: userToken, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When blocking/unblocking/removing user', function () {
|
||||
|
||||
it('Should fail with an incorrect id', async function () {
|
||||
const options = { userId: 'blabla' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }
|
||||
|
||||
await server.users.remove(options)
|
||||
await server.users.banUser({ userId: 'blabla' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await server.users.unbanUser({ userId: 'blabla' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with the root user', async function () {
|
||||
const options = { userId: rootId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }
|
||||
|
||||
await server.users.remove(options)
|
||||
await server.users.banUser(options)
|
||||
await server.users.unbanUser(options)
|
||||
})
|
||||
|
||||
it('Should return 404 with a non existing id', async function () {
|
||||
const options = { userId: 4545454, expectedStatus: HttpStatusCode.NOT_FOUND_404 }
|
||||
|
||||
await server.users.remove(options)
|
||||
await server.users.banUser(options)
|
||||
await server.users.unbanUser(options)
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
const options = { userId, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }
|
||||
|
||||
await server.users.remove(options)
|
||||
await server.users.banUser(options)
|
||||
await server.users.unbanUser(options)
|
||||
})
|
||||
|
||||
it('Should fail on a moderator with a moderator', async function () {
|
||||
const options = { userId: moderatorId, token: moderatorToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }
|
||||
|
||||
await server.users.remove(options)
|
||||
await server.users.banUser(options)
|
||||
await server.users.unbanUser(options)
|
||||
})
|
||||
|
||||
it('Should succeed on a user with a moderator', async function () {
|
||||
const options = { userId, token: moderatorToken }
|
||||
|
||||
await server.users.banUser(options)
|
||||
await server.users.unbanUser(options)
|
||||
})
|
||||
})
|
||||
|
||||
describe('When deleting our account', function () {
|
||||
|
||||
it('Should fail with with the root account', async function () {
|
||||
await server.users.deleteMe({ expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
MockSmtpServer.Instance.kill()
|
||||
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,490 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { HttpStatusCode, PeerTubePlugin, PluginType } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
makePutBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test server plugins API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken = null
|
||||
|
||||
const npmPlugin = 'peertube-plugin-hello-world'
|
||||
const pluginName = 'hello-world'
|
||||
let npmVersion: string
|
||||
|
||||
const themePlugin = 'peertube-theme-background-red'
|
||||
const themeName = 'background-red'
|
||||
let themeVersion: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
const user = {
|
||||
username: 'user1',
|
||||
password: 'password'
|
||||
}
|
||||
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
userAccessToken = await server.login.getAccessToken(user)
|
||||
|
||||
{
|
||||
const res = await server.plugins.install({ npmName: npmPlugin })
|
||||
const plugin = res.body as PeerTubePlugin
|
||||
npmVersion = plugin.version
|
||||
}
|
||||
|
||||
{
|
||||
const res = await server.plugins.install({ npmName: themePlugin })
|
||||
const plugin = res.body as PeerTubePlugin
|
||||
themeVersion = plugin.version
|
||||
}
|
||||
})
|
||||
|
||||
describe('With static plugin routes', function () {
|
||||
it('Should fail with an unknown plugin name/plugin version', async function () {
|
||||
const paths = [
|
||||
'/plugins/' + pluginName + '/0.0.1/auth/fake-auth',
|
||||
'/plugins/' + pluginName + '/0.0.1/static/images/chocobo.png',
|
||||
'/plugins/' + pluginName + '/0.0.1/client-scripts/client/common-client-plugin.js',
|
||||
'/themes/' + themeName + '/0.0.1/static/images/chocobo.png',
|
||||
'/themes/' + themeName + '/0.0.1/client-scripts/client/video-watch-client-plugin.js',
|
||||
'/themes/' + themeName + '/0.0.1/css/assets/style1.css'
|
||||
]
|
||||
|
||||
for (const p of paths) {
|
||||
await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail when requesting a plugin in the theme path', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: '/themes/' + pluginName + '/' + npmVersion + '/static/images/chocobo.png',
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with invalid versions', async function () {
|
||||
const paths = [
|
||||
'/plugins/' + pluginName + '/0.0.1.1/auth/fake-auth',
|
||||
'/plugins/' + pluginName + '/0.0.1.1/static/images/chocobo.png',
|
||||
'/plugins/' + pluginName + '/0.1/client-scripts/client/common-client-plugin.js',
|
||||
'/themes/' + themeName + '/1/static/images/chocobo.png',
|
||||
'/themes/' + themeName + '/0.0.1000a/client-scripts/client/video-watch-client-plugin.js',
|
||||
'/themes/' + themeName + '/0.a.1/css/assets/style1.css'
|
||||
]
|
||||
|
||||
for (const p of paths) {
|
||||
await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with invalid paths', async function () {
|
||||
const paths = [
|
||||
'/plugins/' + pluginName + '/' + npmVersion + '/static/images/../chocobo.png',
|
||||
'/plugins/' + pluginName + '/' + npmVersion + '/client-scripts/h/o/../client/common-client-plugin.js',
|
||||
'/themes/' + themeName + '/' + themeVersion + '/static/hola/a/../images/chocobo.png',
|
||||
'/themes/' + themeName + '/' + themeVersion + '/client-scripts/client/video-watch-client-plugin.js/..',
|
||||
'/themes/' + themeName + '/' + themeVersion + '/css/hiha//j../assets/style1.css'
|
||||
]
|
||||
|
||||
for (const p of paths) {
|
||||
await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an unknown auth name', async function () {
|
||||
const path = '/plugins/' + pluginName + '/' + npmVersion + '/auth/bad-auth'
|
||||
|
||||
await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown static file', async function () {
|
||||
const paths = [
|
||||
'/plugins/' + pluginName + '/' + npmVersion + '/static/fake/chocobo.png',
|
||||
'/plugins/' + pluginName + '/' + npmVersion + '/client-scripts/client/fake.js',
|
||||
'/themes/' + themeName + '/' + themeVersion + '/static/fake/chocobo.png',
|
||||
'/themes/' + themeName + '/' + themeVersion + '/client-scripts/client/fake.js'
|
||||
]
|
||||
|
||||
for (const p of paths) {
|
||||
await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an unknown CSS file', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: '/themes/' + themeName + '/' + themeVersion + '/css/assets/fake.css',
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
const paths = [
|
||||
'/plugins/' + pluginName + '/' + npmVersion + '/static/images/chocobo.png',
|
||||
'/plugins/' + pluginName + '/' + npmVersion + '/client-scripts/client/common-client-plugin.js',
|
||||
'/themes/' + themeName + '/' + themeVersion + '/static/images/chocobo.png',
|
||||
'/themes/' + themeName + '/' + themeVersion + '/client-scripts/client/video-watch-client-plugin.js',
|
||||
'/themes/' + themeName + '/' + themeVersion + '/css/assets/style1.css'
|
||||
]
|
||||
|
||||
for (const p of paths) {
|
||||
await makeGetRequest({ url: server.url, path: p, expectedStatus: HttpStatusCode.OK_200 })
|
||||
}
|
||||
|
||||
const authPath = '/plugins/' + pluginName + '/' + npmVersion + '/auth/fake-auth'
|
||||
await makeGetRequest({ url: server.url, path: authPath, expectedStatus: HttpStatusCode.FOUND_302 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing available plugins/themes', function () {
|
||||
const path = '/api/v1/plugins/available'
|
||||
const baseQuery = {
|
||||
search: 'super search',
|
||||
pluginType: PluginType.PLUGIN,
|
||||
currentPeerTubeEngine: '1.2.3'
|
||||
}
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: 'fake_token',
|
||||
query: baseQuery,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userAccessToken,
|
||||
query: baseQuery,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid plugin type', async function () {
|
||||
const query = { ...baseQuery, pluginType: 5 }
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
query
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid current peertube engine', async function () {
|
||||
const query = { ...baseQuery, currentPeerTubeEngine: '1.0' }
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
query
|
||||
})
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
query: baseQuery,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing local plugins/themes', function () {
|
||||
const path = '/api/v1/plugins'
|
||||
const baseQuery = {
|
||||
pluginType: PluginType.THEME
|
||||
}
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: 'fake_token',
|
||||
query: baseQuery,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userAccessToken,
|
||||
query: baseQuery,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid plugin type', async function () {
|
||||
const query = { ...baseQuery, pluginType: 5 }
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
query
|
||||
})
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
query: baseQuery,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting a plugin or the registered settings or public settings', function () {
|
||||
const path = '/api/v1/plugins/'
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
for (const suffix of [ npmPlugin, `${npmPlugin}/registered-settings` ]) {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + suffix,
|
||||
token: 'fake_token',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
for (const suffix of [ npmPlugin, `${npmPlugin}/registered-settings` ]) {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + suffix,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an invalid npm name', async function () {
|
||||
for (const suffix of [ 'toto', 'toto/registered-settings', 'toto/public-settings' ]) {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + suffix,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
}
|
||||
|
||||
for (const suffix of [ 'peertube-plugin-TOTO', 'peertube-plugin-TOTO/registered-settings', 'peertube-plugin-TOTO/public-settings' ]) {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + suffix,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an unknown plugin', async function () {
|
||||
for (const suffix of [ 'peertube-plugin-toto', 'peertube-plugin-toto/registered-settings', 'peertube-plugin-toto/public-settings' ]) {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + suffix,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
for (const suffix of [ npmPlugin, `${npmPlugin}/registered-settings`, `${npmPlugin}/public-settings` ]) {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + suffix,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating plugin settings', function () {
|
||||
const path = '/api/v1/plugins/'
|
||||
const settings = { setting1: 'value1' }
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + npmPlugin + '/settings',
|
||||
fields: { settings },
|
||||
token: 'fake_token',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + npmPlugin + '/settings',
|
||||
fields: { settings },
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid npm name', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + 'toto/settings',
|
||||
fields: { settings },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + 'peertube-plugin-TOTO/settings',
|
||||
fields: { settings },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown plugin', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + 'peertube-plugin-toto/settings',
|
||||
fields: { settings },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + npmPlugin + '/settings',
|
||||
fields: { settings },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When installing/updating/uninstalling a plugin', function () {
|
||||
const path = '/api/v1/plugins/'
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
for (const suffix of [ 'install', 'update', 'uninstall' ]) {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + suffix,
|
||||
fields: { npmName: npmPlugin },
|
||||
token: 'fake_token',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
for (const suffix of [ 'install', 'update', 'uninstall' ]) {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + suffix,
|
||||
fields: { npmName: npmPlugin },
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an invalid npm name', async function () {
|
||||
for (const suffix of [ 'install', 'update', 'uninstall' ]) {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + suffix,
|
||||
fields: { npmName: 'toto' },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
}
|
||||
|
||||
for (const suffix of [ 'install', 'update', 'uninstall' ]) {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + suffix,
|
||||
fields: { npmName: 'peertube-plugin-TOTO' },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
const it = [
|
||||
{ suffix: 'install', status: HttpStatusCode.OK_200 },
|
||||
{ suffix: 'update', status: HttpStatusCode.OK_200 },
|
||||
{ suffix: 'uninstall', status: HttpStatusCode.NO_CONTENT_204 }
|
||||
]
|
||||
|
||||
for (const obj of it) {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + obj.suffix,
|
||||
fields: { npmName: npmPlugin },
|
||||
token: server.accessToken,
|
||||
expectedStatus: obj.status
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,240 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { HttpStatusCode, VideoCreateResult } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createMultipleServers,
|
||||
doubleFollow,
|
||||
makeDeleteRequest,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
makePutBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test server redundancy API validators', function () {
|
||||
let servers: PeerTubeServer[]
|
||||
let userAccessToken = null
|
||||
let videoIdLocal: number
|
||||
let videoRemote: VideoCreateResult
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(240000)
|
||||
|
||||
servers = await createMultipleServers(2)
|
||||
|
||||
await setAccessTokensToServers(servers)
|
||||
await doubleFollow(servers[0], servers[1])
|
||||
|
||||
const user = {
|
||||
username: 'user1',
|
||||
password: 'password'
|
||||
}
|
||||
|
||||
await servers[0].users.create({ username: user.username, password: user.password })
|
||||
userAccessToken = await servers[0].login.getAccessToken(user)
|
||||
|
||||
videoIdLocal = (await servers[0].videos.quickUpload({ name: 'video' })).id
|
||||
|
||||
const remoteUUID = (await servers[1].videos.quickUpload({ name: 'video' })).uuid
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
videoRemote = await servers[0].videos.get({ id: remoteUUID })
|
||||
})
|
||||
|
||||
describe('When listing redundancies', function () {
|
||||
const path = '/api/v1/server/redundancy/videos'
|
||||
|
||||
let url: string
|
||||
let token: string
|
||||
|
||||
before(function () {
|
||||
url = servers[0].url
|
||||
token = servers[0].accessToken
|
||||
})
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
await makeGetRequest({ url, path, token: 'fake_token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makeGetRequest({ url, path, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(url, path, servers[0].accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(url, path, servers[0].accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(url, path, servers[0].accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad target', async function () {
|
||||
await makeGetRequest({ url, path, token, query: { target: 'bad target' } })
|
||||
})
|
||||
|
||||
it('Should fail without target', async function () {
|
||||
await makeGetRequest({ url, path, token })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeGetRequest({ url, path, token, query: { target: 'my-videos' }, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When manually adding a redundancy', function () {
|
||||
const path = '/api/v1/server/redundancy/videos'
|
||||
|
||||
let url: string
|
||||
let token: string
|
||||
|
||||
before(function () {
|
||||
url = servers[0].url
|
||||
token = servers[0].accessToken
|
||||
})
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
await makePostBodyRequest({ url, path, token: 'fake_token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makePostBodyRequest({ url, path, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail without a video id', async function () {
|
||||
await makePostBodyRequest({ url, path, token })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect video id', async function () {
|
||||
await makePostBodyRequest({ url, path, token, fields: { videoId: 'peertube' } })
|
||||
})
|
||||
|
||||
it('Should fail with a not found video id', async function () {
|
||||
await makePostBodyRequest({ url, path, token, fields: { videoId: 6565 }, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a local a video id', async function () {
|
||||
await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdLocal } })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makePostBodyRequest({
|
||||
url,
|
||||
path,
|
||||
token,
|
||||
fields: { videoId: videoRemote.shortUUID },
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the video is already duplicated', async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
await makePostBodyRequest({
|
||||
url,
|
||||
path,
|
||||
token,
|
||||
fields: { videoId: videoRemote.uuid },
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When manually removing a redundancy', function () {
|
||||
const path = '/api/v1/server/redundancy/videos/'
|
||||
|
||||
let url: string
|
||||
let token: string
|
||||
|
||||
before(function () {
|
||||
url = servers[0].url
|
||||
token = servers[0].accessToken
|
||||
})
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
await makeDeleteRequest({ url, path: path + '1', token: 'fake_token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makeDeleteRequest({ url, path: path + '1', token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect video id', async function () {
|
||||
await makeDeleteRequest({ url, path: path + 'toto', token })
|
||||
})
|
||||
|
||||
it('Should fail with a not found video redundancy', async function () {
|
||||
await makeDeleteRequest({ url, path: path + '454545', token, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating server redundancy', function () {
|
||||
const path = '/api/v1/server/redundancy'
|
||||
|
||||
it('Should fail with an invalid token', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: servers[0].url,
|
||||
path: path + '/' + servers[1].host,
|
||||
fields: { redundancyAllowed: true },
|
||||
token: 'fake_token',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user is not an administrator', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: servers[0].url,
|
||||
path: path + '/' + servers[1].host,
|
||||
fields: { redundancyAllowed: true },
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if we do not follow this server', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: servers[0].url,
|
||||
path: path + '/example.com',
|
||||
fields: { redundancyAllowed: true },
|
||||
token: servers[0].accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without de redundancyAllowed param', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: servers[0].url,
|
||||
path: path + '/' + servers[1].host,
|
||||
fields: { blabla: true },
|
||||
token: servers[0].accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: servers[0].url,
|
||||
path: path + '/' + servers[1].host,
|
||||
fields: { redundancyAllowed: true },
|
||||
token: servers[0].accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests(servers)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,446 @@
|
||||
import { omit } from '@peertube/peertube-core-utils'
|
||||
import { HttpStatusCode, HttpStatusCodeType, UserRole } from '@peertube/peertube-models'
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makePostBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
setDefaultAccountAvatar,
|
||||
setDefaultChannelAvatar
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test registrations API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
let userToken: string
|
||||
let moderatorToken: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultAccountAvatar([ server ])
|
||||
await setDefaultChannelAvatar([ server ])
|
||||
|
||||
await server.config.enableSignup(false);
|
||||
|
||||
({ token: moderatorToken } = await server.users.generate('moderator', UserRole.MODERATOR));
|
||||
({ token: userToken } = await server.users.generate('user', UserRole.USER))
|
||||
})
|
||||
|
||||
describe('Register', function () {
|
||||
const registrationPath = '/api/v1/users/register'
|
||||
const registrationRequestPath = '/api/v1/users/registrations/request'
|
||||
|
||||
const baseCorrectParams = {
|
||||
username: 'user3',
|
||||
displayName: 'super user',
|
||||
email: 'test3@example.com',
|
||||
password: 'my super password',
|
||||
registrationReason: 'my super registration reason'
|
||||
}
|
||||
|
||||
describe('When registering a new user or requesting user registration', function () {
|
||||
|
||||
async function check (fields: any, expectedStatus: HttpStatusCodeType = HttpStatusCode.BAD_REQUEST_400) {
|
||||
await server.config.enableSignup(false)
|
||||
await makePostBodyRequest({ url: server.url, path: registrationPath, fields, expectedStatus })
|
||||
|
||||
await server.config.enableSignup(true)
|
||||
await makePostBodyRequest({ url: server.url, path: registrationRequestPath, fields, expectedStatus })
|
||||
}
|
||||
|
||||
it('Should fail with a too small username', async function () {
|
||||
const fields = { ...baseCorrectParams, username: '' }
|
||||
|
||||
await check(fields)
|
||||
})
|
||||
|
||||
it('Should fail with a too long username', async function () {
|
||||
const fields = { ...baseCorrectParams, username: 'super'.repeat(50) }
|
||||
|
||||
await check(fields)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect username', async function () {
|
||||
const fields = { ...baseCorrectParams, username: 'my username' }
|
||||
|
||||
await check(fields)
|
||||
})
|
||||
|
||||
it('Should fail with a missing email', async function () {
|
||||
const fields = omit(baseCorrectParams, [ 'email' ])
|
||||
|
||||
await check(fields)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid email', async function () {
|
||||
const fields = { ...baseCorrectParams, email: 'test_example.com' }
|
||||
|
||||
await check(fields)
|
||||
})
|
||||
|
||||
it('Should fail with a too small password', async function () {
|
||||
const fields = { ...baseCorrectParams, password: 'bla' }
|
||||
|
||||
await check(fields)
|
||||
})
|
||||
|
||||
it('Should fail with a too long password', async function () {
|
||||
const fields = { ...baseCorrectParams, password: 'super'.repeat(61) }
|
||||
|
||||
await check(fields)
|
||||
})
|
||||
|
||||
it('Should fail if we register a user with the same username', async function () {
|
||||
const fields = { ...baseCorrectParams, username: 'root' }
|
||||
|
||||
await check(fields, HttpStatusCode.CONFLICT_409)
|
||||
})
|
||||
|
||||
it('Should fail with a "peertube" username', async function () {
|
||||
const fields = { ...baseCorrectParams, username: 'peertube' }
|
||||
|
||||
await check(fields, HttpStatusCode.CONFLICT_409)
|
||||
})
|
||||
|
||||
it('Should fail if we register a user with the same email', async function () {
|
||||
const fields = { ...baseCorrectParams, email: 'admin' + server.internalServerNumber + '@example.com' }
|
||||
|
||||
await check(fields, HttpStatusCode.CONFLICT_409)
|
||||
})
|
||||
|
||||
it('Should fail with a bad display name', async function () {
|
||||
const fields = { ...baseCorrectParams, displayName: 'a'.repeat(150) }
|
||||
|
||||
await check(fields)
|
||||
})
|
||||
|
||||
it('Should fail with a bad channel name', async function () {
|
||||
const fields = { ...baseCorrectParams, channel: { name: '[]azf', displayName: 'toto' } }
|
||||
|
||||
await check(fields)
|
||||
})
|
||||
|
||||
it('Should fail with a bad channel display name', async function () {
|
||||
const fields = { ...baseCorrectParams, channel: { name: 'toto', displayName: '' } }
|
||||
|
||||
await check(fields)
|
||||
})
|
||||
|
||||
it('Should fail with a channel name that is the same as username', async function () {
|
||||
const source = { username: 'super_user', channel: { name: 'super_user', displayName: 'display name' } }
|
||||
const fields = { ...baseCorrectParams, ...source }
|
||||
|
||||
await check(fields)
|
||||
})
|
||||
|
||||
it('Should fail with an existing channel', async function () {
|
||||
const attributes = { name: 'existing_channel', displayName: 'hello', description: 'super description' }
|
||||
await server.channels.create({ attributes })
|
||||
|
||||
const fields = { ...baseCorrectParams, channel: { name: 'existing_channel', displayName: 'toto' } }
|
||||
|
||||
await check(fields, HttpStatusCode.CONFLICT_409)
|
||||
})
|
||||
|
||||
it('Should fail on a server with registration disabled', async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
signup: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await server.registrations.register({ username: 'user4', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
await server.registrations.requestRegistration({
|
||||
username: 'user4',
|
||||
registrationReason: 'reason',
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the user limit is reached', async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
const { total } = await server.users.list()
|
||||
|
||||
await server.config.enableSignup(false, total)
|
||||
await server.registrations.register({ username: 'user42', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
|
||||
await server.config.enableSignup(true, total)
|
||||
await server.registrations.requestRegistration({
|
||||
username: 'user42',
|
||||
registrationReason: 'reason',
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed if the user limit is not reached', async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
const { total } = await server.users.list()
|
||||
|
||||
await server.config.enableSignup(false, total + 1)
|
||||
await server.registrations.register({ username: 'user43', expectedStatus: HttpStatusCode.NO_CONTENT_204 })
|
||||
|
||||
await server.config.enableSignup(true, total + 2)
|
||||
await server.registrations.requestRegistration({
|
||||
username: 'user44',
|
||||
registrationReason: 'reason',
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('On direct registration', function () {
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.config.enableSignup(false)
|
||||
|
||||
const fields = {
|
||||
username: 'user_direct_1',
|
||||
displayName: 'super user direct 1',
|
||||
email: 'user_direct_1@example.com',
|
||||
password: 'my super password',
|
||||
channel: { name: 'super_user_direct_1_channel', displayName: 'super user direct 1 channel' }
|
||||
}
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path: registrationPath, fields, expectedStatus: HttpStatusCode.NO_CONTENT_204 })
|
||||
})
|
||||
|
||||
it('Should fail if the instance requires approval', async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
await server.config.enableSignup(true)
|
||||
await server.registrations.register({ username: 'user42', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('On registration request', function () {
|
||||
|
||||
before(async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
await server.config.enableSignup(true)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid registration reason', async function () {
|
||||
for (const registrationReason of [ '', 't', 't'.repeat(5000) ]) {
|
||||
await server.registrations.requestRegistration({
|
||||
username: 'user_request_1',
|
||||
registrationReason,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.registrations.requestRegistration({
|
||||
username: 'user_request_2',
|
||||
registrationReason: 'tt',
|
||||
channel: {
|
||||
displayName: 'my user request 2 channel',
|
||||
name: 'user_request_2_channel'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the username is already awaiting registration approval', async function () {
|
||||
await server.registrations.requestRegistration({
|
||||
username: 'user_request_2',
|
||||
registrationReason: 'tt',
|
||||
channel: {
|
||||
displayName: 'my user request 42 channel',
|
||||
name: 'user_request_42_channel'
|
||||
},
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the email is already awaiting registration approval', async function () {
|
||||
await server.registrations.requestRegistration({
|
||||
username: 'user42',
|
||||
email: 'user_request_2@example.com',
|
||||
registrationReason: 'tt',
|
||||
channel: {
|
||||
displayName: 'my user request 42 channel',
|
||||
name: 'user_request_42_channel'
|
||||
},
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the channel is already awaiting registration approval', async function () {
|
||||
await server.registrations.requestRegistration({
|
||||
username: 'user42',
|
||||
registrationReason: 'tt',
|
||||
channel: {
|
||||
displayName: 'my user request 2 channel',
|
||||
name: 'user_request_2_channel'
|
||||
},
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if the instance does not require approval', async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
await server.config.enableSignup(false)
|
||||
|
||||
await server.registrations.requestRegistration({
|
||||
username: 'user42',
|
||||
registrationReason: 'toto',
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Registrations accept/reject', function () {
|
||||
let id1: number
|
||||
let id2: number
|
||||
|
||||
before(async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
await server.config.enableSignup(true);
|
||||
|
||||
({ id: id1 } = await server.registrations.requestRegistration({ username: 'request_2', registrationReason: 'toto' }));
|
||||
({ id: id2 } = await server.registrations.requestRegistration({ username: 'request_3', registrationReason: 'toto' }))
|
||||
})
|
||||
|
||||
it('Should fail to accept/reject registration without token', async function () {
|
||||
const options = { id: id1, moderationResponse: 'tt', token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }
|
||||
await server.registrations.accept(options)
|
||||
await server.registrations.reject(options)
|
||||
})
|
||||
|
||||
it('Should fail to accept/reject registration with a non moderator user', async function () {
|
||||
const options = { id: id1, moderationResponse: 'tt', token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }
|
||||
await server.registrations.accept(options)
|
||||
await server.registrations.reject(options)
|
||||
})
|
||||
|
||||
it('Should fail to accept/reject registration with a bad registration id', async function () {
|
||||
{
|
||||
const options = { id: 't' as any, moderationResponse: 'tt', token: moderatorToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }
|
||||
await server.registrations.accept(options)
|
||||
await server.registrations.reject(options)
|
||||
}
|
||||
|
||||
{
|
||||
const options = { id: 42, moderationResponse: 'tt', token: moderatorToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 }
|
||||
await server.registrations.accept(options)
|
||||
await server.registrations.reject(options)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail to accept/reject registration with a bad moderation resposne', async function () {
|
||||
for (const moderationResponse of [ '', 't', 't'.repeat(5000) ]) {
|
||||
const options = { id: id1, moderationResponse, token: moderatorToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }
|
||||
await server.registrations.accept(options)
|
||||
await server.registrations.reject(options)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed to accept a registration', async function () {
|
||||
await server.registrations.accept({ id: id1, moderationResponse: 'tt', token: moderatorToken })
|
||||
})
|
||||
|
||||
it('Should succeed to reject a registration', async function () {
|
||||
await server.registrations.reject({ id: id2, moderationResponse: 'tt', token: moderatorToken })
|
||||
})
|
||||
|
||||
it('Should fail to accept/reject a registration that was already accepted/rejected', async function () {
|
||||
for (const id of [ id1, id2 ]) {
|
||||
const options = { id, moderationResponse: 'tt', token: moderatorToken, expectedStatus: HttpStatusCode.CONFLICT_409 }
|
||||
await server.registrations.accept(options)
|
||||
await server.registrations.reject(options)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Registrations deletion', function () {
|
||||
let id1: number
|
||||
let id2: number
|
||||
let id3: number
|
||||
|
||||
before(async function () {
|
||||
({ id: id1 } = await server.registrations.requestRegistration({ username: 'request_4', registrationReason: 'toto' }));
|
||||
({ id: id2 } = await server.registrations.requestRegistration({ username: 'request_5', registrationReason: 'toto' }));
|
||||
({ id: id3 } = await server.registrations.requestRegistration({ username: 'request_6', registrationReason: 'toto' }))
|
||||
|
||||
await server.registrations.accept({ id: id2, moderationResponse: 'tt' })
|
||||
await server.registrations.reject({ id: id3, moderationResponse: 'tt' })
|
||||
})
|
||||
|
||||
it('Should fail to delete registration without token', async function () {
|
||||
await server.registrations.delete({ id: id1, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail to delete registration with a non moderator user', async function () {
|
||||
await server.registrations.delete({ id: id1, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail to delete registration with a bad registration id', async function () {
|
||||
await server.registrations.delete({ id: 't' as any, token: moderatorToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await server.registrations.delete({ id: 42, token: moderatorToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.registrations.delete({ id: id1, token: moderatorToken })
|
||||
await server.registrations.delete({ id: id2, token: moderatorToken })
|
||||
await server.registrations.delete({ id: id3, token: moderatorToken })
|
||||
})
|
||||
})
|
||||
|
||||
describe('Listing registrations', function () {
|
||||
const path = '/api/v1/users/registrations'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await server.registrations.list({
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
await server.registrations.list({
|
||||
token: userToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.registrations.list({
|
||||
token: moderatorToken,
|
||||
search: 'toto'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,911 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
import { basename } from 'path'
|
||||
import {
|
||||
HttpStatusCode,
|
||||
HttpStatusCodeType,
|
||||
isVideoStudioTaskIntro,
|
||||
RunnerJob,
|
||||
RunnerJobState,
|
||||
RunnerJobStudioTranscodingPayload,
|
||||
RunnerJobSuccessPayload,
|
||||
RunnerJobUpdatePayload,
|
||||
VideoPrivacy,
|
||||
VideoStudioTaskIntro
|
||||
} from '@peertube/peertube-models'
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makePostBodyRequest,
|
||||
PeerTubeServer,
|
||||
sendRTMPStream,
|
||||
setAccessTokensToServers,
|
||||
setDefaultVideoChannel,
|
||||
stopFfmpeg,
|
||||
VideoStudioCommand,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
const badUUID = '910ec12a-d9e6-458b-a274-0abb655f9464'
|
||||
|
||||
describe('Test managing runners', function () {
|
||||
let server: PeerTubeServer
|
||||
|
||||
let userToken: string
|
||||
|
||||
let registrationTokenId: number
|
||||
let registrationToken: string
|
||||
|
||||
let runnerToken: string
|
||||
let runnerToken2: string
|
||||
|
||||
let completedJobToken: string
|
||||
let completedJobUUID: string
|
||||
|
||||
let cancelledJobToken: string
|
||||
let cancelledJobUUID: string
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
const config = {
|
||||
rates_limit: {
|
||||
api: {
|
||||
max: 5000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
server = await createSingleServer(1, config)
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultVideoChannel([ server ])
|
||||
|
||||
userToken = await server.users.generateUserAndToken('user1')
|
||||
|
||||
const { data } = await server.runnerRegistrationTokens.list()
|
||||
registrationToken = data[0].registrationToken
|
||||
registrationTokenId = data[0].id
|
||||
|
||||
await server.config.enableTranscoding({ hls: true, webVideo: true })
|
||||
await server.config.enableStudio()
|
||||
await server.config.enableRemoteTranscoding()
|
||||
await server.config.enableRemoteStudio()
|
||||
|
||||
runnerToken = await server.runners.autoRegisterRunner()
|
||||
runnerToken2 = await server.runners.autoRegisterRunner()
|
||||
|
||||
{
|
||||
await server.videos.quickUpload({ name: 'video 1' })
|
||||
await server.videos.quickUpload({ name: 'video 2' })
|
||||
|
||||
await waitJobs([ server ])
|
||||
|
||||
{
|
||||
const job = await server.runnerJobs.autoProcessWebVideoJob(runnerToken)
|
||||
completedJobToken = job.jobToken
|
||||
completedJobUUID = job.uuid
|
||||
}
|
||||
|
||||
{
|
||||
const { job } = await server.runnerJobs.autoAccept({ runnerToken })
|
||||
cancelledJobToken = job.jobToken
|
||||
cancelledJobUUID = job.uuid
|
||||
await server.runnerJobs.cancelByAdmin({ jobUUID: cancelledJobUUID })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
describe('Managing runner registration tokens', function () {
|
||||
|
||||
describe('Common', function () {
|
||||
|
||||
it('Should fail to generate, list or delete runner registration token without oauth token', async function () {
|
||||
const expectedStatus = HttpStatusCode.UNAUTHORIZED_401
|
||||
|
||||
await server.runnerRegistrationTokens.generate({ token: null, expectedStatus })
|
||||
await server.runnerRegistrationTokens.list({ token: null, expectedStatus })
|
||||
await server.runnerRegistrationTokens.delete({ token: null, id: registrationTokenId, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail to generate, list or delete runner registration token without admin rights', async function () {
|
||||
const expectedStatus = HttpStatusCode.FORBIDDEN_403
|
||||
|
||||
await server.runnerRegistrationTokens.generate({ token: userToken, expectedStatus })
|
||||
await server.runnerRegistrationTokens.list({ token: userToken, expectedStatus })
|
||||
await server.runnerRegistrationTokens.delete({ token: userToken, id: registrationTokenId, expectedStatus })
|
||||
})
|
||||
})
|
||||
|
||||
describe('Delete', function () {
|
||||
|
||||
it('Should fail to delete with a bad id', async function () {
|
||||
await server.runnerRegistrationTokens.delete({ id: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('List', function () {
|
||||
const path = '/api/v1/runners/registration-tokens'
|
||||
|
||||
it('Should fail to list with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail to list with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail to list with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should succeed to list with the correct params', async function () {
|
||||
await server.runnerRegistrationTokens.list({ start: 0, count: 5, sort: '-createdAt' })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Managing runners', function () {
|
||||
let toDeleteId: number
|
||||
|
||||
describe('Register', function () {
|
||||
const name = 'runner name'
|
||||
|
||||
it('Should fail with a bad registration token', async function () {
|
||||
const expectedStatus = HttpStatusCode.BAD_REQUEST_400
|
||||
|
||||
await server.runners.register({ name, registrationToken: 'a'.repeat(4000), expectedStatus })
|
||||
await server.runners.register({ name, registrationToken: null, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown registration token', async function () {
|
||||
await server.runners.register({ name, registrationToken: 'aaa', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad name', async function () {
|
||||
const expectedStatus = HttpStatusCode.BAD_REQUEST_400
|
||||
|
||||
await server.runners.register({ name: '', registrationToken, expectedStatus })
|
||||
await server.runners.register({ name: 'a'.repeat(200), registrationToken, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid description', async function () {
|
||||
const expectedStatus = HttpStatusCode.BAD_REQUEST_400
|
||||
|
||||
await server.runners.register({ name, description: '', registrationToken, expectedStatus })
|
||||
await server.runners.register({ name, description: 'a'.repeat(5000), registrationToken, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const { id } = await server.runners.register({ name, description: 'super description', registrationToken })
|
||||
|
||||
toDeleteId = id
|
||||
})
|
||||
|
||||
it('Should fail with the same runner name', async function () {
|
||||
await server.runners.register({
|
||||
name,
|
||||
description: 'super description',
|
||||
registrationToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Delete', function () {
|
||||
|
||||
it('Should fail without oauth token', async function () {
|
||||
await server.runners.delete({ token: null, id: toDeleteId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail without admin rights', async function () {
|
||||
await server.runners.delete({ token: userToken, id: toDeleteId, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad id', async function () {
|
||||
await server.runners.delete({ id: 'hi' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown id', async function () {
|
||||
await server.runners.delete({ id: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.runners.delete({ id: toDeleteId })
|
||||
})
|
||||
})
|
||||
|
||||
describe('List', function () {
|
||||
const path = '/api/v1/runners'
|
||||
|
||||
it('Should fail without oauth token', async function () {
|
||||
await server.runners.list({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail without admin rights', async function () {
|
||||
await server.runners.list({ token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail to list with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail to list with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail to list with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid state', async function () {
|
||||
await server.runners.list({ start: 0, count: 5, sort: '-createdAt' })
|
||||
})
|
||||
|
||||
it('Should succeed to list with the correct params', async function () {
|
||||
await server.runners.list({ start: 0, count: 5, sort: '-createdAt' })
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('Runner jobs by admin', function () {
|
||||
|
||||
describe('Cancel', function () {
|
||||
let jobUUID: string
|
||||
|
||||
before(async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
await server.videos.quickUpload({ name: 'video' })
|
||||
await waitJobs([ server ])
|
||||
|
||||
const { availableJobs } = await server.runnerJobs.request({ runnerToken })
|
||||
jobUUID = availableJobs[0].uuid
|
||||
})
|
||||
|
||||
it('Should fail without oauth token', async function () {
|
||||
await server.runnerJobs.cancelByAdmin({ token: null, jobUUID, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail without admin rights', async function () {
|
||||
await server.runnerJobs.cancelByAdmin({ token: userToken, jobUUID, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad job uuid', async function () {
|
||||
await server.runnerJobs.cancelByAdmin({ jobUUID: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown job uuid', async function () {
|
||||
const jobUUID = badUUID
|
||||
await server.runnerJobs.cancelByAdmin({ jobUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with an already cancelled job', async function () {
|
||||
await server.runnerJobs.cancelByAdmin({ jobUUID: cancelledJobUUID, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.runnerJobs.cancelByAdmin({ jobUUID })
|
||||
})
|
||||
})
|
||||
|
||||
describe('List', function () {
|
||||
const path = '/api/v1/runners/jobs'
|
||||
|
||||
it('Should fail without oauth token', async function () {
|
||||
await server.runnerJobs.list({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail without admin rights', async function () {
|
||||
await server.runnerJobs.list({ token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail to list with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail to list with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail to list with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid state', async function () {
|
||||
await server.runnerJobs.list({ start: 0, count: 5, sort: '-createdAt', stateOneOf: 42 as any })
|
||||
await server.runnerJobs.list({ start: 0, count: 5, sort: '-createdAt', stateOneOf: [ 42 ] as any })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.runnerJobs.list({ start: 0, count: 5, sort: '-createdAt', stateOneOf: [ RunnerJobState.COMPLETED ] })
|
||||
})
|
||||
})
|
||||
|
||||
describe('Delete', function () {
|
||||
let jobUUID: string
|
||||
|
||||
before(async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
await server.videos.quickUpload({ name: 'video' })
|
||||
await waitJobs([ server ])
|
||||
|
||||
const { availableJobs } = await server.runnerJobs.request({ runnerToken })
|
||||
jobUUID = availableJobs[0].uuid
|
||||
})
|
||||
|
||||
it('Should fail without oauth token', async function () {
|
||||
await server.runnerJobs.deleteByAdmin({ token: null, jobUUID, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail without admin rights', async function () {
|
||||
await server.runnerJobs.deleteByAdmin({ token: userToken, jobUUID, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad job uuid', async function () {
|
||||
await server.runnerJobs.deleteByAdmin({ jobUUID: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown job uuid', async function () {
|
||||
const jobUUID = badUUID
|
||||
await server.runnerJobs.deleteByAdmin({ jobUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.runnerJobs.deleteByAdmin({ jobUUID })
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('Runner jobs by runners', function () {
|
||||
let jobUUID: string
|
||||
let jobToken: string
|
||||
let videoUUID: string
|
||||
|
||||
let jobUUID2: string
|
||||
let jobToken2: string
|
||||
|
||||
let videoUUID2: string
|
||||
|
||||
let pendingUUID: string
|
||||
|
||||
let videoStudioUUID: string
|
||||
let studioFile: string
|
||||
|
||||
let liveAcceptedJob: RunnerJob & { jobToken: string }
|
||||
let studioAcceptedJob: RunnerJob & { jobToken: string }
|
||||
|
||||
async function fetchVideoInputFiles (options: {
|
||||
jobUUID: string
|
||||
videoUUID: string
|
||||
runnerToken: string
|
||||
jobToken: string
|
||||
expectedStatus: HttpStatusCodeType
|
||||
}) {
|
||||
const { jobUUID, expectedStatus, videoUUID, runnerToken, jobToken } = options
|
||||
|
||||
const basePath = '/api/v1/runners/jobs/' + jobUUID + '/files/videos/' + videoUUID
|
||||
const paths = [ `${basePath}/max-quality`, `${basePath}/previews/max-quality` ]
|
||||
|
||||
for (const path of paths) {
|
||||
await makePostBodyRequest({ url: server.url, path, fields: { runnerToken, jobToken }, expectedStatus })
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchStudioFiles (options: {
|
||||
jobUUID: string
|
||||
videoUUID: string
|
||||
runnerToken: string
|
||||
jobToken: string
|
||||
studioFile?: string
|
||||
expectedStatus: HttpStatusCodeType
|
||||
}) {
|
||||
const { jobUUID, expectedStatus, videoUUID, runnerToken, jobToken, studioFile } = options
|
||||
|
||||
const path = `/api/v1/runners/jobs/${jobUUID}/files/videos/${videoUUID}/studio/task-files/${studioFile}`
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, fields: { runnerToken, jobToken }, expectedStatus })
|
||||
}
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
{
|
||||
await server.runnerJobs.cancelAllJobs({ state: RunnerJobState.PENDING })
|
||||
}
|
||||
|
||||
{
|
||||
const { uuid } = await server.videos.quickUpload({ name: 'video' })
|
||||
videoUUID = uuid
|
||||
|
||||
await waitJobs([ server ])
|
||||
|
||||
const { job } = await server.runnerJobs.autoAccept({ runnerToken })
|
||||
jobUUID = job.uuid
|
||||
jobToken = job.jobToken
|
||||
}
|
||||
|
||||
{
|
||||
const { uuid } = await server.videos.quickUpload({ name: 'video' })
|
||||
videoUUID2 = uuid
|
||||
|
||||
await waitJobs([ server ])
|
||||
|
||||
const { job } = await server.runnerJobs.autoAccept({ runnerToken: runnerToken2 })
|
||||
jobUUID2 = job.uuid
|
||||
jobToken2 = job.jobToken
|
||||
}
|
||||
|
||||
{
|
||||
await server.videos.quickUpload({ name: 'video' })
|
||||
await waitJobs([ server ])
|
||||
|
||||
const { availableJobs } = await server.runnerJobs.request({ runnerToken })
|
||||
pendingUUID = availableJobs[0].uuid
|
||||
}
|
||||
|
||||
{
|
||||
await server.config.disableTranscoding()
|
||||
|
||||
const { uuid } = await server.videos.quickUpload({ name: 'video studio' })
|
||||
videoStudioUUID = uuid
|
||||
|
||||
await server.config.enableTranscoding({ hls: true, webVideo: true })
|
||||
await server.config.enableStudio()
|
||||
|
||||
await server.videoStudio.createEditionTasks({
|
||||
videoId: videoStudioUUID,
|
||||
tasks: VideoStudioCommand.getComplexTask()
|
||||
})
|
||||
|
||||
const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'video-studio-transcoding' })
|
||||
studioAcceptedJob = job
|
||||
|
||||
const tasks = (job.payload as RunnerJobStudioTranscodingPayload).tasks
|
||||
const fileUrl = (tasks.find(t => isVideoStudioTaskIntro(t)) as VideoStudioTaskIntro).options.file as string
|
||||
studioFile = basename(fileUrl)
|
||||
}
|
||||
|
||||
{
|
||||
await server.config.enableLive({
|
||||
allowReplay: false,
|
||||
resolutions: 'max',
|
||||
transcoding: true
|
||||
})
|
||||
|
||||
const { live } = await server.live.quickCreate({ permanentLive: true, saveReplay: false, privacy: VideoPrivacy.PUBLIC })
|
||||
|
||||
const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey })
|
||||
await waitJobs([ server ])
|
||||
|
||||
await server.runnerJobs.requestLiveJob(runnerToken)
|
||||
|
||||
const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'live-rtmp-hls-transcoding' })
|
||||
liveAcceptedJob = job
|
||||
|
||||
await stopFfmpeg(ffmpegCommand)
|
||||
}
|
||||
})
|
||||
|
||||
describe('Common runner tokens validations', function () {
|
||||
|
||||
async function testEndpoints (options: {
|
||||
jobUUID: string
|
||||
runnerToken: string
|
||||
jobToken: string
|
||||
expectedStatus: HttpStatusCodeType
|
||||
}) {
|
||||
await server.runnerJobs.abort({ ...options, reason: 'reason' })
|
||||
await server.runnerJobs.update({ ...options })
|
||||
await server.runnerJobs.error({ ...options, message: 'message' })
|
||||
await server.runnerJobs.success({ ...options, payload: { videoFile: 'video_short.mp4' } })
|
||||
}
|
||||
|
||||
it('Should fail with an invalid job uuid', async function () {
|
||||
const options = { jobUUID: 'a', runnerToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }
|
||||
|
||||
await testEndpoints({ ...options, jobToken })
|
||||
await fetchVideoInputFiles({ ...options, videoUUID, jobToken })
|
||||
await fetchStudioFiles({ ...options, videoUUID, jobToken: studioAcceptedJob.jobToken, studioFile })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown job uuid', async function () {
|
||||
const options = { jobUUID: badUUID, runnerToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 }
|
||||
|
||||
await testEndpoints({ ...options, jobToken })
|
||||
await fetchVideoInputFiles({ ...options, videoUUID, jobToken })
|
||||
await fetchStudioFiles({ ...options, jobToken: studioAcceptedJob.jobToken, videoUUID, studioFile })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid runner token', async function () {
|
||||
const options = { runnerToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }
|
||||
|
||||
await testEndpoints({ ...options, jobUUID, jobToken })
|
||||
await fetchVideoInputFiles({ ...options, jobUUID, videoUUID, jobToken })
|
||||
await fetchStudioFiles({
|
||||
...options,
|
||||
jobToken: studioAcceptedJob.jobToken,
|
||||
jobUUID: studioAcceptedJob.uuid,
|
||||
videoUUID: videoStudioUUID,
|
||||
studioFile
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown runner token', async function () {
|
||||
const options = { runnerToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }
|
||||
|
||||
await testEndpoints({ ...options, jobUUID, jobToken })
|
||||
await fetchVideoInputFiles({ ...options, jobUUID, videoUUID, jobToken })
|
||||
await fetchStudioFiles({
|
||||
...options,
|
||||
jobToken: studioAcceptedJob.jobToken,
|
||||
jobUUID: studioAcceptedJob.uuid,
|
||||
videoUUID: videoStudioUUID,
|
||||
studioFile
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid job token job uuid', async function () {
|
||||
const options = { runnerToken, jobToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 }
|
||||
|
||||
await testEndpoints({ ...options, jobUUID })
|
||||
await fetchVideoInputFiles({ ...options, jobUUID, videoUUID })
|
||||
await fetchStudioFiles({ ...options, jobUUID: studioAcceptedJob.uuid, videoUUID: videoStudioUUID, studioFile })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown job token job uuid', async function () {
|
||||
const options = { runnerToken, jobToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 }
|
||||
|
||||
await testEndpoints({ ...options, jobUUID })
|
||||
await fetchVideoInputFiles({ ...options, jobUUID, videoUUID })
|
||||
await fetchStudioFiles({ ...options, jobUUID: studioAcceptedJob.uuid, videoUUID: videoStudioUUID, studioFile })
|
||||
})
|
||||
|
||||
it('Should fail with a runner token not associated to this job', async function () {
|
||||
const options = { runnerToken: runnerToken2, expectedStatus: HttpStatusCode.NOT_FOUND_404 }
|
||||
|
||||
await testEndpoints({ ...options, jobUUID, jobToken })
|
||||
await fetchVideoInputFiles({ ...options, jobUUID, videoUUID, jobToken })
|
||||
await fetchStudioFiles({
|
||||
...options,
|
||||
jobToken: studioAcceptedJob.jobToken,
|
||||
jobUUID: studioAcceptedJob.uuid,
|
||||
videoUUID: videoStudioUUID,
|
||||
studioFile
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a job uuid not associated to the job token', async function () {
|
||||
{
|
||||
const options = { jobUUID: jobUUID2, runnerToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 }
|
||||
|
||||
await testEndpoints({ ...options, jobToken })
|
||||
await fetchVideoInputFiles({ ...options, jobToken, videoUUID })
|
||||
await fetchStudioFiles({ ...options, jobToken: studioAcceptedJob.jobToken, videoUUID: videoStudioUUID, studioFile })
|
||||
}
|
||||
|
||||
{
|
||||
const options = { runnerToken, jobToken: jobToken2, expectedStatus: HttpStatusCode.NOT_FOUND_404 }
|
||||
|
||||
await testEndpoints({ ...options, jobUUID })
|
||||
await fetchVideoInputFiles({ ...options, jobUUID, videoUUID })
|
||||
await fetchStudioFiles({ ...options, jobUUID: studioAcceptedJob.uuid, videoUUID: videoStudioUUID, studioFile })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Unregister', function () {
|
||||
|
||||
it('Should fail without a runner token', async function () {
|
||||
await server.runners.unregister({ runnerToken: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad a runner token', async function () {
|
||||
await server.runners.unregister({ runnerToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown runner token', async function () {
|
||||
await server.runners.unregister({ runnerToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('Request', function () {
|
||||
|
||||
it('Should fail without a runner token', async function () {
|
||||
await server.runnerJobs.request({ runnerToken: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad a runner token', async function () {
|
||||
await server.runnerJobs.request({ runnerToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown runner token', async function () {
|
||||
await server.runnerJobs.request({ runnerToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('Accept', function () {
|
||||
|
||||
it('Should fail with a bad a job uuid', async function () {
|
||||
await server.runnerJobs.accept({ jobUUID: '', runnerToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown job uuid', async function () {
|
||||
await server.runnerJobs.accept({ jobUUID: badUUID, runnerToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a job not in pending state', async function () {
|
||||
await server.runnerJobs.accept({ jobUUID: completedJobUUID, runnerToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await server.runnerJobs.accept({ jobUUID: cancelledJobUUID, runnerToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail without a runner token', async function () {
|
||||
await server.runnerJobs.accept({ jobUUID: pendingUUID, runnerToken: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad a runner token', async function () {
|
||||
await server.runnerJobs.accept({ jobUUID: pendingUUID, runnerToken: '', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown runner token', async function () {
|
||||
await server.runnerJobs.accept({ jobUUID: pendingUUID, runnerToken: badUUID, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('Abort', function () {
|
||||
|
||||
it('Should fail without a reason', async function () {
|
||||
await server.runnerJobs.abort({ jobUUID, jobToken, runnerToken, reason: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad reason', async function () {
|
||||
const reason = 'reason'.repeat(5000)
|
||||
await server.runnerJobs.abort({ jobUUID, jobToken, runnerToken, reason, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a job not in processing state', async function () {
|
||||
await server.runnerJobs.abort({
|
||||
jobUUID: completedJobUUID,
|
||||
jobToken: completedJobToken,
|
||||
runnerToken,
|
||||
reason: 'reason',
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Update', function () {
|
||||
|
||||
describe('Common', function () {
|
||||
|
||||
it('Should fail with an invalid progress', async function () {
|
||||
await server.runnerJobs.update({ jobUUID, jobToken, runnerToken, progress: 101, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a job not in processing state', async function () {
|
||||
await server.runnerJobs.update({
|
||||
jobUUID: cancelledJobUUID,
|
||||
jobToken: cancelledJobToken,
|
||||
runnerToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Live RTMP to HLS', function () {
|
||||
const base: RunnerJobUpdatePayload = {
|
||||
masterPlaylistFile: 'live/master.m3u8',
|
||||
resolutionPlaylistFilename: '0.m3u8',
|
||||
resolutionPlaylistFile: 'live/1.m3u8',
|
||||
type: 'add-chunk',
|
||||
videoChunkFile: 'live/1-000069.ts',
|
||||
videoChunkFilename: '1-000068.ts'
|
||||
}
|
||||
|
||||
function testUpdate (payload: RunnerJobUpdatePayload) {
|
||||
return server.runnerJobs.update({
|
||||
jobUUID: liveAcceptedJob.uuid,
|
||||
jobToken: liveAcceptedJob.jobToken,
|
||||
payload,
|
||||
runnerToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
}
|
||||
|
||||
it('Should fail with an invalid resolutionPlaylistFilename', async function () {
|
||||
await testUpdate({ ...base, resolutionPlaylistFilename: undefined })
|
||||
await testUpdate({ ...base, resolutionPlaylistFilename: 'coucou/hello' })
|
||||
await testUpdate({ ...base, resolutionPlaylistFilename: 'hello' })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid videoChunkFilename', async function () {
|
||||
await testUpdate({ ...base, resolutionPlaylistFilename: undefined })
|
||||
await testUpdate({ ...base, resolutionPlaylistFilename: 'coucou/hello' })
|
||||
await testUpdate({ ...base, resolutionPlaylistFilename: 'hello' })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid type', async function () {
|
||||
await testUpdate({ ...base, type: undefined })
|
||||
await testUpdate({ ...base, type: 'toto' as any })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Error', function () {
|
||||
|
||||
it('Should fail with a missing error message', async function () {
|
||||
await server.runnerJobs.error({ jobUUID, jobToken, runnerToken, message: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid error messgae', async function () {
|
||||
const message = 'a'.repeat(6000)
|
||||
await server.runnerJobs.error({ jobUUID, jobToken, runnerToken, message, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a job not in processing state', async function () {
|
||||
await server.runnerJobs.error({
|
||||
jobUUID: completedJobUUID,
|
||||
jobToken: completedJobToken,
|
||||
message: 'my message',
|
||||
runnerToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Success', function () {
|
||||
let vodJobUUID: string
|
||||
let vodJobToken: string
|
||||
|
||||
describe('Common', function () {
|
||||
|
||||
it('Should fail with a job not in processing state', async function () {
|
||||
await server.runnerJobs.success({
|
||||
jobUUID: completedJobUUID,
|
||||
jobToken: completedJobToken,
|
||||
payload: { videoFile: 'video_short.mp4' },
|
||||
runnerToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('VOD', function () {
|
||||
|
||||
it('Should fail with an invalid vod web video payload', async function () {
|
||||
const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'vod-web-video-transcoding' })
|
||||
|
||||
await server.runnerJobs.success({
|
||||
jobUUID: job.uuid,
|
||||
jobToken: job.jobToken,
|
||||
payload: { hello: 'video_short.mp4' } as any,
|
||||
runnerToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
vodJobUUID = job.uuid
|
||||
vodJobToken = job.jobToken
|
||||
})
|
||||
|
||||
it('Should fail with an invalid vod hls payload', async function () {
|
||||
// To create HLS jobs
|
||||
const payload: RunnerJobSuccessPayload = { videoFile: 'video_short.mp4' }
|
||||
await server.runnerJobs.success({ runnerToken, jobUUID: vodJobUUID, jobToken: vodJobToken, payload })
|
||||
|
||||
await waitJobs([ server ])
|
||||
|
||||
const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'vod-hls-transcoding' })
|
||||
|
||||
await server.runnerJobs.success({
|
||||
jobUUID: job.uuid,
|
||||
jobToken: job.jobToken,
|
||||
payload: { videoFile: 'video_short.mp4' } as any,
|
||||
runnerToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid vod audio merge payload', async function () {
|
||||
const attributes = { name: 'audio_with_preview', previewfile: 'custom-preview.jpg', fixture: 'sample.ogg' }
|
||||
await server.videos.upload({ attributes, mode: 'legacy' })
|
||||
|
||||
await waitJobs([ server ])
|
||||
|
||||
const { job } = await server.runnerJobs.autoAccept({ runnerToken, type: 'vod-audio-merge-transcoding' })
|
||||
|
||||
await server.runnerJobs.success({
|
||||
jobUUID: job.uuid,
|
||||
jobToken: job.jobToken,
|
||||
payload: { hello: 'video_short.mp4' } as any,
|
||||
runnerToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Video studio', function () {
|
||||
|
||||
it('Should fail with an invalid video studio transcoding payload', async function () {
|
||||
await server.runnerJobs.success({
|
||||
jobUUID: studioAcceptedJob.uuid,
|
||||
jobToken: studioAcceptedJob.jobToken,
|
||||
payload: { hello: 'video_short.mp4' } as any,
|
||||
runnerToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Job files', function () {
|
||||
|
||||
describe('Check video param for common job file routes', function () {
|
||||
|
||||
async function fetchFiles (options: {
|
||||
videoUUID?: string
|
||||
expectedStatus: HttpStatusCodeType
|
||||
}) {
|
||||
await fetchVideoInputFiles({ videoUUID, ...options, jobToken, jobUUID, runnerToken })
|
||||
|
||||
await fetchStudioFiles({
|
||||
videoUUID: videoStudioUUID,
|
||||
|
||||
...options,
|
||||
|
||||
jobToken: studioAcceptedJob.jobToken,
|
||||
jobUUID: studioAcceptedJob.uuid,
|
||||
runnerToken,
|
||||
studioFile
|
||||
})
|
||||
}
|
||||
|
||||
it('Should fail with an invalid video id', async function () {
|
||||
await fetchFiles({
|
||||
videoUUID: 'a',
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown video id', async function () {
|
||||
const videoUUID = '910ec12a-d9e6-458b-a274-0abb655f9464'
|
||||
|
||||
await fetchFiles({
|
||||
videoUUID,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a video id not associated to this job', async function () {
|
||||
await fetchFiles({
|
||||
videoUUID: videoUUID2,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await fetchFiles({ expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('Video studio tasks file routes', function () {
|
||||
|
||||
it('Should fail with an invalid studio filename', async function () {
|
||||
await fetchStudioFiles({
|
||||
videoUUID: videoStudioUUID,
|
||||
jobUUID: studioAcceptedJob.uuid,
|
||||
runnerToken,
|
||||
jobToken: studioAcceptedJob.jobToken,
|
||||
studioFile: 'toto',
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,278 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
function updateSearchIndex (server: PeerTubeServer, enabled: boolean, disableLocalSearch = false) {
|
||||
return server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
search: {
|
||||
searchIndex: {
|
||||
enabled,
|
||||
disableLocalSearch
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
describe('Test videos API validator', function () {
|
||||
let server: PeerTubeServer
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
await setAccessTokensToServers([ server ])
|
||||
})
|
||||
|
||||
describe('When searching videos', function () {
|
||||
const path = '/api/v1/search/videos/'
|
||||
|
||||
const query = {
|
||||
search: 'coucou'
|
||||
}
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, null, query)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, null, query)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, null, query)
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path, query, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid category', async function () {
|
||||
const customQuery1 = { ...query, categoryOneOf: [ 'aa', 'b' ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
const customQuery2 = { ...query, categoryOneOf: 'a' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with a valid category', async function () {
|
||||
const customQuery1 = { ...query, categoryOneOf: [ 1, 7 ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.OK_200 })
|
||||
|
||||
const customQuery2 = { ...query, categoryOneOf: 1 }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid licence', async function () {
|
||||
const customQuery1 = { ...query, licenceOneOf: [ 'aa', 'b' ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
const customQuery2 = { ...query, licenceOneOf: 'a' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with a valid licence', async function () {
|
||||
const customQuery1 = { ...query, licenceOneOf: [ 1, 2 ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.OK_200 })
|
||||
|
||||
const customQuery2 = { ...query, licenceOneOf: 1 }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
||||
it('Should succeed with a valid language', async function () {
|
||||
const customQuery1 = { ...query, languageOneOf: [ 'fr', 'en' ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.OK_200 })
|
||||
|
||||
const customQuery2 = { ...query, languageOneOf: 'fr' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
||||
it('Should succeed with valid tags', async function () {
|
||||
const customQuery1 = { ...query, tagsOneOf: [ 'tag1', 'tag2' ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.OK_200 })
|
||||
|
||||
const customQuery2 = { ...query, tagsOneOf: 'tag1' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.OK_200 })
|
||||
|
||||
const customQuery3 = { ...query, tagsAllOf: [ 'tag1', 'tag2' ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery3, expectedStatus: HttpStatusCode.OK_200 })
|
||||
|
||||
const customQuery4 = { ...query, tagsAllOf: 'tag1' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery4, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
||||
it('Should fail with invalid durations', async function () {
|
||||
const customQuery1 = { ...query, durationMin: 'hello' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
const customQuery2 = { ...query, durationMax: 'hello' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with invalid dates', async function () {
|
||||
const customQuery1 = { ...query, startDate: 'hello' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
const customQuery2 = { ...query, endDate: 'hello' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery2, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
const customQuery3 = { ...query, originallyPublishedStartDate: 'hello' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery3, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
const customQuery4 = { ...query, originallyPublishedEndDate: 'hello' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery4, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid host', async function () {
|
||||
const customQuery = { ...query, host: '6565' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with a host', async function () {
|
||||
const customQuery = { ...query, host: 'example.com' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
||||
it('Should fail with invalid uuids', async function () {
|
||||
const customQuery = { ...query, uuids: [ '6565', 'dfd70b83-639f-4980-94af-304a56ab4b35' ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with valid uuids', async function () {
|
||||
const customQuery = { ...query, uuids: [ 'dfd70b83-639f-4980-94af-304a56ab4b35' ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When searching video playlists', function () {
|
||||
const path = '/api/v1/search/video-playlists/'
|
||||
|
||||
const query = {
|
||||
search: 'coucou',
|
||||
host: 'example.com'
|
||||
}
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, null, query)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, null, query)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, null, query)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid host', async function () {
|
||||
await makeGetRequest({ url: server.url, path, query: { ...query, host: '6565' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with invalid uuids', async function () {
|
||||
const customQuery = { ...query, uuids: [ '6565', 'dfd70b83-639f-4980-94af-304a56ab4b35' ] }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path, query, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When searching video channels', function () {
|
||||
const path = '/api/v1/search/video-channels/'
|
||||
|
||||
const query = {
|
||||
search: 'coucou',
|
||||
host: 'example.com'
|
||||
}
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, null, query)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, null, query)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, null, query)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid host', async function () {
|
||||
await makeGetRequest({ url: server.url, path, query: { ...query, host: '6565' }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with invalid handles', async function () {
|
||||
await makeGetRequest({ url: server.url, path, query: { ...query, handles: [ '' ] }, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path, query, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('Search target', function () {
|
||||
|
||||
it('Should fail/succeed depending on the search target', async function () {
|
||||
const query = { search: 'coucou' }
|
||||
const paths = [
|
||||
'/api/v1/search/video-playlists/',
|
||||
'/api/v1/search/video-channels/',
|
||||
'/api/v1/search/videos/'
|
||||
]
|
||||
|
||||
for (const path of paths) {
|
||||
{
|
||||
const customQuery = { ...query, searchTarget: 'hello' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
}
|
||||
|
||||
{
|
||||
const customQuery = { ...query, searchTarget: undefined }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
|
||||
}
|
||||
|
||||
{
|
||||
const customQuery = { ...query, searchTarget: 'local' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
|
||||
}
|
||||
|
||||
{
|
||||
const customQuery = { ...query, searchTarget: 'search-index' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
}
|
||||
|
||||
await updateSearchIndex(server, true, true)
|
||||
|
||||
{
|
||||
const customQuery = { ...query, searchTarget: 'search-index' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
|
||||
}
|
||||
|
||||
await updateSearchIndex(server, true, false)
|
||||
|
||||
{
|
||||
const customQuery = { ...query, searchTarget: 'local' }
|
||||
await makeGetRequest({ url: server.url, path, query: customQuery, expectedStatus: HttpStatusCode.OK_200 })
|
||||
}
|
||||
|
||||
await updateSearchIndex(server, false, false)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,207 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import {
|
||||
HttpStatusCode,
|
||||
HttpStatusCodeType,
|
||||
VideoCreateResult,
|
||||
VideoPlaylistCreateResult,
|
||||
VideoPlaylistPrivacy,
|
||||
VideoPrivacy
|
||||
} from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
setDefaultVideoChannel
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test services API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
let playlistUUID: string
|
||||
|
||||
let privateVideo: VideoCreateResult
|
||||
let unlistedVideo: VideoCreateResult
|
||||
|
||||
let privatePlaylist: VideoPlaylistCreateResult
|
||||
let unlistedPlaylist: VideoPlaylistCreateResult
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultVideoChannel([ server ])
|
||||
|
||||
server.store.videoCreated = await server.videos.upload({ attributes: { name: 'my super name' } })
|
||||
|
||||
privateVideo = await server.videos.quickUpload({ name: 'private', privacy: VideoPrivacy.PRIVATE })
|
||||
unlistedVideo = await server.videos.quickUpload({ name: 'unlisted', privacy: VideoPrivacy.UNLISTED })
|
||||
|
||||
{
|
||||
const created = await server.playlists.create({
|
||||
attributes: {
|
||||
displayName: 'super playlist',
|
||||
privacy: VideoPlaylistPrivacy.PUBLIC,
|
||||
videoChannelId: server.store.channel.id
|
||||
}
|
||||
})
|
||||
|
||||
playlistUUID = created.uuid
|
||||
|
||||
privatePlaylist = await server.playlists.create({
|
||||
attributes: {
|
||||
displayName: 'private',
|
||||
privacy: VideoPlaylistPrivacy.PRIVATE,
|
||||
videoChannelId: server.store.channel.id
|
||||
}
|
||||
})
|
||||
|
||||
unlistedPlaylist = await server.playlists.create({
|
||||
attributes: {
|
||||
displayName: 'unlisted',
|
||||
privacy: VideoPlaylistPrivacy.UNLISTED,
|
||||
videoChannelId: server.store.channel.id
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
describe('Test oEmbed API validators', function () {
|
||||
|
||||
it('Should fail with an invalid url', async function () {
|
||||
const embedUrl = 'hello.com'
|
||||
await checkParamEmbed(server, embedUrl)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid host', async function () {
|
||||
const embedUrl = 'http://hello.com/videos/watch/' + server.store.videoCreated.uuid
|
||||
await checkParamEmbed(server, embedUrl)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid element id', async function () {
|
||||
const embedUrl = `${server.url}/videos/watch/blabla`
|
||||
await checkParamEmbed(server, embedUrl)
|
||||
})
|
||||
|
||||
it('Should fail with an unknown element', async function () {
|
||||
const embedUrl = `${server.url}/videos/watch/88fc0165-d1f0-4a35-a51a-3b47f668689c`
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.NOT_FOUND_404)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid path', async function () {
|
||||
const embedUrl = `${server.url}/videos/watchs/${server.store.videoCreated.uuid}`
|
||||
|
||||
await checkParamEmbed(server, embedUrl)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid max height', async function () {
|
||||
const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}`
|
||||
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.BAD_REQUEST_400, { maxheight: 'hello' })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid max width', async function () {
|
||||
const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}`
|
||||
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.BAD_REQUEST_400, { maxwidth: 'hello' })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid format', async function () {
|
||||
const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}`
|
||||
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.BAD_REQUEST_400, { format: 'blabla' })
|
||||
})
|
||||
|
||||
it('Should fail with a non supported format', async function () {
|
||||
const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}`
|
||||
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.NOT_IMPLEMENTED_501, { format: 'xml' })
|
||||
})
|
||||
|
||||
it('Should fail with a private video', async function () {
|
||||
const embedUrl = `${server.url}/videos/watch/${privateVideo.uuid}`
|
||||
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.FORBIDDEN_403)
|
||||
})
|
||||
|
||||
it('Should fail with an unlisted video with the int id', async function () {
|
||||
const embedUrl = `${server.url}/videos/watch/${unlistedVideo.id}`
|
||||
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.FORBIDDEN_403)
|
||||
})
|
||||
|
||||
it('Should succeed with an unlisted video using the uuid id', async function () {
|
||||
for (const uuid of [ unlistedVideo.uuid, unlistedVideo.shortUUID ]) {
|
||||
const embedUrl = `${server.url}/videos/watch/${uuid}`
|
||||
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.OK_200)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with a private playlist', async function () {
|
||||
const embedUrl = `${server.url}/videos/watch/playlist/${privatePlaylist.uuid}`
|
||||
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.FORBIDDEN_403)
|
||||
})
|
||||
|
||||
it('Should fail with an unlisted playlist using the int id', async function () {
|
||||
const embedUrl = `${server.url}/videos/watch/playlist/${unlistedPlaylist.id}`
|
||||
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.FORBIDDEN_403)
|
||||
})
|
||||
|
||||
it('Should succeed with an unlisted playlist using the uuid id', async function () {
|
||||
for (const uuid of [ unlistedPlaylist.uuid, unlistedPlaylist.shortUUID ]) {
|
||||
const embedUrl = `${server.url}/videos/watch/playlist/${uuid}`
|
||||
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.OK_200)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params with a video', async function () {
|
||||
const embedUrl = `${server.url}/videos/watch/${server.store.videoCreated.uuid}`
|
||||
const query = {
|
||||
format: 'json',
|
||||
maxheight: 400,
|
||||
maxwidth: 400
|
||||
}
|
||||
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.OK_200, query)
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params with a playlist', async function () {
|
||||
const embedUrl = `${server.url}/videos/watch/playlist/${playlistUUID}`
|
||||
const query = {
|
||||
format: 'json',
|
||||
maxheight: 400,
|
||||
maxwidth: 400
|
||||
}
|
||||
|
||||
await checkParamEmbed(server, embedUrl, HttpStatusCode.OK_200, query)
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
|
||||
function checkParamEmbed (
|
||||
server: PeerTubeServer,
|
||||
embedUrl: string,
|
||||
expectedStatus: HttpStatusCodeType = HttpStatusCode.BAD_REQUEST_400,
|
||||
query = {}
|
||||
) {
|
||||
const path = '/services/oembed'
|
||||
|
||||
return makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: Object.assign(query, { url: embedUrl }),
|
||||
expectedStatus
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode, UserRole } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createMultipleServers,
|
||||
doubleFollow,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test transcoding API validators', function () {
|
||||
let servers: PeerTubeServer[]
|
||||
|
||||
let userToken: string
|
||||
let moderatorToken: string
|
||||
|
||||
let remoteId: string
|
||||
let validId: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(240000)
|
||||
|
||||
servers = await createMultipleServers(2)
|
||||
await setAccessTokensToServers(servers)
|
||||
|
||||
await doubleFollow(servers[0], servers[1])
|
||||
|
||||
userToken = await servers[0].users.generateUserAndToken('user', UserRole.USER)
|
||||
moderatorToken = await servers[0].users.generateUserAndToken('moderator', UserRole.MODERATOR)
|
||||
|
||||
{
|
||||
const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' })
|
||||
remoteId = uuid
|
||||
}
|
||||
|
||||
{
|
||||
const { uuid } = await servers[0].videos.quickUpload({ name: 'both 1' })
|
||||
validId = uuid
|
||||
}
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
await servers[0].config.enableTranscoding()
|
||||
})
|
||||
|
||||
it('Should not run transcoding of a unknown video', async function () {
|
||||
await servers[0].videos.runTranscoding({ videoId: 404, transcodingType: 'hls', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await servers[0].videos.runTranscoding({ videoId: 404, transcodingType: 'web-video', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should not run transcoding of a remote video', async function () {
|
||||
const expectedStatus = HttpStatusCode.BAD_REQUEST_400
|
||||
|
||||
await servers[0].videos.runTranscoding({ videoId: remoteId, transcodingType: 'hls', expectedStatus })
|
||||
await servers[0].videos.runTranscoding({ videoId: remoteId, transcodingType: 'web-video', expectedStatus })
|
||||
})
|
||||
|
||||
it('Should not run transcoding by a non admin user', async function () {
|
||||
const expectedStatus = HttpStatusCode.FORBIDDEN_403
|
||||
|
||||
await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'hls', token: userToken, expectedStatus })
|
||||
await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', token: moderatorToken, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should not run transcoding without transcoding type', async function () {
|
||||
await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should not run transcoding with an incorrect transcoding type', async function () {
|
||||
const expectedStatus = HttpStatusCode.BAD_REQUEST_400
|
||||
|
||||
await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'toto' as any, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should not run transcoding if the instance disabled it', async function () {
|
||||
const expectedStatus = HttpStatusCode.BAD_REQUEST_400
|
||||
|
||||
await servers[0].config.disableTranscoding()
|
||||
|
||||
await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'hls', expectedStatus })
|
||||
await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', expectedStatus })
|
||||
})
|
||||
|
||||
it('Should run transcoding', async function () {
|
||||
this.timeout(120_000)
|
||||
|
||||
await servers[0].config.enableTranscoding()
|
||||
|
||||
await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'hls' })
|
||||
await waitJobs(servers)
|
||||
|
||||
await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', forceTranscoding: true })
|
||||
await waitJobs(servers)
|
||||
})
|
||||
|
||||
it('Should not run transcoding on a video that is already being transcoded if forceTranscoding is not set', async function () {
|
||||
await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video' })
|
||||
|
||||
const expectedStatus = HttpStatusCode.CONFLICT_409
|
||||
await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', expectedStatus })
|
||||
|
||||
await servers[0].videos.runTranscoding({ videoId: validId, transcodingType: 'web-video', forceTranscoding: true })
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests(servers)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,294 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
TwoFactorCommand
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test two factor API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
|
||||
let rootId: number
|
||||
let rootPassword: string
|
||||
let rootRequestToken: string
|
||||
let rootOTPToken: string
|
||||
|
||||
let userId: number
|
||||
let userToken = ''
|
||||
let userPassword: string
|
||||
let userRequestToken: string
|
||||
let userOTPToken: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
{
|
||||
server = await createSingleServer(1)
|
||||
await setAccessTokensToServers([ server ])
|
||||
}
|
||||
|
||||
{
|
||||
const result = await server.users.generate('user1')
|
||||
userToken = result.token
|
||||
userId = result.userId
|
||||
userPassword = result.password
|
||||
}
|
||||
|
||||
{
|
||||
const { id } = await server.users.getMyInfo()
|
||||
rootId = id
|
||||
rootPassword = server.store.user.password
|
||||
}
|
||||
})
|
||||
|
||||
describe('When requesting two factor', function () {
|
||||
|
||||
it('Should fail with an unknown user id', async function () {
|
||||
await server.twoFactor.request({ userId: 42, currentPassword: rootPassword, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid user id', async function () {
|
||||
await server.twoFactor.request({
|
||||
userId: 'invalid' as any,
|
||||
currentPassword: rootPassword,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to request another user two factor without the appropriate rights', async function () {
|
||||
await server.twoFactor.request({
|
||||
userId: rootId,
|
||||
token: userToken,
|
||||
currentPassword: userPassword,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed to request another user two factor with the appropriate rights', async function () {
|
||||
await server.twoFactor.request({ userId, currentPassword: rootPassword })
|
||||
})
|
||||
|
||||
it('Should fail to request two factor without a password', async function () {
|
||||
await server.twoFactor.request({
|
||||
userId,
|
||||
token: userToken,
|
||||
currentPassword: undefined,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to request two factor with an incorrect password', async function () {
|
||||
await server.twoFactor.request({
|
||||
userId,
|
||||
token: userToken,
|
||||
currentPassword: rootPassword,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed to request two factor without a password when targeting a remote user with an admin account', async function () {
|
||||
await server.twoFactor.request({ userId })
|
||||
})
|
||||
|
||||
it('Should fail to request two factor without a password when targeting myself with an admin account', async function () {
|
||||
await server.twoFactor.request({ userId: rootId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await server.twoFactor.request({ userId: rootId, currentPassword: 'bad', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed to request my two factor auth', async function () {
|
||||
{
|
||||
const { otpRequest } = await server.twoFactor.request({ userId, token: userToken, currentPassword: userPassword })
|
||||
userRequestToken = otpRequest.requestToken
|
||||
userOTPToken = TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate()
|
||||
}
|
||||
|
||||
{
|
||||
const { otpRequest } = await server.twoFactor.request({ userId: rootId, currentPassword: rootPassword })
|
||||
rootRequestToken = otpRequest.requestToken
|
||||
rootOTPToken = TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('When confirming two factor request', function () {
|
||||
|
||||
it('Should fail with an unknown user id', async function () {
|
||||
await server.twoFactor.confirmRequest({
|
||||
userId: 42,
|
||||
requestToken: rootRequestToken,
|
||||
otpToken: rootOTPToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid user id', async function () {
|
||||
await server.twoFactor.confirmRequest({
|
||||
userId: 'invalid' as any,
|
||||
requestToken: rootRequestToken,
|
||||
otpToken: rootOTPToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to confirm another user two factor request without the appropriate rights', async function () {
|
||||
await server.twoFactor.confirmRequest({
|
||||
userId: rootId,
|
||||
token: userToken,
|
||||
requestToken: rootRequestToken,
|
||||
otpToken: rootOTPToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without request token', async function () {
|
||||
await server.twoFactor.confirmRequest({
|
||||
userId,
|
||||
requestToken: undefined,
|
||||
otpToken: userOTPToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid request token', async function () {
|
||||
await server.twoFactor.confirmRequest({
|
||||
userId,
|
||||
requestToken: 'toto',
|
||||
otpToken: userOTPToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with request token of another user', async function () {
|
||||
await server.twoFactor.confirmRequest({
|
||||
userId,
|
||||
requestToken: rootRequestToken,
|
||||
otpToken: userOTPToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without an otp token', async function () {
|
||||
await server.twoFactor.confirmRequest({
|
||||
userId,
|
||||
requestToken: userRequestToken,
|
||||
otpToken: undefined,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad otp token', async function () {
|
||||
await server.twoFactor.confirmRequest({
|
||||
userId,
|
||||
requestToken: userRequestToken,
|
||||
otpToken: '123456',
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed to confirm another user two factor request with the appropriate rights', async function () {
|
||||
await server.twoFactor.confirmRequest({
|
||||
userId,
|
||||
requestToken: userRequestToken,
|
||||
otpToken: userOTPToken
|
||||
})
|
||||
|
||||
// Reinit
|
||||
await server.twoFactor.disable({ userId, currentPassword: rootPassword })
|
||||
})
|
||||
|
||||
it('Should succeed to confirm my two factor request', async function () {
|
||||
await server.twoFactor.confirmRequest({
|
||||
userId,
|
||||
token: userToken,
|
||||
requestToken: userRequestToken,
|
||||
otpToken: userOTPToken
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to confirm again two factor request', async function () {
|
||||
await server.twoFactor.confirmRequest({
|
||||
userId,
|
||||
token: userToken,
|
||||
requestToken: userRequestToken,
|
||||
otpToken: userOTPToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When disabling two factor', function () {
|
||||
|
||||
it('Should fail with an unknown user id', async function () {
|
||||
await server.twoFactor.disable({
|
||||
userId: 42,
|
||||
currentPassword: rootPassword,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid user id', async function () {
|
||||
await server.twoFactor.disable({
|
||||
userId: 'invalid' as any,
|
||||
currentPassword: rootPassword,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to disable another user two factor without the appropriate rights', async function () {
|
||||
await server.twoFactor.disable({
|
||||
userId: rootId,
|
||||
token: userToken,
|
||||
currentPassword: userPassword,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to disable two factor with an incorrect password', async function () {
|
||||
await server.twoFactor.disable({
|
||||
userId,
|
||||
token: userToken,
|
||||
currentPassword: rootPassword,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed to disable two factor without a password when targeting a remote user with an admin account', async function () {
|
||||
await server.twoFactor.disable({ userId })
|
||||
await server.twoFactor.requestAndConfirm({ userId })
|
||||
})
|
||||
|
||||
it('Should fail to disable two factor without a password when targeting myself with an admin account', async function () {
|
||||
await server.twoFactor.disable({ userId: rootId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await server.twoFactor.disable({ userId: rootId, currentPassword: 'bad', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed to disable another user two factor with the appropriate rights', async function () {
|
||||
await server.twoFactor.disable({ userId, currentPassword: rootPassword })
|
||||
|
||||
await server.twoFactor.requestAndConfirm({ userId })
|
||||
})
|
||||
|
||||
it('Should succeed to update my two factor auth', async function () {
|
||||
await server.twoFactor.disable({ userId, token: userToken, currentPassword: userPassword })
|
||||
})
|
||||
|
||||
it('Should fail to disable again two factor', async function () {
|
||||
await server.twoFactor.disable({
|
||||
userId,
|
||||
token: userToken,
|
||||
currentPassword: userPassword,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,134 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { expect } from 'chai'
|
||||
import { FIXTURE_URLS } from '@tests/shared/fixture-urls.js'
|
||||
import { randomInt } from '@peertube/peertube-core-utils'
|
||||
import { HttpStatusCode, VideoImportState, VideoPrivacy } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
setDefaultVideoChannel,
|
||||
VideosCommand,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test upload quota', function () {
|
||||
let server: PeerTubeServer
|
||||
let rootId: number
|
||||
let command: VideosCommand
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultVideoChannel([ server ])
|
||||
|
||||
const user = await server.users.getMyInfo()
|
||||
rootId = user.id
|
||||
|
||||
await server.users.update({ userId: rootId, videoQuota: 42 })
|
||||
|
||||
command = server.videos
|
||||
})
|
||||
|
||||
describe('When having a video quota', function () {
|
||||
|
||||
it('Should fail with a registered user having too many videos with legacy upload', async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
const user = { username: 'registered' + randomInt(1, 1500), password: 'password' }
|
||||
await server.registrations.register(user)
|
||||
const userToken = await server.login.getAccessToken(user)
|
||||
|
||||
const attributes = { fixture: 'video_short2.webm' }
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await command.upload({ token: userToken, attributes })
|
||||
}
|
||||
|
||||
await command.upload({ token: userToken, attributes, expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'legacy' })
|
||||
})
|
||||
|
||||
it('Should fail with a registered user having too many videos with resumable upload', async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
const user = { username: 'registered' + randomInt(1, 1500), password: 'password' }
|
||||
await server.registrations.register(user)
|
||||
const userToken = await server.login.getAccessToken(user)
|
||||
|
||||
const attributes = { fixture: 'video_short2.webm' }
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await command.upload({ token: userToken, attributes })
|
||||
}
|
||||
|
||||
await command.upload({ token: userToken, attributes, expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'resumable' })
|
||||
})
|
||||
|
||||
it('Should fail to import with HTTP/Torrent/magnet', async function () {
|
||||
this.timeout(120_000)
|
||||
|
||||
const baseAttributes = {
|
||||
channelId: server.store.channel.id,
|
||||
privacy: VideoPrivacy.PUBLIC
|
||||
}
|
||||
await server.videoImports.importVideo({ attributes: { ...baseAttributes, targetUrl: FIXTURE_URLS.goodVideo } })
|
||||
await server.videoImports.importVideo({ attributes: { ...baseAttributes, magnetUri: FIXTURE_URLS.magnet } })
|
||||
await server.videoImports.importVideo({ attributes: { ...baseAttributes, torrentfile: 'video-720p.torrent' as any } })
|
||||
|
||||
await waitJobs([ server ])
|
||||
|
||||
const { total, data: videoImports } = await server.videoImports.getMyVideoImports()
|
||||
expect(total).to.equal(3)
|
||||
|
||||
expect(videoImports).to.have.lengthOf(3)
|
||||
|
||||
for (const videoImport of videoImports) {
|
||||
expect(videoImport.state.id).to.equal(VideoImportState.FAILED)
|
||||
expect(videoImport.error).not.to.be.undefined
|
||||
expect(videoImport.error).to.contain('user video quota is exceeded')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('When having a daily video quota', function () {
|
||||
|
||||
it('Should fail with a user having too many videos daily', async function () {
|
||||
await server.users.update({ userId: rootId, videoQuotaDaily: 42 })
|
||||
|
||||
await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'legacy' })
|
||||
await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'resumable' })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When having an absolute and daily video quota', function () {
|
||||
it('Should fail if exceeding total quota', async function () {
|
||||
await server.users.update({
|
||||
userId: rootId,
|
||||
videoQuota: 42,
|
||||
videoQuotaDaily: 1024 * 1024 * 1024
|
||||
})
|
||||
|
||||
await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'legacy' })
|
||||
await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'resumable' })
|
||||
})
|
||||
|
||||
it('Should fail if exceeding daily quota', async function () {
|
||||
await server.users.update({
|
||||
userId: rootId,
|
||||
videoQuota: 1024 * 1024 * 1024,
|
||||
videoQuotaDaily: 42
|
||||
})
|
||||
|
||||
await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'legacy' })
|
||||
await command.upload({ expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413, mode: 'resumable' })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,339 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { wait } from '@peertube/peertube-core-utils'
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
makeRawRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test user export API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
let rootId: number
|
||||
|
||||
let userId: number
|
||||
let userToken: string
|
||||
|
||||
let exportId: number
|
||||
let userExportId: number
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
{
|
||||
const user = await server.users.getMyInfo()
|
||||
rootId = user.id
|
||||
}
|
||||
|
||||
{
|
||||
userToken = await server.users.generateUserAndToken('user')
|
||||
const user = await server.users.getMyInfo({ token: userToken })
|
||||
userId = user.id
|
||||
}
|
||||
})
|
||||
|
||||
describe('Request export', function () {
|
||||
|
||||
it('Should fail if export is disabled', async function () {
|
||||
await server.config.disableUserExport()
|
||||
|
||||
await server.userExports.request({ userId: rootId, withVideoFiles: false, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
await server.config.enableUserExport()
|
||||
})
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await server.userExports.request({
|
||||
userId: rootId,
|
||||
withVideoFiles: false,
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with invalid token', async function () {
|
||||
await server.userExports.request({
|
||||
userId: rootId,
|
||||
withVideoFiles: false,
|
||||
token: 'hello',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a token of another user', async function () {
|
||||
await server.userExports.request({
|
||||
userId: rootId,
|
||||
withVideoFiles: false,
|
||||
token: userToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown user', async function () {
|
||||
await server.userExports.request({ userId: 404, withVideoFiles: false, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail if user quota is too big', async function () {
|
||||
const { videoQuotaUsed } = await server.users.getMyQuotaUsed()
|
||||
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
export: {
|
||||
users: { maxUserVideoQuota: videoQuotaUsed - 1 }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await server.userExports.request({ userId: rootId, withVideoFiles: true, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
await server.userExports.request({ userId: rootId, withVideoFiles: false, expectedStatus: HttpStatusCode.OK_200 })
|
||||
|
||||
// Cleanup
|
||||
await server.userExports.waitForCreation({ userId: rootId })
|
||||
await server.userExports.deleteAllArchives({ userId: rootId })
|
||||
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
export: {
|
||||
users: { maxUserVideoQuota: 1000 * 1000 * 1000 * 1000 }
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the appropriate token', async function () {
|
||||
const { export: { id } } = await server.userExports.request({ userId: rootId, withVideoFiles: false })
|
||||
|
||||
exportId = id
|
||||
})
|
||||
|
||||
it('Should fail if there is already an export', async function () {
|
||||
await server.userExports.request({
|
||||
userId: rootId,
|
||||
withVideoFiles: false,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed after a delete with an admin token', async function () {
|
||||
await server.userExports.waitForCreation({ userId: rootId })
|
||||
await server.userExports.delete({ userId: rootId, exportId })
|
||||
|
||||
const { export: { id } } = await server.userExports.request({ userId: rootId, withVideoFiles: false })
|
||||
exportId = id
|
||||
})
|
||||
})
|
||||
|
||||
describe('List exports', function () {
|
||||
|
||||
it('Should fail if export is disabled', async function () {
|
||||
await server.config.disableUserExport()
|
||||
|
||||
await server.userExports.list({ userId: rootId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
await server.config.enableUserExport()
|
||||
})
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await server.userExports.list({
|
||||
userId: rootId,
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with invalid token', async function () {
|
||||
await server.userExports.list({
|
||||
userId: rootId,
|
||||
token: 'toto',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a token of another user', async function () {
|
||||
await server.userExports.list({
|
||||
userId: rootId,
|
||||
token: userToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown user', async function () {
|
||||
await server.userExports.list({ userId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
// User token
|
||||
await server.userExports.list({ userId, token: userToken })
|
||||
// Root token
|
||||
await server.userExports.list({ userId })
|
||||
})
|
||||
})
|
||||
|
||||
describe('Deleting export', function () {
|
||||
|
||||
before(async function () {
|
||||
const { export: { id } } = await server.userExports.request({ userId, withVideoFiles: true })
|
||||
userExportId = id
|
||||
|
||||
await server.userExports.waitForCreation({ userId })
|
||||
})
|
||||
|
||||
it('Should fail if export is disabled', async function () {
|
||||
await server.config.disableUserExport()
|
||||
|
||||
await server.userExports.delete({ userId, exportId: userExportId, token: userToken, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
await server.config.enableUserExport()
|
||||
})
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await server.userExports.delete({
|
||||
userId: rootId,
|
||||
exportId,
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with invalid token', async function () {
|
||||
await server.userExports.delete({
|
||||
userId: rootId,
|
||||
exportId,
|
||||
token: 'toto',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a token of another user', async function () {
|
||||
await server.userExports.delete({
|
||||
userId: rootId,
|
||||
exportId,
|
||||
token: userToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an export id of another user', async function () {
|
||||
await server.userExports.delete({
|
||||
userId,
|
||||
exportId,
|
||||
token: userToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown user', async function () {
|
||||
await server.userExports.delete({
|
||||
userId: 404,
|
||||
exportId,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown export id', async function () {
|
||||
await server.userExports.delete({
|
||||
userId,
|
||||
exportId: 404,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await server.userExports.delete({
|
||||
userId,
|
||||
exportId: userExportId,
|
||||
token: userToken
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Downloading an export', function () {
|
||||
|
||||
before(async function () {
|
||||
await server.userExports.request({ userId, withVideoFiles: true })
|
||||
await server.userExports.waitForCreation({ userId })
|
||||
})
|
||||
|
||||
it('Should fail without jwt token', async function () {
|
||||
const { data } = await server.userExports.list({ userId })
|
||||
|
||||
const url = data[0].privateDownloadUrl.replace('jwt=', 'toto=')
|
||||
await makeRawRequest({ url, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a wrong jwt token', async function () {
|
||||
const { data } = await server.userExports.list({ userId })
|
||||
|
||||
// Invalid format
|
||||
{
|
||||
const url = data[0].privateDownloadUrl.replace('jwt=', 'jwt=hello.coucou')
|
||||
await makeRawRequest({ url, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
}
|
||||
|
||||
// Invalid content
|
||||
{
|
||||
const url = data[0].privateDownloadUrl.replace('jwt=', 'jwt=a')
|
||||
await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with a jwt token of another export', async function () {
|
||||
let userQuery: string
|
||||
|
||||
// Save user JWT token
|
||||
{
|
||||
const { data } = await server.userExports.list({ userId })
|
||||
|
||||
const { pathname, search } = new URL(data[0].privateDownloadUrl)
|
||||
const rawQuery = search.replace('?', '')
|
||||
userQuery = rawQuery
|
||||
|
||||
await makeGetRequest({ url: server.url, path: pathname, rawQuery, expectedStatus: HttpStatusCode.OK_200 })
|
||||
}
|
||||
|
||||
// This user JWT token must not be used to download an export of another user
|
||||
{
|
||||
const { data } = await server.userExports.list({ userId: rootId })
|
||||
|
||||
const { pathname, search } = new URL(data[0].privateDownloadUrl)
|
||||
const rawQuery = search.replace('?', '')
|
||||
|
||||
await makeGetRequest({ url: server.url, path: pathname, rawQuery, expectedStatus: HttpStatusCode.OK_200 })
|
||||
await makeGetRequest({ url: server.url, path: pathname, rawQuery: userQuery, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an invalid filename', async function () {
|
||||
const { data } = await server.userExports.list({ userId })
|
||||
|
||||
const url = data[0].privateDownloadUrl.replace('.zip', '.tar')
|
||||
await makeRawRequest({ url, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with an expired JWT token', async function () {
|
||||
const { data } = await server.userExports.list({ userId })
|
||||
|
||||
await wait(3000)
|
||||
await makeRawRequest({ url: data[0].privateDownloadUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const { data } = await server.userExports.list({ userId })
|
||||
await makeRawRequest({ url: data[0].privateDownloadUrl, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,169 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer, PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
import { expect } from 'chai'
|
||||
|
||||
describe('Test user import API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
let userId: number
|
||||
let rootId: number
|
||||
let token: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
{
|
||||
const result = await server.users.generate('user')
|
||||
userId = result.userId
|
||||
token = result.token
|
||||
}
|
||||
|
||||
{
|
||||
const { id } = await server.users.getMyInfo()
|
||||
rootId = id
|
||||
}
|
||||
})
|
||||
|
||||
describe('Request import', function () {
|
||||
|
||||
it('Should fail if import is disabled', async function () {
|
||||
await server.config.disableUserImport()
|
||||
|
||||
await server.userImports.importArchive({
|
||||
userId,
|
||||
fixture: 'export-without-files.zip',
|
||||
token,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await server.config.enableUserImport()
|
||||
})
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await server.userImports.importArchive({
|
||||
userId,
|
||||
fixture: 'export-without-files.zip',
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with invalid token', async function () {
|
||||
await server.userImports.importArchive({
|
||||
userId,
|
||||
fixture: 'export-without-files.zip',
|
||||
token: 'invalid',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a token of another user', async function () {
|
||||
await server.userImports.importArchive({
|
||||
userId: rootId,
|
||||
fixture: 'export-without-files.zip',
|
||||
token,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown user', async function () {
|
||||
await server.userImports.importArchive({
|
||||
userId: 404,
|
||||
fixture: 'export-without-files.zip',
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if user quota is exceeded', async function () {
|
||||
await server.users.update({ userId, videoQuota: 100 })
|
||||
|
||||
await server.userImports.importArchive({
|
||||
userId,
|
||||
fixture: 'export-without-files.zip',
|
||||
expectedStatus: HttpStatusCode.PAYLOAD_TOO_LARGE_413
|
||||
})
|
||||
|
||||
await server.users.update({ userId, videoQuota: -1 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.userImports.importArchive({ userId, fixture: 'export-without-files.zip' })
|
||||
|
||||
await waitJobs([ server ])
|
||||
})
|
||||
|
||||
it('Should fail with an import that is already being processed', async function () {
|
||||
await server.userImports.importArchive({ userId, fixture: 'export-without-files.zip' })
|
||||
await server.userImports.importArchive({
|
||||
userId,
|
||||
fixture: 'export-without-files.zip',
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with invalid ZIPs', async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
const toTest = [
|
||||
'export-bad-video-file.zip',
|
||||
'export-bad-video.zip',
|
||||
'export-without-videos.zip',
|
||||
'export-bad-structure.zip',
|
||||
'export-bad-structure.zip'
|
||||
]
|
||||
|
||||
const tokens: string[] = []
|
||||
|
||||
for (let i = 0; i < toTest.length; i++) {
|
||||
const { token, userId } = await server.users.generate('import' + i)
|
||||
await server.userImports.importArchive({ userId, token, fixture: toTest[i] })
|
||||
}
|
||||
|
||||
await waitJobs([ server ])
|
||||
|
||||
for (const token of tokens) {
|
||||
const { data } = await server.videos.listMyVideos({ token })
|
||||
expect(data).to.have.lengthOf(0)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Get latest import status', function () {
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await server.userImports.getLatestImport({ userId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with invalid token', async function () {
|
||||
await server.userImports.getLatestImport({ userId, token: 'invalid', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown user', async function () {
|
||||
await server.userImports.getLatestImport({ userId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a token of another user', async function () {
|
||||
await server.userImports.getLatestImport({ userId: rootId, token, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await server.userImports.getLatestImport({ userId, token })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,291 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { io } from 'socket.io-client'
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { wait } from '@peertube/peertube-core-utils'
|
||||
import { HttpStatusCode, UserNotificationSetting, UserNotificationSettingValue } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
makePutBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test user notifications API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
})
|
||||
|
||||
describe('When listing my notifications', function () {
|
||||
const path = '/api/v1/users/me/notifications'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect unread parameter', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: {
|
||||
unread: 'toto'
|
||||
},
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When marking as read my notifications', function () {
|
||||
const path = '/api/v1/users/me/notifications/read'
|
||||
|
||||
it('Should fail with wrong ids parameters', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: {
|
||||
ids: [ 'hello' ]
|
||||
},
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: {
|
||||
ids: [ ]
|
||||
},
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: {
|
||||
ids: 5
|
||||
},
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: {
|
||||
ids: [ 5 ]
|
||||
},
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: {
|
||||
ids: [ 5 ]
|
||||
},
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When marking as read my notifications', function () {
|
||||
const path = '/api/v1/users/me/notifications/read-all'
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating my notification settings', function () {
|
||||
const path = '/api/v1/users/me/notification-settings'
|
||||
const correctFields: UserNotificationSetting = {
|
||||
newVideoFromSubscription: UserNotificationSettingValue.WEB,
|
||||
newCommentOnMyVideo: UserNotificationSettingValue.WEB,
|
||||
abuseAsModerator: UserNotificationSettingValue.WEB,
|
||||
videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB,
|
||||
blacklistOnMyVideo: UserNotificationSettingValue.WEB,
|
||||
myVideoImportFinished: UserNotificationSettingValue.WEB,
|
||||
myVideoPublished: UserNotificationSettingValue.WEB,
|
||||
commentMention: UserNotificationSettingValue.WEB,
|
||||
newFollow: UserNotificationSettingValue.WEB,
|
||||
newUserRegistration: UserNotificationSettingValue.WEB,
|
||||
newInstanceFollower: UserNotificationSettingValue.WEB,
|
||||
autoInstanceFollowing: UserNotificationSettingValue.WEB,
|
||||
abuseNewMessage: UserNotificationSettingValue.WEB,
|
||||
abuseStateChange: UserNotificationSettingValue.WEB,
|
||||
newPeerTubeVersion: UserNotificationSettingValue.WEB,
|
||||
myVideoStudioEditionFinished: UserNotificationSettingValue.WEB,
|
||||
myVideoTranscriptionGenerated: UserNotificationSettingValue.WEB,
|
||||
newPluginVersion: UserNotificationSettingValue.WEB
|
||||
}
|
||||
|
||||
it('Should fail with missing fields', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: { newVideoFromSubscription: UserNotificationSettingValue.WEB },
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with incorrect field values', async function () {
|
||||
{
|
||||
const fields = { ...correctFields, newCommentOnMyVideo: 15 }
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
const fields = { ...correctFields, newCommentOnMyVideo: 'toto' }
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: correctFields,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: correctFields,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When connecting to my notification socket', function () {
|
||||
|
||||
it('Should fail with no token', function (next) {
|
||||
const socket = io(`${server.url}/user-notifications`, { reconnection: false })
|
||||
|
||||
socket.once('connect_error', function () {
|
||||
socket.disconnect()
|
||||
next()
|
||||
})
|
||||
|
||||
socket.on('connect', () => {
|
||||
socket.disconnect()
|
||||
next(new Error('Connected with a missing token.'))
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid token', function (next) {
|
||||
const socket = io(`${server.url}/user-notifications`, {
|
||||
query: { accessToken: 'bad_access_token' },
|
||||
reconnection: false
|
||||
})
|
||||
|
||||
socket.once('connect_error', function () {
|
||||
socket.disconnect()
|
||||
next()
|
||||
})
|
||||
|
||||
socket.on('connect', () => {
|
||||
socket.disconnect()
|
||||
next(new Error('Connected with an invalid token.'))
|
||||
})
|
||||
})
|
||||
|
||||
it('Should success with the correct token', function (next) {
|
||||
const socket = io(`${server.url}/user-notifications`, {
|
||||
query: { accessToken: server.accessToken },
|
||||
reconnection: false
|
||||
})
|
||||
|
||||
function errorListener (err) {
|
||||
next(new Error('Error in connection: ' + err))
|
||||
}
|
||||
|
||||
socket.on('connect_error', errorListener)
|
||||
|
||||
socket.once('connect', async () => {
|
||||
socket.disconnect()
|
||||
|
||||
await wait(500)
|
||||
next()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,298 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeDeleteRequest,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import { checkBadStartPagination, checkBadCountPagination, checkBadSortPagination } from '@tests/shared/checks.js'
|
||||
|
||||
describe('Test user subscriptions API validators', function () {
|
||||
const path = '/api/v1/users/me/subscriptions'
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken = ''
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
const user = {
|
||||
username: 'user1',
|
||||
password: 'my super password'
|
||||
}
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
userAccessToken = await server.login.getAccessToken(user)
|
||||
})
|
||||
|
||||
describe('When listing my subscriptions', function () {
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing my subscriptions videos', function () {
|
||||
const path = '/api/v1/users/me/subscriptions/videos'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When adding a subscription', function () {
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields: { uri: 'user1_channel@' + server.host },
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with bad URIs', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: { uri: 'root' },
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: { uri: 'root@' },
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: { uri: 'root@hello@' },
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
this.timeout(20000)
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: { uri: 'user1_channel@' + server.host },
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
|
||||
await waitJobs([ server ])
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting a subscription', function () {
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + '/user1_channel@' + server.host,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with bad URIs', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + '/root',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + '/root@',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + '/root@hello@',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown subscription', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + '/root1@' + server.host,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + '/user1_channel@' + server.host,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When checking if subscriptions exist', function () {
|
||||
const existPath = path + '/exist'
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: existPath,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with bad URIs', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: existPath,
|
||||
query: { uris: 'toto' },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: existPath,
|
||||
query: { 'uris[]': 1 },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: existPath,
|
||||
query: { 'uris[]': 'coucou@' + server.host },
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When removing a subscription', function () {
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/user1_channel@' + server.host,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with bad URIs', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/root',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/root@',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/root@hello@',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown subscription', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/root1@' + server.host,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '/user1_channel@' + server.host,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,457 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { MockSmtpServer } from '@tests/shared/mock-servers/index.js'
|
||||
import { omit } from '@peertube/peertube-core-utils'
|
||||
import { HttpStatusCode, UserAdminFlag, UserRole } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
ConfigCommand,
|
||||
createSingleServer,
|
||||
killallServers,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
makePutBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test users admin API validators', function () {
|
||||
const path = '/api/v1/users/'
|
||||
let userId: number
|
||||
let rootId: number
|
||||
let moderatorId: number
|
||||
let server: PeerTubeServer
|
||||
let userToken = ''
|
||||
let moderatorToken = ''
|
||||
let emailPort: number
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
const emails: object[] = []
|
||||
emailPort = await MockSmtpServer.Instance.collectEmails(emails)
|
||||
|
||||
{
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
}
|
||||
|
||||
{
|
||||
const result = await server.users.generate('user1')
|
||||
userToken = result.token
|
||||
userId = result.userId
|
||||
}
|
||||
|
||||
{
|
||||
const result = await server.users.generate('moderator1', UserRole.MODERATOR)
|
||||
moderatorToken = result.token
|
||||
}
|
||||
|
||||
{
|
||||
const result = await server.users.generate('moderator2', UserRole.MODERATOR)
|
||||
moderatorId = result.userId
|
||||
}
|
||||
})
|
||||
|
||||
describe('When listing users', function () {
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When adding a new user', function () {
|
||||
const baseCorrectParams = {
|
||||
username: 'user2',
|
||||
email: 'test@example.com',
|
||||
password: 'my super password',
|
||||
videoQuota: -1,
|
||||
videoQuotaDaily: -1,
|
||||
role: UserRole.USER,
|
||||
adminFlags: UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST
|
||||
}
|
||||
|
||||
it('Should fail with a too small username', async function () {
|
||||
const fields = { ...baseCorrectParams, username: '' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a too long username', async function () {
|
||||
const fields = { ...baseCorrectParams, username: 'super'.repeat(50) }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a not lowercase username', async function () {
|
||||
const fields = { ...baseCorrectParams, username: 'Toto' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect username', async function () {
|
||||
const fields = { ...baseCorrectParams, username: 'my username' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a missing email', async function () {
|
||||
const fields = omit(baseCorrectParams, [ 'email' ])
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid email', async function () {
|
||||
const fields = { ...baseCorrectParams, email: 'test_example.com' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a too small password', async function () {
|
||||
const fields = { ...baseCorrectParams, password: 'bla' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a too long password', async function () {
|
||||
const fields = { ...baseCorrectParams, password: 'super'.repeat(61) }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with empty password and no smtp configured', async function () {
|
||||
const fields = { ...baseCorrectParams, password: '' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should succeed with no password on a server with smtp enabled', async function () {
|
||||
this.timeout(20000)
|
||||
|
||||
await killallServers([ server ])
|
||||
|
||||
await server.run(ConfigCommand.getEmailOverrideConfig(emailPort))
|
||||
|
||||
const fields = {
|
||||
...baseCorrectParams,
|
||||
|
||||
password: '',
|
||||
username: 'create_password',
|
||||
email: 'create_password@example.com'
|
||||
}
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with invalid admin flags', async function () {
|
||||
const fields = { ...baseCorrectParams, adminFlags: 'toto' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an non authenticated user', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: 'supertoken',
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if we add a user with the same username', async function () {
|
||||
const fields = { ...baseCorrectParams, username: 'user1' }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if we add a user with the same email', async function () {
|
||||
const fields = { ...baseCorrectParams, email: 'user1@example.com' }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid videoQuota', async function () {
|
||||
const fields = { ...baseCorrectParams, videoQuota: -5 }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid videoQuotaDaily', async function () {
|
||||
const fields = { ...baseCorrectParams, videoQuotaDaily: -7 }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail without a user role', async function () {
|
||||
const fields = omit(baseCorrectParams, [ 'role' ])
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid user role', async function () {
|
||||
const fields = { ...baseCorrectParams, role: 88989 }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a "peertube" username', async function () {
|
||||
const fields = { ...baseCorrectParams, username: 'peertube' }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to create a moderator or an admin with a moderator', async function () {
|
||||
for (const role of [ UserRole.MODERATOR, UserRole.ADMINISTRATOR ]) {
|
||||
const fields = { ...baseCorrectParams, role }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: moderatorToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed to create a user with a moderator', async function () {
|
||||
const fields = { ...baseCorrectParams, username: 'a4656', email: 'a4656@example.com', role: UserRole.USER }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: moderatorToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
const user = { username: 'user1' }
|
||||
userToken = await server.login.getAccessToken(user)
|
||||
|
||||
const fields = {
|
||||
username: 'user3',
|
||||
email: 'test@example.com',
|
||||
password: 'my super password',
|
||||
videoQuota: 42000000
|
||||
}
|
||||
await makePostBodyRequest({ url: server.url, path, token: userToken, fields, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting a user', function () {
|
||||
|
||||
it('Should fail with an non authenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + userId,
|
||||
token: 'supertoken',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeGetRequest({ url: server.url, path: path + userId, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating a user', function () {
|
||||
|
||||
it('Should fail with an invalid email attribute', async function () {
|
||||
const fields = {
|
||||
email: 'blabla'
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid emailVerified attribute', async function () {
|
||||
const fields = {
|
||||
emailVerified: 'yes'
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid videoQuota attribute', async function () {
|
||||
const fields = {
|
||||
videoQuota: -90
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid user role attribute', async function () {
|
||||
const fields = {
|
||||
role: 54878
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a too small password', async function () {
|
||||
const fields = {
|
||||
currentPassword: 'password',
|
||||
password: 'bla'
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a too long password', async function () {
|
||||
const fields = {
|
||||
currentPassword: 'password',
|
||||
password: 'super'.repeat(61)
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an non authenticated user', async function () {
|
||||
const fields = {
|
||||
videoQuota: 42
|
||||
}
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + userId,
|
||||
token: 'supertoken',
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail when updating root role', async function () {
|
||||
const fields = {
|
||||
role: UserRole.MODERATOR
|
||||
}
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + rootId, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with invalid admin flags', async function () {
|
||||
const fields = { adminFlags: 'toto' }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail to update an admin with a moderator', async function () {
|
||||
const fields = {
|
||||
videoQuota: 42
|
||||
}
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + moderatorId,
|
||||
token: moderatorToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed to update a user with a moderator', async function () {
|
||||
const fields = {
|
||||
videoQuota: 42
|
||||
}
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + userId,
|
||||
token: moderatorToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const fields = {
|
||||
email: 'email@example.com',
|
||||
emailVerified: true,
|
||||
videoQuota: 42,
|
||||
role: UserRole.USER
|
||||
}
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + userId,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
MockSmtpServer.Instance.kill()
|
||||
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,122 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
import { HttpStatusCode, UserRole } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makePostBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test users API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1, {
|
||||
rates_limit: {
|
||||
ask_send_email: {
|
||||
max: 10
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
await server.config.enableSignup(true)
|
||||
|
||||
await server.users.generate('moderator2', UserRole.MODERATOR)
|
||||
|
||||
await server.registrations.requestRegistration({
|
||||
username: 'request1',
|
||||
registrationReason: 'tt'
|
||||
})
|
||||
})
|
||||
|
||||
describe('When asking a password reset', function () {
|
||||
const path = '/api/v1/users/ask-reset-password'
|
||||
|
||||
it('Should fail with a missing email', async function () {
|
||||
const fields = {}
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid email', async function () {
|
||||
const fields = { email: 'hello' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, fields })
|
||||
})
|
||||
|
||||
it('Should success with the correct params', async function () {
|
||||
const fields = { email: 'admin@example.com' }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When asking for an account verification email', function () {
|
||||
const path = '/api/v1/users/ask-send-verify-email'
|
||||
|
||||
it('Should fail with a missing email', async function () {
|
||||
const fields = {}
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid email', async function () {
|
||||
const fields = { email: 'hello' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, fields })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const fields = { email: 'admin@example.com' }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When asking for a registration verification email', function () {
|
||||
const path = '/api/v1/users/registrations/ask-send-verify-email'
|
||||
|
||||
it('Should fail with a missing email', async function () {
|
||||
const fields = {}
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid email', async function () {
|
||||
const fields = { email: 'hello' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, fields })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const fields = { email: 'request1@example.com' }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,292 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { expect } from 'chai'
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { HttpStatusCode, VideoBlacklistType } from '@peertube/peertube-models'
|
||||
import {
|
||||
BlacklistCommand,
|
||||
cleanupTests,
|
||||
createMultipleServers,
|
||||
doubleFollow,
|
||||
makePostBodyRequest,
|
||||
makePutBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test video blacklist API validators', function () {
|
||||
let servers: PeerTubeServer[]
|
||||
let notBlacklistedVideoId: string
|
||||
let remoteVideoUUID: string
|
||||
let userAccessToken1 = ''
|
||||
let userAccessToken2 = ''
|
||||
let command: BlacklistCommand
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(240000)
|
||||
|
||||
servers = await createMultipleServers(2)
|
||||
|
||||
await setAccessTokensToServers(servers)
|
||||
await doubleFollow(servers[0], servers[1])
|
||||
|
||||
{
|
||||
const username = 'user1'
|
||||
const password = 'my super password'
|
||||
await servers[0].users.create({ username, password })
|
||||
userAccessToken1 = await servers[0].login.getAccessToken({ username, password })
|
||||
}
|
||||
|
||||
{
|
||||
const username = 'user2'
|
||||
const password = 'my super password'
|
||||
await servers[0].users.create({ username, password })
|
||||
userAccessToken2 = await servers[0].login.getAccessToken({ username, password })
|
||||
}
|
||||
|
||||
{
|
||||
servers[0].store.videoCreated = await servers[0].videos.upload({ token: userAccessToken1 })
|
||||
}
|
||||
|
||||
{
|
||||
const { uuid } = await servers[0].videos.upload()
|
||||
notBlacklistedVideoId = uuid
|
||||
}
|
||||
|
||||
{
|
||||
const { uuid } = await servers[1].videos.upload()
|
||||
remoteVideoUUID = uuid
|
||||
}
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
command = servers[0].blacklist
|
||||
})
|
||||
|
||||
describe('When adding a video in blacklist', function () {
|
||||
const basePath = '/api/v1/videos/'
|
||||
|
||||
it('Should fail with nothing', async function () {
|
||||
const path = basePath + servers[0].store.videoCreated + '/blacklist'
|
||||
const fields = {}
|
||||
await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a wrong video', async function () {
|
||||
const wrongPath = '/api/v1/videos/blabla/blacklist'
|
||||
const fields = {}
|
||||
await makePostBodyRequest({ url: servers[0].url, path: wrongPath, token: servers[0].accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
const path = basePath + servers[0].store.videoCreated + '/blacklist'
|
||||
const fields = {}
|
||||
await makePostBodyRequest({ url: servers[0].url, path, token: 'hello', fields, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
const path = basePath + servers[0].store.videoCreated + '/blacklist'
|
||||
const fields = {}
|
||||
await makePostBodyRequest({
|
||||
url: servers[0].url,
|
||||
path,
|
||||
token: userAccessToken2,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid reason', async function () {
|
||||
const path = basePath + servers[0].store.videoCreated.uuid + '/blacklist'
|
||||
const fields = { reason: 'a'.repeat(305) }
|
||||
|
||||
await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail to unfederate a remote video', async function () {
|
||||
const path = basePath + remoteVideoUUID + '/blacklist'
|
||||
const fields = { unfederate: true }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: servers[0].url,
|
||||
path,
|
||||
token: servers[0].accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const path = basePath + servers[0].store.videoCreated.uuid + '/blacklist'
|
||||
const fields = {}
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: servers[0].url,
|
||||
path,
|
||||
token: servers[0].accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating a video in blacklist', function () {
|
||||
const basePath = '/api/v1/videos/'
|
||||
|
||||
it('Should fail with a wrong video', async function () {
|
||||
const wrongPath = '/api/v1/videos/blabla/blacklist'
|
||||
const fields = {}
|
||||
await makePutBodyRequest({ url: servers[0].url, path: wrongPath, token: servers[0].accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a video not blacklisted', async function () {
|
||||
const path = '/api/v1/videos/' + notBlacklistedVideoId + '/blacklist'
|
||||
const fields = {}
|
||||
await makePutBodyRequest({
|
||||
url: servers[0].url,
|
||||
path,
|
||||
token: servers[0].accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
const path = basePath + servers[0].store.videoCreated + '/blacklist'
|
||||
const fields = {}
|
||||
await makePutBodyRequest({ url: servers[0].url, path, token: 'hello', fields, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
const path = basePath + servers[0].store.videoCreated + '/blacklist'
|
||||
const fields = {}
|
||||
await makePutBodyRequest({
|
||||
url: servers[0].url,
|
||||
path,
|
||||
token: userAccessToken2,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid reason', async function () {
|
||||
const path = basePath + servers[0].store.videoCreated.uuid + '/blacklist'
|
||||
const fields = { reason: 'a'.repeat(305) }
|
||||
|
||||
await makePutBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const path = basePath + servers[0].store.videoCreated.shortUUID + '/blacklist'
|
||||
const fields = { reason: 'hello' }
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: servers[0].url,
|
||||
path,
|
||||
token: servers[0].accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting blacklisted video', function () {
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await servers[0].videos.get({ id: servers[0].store.videoCreated.uuid, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with another user', async function () {
|
||||
await servers[0].videos.getWithToken({
|
||||
token: userAccessToken2,
|
||||
id: servers[0].store.videoCreated.uuid,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the owner authenticated user', async function () {
|
||||
const video = await servers[0].videos.getWithToken({ token: userAccessToken1, id: servers[0].store.videoCreated.uuid })
|
||||
expect(video.blacklisted).to.be.true
|
||||
})
|
||||
|
||||
it('Should succeed with an admin', async function () {
|
||||
const video = servers[0].store.videoCreated
|
||||
|
||||
for (const id of [ video.id, video.uuid, video.shortUUID ]) {
|
||||
const video = await servers[0].videos.getWithToken({ id, expectedStatus: HttpStatusCode.OK_200 })
|
||||
expect(video.blacklisted).to.be.true
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('When removing a video in blacklist', function () {
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await command.remove({
|
||||
token: 'faketoken',
|
||||
videoId: servers[0].store.videoCreated.uuid,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
await command.remove({
|
||||
token: userAccessToken2,
|
||||
videoId: servers[0].store.videoCreated.uuid,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect id', async function () {
|
||||
await command.remove({ videoId: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a not blacklisted video', async function () {
|
||||
// The video was not added to the blacklist so it should fail
|
||||
await command.remove({ videoId: notBlacklistedVideoId, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await command.remove({ videoId: servers[0].store.videoCreated.uuid, expectedStatus: HttpStatusCode.NO_CONTENT_204 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing videos in blacklist', function () {
|
||||
const basePath = '/api/v1/videos/blacklist/'
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await servers[0].blacklist.list({ token: 'faketoken', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a non admin user', async function () {
|
||||
await servers[0].blacklist.list({ token: userAccessToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(servers[0].url, basePath, servers[0].accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(servers[0].url, basePath, servers[0].accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(servers[0].url, basePath, servers[0].accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid type', async function () {
|
||||
await servers[0].blacklist.list({ type: 0 as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await servers[0].blacklist.list({ type: VideoBlacklistType.MANUAL })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests(servers)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,312 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
|
||||
import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeDeleteRequest,
|
||||
makeGetRequest,
|
||||
makeUploadRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test video captions API validator', function () {
|
||||
const path = '/api/v1/videos/'
|
||||
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken: string
|
||||
let video: VideoCreateResult
|
||||
let privateVideo: VideoCreateResult
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
video = await server.videos.upload()
|
||||
privateVideo = await server.videos.upload({ attributes: { privacy: VideoPrivacy.PRIVATE } })
|
||||
userAccessToken = await server.users.generateUserAndToken('user1')
|
||||
})
|
||||
|
||||
describe('When adding video caption', function () {
|
||||
const fields = { }
|
||||
const attaches = {
|
||||
captionfile: buildAbsoluteFixturePath('subtitle-good1.vtt')
|
||||
}
|
||||
|
||||
it('Should fail without a valid uuid', async function () {
|
||||
await makeUploadRequest({
|
||||
method: 'PUT',
|
||||
url: server.url,
|
||||
path: path + '4da6fde3-88f7-4d16-b119-108df563d0b06/captions/fr',
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
attaches
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown id', async function () {
|
||||
await makeUploadRequest({
|
||||
method: 'PUT',
|
||||
url: server.url,
|
||||
path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/captions/fr',
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
attaches,
|
||||
expectedStatus: 404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a missing language in path', async function () {
|
||||
const captionPath = path + video.uuid + '/captions'
|
||||
await makeUploadRequest({
|
||||
method: 'PUT',
|
||||
url: server.url,
|
||||
path: captionPath,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
attaches
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown language', async function () {
|
||||
const captionPath = path + video.uuid + '/captions/15'
|
||||
await makeUploadRequest({
|
||||
method: 'PUT',
|
||||
url: server.url,
|
||||
path: captionPath,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
attaches
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without access token', async function () {
|
||||
const captionPath = path + video.uuid + '/captions/fr'
|
||||
await makeUploadRequest({
|
||||
method: 'PUT',
|
||||
url: server.url,
|
||||
path: captionPath,
|
||||
fields,
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad access token', async function () {
|
||||
const captionPath = path + video.uuid + '/captions/fr'
|
||||
await makeUploadRequest({
|
||||
method: 'PUT',
|
||||
url: server.url,
|
||||
path: captionPath,
|
||||
token: 'blabla',
|
||||
fields,
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with another user token', async function () {
|
||||
const captionPath = path + video.uuid + '/captions/fr'
|
||||
await makeUploadRequest({
|
||||
method: 'PUT',
|
||||
url: server.url,
|
||||
path: captionPath,
|
||||
token: userAccessToken,
|
||||
fields,
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
// We accept any file now
|
||||
// it('Should fail with an invalid captionfile extension', async function () {
|
||||
// const attaches = {
|
||||
// 'captionfile': buildAbsoluteFixturePath('subtitle-bad.txt')
|
||||
// }
|
||||
//
|
||||
// const captionPath = path + video.uuid + '/captions/fr'
|
||||
// await makeUploadRequest({
|
||||
// method: 'PUT',
|
||||
// url: server.url,
|
||||
// path: captionPath,
|
||||
// token: server.accessToken,
|
||||
// fields,
|
||||
// attaches,
|
||||
// expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
// })
|
||||
// })
|
||||
|
||||
// We don't check the extension yet
|
||||
// it('Should fail with an invalid captionfile extension and octet-stream mime type', async function () {
|
||||
// await createVideoCaption({
|
||||
// url: server.url,
|
||||
// accessToken: server.accessToken,
|
||||
// language: 'zh',
|
||||
// videoId: video.uuid,
|
||||
// fixture: 'subtitle-bad.txt',
|
||||
// mimeType: 'application/octet-stream',
|
||||
// expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
// })
|
||||
// })
|
||||
|
||||
it('Should succeed with a valid captionfile extension and octet-stream mime type', async function () {
|
||||
await server.captions.add({
|
||||
language: 'zh',
|
||||
videoId: video.uuid,
|
||||
fixture: 'subtitle-good.srt',
|
||||
mimeType: 'application/octet-stream'
|
||||
})
|
||||
})
|
||||
|
||||
// We don't check the file validity yet
|
||||
// it('Should fail with an invalid captionfile srt', async function () {
|
||||
// const attaches = {
|
||||
// 'captionfile': buildAbsoluteFixturePath('subtitle-bad.srt')
|
||||
// }
|
||||
//
|
||||
// const captionPath = path + video.uuid + '/captions/fr'
|
||||
// await makeUploadRequest({
|
||||
// method: 'PUT',
|
||||
// url: server.url,
|
||||
// path: captionPath,
|
||||
// token: server.accessToken,
|
||||
// fields,
|
||||
// attaches,
|
||||
// expectedStatus: HttpStatusCode.INTERNAL_SERVER_ERROR_500
|
||||
// })
|
||||
// })
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
const captionPath = path + video.uuid + '/captions/fr'
|
||||
await makeUploadRequest({
|
||||
method: 'PUT',
|
||||
url: server.url,
|
||||
path: captionPath,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing video captions', function () {
|
||||
it('Should fail without a valid uuid', async function () {
|
||||
await makeGetRequest({ url: server.url, path: path + '4da6fde3-88f7-4d16-b119-108df563d0b06/captions' })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown id', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/captions',
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a private video without token', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + privateVideo.shortUUID + '/captions',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with another user token', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: userAccessToken,
|
||||
path: path + privateVideo.shortUUID + '/captions',
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path: path + video.shortUUID + '/captions', expectedStatus: HttpStatusCode.OK_200 })
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: path + privateVideo.shortUUID + '/captions',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When deleting video caption', function () {
|
||||
it('Should fail without a valid uuid', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '4da6fde3-88f7-4d16-b119-108df563d0b06/captions/fr',
|
||||
token: server.accessToken
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown id', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/captions/fr',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid language', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/captions/16',
|
||||
token: server.accessToken
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a missing language', async function () {
|
||||
const captionPath = path + video.shortUUID + '/captions'
|
||||
await makeDeleteRequest({ url: server.url, path: captionPath, token: server.accessToken })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown language', async function () {
|
||||
const captionPath = path + video.shortUUID + '/captions/15'
|
||||
await makeDeleteRequest({ url: server.url, path: captionPath, token: server.accessToken })
|
||||
})
|
||||
|
||||
it('Should fail without access token', async function () {
|
||||
const captionPath = path + video.shortUUID + '/captions/fr'
|
||||
await makeDeleteRequest({ url: server.url, path: captionPath, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad access token', async function () {
|
||||
const captionPath = path + video.shortUUID + '/captions/fr'
|
||||
await makeDeleteRequest({ url: server.url, path: captionPath, token: 'coucou', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with another user', async function () {
|
||||
const captionPath = path + video.shortUUID + '/captions/fr'
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: captionPath,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
const captionPath = path + video.shortUUID + '/captions/fr'
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: captionPath,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,319 @@
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { FIXTURE_URLS } from '@tests/shared/fixture-urls.js'
|
||||
import { HttpStatusCode, VideoChannelSyncCreate } from '@peertube/peertube-models'
|
||||
import {
|
||||
ChannelSyncsCommand,
|
||||
createSingleServer,
|
||||
makePostBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
setDefaultVideoChannel
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test video channel sync API validator', () => {
|
||||
const path = '/api/v1/video-channel-syncs'
|
||||
let server: PeerTubeServer
|
||||
let command: ChannelSyncsCommand
|
||||
let rootChannelId: number
|
||||
let rootChannelSyncId: number
|
||||
const userInfo = {
|
||||
accessToken: '',
|
||||
username: 'user1',
|
||||
id: -1,
|
||||
channelId: -1,
|
||||
syncId: -1
|
||||
}
|
||||
|
||||
async function withChannelSyncDisabled<T> (callback: () => Promise<T>): Promise<void> {
|
||||
try {
|
||||
await server.config.disableChannelSync()
|
||||
await callback()
|
||||
} finally {
|
||||
await server.config.enableChannelSync()
|
||||
}
|
||||
}
|
||||
|
||||
async function withMaxSyncsPerUser<T> (maxSync: number, callback: () => Promise<T>): Promise<void> {
|
||||
const origConfig = await server.config.getCustomConfig()
|
||||
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
import: {
|
||||
videoChannelSynchronization: {
|
||||
maxPerUser: maxSync
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
await callback()
|
||||
} finally {
|
||||
await server.config.updateCustomConfig({ newCustomConfig: origConfig })
|
||||
}
|
||||
}
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30_000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultVideoChannel([ server ])
|
||||
|
||||
command = server.channelSyncs
|
||||
|
||||
rootChannelId = server.store.channel.id
|
||||
|
||||
{
|
||||
userInfo.accessToken = await server.users.generateUserAndToken(userInfo.username)
|
||||
|
||||
const { videoChannels, id: userId } = await server.users.getMyInfo({ token: userInfo.accessToken })
|
||||
userInfo.id = userId
|
||||
userInfo.channelId = videoChannels[0].id
|
||||
}
|
||||
|
||||
await server.config.enableChannelSync()
|
||||
})
|
||||
|
||||
describe('When creating a sync', function () {
|
||||
let baseCorrectParams: VideoChannelSyncCreate
|
||||
|
||||
before(function () {
|
||||
baseCorrectParams = {
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel,
|
||||
videoChannelId: rootChannelId
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail when sync is disabled', async function () {
|
||||
await withChannelSyncDisabled(async () => {
|
||||
await command.create({
|
||||
token: server.accessToken,
|
||||
attributes: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with nothing', async function () {
|
||||
const fields = {}
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with no authentication', async function () {
|
||||
await command.create({
|
||||
token: null,
|
||||
attributes: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without a target url', async function () {
|
||||
const attributes: VideoChannelSyncCreate = {
|
||||
...baseCorrectParams,
|
||||
externalChannelUrl: null
|
||||
}
|
||||
await command.create({
|
||||
token: server.accessToken,
|
||||
attributes,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without a channelId', async function () {
|
||||
const attributes: VideoChannelSyncCreate = {
|
||||
...baseCorrectParams,
|
||||
videoChannelId: null
|
||||
}
|
||||
await command.create({
|
||||
token: server.accessToken,
|
||||
attributes,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a channelId referring nothing', async function () {
|
||||
const attributes: VideoChannelSyncCreate = {
|
||||
...baseCorrectParams,
|
||||
videoChannelId: 42
|
||||
}
|
||||
await command.create({
|
||||
token: server.accessToken,
|
||||
attributes,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to create a sync when the user does not own the channel', async function () {
|
||||
await command.create({
|
||||
token: userInfo.accessToken,
|
||||
attributes: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed to create a sync with root and for another user\'s channel', async function () {
|
||||
const { videoChannelSync } = await command.create({
|
||||
token: server.accessToken,
|
||||
attributes: {
|
||||
...baseCorrectParams,
|
||||
videoChannelId: userInfo.channelId
|
||||
},
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
userInfo.syncId = videoChannelSync.id
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
const { videoChannelSync } = await command.create({
|
||||
token: server.accessToken,
|
||||
attributes: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
rootChannelSyncId = videoChannelSync.id
|
||||
})
|
||||
|
||||
it('Should fail when the user exceeds allowed number of synchronizations', async function () {
|
||||
await withMaxSyncsPerUser(1, async () => {
|
||||
await command.create({
|
||||
token: server.accessToken,
|
||||
attributes: {
|
||||
...baseCorrectParams,
|
||||
videoChannelId: userInfo.channelId
|
||||
},
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing my channel syncs', function () {
|
||||
const myPath = '/api/v1/accounts/root/video-channel-syncs'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, myPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, myPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, myPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await command.listByAccount({
|
||||
accountName: 'root',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with no authentication', async function () {
|
||||
await command.listByAccount({
|
||||
accountName: 'root',
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail when a simple user lists another user\'s synchronizations', async function () {
|
||||
await command.listByAccount({
|
||||
accountName: 'root',
|
||||
token: userInfo.accessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed when root lists another user\'s synchronizations', async function () {
|
||||
await command.listByAccount({
|
||||
accountName: userInfo.username,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed even with synchronization disabled', async function () {
|
||||
await withChannelSyncDisabled(async function () {
|
||||
await command.listByAccount({
|
||||
accountName: 'root',
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When triggering deletion', function () {
|
||||
it('should fail with no authentication', async function () {
|
||||
await command.delete({
|
||||
channelSyncId: userInfo.syncId,
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail when channelSyncId does not refer to any sync', async function () {
|
||||
await command.delete({
|
||||
channelSyncId: 42,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail when sync is not owned by the user', async function () {
|
||||
await command.delete({
|
||||
channelSyncId: rootChannelSyncId,
|
||||
token: userInfo.accessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed when root delete a sync they do not own', async function () {
|
||||
await command.delete({
|
||||
channelSyncId: userInfo.syncId,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed when user delete a sync they own', async function () {
|
||||
const { videoChannelSync } = await command.create({
|
||||
attributes: {
|
||||
externalChannelUrl: FIXTURE_URLS.youtubeChannel,
|
||||
videoChannelId: userInfo.channelId
|
||||
},
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
|
||||
await command.delete({
|
||||
channelSyncId: videoChannelSync.id,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed even when synchronization is disabled', async function () {
|
||||
await withChannelSyncDisabled(async function () {
|
||||
await command.delete({
|
||||
channelSyncId: rootChannelSyncId,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await server?.kill()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,379 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { expect } from 'chai'
|
||||
import { omit } from '@peertube/peertube-core-utils'
|
||||
import { HttpStatusCode, VideoChannelUpdate } from '@peertube/peertube-models'
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
|
||||
import {
|
||||
ChannelsCommand,
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
makePutBodyRequest,
|
||||
makeUploadRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test video channels API validator', function () {
|
||||
const videoChannelPath = '/api/v1/video-channels'
|
||||
let server: PeerTubeServer
|
||||
const userInfo = {
|
||||
accessToken: '',
|
||||
channelName: 'fake_channel',
|
||||
id: -1,
|
||||
videoQuota: -1,
|
||||
videoQuotaDaily: -1
|
||||
}
|
||||
let command: ChannelsCommand
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
const userCreds = {
|
||||
username: 'fake',
|
||||
password: 'fake_password'
|
||||
}
|
||||
|
||||
{
|
||||
const user = await server.users.create({ username: userCreds.username, password: userCreds.password })
|
||||
userInfo.id = user.id
|
||||
userInfo.accessToken = await server.login.getAccessToken(userCreds)
|
||||
}
|
||||
|
||||
command = server.channels
|
||||
})
|
||||
|
||||
describe('When listing a video channels', function () {
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, videoChannelPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, videoChannelPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, videoChannelPath, server.accessToken)
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing account video channels', function () {
|
||||
const accountChannelPath = '/api/v1/accounts/fake/video-channels'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, accountChannelPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, accountChannelPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, accountChannelPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a unknown account', async function () {
|
||||
await server.channels.listByAccount({ accountName: 'unknown', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: accountChannelPath,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When adding a video channel', function () {
|
||||
const baseCorrectParams = {
|
||||
name: 'super_channel',
|
||||
displayName: 'hello',
|
||||
description: 'super description',
|
||||
support: 'super support text'
|
||||
}
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: videoChannelPath,
|
||||
token: 'none',
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with nothing', async function () {
|
||||
const fields = {}
|
||||
await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail without a name', async function () {
|
||||
const fields = omit(baseCorrectParams, [ 'name' ])
|
||||
await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad name', async function () {
|
||||
const fields = { ...baseCorrectParams, name: 'super name' }
|
||||
await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail without a name', async function () {
|
||||
const fields = omit(baseCorrectParams, [ 'displayName' ])
|
||||
await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long name', async function () {
|
||||
const fields = { ...baseCorrectParams, displayName: 'super'.repeat(25) }
|
||||
await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long description', async function () {
|
||||
const fields = { ...baseCorrectParams, description: 'super'.repeat(201) }
|
||||
await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long support text', async function () {
|
||||
const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
|
||||
await makePostBodyRequest({ url: server.url, path: videoChannelPath, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: videoChannelPath,
|
||||
token: server.accessToken,
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail when adding a channel with the same username', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: videoChannelPath,
|
||||
token: server.accessToken,
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating a video channel', function () {
|
||||
const baseCorrectParams: VideoChannelUpdate = {
|
||||
displayName: 'hello',
|
||||
description: 'super description',
|
||||
support: 'toto',
|
||||
bulkVideosSupportUpdate: false
|
||||
}
|
||||
let path: string
|
||||
|
||||
before(async function () {
|
||||
path = videoChannelPath + '/super_channel'
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: 'hi',
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with another authenticated user', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: userInfo.accessToken,
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a long name', async function () {
|
||||
const fields = { ...baseCorrectParams, displayName: 'super'.repeat(25) }
|
||||
await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long description', async function () {
|
||||
const fields = { ...baseCorrectParams, description: 'super'.repeat(201) }
|
||||
await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long support text', async function () {
|
||||
const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
|
||||
await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad bulkVideosSupportUpdate field', async function () {
|
||||
const fields = { ...baseCorrectParams, bulkVideosSupportUpdate: 'super' }
|
||||
await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating video channel avatars/banners', function () {
|
||||
const types = [ 'avatar', 'banner' ]
|
||||
let path: string
|
||||
|
||||
before(async function () {
|
||||
path = videoChannelPath + '/super_channel'
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect input file', async function () {
|
||||
for (const type of types) {
|
||||
const fields = {}
|
||||
const attaches = {
|
||||
[type + 'file']: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
|
||||
await makeUploadRequest({ url: server.url, path: `${path}/${type}/pick`, token: server.accessToken, fields, attaches })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with a big file', async function () {
|
||||
for (const type of types) {
|
||||
const fields = {}
|
||||
const attaches = {
|
||||
[type + 'file']: buildAbsoluteFixturePath('avatar-big.png')
|
||||
}
|
||||
await makeUploadRequest({ url: server.url, path: `${path}/${type}/pick`, token: server.accessToken, fields, attaches })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
for (const type of types) {
|
||||
const fields = {}
|
||||
const attaches = {
|
||||
[type + 'file']: buildAbsoluteFixturePath('avatar.png')
|
||||
}
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
path: `${path}/${type}/pick`,
|
||||
fields,
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
for (const type of types) {
|
||||
const fields = {}
|
||||
const attaches = {
|
||||
[type + 'file']: buildAbsoluteFixturePath('avatar.png')
|
||||
}
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
path: `${path}/${type}/pick`,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting a video channel', function () {
|
||||
it('Should return the list of the video channels with nothing', async function () {
|
||||
const res = await makeGetRequest({
|
||||
url: server.url,
|
||||
path: videoChannelPath,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
|
||||
expect(res.body.data).to.be.an('array')
|
||||
})
|
||||
|
||||
it('Should return 404 with an incorrect video channel', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: videoChannelPath + '/super_channel2',
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: videoChannelPath + '/super_channel',
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting channel followers', function () {
|
||||
const path = '/api/v1/video-channels/super_channel/followers'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a unauthenticated user', async function () {
|
||||
await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a another user', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: userInfo.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeGetRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When deleting a video channel', function () {
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await command.delete({ token: 'coucou', channelName: 'super_channel', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with another authenticated user', async function () {
|
||||
await command.delete({ token: userInfo.accessToken, channelName: 'super_channel', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown video channel id', async function () {
|
||||
await command.delete({ channelName: 'super_channel2', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await command.delete({ channelName: 'super_channel' })
|
||||
})
|
||||
|
||||
it('Should fail to delete the last user video channel', async function () {
|
||||
await command.delete({ channelName: 'root_channel', expectedStatus: HttpStatusCode.CONFLICT_409 })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,172 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode, Video, VideoCreateResult, VideoPrivacy } from '@peertube/peertube-models'
|
||||
import {
|
||||
PeerTubeServer,
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
setAccessTokensToServers,
|
||||
setDefaultVideoChannel
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test videos chapters API validator', function () {
|
||||
let server: PeerTubeServer
|
||||
let video: VideoCreateResult
|
||||
let live: Video
|
||||
let privateVideo: VideoCreateResult
|
||||
let userAccessToken: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultVideoChannel([ server ])
|
||||
|
||||
video = await server.videos.upload()
|
||||
privateVideo = await server.videos.upload({ attributes: { privacy: VideoPrivacy.PRIVATE } })
|
||||
userAccessToken = await server.users.generateUserAndToken('user1')
|
||||
|
||||
await server.config.enableLive({ allowReplay: false })
|
||||
|
||||
const res = await server.live.quickCreate({ saveReplay: false, permanentLive: false })
|
||||
live = res.video
|
||||
})
|
||||
|
||||
describe('When updating chapters', function () {
|
||||
|
||||
it('Should fail without a valid uuid', async function () {
|
||||
await server.chapters.update({ videoId: '4da6fd', chapters: [], expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown id', async function () {
|
||||
await server.chapters.update({
|
||||
videoId: 'ce0801ef-7124-48df-9b22-b473ace78797',
|
||||
chapters: [],
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without access token', async function () {
|
||||
await server.chapters.update({
|
||||
videoId: video.id,
|
||||
chapters: [],
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad access token', async function () {
|
||||
await server.chapters.update({
|
||||
videoId: video.id,
|
||||
chapters: [],
|
||||
token: 'toto',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a another user access token', async function () {
|
||||
await server.chapters.update({
|
||||
videoId: video.id,
|
||||
chapters: [],
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a wrong chapters param', async function () {
|
||||
await server.chapters.update({
|
||||
videoId: video.id,
|
||||
chapters: 'hello' as any,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad chapter title', async function () {
|
||||
await server.chapters.update({
|
||||
videoId: video.id,
|
||||
chapters: [ { title: 'hello', timecode: 21 }, { title: '', timecode: 21 } ],
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await server.chapters.update({
|
||||
videoId: video.id,
|
||||
chapters: [ { title: 'hello', timecode: 21 }, { title: 'a'.repeat(150), timecode: 21 } ],
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad timecode', async function () {
|
||||
await server.chapters.update({
|
||||
videoId: video.id,
|
||||
chapters: [ { title: 'hello', timecode: 21 }, { title: 'title', timecode: -5 } ],
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
|
||||
await server.chapters.update({
|
||||
videoId: video.id,
|
||||
chapters: [ { title: 'hello', timecode: 21 }, { title: 'title', timecode: 'hi' as any } ],
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with non unique timecodes', async function () {
|
||||
await server.chapters.update({
|
||||
videoId: video.id,
|
||||
chapters: [ { title: 'hello', timecode: 21 }, { title: 'title', timecode: 22 }, { title: 'hello', timecode: 21 } ],
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to create chapters on a live', async function () {
|
||||
await server.chapters.update({
|
||||
videoId: live.id,
|
||||
chapters: [],
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.chapters.update({
|
||||
videoId: video.id,
|
||||
chapters: []
|
||||
})
|
||||
|
||||
await server.chapters.update({
|
||||
videoId: video.id,
|
||||
chapters: [ { title: 'hello', timecode: 21 }, { title: 'hello 2', timecode: 35 } ]
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing chapters', function () {
|
||||
|
||||
it('Should fail without a valid uuid', async function () {
|
||||
await server.chapters.list({ videoId: '4da6fd', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown id', async function () {
|
||||
await server.chapters.list({ videoId: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should not list private chapters to anyone', async function () {
|
||||
await server.chapters.list({ videoId: privateVideo.uuid, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should not list private chapters to another user', async function () {
|
||||
await server.chapters.list({ videoId: privateVideo.uuid, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should list chapters', async function () {
|
||||
await server.chapters.list({ videoId: privateVideo.uuid })
|
||||
await server.chapters.list({ videoId: video.uuid })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,576 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode, VideoCommentPolicy, VideoCreateResult, VideoPrivacy } from '@peertube/peertube-models'
|
||||
import {
|
||||
PeerTubeServer,
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeDeleteRequest,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
setAccessTokensToServers,
|
||||
setDefaultVideoChannel
|
||||
} from '@peertube/peertube-server-commands'
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { expect } from 'chai'
|
||||
|
||||
describe('Test video comments API validator', function () {
|
||||
let pathThread: string
|
||||
let pathComment: string
|
||||
|
||||
let server: PeerTubeServer
|
||||
|
||||
let video: VideoCreateResult
|
||||
|
||||
let userAccessToken: string
|
||||
let userAccessToken2: string
|
||||
|
||||
let commentId: number
|
||||
let privateCommentId: number
|
||||
let privateVideo: VideoCreateResult
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultVideoChannel([ server ])
|
||||
|
||||
{
|
||||
video = await server.videos.upload({ attributes: {} })
|
||||
pathThread = '/api/v1/videos/' + video.uuid + '/comment-threads'
|
||||
}
|
||||
|
||||
{
|
||||
privateVideo = await server.videos.upload({ attributes: { privacy: VideoPrivacy.PRIVATE } })
|
||||
}
|
||||
|
||||
{
|
||||
const created = await server.comments.createThread({ videoId: video.uuid, text: 'coucou' })
|
||||
commentId = created.id
|
||||
pathComment = '/api/v1/videos/' + video.uuid + '/comments/' + commentId
|
||||
}
|
||||
|
||||
{
|
||||
const created = await server.comments.createThread({ videoId: privateVideo.uuid, text: 'coucou' })
|
||||
privateCommentId = created.id
|
||||
}
|
||||
|
||||
{
|
||||
const user = { username: 'user1', password: 'my super password' }
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
userAccessToken = await server.login.getAccessToken(user)
|
||||
}
|
||||
|
||||
{
|
||||
const user = { username: 'user2', password: 'my super password' }
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
userAccessToken2 = await server.login.getAccessToken(user)
|
||||
}
|
||||
})
|
||||
|
||||
describe('When listing video comment threads', function () {
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, pathThread, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, pathThread, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, pathThread, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect video', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comment-threads',
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a private video without token', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with another user token', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: userAccessToken,
|
||||
path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads',
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads',
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing comments of a thread', function () {
|
||||
it('Should fail with an incorrect video', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comment-threads/' + commentId,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect thread id', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: '/api/v1/videos/' + video.shortUUID + '/comment-threads/156',
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a private video without token', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads/' + privateCommentId,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with another user token', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: userAccessToken,
|
||||
path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads/' + privateCommentId,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should success with the correct params', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads/' + privateCommentId,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: '/api/v1/videos/' + video.shortUUID + '/comment-threads/' + commentId,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When adding a video thread', function () {
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
const fields = {
|
||||
text: 'text'
|
||||
}
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: pathThread,
|
||||
token: 'none',
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with nothing', async function () {
|
||||
const fields = {}
|
||||
await makePostBodyRequest({ url: server.url, path: pathThread, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a short comment', async function () {
|
||||
const fields = {
|
||||
text: ''
|
||||
}
|
||||
await makePostBodyRequest({ url: server.url, path: pathThread, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long comment', async function () {
|
||||
const fields = {
|
||||
text: 'h'.repeat(10001)
|
||||
}
|
||||
await makePostBodyRequest({ url: server.url, path: pathThread, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect video', async function () {
|
||||
const path = '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comment-threads'
|
||||
const fields = { text: 'super comment' }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a private video of another user', async function () {
|
||||
const fields = { text: 'super comment' }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: '/api/v1/videos/' + privateVideo.shortUUID + '/comment-threads',
|
||||
token: userAccessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
const fields = { text: 'super comment' }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: pathThread,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When adding a comment to a thread', function () {
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
const fields = {
|
||||
text: 'text'
|
||||
}
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: pathComment,
|
||||
token: 'none',
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with nothing', async function () {
|
||||
const fields = {}
|
||||
await makePostBodyRequest({ url: server.url, path: pathComment, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a short comment', async function () {
|
||||
const fields = {
|
||||
text: ''
|
||||
}
|
||||
await makePostBodyRequest({ url: server.url, path: pathComment, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long comment', async function () {
|
||||
const fields = {
|
||||
text: 'h'.repeat(10001)
|
||||
}
|
||||
await makePostBodyRequest({ url: server.url, path: pathComment, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect video', async function () {
|
||||
const path = '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comments/' + commentId
|
||||
const fields = {
|
||||
text: 'super comment'
|
||||
}
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a private video of another user', async function () {
|
||||
const fields = { text: 'super comment' }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: '/api/v1/videos/' + privateVideo.uuid + '/comments/' + privateCommentId,
|
||||
token: userAccessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect comment', async function () {
|
||||
const path = '/api/v1/videos/' + video.uuid + '/comments/124'
|
||||
const fields = {
|
||||
text: 'super comment'
|
||||
}
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
const fields = {
|
||||
text: 'super comment'
|
||||
}
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: pathComment,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When removing video comments', function () {
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await makeDeleteRequest({ url: server.url, path: pathComment, token: 'none', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with another user', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: pathComment,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect video', async function () {
|
||||
const path = '/api/v1/videos/ba708d62-e3d7-45d9-9d73-41b9097cc02d/comments/' + commentId
|
||||
await makeDeleteRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect comment', async function () {
|
||||
const path = '/api/v1/videos/' + video.uuid + '/comments/124'
|
||||
await makeDeleteRequest({ url: server.url, path, token: server.accessToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the same user', async function () {
|
||||
let commentToDelete: number
|
||||
|
||||
{
|
||||
const created = await server.comments.createThread({ videoId: video.uuid, token: userAccessToken, text: 'hello' })
|
||||
commentToDelete = created.id
|
||||
}
|
||||
|
||||
const path = '/api/v1/videos/' + video.uuid + '/comments/' + commentToDelete
|
||||
|
||||
await makeDeleteRequest({ url: server.url, path, token: userAccessToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
await makeDeleteRequest({ url: server.url, path, token: userAccessToken, expectedStatus: HttpStatusCode.NO_CONTENT_204 })
|
||||
})
|
||||
|
||||
it('Should succeed with the owner of the video', async function () {
|
||||
let commentToDelete: number
|
||||
let anotherVideoUUID: string
|
||||
|
||||
{
|
||||
const { uuid } = await server.videos.upload({ token: userAccessToken, attributes: { name: 'video' } })
|
||||
anotherVideoUUID = uuid
|
||||
}
|
||||
|
||||
{
|
||||
const created = await server.comments.createThread({ videoId: anotherVideoUUID, text: 'hello' })
|
||||
commentToDelete = created.id
|
||||
}
|
||||
|
||||
const path = '/api/v1/videos/' + anotherVideoUUID + '/comments/' + commentToDelete
|
||||
|
||||
await makeDeleteRequest({ url: server.url, path, token: userAccessToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
await makeDeleteRequest({ url: server.url, path, token: userAccessToken, expectedStatus: HttpStatusCode.NO_CONTENT_204 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path: pathComment,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When a video has comments disabled', function () {
|
||||
|
||||
before(async function () {
|
||||
video = await server.videos.upload({ attributes: { commentsPolicy: VideoCommentPolicy.DISABLED } })
|
||||
pathThread = `/api/v1/videos/${video.uuid}/comment-threads`
|
||||
})
|
||||
|
||||
it('Should return an empty thread list', async function () {
|
||||
const res = await makeGetRequest({
|
||||
url: server.url,
|
||||
path: pathThread,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
expect(res.body.total).to.equal(0)
|
||||
expect(res.body.data).to.have.lengthOf(0)
|
||||
})
|
||||
|
||||
it('Should return an thread comments list')
|
||||
|
||||
it('Should return conflict on thread add', async function () {
|
||||
const fields = {
|
||||
text: 'super comment'
|
||||
}
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: pathThread,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should return conflict on comment thread add')
|
||||
})
|
||||
|
||||
describe('When listing admin/user comments', function () {
|
||||
const paths = [ '/api/v1/videos/comments', '/api/v1/users/me/videos/comments' ]
|
||||
|
||||
it('Should fail with a bad start/count pagination of invalid sort', async function () {
|
||||
for (const path of paths) {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await server.comments.listForAdmin({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
await server.comments.listCommentsOnMyVideos({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail to list admin comments with a non admin user', async function () {
|
||||
await server.comments.listForAdmin({ token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid video', async function () {
|
||||
await server.comments.listForAdmin({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await server.comments.listCommentsOnMyVideos({ videoId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
await server.comments.listForAdmin({ videoId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await server.comments.listCommentsOnMyVideos({ videoId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid channel', async function () {
|
||||
await server.comments.listForAdmin({ videoChannelId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await server.comments.listCommentsOnMyVideos({ videoChannelId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
await server.comments.listForAdmin({ videoChannelId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await server.comments.listCommentsOnMyVideos({ videoChannelId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail to list comments on my videos with non owned video or channel', async function () {
|
||||
await server.comments.listCommentsOnMyVideos({
|
||||
videoId: video.uuid,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
|
||||
await server.comments.listCommentsOnMyVideos({
|
||||
videoChannelId: server.store.channel.id,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
const base = {
|
||||
search: 'toto',
|
||||
searchAccount: 'toto',
|
||||
searchVideo: 'toto',
|
||||
videoId: video.uuid,
|
||||
videoChannelId: server.store.channel.id,
|
||||
autoTagOneOf: [ 'external-link' ]
|
||||
}
|
||||
|
||||
await server.comments.listForAdmin({ ...base, isLocal: false })
|
||||
await server.comments.listCommentsOnMyVideos(base)
|
||||
})
|
||||
})
|
||||
|
||||
describe('When approving a comment', function () {
|
||||
let videoId: string
|
||||
let commentId: number
|
||||
let deletedCommentId: number
|
||||
let userAccessToken3: string
|
||||
|
||||
before(async function () {
|
||||
userAccessToken3 = await server.users.generateUserAndToken('user3')
|
||||
|
||||
{
|
||||
const res = await server.videos.upload({
|
||||
token: userAccessToken,
|
||||
attributes: {
|
||||
name: 'review policy',
|
||||
commentsPolicy: VideoCommentPolicy.REQUIRES_APPROVAL
|
||||
}
|
||||
})
|
||||
|
||||
videoId = res.uuid
|
||||
}
|
||||
|
||||
{
|
||||
const res = await server.comments.createThread({ text: 'thread', videoId, token: userAccessToken2 })
|
||||
commentId = res.id
|
||||
}
|
||||
|
||||
{
|
||||
const res = await server.comments.createThread({ text: 'deleted', videoId, token: userAccessToken2 })
|
||||
deletedCommentId = res.id
|
||||
|
||||
await server.comments.delete({ commentId: deletedCommentId, videoId })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with a non authenticated user', async function () {
|
||||
await server.comments.approve({ token: 'none', commentId, videoId, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with another user', async function () {
|
||||
await server.comments.approve({ token: userAccessToken3, commentId, videoId, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with the owner', async function () {
|
||||
await server.comments.approve({ token: userAccessToken2, commentId, videoId, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect video', async function () {
|
||||
await server.comments.approve({ token: userAccessToken, commentId, videoId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect comment', async function () {
|
||||
await server.comments.approve({ token: userAccessToken, commentId: 42, videoId, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a deleted comment', async function () {
|
||||
await server.comments.approve({
|
||||
token: userAccessToken,
|
||||
commentId: deletedCommentId,
|
||||
videoId,
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.comments.approve({ token: userAccessToken, commentId, videoId })
|
||||
})
|
||||
|
||||
it('Should fail with an already held for review comment', async function () {
|
||||
await server.comments.approve({ token: userAccessToken, commentId, videoId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,195 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { getAllFiles } from '@peertube/peertube-core-utils'
|
||||
import { HttpStatusCode, UserRole, VideoDetails, VideoPrivacy } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createMultipleServers,
|
||||
doubleFollow,
|
||||
makeRawRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test videos files', function () {
|
||||
let servers: PeerTubeServer[]
|
||||
|
||||
let userToken: string
|
||||
let moderatorToken: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(300_000)
|
||||
|
||||
servers = await createMultipleServers(2)
|
||||
await setAccessTokensToServers(servers)
|
||||
|
||||
await doubleFollow(servers[0], servers[1])
|
||||
|
||||
userToken = await servers[0].users.generateUserAndToken('user', UserRole.USER)
|
||||
moderatorToken = await servers[0].users.generateUserAndToken('moderator', UserRole.MODERATOR)
|
||||
})
|
||||
|
||||
describe('Getting metadata', function () {
|
||||
let video: VideoDetails
|
||||
|
||||
before(async function () {
|
||||
const { uuid } = await servers[0].videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE })
|
||||
video = await servers[0].videos.getWithToken({ id: uuid })
|
||||
})
|
||||
|
||||
it('Should not get metadata of private video without token', async function () {
|
||||
for (const file of getAllFiles(video)) {
|
||||
await makeRawRequest({ url: file.metadataUrl, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should not get metadata of private video without the appropriate token', async function () {
|
||||
for (const file of getAllFiles(video)) {
|
||||
await makeRawRequest({ url: file.metadataUrl, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should get metadata of private video with the appropriate token', async function () {
|
||||
for (const file of getAllFiles(video)) {
|
||||
await makeRawRequest({ url: file.metadataUrl, token: servers[0].accessToken, expectedStatus: HttpStatusCode.OK_200 })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('Deleting files', function () {
|
||||
let webVideoId: string
|
||||
let hlsId: string
|
||||
let remoteId: string
|
||||
|
||||
let validId1: string
|
||||
let validId2: string
|
||||
|
||||
let hlsFileId: number
|
||||
let webVideoFileId: number
|
||||
|
||||
let remoteHLSFileId: number
|
||||
let remoteWebVideoFileId: number
|
||||
|
||||
before(async function () {
|
||||
this.timeout(300_000)
|
||||
|
||||
{
|
||||
const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' })
|
||||
await waitJobs(servers)
|
||||
|
||||
const video = await servers[1].videos.get({ id: uuid })
|
||||
remoteId = video.uuid
|
||||
remoteHLSFileId = video.streamingPlaylists[0].files[0].id
|
||||
remoteWebVideoFileId = video.files[0].id
|
||||
}
|
||||
|
||||
{
|
||||
await servers[0].config.enableTranscoding({ hls: true, webVideo: true })
|
||||
|
||||
{
|
||||
const { uuid } = await servers[0].videos.quickUpload({ name: 'both 1' })
|
||||
await waitJobs(servers)
|
||||
|
||||
const video = await servers[0].videos.get({ id: uuid })
|
||||
validId1 = video.uuid
|
||||
hlsFileId = video.streamingPlaylists[0].files[0].id
|
||||
webVideoFileId = video.files[0].id
|
||||
}
|
||||
|
||||
{
|
||||
const { uuid } = await servers[0].videos.quickUpload({ name: 'both 2' })
|
||||
validId2 = uuid
|
||||
}
|
||||
}
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
{
|
||||
await servers[0].config.enableTranscoding({ hls: true, webVideo: false })
|
||||
const { uuid } = await servers[0].videos.quickUpload({ name: 'hls' })
|
||||
hlsId = uuid
|
||||
}
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
{
|
||||
await servers[0].config.enableTranscoding({ webVideo: true, hls: false })
|
||||
const { uuid } = await servers[0].videos.quickUpload({ name: 'web-video' })
|
||||
webVideoId = uuid
|
||||
}
|
||||
|
||||
await waitJobs(servers)
|
||||
})
|
||||
|
||||
it('Should not delete files of a unknown video', async function () {
|
||||
const expectedStatus = HttpStatusCode.NOT_FOUND_404
|
||||
|
||||
await servers[0].videos.removeHLSPlaylist({ videoId: 404, expectedStatus })
|
||||
await servers[0].videos.removeAllWebVideoFiles({ videoId: 404, expectedStatus })
|
||||
|
||||
await servers[0].videos.removeHLSFile({ videoId: 404, fileId: hlsFileId, expectedStatus })
|
||||
await servers[0].videos.removeWebVideoFile({ videoId: 404, fileId: webVideoFileId, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should not delete unknown files', async function () {
|
||||
const expectedStatus = HttpStatusCode.NOT_FOUND_404
|
||||
|
||||
await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: webVideoFileId, expectedStatus })
|
||||
await servers[0].videos.removeWebVideoFile({ videoId: validId1, fileId: hlsFileId, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should not delete files of a remote video', async function () {
|
||||
const expectedStatus = HttpStatusCode.BAD_REQUEST_400
|
||||
|
||||
await servers[0].videos.removeHLSPlaylist({ videoId: remoteId, expectedStatus })
|
||||
await servers[0].videos.removeAllWebVideoFiles({ videoId: remoteId, expectedStatus })
|
||||
|
||||
await servers[0].videos.removeHLSFile({ videoId: remoteId, fileId: remoteHLSFileId, expectedStatus })
|
||||
await servers[0].videos.removeWebVideoFile({ videoId: remoteId, fileId: remoteWebVideoFileId, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should not delete files by a non admin user', async function () {
|
||||
const expectedStatus = HttpStatusCode.FORBIDDEN_403
|
||||
|
||||
await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: userToken, expectedStatus })
|
||||
await servers[0].videos.removeHLSPlaylist({ videoId: validId1, token: moderatorToken, expectedStatus })
|
||||
|
||||
await servers[0].videos.removeAllWebVideoFiles({ videoId: validId1, token: userToken, expectedStatus })
|
||||
await servers[0].videos.removeAllWebVideoFiles({ videoId: validId1, token: moderatorToken, expectedStatus })
|
||||
|
||||
await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: userToken, expectedStatus })
|
||||
await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId, token: moderatorToken, expectedStatus })
|
||||
|
||||
await servers[0].videos.removeWebVideoFile({ videoId: validId1, fileId: webVideoFileId, token: userToken, expectedStatus })
|
||||
await servers[0].videos.removeWebVideoFile({ videoId: validId1, fileId: webVideoFileId, token: moderatorToken, expectedStatus })
|
||||
})
|
||||
|
||||
it('Should not delete files if the files are not available', async function () {
|
||||
await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await servers[0].videos.removeAllWebVideoFiles({ videoId: webVideoId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
await servers[0].videos.removeHLSFile({ videoId: hlsId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await servers[0].videos.removeWebVideoFile({ videoId: webVideoId, fileId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should not delete files if no both versions are available', async function () {
|
||||
await servers[0].videos.removeHLSPlaylist({ videoId: hlsId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await servers[0].videos.removeAllWebVideoFiles({ videoId: webVideoId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should delete files if both versions are available', async function () {
|
||||
await servers[0].videos.removeHLSFile({ videoId: validId1, fileId: hlsFileId })
|
||||
await servers[0].videos.removeWebVideoFile({ videoId: validId1, fileId: webVideoFileId })
|
||||
|
||||
await servers[0].videos.removeHLSPlaylist({ videoId: validId1 })
|
||||
await servers[0].videos.removeAllWebVideoFiles({ videoId: validId2 })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests(servers)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,439 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { omit } from '@peertube/peertube-core-utils'
|
||||
import { HttpStatusCode, VideoCommentPolicy, VideoImportCreate, VideoPrivacy } from '@peertube/peertube-models'
|
||||
import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
|
||||
import {
|
||||
PeerTubeServer,
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
makeUploadRequest,
|
||||
setAccessTokensToServers,
|
||||
setDefaultVideoChannel,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { FIXTURE_URLS } from '@tests/shared/fixture-urls.js'
|
||||
|
||||
describe('Test video imports API validator', function () {
|
||||
const path = '/api/v1/videos/imports'
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken = ''
|
||||
let channelId: number
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultVideoChannel([ server ])
|
||||
|
||||
const username = 'user1'
|
||||
const password = 'my super password'
|
||||
await server.users.create({ username, password })
|
||||
userAccessToken = await server.login.getAccessToken({ username, password })
|
||||
|
||||
{
|
||||
const { videoChannels } = await server.users.getMyInfo()
|
||||
channelId = videoChannels[0].id
|
||||
}
|
||||
})
|
||||
|
||||
describe('When listing my video imports', function () {
|
||||
const myPath = '/api/v1/users/me/videos/imports'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, myPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, myPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, myPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad videoChannelSyncId param', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: myPath,
|
||||
query: { videoChannelSyncId: 'toto' },
|
||||
token: server.accessToken
|
||||
})
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path: myPath, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When adding a video import', function () {
|
||||
let baseCorrectParams: VideoImportCreate
|
||||
|
||||
before(function () {
|
||||
baseCorrectParams = {
|
||||
targetUrl: FIXTURE_URLS.goodVideo,
|
||||
name: 'my super name',
|
||||
category: 5,
|
||||
licence: 1,
|
||||
language: 'pt',
|
||||
nsfw: false,
|
||||
commentsPolicy: VideoCommentPolicy.ENABLED,
|
||||
downloadEnabled: true,
|
||||
waitTranscoding: true,
|
||||
description: 'my super description',
|
||||
support: 'my super support text',
|
||||
tags: [ 'tag1', 'tag2' ],
|
||||
privacy: VideoPrivacy.PUBLIC,
|
||||
channelId
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with nothing', async function () {
|
||||
const fields = {}
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without a target url', async function () {
|
||||
const fields = omit(baseCorrectParams, [ 'targetUrl' ])
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad target url', async function () {
|
||||
const fields = { ...baseCorrectParams, targetUrl: 'htt://hello' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with localhost', async function () {
|
||||
const fields = { ...baseCorrectParams, targetUrl: 'http://localhost:8000' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a private IP target urls', async function () {
|
||||
const targetUrls = [
|
||||
'http://127.0.0.1:8000',
|
||||
'http://127.0.0.1',
|
||||
'http://127.0.0.1/hello',
|
||||
'https://192.168.1.42',
|
||||
'http://192.168.1.42',
|
||||
'http://127.0.0.1.cpy.re'
|
||||
]
|
||||
|
||||
for (const targetUrl of targetUrls) {
|
||||
const fields = { ...baseCorrectParams, targetUrl }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with a long name', async function () {
|
||||
const fields = { ...baseCorrectParams, name: 'super'.repeat(65) }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad category', async function () {
|
||||
const fields = { ...baseCorrectParams, category: 125 }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad licence', async function () {
|
||||
const fields = { ...baseCorrectParams, licence: 125 }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad language', async function () {
|
||||
const fields = { ...baseCorrectParams, language: 'a'.repeat(15) }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad commentsPolicy', async function () {
|
||||
const fields = { ...baseCorrectParams, commentsPolicy: 42 }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long description', async function () {
|
||||
const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long support text', async function () {
|
||||
const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail without a channel', async function () {
|
||||
const fields = omit(baseCorrectParams, [ 'channelId' ])
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad channel', async function () {
|
||||
const fields = { ...baseCorrectParams, channelId: 545454 }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with another user channel', async function () {
|
||||
const user = {
|
||||
username: 'fake',
|
||||
password: 'fake_password'
|
||||
}
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
|
||||
const accessTokenUser = await server.login.getAccessToken(user)
|
||||
const { videoChannels } = await server.users.getMyInfo({ token: accessTokenUser })
|
||||
const customChannelId = videoChannels[0].id
|
||||
|
||||
const fields = { ...baseCorrectParams, channelId: customChannelId }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with too many tags', async function () {
|
||||
const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a tag length too low', async function () {
|
||||
const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a tag length too big', async function () {
|
||||
const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect thumbnail file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
thumbnailfile: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
|
||||
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
|
||||
})
|
||||
|
||||
it('Should fail with a big thumbnail file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
thumbnailfile: buildAbsoluteFixturePath('custom-preview-big.png')
|
||||
}
|
||||
|
||||
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect preview file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
previewfile: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
|
||||
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
|
||||
})
|
||||
|
||||
it('Should fail with a big preview file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
previewfile: buildAbsoluteFixturePath('custom-preview-big.png')
|
||||
}
|
||||
|
||||
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid torrent file', async function () {
|
||||
const fields = omit(baseCorrectParams, [ 'targetUrl' ])
|
||||
const attaches = {
|
||||
torrentfile: buildAbsoluteFixturePath('avatar-big.png')
|
||||
}
|
||||
|
||||
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid magnet URI', async function () {
|
||||
let fields = omit(baseCorrectParams, [ 'targetUrl' ])
|
||||
fields = { ...fields, magnetUri: 'blabla' }
|
||||
|
||||
await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
|
||||
it('Should forbid to import http videos', async function () {
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
import: {
|
||||
videos: {
|
||||
http: {
|
||||
enabled: false
|
||||
},
|
||||
torrent: {
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields: baseCorrectParams,
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
|
||||
it('Should forbid to import torrent videos', async function () {
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
import: {
|
||||
videos: {
|
||||
http: {
|
||||
enabled: true
|
||||
},
|
||||
torrent: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let fields = omit(baseCorrectParams, [ 'targetUrl' ])
|
||||
fields = { ...fields, magnetUri: FIXTURE_URLS.magnet }
|
||||
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
|
||||
fields = omit(fields, [ 'magnetUri' ])
|
||||
const attaches = {
|
||||
torrentfile: buildAbsoluteFixturePath('video-720p.torrent')
|
||||
}
|
||||
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
attaches,
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Deleting/cancelling a video import', function () {
|
||||
let importId: number
|
||||
|
||||
async function importVideo () {
|
||||
const attributes = { channelId: server.store.channel.id, targetUrl: FIXTURE_URLS.goodVideo }
|
||||
const res = await server.videoImports.importVideo({ attributes })
|
||||
|
||||
return res.id
|
||||
}
|
||||
|
||||
before(async function () {
|
||||
importId = await importVideo()
|
||||
})
|
||||
|
||||
it('Should fail with an invalid import id', async function () {
|
||||
await server.videoImports.cancel({ importId: 'artyom' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await server.videoImports.delete({ importId: 'artyom' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown import id', async function () {
|
||||
await server.videoImports.cancel({ importId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await server.videoImports.delete({ importId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await server.videoImports.cancel({ importId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
await server.videoImports.delete({ importId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with another user token', async function () {
|
||||
await server.videoImports.cancel({ importId, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
await server.videoImports.delete({ importId, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail to cancel non pending import', async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
await waitJobs([ server ])
|
||||
|
||||
await server.videoImports.cancel({ importId, expectedStatus: HttpStatusCode.CONFLICT_409 })
|
||||
})
|
||||
|
||||
it('Should succeed to delete an import', async function () {
|
||||
await server.videoImports.delete({ importId })
|
||||
})
|
||||
|
||||
it('Should fail to delete a pending import', async function () {
|
||||
await server.jobs.pauseJobQueue()
|
||||
|
||||
importId = await importVideo()
|
||||
|
||||
await server.videoImports.delete({ importId, expectedStatus: HttpStatusCode.CONFLICT_409 })
|
||||
})
|
||||
|
||||
it('Should succeed to cancel an import', async function () {
|
||||
importId = await importVideo()
|
||||
|
||||
await server.videoImports.cancel({ importId })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,605 @@
|
||||
import {
|
||||
HttpStatusCode,
|
||||
HttpStatusCodeType,
|
||||
PeerTubeProblemDocument,
|
||||
ServerErrorCode,
|
||||
VideoCommentPolicy,
|
||||
VideoCreateResult,
|
||||
VideoPrivacy
|
||||
} from '@peertube/peertube-models'
|
||||
import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
|
||||
import {
|
||||
PeerTubeServer,
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makePostBodyRequest,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { FIXTURE_URLS } from '@tests/shared/fixture-urls.js'
|
||||
import { checkUploadVideoParam } from '@tests/shared/videos.js'
|
||||
import { expect } from 'chai'
|
||||
|
||||
describe('Test video passwords validator', function () {
|
||||
let path: string
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken = ''
|
||||
let video: VideoCreateResult
|
||||
let channelId: number
|
||||
let publicVideo: VideoCreateResult
|
||||
let commentId: number
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(50000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
live: {
|
||||
enabled: true,
|
||||
latencySetting: {
|
||||
enabled: false
|
||||
},
|
||||
allowReplay: false
|
||||
},
|
||||
import: {
|
||||
videos: {
|
||||
http:{
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
userAccessToken = await server.users.generateUserAndToken('user1')
|
||||
|
||||
{
|
||||
const body = await server.users.getMyInfo()
|
||||
channelId = body.videoChannels[0].id
|
||||
}
|
||||
|
||||
{
|
||||
video = await server.videos.quickUpload({
|
||||
name: 'password protected video',
|
||||
privacy: VideoPrivacy.PASSWORD_PROTECTED,
|
||||
videoPasswords: [ 'password1', 'password2' ]
|
||||
})
|
||||
}
|
||||
path = '/api/v1/videos/'
|
||||
})
|
||||
|
||||
async function checkVideoPasswordOptions (options: {
|
||||
server: PeerTubeServer
|
||||
token: string
|
||||
videoPasswords: string[]
|
||||
expectedStatus: HttpStatusCodeType
|
||||
mode: 'uploadLegacy' | 'uploadResumable' | 'import' | 'updateVideo' | 'updatePasswords' | 'live'
|
||||
}) {
|
||||
const { server, token, videoPasswords, expectedStatus = HttpStatusCode.OK_200, mode } = options
|
||||
const attaches = {
|
||||
fixture: buildAbsoluteFixturePath('video_short.webm')
|
||||
}
|
||||
const baseCorrectParams = {
|
||||
name: 'my super name',
|
||||
category: 5,
|
||||
licence: 1,
|
||||
language: 'pt',
|
||||
nsfw: false,
|
||||
commentsPolicy: VideoCommentPolicy.ENABLED,
|
||||
downloadEnabled: true,
|
||||
waitTranscoding: true,
|
||||
description: 'my super description',
|
||||
support: 'my super support text',
|
||||
tags: [ 'tag1', 'tag2' ],
|
||||
privacy: VideoPrivacy.PASSWORD_PROTECTED,
|
||||
channelId,
|
||||
originallyPublishedAt: new Date().toISOString()
|
||||
}
|
||||
if (mode === 'uploadLegacy') {
|
||||
const fields = { ...baseCorrectParams, videoPasswords }
|
||||
return checkUploadVideoParam({ server, token, attributes: { ...fields, ...attaches }, expectedStatus, mode: 'legacy' })
|
||||
}
|
||||
|
||||
if (mode === 'uploadResumable') {
|
||||
const fields = { ...baseCorrectParams, videoPasswords }
|
||||
return checkUploadVideoParam({ server, token, attributes: { ...fields, ...attaches }, expectedStatus, mode: 'resumable' })
|
||||
}
|
||||
|
||||
if (mode === 'import') {
|
||||
const attributes = { ...baseCorrectParams, targetUrl: FIXTURE_URLS.goodVideo, videoPasswords }
|
||||
return server.videoImports.importVideo({ attributes, expectedStatus })
|
||||
}
|
||||
|
||||
if (mode === 'updateVideo') {
|
||||
const attributes = { ...baseCorrectParams, videoPasswords }
|
||||
return server.videos.update({ token, expectedStatus, id: video.id, attributes })
|
||||
}
|
||||
|
||||
if (mode === 'updatePasswords') {
|
||||
return server.videoPasswords.updateAll({ token, expectedStatus, videoId: video.id, passwords: videoPasswords })
|
||||
}
|
||||
|
||||
if (mode === 'live') {
|
||||
const fields = { ...baseCorrectParams, videoPasswords }
|
||||
|
||||
return server.live.create({ fields, expectedStatus })
|
||||
}
|
||||
}
|
||||
|
||||
function validateVideoPasswordList (mode: 'uploadLegacy' | 'uploadResumable' | 'import' | 'updateVideo' | 'updatePasswords' | 'live') {
|
||||
|
||||
it('Should fail with a password protected privacy without providing a password', async function () {
|
||||
await checkVideoPasswordOptions({
|
||||
server,
|
||||
token: server.accessToken,
|
||||
videoPasswords: undefined,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
|
||||
mode
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a password protected privacy and an empty password list', async function () {
|
||||
const videoPasswords = []
|
||||
|
||||
await checkVideoPasswordOptions({
|
||||
server,
|
||||
token: server.accessToken,
|
||||
videoPasswords,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
|
||||
mode
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a password protected privacy and a too short password', async function () {
|
||||
const videoPasswords = [ 'p' ]
|
||||
|
||||
await checkVideoPasswordOptions({
|
||||
server,
|
||||
token: server.accessToken,
|
||||
videoPasswords,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
|
||||
mode
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a password protected privacy and a too long password', async function () {
|
||||
const videoPasswords = [ 'Very very very very very very very very very very very very very very very very very very long password' ]
|
||||
|
||||
await checkVideoPasswordOptions({
|
||||
server,
|
||||
token: server.accessToken,
|
||||
videoPasswords,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
|
||||
mode
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a password protected privacy and an empty password', async function () {
|
||||
const videoPasswords = [ '' ]
|
||||
|
||||
await checkVideoPasswordOptions({
|
||||
server,
|
||||
token: server.accessToken,
|
||||
videoPasswords,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
|
||||
mode
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a password protected privacy and duplicated passwords', async function () {
|
||||
const videoPasswords = [ 'password', 'password' ]
|
||||
|
||||
await checkVideoPasswordOptions({
|
||||
server,
|
||||
token: server.accessToken,
|
||||
videoPasswords,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
|
||||
mode
|
||||
})
|
||||
})
|
||||
|
||||
if (mode === 'updatePasswords') {
|
||||
it('Should fail for an unauthenticated user', async function () {
|
||||
const videoPasswords = [ 'password' ]
|
||||
await checkVideoPasswordOptions({
|
||||
server,
|
||||
token: null,
|
||||
videoPasswords,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401,
|
||||
mode
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail for an unauthorized user', async function () {
|
||||
const videoPasswords = [ 'password' ]
|
||||
await checkVideoPasswordOptions({
|
||||
server,
|
||||
token: userAccessToken,
|
||||
videoPasswords,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403,
|
||||
mode
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
it('Should succeed with a password protected privacy and correct passwords', async function () {
|
||||
const videoPasswords = [ 'password1', 'password2' ]
|
||||
const expectedStatus = mode === 'updatePasswords' || mode === 'updateVideo'
|
||||
? HttpStatusCode.NO_CONTENT_204
|
||||
: HttpStatusCode.OK_200
|
||||
|
||||
await checkVideoPasswordOptions({ server, token: server.accessToken, videoPasswords, expectedStatus, mode })
|
||||
})
|
||||
}
|
||||
|
||||
describe('When adding or updating a video', function () {
|
||||
describe('Resumable upload', function () {
|
||||
validateVideoPasswordList('uploadResumable')
|
||||
})
|
||||
|
||||
describe('Legacy upload', function () {
|
||||
validateVideoPasswordList('uploadLegacy')
|
||||
})
|
||||
|
||||
describe('When importing a video', function () {
|
||||
validateVideoPasswordList('import')
|
||||
})
|
||||
|
||||
describe('When updating a video', function () {
|
||||
validateVideoPasswordList('updateVideo')
|
||||
})
|
||||
|
||||
describe('When updating the password list of a video', function () {
|
||||
validateVideoPasswordList('updatePasswords')
|
||||
})
|
||||
|
||||
describe('When creating a live', function () {
|
||||
validateVideoPasswordList('live')
|
||||
})
|
||||
})
|
||||
|
||||
async function checkVideoAccessOptions (options: {
|
||||
server: PeerTubeServer
|
||||
token?: string
|
||||
videoPassword?: string
|
||||
expectedStatus: HttpStatusCodeType
|
||||
mode: 'get' | 'getWithPassword' | 'getWithToken' | 'listCaptions' | 'createThread' | 'listThreads' | 'replyThread' | 'rate' | 'token'
|
||||
}) {
|
||||
const { server, token = null, videoPassword, expectedStatus, mode } = options
|
||||
|
||||
if (mode === 'get') {
|
||||
return server.videos.get({ id: video.id, expectedStatus })
|
||||
}
|
||||
|
||||
if (mode === 'getWithToken') {
|
||||
return server.videos.getWithToken({
|
||||
id: video.id,
|
||||
token,
|
||||
expectedStatus
|
||||
})
|
||||
}
|
||||
|
||||
if (mode === 'getWithPassword') {
|
||||
return server.videos.getWithPassword({
|
||||
id: video.id,
|
||||
token,
|
||||
expectedStatus,
|
||||
password: videoPassword
|
||||
})
|
||||
}
|
||||
|
||||
if (mode === 'rate') {
|
||||
return server.videos.rate({
|
||||
id: video.id,
|
||||
token,
|
||||
expectedStatus,
|
||||
rating: 'like',
|
||||
videoPassword
|
||||
})
|
||||
}
|
||||
|
||||
if (mode === 'createThread') {
|
||||
const fields = { text: 'super comment' }
|
||||
const headers = videoPassword !== undefined && videoPassword !== null
|
||||
? { 'x-peertube-video-password': videoPassword }
|
||||
: undefined
|
||||
const body = await makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + video.uuid + '/comment-threads',
|
||||
token,
|
||||
fields,
|
||||
headers,
|
||||
expectedStatus
|
||||
})
|
||||
return JSON.parse(body.text)
|
||||
}
|
||||
|
||||
if (mode === 'replyThread') {
|
||||
const fields = { text: 'super reply' }
|
||||
const headers = videoPassword !== undefined && videoPassword !== null
|
||||
? { 'x-peertube-video-password': videoPassword }
|
||||
: undefined
|
||||
return makePostBodyRequest({
|
||||
url: server.url,
|
||||
path: path + video.uuid + '/comments/' + commentId,
|
||||
token,
|
||||
fields,
|
||||
headers,
|
||||
expectedStatus
|
||||
})
|
||||
}
|
||||
if (mode === 'listThreads') {
|
||||
return server.comments.listThreads({
|
||||
videoId: video.id,
|
||||
token,
|
||||
expectedStatus,
|
||||
videoPassword
|
||||
})
|
||||
}
|
||||
|
||||
if (mode === 'listCaptions') {
|
||||
return server.captions.list({
|
||||
videoId: video.id,
|
||||
token,
|
||||
expectedStatus,
|
||||
videoPassword
|
||||
})
|
||||
}
|
||||
|
||||
if (mode === 'token') {
|
||||
return server.videoToken.create({
|
||||
videoId: video.id,
|
||||
token,
|
||||
expectedStatus,
|
||||
videoPassword
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function checkVideoError (error: any, mode: 'providePassword' | 'incorrectPassword') {
|
||||
const serverCode = mode === 'providePassword'
|
||||
? ServerErrorCode.VIDEO_REQUIRES_PASSWORD
|
||||
: ServerErrorCode.INCORRECT_VIDEO_PASSWORD
|
||||
|
||||
const message = mode === 'providePassword'
|
||||
? 'Please provide a password to access this password protected video'
|
||||
: 'Incorrect video password. Access to the video is denied.'
|
||||
|
||||
if (!error.code) {
|
||||
error = JSON.parse(error.text)
|
||||
}
|
||||
|
||||
expect(error.code).to.equal(serverCode)
|
||||
expect(error.detail).to.equal(message)
|
||||
expect(error.error).to.equal(message)
|
||||
|
||||
expect(error.status).to.equal(HttpStatusCode.FORBIDDEN_403)
|
||||
}
|
||||
|
||||
function validateVideoAccess (mode: 'get' | 'listCaptions' | 'createThread' | 'listThreads' | 'replyThread' | 'rate' | 'token') {
|
||||
const requiresUserAuth = [ 'createThread', 'replyThread', 'rate' ].includes(mode)
|
||||
let tokens: string[]
|
||||
if (!requiresUserAuth) {
|
||||
it('Should fail without providing a password for an unlogged user', async function () {
|
||||
const body = await checkVideoAccessOptions({ server, expectedStatus: HttpStatusCode.FORBIDDEN_403, mode })
|
||||
const error = body as unknown as PeerTubeProblemDocument
|
||||
|
||||
checkVideoError(error, 'providePassword')
|
||||
})
|
||||
}
|
||||
|
||||
it('Should fail without providing a password for an unauthorised user', async function () {
|
||||
const tmp = mode === 'get' ? 'getWithToken' : mode
|
||||
|
||||
const body = await checkVideoAccessOptions({
|
||||
server,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403,
|
||||
mode: tmp
|
||||
})
|
||||
|
||||
const error = body as unknown as PeerTubeProblemDocument
|
||||
|
||||
checkVideoError(error, 'providePassword')
|
||||
})
|
||||
|
||||
it('Should fail if a wrong password is entered', async function () {
|
||||
const tmp = mode === 'get' ? 'getWithPassword' : mode
|
||||
tokens = [ userAccessToken, server.accessToken ]
|
||||
|
||||
if (!requiresUserAuth) tokens.push(null)
|
||||
|
||||
for (const token of tokens) {
|
||||
const body = await checkVideoAccessOptions({
|
||||
server,
|
||||
token,
|
||||
videoPassword: 'toto',
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403,
|
||||
mode: tmp
|
||||
})
|
||||
const error = body as unknown as PeerTubeProblemDocument
|
||||
|
||||
checkVideoError(error, 'incorrectPassword')
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail if an empty password is entered', async function () {
|
||||
const tmp = mode === 'get' ? 'getWithPassword' : mode
|
||||
|
||||
for (const token of tokens) {
|
||||
const body = await checkVideoAccessOptions({
|
||||
server,
|
||||
token,
|
||||
videoPassword: '',
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403,
|
||||
mode: tmp
|
||||
})
|
||||
const error = body as unknown as PeerTubeProblemDocument
|
||||
|
||||
checkVideoError(error, 'incorrectPassword')
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail if an inccorect password containing the correct password is entered', async function () {
|
||||
const tmp = mode === 'get' ? 'getWithPassword' : mode
|
||||
|
||||
for (const token of tokens) {
|
||||
const body = await checkVideoAccessOptions({
|
||||
server,
|
||||
token,
|
||||
videoPassword: 'password11',
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403,
|
||||
mode: tmp
|
||||
})
|
||||
const error = body as unknown as PeerTubeProblemDocument
|
||||
|
||||
checkVideoError(error, 'incorrectPassword')
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed without providing a password for an authorised user', async function () {
|
||||
const tmp = mode === 'get' ? 'getWithToken' : mode
|
||||
const expectedStatus = mode === 'rate' ? HttpStatusCode.NO_CONTENT_204 : HttpStatusCode.OK_200
|
||||
|
||||
const body = await checkVideoAccessOptions({ server, token: server.accessToken, expectedStatus, mode: tmp })
|
||||
|
||||
if (mode === 'createThread') commentId = body.comment.id
|
||||
})
|
||||
|
||||
it('Should succeed using correct passwords', async function () {
|
||||
const tmp = mode === 'get' ? 'getWithPassword' : mode
|
||||
const expectedStatus = mode === 'rate' ? HttpStatusCode.NO_CONTENT_204 : HttpStatusCode.OK_200
|
||||
|
||||
for (const token of tokens) {
|
||||
await checkVideoAccessOptions({ server, videoPassword: 'password1', token, expectedStatus, mode: tmp })
|
||||
await checkVideoAccessOptions({ server, videoPassword: 'password2', token, expectedStatus, mode: tmp })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
describe('When accessing password protected video', function () {
|
||||
|
||||
describe('For getting a password protected video', function () {
|
||||
validateVideoAccess('get')
|
||||
})
|
||||
|
||||
describe('For rating a video', function () {
|
||||
validateVideoAccess('rate')
|
||||
})
|
||||
|
||||
describe('For creating a thread', function () {
|
||||
validateVideoAccess('createThread')
|
||||
})
|
||||
|
||||
describe('For replying to a thread', function () {
|
||||
validateVideoAccess('replyThread')
|
||||
})
|
||||
|
||||
describe('For listing threads', function () {
|
||||
validateVideoAccess('listThreads')
|
||||
})
|
||||
|
||||
describe('For getting captions', function () {
|
||||
validateVideoAccess('listCaptions')
|
||||
})
|
||||
|
||||
describe('For creating video file token', function () {
|
||||
validateVideoAccess('token')
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing passwords', function () {
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path + video.uuid + '/passwords', server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path + video.uuid + '/passwords', server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path + video.uuid + '/passwords', server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail for unauthenticated user', async function () {
|
||||
await server.videoPasswords.list({
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401,
|
||||
videoId: video.id
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail for unauthorized user', async function () {
|
||||
await server.videoPasswords.list({
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403,
|
||||
videoId: video.id
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await server.videoPasswords.list({
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200,
|
||||
videoId: video.id
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When deleting a password', async function () {
|
||||
const passwords = (await server.videoPasswords.list({ videoId: video.id })).data
|
||||
|
||||
it('Should fail with wrong password id', async function () {
|
||||
await server.videoPasswords.remove({ id: -1, videoId: video.id, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail for unauthenticated user', async function () {
|
||||
await server.videoPasswords.remove({
|
||||
id: passwords[0].id,
|
||||
token: null,
|
||||
videoId: video.id,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail for unauthorized user', async function () {
|
||||
await server.videoPasswords.remove({
|
||||
id: passwords[0].id,
|
||||
token: userAccessToken,
|
||||
videoId: video.id,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail for non password protected video', async function () {
|
||||
publicVideo = await server.videos.quickUpload({ name: 'public video' })
|
||||
await server.videoPasswords.remove({ id: passwords[0].id, videoId: publicVideo.id, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail for password not linked to correct video', async function () {
|
||||
const video2 = await server.videos.quickUpload({
|
||||
name: 'password protected video',
|
||||
privacy: VideoPrivacy.PASSWORD_PROTECTED,
|
||||
videoPasswords: [ 'password1', 'password2' ]
|
||||
})
|
||||
await server.videoPasswords.remove({ id: passwords[0].id, videoId: video2.id, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with correct parameter', async function () {
|
||||
await server.videoPasswords.remove({ id: passwords[0].id, videoId: video.id, expectedStatus: HttpStatusCode.NO_CONTENT_204 })
|
||||
})
|
||||
|
||||
it('Should fail for last password of a video', async function () {
|
||||
await server.videoPasswords.remove({ id: passwords[1].id, videoId: video.id, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,695 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import {
|
||||
HttpStatusCode,
|
||||
VideoPlaylistCreate,
|
||||
VideoPlaylistCreateResult,
|
||||
VideoPlaylistElementCreate,
|
||||
VideoPlaylistElementUpdate,
|
||||
VideoPlaylistPrivacy,
|
||||
VideoPlaylistReorder,
|
||||
VideoPlaylistType
|
||||
} from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
PeerTubeServer,
|
||||
PlaylistsCommand,
|
||||
setAccessTokensToServers,
|
||||
setDefaultVideoChannel
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test video playlists API validator', function () {
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken: string
|
||||
|
||||
let playlist: VideoPlaylistCreateResult
|
||||
let privatePlaylistUUID: string
|
||||
|
||||
let watchLaterPlaylistId: number
|
||||
let videoId: number
|
||||
let elementId: number
|
||||
|
||||
let command: PlaylistsCommand
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultVideoChannel([ server ])
|
||||
|
||||
userAccessToken = await server.users.generateUserAndToken('user1')
|
||||
videoId = (await server.videos.quickUpload({ name: 'video 1' })).id
|
||||
|
||||
command = server.playlists
|
||||
|
||||
{
|
||||
const { data } = await command.listByAccount({
|
||||
token: server.accessToken,
|
||||
handle: 'root',
|
||||
start: 0,
|
||||
count: 5,
|
||||
playlistType: VideoPlaylistType.WATCH_LATER
|
||||
})
|
||||
watchLaterPlaylistId = data[0].id
|
||||
}
|
||||
|
||||
{
|
||||
playlist = await command.create({
|
||||
attributes: {
|
||||
displayName: 'super playlist',
|
||||
privacy: VideoPlaylistPrivacy.PUBLIC,
|
||||
videoChannelId: server.store.channel.id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
const created = await command.create({
|
||||
attributes: {
|
||||
displayName: 'private',
|
||||
privacy: VideoPlaylistPrivacy.PRIVATE
|
||||
}
|
||||
})
|
||||
privatePlaylistUUID = created.uuid
|
||||
}
|
||||
})
|
||||
|
||||
describe('When listing playlists', function () {
|
||||
const globalPath = '/api/v1/video-playlists'
|
||||
const accountPath = '/api/v1/accounts/root/video-playlists'
|
||||
const videoChannelPath = '/api/v1/video-channels/root_channel/video-playlists'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, globalPath, server.accessToken)
|
||||
await checkBadStartPagination(server.url, accountPath, server.accessToken)
|
||||
await checkBadStartPagination(server.url, videoChannelPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, globalPath, server.accessToken)
|
||||
await checkBadCountPagination(server.url, accountPath, server.accessToken)
|
||||
await checkBadCountPagination(server.url, videoChannelPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, globalPath, server.accessToken)
|
||||
await checkBadSortPagination(server.url, accountPath, server.accessToken)
|
||||
await checkBadSortPagination(server.url, videoChannelPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad playlist type', async function () {
|
||||
await makeGetRequest({ url: server.url, path: globalPath, query: { playlistType: 3 } })
|
||||
await makeGetRequest({ url: server.url, path: accountPath, query: { playlistType: 3 } })
|
||||
await makeGetRequest({ url: server.url, path: videoChannelPath, query: { playlistType: 3 } })
|
||||
})
|
||||
|
||||
it('Should fail with a bad account parameter', async function () {
|
||||
const accountPath = '/api/v1/accounts/root2/video-playlists'
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: accountPath,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404,
|
||||
token: server.accessToken
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad video channel parameter', async function () {
|
||||
const accountPath = '/api/v1/video-channels/bad_channel/video-playlists'
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: accountPath,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404,
|
||||
token: server.accessToken
|
||||
})
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path: globalPath, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken })
|
||||
await makeGetRequest({ url: server.url, path: accountPath, expectedStatus: HttpStatusCode.OK_200, token: server.accessToken })
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: videoChannelPath,
|
||||
expectedStatus: HttpStatusCode.OK_200,
|
||||
token: server.accessToken
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing videos of a playlist', function () {
|
||||
const path = '/api/v1/video-playlists/'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path + playlist.shortUUID + '/videos', server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path + playlist.shortUUID + '/videos', server.accessToken)
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path: path + playlist.shortUUID + '/videos', expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting a video playlist', function () {
|
||||
it('Should fail with a bad id or uuid', async function () {
|
||||
await command.get({ playlistId: 'toto', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown playlist', async function () {
|
||||
await command.get({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail to get an unlisted playlist with the number id', async function () {
|
||||
const playlist = await command.create({
|
||||
attributes: {
|
||||
displayName: 'super playlist',
|
||||
videoChannelId: server.store.channel.id,
|
||||
privacy: VideoPlaylistPrivacy.UNLISTED
|
||||
}
|
||||
})
|
||||
|
||||
await command.get({ playlistId: playlist.id, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await command.get({ playlistId: playlist.uuid, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await command.get({ playlistId: playlist.uuid, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When creating/updating a video playlist', function () {
|
||||
const getBase = (
|
||||
attributes?: Partial<VideoPlaylistCreate>,
|
||||
wrapper?: Partial<Parameters<PlaylistsCommand['create']>[0]>
|
||||
) => {
|
||||
return {
|
||||
attributes: {
|
||||
displayName: 'display name',
|
||||
privacy: VideoPlaylistPrivacy.UNLISTED,
|
||||
thumbnailfile: 'custom-thumbnail.jpg',
|
||||
videoChannelId: server.store.channel.id,
|
||||
|
||||
...attributes
|
||||
},
|
||||
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
|
||||
|
||||
...wrapper
|
||||
}
|
||||
}
|
||||
const getUpdate = (params: any, playlistId: number | string) => {
|
||||
return { ...params, playlistId }
|
||||
}
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
|
||||
await command.create(params)
|
||||
await command.update(getUpdate(params, playlist.shortUUID))
|
||||
})
|
||||
|
||||
it('Should fail without displayName', async function () {
|
||||
const params = getBase({ displayName: undefined })
|
||||
|
||||
await command.create(params)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect display name', async function () {
|
||||
const params = getBase({ displayName: 's'.repeat(300) })
|
||||
|
||||
await command.create(params)
|
||||
await command.update(getUpdate(params, playlist.shortUUID))
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect description', async function () {
|
||||
const params = getBase({ description: 't' })
|
||||
|
||||
await command.create(params)
|
||||
await command.update(getUpdate(params, playlist.shortUUID))
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect privacy', async function () {
|
||||
const params = getBase({ privacy: 45 as any })
|
||||
|
||||
await command.create(params)
|
||||
await command.update(getUpdate(params, playlist.shortUUID))
|
||||
})
|
||||
|
||||
it('Should fail with an unknown video channel id', async function () {
|
||||
const params = getBase({ videoChannelId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
|
||||
await command.create(params)
|
||||
await command.update(getUpdate(params, playlist.shortUUID))
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect thumbnail file', async function () {
|
||||
const params = getBase({ thumbnailfile: 'video_short.mp4' })
|
||||
|
||||
await command.create(params)
|
||||
await command.update(getUpdate(params, playlist.shortUUID))
|
||||
})
|
||||
|
||||
it('Should fail with a thumbnail file too big', async function () {
|
||||
const params = getBase({ thumbnailfile: 'custom-preview-big.png' })
|
||||
|
||||
await command.create(params)
|
||||
await command.update(getUpdate(params, playlist.shortUUID))
|
||||
})
|
||||
|
||||
it('Should fail to set "public" a playlist not assigned to a channel', async function () {
|
||||
const params = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: undefined })
|
||||
const params2 = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: 'null' as any })
|
||||
const params3 = getBase({ privacy: undefined, videoChannelId: 'null' as any })
|
||||
|
||||
await command.create(params)
|
||||
await command.create(params2)
|
||||
await command.update(getUpdate(params, privatePlaylistUUID))
|
||||
await command.update(getUpdate(params2, playlist.shortUUID))
|
||||
await command.update(getUpdate(params3, playlist.shortUUID))
|
||||
})
|
||||
|
||||
it('Should fail with an unknown playlist to update', async function () {
|
||||
await command.update(getUpdate(
|
||||
getBase({}, { expectedStatus: HttpStatusCode.NOT_FOUND_404 }),
|
||||
42
|
||||
))
|
||||
})
|
||||
|
||||
it('Should fail to update a playlist of another user', async function () {
|
||||
await command.update(getUpdate(
|
||||
getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }),
|
||||
playlist.shortUUID
|
||||
))
|
||||
})
|
||||
|
||||
it('Should fail to update the watch later playlist', async function () {
|
||||
await command.update(getUpdate(
|
||||
getBase({}, { expectedStatus: HttpStatusCode.BAD_REQUEST_400 }),
|
||||
watchLaterPlaylistId
|
||||
))
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
{
|
||||
const params = getBase({}, { expectedStatus: HttpStatusCode.OK_200 })
|
||||
await command.create(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
|
||||
await command.update(getUpdate(params, playlist.shortUUID))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('When adding an element in a playlist', function () {
|
||||
const getBase = (
|
||||
attributes?: Partial<VideoPlaylistElementCreate>,
|
||||
wrapper?: Partial<Parameters<PlaylistsCommand['addElement']>[0]>
|
||||
) => {
|
||||
return {
|
||||
attributes: {
|
||||
videoId,
|
||||
startTimestamp: 2,
|
||||
stopTimestamp: 3,
|
||||
|
||||
...attributes
|
||||
},
|
||||
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
|
||||
playlistId: playlist.id,
|
||||
|
||||
...wrapper
|
||||
}
|
||||
}
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
await command.addElement(params)
|
||||
})
|
||||
|
||||
it('Should fail with the playlist of another user', async function () {
|
||||
const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
await command.addElement(params)
|
||||
})
|
||||
|
||||
it('Should fail with an unknown or incorrect playlist id', async function () {
|
||||
{
|
||||
const params = getBase({}, { playlistId: 'toto' })
|
||||
await command.addElement(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await command.addElement(params)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an unknown or incorrect video id', async function () {
|
||||
const params = getBase({ videoId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await command.addElement(params)
|
||||
})
|
||||
|
||||
it('Should fail with a bad start/stop timestamp', async function () {
|
||||
{
|
||||
const params = getBase({ startTimestamp: -42 })
|
||||
await command.addElement(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({ stopTimestamp: 'toto' as any })
|
||||
await command.addElement(params)
|
||||
}
|
||||
})
|
||||
|
||||
it('Succeed with the correct params', async function () {
|
||||
const params = getBase({}, { expectedStatus: HttpStatusCode.OK_200 })
|
||||
const created = await command.addElement(params)
|
||||
elementId = created.id
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating an element in a playlist', function () {
|
||||
const getBase = (
|
||||
attributes?: Partial<VideoPlaylistElementUpdate>,
|
||||
wrapper?: Partial<Parameters<PlaylistsCommand['updateElement']>[0]>
|
||||
) => {
|
||||
return {
|
||||
attributes: {
|
||||
startTimestamp: 1,
|
||||
stopTimestamp: 2,
|
||||
|
||||
...attributes
|
||||
},
|
||||
|
||||
elementId,
|
||||
playlistId: playlist.id,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
|
||||
|
||||
...wrapper
|
||||
}
|
||||
}
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
await command.updateElement(params)
|
||||
})
|
||||
|
||||
it('Should fail with the playlist of another user', async function () {
|
||||
const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
await command.updateElement(params)
|
||||
})
|
||||
|
||||
it('Should fail with an unknown or incorrect playlist id', async function () {
|
||||
{
|
||||
const params = getBase({}, { playlistId: 'toto' })
|
||||
await command.updateElement(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await command.updateElement(params)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an unknown or incorrect playlistElement id', async function () {
|
||||
{
|
||||
const params = getBase({}, { elementId: 'toto' })
|
||||
await command.updateElement(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({}, { elementId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await command.updateElement(params)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with a bad start/stop timestamp', async function () {
|
||||
{
|
||||
const params = getBase({ startTimestamp: 'toto' as any })
|
||||
await command.updateElement(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({ stopTimestamp: -42 })
|
||||
await command.updateElement(params)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an unknown element', async function () {
|
||||
const params = getBase({}, { elementId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await command.updateElement(params)
|
||||
})
|
||||
|
||||
it('Succeed with the correct params', async function () {
|
||||
const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
|
||||
await command.updateElement(params)
|
||||
})
|
||||
})
|
||||
|
||||
describe('When reordering elements of a playlist', function () {
|
||||
let videoId3: number
|
||||
let videoId4: number
|
||||
|
||||
const getBase = (
|
||||
attributes?: Partial<VideoPlaylistReorder>,
|
||||
wrapper?: Partial<Parameters<PlaylistsCommand['reorderElements']>[0]>
|
||||
) => {
|
||||
return {
|
||||
attributes: {
|
||||
startPosition: 1,
|
||||
insertAfterPosition: 2,
|
||||
reorderLength: 3,
|
||||
|
||||
...attributes
|
||||
},
|
||||
|
||||
playlistId: playlist.shortUUID,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
|
||||
|
||||
...wrapper
|
||||
}
|
||||
}
|
||||
|
||||
before(async function () {
|
||||
videoId3 = (await server.videos.quickUpload({ name: 'video 3' })).id
|
||||
videoId4 = (await server.videos.quickUpload({ name: 'video 4' })).id
|
||||
|
||||
for (const id of [ videoId3, videoId4 ]) {
|
||||
await command.addElement({ playlistId: playlist.shortUUID, attributes: { videoId: id } })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
await command.reorderElements(params)
|
||||
})
|
||||
|
||||
it('Should fail with the playlist of another user', async function () {
|
||||
const params = getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
await command.reorderElements(params)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid playlist', async function () {
|
||||
{
|
||||
const params = getBase({}, { playlistId: 'toto' })
|
||||
await command.reorderElements(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({}, { playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await command.reorderElements(params)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an invalid start position', async function () {
|
||||
{
|
||||
const params = getBase({ startPosition: -1 })
|
||||
await command.reorderElements(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({ startPosition: 'toto' as any })
|
||||
await command.reorderElements(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({ startPosition: 42 })
|
||||
await command.reorderElements(params)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an invalid insert after position', async function () {
|
||||
{
|
||||
const params = getBase({ insertAfterPosition: 'toto' as any })
|
||||
await command.reorderElements(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({ insertAfterPosition: -2 })
|
||||
await command.reorderElements(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({ insertAfterPosition: 42 })
|
||||
await command.reorderElements(params)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an invalid reorder length', async function () {
|
||||
{
|
||||
const params = getBase({ reorderLength: 'toto' as any })
|
||||
await command.reorderElements(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({ reorderLength: -2 })
|
||||
await command.reorderElements(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({ reorderLength: 42 })
|
||||
await command.reorderElements(params)
|
||||
}
|
||||
})
|
||||
|
||||
it('Succeed with the correct params', async function () {
|
||||
const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
|
||||
await command.reorderElements(params)
|
||||
})
|
||||
})
|
||||
|
||||
describe('When checking exists in playlist endpoint', function () {
|
||||
const path = '/api/v1/users/me/video-playlists/videos-exist'
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
query: { videoIds: [ 1, 2 ] },
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with invalid video ids', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
query: { videoIds: 'toto' }
|
||||
})
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
query: { videoIds: [ 'toto' ] }
|
||||
})
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
query: { videoIds: [ 1, 'toto' ] }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
query: { videoIds: [ 1, 2 ] },
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When deleting an element in a playlist', function () {
|
||||
const getBase = (wrapper: Partial<Parameters<PlaylistsCommand['removeElement']>[0]>) => {
|
||||
return {
|
||||
elementId,
|
||||
playlistId: playlist.uuid,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
|
||||
|
||||
...wrapper
|
||||
}
|
||||
}
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
const params = getBase({ token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
await command.removeElement(params)
|
||||
})
|
||||
|
||||
it('Should fail with the playlist of another user', async function () {
|
||||
const params = getBase({ token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
await command.removeElement(params)
|
||||
})
|
||||
|
||||
it('Should fail with an unknown or incorrect playlist id', async function () {
|
||||
{
|
||||
const params = getBase({ playlistId: 'toto' })
|
||||
await command.removeElement(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await command.removeElement(params)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an unknown or incorrect video id', async function () {
|
||||
{
|
||||
const params = getBase({ elementId: 'toto' as any })
|
||||
await command.removeElement(params)
|
||||
}
|
||||
|
||||
{
|
||||
const params = getBase({ elementId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await command.removeElement(params)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an unknown element', async function () {
|
||||
const params = getBase({ elementId: 888, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
await command.removeElement(params)
|
||||
})
|
||||
|
||||
it('Succeed with the correct params', async function () {
|
||||
const params = getBase({ expectedStatus: HttpStatusCode.NO_CONTENT_204 })
|
||||
await command.removeElement(params)
|
||||
})
|
||||
})
|
||||
|
||||
describe('When deleting a playlist', function () {
|
||||
it('Should fail with an unknown playlist', async function () {
|
||||
await command.delete({ playlistId: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a playlist of another user', async function () {
|
||||
await command.delete({ token: userAccessToken, playlistId: playlist.uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with the watch later playlist', async function () {
|
||||
await command.delete({ playlistId: watchLaterPlaylistId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await command.delete({ playlistId: playlist.uuid })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,247 @@
|
||||
import { HttpStatusCode, VideoSource } from '@peertube/peertube-models'
|
||||
import {
|
||||
PeerTubeServer,
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeRawRequest,
|
||||
setAccessTokensToServers,
|
||||
setDefaultVideoChannel,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test video sources API validator', function () {
|
||||
let server: PeerTubeServer = null
|
||||
let uuid: string
|
||||
let userToken: string
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultVideoChannel([ server ])
|
||||
|
||||
userToken = await server.users.generateUserAndToken('user1')
|
||||
})
|
||||
|
||||
describe('When getting latest source', function () {
|
||||
|
||||
before(async function () {
|
||||
const created = await server.videos.quickUpload({ name: 'video' })
|
||||
uuid = created.uuid
|
||||
})
|
||||
|
||||
it('Should fail without a valid uuid', async function () {
|
||||
await server.videos.getSource({ id: '4da6fde3-88f7-4d16-b119-108df563d0b0', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should receive 404 when passing a non existing video id', async function () {
|
||||
await server.videos.getSource({ id: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should not get the source as unauthenticated', async function () {
|
||||
await server.videos.getSource({ id: uuid, expectedStatus: HttpStatusCode.UNAUTHORIZED_401, token: null })
|
||||
})
|
||||
|
||||
it('Should not get the source with another user', async function () {
|
||||
await server.videos.getSource({ id: uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403, token: userToken })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters get the source as another user', async function () {
|
||||
await server.videos.getSource({ id: uuid })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating source video file', function () {
|
||||
let userAccessToken: string
|
||||
let userId: number
|
||||
|
||||
let videoId: string
|
||||
let userVideoId: string
|
||||
|
||||
before(async function () {
|
||||
const res = await server.users.generate('user2')
|
||||
userAccessToken = res.token
|
||||
userId = res.userId
|
||||
|
||||
const { uuid } = await server.videos.quickUpload({ name: 'video' })
|
||||
videoId = uuid
|
||||
|
||||
await waitJobs([ server ])
|
||||
})
|
||||
|
||||
it('Should fail if not enabled on the instance', async function () {
|
||||
await server.config.disableFileUpdate()
|
||||
|
||||
await server.videos.replaceSourceFile({ videoId, fixture: 'video_short.mp4', expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail on an unknown video', async function () {
|
||||
await server.config.enableFileUpdate()
|
||||
|
||||
await server.videos.replaceSourceFile({ videoId: 404, fixture: 'video_short.mp4', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid video', async function () {
|
||||
await server.config.enableLive({ allowReplay: false })
|
||||
|
||||
const { video } = await server.live.quickCreate({ saveReplay: false, permanentLive: true })
|
||||
await server.videos.replaceSourceFile({
|
||||
videoId: video.uuid,
|
||||
fixture: 'video_short.mp4',
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await server.videos.replaceSourceFile({
|
||||
token: null,
|
||||
videoId,
|
||||
fixture: 'video_short.mp4',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with another user', async function () {
|
||||
await server.videos.replaceSourceFile({
|
||||
token: userAccessToken,
|
||||
videoId,
|
||||
fixture: 'video_short.mp4',
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect input file', async function () {
|
||||
await server.videos.replaceSourceFile({
|
||||
fixture: 'video_short_fake.webm',
|
||||
videoId,
|
||||
completedExpectedStatus: HttpStatusCode.UNPROCESSABLE_ENTITY_422
|
||||
})
|
||||
|
||||
await server.videos.replaceSourceFile({
|
||||
fixture: 'video_short.mkv',
|
||||
videoId,
|
||||
expectedStatus: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if quota is exceeded', async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
const { uuid } = await server.videos.quickUpload({ name: 'user video' })
|
||||
userVideoId = uuid
|
||||
await waitJobs([ server ])
|
||||
|
||||
await server.users.update({ userId, videoQuota: 1 })
|
||||
await server.videos.replaceSourceFile({
|
||||
token: userAccessToken,
|
||||
videoId: uuid,
|
||||
fixture: 'video_short.mp4',
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
await server.users.update({ userId, videoQuota: 1000 * 1000 * 1000 })
|
||||
await server.videos.replaceSourceFile({ videoId: userVideoId, fixture: 'video_short.mp4' })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When downloading the source file', function () {
|
||||
let videoFileToken: string
|
||||
let videoId: string
|
||||
let source: VideoSource
|
||||
let user3: string
|
||||
let user4: string
|
||||
|
||||
before(async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
user3 = await server.users.generateUserAndToken('user3')
|
||||
user4 = await server.users.generateUserAndToken('user4')
|
||||
|
||||
await server.config.enableMinimumTranscoding({ hls: true, keepOriginal: true, webVideo: true })
|
||||
|
||||
const { uuid } = await server.videos.quickUpload({ name: 'video', token: user3 })
|
||||
|
||||
videoId = uuid
|
||||
videoFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid, token: user3 })
|
||||
|
||||
await waitJobs([ server ])
|
||||
|
||||
source = await server.videos.getSource({ id: videoId, token: user3 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid filename', async function () {
|
||||
await makeRawRequest({ url: server.url + '/download/original-video-files/hello.mp4', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail without header token or video file token', async function () {
|
||||
await makeRawRequest({ url: source.fileDownloadUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid header token', async function () {
|
||||
await makeRawRequest({ url: source.fileDownloadUrl, token: 'toto', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid video file token', async function () {
|
||||
await makeRawRequest({ url: source.fileDownloadUrl, query: { videoFileToken: 'toto' }, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with header token of another user', async function () {
|
||||
await makeRawRequest({ url: source.fileDownloadUrl, token: user4, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with video file token of another user', async function () {
|
||||
const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid, token: user4 })
|
||||
|
||||
await makeRawRequest({ url: source.fileDownloadUrl, query: { videoFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should succeed with a valid header token', async function () {
|
||||
await makeRawRequest({ url: source.fileDownloadUrl, token: user3, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
||||
it('Should succeed with a valid header token', async function () {
|
||||
await makeRawRequest({ url: source.fileDownloadUrl, query: { videoFileToken }, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When deleting video source file', function () {
|
||||
let userAccessToken: string
|
||||
|
||||
let videoId: string
|
||||
|
||||
before(async function () {
|
||||
userAccessToken = await server.users.generateUserAndToken('user56')
|
||||
|
||||
await server.config.enableMinimumTranscoding({ keepOriginal: true })
|
||||
const { uuid } = await server.videos.quickUpload({ name: 'with source' })
|
||||
videoId = uuid
|
||||
|
||||
await waitJobs([ server ])
|
||||
})
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await server.videos.deleteSource({ id: videoId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with another user', async function () {
|
||||
await server.videos.deleteSource({ id: videoId, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown video', async function () {
|
||||
await server.videos.deleteSource({ id: 42, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await server.videos.deleteSource({ id: videoId })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,45 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode, VideoPrivacy } from '@peertube/peertube-models'
|
||||
import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test video storyboards API validator', function () {
|
||||
let server: PeerTubeServer
|
||||
|
||||
let publicVideo: { uuid: string }
|
||||
let privateVideo: { uuid: string }
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
publicVideo = await server.videos.quickUpload({ name: 'public' })
|
||||
privateVideo = await server.videos.quickUpload({ name: 'private', privacy: VideoPrivacy.PRIVATE })
|
||||
})
|
||||
|
||||
it('Should fail without a valid uuid', async function () {
|
||||
await server.storyboard.list({ id: '4da6fde3-88f7-4d16-b119-108df563d0b0', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should receive 404 when passing a non existing video id', async function () {
|
||||
await server.storyboard.list({ id: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should not get the private storyboard without the appropriate token', async function () {
|
||||
await server.storyboard.list({ id: privateVideo.uuid, expectedStatus: HttpStatusCode.UNAUTHORIZED_401, token: null })
|
||||
await server.storyboard.list({ id: publicVideo.uuid, expectedStatus: HttpStatusCode.OK_200, token: null })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await server.storyboard.list({ id: privateVideo.uuid })
|
||||
await server.storyboard.list({ id: publicVideo.uuid })
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,392 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode, HttpStatusCodeType, VideoStudioTask } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
VideoStudioCommand,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test video studio API validator', function () {
|
||||
let server: PeerTubeServer
|
||||
let command: VideoStudioCommand
|
||||
let userAccessToken: string
|
||||
let videoUUID: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120_000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
userAccessToken = await server.users.generateUserAndToken('user1')
|
||||
|
||||
await server.config.enableMinimumTranscoding()
|
||||
|
||||
const { uuid } = await server.videos.quickUpload({ name: 'video' })
|
||||
videoUUID = uuid
|
||||
|
||||
command = server.videoStudio
|
||||
|
||||
await waitJobs([ server ])
|
||||
})
|
||||
|
||||
describe('Task creation', function () {
|
||||
|
||||
describe('Config settings', function () {
|
||||
|
||||
it('Should fail if studio is disabled', async function () {
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
videoStudio: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await command.createEditionTasks({
|
||||
videoId: videoUUID,
|
||||
tasks: VideoStudioCommand.getComplexTask(),
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to enable studio if transcoding is disabled', async function () {
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
videoStudio: {
|
||||
enabled: true
|
||||
},
|
||||
transcoding: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed to enable video studio', async function () {
|
||||
await server.config.updateExistingConfig({
|
||||
newConfig: {
|
||||
videoStudio: {
|
||||
enabled: true
|
||||
},
|
||||
transcoding: {
|
||||
enabled: true
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Common tasks', function () {
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await command.createEditionTasks({
|
||||
token: null,
|
||||
videoId: videoUUID,
|
||||
tasks: VideoStudioCommand.getComplexTask(),
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with another user token', async function () {
|
||||
await command.createEditionTasks({
|
||||
token: userAccessToken,
|
||||
videoId: videoUUID,
|
||||
tasks: VideoStudioCommand.getComplexTask(),
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid video', async function () {
|
||||
await command.createEditionTasks({
|
||||
videoId: 'tintin',
|
||||
tasks: VideoStudioCommand.getComplexTask(),
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an unknown video', async function () {
|
||||
await command.createEditionTasks({
|
||||
videoId: 42,
|
||||
tasks: VideoStudioCommand.getComplexTask(),
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an already in transcoding state video', async function () {
|
||||
this.timeout(60000)
|
||||
|
||||
const { uuid } = await server.videos.quickUpload({ name: 'transcoded video' })
|
||||
await waitJobs([ server ])
|
||||
|
||||
await server.jobs.pauseJobQueue()
|
||||
await server.videos.runTranscoding({ videoId: uuid, transcodingType: 'hls' })
|
||||
|
||||
await command.createEditionTasks({
|
||||
videoId: uuid,
|
||||
tasks: VideoStudioCommand.getComplexTask(),
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
|
||||
await server.jobs.resumeJobQueue()
|
||||
})
|
||||
|
||||
it('Should fail with a bad complex task', async function () {
|
||||
await command.createEditionTasks({
|
||||
videoId: videoUUID,
|
||||
tasks: [
|
||||
{
|
||||
name: 'cut',
|
||||
options: {
|
||||
start: 1,
|
||||
end: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'hadock',
|
||||
options: {
|
||||
start: 1,
|
||||
end: 2
|
||||
}
|
||||
}
|
||||
] as any,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without task', async function () {
|
||||
await command.createEditionTasks({
|
||||
videoId: videoUUID,
|
||||
tasks: [],
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with too many tasks', async function () {
|
||||
const tasks: VideoStudioTask[] = []
|
||||
|
||||
for (let i = 0; i < 110; i++) {
|
||||
tasks.push({
|
||||
name: 'cut',
|
||||
options: {
|
||||
start: 1
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
await command.createEditionTasks({
|
||||
videoId: videoUUID,
|
||||
tasks,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with correct parameters', async function () {
|
||||
await server.jobs.pauseJobQueue()
|
||||
|
||||
await command.createEditionTasks({
|
||||
videoId: videoUUID,
|
||||
tasks: VideoStudioCommand.getComplexTask(),
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a video that is already waiting for edition', async function () {
|
||||
this.timeout(360000)
|
||||
|
||||
await command.createEditionTasks({
|
||||
videoId: videoUUID,
|
||||
tasks: VideoStudioCommand.getComplexTask(),
|
||||
expectedStatus: HttpStatusCode.CONFLICT_409
|
||||
})
|
||||
|
||||
await server.jobs.resumeJobQueue()
|
||||
|
||||
await waitJobs([ server ])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Cut task', function () {
|
||||
|
||||
async function cut (start: number, end: number, expectedStatus: HttpStatusCodeType = HttpStatusCode.BAD_REQUEST_400) {
|
||||
await command.createEditionTasks({
|
||||
videoId: videoUUID,
|
||||
tasks: [
|
||||
{
|
||||
name: 'cut',
|
||||
options: {
|
||||
start,
|
||||
end
|
||||
}
|
||||
}
|
||||
],
|
||||
expectedStatus
|
||||
})
|
||||
}
|
||||
|
||||
it('Should fail with bad start/end', async function () {
|
||||
const invalid = [
|
||||
'tintin',
|
||||
-1,
|
||||
undefined
|
||||
]
|
||||
|
||||
for (const value of invalid) {
|
||||
await cut(value as any, undefined)
|
||||
await cut(undefined, value as any)
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with the same start/end', async function () {
|
||||
await cut(2, 2)
|
||||
})
|
||||
|
||||
it('Should fail with inconsistents start/end', async function () {
|
||||
await cut(2, 1)
|
||||
})
|
||||
|
||||
it('Should fail without start and end', async function () {
|
||||
await cut(undefined, undefined)
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
this.timeout(360000)
|
||||
|
||||
await cut(0, 2, HttpStatusCode.NO_CONTENT_204)
|
||||
|
||||
await waitJobs([ server ])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Watermark task', function () {
|
||||
|
||||
async function addWatermark (file: string, expectedStatus: HttpStatusCodeType = HttpStatusCode.BAD_REQUEST_400) {
|
||||
await command.createEditionTasks({
|
||||
videoId: videoUUID,
|
||||
tasks: [
|
||||
{
|
||||
name: 'add-watermark',
|
||||
options: {
|
||||
file
|
||||
}
|
||||
}
|
||||
],
|
||||
expectedStatus
|
||||
})
|
||||
}
|
||||
|
||||
it('Should fail without waterkmark', async function () {
|
||||
await addWatermark(undefined)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid watermark', async function () {
|
||||
await addWatermark('video_short.mp4')
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
this.timeout(360000)
|
||||
|
||||
await addWatermark('custom-thumbnail.jpg', HttpStatusCode.NO_CONTENT_204)
|
||||
|
||||
await waitJobs([ server ])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Intro/Outro task', function () {
|
||||
|
||||
async function addIntroOutro (
|
||||
type: 'add-intro' | 'add-outro',
|
||||
file: string,
|
||||
expectedStatus: HttpStatusCodeType = HttpStatusCode.BAD_REQUEST_400
|
||||
) {
|
||||
await command.createEditionTasks({
|
||||
videoId: videoUUID,
|
||||
tasks: [
|
||||
{
|
||||
name: type,
|
||||
options: {
|
||||
file
|
||||
}
|
||||
}
|
||||
],
|
||||
expectedStatus
|
||||
})
|
||||
}
|
||||
|
||||
it('Should fail without file', async function () {
|
||||
await addIntroOutro('add-intro', undefined)
|
||||
await addIntroOutro('add-outro', undefined)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid file', async function () {
|
||||
await addIntroOutro('add-intro', 'custom-thumbnail.jpg')
|
||||
await addIntroOutro('add-outro', 'custom-thumbnail.jpg')
|
||||
})
|
||||
|
||||
it('Should fail with a file that does not contain video stream', async function () {
|
||||
await addIntroOutro('add-intro', 'sample.ogg')
|
||||
await addIntroOutro('add-outro', 'sample.ogg')
|
||||
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
this.timeout(360000)
|
||||
|
||||
await addIntroOutro('add-intro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204)
|
||||
await waitJobs([ server ])
|
||||
|
||||
await addIntroOutro('add-outro', 'video_very_short_240p.mp4', HttpStatusCode.NO_CONTENT_204)
|
||||
await waitJobs([ server ])
|
||||
})
|
||||
|
||||
it('Should check total quota when creating the task', async function () {
|
||||
this.timeout(360000)
|
||||
|
||||
const user = await server.users.create({ username: 'user_quota_1' })
|
||||
const token = await server.login.getAccessToken('user_quota_1')
|
||||
const { uuid } = await server.videos.quickUpload({ token, name: 'video_quota_1', fixture: 'video_short.mp4' })
|
||||
|
||||
const addIntroOutroByUser = (type: 'add-intro' | 'add-outro', expectedStatus: HttpStatusCodeType) => {
|
||||
return command.createEditionTasks({
|
||||
token,
|
||||
videoId: uuid,
|
||||
tasks: [
|
||||
{
|
||||
name: type,
|
||||
options: {
|
||||
file: 'video_short.mp4'
|
||||
}
|
||||
}
|
||||
],
|
||||
expectedStatus
|
||||
})
|
||||
}
|
||||
|
||||
await waitJobs([ server ])
|
||||
|
||||
const { videoQuotaUsed } = await server.users.getMyQuotaUsed({ token })
|
||||
await server.users.update({ userId: user.id, videoQuota: Math.round(videoQuotaUsed * 2.5) })
|
||||
|
||||
// Still valid
|
||||
await addIntroOutroByUser('add-intro', HttpStatusCode.NO_CONTENT_204)
|
||||
|
||||
await waitJobs([ server ])
|
||||
|
||||
// Too much quota
|
||||
await addIntroOutroByUser('add-intro', HttpStatusCode.PAYLOAD_TOO_LARGE_413)
|
||||
await addIntroOutroByUser('add-outro', HttpStatusCode.PAYLOAD_TOO_LARGE_413)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,70 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode, VideoPrivacy } from '@peertube/peertube-models'
|
||||
import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test video tokens', function () {
|
||||
let server: PeerTubeServer
|
||||
let privateVideoId: string
|
||||
let passwordProtectedVideoId: string
|
||||
let userToken: string
|
||||
|
||||
const videoPassword = 'password'
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(300_000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
await setAccessTokensToServers([ server ])
|
||||
{
|
||||
const { uuid } = await server.videos.quickUpload({ name: 'private video', privacy: VideoPrivacy.PRIVATE })
|
||||
privateVideoId = uuid
|
||||
}
|
||||
{
|
||||
const { uuid } = await server.videos.quickUpload({
|
||||
name: 'password protected video',
|
||||
privacy: VideoPrivacy.PASSWORD_PROTECTED,
|
||||
videoPasswords: [ videoPassword ]
|
||||
})
|
||||
passwordProtectedVideoId = uuid
|
||||
}
|
||||
userToken = await server.users.generateUserAndToken('user1')
|
||||
})
|
||||
|
||||
it('Should not generate tokens on private video for unauthenticated user', async function () {
|
||||
await server.videoToken.create({ videoId: privateVideoId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should not generate tokens of unknown video', async function () {
|
||||
await server.videoToken.create({ videoId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should not generate tokens with incorrect password', async function () {
|
||||
await server.videoToken.create({
|
||||
videoId: passwordProtectedVideoId,
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403,
|
||||
videoPassword: 'incorrectPassword'
|
||||
})
|
||||
})
|
||||
|
||||
it('Should not generate tokens of a non owned video', async function () {
|
||||
await server.videoToken.create({ videoId: privateVideoId, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should generate token', async function () {
|
||||
await server.videoToken.create({ videoId: privateVideoId })
|
||||
})
|
||||
|
||||
it('Should generate token on password protected video', async function () {
|
||||
await server.videoToken.create({ videoId: passwordProtectedVideoId, videoPassword, token: null })
|
||||
await server.videoToken.create({ videoId: passwordProtectedVideoId, videoPassword, token: userToken })
|
||||
await server.videoToken.create({ videoId: passwordProtectedVideoId, videoPassword })
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,106 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode, UserRole } from '@peertube/peertube-models'
|
||||
import {
|
||||
PeerTubeServer,
|
||||
cleanupTests,
|
||||
createMultipleServers,
|
||||
doubleFollow,
|
||||
setAccessTokensToServers,
|
||||
waitJobs
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test video transcription API validator', function () {
|
||||
let servers: PeerTubeServer[]
|
||||
|
||||
let userToken: string
|
||||
let anotherUserToken: string
|
||||
|
||||
let remoteId: string
|
||||
let validId: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(240000)
|
||||
|
||||
servers = await createMultipleServers(2)
|
||||
await setAccessTokensToServers(servers)
|
||||
|
||||
await doubleFollow(servers[0], servers[1])
|
||||
|
||||
userToken = await servers[0].users.generateUserAndToken('user', UserRole.USER)
|
||||
anotherUserToken = await servers[0].users.generateUserAndToken('user2', UserRole.USER)
|
||||
|
||||
{
|
||||
const { uuid } = await servers[1].videos.quickUpload({ name: 'remote video' })
|
||||
remoteId = uuid
|
||||
}
|
||||
|
||||
{
|
||||
const { uuid } = await servers[0].videos.quickUpload({ name: 'both 1', token: userToken })
|
||||
validId = uuid
|
||||
}
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
await servers[0].config.enableTranscription()
|
||||
})
|
||||
|
||||
it('Should not run transcription of an unknown video', async function () {
|
||||
await servers[0].captions.runGenerate({ videoId: 404, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should not run transcription of a remote video', async function () {
|
||||
await servers[0].captions.runGenerate({ videoId: remoteId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should not run transcription by a owner/moderator user', async function () {
|
||||
await servers[0].captions.runGenerate({ videoId: validId, token: anotherUserToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should not run transcription if a caption file already exists', async function () {
|
||||
await servers[0].captions.add({
|
||||
language: 'en',
|
||||
videoId: validId,
|
||||
fixture: 'subtitle-good1.vtt'
|
||||
})
|
||||
|
||||
await servers[0].captions.runGenerate({ videoId: validId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
await servers[0].captions.delete({ language: 'en', videoId: validId })
|
||||
})
|
||||
|
||||
it('Should not run transcription if the instance disabled it', async function () {
|
||||
await servers[0].config.disableTranscription()
|
||||
|
||||
await servers[0].captions.runGenerate({ videoId: validId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
await servers[0].config.enableTranscription()
|
||||
})
|
||||
|
||||
it('Should succeed to run transcription', async function () {
|
||||
await servers[0].captions.runGenerate({ videoId: validId, token: userToken })
|
||||
})
|
||||
|
||||
it('Should fail to run transcription twice', async function () {
|
||||
await servers[0].captions.runGenerate({ videoId: validId, token: userToken, expectedStatus: HttpStatusCode.CONFLICT_409 })
|
||||
})
|
||||
|
||||
it('Should fail to run transcription twice with a non-admin user with the forceTranscription boolean', async function () {
|
||||
await servers[0].captions.runGenerate({
|
||||
videoId: validId,
|
||||
token: userToken,
|
||||
forceTranscription: true,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed to run transcription twice with the forceTranscription boolean', async function () {
|
||||
await servers[0].captions.runGenerate({ videoId: validId, forceTranscription: true })
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests(servers)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,196 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import {
|
||||
HttpStatusCode,
|
||||
HttpStatusCodeType,
|
||||
UserRole,
|
||||
VideoInclude,
|
||||
VideoIncludeType,
|
||||
VideoPrivacy,
|
||||
VideoPrivacyType
|
||||
} from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
setDefaultVideoChannel
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test video filters validators', function () {
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken: string
|
||||
let moderatorAccessToken: string
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultVideoChannel([ server ])
|
||||
|
||||
const user = { username: 'user1', password: 'my super password' }
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
userAccessToken = await server.login.getAccessToken(user)
|
||||
|
||||
const moderator = { username: 'moderator', password: 'my super password' }
|
||||
await server.users.create({ username: moderator.username, password: moderator.password, role: UserRole.MODERATOR })
|
||||
|
||||
moderatorAccessToken = await server.login.getAccessToken(moderator)
|
||||
})
|
||||
|
||||
describe('When setting video filters', function () {
|
||||
|
||||
const validIncludes = [
|
||||
VideoInclude.NONE,
|
||||
VideoInclude.BLOCKED_OWNER,
|
||||
VideoInclude.NOT_PUBLISHED_STATE | VideoInclude.BLACKLISTED,
|
||||
VideoInclude.SOURCE
|
||||
]
|
||||
|
||||
async function testEndpoints (options: {
|
||||
token?: string
|
||||
isLocal?: boolean
|
||||
include?: VideoIncludeType
|
||||
privacyOneOf?: VideoPrivacyType[]
|
||||
autoTagOneOf?: string[]
|
||||
expectedStatus: HttpStatusCodeType
|
||||
excludeAlreadyWatched?: boolean
|
||||
unauthenticatedUser?: boolean
|
||||
filter?: string
|
||||
}) {
|
||||
const paths = [
|
||||
'/api/v1/video-channels/root_channel/videos',
|
||||
'/api/v1/accounts/root/videos',
|
||||
'/api/v1/videos',
|
||||
'/api/v1/search/videos'
|
||||
]
|
||||
|
||||
for (const path of paths) {
|
||||
const token = options.unauthenticatedUser
|
||||
? undefined
|
||||
: options.token || server.accessToken
|
||||
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
token,
|
||||
query: {
|
||||
isLocal: options.isLocal,
|
||||
privacyOneOf: options.privacyOneOf,
|
||||
autoTagOneOf: options.autoTagOneOf,
|
||||
include: options.include,
|
||||
excludeAlreadyWatched: options.excludeAlreadyWatched,
|
||||
filter: options.filter
|
||||
},
|
||||
expectedStatus: options.expectedStatus
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
it('Should fail with the old filter query param', async function () {
|
||||
await testEndpoints({ filter: 'all-local', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad privacyOneOf', async function () {
|
||||
await testEndpoints({ privacyOneOf: [ 'toto' ] as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with a good privacyOneOf', async function () {
|
||||
await testEndpoints({ privacyOneOf: [ VideoPrivacy.INTERNAL ], expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
||||
it('Should fail to use privacyOneOf with a simple user', async function () {
|
||||
await testEndpoints({
|
||||
privacyOneOf: [ VideoPrivacy.INTERNAL ],
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail to use autoTagOneOf with a simple user', async function () {
|
||||
await testEndpoints({
|
||||
autoTagOneOf: [ 'test' ],
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed to use autoTagOneOf with a moderator', async function () {
|
||||
await testEndpoints({
|
||||
autoTagOneOf: [ 'test' ],
|
||||
token: moderatorAccessToken,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad include', async function () {
|
||||
await testEndpoints({ include: 'toto' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with a good include', async function () {
|
||||
for (const include of validIncludes) {
|
||||
await testEndpoints({ include, expectedStatus: HttpStatusCode.OK_200 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail to include more videos with a simple user', async function () {
|
||||
for (const include of validIncludes) {
|
||||
await testEndpoints({ token: userAccessToken, include, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed to list all local/all with a moderator', async function () {
|
||||
for (const include of validIncludes) {
|
||||
await testEndpoints({ token: moderatorAccessToken, include, expectedStatus: HttpStatusCode.OK_200 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed to list all local/all with an admin', async function () {
|
||||
for (const include of validIncludes) {
|
||||
await testEndpoints({ token: server.accessToken, include, expectedStatus: HttpStatusCode.OK_200 })
|
||||
}
|
||||
})
|
||||
|
||||
// Because we cannot authenticate the user on the RSS endpoint
|
||||
it('Should fail on the feeds endpoint with the all filter', async function () {
|
||||
for (const include of [ VideoInclude.NOT_PUBLISHED_STATE ]) {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: '/feeds/videos.json',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401,
|
||||
query: {
|
||||
include
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed on the feeds endpoint with the local filter', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: '/feeds/videos.json',
|
||||
expectedStatus: HttpStatusCode.OK_200,
|
||||
query: {
|
||||
isLocal: true
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail when trying to exclude already watched videos for an unlogged user', async function () {
|
||||
await testEndpoints({ excludeAlreadyWatched: true, unauthenticatedUser: true, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed when trying to exclude already watched videos for a logged user', async function () {
|
||||
await testEndpoints({ token: userAccessToken, excludeAlreadyWatched: true, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,145 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { checkBadCountPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeDeleteRequest,
|
||||
makeGetRequest,
|
||||
makePostBodyRequest,
|
||||
makePutBodyRequest,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test videos history API validator', function () {
|
||||
const myHistoryPath = '/api/v1/users/me/history/videos'
|
||||
const myHistoryRemove = myHistoryPath + '/remove'
|
||||
let viewPath: string
|
||||
let server: PeerTubeServer
|
||||
let videoId: number
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
const { id, uuid } = await server.videos.upload()
|
||||
viewPath = '/api/v1/videos/' + uuid + '/views'
|
||||
videoId = id
|
||||
})
|
||||
|
||||
describe('When notifying a user is watching a video', function () {
|
||||
|
||||
it('Should fail with a bad token', async function () {
|
||||
const fields = { currentTime: 5 }
|
||||
await makePutBodyRequest({ url: server.url, path: viewPath, fields, token: 'bad', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
const fields = { currentTime: 5 }
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: viewPath,
|
||||
fields,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing user videos history', function () {
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, myHistoryPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, myHistoryPath, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makeGetRequest({ url: server.url, path: myHistoryPath, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
await makeGetRequest({ url: server.url, token: server.accessToken, path: myHistoryPath, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When removing a specific user video history element', function () {
|
||||
let path: string
|
||||
|
||||
before(function () {
|
||||
path = myHistoryPath + '/' + videoId
|
||||
})
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makeDeleteRequest({ url: server.url, path, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad videoId parameter', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path: myHistoryRemove + '/hi',
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When removing all user videos history', function () {
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
await makePostBodyRequest({ url: server.url, path: myHistoryPath + '/remove', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with a bad beforeDate parameter', async function () {
|
||||
const body = { beforeDate: '15' }
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path: myHistoryRemove,
|
||||
fields: body,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with a valid beforeDate param', async function () {
|
||||
const body = { beforeDate: new Date().toISOString() }
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path: myHistoryRemove,
|
||||
fields: body,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed without body', async function () {
|
||||
await makePostBodyRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path: myHistoryRemove,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { cleanupTests, createSingleServer, PeerTubeServer } from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test videos overview API validator', function () {
|
||||
let server: PeerTubeServer
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
})
|
||||
|
||||
describe('When getting videos overview', function () {
|
||||
|
||||
it('Should fail with a bad pagination', async function () {
|
||||
await server.overviews.getVideos({ page: 0, expectedStatus: 400 })
|
||||
await server.overviews.getVideos({ page: 100, expectedStatus: 400 })
|
||||
})
|
||||
|
||||
it('Should succeed with a good pagination', async function () {
|
||||
await server.overviews.getVideos({ page: 1 })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,897 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { omit, randomInt } from '@peertube/peertube-core-utils'
|
||||
import {
|
||||
HttpStatusCode,
|
||||
PeerTubeProblemDocument,
|
||||
VideoCommentPolicy,
|
||||
VideoCreateResult,
|
||||
VideoPrivacy
|
||||
} from '@peertube/peertube-models'
|
||||
import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
|
||||
import {
|
||||
PeerTubeServer,
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeDeleteRequest,
|
||||
makeGetRequest,
|
||||
makePutBodyRequest,
|
||||
makeUploadRequest,
|
||||
setAccessTokensToServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
import { checkUploadVideoParam } from '@tests/shared/videos.js'
|
||||
import { expect } from 'chai'
|
||||
import { join } from 'path'
|
||||
|
||||
describe('Test videos API validator', function () {
|
||||
const path = '/api/v1/videos/'
|
||||
let server: PeerTubeServer
|
||||
let userAccessToken = ''
|
||||
let accountName: string
|
||||
let channelId: number
|
||||
let channelName: string
|
||||
let video: VideoCreateResult
|
||||
let privateVideo: VideoCreateResult
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
before(async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
|
||||
userAccessToken = await server.users.generateUserAndToken('user1')
|
||||
|
||||
{
|
||||
const body = await server.users.getMyInfo()
|
||||
channelId = body.videoChannels[0].id
|
||||
channelName = body.videoChannels[0].name
|
||||
accountName = body.account.name + '@' + body.account.host
|
||||
}
|
||||
|
||||
{
|
||||
privateVideo = await server.videos.quickUpload({ name: 'private video', privacy: VideoPrivacy.PRIVATE })
|
||||
}
|
||||
})
|
||||
|
||||
describe('When listing videos', function () {
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path)
|
||||
})
|
||||
|
||||
it('Should fail with a bad skipVideos query', async function () {
|
||||
await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200, query: { skipCount: 'toto' } })
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200, query: { skipCount: false } })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When searching a video', function () {
|
||||
|
||||
it('Should fail with nothing', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path: join(path, 'search'),
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, join(path, 'search', 'test'))
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, join(path, 'search', 'test'))
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, join(path, 'search', 'test'))
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing my videos', function () {
|
||||
const path = '/api/v1/users/me/videos'
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an invalid channel', async function () {
|
||||
await makeGetRequest({ url: server.url, token: server.accessToken, path, query: { channelId: 'toto' } })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown channel', async function () {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: server.accessToken,
|
||||
path,
|
||||
query: { channelId: 89898 },
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, token: server.accessToken, path, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing account videos', function () {
|
||||
let path: string
|
||||
|
||||
before(async function () {
|
||||
path = '/api/v1/accounts/' + accountName + '/videos'
|
||||
})
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When listing video channel videos', function () {
|
||||
let path: string
|
||||
|
||||
before(async function () {
|
||||
path = '/api/v1/video-channels/' + channelName + '/videos'
|
||||
})
|
||||
|
||||
it('Should fail with a bad start pagination', async function () {
|
||||
await checkBadStartPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with a bad count pagination', async function () {
|
||||
await checkBadCountPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect sort', async function () {
|
||||
await checkBadSortPagination(server.url, path, server.accessToken)
|
||||
})
|
||||
|
||||
it('Should success with the correct parameters', async function () {
|
||||
await makeGetRequest({ url: server.url, path, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When adding a video', function () {
|
||||
const baseCorrectParams = {
|
||||
name: 'my super name',
|
||||
category: 5,
|
||||
licence: 1,
|
||||
language: 'pt',
|
||||
nsfw: false,
|
||||
commentsPolicy: VideoCommentPolicy.ENABLED,
|
||||
downloadEnabled: true,
|
||||
waitTranscoding: true,
|
||||
description: 'my super description',
|
||||
support: 'my super support text',
|
||||
tags: [ 'tag1', 'tag2' ],
|
||||
privacy: VideoPrivacy.PUBLIC,
|
||||
channelId: -1,
|
||||
originallyPublishedAt: new Date().toISOString()
|
||||
}
|
||||
|
||||
const baseCorrectAttaches = {
|
||||
fixture: buildAbsoluteFixturePath('video_short.webm')
|
||||
}
|
||||
|
||||
before(function () {
|
||||
// Put in before to have channelId
|
||||
baseCorrectParams.channelId = channelId
|
||||
})
|
||||
|
||||
function runSuite (mode: 'legacy' | 'resumable') {
|
||||
|
||||
const baseOptions = () => {
|
||||
return {
|
||||
server,
|
||||
token: server.accessToken,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400,
|
||||
mode
|
||||
}
|
||||
}
|
||||
|
||||
it('Should fail with nothing', async function () {
|
||||
const fields = {}
|
||||
const attaches = {}
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail without name', async function () {
|
||||
const fields = omit(baseCorrectParams, [ 'name' ])
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a long name', async function () {
|
||||
const fields = { ...baseCorrectParams, name: 'super'.repeat(65) }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a bad category', async function () {
|
||||
const fields = { ...baseCorrectParams, category: 125 }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a bad licence', async function () {
|
||||
const fields = { ...baseCorrectParams, licence: 125 }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a bad language', async function () {
|
||||
const fields = { ...baseCorrectParams, language: 'a'.repeat(15) }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with bad commentsPolicy', async function () {
|
||||
const fields = { ...baseCorrectParams, commentsPolicy: 42 as any }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a long description', async function () {
|
||||
const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a long support text', async function () {
|
||||
const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail without a channel', async function () {
|
||||
const fields = omit(baseCorrectParams, [ 'channelId' ])
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a bad channel', async function () {
|
||||
const fields = { ...baseCorrectParams, channelId: 545454 }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with another user channel', async function () {
|
||||
const user = {
|
||||
username: 'fake' + randomInt(0, 1500),
|
||||
password: 'fake_password'
|
||||
}
|
||||
await server.users.create({ username: user.username, password: user.password })
|
||||
|
||||
const accessTokenUser = await server.login.getAccessToken(user)
|
||||
const { videoChannels } = await server.users.getMyInfo({ token: accessTokenUser })
|
||||
const customChannelId = videoChannels[0].id
|
||||
|
||||
const fields = { ...baseCorrectParams, channelId: customChannelId }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({
|
||||
...baseOptions(),
|
||||
token: userAccessToken,
|
||||
attributes: { ...fields, ...attaches }
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with too many tags', async function () {
|
||||
const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a tag length too low', async function () {
|
||||
const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a tag length too big', async function () {
|
||||
const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a bad schedule update (miss updateAt)', async function () {
|
||||
const fields = { ...baseCorrectParams, scheduleUpdate: { privacy: VideoPrivacy.PUBLIC } as any }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a bad schedule update (wrong updateAt)', async function () {
|
||||
const fields = {
|
||||
...baseCorrectParams,
|
||||
|
||||
scheduleUpdate: {
|
||||
privacy: VideoPrivacy.PUBLIC,
|
||||
updateAt: 'toto'
|
||||
}
|
||||
}
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a bad originally published at attribute', async function () {
|
||||
const fields = { ...baseCorrectParams, originallyPublishedAt: 'toto' }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail without an input file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {}
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect input file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
let attaches = { fixture: buildAbsoluteFixturePath('video_short_fake.webm') }
|
||||
|
||||
await checkUploadVideoParam({
|
||||
...baseOptions(),
|
||||
attributes: { ...fields, ...attaches },
|
||||
// 200 for the init request, 422 when the file has finished being uploaded
|
||||
expectedStatus: undefined,
|
||||
completedExpectedStatus: HttpStatusCode.UNPROCESSABLE_ENTITY_422
|
||||
})
|
||||
|
||||
attaches = { fixture: buildAbsoluteFixturePath('video_short.mkv') }
|
||||
await checkUploadVideoParam({
|
||||
...baseOptions(),
|
||||
attributes: { ...fields, ...attaches },
|
||||
expectedStatus: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect thumbnail file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
thumbnailfile: buildAbsoluteFixturePath('video_short.mp4'),
|
||||
fixture: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a big thumbnail file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
thumbnailfile: buildAbsoluteFixturePath('custom-preview-big.png'),
|
||||
fixture: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect preview file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
previewfile: buildAbsoluteFixturePath('video_short.mp4'),
|
||||
fixture: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should fail with a big preview file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
previewfile: buildAbsoluteFixturePath('custom-preview-big.png'),
|
||||
fixture: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
|
||||
await checkUploadVideoParam({ ...baseOptions(), attributes: { ...fields, ...attaches } })
|
||||
})
|
||||
|
||||
it('Should report the appropriate error', async function () {
|
||||
const fields = { ...baseCorrectParams, language: 'a'.repeat(15) }
|
||||
const attaches = baseCorrectAttaches
|
||||
|
||||
const attributes = { ...fields, ...attaches }
|
||||
const body = await checkUploadVideoParam({ ...baseOptions(), attributes })
|
||||
|
||||
const error = body as unknown as PeerTubeProblemDocument
|
||||
|
||||
if (mode === 'legacy') {
|
||||
expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadLegacy')
|
||||
} else {
|
||||
expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadResumableInit')
|
||||
}
|
||||
|
||||
expect(error.type).to.equal('about:blank')
|
||||
expect(error.title).to.equal('Bad Request')
|
||||
|
||||
expect(error.detail).to.equal('Incorrect request parameters: language')
|
||||
expect(error.error).to.equal('Incorrect request parameters: language')
|
||||
|
||||
expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400)
|
||||
expect(error['invalid-params'].language).to.exist
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
this.timeout(30000)
|
||||
|
||||
const fields = baseCorrectParams
|
||||
|
||||
{
|
||||
const attaches = baseCorrectAttaches
|
||||
await checkUploadVideoParam({
|
||||
...baseOptions(),
|
||||
attributes: { ...fields, ...attaches },
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
const attaches = {
|
||||
...baseCorrectAttaches,
|
||||
|
||||
videofile: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
|
||||
await checkUploadVideoParam({
|
||||
...baseOptions(),
|
||||
attributes: { ...fields, ...attaches },
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
const attaches = {
|
||||
...baseCorrectAttaches,
|
||||
|
||||
videofile: buildAbsoluteFixturePath('video_short.ogv')
|
||||
}
|
||||
|
||||
await checkUploadVideoParam({
|
||||
...baseOptions(),
|
||||
attributes: { ...fields, ...attaches },
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
describe('Resumable upload', function () {
|
||||
runSuite('resumable')
|
||||
})
|
||||
|
||||
describe('Legacy upload', function () {
|
||||
runSuite('legacy')
|
||||
})
|
||||
})
|
||||
|
||||
describe('When updating a video', function () {
|
||||
const baseCorrectParams = {
|
||||
name: 'my super name',
|
||||
category: 5,
|
||||
licence: 2,
|
||||
language: 'pt',
|
||||
nsfw: false,
|
||||
commentsPolicy: VideoCommentPolicy.DISABLED,
|
||||
downloadEnabled: false,
|
||||
description: 'my super description',
|
||||
privacy: VideoPrivacy.PUBLIC,
|
||||
tags: [ 'tag1', 'tag2' ]
|
||||
}
|
||||
|
||||
before(async function () {
|
||||
const { data } = await server.videos.list()
|
||||
video = data[0]
|
||||
})
|
||||
|
||||
it('Should fail with nothing', async function () {
|
||||
const fields = {}
|
||||
await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail without a valid uuid', async function () {
|
||||
const fields = baseCorrectParams
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'blabla', token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown id', async function () {
|
||||
const fields = baseCorrectParams
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + '4da6fde3-88f7-4d16-b119-108df5630b06',
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a long name', async function () {
|
||||
const fields = { ...baseCorrectParams, name: 'super'.repeat(65) }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad category', async function () {
|
||||
const fields = { ...baseCorrectParams, category: 125 }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad licence', async function () {
|
||||
const fields = { ...baseCorrectParams, licence: 125 }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad language', async function () {
|
||||
const fields = { ...baseCorrectParams, language: 'a'.repeat(15) }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long description', async function () {
|
||||
const fields = { ...baseCorrectParams, description: 'super'.repeat(2500) }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a long support text', async function () {
|
||||
const fields = { ...baseCorrectParams, support: 'super'.repeat(201) }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad channel', async function () {
|
||||
const fields = { ...baseCorrectParams, channelId: 545454 }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with too many tags', async function () {
|
||||
const fields = { ...baseCorrectParams, tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a tag length too low', async function () {
|
||||
const fields = { ...baseCorrectParams, tags: [ 'tag1', 't' ] }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a tag length too big', async function () {
|
||||
const fields = { ...baseCorrectParams, tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad schedule update (miss updateAt)', async function () {
|
||||
const fields = { ...baseCorrectParams, scheduleUpdate: { privacy: VideoPrivacy.PUBLIC } }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad schedule update (wrong updateAt)', async function () {
|
||||
const fields = { ...baseCorrectParams, scheduleUpdate: { updateAt: 'toto', privacy: VideoPrivacy.PUBLIC } }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a bad originally published at param', async function () {
|
||||
const fields = { ...baseCorrectParams, originallyPublishedAt: 'toto' }
|
||||
|
||||
await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect thumbnail file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
thumbnailfile: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
method: 'PUT',
|
||||
path: path + video.shortUUID,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
attaches
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a big thumbnail file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
thumbnailfile: buildAbsoluteFixturePath('custom-preview-big.png')
|
||||
}
|
||||
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
method: 'PUT',
|
||||
path: path + video.shortUUID,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
attaches
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an incorrect preview file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
previewfile: buildAbsoluteFixturePath('video_short.mp4')
|
||||
}
|
||||
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
method: 'PUT',
|
||||
path: path + video.shortUUID,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
attaches
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a big preview file', async function () {
|
||||
const fields = baseCorrectParams
|
||||
const attaches = {
|
||||
previewfile: buildAbsoluteFixturePath('custom-preview-big.png')
|
||||
}
|
||||
|
||||
await makeUploadRequest({
|
||||
url: server.url,
|
||||
method: 'PUT',
|
||||
path: path + video.shortUUID,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
attaches
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a video of another user without the appropriate right', async function () {
|
||||
const fields = baseCorrectParams
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + video.shortUUID,
|
||||
token: userAccessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a video of another server')
|
||||
|
||||
it('Shoud report the appropriate error', async function () {
|
||||
const fields = { ...baseCorrectParams, licence: 125 }
|
||||
|
||||
const res = await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
|
||||
const error = res.body as PeerTubeProblemDocument
|
||||
|
||||
expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/putVideo')
|
||||
|
||||
expect(error.type).to.equal('about:blank')
|
||||
expect(error.title).to.equal('Bad Request')
|
||||
|
||||
expect(error.detail).to.equal('Incorrect request parameters: licence')
|
||||
expect(error.error).to.equal('Incorrect request parameters: licence')
|
||||
|
||||
expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400)
|
||||
expect(error['invalid-params'].licence).to.exist
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
const fields = baseCorrectParams
|
||||
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + video.shortUUID,
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting a video', function () {
|
||||
it('Should return the list of the videos with nothing', async function () {
|
||||
const res = await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.OK_200
|
||||
})
|
||||
|
||||
expect(res.body.data).to.be.an('array')
|
||||
expect(res.body.data.length).to.equal(6)
|
||||
})
|
||||
|
||||
it('Should fail without a correct uuid', async function () {
|
||||
await server.videos.get({ id: 'coucou', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should return 404 with an incorrect video', async function () {
|
||||
await server.videos.get({ id: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Shoud report the appropriate error', async function () {
|
||||
const body = await server.videos.get({ id: 'hi', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
const error = body as unknown as PeerTubeProblemDocument
|
||||
|
||||
expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo')
|
||||
|
||||
expect(error.type).to.equal('about:blank')
|
||||
expect(error.title).to.equal('Bad Request')
|
||||
|
||||
expect(error.detail).to.equal('Incorrect request parameters: id')
|
||||
expect(error.error).to.equal('Incorrect request parameters: id')
|
||||
|
||||
expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400)
|
||||
expect(error['invalid-params'].id).to.exist
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await server.videos.get({ id: video.shortUUID })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When rating a video', function () {
|
||||
let videoId: number
|
||||
|
||||
before(async function () {
|
||||
const { data } = await server.videos.list()
|
||||
videoId = data[0].id
|
||||
})
|
||||
|
||||
it('Should fail without a valid uuid', async function () {
|
||||
const fields = {
|
||||
rating: 'like'
|
||||
}
|
||||
await makePutBodyRequest({ url: server.url, path: path + 'blabla/rate', token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with an unknown id', async function () {
|
||||
const fields = {
|
||||
rating: 'like'
|
||||
}
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + '4da6fde3-88f7-4d16-b119-108df5630b06/rate',
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a wrong rating', async function () {
|
||||
const fields = {
|
||||
rating: 'likes'
|
||||
}
|
||||
await makePutBodyRequest({ url: server.url, path: path + videoId + '/rate', token: server.accessToken, fields })
|
||||
})
|
||||
|
||||
it('Should fail with a private video of another user', async function () {
|
||||
const fields = {
|
||||
rating: 'like'
|
||||
}
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + privateVideo.uuid + '/rate',
|
||||
token: userAccessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
const fields = {
|
||||
rating: 'like'
|
||||
}
|
||||
await makePutBodyRequest({
|
||||
url: server.url,
|
||||
path: path + videoId + '/rate',
|
||||
token: server.accessToken,
|
||||
fields,
|
||||
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When removing a video', function () {
|
||||
it('Should have 404 with nothing', async function () {
|
||||
await makeDeleteRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without a correct uuid', async function () {
|
||||
await server.videos.remove({ id: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with a video which does not exist', async function () {
|
||||
await server.videos.remove({ id: '4da6fde3-88f7-4d16-b119-108df5630b06', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
|
||||
it('Should fail with a video of another user without the appropriate right', async function () {
|
||||
await server.videos.remove({ token: userAccessToken, id: video.uuid, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail with a video of another server')
|
||||
|
||||
it('Shoud report the appropriate error', async function () {
|
||||
const body = await server.videos.remove({ id: 'hello', expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
const error = body as PeerTubeProblemDocument
|
||||
|
||||
expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/delVideo')
|
||||
|
||||
expect(error.type).to.equal('about:blank')
|
||||
expect(error.title).to.equal('Bad Request')
|
||||
|
||||
expect(error.detail).to.equal('Incorrect request parameters: id')
|
||||
expect(error.error).to.equal('Incorrect request parameters: id')
|
||||
|
||||
expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400)
|
||||
expect(error['invalid-params'].id).to.exist
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await server.videos.remove({ id: video.uuid })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,228 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode, VideoPrivacy } from '@peertube/peertube-models'
|
||||
import {
|
||||
cleanupTests,
|
||||
createMultipleServers,
|
||||
doubleFollow,
|
||||
PeerTubeServer,
|
||||
setAccessTokensToServers,
|
||||
setDefaultVideoChannel
|
||||
} from '@peertube/peertube-server-commands'
|
||||
|
||||
describe('Test videos views API validators', function () {
|
||||
let servers: PeerTubeServer[]
|
||||
let liveVideoId: string
|
||||
let videoId: string
|
||||
let remoteVideoId: string
|
||||
let userAccessToken: string
|
||||
|
||||
before(async function () {
|
||||
this.timeout(240000)
|
||||
|
||||
servers = await createMultipleServers(2)
|
||||
await setAccessTokensToServers(servers)
|
||||
await setDefaultVideoChannel(servers)
|
||||
|
||||
await servers[0].config.enableLive({ allowReplay: false, transcoding: false });
|
||||
|
||||
({ uuid: videoId } = await servers[0].videos.quickUpload({ name: 'video' }));
|
||||
({ uuid: remoteVideoId } = await servers[1].videos.quickUpload({ name: 'video' }));
|
||||
({ uuid: liveVideoId } = await servers[0].live.create({
|
||||
fields: {
|
||||
name: 'live',
|
||||
privacy: VideoPrivacy.PUBLIC,
|
||||
channelId: servers[0].store.channel.id
|
||||
}
|
||||
}))
|
||||
|
||||
userAccessToken = await servers[0].users.generateUserAndToken('user')
|
||||
|
||||
await doubleFollow(servers[0], servers[1])
|
||||
})
|
||||
|
||||
describe('When viewing a video', async function () {
|
||||
|
||||
it('Should fail without current time', async function () {
|
||||
await servers[0].views.view({ id: videoId, currentTime: undefined, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid current time', async function () {
|
||||
await servers[0].views.view({ id: videoId, currentTime: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await servers[0].views.view({ id: videoId, currentTime: -1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await servers[0].views.view({ id: videoId, currentTime: 10, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with correct parameters', async function () {
|
||||
await servers[0].views.view({ id: videoId, currentTime: 1 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting overall stats', function () {
|
||||
|
||||
it('Should fail with a remote video', async function () {
|
||||
await servers[0].videoStats.getOverallStats({ videoId: remoteVideoId, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
})
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await servers[0].videoStats.getOverallStats({ videoId, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
})
|
||||
|
||||
it('Should fail with another token', async function () {
|
||||
await servers[0].videoStats.getOverallStats({
|
||||
videoId,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid start date', async function () {
|
||||
await servers[0].videoStats.getOverallStats({
|
||||
videoId,
|
||||
startDate: 'fake' as any,
|
||||
endDate: new Date().toISOString(),
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid end date', async function () {
|
||||
await servers[0].videoStats.getOverallStats({
|
||||
videoId,
|
||||
startDate: new Date().toISOString(),
|
||||
endDate: 'fake' as any,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await servers[0].videoStats.getOverallStats({
|
||||
videoId,
|
||||
startDate: new Date().toISOString(),
|
||||
endDate: new Date().toISOString()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting timeserie stats', function () {
|
||||
|
||||
it('Should fail with a remote video', async function () {
|
||||
await servers[0].videoStats.getTimeserieStats({
|
||||
videoId: remoteVideoId,
|
||||
metric: 'viewers',
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await servers[0].videoStats.getTimeserieStats({
|
||||
videoId,
|
||||
token: null,
|
||||
metric: 'viewers',
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with another token', async function () {
|
||||
await servers[0].videoStats.getTimeserieStats({
|
||||
videoId,
|
||||
token: userAccessToken,
|
||||
metric: 'viewers',
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid metric', async function () {
|
||||
await servers[0].videoStats.getTimeserieStats({ videoId, metric: 'hello' as any, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should fail with an invalid start date', async function () {
|
||||
await servers[0].videoStats.getTimeserieStats({
|
||||
videoId,
|
||||
metric: 'viewers',
|
||||
startDate: 'fake' as any,
|
||||
endDate: new Date(),
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with an invalid end date', async function () {
|
||||
await servers[0].videoStats.getTimeserieStats({
|
||||
videoId,
|
||||
metric: 'viewers',
|
||||
startDate: new Date(),
|
||||
endDate: 'fake' as any,
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if start date is specified but not end date', async function () {
|
||||
await servers[0].videoStats.getTimeserieStats({
|
||||
videoId,
|
||||
metric: 'viewers',
|
||||
startDate: new Date(),
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail if end date is specified but not start date', async function () {
|
||||
await servers[0].videoStats.getTimeserieStats({
|
||||
videoId,
|
||||
metric: 'viewers',
|
||||
endDate: new Date(),
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with a too big interval', async function () {
|
||||
await servers[0].videoStats.getTimeserieStats({
|
||||
videoId,
|
||||
metric: 'viewers',
|
||||
startDate: new Date('2000-04-07T08:31:57.126Z'),
|
||||
endDate: new Date(),
|
||||
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||
})
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await servers[0].videoStats.getTimeserieStats({ videoId, metric: 'viewers' })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When getting retention stats', function () {
|
||||
|
||||
it('Should fail with a remote video', async function () {
|
||||
await servers[0].videoStats.getRetentionStats({
|
||||
videoId: remoteVideoId,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail without token', async function () {
|
||||
await servers[0].videoStats.getRetentionStats({
|
||||
videoId,
|
||||
token: null,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail with another token', async function () {
|
||||
await servers[0].videoStats.getRetentionStats({
|
||||
videoId,
|
||||
token: userAccessToken,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
})
|
||||
|
||||
it('Should fail on live video', async function () {
|
||||
await servers[0].videoStats.getRetentionStats({ videoId: liveVideoId, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
})
|
||||
|
||||
it('Should succeed with the correct parameters', async function () {
|
||||
await servers[0].videoStats.getRetentionStats({ videoId })
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests(servers)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,254 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||
|
||||
import { HttpStatusCode, UserRole } from '@peertube/peertube-models'
|
||||
import {
|
||||
PeerTubeServer,
|
||||
WatchedWordsCommand,
|
||||
cleanupTests,
|
||||
createSingleServer,
|
||||
makeGetRequest,
|
||||
setAccessTokensToServers,
|
||||
setDefaultAccountAvatar
|
||||
} from '@peertube/peertube-server-commands'
|
||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
|
||||
|
||||
describe('Test watched words API validators', function () {
|
||||
let server: PeerTubeServer
|
||||
|
||||
let userToken: string
|
||||
let userToken2: string
|
||||
let moderatorToken: string
|
||||
|
||||
let command: WatchedWordsCommand
|
||||
|
||||
let accountListId: number
|
||||
let serverListId: number
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
server = await createSingleServer(1)
|
||||
await setAccessTokensToServers([ server ])
|
||||
await setDefaultAccountAvatar([ server ])
|
||||
|
||||
userToken = await server.users.generateUserAndToken('user1')
|
||||
userToken2 = await server.users.generateUserAndToken('user2')
|
||||
moderatorToken = await server.users.generateUserAndToken('moderator', UserRole.MODERATOR)
|
||||
|
||||
command = server.watchedWordsLists
|
||||
|
||||
{
|
||||
const { watchedWordsList } = await command.createList({
|
||||
accountName: 'user1',
|
||||
token: userToken,
|
||||
listName: 'default',
|
||||
words: [ 'word1' ]
|
||||
})
|
||||
accountListId = watchedWordsList.id
|
||||
}
|
||||
|
||||
{
|
||||
const { watchedWordsList } = await command.createList({
|
||||
listName: 'default',
|
||||
words: [ 'word1' ]
|
||||
})
|
||||
serverListId = watchedWordsList.id
|
||||
}
|
||||
})
|
||||
|
||||
describe('Account & server watched words', function () {
|
||||
|
||||
describe('When listing watched words', function () {
|
||||
const paths = [
|
||||
'/api/v1/watched-words/accounts/user1/lists',
|
||||
'/api/v1/watched-words/server/lists'
|
||||
]
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
for (const path of paths) {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with the wrong token', async function () {
|
||||
for (const path of paths) {
|
||||
await makeGetRequest({
|
||||
url: server.url,
|
||||
token: userToken2,
|
||||
path,
|
||||
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with a bad start/count pagination or incorrect sort', async function () {
|
||||
for (const path of paths) {
|
||||
await checkBadStartPagination(server.url, path, userToken)
|
||||
await checkBadCountPagination(server.url, path, userToken)
|
||||
await checkBadSortPagination(server.url, path, userToken)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('When adding/updating watched words', function () {
|
||||
const baseParams = () => ([
|
||||
{
|
||||
token: userToken,
|
||||
accountName: 'user1',
|
||||
listName: 'list',
|
||||
words: [ 'word1' ],
|
||||
listId: accountListId
|
||||
},
|
||||
{
|
||||
token: moderatorToken,
|
||||
listName: 'list',
|
||||
words: [ 'word1' ],
|
||||
listId: serverListId
|
||||
}
|
||||
])
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
for (const baseParam of baseParams()) {
|
||||
await command.createList({ ...baseParam, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
await command.updateList({ ...baseParam, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with the wrong token', async function () {
|
||||
for (const baseParam of baseParams()) {
|
||||
await command.createList({ ...baseParam, token: userToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
await command.updateList({ ...baseParam, token: userToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with an invalid listName', async function () {
|
||||
for (const baseParam of baseParams()) {
|
||||
await command.createList({ ...baseParam, listName: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
for (const listName of [ '', 'a'.repeat(500) ]) {
|
||||
await command.createList({ ...baseParam, listName, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await command.updateList({ ...baseParam, listName, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with invalid words', async function () {
|
||||
const bigArray: string[] = []
|
||||
for (let i = 0; i < 550; i++) {
|
||||
bigArray.push(`word${i}`)
|
||||
}
|
||||
|
||||
const toTest = [
|
||||
[],
|
||||
bigArray,
|
||||
[ 'a'.repeat(102) ],
|
||||
[ '' ],
|
||||
[ '', 'word' ]
|
||||
]
|
||||
|
||||
for (const baseParam of baseParams()) {
|
||||
await command.createList({ ...baseParam, words: null, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
for (const words of toTest) {
|
||||
await command.createList({ ...baseParam, words, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await command.updateList({ ...baseParam, words, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
for (const baseParam of baseParams()) {
|
||||
await command.createList(baseParam)
|
||||
await command.updateList({ ...baseParam, listName: 'updated-list' })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed to update a list with the same name', async function () {
|
||||
for (const baseParam of baseParams()) {
|
||||
await command.updateList({ ...baseParam, listName: 'updated-list' })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail to add a list with an already existing name', async function () {
|
||||
for (const baseParam of baseParams()) {
|
||||
await command.createList({ ...baseParam, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
await command.updateList({ ...baseParam, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('When deleting watched words', function () {
|
||||
const baseParams = () => ([
|
||||
{
|
||||
token: userToken,
|
||||
accountName: 'user1',
|
||||
listId: accountListId
|
||||
},
|
||||
{
|
||||
token: moderatorToken,
|
||||
listId: serverListId
|
||||
}
|
||||
])
|
||||
|
||||
it('Should fail with an unauthenticated user', async function () {
|
||||
for (const baseParam of baseParams()) {
|
||||
await command.deleteList({ ...baseParam, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should fail with the wrong token', async function () {
|
||||
for (const baseParam of baseParams()) {
|
||||
await command.deleteList({ ...baseParam, token: userToken2, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
||||
}
|
||||
})
|
||||
|
||||
it('Should succeed with the correct params', async function () {
|
||||
for (const baseParam of baseParams()) {
|
||||
await command.deleteList(baseParam)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Account specific watched words', function () {
|
||||
|
||||
describe('When listing watched words', function () {
|
||||
it('Should fail with an unknown account', async function () {
|
||||
await command.listWordsLists({ accountName: 'unknown', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When adding/updating watched words', function () {
|
||||
const baseParams = () => ({
|
||||
token: userToken,
|
||||
accountName: 'user1',
|
||||
listName: 'list',
|
||||
words: [ 'word1' ]
|
||||
})
|
||||
|
||||
it('Should fail with an unknown account', async function () {
|
||||
await command.createList({ ...baseParams(), accountName: 'unknown', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('When deleting watched words', function () {
|
||||
const baseParams = () => ({
|
||||
listId: accountListId,
|
||||
token: userToken,
|
||||
accountName: 'user1'
|
||||
})
|
||||
|
||||
it('Should fail with an unknown account', async function () {
|
||||
await command.deleteList({ ...baseParams(), accountName: 'unknown', expectedStatus: HttpStatusCode.NOT_FOUND_404 })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await cleanupTests([ server ])
|
||||
})
|
||||
})
|
||||
新しい課題から参照
ユーザをブロックする