はじまりの大地

このコミットが含まれているのは:
2024-07-15 09:14:04 +09:00
コミット 6632905f32
3501個のファイルの変更1439465行の追加0行の削除
+438
ファイルの表示
@@ -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 ])
})
})
+43
ファイルの表示
@@ -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 ])
})
})
+137
ファイルの表示
@@ -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 ])
})
})
+556
ファイルの表示
@@ -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)
})
})
+86
ファイルの表示
@@ -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 ])
})
})
+209
ファイルの表示
@@ -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 ])
})
})
+305
ファイルの表示
@@ -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 ])
})
})
+86
ファイルの表示
@@ -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 ])
})
})
+79
ファイルの表示
@@ -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 ])
})
})
+67
ファイルの表示
@@ -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 ])
})
})
+369
ファイルの表示
@@ -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 ])
})
})
+51
ファイルの表示
@@ -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'
+125
ファイルの表示
@@ -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 ])
})
})
+576
ファイルの表示
@@ -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 ])
})
})
+163
ファイルの表示
@@ -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 ])
})
})
+214
ファイルの表示
@@ -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 ])
})
})
+492
ファイルの表示
@@ -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 ])
})
})
+490
ファイルの表示
@@ -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 ])
})
})
+240
ファイルの表示
@@ -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)
})
})
+446
ファイルの表示
@@ -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 ])
})
})
+911
ファイルの表示
@@ -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 ])
})
})
+278
ファイルの表示
@@ -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 ])
})
})
+207
ファイルの表示
@@ -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
})
}
+112
ファイルの表示
@@ -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)
})
})
+294
ファイルの表示
@@ -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 ])
})
})
+134
ファイルの表示
@@ -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 ])
})
})
+339
ファイルの表示
@@ -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 ])
})
})
+169
ファイルの表示
@@ -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 ])
})
})
+291
ファイルの表示
@@ -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 ])
})
})
+298
ファイルの表示
@@ -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 ])
})
})
+457
ファイルの表示
@@ -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 ])
})
})
+122
ファイルの表示
@@ -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 ])
})
})
+292
ファイルの表示
@@ -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)
})
})
+312
ファイルの表示
@@ -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 ])
})
})
+319
ファイルの表示
@@ -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()
})
})
+379
ファイルの表示
@@ -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 ])
})
})
+172
ファイルの表示
@@ -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 ])
})
})
+576
ファイルの表示
@@ -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 ])
})
})
+195
ファイルの表示
@@ -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)
})
})
+439
ファイルの表示
@@ -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 ])
})
})
+605
ファイルの表示
@@ -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 ])
})
})
+695
ファイルの表示
@@ -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 ])
})
})
+247
ファイルの表示
@@ -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 ])
})
})
+45
ファイルの表示
@@ -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 ])
})
})
+392
ファイルの表示
@@ -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 ])
})
})
+70
ファイルの表示
@@ -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 ])
})
})
+106
ファイルの表示
@@ -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)
})
})
+196
ファイルの表示
@@ -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 ])
})
})
+145
ファイルの表示
@@ -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 ])
})
})
+31
ファイルの表示
@@ -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 ])
})
})
+897
ファイルの表示
@@ -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 ])
})
})
+228
ファイルの表示
@@ -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)
})
})
+254
ファイルの表示
@@ -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 ])
})
})