aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests
diff options
context:
space:
mode:
Diffstat (limited to 'server/tests')
-rw-r--r--server/tests/api/activitypub/client.ts98
-rw-r--r--server/tests/api/activitypub/helpers.ts37
-rw-r--r--server/tests/api/activitypub/security.ts7
-rw-r--r--server/tests/api/check-params/abuses.ts2
-rw-r--r--server/tests/api/check-params/config.ts3
-rw-r--r--server/tests/api/check-params/custom-pages.ts81
-rw-r--r--server/tests/api/check-params/index.ts1
-rw-r--r--server/tests/api/check-params/live.ts52
-rw-r--r--server/tests/api/check-params/plugins.ts12
-rw-r--r--server/tests/api/check-params/redundancy.ts38
-rw-r--r--server/tests/api/check-params/search.ts25
-rw-r--r--server/tests/api/check-params/users.ts22
-rw-r--r--server/tests/api/check-params/video-blacklist.ts12
-rw-r--r--server/tests/api/check-params/video-captions.ts47
-rw-r--r--server/tests/api/check-params/video-channels.ts14
-rw-r--r--server/tests/api/check-params/video-comments.ts31
-rw-r--r--server/tests/api/check-params/video-imports.ts18
-rw-r--r--server/tests/api/check-params/video-playlists.ts64
-rw-r--r--server/tests/api/check-params/videos-filter.ts2
-rw-r--r--server/tests/api/check-params/videos.ts126
-rw-r--r--server/tests/api/live/index.ts2
-rw-r--r--server/tests/api/live/live-permanent.ts4
-rw-r--r--server/tests/api/live/live-socket-messages.ts196
-rw-r--r--server/tests/api/live/live-views.ts130
-rw-r--r--server/tests/api/live/live.ts231
-rw-r--r--server/tests/api/moderation/blocklist.ts60
-rw-r--r--server/tests/api/notifications/comments-notifications.ts25
-rw-r--r--server/tests/api/notifications/moderation-notifications.ts30
-rw-r--r--server/tests/api/notifications/user-notifications.ts10
-rw-r--r--server/tests/api/search/index.ts4
-rw-r--r--server/tests/api/search/search-activitypub-video-channels.ts16
-rw-r--r--server/tests/api/search/search-activitypub-video-playlists.ts212
-rw-r--r--server/tests/api/search/search-activitypub-videos.ts35
-rw-r--r--server/tests/api/search/search-index.ts62
-rw-r--r--server/tests/api/search/search-playlists.ts128
-rw-r--r--server/tests/api/server/bulk.ts9
-rw-r--r--server/tests/api/server/config.ts5
-rw-r--r--server/tests/api/server/contact-form.ts4
-rw-r--r--server/tests/api/server/follow-constraints.ts16
-rw-r--r--server/tests/api/server/follows.ts50
-rw-r--r--server/tests/api/server/handle-down.ts14
-rw-r--r--server/tests/api/server/homepage.ts85
-rw-r--r--server/tests/api/server/index.ts1
-rw-r--r--server/tests/api/server/plugins.ts42
-rw-r--r--server/tests/api/server/services.ts104
-rw-r--r--server/tests/api/users/users-verification.ts5
-rw-r--r--server/tests/api/users/users.ts18
-rw-r--r--server/tests/api/videos/multiple-servers.ts23
-rw-r--r--server/tests/api/videos/resumable-upload.ts4
-rw-r--r--server/tests/api/videos/video-change-ownership.ts108
-rw-r--r--server/tests/api/videos/video-channels.ts18
-rw-r--r--server/tests/api/videos/video-comments.ts5
-rw-r--r--server/tests/api/videos/video-playlists.ts71
-rw-r--r--server/tests/api/videos/video-privacy.ts351
-rw-r--r--server/tests/api/videos/videos-filter.ts4
-rw-r--r--server/tests/api/videos/videos-overview.ts4
-rw-r--r--server/tests/cli/prune-storage.ts34
-rw-r--r--server/tests/client.ts449
-rw-r--r--server/tests/external-plugins/auto-block-videos.ts5
-rw-r--r--server/tests/external-plugins/auto-mute.ts5
-rw-r--r--server/tests/fixtures/ap-json/mastodon/bad-body-http-signature.json (renamed from server/tests/api/activitypub/json/mastodon/bad-body-http-signature.json)0
-rw-r--r--server/tests/fixtures/ap-json/mastodon/bad-http-signature.json (renamed from server/tests/api/activitypub/json/mastodon/bad-http-signature.json)0
-rw-r--r--server/tests/fixtures/ap-json/mastodon/bad-public-key.json (renamed from server/tests/api/activitypub/json/mastodon/bad-public-key.json)0
-rw-r--r--server/tests/fixtures/ap-json/mastodon/create-bad-signature.json (renamed from server/tests/api/activitypub/json/mastodon/create-bad-signature.json)0
-rw-r--r--server/tests/fixtures/ap-json/mastodon/create.json (renamed from server/tests/api/activitypub/json/mastodon/create.json)0
-rw-r--r--server/tests/fixtures/ap-json/mastodon/http-signature.json (renamed from server/tests/api/activitypub/json/mastodon/http-signature.json)0
-rw-r--r--server/tests/fixtures/ap-json/mastodon/public-key.json (renamed from server/tests/api/activitypub/json/mastodon/public-key.json)0
-rw-r--r--server/tests/fixtures/ap-json/peertube/announce-without-context.json (renamed from server/tests/api/activitypub/json/peertube/announce-without-context.json)0
-rw-r--r--server/tests/fixtures/ap-json/peertube/invalid-keys.json (renamed from server/tests/api/activitypub/json/peertube/invalid-keys.json)0
-rw-r--r--server/tests/fixtures/ap-json/peertube/keys.json (renamed from server/tests/api/activitypub/json/peertube/keys.json)0
-rw-r--r--server/tests/fixtures/peertube-plugin-test-broken/main.js12
-rw-r--r--server/tests/fixtures/peertube-plugin-test-broken/package.json (renamed from server/tests/fixtures/peertube-plugin-test-three/package.json)4
-rw-r--r--server/tests/fixtures/peertube-plugin-test-filter-translations/languages/fr.json (renamed from server/tests/fixtures/peertube-plugin-test-two/languages/fr.json)0
-rw-r--r--server/tests/fixtures/peertube-plugin-test-filter-translations/languages/it.json (renamed from server/tests/fixtures/peertube-plugin-test-two/languages/it.json)0
-rw-r--r--server/tests/fixtures/peertube-plugin-test-filter-translations/main.js (renamed from server/tests/fixtures/peertube-plugin-test-two/main.js)0
-rw-r--r--server/tests/fixtures/peertube-plugin-test-filter-translations/package.json (renamed from server/tests/fixtures/peertube-plugin-test-two/package.json)4
-rw-r--r--server/tests/fixtures/peertube-plugin-test-video-constants/main.js (renamed from server/tests/fixtures/peertube-plugin-test-three/main.js)2
-rw-r--r--server/tests/fixtures/peertube-plugin-test-video-constants/package.json20
-rw-r--r--server/tests/fixtures/peertube-plugin-test/main.js8
-rw-r--r--server/tests/plugins/action-hooks.ts40
-rw-r--r--server/tests/plugins/filter-hooks.ts32
-rw-r--r--server/tests/plugins/html-injection.ts2
-rw-r--r--server/tests/plugins/plugin-helpers.ts2
-rw-r--r--server/tests/plugins/translations.ts8
-rw-r--r--server/tests/plugins/video-constants.ts6
-rw-r--r--server/tests/register.ts3
86 files changed, 2367 insertions, 1047 deletions
diff --git a/server/tests/api/activitypub/client.ts b/server/tests/api/activitypub/client.ts
index b6c538e19..be94e219c 100644
--- a/server/tests/api/activitypub/client.ts
+++ b/server/tests/api/activitypub/client.ts
@@ -1,23 +1,65 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
4import * as chai from 'chai'
5import { VideoPlaylistPrivacy } from '@shared/models'
6import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
5import { 7import {
6 cleanupTests, 8 cleanupTests,
9 createVideoPlaylist,
7 doubleFollow, 10 doubleFollow,
8 flushAndRunMultipleServers, 11 flushAndRunMultipleServers,
9 makeActivityPubGetRequest, 12 makeActivityPubGetRequest,
10 ServerInfo, 13 ServerInfo,
11 setAccessTokensToServers, 14 setAccessTokensToServers,
12 uploadVideo 15 setDefaultVideoChannel,
16 uploadVideoAndGetId
13} from '../../../../shared/extra-utils' 17} from '../../../../shared/extra-utils'
14import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
15 18
16const expect = chai.expect 19const expect = chai.expect
17 20
18describe('Test activitypub', function () { 21describe('Test activitypub', function () {
19 let servers: ServerInfo[] = [] 22 let servers: ServerInfo[] = []
20 let videoUUID: string 23 let video: { id: number, uuid: string, shortUUID: string }
24 let playlist: { id: number, uuid: string, shortUUID: string }
25
26 async function testAccount (path: string) {
27 const res = await makeActivityPubGetRequest(servers[0].url, path)
28 const object = res.body
29
30 expect(object.type).to.equal('Person')
31 expect(object.id).to.equal('http://localhost:' + servers[0].port + '/accounts/root')
32 expect(object.name).to.equal('root')
33 expect(object.preferredUsername).to.equal('root')
34 }
35
36 async function testChannel (path: string) {
37 const res = await makeActivityPubGetRequest(servers[0].url, path)
38 const object = res.body
39
40 expect(object.type).to.equal('Group')
41 expect(object.id).to.equal('http://localhost:' + servers[0].port + '/video-channels/root_channel')
42 expect(object.name).to.equal('Main root channel')
43 expect(object.preferredUsername).to.equal('root_channel')
44 }
45
46 async function testVideo (path: string) {
47 const res = await makeActivityPubGetRequest(servers[0].url, path)
48 const object = res.body
49
50 expect(object.type).to.equal('Video')
51 expect(object.id).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + video.uuid)
52 expect(object.name).to.equal('video')
53 }
54
55 async function testPlaylist (path: string) {
56 const res = await makeActivityPubGetRequest(servers[0].url, path)
57 const object = res.body
58
59 expect(object.type).to.equal('Playlist')
60 expect(object.id).to.equal('http://localhost:' + servers[0].port + '/video-playlists/' + playlist.uuid)
61 expect(object.name).to.equal('playlist')
62 }
21 63
22 before(async function () { 64 before(async function () {
23 this.timeout(30000) 65 this.timeout(30000)
@@ -25,38 +67,56 @@ describe('Test activitypub', function () {
25 servers = await flushAndRunMultipleServers(2) 67 servers = await flushAndRunMultipleServers(2)
26 68
27 await setAccessTokensToServers(servers) 69 await setAccessTokensToServers(servers)
70 await setDefaultVideoChannel(servers)
28 71
29 { 72 {
30 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' }) 73 video = await uploadVideoAndGetId({ server: servers[0], videoName: 'video' })
31 videoUUID = res.body.video.uuid 74 }
75
76 {
77 const playlistAttrs = { displayName: 'playlist', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[0].videoChannel.id }
78 const resCreate = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs })
79 playlist = resCreate.body.videoPlaylist
32 } 80 }
33 81
34 await doubleFollow(servers[0], servers[1]) 82 await doubleFollow(servers[0], servers[1])
35 }) 83 })
36 84
37 it('Should return the account object', async function () { 85 it('Should return the account object', async function () {
38 const res = await makeActivityPubGetRequest(servers[0].url, '/accounts/root') 86 await testAccount('/accounts/root')
39 const object = res.body 87 await testAccount('/a/root')
88 })
40 89
41 expect(object.type).to.equal('Person') 90 it('Should return the channel object', async function () {
42 expect(object.id).to.equal('http://localhost:' + servers[0].port + '/accounts/root') 91 await testChannel('/video-channels/root_channel')
43 expect(object.name).to.equal('root') 92 await testChannel('/c/root_channel')
44 expect(object.preferredUsername).to.equal('root')
45 }) 93 })
46 94
47 it('Should return the video object', async function () { 95 it('Should return the video object', async function () {
48 const res = await makeActivityPubGetRequest(servers[0].url, '/videos/watch/' + videoUUID) 96 await testVideo('/videos/watch/' + video.id)
49 const object = res.body 97 await testVideo('/videos/watch/' + video.uuid)
98 await testVideo('/videos/watch/' + video.shortUUID)
99 await testVideo('/w/' + video.id)
100 await testVideo('/w/' + video.uuid)
101 await testVideo('/w/' + video.shortUUID)
102 })
50 103
51 expect(object.type).to.equal('Video') 104 it('Should return the playlist object', async function () {
52 expect(object.id).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + videoUUID) 105 await testPlaylist('/video-playlists/' + playlist.id)
53 expect(object.name).to.equal('video') 106 await testPlaylist('/video-playlists/' + playlist.uuid)
107 await testPlaylist('/video-playlists/' + playlist.shortUUID)
108 await testPlaylist('/w/p/' + playlist.id)
109 await testPlaylist('/w/p/' + playlist.uuid)
110 await testPlaylist('/w/p/' + playlist.shortUUID)
111 await testPlaylist('/videos/watch/playlist/' + playlist.id)
112 await testPlaylist('/videos/watch/playlist/' + playlist.uuid)
113 await testPlaylist('/videos/watch/playlist/' + playlist.shortUUID)
54 }) 114 })
55 115
56 it('Should redirect to the origin video object', async function () { 116 it('Should redirect to the origin video object', async function () {
57 const res = await makeActivityPubGetRequest(servers[1].url, '/videos/watch/' + videoUUID, HttpStatusCode.FOUND_302) 117 const res = await makeActivityPubGetRequest(servers[1].url, '/videos/watch/' + video.uuid, HttpStatusCode.FOUND_302)
58 118
59 expect(res.header.location).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + videoUUID) 119 expect(res.header.location).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + video.uuid)
60 }) 120 })
61 121
62 after(async function () { 122 after(async function () {
diff --git a/server/tests/api/activitypub/helpers.ts b/server/tests/api/activitypub/helpers.ts
index 60d95b823..66d7631b7 100644
--- a/server/tests/api/activitypub/helpers.ts
+++ b/server/tests/api/activitypub/helpers.ts
@@ -6,13 +6,14 @@ import { buildRequestStub } from '../../../../shared/extra-utils/miscs/stubs'
6import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../../../helpers/peertube-crypto' 6import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../../../helpers/peertube-crypto'
7import { cloneDeep } from 'lodash' 7import { cloneDeep } from 'lodash'
8import { buildSignedActivity } from '../../../helpers/activitypub' 8import { buildSignedActivity } from '../../../helpers/activitypub'
9import { buildAbsoluteFixturePath } from '@shared/extra-utils'
9 10
10describe('Test activity pub helpers', function () { 11describe('Test activity pub helpers', function () {
11 describe('When checking the Linked Signature', function () { 12 describe('When checking the Linked Signature', function () {
12 13
13 it('Should fail with an invalid Mastodon signature', async function () { 14 it('Should fail with an invalid Mastodon signature', async function () {
14 const body = require('./json/mastodon/create-bad-signature.json') 15 const body = require(buildAbsoluteFixturePath('./ap-json/mastodon/create-bad-signature.json'))
15 const publicKey = require('./json/mastodon/public-key.json').publicKey 16 const publicKey = require(buildAbsoluteFixturePath('./ap-json/mastodon/public-key.json')).publicKey
16 const fromActor = { publicKey, url: 'http://localhost:9002/accounts/peertube' } 17 const fromActor = { publicKey, url: 'http://localhost:9002/accounts/peertube' }
17 18
18 const result = await isJsonLDSignatureVerified(fromActor as any, body) 19 const result = await isJsonLDSignatureVerified(fromActor as any, body)
@@ -21,8 +22,8 @@ describe('Test activity pub helpers', function () {
21 }) 22 })
22 23
23 it('Should fail with an invalid public key', async function () { 24 it('Should fail with an invalid public key', async function () {
24 const body = require('./json/mastodon/create.json') 25 const body = require(buildAbsoluteFixturePath('./ap-json/mastodon/create.json'))
25 const publicKey = require('./json/mastodon/bad-public-key.json').publicKey 26 const publicKey = require(buildAbsoluteFixturePath('./ap-json/mastodon/bad-public-key.json')).publicKey
26 const fromActor = { publicKey, url: 'http://localhost:9002/accounts/peertube' } 27 const fromActor = { publicKey, url: 'http://localhost:9002/accounts/peertube' }
27 28
28 const result = await isJsonLDSignatureVerified(fromActor as any, body) 29 const result = await isJsonLDSignatureVerified(fromActor as any, body)
@@ -31,8 +32,8 @@ describe('Test activity pub helpers', function () {
31 }) 32 })
32 33
33 it('Should succeed with a valid Mastodon signature', async function () { 34 it('Should succeed with a valid Mastodon signature', async function () {
34 const body = require('./json/mastodon/create.json') 35 const body = require(buildAbsoluteFixturePath('./ap-json/mastodon/create.json'))
35 const publicKey = require('./json/mastodon/public-key.json').publicKey 36 const publicKey = require(buildAbsoluteFixturePath('./ap-json/mastodon/public-key.json')).publicKey
36 const fromActor = { publicKey, url: 'http://localhost:9002/accounts/peertube' } 37 const fromActor = { publicKey, url: 'http://localhost:9002/accounts/peertube' }
37 38
38 const result = await isJsonLDSignatureVerified(fromActor as any, body) 39 const result = await isJsonLDSignatureVerified(fromActor as any, body)
@@ -41,8 +42,8 @@ describe('Test activity pub helpers', function () {
41 }) 42 })
42 43
43 it('Should fail with an invalid PeerTube signature', async function () { 44 it('Should fail with an invalid PeerTube signature', async function () {
44 const keys = require('./json/peertube/invalid-keys.json') 45 const keys = require(buildAbsoluteFixturePath('./ap-json/peertube/invalid-keys.json'))
45 const body = require('./json/peertube/announce-without-context.json') 46 const body = require(buildAbsoluteFixturePath('./ap-json/peertube/announce-without-context.json'))
46 47
47 const actorSignature = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey } 48 const actorSignature = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey }
48 const signedBody = await buildSignedActivity(actorSignature as any, body) 49 const signedBody = await buildSignedActivity(actorSignature as any, body)
@@ -54,8 +55,8 @@ describe('Test activity pub helpers', function () {
54 }) 55 })
55 56
56 it('Should succeed with a valid PeerTube signature', async function () { 57 it('Should succeed with a valid PeerTube signature', async function () {
57 const keys = require('./json/peertube/keys.json') 58 const keys = require(buildAbsoluteFixturePath('./ap-json/peertube/keys.json'))
58 const body = require('./json/peertube/announce-without-context.json') 59 const body = require(buildAbsoluteFixturePath('./ap-json/peertube/announce-without-context.json'))
59 60
60 const actorSignature = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey } 61 const actorSignature = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey }
61 const signedBody = await buildSignedActivity(actorSignature as any, body) 62 const signedBody = await buildSignedActivity(actorSignature as any, body)
@@ -73,12 +74,12 @@ describe('Test activity pub helpers', function () {
73 req.method = 'POST' 74 req.method = 'POST'
74 req.url = '/accounts/ronan/inbox' 75 req.url = '/accounts/ronan/inbox'
75 76
76 const mastodonObject = cloneDeep(require('./json/mastodon/bad-http-signature.json')) 77 const mastodonObject = cloneDeep(require(buildAbsoluteFixturePath('./ap-json/mastodon/bad-http-signature.json')))
77 req.body = mastodonObject.body 78 req.body = mastodonObject.body
78 req.headers = mastodonObject.headers 79 req.headers = mastodonObject.headers
79 80
80 const parsed = parseHTTPSignature(req, 3600 * 1000 * 365 * 10) 81 const parsed = parseHTTPSignature(req, 3600 * 1000 * 365 * 10)
81 const publicKey = require('./json/mastodon/public-key.json').publicKey 82 const publicKey = require(buildAbsoluteFixturePath('./ap-json/mastodon/public-key.json')).publicKey
82 83
83 const actor = { publicKey } 84 const actor = { publicKey }
84 const verified = isHTTPSignatureVerified(parsed, actor as any) 85 const verified = isHTTPSignatureVerified(parsed, actor as any)
@@ -91,12 +92,12 @@ describe('Test activity pub helpers', function () {
91 req.method = 'POST' 92 req.method = 'POST'
92 req.url = '/accounts/ronan/inbox' 93 req.url = '/accounts/ronan/inbox'
93 94
94 const mastodonObject = cloneDeep(require('./json/mastodon/http-signature.json')) 95 const mastodonObject = cloneDeep(require(buildAbsoluteFixturePath('./ap-json/mastodon/http-signature.json')))
95 req.body = mastodonObject.body 96 req.body = mastodonObject.body
96 req.headers = mastodonObject.headers 97 req.headers = mastodonObject.headers
97 98
98 const parsed = parseHTTPSignature(req, 3600 * 1000 * 365 * 10) 99 const parsed = parseHTTPSignature(req, 3600 * 1000 * 365 * 10)
99 const publicKey = require('./json/mastodon/bad-public-key.json').publicKey 100 const publicKey = require(buildAbsoluteFixturePath('./ap-json/mastodon/bad-public-key.json')).publicKey
100 101
101 const actor = { publicKey } 102 const actor = { publicKey }
102 const verified = isHTTPSignatureVerified(parsed, actor as any) 103 const verified = isHTTPSignatureVerified(parsed, actor as any)
@@ -109,7 +110,7 @@ describe('Test activity pub helpers', function () {
109 req.method = 'POST' 110 req.method = 'POST'
110 req.url = '/accounts/ronan/inbox' 111 req.url = '/accounts/ronan/inbox'
111 112
112 const mastodonObject = cloneDeep(require('./json/mastodon/http-signature.json')) 113 const mastodonObject = cloneDeep(require(buildAbsoluteFixturePath('./ap-json/mastodon/http-signature.json')))
113 req.body = mastodonObject.body 114 req.body = mastodonObject.body
114 req.headers = mastodonObject.headers 115 req.headers = mastodonObject.headers
115 116
@@ -128,7 +129,7 @@ describe('Test activity pub helpers', function () {
128 req.method = 'POST' 129 req.method = 'POST'
129 req.url = '/accounts/ronan/inbox' 130 req.url = '/accounts/ronan/inbox'
130 131
131 const mastodonObject = cloneDeep(require('./json/mastodon/http-signature.json')) 132 const mastodonObject = cloneDeep(require(buildAbsoluteFixturePath('./ap-json/mastodon/http-signature.json')))
132 req.body = mastodonObject.body 133 req.body = mastodonObject.body
133 req.headers = mastodonObject.headers 134 req.headers = mastodonObject.headers
134 req.headers = 'Signature ' + mastodonObject.headers 135 req.headers = 'Signature ' + mastodonObject.headers
@@ -148,12 +149,12 @@ describe('Test activity pub helpers', function () {
148 req.method = 'POST' 149 req.method = 'POST'
149 req.url = '/accounts/ronan/inbox' 150 req.url = '/accounts/ronan/inbox'
150 151
151 const mastodonObject = cloneDeep(require('./json/mastodon/http-signature.json')) 152 const mastodonObject = cloneDeep(require(buildAbsoluteFixturePath('./ap-json/mastodon/http-signature.json')))
152 req.body = mastodonObject.body 153 req.body = mastodonObject.body
153 req.headers = mastodonObject.headers 154 req.headers = mastodonObject.headers
154 155
155 const parsed = parseHTTPSignature(req, 3600 * 1000 * 365 * 10) 156 const parsed = parseHTTPSignature(req, 3600 * 1000 * 365 * 10)
156 const publicKey = require('./json/mastodon/public-key.json').publicKey 157 const publicKey = require(buildAbsoluteFixturePath('./ap-json/mastodon/public-key.json')).publicKey
157 158
158 const actor = { publicKey } 159 const actor = { publicKey }
159 const verified = isHTTPSignatureVerified(parsed, actor as any) 160 const verified = isHTTPSignatureVerified(parsed, actor as any)
diff --git a/server/tests/api/activitypub/security.ts b/server/tests/api/activitypub/security.ts
index 364b53e0f..61db272f6 100644
--- a/server/tests/api/activitypub/security.ts
+++ b/server/tests/api/activitypub/security.ts
@@ -5,6 +5,7 @@ import * as chai from 'chai'
5import { buildDigest } from '@server/helpers/peertube-crypto' 5import { buildDigest } from '@server/helpers/peertube-crypto'
6import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 6import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
7import { 7import {
8 buildAbsoluteFixturePath,
8 cleanupTests, 9 cleanupTests,
9 closeAllSequelize, 10 closeAllSequelize,
10 flushAndRunMultipleServers, 11 flushAndRunMultipleServers,
@@ -40,7 +41,7 @@ function setUpdatedAtOfServer (onServer: ServerInfo, ofServer: ServerInfo, updat
40} 41}
41 42
42function getAnnounceWithoutContext (server: ServerInfo) { 43function getAnnounceWithoutContext (server: ServerInfo) {
43 const json = require('./json/peertube/announce-without-context.json') 44 const json = require(buildAbsoluteFixturePath('./ap-json/peertube/announce-without-context.json'))
44 const result: typeof json = {} 45 const result: typeof json = {}
45 46
46 for (const key of Object.keys(json)) { 47 for (const key of Object.keys(json)) {
@@ -58,8 +59,8 @@ describe('Test ActivityPub security', function () {
58 let servers: ServerInfo[] 59 let servers: ServerInfo[]
59 let url: string 60 let url: string
60 61
61 const keys = require('./json/peertube/keys.json') 62 const keys = require(buildAbsoluteFixturePath('./ap-json/peertube/keys.json'))
62 const invalidKeys = require('./json/peertube/invalid-keys.json') 63 const invalidKeys = require(buildAbsoluteFixturePath('./ap-json/peertube/invalid-keys.json'))
63 const baseHttpSignature = () => ({ 64 const baseHttpSignature = () => ({
64 algorithm: HTTP_SIGNATURE.ALGORITHM, 65 algorithm: HTTP_SIGNATURE.ALGORITHM,
65 authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME, 66 authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME,
diff --git a/server/tests/api/check-params/abuses.ts b/server/tests/api/check-params/abuses.ts
index 2aa09334c..2054776cc 100644
--- a/server/tests/api/check-params/abuses.ts
+++ b/server/tests/api/check-params/abuses.ts
@@ -258,7 +258,7 @@ describe('Test abuses API validators', function () {
258 }) 258 })
259 259
260 it('Should succeed with the correct parameters (basic)', async function () { 260 it('Should succeed with the correct parameters (basic)', async function () {
261 const fields: AbuseCreate = { video: { id: server.video.id }, reason: 'my super reason' } 261 const fields: AbuseCreate = { video: { id: server.video.shortUUID }, reason: 'my super reason' }
262 262
263 const res = await makePostBodyRequest({ 263 const res = await makePostBodyRequest({
264 url: server.url, 264 url: server.url,
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts
index 004aa65b3..9549070ef 100644
--- a/server/tests/api/check-params/config.ts
+++ b/server/tests/api/check-params/config.ts
@@ -73,7 +73,8 @@ describe('Test config API validators', function () {
73 signup: { 73 signup: {
74 enabled: false, 74 enabled: false,
75 limit: 5, 75 limit: 5,
76 requiresEmailVerification: false 76 requiresEmailVerification: false,
77 minimumAge: 16
77 }, 78 },
78 admin: { 79 admin: {
79 email: 'superadmin1@example.com' 80 email: 'superadmin1@example.com'
diff --git a/server/tests/api/check-params/custom-pages.ts b/server/tests/api/check-params/custom-pages.ts
new file mode 100644
index 000000000..74ca3384c
--- /dev/null
+++ b/server/tests/api/check-params/custom-pages.ts
@@ -0,0 +1,81 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
5import {
6 cleanupTests,
7 createUser,
8 flushAndRunServer,
9 ServerInfo,
10 setAccessTokensToServers,
11 userLogin
12} from '../../../../shared/extra-utils'
13import { makeGetRequest, makePutBodyRequest } from '../../../../shared/extra-utils/requests/requests'
14
15describe('Test custom pages validators', function () {
16 const path = '/api/v1/custom-pages/homepage/instance'
17
18 let server: ServerInfo
19 let userAccessToken: string
20
21 // ---------------------------------------------------------------
22
23 before(async function () {
24 this.timeout(120000)
25
26 server = await flushAndRunServer(1)
27 await setAccessTokensToServers([ server ])
28
29 const user = { username: 'user1', password: 'password' }
30 await createUser({ url: server.url, accessToken: server.accessToken, username: user.username, password: user.password })
31
32 userAccessToken = await userLogin(server, user)
33 })
34
35 describe('When updating instance homepage', function () {
36
37 it('Should fail with an unauthenticated user', async function () {
38 await makePutBodyRequest({
39 url: server.url,
40 path,
41 fields: { content: 'super content' },
42 statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
43 })
44 })
45
46 it('Should fail with a non admin user', async function () {
47 await makePutBodyRequest({
48 url: server.url,
49 path,
50 token: userAccessToken,
51 fields: { content: 'super content' },
52 statusCodeExpected: HttpStatusCode.FORBIDDEN_403
53 })
54 })
55
56 it('Should succeed with the correct params', async function () {
57 await makePutBodyRequest({
58 url: server.url,
59 path,
60 token: server.accessToken,
61 fields: { content: 'super content' },
62 statusCodeExpected: HttpStatusCode.NO_CONTENT_204
63 })
64 })
65 })
66
67 describe('When getting instance homapage', function () {
68
69 it('Should succeed with the correct params', async function () {
70 await makeGetRequest({
71 url: server.url,
72 path,
73 statusCodeExpected: HttpStatusCode.OK_200
74 })
75 })
76 })
77
78 after(async function () {
79 await cleanupTests([ server ])
80 })
81})
diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts
index 143515838..ce2335e42 100644
--- a/server/tests/api/check-params/index.ts
+++ b/server/tests/api/check-params/index.ts
@@ -3,6 +3,7 @@ import './accounts'
3import './blocklist' 3import './blocklist'
4import './bulk' 4import './bulk'
5import './config' 5import './config'
6import './custom-pages'
6import './contact-form' 7import './contact-form'
7import './debug' 8import './debug'
8import './follows' 9import './follows'
diff --git a/server/tests/api/check-params/live.ts b/server/tests/api/check-params/live.ts
index c171b1f81..933d8abf2 100644
--- a/server/tests/api/check-params/live.ts
+++ b/server/tests/api/check-params/live.ts
@@ -2,9 +2,10 @@
2 2
3import 'mocha' 3import 'mocha'
4import { omit } from 'lodash' 4import { omit } from 'lodash'
5import { join } from 'path' 5import { LiveVideo, VideoCreateResult, VideoPrivacy } from '@shared/models'
6import { LiveVideo, VideoPrivacy } from '@shared/models' 6import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
7import { 7import {
8 buildAbsoluteFixturePath,
8 cleanupTests, 9 cleanupTests,
9 createUser, 10 createUser,
10 flushAndRunServer, 11 flushAndRunServer,
@@ -24,14 +25,13 @@ import {
24 userLogin, 25 userLogin,
25 waitUntilLivePublished 26 waitUntilLivePublished
26} from '../../../../shared/extra-utils' 27} from '../../../../shared/extra-utils'
27import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
28 28
29describe('Test video lives API validator', function () { 29describe('Test video lives API validator', function () {
30 const path = '/api/v1/videos/live' 30 const path = '/api/v1/videos/live'
31 let server: ServerInfo 31 let server: ServerInfo
32 let userAccessToken = '' 32 let userAccessToken = ''
33 let channelId: number 33 let channelId: number
34 let videoId: number 34 let video: VideoCreateResult
35 let videoIdNotLive: number 35 let videoIdNotLive: number
36 36
37 // --------------------------------------------------------------- 37 // ---------------------------------------------------------------
@@ -180,7 +180,7 @@ describe('Test video lives API validator', function () {
180 it('Should fail with an incorrect thumbnail file', async function () { 180 it('Should fail with an incorrect thumbnail file', async function () {
181 const fields = baseCorrectParams 181 const fields = baseCorrectParams
182 const attaches = { 182 const attaches = {
183 thumbnailfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') 183 thumbnailfile: buildAbsoluteFixturePath('video_short.mp4')
184 } 184 }
185 185
186 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 186 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -189,7 +189,7 @@ describe('Test video lives API validator', function () {
189 it('Should fail with a big thumbnail file', async function () { 189 it('Should fail with a big thumbnail file', async function () {
190 const fields = baseCorrectParams 190 const fields = baseCorrectParams
191 const attaches = { 191 const attaches = {
192 thumbnailfile: join(__dirname, '..', '..', 'fixtures', 'preview-big.png') 192 thumbnailfile: buildAbsoluteFixturePath('preview-big.png')
193 } 193 }
194 194
195 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 195 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -198,7 +198,7 @@ describe('Test video lives API validator', function () {
198 it('Should fail with an incorrect preview file', async function () { 198 it('Should fail with an incorrect preview file', async function () {
199 const fields = baseCorrectParams 199 const fields = baseCorrectParams
200 const attaches = { 200 const attaches = {
201 previewfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') 201 previewfile: buildAbsoluteFixturePath('video_short.mp4')
202 } 202 }
203 203
204 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 204 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -207,7 +207,7 @@ describe('Test video lives API validator', function () {
207 it('Should fail with a big preview file', async function () { 207 it('Should fail with a big preview file', async function () {
208 const fields = baseCorrectParams 208 const fields = baseCorrectParams
209 const attaches = { 209 const attaches = {
210 previewfile: join(__dirname, '..', '..', 'fixtures', 'preview-big.png') 210 previewfile: buildAbsoluteFixturePath('preview-big.png')
211 } 211 }
212 212
213 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 213 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -230,7 +230,7 @@ describe('Test video lives API validator', function () {
230 statusCodeExpected: HttpStatusCode.OK_200 230 statusCodeExpected: HttpStatusCode.OK_200
231 }) 231 })
232 232
233 videoId = res.body.video.id 233 video = res.body.video
234 }) 234 })
235 235
236 it('Should forbid if live is disabled', async function () { 236 it('Should forbid if live is disabled', async function () {
@@ -326,15 +326,15 @@ describe('Test video lives API validator', function () {
326 describe('When getting live information', function () { 326 describe('When getting live information', function () {
327 327
328 it('Should fail without access token', async function () { 328 it('Should fail without access token', async function () {
329 await getLive(server.url, '', videoId, HttpStatusCode.UNAUTHORIZED_401) 329 await getLive(server.url, '', video.id, HttpStatusCode.UNAUTHORIZED_401)
330 }) 330 })
331 331
332 it('Should fail with a bad access token', async function () { 332 it('Should fail with a bad access token', async function () {
333 await getLive(server.url, 'toto', videoId, HttpStatusCode.UNAUTHORIZED_401) 333 await getLive(server.url, 'toto', video.id, HttpStatusCode.UNAUTHORIZED_401)
334 }) 334 })
335 335
336 it('Should fail with access token of another user', async function () { 336 it('Should fail with access token of another user', async function () {
337 await getLive(server.url, userAccessToken, videoId, HttpStatusCode.FORBIDDEN_403) 337 await getLive(server.url, userAccessToken, video.id, HttpStatusCode.FORBIDDEN_403)
338 }) 338 })
339 339
340 it('Should fail with a bad video id', async function () { 340 it('Should fail with a bad video id', async function () {
@@ -350,22 +350,23 @@ describe('Test video lives API validator', function () {
350 }) 350 })
351 351
352 it('Should succeed with the correct params', async function () { 352 it('Should succeed with the correct params', async function () {
353 await getLive(server.url, server.accessToken, videoId) 353 await getLive(server.url, server.accessToken, video.id)
354 await getLive(server.url, server.accessToken, video.shortUUID)
354 }) 355 })
355 }) 356 })
356 357
357 describe('When updating live information', async function () { 358 describe('When updating live information', async function () {
358 359
359 it('Should fail without access token', async function () { 360 it('Should fail without access token', async function () {
360 await updateLive(server.url, '', videoId, {}, HttpStatusCode.UNAUTHORIZED_401) 361 await updateLive(server.url, '', video.id, {}, HttpStatusCode.UNAUTHORIZED_401)
361 }) 362 })
362 363
363 it('Should fail with a bad access token', async function () { 364 it('Should fail with a bad access token', async function () {
364 await updateLive(server.url, 'toto', videoId, {}, HttpStatusCode.UNAUTHORIZED_401) 365 await updateLive(server.url, 'toto', video.id, {}, HttpStatusCode.UNAUTHORIZED_401)
365 }) 366 })
366 367
367 it('Should fail with access token of another user', async function () { 368 it('Should fail with access token of another user', async function () {
368 await updateLive(server.url, userAccessToken, videoId, {}, HttpStatusCode.FORBIDDEN_403) 369 await updateLive(server.url, userAccessToken, video.id, {}, HttpStatusCode.FORBIDDEN_403)
369 }) 370 })
370 371
371 it('Should fail with a bad video id', async function () { 372 it('Should fail with a bad video id', async function () {
@@ -383,11 +384,12 @@ describe('Test video lives API validator', function () {
383 it('Should fail with save replay and permanent live set to true', async function () { 384 it('Should fail with save replay and permanent live set to true', async function () {
384 const fields = { saveReplay: true, permanentLive: true } 385 const fields = { saveReplay: true, permanentLive: true }
385 386
386 await updateLive(server.url, server.accessToken, videoId, fields, HttpStatusCode.BAD_REQUEST_400) 387 await updateLive(server.url, server.accessToken, video.id, fields, HttpStatusCode.BAD_REQUEST_400)
387 }) 388 })
388 389
389 it('Should succeed with the correct params', async function () { 390 it('Should succeed with the correct params', async function () {
390 await updateLive(server.url, server.accessToken, videoId, { saveReplay: false }) 391 await updateLive(server.url, server.accessToken, video.id, { saveReplay: false })
392 await updateLive(server.url, server.accessToken, video.shortUUID, { saveReplay: false })
391 }) 393 })
392 394
393 it('Should fail to update replay status if replay is not allowed on the instance', async function () { 395 it('Should fail to update replay status if replay is not allowed on the instance', async function () {
@@ -398,19 +400,19 @@ describe('Test video lives API validator', function () {
398 } 400 }
399 }) 401 })
400 402
401 await updateLive(server.url, server.accessToken, videoId, { saveReplay: true }, HttpStatusCode.FORBIDDEN_403) 403 await updateLive(server.url, server.accessToken, video.id, { saveReplay: true }, HttpStatusCode.FORBIDDEN_403)
402 }) 404 })
403 405
404 it('Should fail to update a live if it has already started', async function () { 406 it('Should fail to update a live if it has already started', async function () {
405 this.timeout(40000) 407 this.timeout(40000)
406 408
407 const resLive = await getLive(server.url, server.accessToken, videoId) 409 const resLive = await getLive(server.url, server.accessToken, video.id)
408 const live: LiveVideo = resLive.body 410 const live: LiveVideo = resLive.body
409 411
410 const command = sendRTMPStream(live.rtmpUrl, live.streamKey) 412 const command = sendRTMPStream(live.rtmpUrl, live.streamKey)
411 413
412 await waitUntilLivePublished(server.url, server.accessToken, videoId) 414 await waitUntilLivePublished(server.url, server.accessToken, video.id)
413 await updateLive(server.url, server.accessToken, videoId, {}, HttpStatusCode.BAD_REQUEST_400) 415 await updateLive(server.url, server.accessToken, video.id, {}, HttpStatusCode.BAD_REQUEST_400)
414 416
415 await stopFfmpeg(command) 417 await stopFfmpeg(command)
416 }) 418 })
@@ -418,14 +420,14 @@ describe('Test video lives API validator', function () {
418 it('Should fail to stream twice in the save live', async function () { 420 it('Should fail to stream twice in the save live', async function () {
419 this.timeout(40000) 421 this.timeout(40000)
420 422
421 const resLive = await getLive(server.url, server.accessToken, videoId) 423 const resLive = await getLive(server.url, server.accessToken, video.id)
422 const live: LiveVideo = resLive.body 424 const live: LiveVideo = resLive.body
423 425
424 const command = sendRTMPStream(live.rtmpUrl, live.streamKey) 426 const command = sendRTMPStream(live.rtmpUrl, live.streamKey)
425 427
426 await waitUntilLivePublished(server.url, server.accessToken, videoId) 428 await waitUntilLivePublished(server.url, server.accessToken, video.id)
427 429
428 await runAndTestFfmpegStreamError(server.url, server.accessToken, videoId, true) 430 await runAndTestFfmpegStreamError(server.url, server.accessToken, video.id, true)
429 431
430 await stopFfmpeg(command) 432 await stopFfmpeg(command)
431 }) 433 })
diff --git a/server/tests/api/check-params/plugins.ts b/server/tests/api/check-params/plugins.ts
index 6e540bcbb..a833fe6ff 100644
--- a/server/tests/api/check-params/plugins.ts
+++ b/server/tests/api/check-params/plugins.ts
@@ -1,7 +1,7 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4import { HttpStatusCode } from '@shared/core-utils'
5import { 5import {
6 checkBadCountPagination, 6 checkBadCountPagination,
7 checkBadSortPagination, 7 checkBadSortPagination,
@@ -11,14 +11,14 @@ import {
11 flushAndRunServer, 11 flushAndRunServer,
12 immutableAssign, 12 immutableAssign,
13 installPlugin, 13 installPlugin,
14 makeGetRequest, makePostBodyRequest, makePutBodyRequest, 14 makeGetRequest,
15 makePostBodyRequest,
16 makePutBodyRequest,
15 ServerInfo, 17 ServerInfo,
16 setAccessTokensToServers, 18 setAccessTokensToServers,
17 userLogin 19 userLogin
18} from '../../../../shared/extra-utils' 20} from '@shared/extra-utils'
19import { PluginType } from '../../../../shared/models/plugins/plugin.type' 21import { PeerTubePlugin, PluginType } from '@shared/models'
20import { PeerTubePlugin } from '../../../../shared/models/plugins/peertube-plugin.model'
21import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
22 22
23describe('Test server plugins API validators', function () { 23describe('Test server plugins API validators', function () {
24 let server: ServerInfo 24 let server: ServerInfo
diff --git a/server/tests/api/check-params/redundancy.ts b/server/tests/api/check-params/redundancy.ts
index 71be50a6f..dac6938de 100644
--- a/server/tests/api/check-params/redundancy.ts
+++ b/server/tests/api/check-params/redundancy.ts
@@ -1,7 +1,8 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4 4import { VideoCreateResult } from '@shared/models'
5import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
5import { 6import {
6 checkBadCountPagination, 7 checkBadCountPagination,
7 checkBadSortPagination, 8 checkBadSortPagination,
@@ -9,20 +10,24 @@ import {
9 cleanupTests, 10 cleanupTests,
10 createUser, 11 createUser,
11 doubleFollow, 12 doubleFollow,
12 flushAndRunMultipleServers, makeDeleteRequest, 13 flushAndRunMultipleServers,
13 makeGetRequest, makePostBodyRequest, 14 getVideo,
15 makeDeleteRequest,
16 makeGetRequest,
17 makePostBodyRequest,
14 makePutBodyRequest, 18 makePutBodyRequest,
15 ServerInfo, 19 ServerInfo,
16 setAccessTokensToServers, uploadVideoAndGetId, 20 setAccessTokensToServers,
17 userLogin, waitJobs, getVideoIdFromUUID 21 uploadVideoAndGetId,
22 userLogin,
23 waitJobs
18} from '../../../../shared/extra-utils' 24} from '../../../../shared/extra-utils'
19import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
20 25
21describe('Test server redundancy API validators', function () { 26describe('Test server redundancy API validators', function () {
22 let servers: ServerInfo[] 27 let servers: ServerInfo[]
23 let userAccessToken = null 28 let userAccessToken = null
24 let videoIdLocal: number 29 let videoIdLocal: number
25 let videoIdRemote: number 30 let videoRemote: VideoCreateResult
26 31
27 // --------------------------------------------------------------- 32 // ---------------------------------------------------------------
28 33
@@ -48,7 +53,8 @@ describe('Test server redundancy API validators', function () {
48 53
49 await waitJobs(servers) 54 await waitJobs(servers)
50 55
51 videoIdRemote = await getVideoIdFromUUID(servers[0].url, remoteUUID) 56 const resVideo = await getVideo(servers[0].url, remoteUUID)
57 videoRemote = resVideo.body
52 }) 58 })
53 59
54 describe('When listing redundancies', function () { 60 describe('When listing redundancies', function () {
@@ -131,7 +137,13 @@ describe('Test server redundancy API validators', function () {
131 }) 137 })
132 138
133 it('Should succeed with the correct params', async function () { 139 it('Should succeed with the correct params', async function () {
134 await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdRemote }, statusCodeExpected: HttpStatusCode.NO_CONTENT_204 }) 140 await makePostBodyRequest({
141 url,
142 path,
143 token,
144 fields: { videoId: videoRemote.shortUUID },
145 statusCodeExpected: HttpStatusCode.NO_CONTENT_204
146 })
135 }) 147 })
136 148
137 it('Should fail if the video is already duplicated', async function () { 149 it('Should fail if the video is already duplicated', async function () {
@@ -139,7 +151,13 @@ describe('Test server redundancy API validators', function () {
139 151
140 await waitJobs(servers) 152 await waitJobs(servers)
141 153
142 await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdRemote }, statusCodeExpected: HttpStatusCode.CONFLICT_409 }) 154 await makePostBodyRequest({
155 url,
156 path,
157 token,
158 fields: { videoId: videoRemote.uuid },
159 statusCodeExpected: HttpStatusCode.CONFLICT_409
160 })
143 }) 161 })
144 }) 162 })
145 163
diff --git a/server/tests/api/check-params/search.ts b/server/tests/api/check-params/search.ts
index 8378c3a89..20ad46cff 100644
--- a/server/tests/api/check-params/search.ts
+++ b/server/tests/api/check-params/search.ts
@@ -140,6 +140,30 @@ describe('Test videos API validator', function () {
140 }) 140 })
141 }) 141 })
142 142
143 describe('When searching video playlists', function () {
144 const path = '/api/v1/search/video-playlists/'
145
146 const query = {
147 search: 'coucou'
148 }
149
150 it('Should fail with a bad start pagination', async function () {
151 await checkBadStartPagination(server.url, path, null, query)
152 })
153
154 it('Should fail with a bad count pagination', async function () {
155 await checkBadCountPagination(server.url, path, null, query)
156 })
157
158 it('Should fail with an incorrect sort', async function () {
159 await checkBadSortPagination(server.url, path, null, query)
160 })
161
162 it('Should success with the correct parameters', async function () {
163 await makeGetRequest({ url: server.url, path, query, statusCodeExpected: HttpStatusCode.OK_200 })
164 })
165 })
166
143 describe('When searching video channels', function () { 167 describe('When searching video channels', function () {
144 const path = '/api/v1/search/video-channels/' 168 const path = '/api/v1/search/video-channels/'
145 169
@@ -171,6 +195,7 @@ describe('Test videos API validator', function () {
171 195
172 const query = { search: 'coucou' } 196 const query = { search: 'coucou' }
173 const paths = [ 197 const paths = [
198 '/api/v1/search/video-playlists/',
174 '/api/v1/search/video-channels/', 199 '/api/v1/search/video-channels/',
175 '/api/v1/search/videos/' 200 '/api/v1/search/videos/'
176 ] 201 ]
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts
index dcff0d52b..70a872ce5 100644
--- a/server/tests/api/check-params/users.ts
+++ b/server/tests/api/check-params/users.ts
@@ -2,12 +2,12 @@
2 2
3import 'mocha' 3import 'mocha'
4import { omit } from 'lodash' 4import { omit } from 'lodash'
5import { join } from 'path' 5import { User, UserRole, VideoCreateResult } from '../../../../shared'
6import { User, UserRole } from '../../../../shared'
7import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 6import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
8import { 7import {
9 addVideoChannel, 8 addVideoChannel,
10 blockUser, 9 blockUser,
10 buildAbsoluteFixturePath,
11 cleanupTests, 11 cleanupTests,
12 createUser, 12 createUser,
13 deleteMe, 13 deleteMe,
@@ -45,7 +45,7 @@ describe('Test users API validators', function () {
45 let userId: number 45 let userId: number
46 let rootId: number 46 let rootId: number
47 let moderatorId: number 47 let moderatorId: number
48 let videoId: number 48 let video: VideoCreateResult
49 let server: ServerInfo 49 let server: ServerInfo
50 let serverWithRegistrationDisabled: ServerInfo 50 let serverWithRegistrationDisabled: ServerInfo
51 let userAccessToken = '' 51 let userAccessToken = ''
@@ -126,7 +126,7 @@ describe('Test users API validators', function () {
126 126
127 { 127 {
128 const res = await uploadVideo(server.url, server.accessToken, {}) 128 const res = await uploadVideo(server.url, server.accessToken, {})
129 videoId = res.body.video.id 129 video = res.body.video
130 } 130 }
131 131
132 { 132 {
@@ -600,7 +600,7 @@ describe('Test users API validators', function () {
600 it('Should fail without an incorrect input file', async function () { 600 it('Should fail without an incorrect input file', async function () {
601 const fields = {} 601 const fields = {}
602 const attaches = { 602 const attaches = {
603 avatarfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') 603 avatarfile: buildAbsoluteFixturePath('video_short.mp4')
604 } 604 }
605 await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) 605 await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
606 }) 606 })
@@ -608,7 +608,7 @@ describe('Test users API validators', function () {
608 it('Should fail with a big file', async function () { 608 it('Should fail with a big file', async function () {
609 const fields = {} 609 const fields = {}
610 const attaches = { 610 const attaches = {
611 avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') 611 avatarfile: buildAbsoluteFixturePath('avatar-big.png')
612 } 612 }
613 await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) 613 await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
614 }) 614 })
@@ -616,7 +616,7 @@ describe('Test users API validators', function () {
616 it('Should fail with an unauthenticated user', async function () { 616 it('Should fail with an unauthenticated user', async function () {
617 const fields = {} 617 const fields = {}
618 const attaches = { 618 const attaches = {
619 avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') 619 avatarfile: buildAbsoluteFixturePath('avatar.png')
620 } 620 }
621 await makeUploadRequest({ 621 await makeUploadRequest({
622 url: server.url, 622 url: server.url,
@@ -630,7 +630,7 @@ describe('Test users API validators', function () {
630 it('Should succeed with the correct params', async function () { 630 it('Should succeed with the correct params', async function () {
631 const fields = {} 631 const fields = {}
632 const attaches = { 632 const attaches = {
633 avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') 633 avatarfile: buildAbsoluteFixturePath('avatar.png')
634 } 634 }
635 await makeUploadRequest({ 635 await makeUploadRequest({
636 url: server.url, 636 url: server.url,
@@ -829,7 +829,7 @@ describe('Test users API validators', function () {
829 829
830 describe('When getting my video rating', function () { 830 describe('When getting my video rating', function () {
831 it('Should fail with a non authenticated user', async function () { 831 it('Should fail with a non authenticated user', async function () {
832 await getMyUserVideoRating(server.url, 'fake_token', videoId, HttpStatusCode.UNAUTHORIZED_401) 832 await getMyUserVideoRating(server.url, 'fake_token', video.id, HttpStatusCode.UNAUTHORIZED_401)
833 }) 833 })
834 834
835 it('Should fail with an incorrect video uuid', async function () { 835 it('Should fail with an incorrect video uuid', async function () {
@@ -841,7 +841,9 @@ describe('Test users API validators', function () {
841 }) 841 })
842 842
843 it('Should succeed with the correct parameters', async function () { 843 it('Should succeed with the correct parameters', async function () {
844 await getMyUserVideoRating(server.url, server.accessToken, videoId) 844 await getMyUserVideoRating(server.url, server.accessToken, video.id)
845 await getMyUserVideoRating(server.url, server.accessToken, video.uuid)
846 await getMyUserVideoRating(server.url, server.accessToken, video.shortUUID)
845 }) 847 })
846 }) 848 })
847 849
diff --git a/server/tests/api/check-params/video-blacklist.ts b/server/tests/api/check-params/video-blacklist.ts
index 3d4837d58..ce7f5fa17 100644
--- a/server/tests/api/check-params/video-blacklist.ts
+++ b/server/tests/api/check-params/video-blacklist.ts
@@ -191,7 +191,7 @@ describe('Test video blacklist API validators', function () {
191 }) 191 })
192 192
193 it('Should succeed with the correct params', async function () { 193 it('Should succeed with the correct params', async function () {
194 const path = basePath + servers[0].video.uuid + '/blacklist' 194 const path = basePath + servers[0].video.shortUUID + '/blacklist'
195 const fields = { reason: 'hello' } 195 const fields = { reason: 'hello' }
196 196
197 await makePutBodyRequest({ 197 await makePutBodyRequest({
@@ -222,10 +222,14 @@ describe('Test video blacklist API validators', function () {
222 }) 222 })
223 223
224 it('Should succeed with an admin', async function () { 224 it('Should succeed with an admin', async function () {
225 const res = await getVideoWithToken(servers[0].url, servers[0].accessToken, servers[0].video.uuid, HttpStatusCode.OK_200) 225 const video = servers[0].video
226 const video: VideoDetails = res.body
227 226
228 expect(video.blacklisted).to.be.true 227 for (const id of [ video.id, video.uuid, video.shortUUID ]) {
228 const res = await getVideoWithToken(servers[0].url, servers[0].accessToken, id, HttpStatusCode.OK_200)
229 const video: VideoDetails = res.body
230
231 expect(video.blacklisted).to.be.true
232 }
229 }) 233 })
230 }) 234 })
231 235
diff --git a/server/tests/api/check-params/video-captions.ts b/server/tests/api/check-params/video-captions.ts
index 2f049c03d..c0595c04d 100644
--- a/server/tests/api/check-params/video-captions.ts
+++ b/server/tests/api/check-params/video-captions.ts
@@ -1,7 +1,10 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { VideoCreateResult } from '@shared/models'
5import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
4import { 6import {
7 buildAbsoluteFixturePath,
5 cleanupTests, 8 cleanupTests,
6 createUser, 9 createUser,
7 flushAndRunServer, 10 flushAndRunServer,
@@ -13,16 +16,14 @@ import {
13 uploadVideo, 16 uploadVideo,
14 userLogin 17 userLogin
15} from '../../../../shared/extra-utils' 18} from '../../../../shared/extra-utils'
16import { join } from 'path'
17import { createVideoCaption } from '../../../../shared/extra-utils/videos/video-captions' 19import { createVideoCaption } from '../../../../shared/extra-utils/videos/video-captions'
18import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
19 20
20describe('Test video captions API validator', function () { 21describe('Test video captions API validator', function () {
21 const path = '/api/v1/videos/' 22 const path = '/api/v1/videos/'
22 23
23 let server: ServerInfo 24 let server: ServerInfo
24 let userAccessToken: string 25 let userAccessToken: string
25 let videoUUID: string 26 let video: VideoCreateResult
26 27
27 // --------------------------------------------------------------- 28 // ---------------------------------------------------------------
28 29
@@ -35,7 +36,7 @@ describe('Test video captions API validator', function () {
35 36
36 { 37 {
37 const res = await uploadVideo(server.url, server.accessToken, {}) 38 const res = await uploadVideo(server.url, server.accessToken, {})
38 videoUUID = res.body.video.uuid 39 video = res.body.video
39 } 40 }
40 41
41 { 42 {
@@ -51,7 +52,7 @@ describe('Test video captions API validator', function () {
51 describe('When adding video caption', function () { 52 describe('When adding video caption', function () {
52 const fields = { } 53 const fields = { }
53 const attaches = { 54 const attaches = {
54 captionfile: join(__dirname, '..', '..', 'fixtures', 'subtitle-good1.vtt') 55 captionfile: buildAbsoluteFixturePath('subtitle-good1.vtt')
55 } 56 }
56 57
57 it('Should fail without a valid uuid', async function () { 58 it('Should fail without a valid uuid', async function () {
@@ -78,7 +79,7 @@ describe('Test video captions API validator', function () {
78 }) 79 })
79 80
80 it('Should fail with a missing language in path', async function () { 81 it('Should fail with a missing language in path', async function () {
81 const captionPath = path + videoUUID + '/captions' 82 const captionPath = path + video.uuid + '/captions'
82 await makeUploadRequest({ 83 await makeUploadRequest({
83 method: 'PUT', 84 method: 'PUT',
84 url: server.url, 85 url: server.url,
@@ -90,7 +91,7 @@ describe('Test video captions API validator', function () {
90 }) 91 })
91 92
92 it('Should fail with an unknown language', async function () { 93 it('Should fail with an unknown language', async function () {
93 const captionPath = path + videoUUID + '/captions/15' 94 const captionPath = path + video.uuid + '/captions/15'
94 await makeUploadRequest({ 95 await makeUploadRequest({
95 method: 'PUT', 96 method: 'PUT',
96 url: server.url, 97 url: server.url,
@@ -102,7 +103,7 @@ describe('Test video captions API validator', function () {
102 }) 103 })
103 104
104 it('Should fail without access token', async function () { 105 it('Should fail without access token', async function () {
105 const captionPath = path + videoUUID + '/captions/fr' 106 const captionPath = path + video.uuid + '/captions/fr'
106 await makeUploadRequest({ 107 await makeUploadRequest({
107 method: 'PUT', 108 method: 'PUT',
108 url: server.url, 109 url: server.url,
@@ -114,7 +115,7 @@ describe('Test video captions API validator', function () {
114 }) 115 })
115 116
116 it('Should fail with a bad access token', async function () { 117 it('Should fail with a bad access token', async function () {
117 const captionPath = path + videoUUID + '/captions/fr' 118 const captionPath = path + video.uuid + '/captions/fr'
118 await makeUploadRequest({ 119 await makeUploadRequest({
119 method: 'PUT', 120 method: 'PUT',
120 url: server.url, 121 url: server.url,
@@ -129,10 +130,10 @@ describe('Test video captions API validator', function () {
129 // We accept any file now 130 // We accept any file now
130 // it('Should fail with an invalid captionfile extension', async function () { 131 // it('Should fail with an invalid captionfile extension', async function () {
131 // const attaches = { 132 // const attaches = {
132 // 'captionfile': join(__dirname, '..', '..', 'fixtures', 'subtitle-bad.txt') 133 // 'captionfile': buildAbsoluteFixturePath('subtitle-bad.txt')
133 // } 134 // }
134 // 135 //
135 // const captionPath = path + videoUUID + '/captions/fr' 136 // const captionPath = path + video.uuid + '/captions/fr'
136 // await makeUploadRequest({ 137 // await makeUploadRequest({
137 // method: 'PUT', 138 // method: 'PUT',
138 // url: server.url, 139 // url: server.url,
@@ -150,7 +151,7 @@ describe('Test video captions API validator', function () {
150 // url: server.url, 151 // url: server.url,
151 // accessToken: server.accessToken, 152 // accessToken: server.accessToken,
152 // language: 'zh', 153 // language: 'zh',
153 // videoId: videoUUID, 154 // videoId: video.uuid,
154 // fixture: 'subtitle-bad.txt', 155 // fixture: 'subtitle-bad.txt',
155 // mimeType: 'application/octet-stream', 156 // mimeType: 'application/octet-stream',
156 // statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 157 // statusCodeExpected: HttpStatusCode.BAD_REQUEST_400
@@ -162,7 +163,7 @@ describe('Test video captions API validator', function () {
162 url: server.url, 163 url: server.url,
163 accessToken: server.accessToken, 164 accessToken: server.accessToken,
164 language: 'zh', 165 language: 'zh',
165 videoId: videoUUID, 166 videoId: video.uuid,
166 fixture: 'subtitle-good.srt', 167 fixture: 'subtitle-good.srt',
167 mimeType: 'application/octet-stream' 168 mimeType: 'application/octet-stream'
168 }) 169 })
@@ -171,10 +172,10 @@ describe('Test video captions API validator', function () {
171 // We don't check the file validity yet 172 // We don't check the file validity yet
172 // it('Should fail with an invalid captionfile srt', async function () { 173 // it('Should fail with an invalid captionfile srt', async function () {
173 // const attaches = { 174 // const attaches = {
174 // 'captionfile': join(__dirname, '..', '..', 'fixtures', 'subtitle-bad.srt') 175 // 'captionfile': buildAbsoluteFixturePath('subtitle-bad.srt')
175 // } 176 // }
176 // 177 //
177 // const captionPath = path + videoUUID + '/captions/fr' 178 // const captionPath = path + video.uuid + '/captions/fr'
178 // await makeUploadRequest({ 179 // await makeUploadRequest({
179 // method: 'PUT', 180 // method: 'PUT',
180 // url: server.url, 181 // url: server.url,
@@ -187,7 +188,7 @@ describe('Test video captions API validator', function () {
187 // }) 188 // })
188 189
189 it('Should success with the correct parameters', async function () { 190 it('Should success with the correct parameters', async function () {
190 const captionPath = path + videoUUID + '/captions/fr' 191 const captionPath = path + video.uuid + '/captions/fr'
191 await makeUploadRequest({ 192 await makeUploadRequest({
192 method: 'PUT', 193 method: 'PUT',
193 url: server.url, 194 url: server.url,
@@ -214,7 +215,7 @@ describe('Test video captions API validator', function () {
214 }) 215 })
215 216
216 it('Should success with the correct parameters', async function () { 217 it('Should success with the correct parameters', async function () {
217 await makeGetRequest({ url: server.url, path: path + videoUUID + '/captions', statusCodeExpected: HttpStatusCode.OK_200 }) 218 await makeGetRequest({ url: server.url, path: path + video.shortUUID + '/captions', statusCodeExpected: HttpStatusCode.OK_200 })
218 }) 219 })
219 }) 220 })
220 221
@@ -245,27 +246,27 @@ describe('Test video captions API validator', function () {
245 }) 246 })
246 247
247 it('Should fail with a missing language', async function () { 248 it('Should fail with a missing language', async function () {
248 const captionPath = path + videoUUID + '/captions' 249 const captionPath = path + video.shortUUID + '/captions'
249 await makeDeleteRequest({ url: server.url, path: captionPath, token: server.accessToken }) 250 await makeDeleteRequest({ url: server.url, path: captionPath, token: server.accessToken })
250 }) 251 })
251 252
252 it('Should fail with an unknown language', async function () { 253 it('Should fail with an unknown language', async function () {
253 const captionPath = path + videoUUID + '/captions/15' 254 const captionPath = path + video.shortUUID + '/captions/15'
254 await makeDeleteRequest({ url: server.url, path: captionPath, token: server.accessToken }) 255 await makeDeleteRequest({ url: server.url, path: captionPath, token: server.accessToken })
255 }) 256 })
256 257
257 it('Should fail without access token', async function () { 258 it('Should fail without access token', async function () {
258 const captionPath = path + videoUUID + '/captions/fr' 259 const captionPath = path + video.shortUUID + '/captions/fr'
259 await makeDeleteRequest({ url: server.url, path: captionPath, statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401 }) 260 await makeDeleteRequest({ url: server.url, path: captionPath, statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401 })
260 }) 261 })
261 262
262 it('Should fail with a bad access token', async function () { 263 it('Should fail with a bad access token', async function () {
263 const captionPath = path + videoUUID + '/captions/fr' 264 const captionPath = path + video.shortUUID + '/captions/fr'
264 await makeDeleteRequest({ url: server.url, path: captionPath, token: 'coucou', statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401 }) 265 await makeDeleteRequest({ url: server.url, path: captionPath, token: 'coucou', statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401 })
265 }) 266 })
266 267
267 it('Should fail with another user', async function () { 268 it('Should fail with another user', async function () {
268 const captionPath = path + videoUUID + '/captions/fr' 269 const captionPath = path + video.shortUUID + '/captions/fr'
269 await makeDeleteRequest({ 270 await makeDeleteRequest({
270 url: server.url, 271 url: server.url,
271 path: captionPath, 272 path: captionPath,
@@ -275,7 +276,7 @@ describe('Test video captions API validator', function () {
275 }) 276 })
276 277
277 it('Should success with the correct parameters', async function () { 278 it('Should success with the correct parameters', async function () {
278 const captionPath = path + videoUUID + '/captions/fr' 279 const captionPath = path + video.shortUUID + '/captions/fr'
279 await makeDeleteRequest({ 280 await makeDeleteRequest({
280 url: server.url, 281 url: server.url,
281 path: captionPath, 282 path: captionPath,
diff --git a/server/tests/api/check-params/video-channels.ts b/server/tests/api/check-params/video-channels.ts
index bc2e6192e..5c02afd31 100644
--- a/server/tests/api/check-params/video-channels.ts
+++ b/server/tests/api/check-params/video-channels.ts
@@ -1,9 +1,11 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha'
3import * as chai from 'chai' 4import * as chai from 'chai'
4import { omit } from 'lodash' 5import { omit } from 'lodash'
5import 'mocha' 6import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
6import { 7import {
8 buildAbsoluteFixturePath,
7 cleanupTests, 9 cleanupTests,
8 createUser, 10 createUser,
9 deleteVideoChannel, 11 deleteVideoChannel,
@@ -23,9 +25,7 @@ import {
23 checkBadSortPagination, 25 checkBadSortPagination,
24 checkBadStartPagination 26 checkBadStartPagination
25} from '../../../../shared/extra-utils/requests/check-api-params' 27} from '../../../../shared/extra-utils/requests/check-api-params'
26import { join } from 'path'
27import { VideoChannelUpdate } from '../../../../shared/models/videos' 28import { VideoChannelUpdate } from '../../../../shared/models/videos'
28import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
29 29
30const expect = chai.expect 30const expect = chai.expect
31 31
@@ -246,7 +246,7 @@ describe('Test video channels API validator', function () {
246 for (const type of types) { 246 for (const type of types) {
247 const fields = {} 247 const fields = {}
248 const attaches = { 248 const attaches = {
249 [type + 'file']: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') 249 [type + 'file']: buildAbsoluteFixturePath('video_short.mp4')
250 } 250 }
251 251
252 await makeUploadRequest({ url: server.url, path: `${path}/${type}/pick`, token: server.accessToken, fields, attaches }) 252 await makeUploadRequest({ url: server.url, path: `${path}/${type}/pick`, token: server.accessToken, fields, attaches })
@@ -257,7 +257,7 @@ describe('Test video channels API validator', function () {
257 for (const type of types) { 257 for (const type of types) {
258 const fields = {} 258 const fields = {}
259 const attaches = { 259 const attaches = {
260 [type + 'file']: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') 260 [type + 'file']: buildAbsoluteFixturePath('avatar-big.png')
261 } 261 }
262 await makeUploadRequest({ url: server.url, path: `${path}/${type}/pick`, token: server.accessToken, fields, attaches }) 262 await makeUploadRequest({ url: server.url, path: `${path}/${type}/pick`, token: server.accessToken, fields, attaches })
263 } 263 }
@@ -267,7 +267,7 @@ describe('Test video channels API validator', function () {
267 for (const type of types) { 267 for (const type of types) {
268 const fields = {} 268 const fields = {}
269 const attaches = { 269 const attaches = {
270 [type + 'file']: join(__dirname, '..', '..', 'fixtures', 'avatar.png') 270 [type + 'file']: buildAbsoluteFixturePath('avatar.png')
271 } 271 }
272 await makeUploadRequest({ 272 await makeUploadRequest({
273 url: server.url, 273 url: server.url,
@@ -283,7 +283,7 @@ describe('Test video channels API validator', function () {
283 for (const type of types) { 283 for (const type of types) {
284 const fields = {} 284 const fields = {}
285 const attaches = { 285 const attaches = {
286 [type + 'file']: join(__dirname, '..', '..', 'fixtures', 'avatar.png') 286 [type + 'file']: buildAbsoluteFixturePath('avatar.png')
287 } 287 }
288 await makeUploadRequest({ 288 await makeUploadRequest({
289 url: server.url, 289 url: server.url,
diff --git a/server/tests/api/check-params/video-comments.ts b/server/tests/api/check-params/video-comments.ts
index 659a10c41..a38420851 100644
--- a/server/tests/api/check-params/video-comments.ts
+++ b/server/tests/api/check-params/video-comments.ts
@@ -1,7 +1,9 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
4import * as chai from 'chai'
5import { VideoCreateResult } from '@shared/models'
6import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
5import { 7import {
6 cleanupTests, 8 cleanupTests,
7 createUser, 9 createUser,
@@ -20,7 +22,6 @@ import {
20 checkBadStartPagination 22 checkBadStartPagination
21} from '../../../../shared/extra-utils/requests/check-api-params' 23} from '../../../../shared/extra-utils/requests/check-api-params'
22import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments' 24import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments'
23import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
24 25
25const expect = chai.expect 26const expect = chai.expect
26 27
@@ -28,7 +29,7 @@ describe('Test video comments API validator', function () {
28 let pathThread: string 29 let pathThread: string
29 let pathComment: string 30 let pathComment: string
30 let server: ServerInfo 31 let server: ServerInfo
31 let videoUUID: string 32 let video: VideoCreateResult
32 let userAccessToken: string 33 let userAccessToken: string
33 let userAccessToken2: string 34 let userAccessToken2: string
34 let commentId: number 35 let commentId: number
@@ -44,14 +45,14 @@ describe('Test video comments API validator', function () {
44 45
45 { 46 {
46 const res = await uploadVideo(server.url, server.accessToken, {}) 47 const res = await uploadVideo(server.url, server.accessToken, {})
47 videoUUID = res.body.video.uuid 48 video = res.body.video
48 pathThread = '/api/v1/videos/' + videoUUID + '/comment-threads' 49 pathThread = '/api/v1/videos/' + video.uuid + '/comment-threads'
49 } 50 }
50 51
51 { 52 {
52 const res = await addVideoCommentThread(server.url, server.accessToken, videoUUID, 'coucou') 53 const res = await addVideoCommentThread(server.url, server.accessToken, video.uuid, 'coucou')
53 commentId = res.body.comment.id 54 commentId = res.body.comment.id
54 pathComment = '/api/v1/videos/' + videoUUID + '/comments/' + commentId 55 pathComment = '/api/v1/videos/' + video.uuid + '/comments/' + commentId
55 } 56 }
56 57
57 { 58 {
@@ -101,7 +102,7 @@ describe('Test video comments API validator', function () {
101 it('Should fail with an incorrect thread id', async function () { 102 it('Should fail with an incorrect thread id', async function () {
102 await makeGetRequest({ 103 await makeGetRequest({
103 url: server.url, 104 url: server.url,
104 path: '/api/v1/videos/' + videoUUID + '/comment-threads/156', 105 path: '/api/v1/videos/' + video.shortUUID + '/comment-threads/156',
105 statusCodeExpected: HttpStatusCode.NOT_FOUND_404 106 statusCodeExpected: HttpStatusCode.NOT_FOUND_404
106 }) 107 })
107 }) 108 })
@@ -109,7 +110,7 @@ describe('Test video comments API validator', function () {
109 it('Should success with the correct params', async function () { 110 it('Should success with the correct params', async function () {
110 await makeGetRequest({ 111 await makeGetRequest({
111 url: server.url, 112 url: server.url,
112 path: '/api/v1/videos/' + videoUUID + '/comment-threads/' + commentId, 113 path: '/api/v1/videos/' + video.shortUUID + '/comment-threads/' + commentId,
113 statusCodeExpected: HttpStatusCode.OK_200 114 statusCodeExpected: HttpStatusCode.OK_200
114 }) 115 })
115 }) 116 })
@@ -225,7 +226,7 @@ describe('Test video comments API validator', function () {
225 }) 226 })
226 227
227 it('Should fail with an incorrect comment', async function () { 228 it('Should fail with an incorrect comment', async function () {
228 const path = '/api/v1/videos/' + videoUUID + '/comments/124' 229 const path = '/api/v1/videos/' + video.uuid + '/comments/124'
229 const fields = { 230 const fields = {
230 text: 'super comment' 231 text: 'super comment'
231 } 232 }
@@ -272,7 +273,7 @@ describe('Test video comments API validator', function () {
272 }) 273 })
273 274
274 it('Should fail with an incorrect comment', async function () { 275 it('Should fail with an incorrect comment', async function () {
275 const path = '/api/v1/videos/' + videoUUID + '/comments/124' 276 const path = '/api/v1/videos/' + video.uuid + '/comments/124'
276 await makeDeleteRequest({ url: server.url, path, token: server.accessToken, statusCodeExpected: HttpStatusCode.NOT_FOUND_404 }) 277 await makeDeleteRequest({ url: server.url, path, token: server.accessToken, statusCodeExpected: HttpStatusCode.NOT_FOUND_404 })
277 }) 278 })
278 279
@@ -280,11 +281,11 @@ describe('Test video comments API validator', function () {
280 let commentToDelete: number 281 let commentToDelete: number
281 282
282 { 283 {
283 const res = await addVideoCommentThread(server.url, userAccessToken, videoUUID, 'hello') 284 const res = await addVideoCommentThread(server.url, userAccessToken, video.uuid, 'hello')
284 commentToDelete = res.body.comment.id 285 commentToDelete = res.body.comment.id
285 } 286 }
286 287
287 const path = '/api/v1/videos/' + videoUUID + '/comments/' + commentToDelete 288 const path = '/api/v1/videos/' + video.uuid + '/comments/' + commentToDelete
288 289
289 await makeDeleteRequest({ url: server.url, path, token: userAccessToken2, statusCodeExpected: HttpStatusCode.FORBIDDEN_403 }) 290 await makeDeleteRequest({ url: server.url, path, token: userAccessToken2, statusCodeExpected: HttpStatusCode.FORBIDDEN_403 })
290 await makeDeleteRequest({ url: server.url, path, token: userAccessToken, statusCodeExpected: HttpStatusCode.NO_CONTENT_204 }) 291 await makeDeleteRequest({ url: server.url, path, token: userAccessToken, statusCodeExpected: HttpStatusCode.NO_CONTENT_204 })
@@ -323,8 +324,8 @@ describe('Test video comments API validator', function () {
323 describe('When a video has comments disabled', function () { 324 describe('When a video has comments disabled', function () {
324 before(async function () { 325 before(async function () {
325 const res = await uploadVideo(server.url, server.accessToken, { commentsEnabled: false }) 326 const res = await uploadVideo(server.url, server.accessToken, { commentsEnabled: false })
326 videoUUID = res.body.video.uuid 327 video = res.body.video
327 pathThread = '/api/v1/videos/' + videoUUID + '/comment-threads' 328 pathThread = '/api/v1/videos/' + video.uuid + '/comment-threads'
328 }) 329 })
329 330
330 it('Should return an empty thread list', async function () { 331 it('Should return an empty thread list', async function () {
diff --git a/server/tests/api/check-params/video-imports.ts b/server/tests/api/check-params/video-imports.ts
index 6de6b40c8..a27b624d0 100644
--- a/server/tests/api/check-params/video-imports.ts
+++ b/server/tests/api/check-params/video-imports.ts
@@ -2,8 +2,9 @@
2 2
3import 'mocha' 3import 'mocha'
4import { omit } from 'lodash' 4import { omit } from 'lodash'
5import { join } from 'path' 5import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
6import { 6import {
7 buildAbsoluteFixturePath,
7 cleanupTests, 8 cleanupTests,
8 createUser, 9 createUser,
9 flushAndRunServer, 10 flushAndRunServer,
@@ -22,9 +23,8 @@ import {
22 checkBadSortPagination, 23 checkBadSortPagination,
23 checkBadStartPagination 24 checkBadStartPagination
24} from '../../../../shared/extra-utils/requests/check-api-params' 25} from '../../../../shared/extra-utils/requests/check-api-params'
25import { getMagnetURI, getGoodVideoUrl } from '../../../../shared/extra-utils/videos/video-imports' 26import { getGoodVideoUrl, getMagnetURI } from '../../../../shared/extra-utils/videos/video-imports'
26import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum' 27import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
27import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
28 28
29describe('Test video imports API validator', function () { 29describe('Test video imports API validator', function () {
30 const path = '/api/v1/videos/imports' 30 const path = '/api/v1/videos/imports'
@@ -201,7 +201,7 @@ describe('Test video imports API validator', function () {
201 it('Should fail with an incorrect thumbnail file', async function () { 201 it('Should fail with an incorrect thumbnail file', async function () {
202 const fields = baseCorrectParams 202 const fields = baseCorrectParams
203 const attaches = { 203 const attaches = {
204 thumbnailfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') 204 thumbnailfile: buildAbsoluteFixturePath('video_short.mp4')
205 } 205 }
206 206
207 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 207 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -210,7 +210,7 @@ describe('Test video imports API validator', function () {
210 it('Should fail with a big thumbnail file', async function () { 210 it('Should fail with a big thumbnail file', async function () {
211 const fields = baseCorrectParams 211 const fields = baseCorrectParams
212 const attaches = { 212 const attaches = {
213 thumbnailfile: join(__dirname, '..', '..', 'fixtures', 'preview-big.png') 213 thumbnailfile: buildAbsoluteFixturePath('preview-big.png')
214 } 214 }
215 215
216 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 216 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -219,7 +219,7 @@ describe('Test video imports API validator', function () {
219 it('Should fail with an incorrect preview file', async function () { 219 it('Should fail with an incorrect preview file', async function () {
220 const fields = baseCorrectParams 220 const fields = baseCorrectParams
221 const attaches = { 221 const attaches = {
222 previewfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') 222 previewfile: buildAbsoluteFixturePath('video_short.mp4')
223 } 223 }
224 224
225 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 225 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -228,7 +228,7 @@ describe('Test video imports API validator', function () {
228 it('Should fail with a big preview file', async function () { 228 it('Should fail with a big preview file', async function () {
229 const fields = baseCorrectParams 229 const fields = baseCorrectParams
230 const attaches = { 230 const attaches = {
231 previewfile: join(__dirname, '..', '..', 'fixtures', 'preview-big.png') 231 previewfile: buildAbsoluteFixturePath('preview-big.png')
232 } 232 }
233 233
234 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 234 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -237,7 +237,7 @@ describe('Test video imports API validator', function () {
237 it('Should fail with an invalid torrent file', async function () { 237 it('Should fail with an invalid torrent file', async function () {
238 const fields = omit(baseCorrectParams, 'targetUrl') 238 const fields = omit(baseCorrectParams, 'targetUrl')
239 const attaches = { 239 const attaches = {
240 torrentfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') 240 torrentfile: buildAbsoluteFixturePath('avatar-big.png')
241 } 241 }
242 242
243 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) 243 await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
@@ -312,7 +312,7 @@ describe('Test video imports API validator', function () {
312 312
313 fields = omit(fields, 'magnetUri') 313 fields = omit(fields, 'magnetUri')
314 const attaches = { 314 const attaches = {
315 torrentfile: join(__dirname, '..', '..', 'fixtures', 'video-720p.torrent') 315 torrentfile: buildAbsoluteFixturePath('video-720p.torrent')
316 } 316 }
317 317
318 await makeUploadRequest({ 318 await makeUploadRequest({
diff --git a/server/tests/api/check-params/video-playlists.ts b/server/tests/api/check-params/video-playlists.ts
index bbea88354..18253d11a 100644
--- a/server/tests/api/check-params/video-playlists.ts
+++ b/server/tests/api/check-params/video-playlists.ts
@@ -1,8 +1,13 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { VideoPlaylistCreateResult, VideoPlaylistPrivacy, VideoPlaylistType } from '@shared/models'
5import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
4import { 6import {
5 addVideoInPlaylist, 7 addVideoInPlaylist,
8 checkBadCountPagination,
9 checkBadSortPagination,
10 checkBadStartPagination,
6 cleanupTests, 11 cleanupTests,
7 createVideoPlaylist, 12 createVideoPlaylist,
8 deleteVideoPlaylist, 13 deleteVideoPlaylist,
@@ -21,20 +26,14 @@ import {
21 updateVideoPlaylistElement, 26 updateVideoPlaylistElement,
22 uploadVideoAndGetId 27 uploadVideoAndGetId
23} from '../../../../shared/extra-utils' 28} from '../../../../shared/extra-utils'
24import {
25 checkBadCountPagination,
26 checkBadSortPagination,
27 checkBadStartPagination
28} from '../../../../shared/extra-utils/requests/check-api-params'
29import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
30import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
31import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
32 29
33describe('Test video playlists API validator', function () { 30describe('Test video playlists API validator', function () {
34 let server: ServerInfo 31 let server: ServerInfo
35 let userAccessToken: string 32 let userAccessToken: string
36 let playlistUUID: string 33
34 let playlist: VideoPlaylistCreateResult
37 let privatePlaylistUUID: string 35 let privatePlaylistUUID: string
36
38 let watchLaterPlaylistId: number 37 let watchLaterPlaylistId: number
39 let videoId: number 38 let videoId: number
40 let playlistElementId: number 39 let playlistElementId: number
@@ -67,7 +66,7 @@ describe('Test video playlists API validator', function () {
67 videoChannelId: server.videoChannel.id 66 videoChannelId: server.videoChannel.id
68 } 67 }
69 }) 68 })
70 playlistUUID = res.body.videoPlaylist.uuid 69 playlist = res.body.videoPlaylist
71 } 70 }
72 71
73 { 72 {
@@ -150,15 +149,15 @@ describe('Test video playlists API validator', function () {
150 const path = '/api/v1/video-playlists/' 149 const path = '/api/v1/video-playlists/'
151 150
152 it('Should fail with a bad start pagination', async function () { 151 it('Should fail with a bad start pagination', async function () {
153 await checkBadStartPagination(server.url, path + playlistUUID + '/videos', server.accessToken) 152 await checkBadStartPagination(server.url, path + playlist.shortUUID + '/videos', server.accessToken)
154 }) 153 })
155 154
156 it('Should fail with a bad count pagination', async function () { 155 it('Should fail with a bad count pagination', async function () {
157 await checkBadCountPagination(server.url, path + playlistUUID + '/videos', server.accessToken) 156 await checkBadCountPagination(server.url, path + playlist.shortUUID + '/videos', server.accessToken)
158 }) 157 })
159 158
160 it('Should success with the correct parameters', async function () { 159 it('Should success with the correct parameters', async function () {
161 await makeGetRequest({ url: server.url, path: path + playlistUUID + '/videos', statusCodeExpected: HttpStatusCode.OK_200 }) 160 await makeGetRequest({ url: server.url, path: path + playlist.shortUUID + '/videos', statusCodeExpected: HttpStatusCode.OK_200 })
162 }) 161 })
163 }) 162 })
164 163
@@ -177,6 +176,7 @@ describe('Test video playlists API validator', function () {
177 token: server.accessToken, 176 token: server.accessToken,
178 playlistAttrs: { 177 playlistAttrs: {
179 displayName: 'super playlist', 178 displayName: 'super playlist',
179 videoChannelId: server.videoChannel.id,
180 privacy: VideoPlaylistPrivacy.UNLISTED 180 privacy: VideoPlaylistPrivacy.UNLISTED
181 } 181 }
182 }) 182 })
@@ -187,7 +187,7 @@ describe('Test video playlists API validator', function () {
187 }) 187 })
188 188
189 it('Should succeed with the correct params', async function () { 189 it('Should succeed with the correct params', async function () {
190 await getVideoPlaylist(server.url, playlistUUID, HttpStatusCode.OK_200) 190 await getVideoPlaylist(server.url, playlist.uuid, HttpStatusCode.OK_200)
191 }) 191 })
192 }) 192 })
193 193
@@ -213,7 +213,7 @@ describe('Test video playlists API validator', function () {
213 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) 213 const params = getBase({}, { token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
214 214
215 await createVideoPlaylist(params) 215 await createVideoPlaylist(params)
216 await updateVideoPlaylist(getUpdate(params, playlistUUID)) 216 await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
217 }) 217 })
218 218
219 it('Should fail without displayName', async function () { 219 it('Should fail without displayName', async function () {
@@ -226,42 +226,42 @@ describe('Test video playlists API validator', function () {
226 const params = getBase({ displayName: 's'.repeat(300) }) 226 const params = getBase({ displayName: 's'.repeat(300) })
227 227
228 await createVideoPlaylist(params) 228 await createVideoPlaylist(params)
229 await updateVideoPlaylist(getUpdate(params, playlistUUID)) 229 await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
230 }) 230 })
231 231
232 it('Should fail with an incorrect description', async function () { 232 it('Should fail with an incorrect description', async function () {
233 const params = getBase({ description: 't' }) 233 const params = getBase({ description: 't' })
234 234
235 await createVideoPlaylist(params) 235 await createVideoPlaylist(params)
236 await updateVideoPlaylist(getUpdate(params, playlistUUID)) 236 await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
237 }) 237 })
238 238
239 it('Should fail with an incorrect privacy', async function () { 239 it('Should fail with an incorrect privacy', async function () {
240 const params = getBase({ privacy: 45 }) 240 const params = getBase({ privacy: 45 })
241 241
242 await createVideoPlaylist(params) 242 await createVideoPlaylist(params)
243 await updateVideoPlaylist(getUpdate(params, playlistUUID)) 243 await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
244 }) 244 })
245 245
246 it('Should fail with an unknown video channel id', async function () { 246 it('Should fail with an unknown video channel id', async function () {
247 const params = getBase({ videoChannelId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 }) 247 const params = getBase({ videoChannelId: 42 }, { expectedStatus: HttpStatusCode.NOT_FOUND_404 })
248 248
249 await createVideoPlaylist(params) 249 await createVideoPlaylist(params)
250 await updateVideoPlaylist(getUpdate(params, playlistUUID)) 250 await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
251 }) 251 })
252 252
253 it('Should fail with an incorrect thumbnail file', async function () { 253 it('Should fail with an incorrect thumbnail file', async function () {
254 const params = getBase({ thumbnailfile: 'video_short.mp4' }) 254 const params = getBase({ thumbnailfile: 'video_short.mp4' })
255 255
256 await createVideoPlaylist(params) 256 await createVideoPlaylist(params)
257 await updateVideoPlaylist(getUpdate(params, playlistUUID)) 257 await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
258 }) 258 })
259 259
260 it('Should fail with a thumbnail file too big', async function () { 260 it('Should fail with a thumbnail file too big', async function () {
261 const params = getBase({ thumbnailfile: 'preview-big.png' }) 261 const params = getBase({ thumbnailfile: 'preview-big.png' })
262 262
263 await createVideoPlaylist(params) 263 await createVideoPlaylist(params)
264 await updateVideoPlaylist(getUpdate(params, playlistUUID)) 264 await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
265 }) 265 })
266 266
267 it('Should fail to set "public" a playlist not assigned to a channel', async function () { 267 it('Should fail to set "public" a playlist not assigned to a channel', async function () {
@@ -272,8 +272,8 @@ describe('Test video playlists API validator', function () {
272 await createVideoPlaylist(params) 272 await createVideoPlaylist(params)
273 await createVideoPlaylist(params2) 273 await createVideoPlaylist(params2)
274 await updateVideoPlaylist(getUpdate(params, privatePlaylistUUID)) 274 await updateVideoPlaylist(getUpdate(params, privatePlaylistUUID))
275 await updateVideoPlaylist(getUpdate(params2, playlistUUID)) 275 await updateVideoPlaylist(getUpdate(params2, playlist.shortUUID))
276 await updateVideoPlaylist(getUpdate(params3, playlistUUID)) 276 await updateVideoPlaylist(getUpdate(params3, playlist.shortUUID))
277 }) 277 })
278 278
279 it('Should fail with an unknown playlist to update', async function () { 279 it('Should fail with an unknown playlist to update', async function () {
@@ -286,7 +286,7 @@ describe('Test video playlists API validator', function () {
286 it('Should fail to update a playlist of another user', async function () { 286 it('Should fail to update a playlist of another user', async function () {
287 await updateVideoPlaylist(getUpdate( 287 await updateVideoPlaylist(getUpdate(
288 getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }), 288 getBase({}, { token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }),
289 playlistUUID 289 playlist.shortUUID
290 )) 290 ))
291 }) 291 })
292 292
@@ -305,7 +305,7 @@ describe('Test video playlists API validator', function () {
305 305
306 { 306 {
307 const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 }) 307 const params = getBase({}, { expectedStatus: HttpStatusCode.NO_CONTENT_204 })
308 await updateVideoPlaylist(getUpdate(params, playlistUUID)) 308 await updateVideoPlaylist(getUpdate(params, playlist.shortUUID))
309 } 309 }
310 }) 310 })
311 }) 311 })
@@ -316,7 +316,7 @@ describe('Test video playlists API validator', function () {
316 expectedStatus: HttpStatusCode.BAD_REQUEST_400, 316 expectedStatus: HttpStatusCode.BAD_REQUEST_400,
317 url: server.url, 317 url: server.url,
318 token: server.accessToken, 318 token: server.accessToken,
319 playlistId: playlistUUID, 319 playlistId: playlist.id,
320 elementAttrs: Object.assign({ 320 elementAttrs: Object.assign({
321 videoId, 321 videoId,
322 startTimestamp: 2, 322 startTimestamp: 2,
@@ -381,7 +381,7 @@ describe('Test video playlists API validator', function () {
381 stopTimestamp: 2 381 stopTimestamp: 2
382 }, elementAttrs), 382 }, elementAttrs),
383 playlistElementId, 383 playlistElementId,
384 playlistId: playlistUUID, 384 playlistId: playlist.id,
385 expectedStatus: HttpStatusCode.BAD_REQUEST_400 385 expectedStatus: HttpStatusCode.BAD_REQUEST_400
386 }, wrapper) 386 }, wrapper)
387 } 387 }
@@ -451,7 +451,7 @@ describe('Test video playlists API validator', function () {
451 return Object.assign({ 451 return Object.assign({
452 url: server.url, 452 url: server.url,
453 token: server.accessToken, 453 token: server.accessToken,
454 playlistId: playlistUUID, 454 playlistId: playlist.shortUUID,
455 elementAttrs: Object.assign({ 455 elementAttrs: Object.assign({
456 startPosition: 1, 456 startPosition: 1,
457 insertAfterPosition: 2, 457 insertAfterPosition: 2,
@@ -469,7 +469,7 @@ describe('Test video playlists API validator', function () {
469 await addVideoInPlaylist({ 469 await addVideoInPlaylist({
470 url: server.url, 470 url: server.url,
471 token: server.accessToken, 471 token: server.accessToken,
472 playlistId: playlistUUID, 472 playlistId: playlist.shortUUID,
473 elementAttrs: { videoId: id } 473 elementAttrs: { videoId: id }
474 }) 474 })
475 } 475 }
@@ -606,7 +606,7 @@ describe('Test video playlists API validator', function () {
606 url: server.url, 606 url: server.url,
607 token: server.accessToken, 607 token: server.accessToken,
608 playlistElementId, 608 playlistElementId,
609 playlistId: playlistUUID, 609 playlistId: playlist.uuid,
610 expectedStatus: HttpStatusCode.BAD_REQUEST_400 610 expectedStatus: HttpStatusCode.BAD_REQUEST_400
611 }, wrapper) 611 }, wrapper)
612 } 612 }
@@ -662,7 +662,7 @@ describe('Test video playlists API validator', function () {
662 }) 662 })
663 663
664 it('Should fail with a playlist of another user', async function () { 664 it('Should fail with a playlist of another user', async function () {
665 await deleteVideoPlaylist(server.url, userAccessToken, playlistUUID, HttpStatusCode.FORBIDDEN_403) 665 await deleteVideoPlaylist(server.url, userAccessToken, playlist.uuid, HttpStatusCode.FORBIDDEN_403)
666 }) 666 })
667 667
668 it('Should fail with the watch later playlist', async function () { 668 it('Should fail with the watch later playlist', async function () {
@@ -670,7 +670,7 @@ describe('Test video playlists API validator', function () {
670 }) 670 })
671 671
672 it('Should succeed with the correct params', async function () { 672 it('Should succeed with the correct params', async function () {
673 await deleteVideoPlaylist(server.url, server.accessToken, playlistUUID) 673 await deleteVideoPlaylist(server.url, server.accessToken, playlist.uuid)
674 }) 674 })
675 }) 675 })
676 676
diff --git a/server/tests/api/check-params/videos-filter.ts b/server/tests/api/check-params/videos-filter.ts
index 2391584a7..4d54a4fd0 100644
--- a/server/tests/api/check-params/videos-filter.ts
+++ b/server/tests/api/check-params/videos-filter.ts
@@ -35,7 +35,7 @@ async function testEndpoints (server: ServerInfo, token: string, filter: string,
35 } 35 }
36} 36}
37 37
38describe('Test videos filters', function () { 38describe('Test video filters validators', function () {
39 let server: ServerInfo 39 let server: ServerInfo
40 let userAccessToken: string 40 let userAccessToken: string
41 let moderatorAccessToken: string 41 let moderatorAccessToken: string
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts
index c970c4a15..4d7a9a23b 100644
--- a/server/tests/api/check-params/videos.ts
+++ b/server/tests/api/check-params/videos.ts
@@ -4,6 +4,8 @@ import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { omit } from 'lodash' 5import { omit } from 'lodash'
6import { join } from 'path' 6import { join } from 'path'
7import { randomInt } from '@shared/core-utils'
8import { PeerTubeProblemDocument, VideoCreateResult } from '@shared/models'
7import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 9import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
8import { 10import {
9 checkUploadVideoParam, 11 checkUploadVideoParam,
@@ -30,7 +32,6 @@ import {
30 checkBadStartPagination 32 checkBadStartPagination
31} from '../../../../shared/extra-utils/requests/check-api-params' 33} from '../../../../shared/extra-utils/requests/check-api-params'
32import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum' 34import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
33import { randomInt } from '@shared/core-utils'
34 35
35const expect = chai.expect 36const expect = chai.expect
36 37
@@ -41,7 +42,7 @@ describe('Test videos API validator', function () {
41 let accountName: string 42 let accountName: string
42 let channelId: number 43 let channelId: number
43 let channelName: string 44 let channelName: string
44 let videoId 45 let video: VideoCreateResult
45 46
46 // --------------------------------------------------------------- 47 // ---------------------------------------------------------------
47 48
@@ -411,6 +412,31 @@ describe('Test videos API validator', function () {
411 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode) 412 await checkUploadVideoParam(server.url, server.accessToken, { ...fields, ...attaches }, HttpStatusCode.BAD_REQUEST_400, mode)
412 }) 413 })
413 414
415 it('Should report the appropriate error', async function () {
416 const fields = immutableAssign(baseCorrectParams, { language: 'a'.repeat(15) })
417 const attaches = baseCorrectAttaches
418
419 const attributes = { ...fields, ...attaches }
420 const res = await checkUploadVideoParam(server.url, server.accessToken, attributes, HttpStatusCode.BAD_REQUEST_400, mode)
421
422 const error = res.body as PeerTubeProblemDocument
423
424 if (mode === 'legacy') {
425 expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadLegacy')
426 } else {
427 expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/uploadResumableInit')
428 }
429
430 expect(error.type).to.equal('about:blank')
431 expect(error.title).to.equal('Bad Request')
432
433 expect(error.detail).to.equal('Incorrect request parameters: language')
434 expect(error.error).to.equal('Incorrect request parameters: language')
435
436 expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400)
437 expect(error['invalid-params'].language).to.exist
438 })
439
414 it('Should succeed with the correct parameters', async function () { 440 it('Should succeed with the correct parameters', async function () {
415 this.timeout(10000) 441 this.timeout(10000)
416 442
@@ -464,7 +490,7 @@ describe('Test videos API validator', function () {
464 490
465 before(async function () { 491 before(async function () {
466 const res = await getVideosList(server.url) 492 const res = await getVideosList(server.url)
467 videoId = res.body.data[0].uuid 493 video = res.body.data[0]
468 }) 494 })
469 495
470 it('Should fail with nothing', async function () { 496 it('Should fail with nothing', async function () {
@@ -492,79 +518,79 @@ describe('Test videos API validator', function () {
492 it('Should fail with a long name', async function () { 518 it('Should fail with a long name', async function () {
493 const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) }) 519 const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) })
494 520
495 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 521 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
496 }) 522 })
497 523
498 it('Should fail with a bad category', async function () { 524 it('Should fail with a bad category', async function () {
499 const fields = immutableAssign(baseCorrectParams, { category: 125 }) 525 const fields = immutableAssign(baseCorrectParams, { category: 125 })
500 526
501 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 527 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
502 }) 528 })
503 529
504 it('Should fail with a bad licence', async function () { 530 it('Should fail with a bad licence', async function () {
505 const fields = immutableAssign(baseCorrectParams, { licence: 125 }) 531 const fields = immutableAssign(baseCorrectParams, { licence: 125 })
506 532
507 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 533 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
508 }) 534 })
509 535
510 it('Should fail with a bad language', async function () { 536 it('Should fail with a bad language', async function () {
511 const fields = immutableAssign(baseCorrectParams, { language: 'a'.repeat(15) }) 537 const fields = immutableAssign(baseCorrectParams, { language: 'a'.repeat(15) })
512 538
513 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 539 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
514 }) 540 })
515 541
516 it('Should fail with a long description', async function () { 542 it('Should fail with a long description', async function () {
517 const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(2500) }) 543 const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(2500) })
518 544
519 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 545 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
520 }) 546 })
521 547
522 it('Should fail with a long support text', async function () { 548 it('Should fail with a long support text', async function () {
523 const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(201) }) 549 const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(201) })
524 550
525 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 551 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
526 }) 552 })
527 553
528 it('Should fail with a bad channel', async function () { 554 it('Should fail with a bad channel', async function () {
529 const fields = immutableAssign(baseCorrectParams, { channelId: 545454 }) 555 const fields = immutableAssign(baseCorrectParams, { channelId: 545454 })
530 556
531 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 557 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
532 }) 558 })
533 559
534 it('Should fail with too many tags', async function () { 560 it('Should fail with too many tags', async function () {
535 const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }) 561 const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] })
536 562
537 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 563 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
538 }) 564 })
539 565
540 it('Should fail with a tag length too low', async function () { 566 it('Should fail with a tag length too low', async function () {
541 const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 't' ] }) 567 const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 't' ] })
542 568
543 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 569 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
544 }) 570 })
545 571
546 it('Should fail with a tag length too big', async function () { 572 it('Should fail with a tag length too big', async function () {
547 const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }) 573 const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] })
548 574
549 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 575 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
550 }) 576 })
551 577
552 it('Should fail with a bad schedule update (miss updateAt)', async function () { 578 it('Should fail with a bad schedule update (miss updateAt)', async function () {
553 const fields = immutableAssign(baseCorrectParams, { scheduleUpdate: { privacy: VideoPrivacy.PUBLIC } }) 579 const fields = immutableAssign(baseCorrectParams, { scheduleUpdate: { privacy: VideoPrivacy.PUBLIC } })
554 580
555 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 581 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
556 }) 582 })
557 583
558 it('Should fail with a bad schedule update (wrong updateAt)', async function () { 584 it('Should fail with a bad schedule update (wrong updateAt)', async function () {
559 const fields = immutableAssign(baseCorrectParams, { scheduleUpdate: { updateAt: 'toto', privacy: VideoPrivacy.PUBLIC } }) 585 const fields = immutableAssign(baseCorrectParams, { scheduleUpdate: { updateAt: 'toto', privacy: VideoPrivacy.PUBLIC } })
560 586
561 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 587 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
562 }) 588 })
563 589
564 it('Should fail with a bad originally published at param', async function () { 590 it('Should fail with a bad originally published at param', async function () {
565 const fields = immutableAssign(baseCorrectParams, { originallyPublishedAt: 'toto' }) 591 const fields = immutableAssign(baseCorrectParams, { originallyPublishedAt: 'toto' })
566 592
567 await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields }) 593 await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
568 }) 594 })
569 595
570 it('Should fail with an incorrect thumbnail file', async function () { 596 it('Should fail with an incorrect thumbnail file', async function () {
@@ -576,7 +602,7 @@ describe('Test videos API validator', function () {
576 await makeUploadRequest({ 602 await makeUploadRequest({
577 url: server.url, 603 url: server.url,
578 method: 'PUT', 604 method: 'PUT',
579 path: path + videoId, 605 path: path + video.shortUUID,
580 token: server.accessToken, 606 token: server.accessToken,
581 fields, 607 fields,
582 attaches 608 attaches
@@ -592,7 +618,7 @@ describe('Test videos API validator', function () {
592 await makeUploadRequest({ 618 await makeUploadRequest({
593 url: server.url, 619 url: server.url,
594 method: 'PUT', 620 method: 'PUT',
595 path: path + videoId, 621 path: path + video.shortUUID,
596 token: server.accessToken, 622 token: server.accessToken,
597 fields, 623 fields,
598 attaches 624 attaches
@@ -608,7 +634,7 @@ describe('Test videos API validator', function () {
608 await makeUploadRequest({ 634 await makeUploadRequest({
609 url: server.url, 635 url: server.url,
610 method: 'PUT', 636 method: 'PUT',
611 path: path + videoId, 637 path: path + video.shortUUID,
612 token: server.accessToken, 638 token: server.accessToken,
613 fields, 639 fields,
614 attaches 640 attaches
@@ -624,7 +650,7 @@ describe('Test videos API validator', function () {
624 await makeUploadRequest({ 650 await makeUploadRequest({
625 url: server.url, 651 url: server.url,
626 method: 'PUT', 652 method: 'PUT',
627 path: path + videoId, 653 path: path + video.shortUUID,
628 token: server.accessToken, 654 token: server.accessToken,
629 fields, 655 fields,
630 attaches 656 attaches
@@ -636,7 +662,7 @@ describe('Test videos API validator', function () {
636 662
637 await makePutBodyRequest({ 663 await makePutBodyRequest({
638 url: server.url, 664 url: server.url,
639 path: path + videoId, 665 path: path + video.shortUUID,
640 token: userAccessToken, 666 token: userAccessToken,
641 fields, 667 fields,
642 statusCodeExpected: HttpStatusCode.FORBIDDEN_403 668 statusCodeExpected: HttpStatusCode.FORBIDDEN_403
@@ -645,12 +671,30 @@ describe('Test videos API validator', function () {
645 671
646 it('Should fail with a video of another server') 672 it('Should fail with a video of another server')
647 673
674 it('Shoud report the appropriate error', async function () {
675 const fields = immutableAssign(baseCorrectParams, { licence: 125 })
676
677 const res = await makePutBodyRequest({ url: server.url, path: path + video.shortUUID, token: server.accessToken, fields })
678 const error = res.body as PeerTubeProblemDocument
679
680 expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/putVideo')
681
682 expect(error.type).to.equal('about:blank')
683 expect(error.title).to.equal('Bad Request')
684
685 expect(error.detail).to.equal('Incorrect request parameters: licence')
686 expect(error.error).to.equal('Incorrect request parameters: licence')
687
688 expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400)
689 expect(error['invalid-params'].licence).to.exist
690 })
691
648 it('Should succeed with the correct parameters', async function () { 692 it('Should succeed with the correct parameters', async function () {
649 const fields = baseCorrectParams 693 const fields = baseCorrectParams
650 694
651 await makePutBodyRequest({ 695 await makePutBodyRequest({
652 url: server.url, 696 url: server.url,
653 path: path + videoId, 697 path: path + video.shortUUID,
654 token: server.accessToken, 698 token: server.accessToken,
655 fields, 699 fields,
656 statusCodeExpected: HttpStatusCode.NO_CONTENT_204 700 statusCodeExpected: HttpStatusCode.NO_CONTENT_204
@@ -678,8 +722,24 @@ describe('Test videos API validator', function () {
678 await getVideo(server.url, '4da6fde3-88f7-4d16-b119-108df5630b06', HttpStatusCode.NOT_FOUND_404) 722 await getVideo(server.url, '4da6fde3-88f7-4d16-b119-108df5630b06', HttpStatusCode.NOT_FOUND_404)
679 }) 723 })
680 724
725 it('Shoud report the appropriate error', async function () {
726 const res = await getVideo(server.url, 'hi', HttpStatusCode.BAD_REQUEST_400)
727 const error = res.body as PeerTubeProblemDocument
728
729 expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/getVideo')
730
731 expect(error.type).to.equal('about:blank')
732 expect(error.title).to.equal('Bad Request')
733
734 expect(error.detail).to.equal('Incorrect request parameters: id')
735 expect(error.error).to.equal('Incorrect request parameters: id')
736
737 expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400)
738 expect(error['invalid-params'].id).to.exist
739 })
740
681 it('Should succeed with the correct parameters', async function () { 741 it('Should succeed with the correct parameters', async function () {
682 await getVideo(server.url, videoId) 742 await getVideo(server.url, video.shortUUID)
683 }) 743 })
684 }) 744 })
685 745
@@ -750,13 +810,29 @@ describe('Test videos API validator', function () {
750 }) 810 })
751 811
752 it('Should fail with a video of another user without the appropriate right', async function () { 812 it('Should fail with a video of another user without the appropriate right', async function () {
753 await removeVideo(server.url, userAccessToken, videoId, HttpStatusCode.FORBIDDEN_403) 813 await removeVideo(server.url, userAccessToken, video.uuid, HttpStatusCode.FORBIDDEN_403)
754 }) 814 })
755 815
756 it('Should fail with a video of another server') 816 it('Should fail with a video of another server')
757 817
818 it('Shoud report the appropriate error', async function () {
819 const res = await removeVideo(server.url, server.accessToken, 'hello', HttpStatusCode.BAD_REQUEST_400)
820 const error = res.body as PeerTubeProblemDocument
821
822 expect(error.docs).to.equal('https://docs.joinpeertube.org/api-rest-reference.html#operation/delVideo')
823
824 expect(error.type).to.equal('about:blank')
825 expect(error.title).to.equal('Bad Request')
826
827 expect(error.detail).to.equal('Incorrect request parameters: id')
828 expect(error.error).to.equal('Incorrect request parameters: id')
829
830 expect(error.status).to.equal(HttpStatusCode.BAD_REQUEST_400)
831 expect(error['invalid-params'].id).to.exist
832 })
833
758 it('Should succeed with the correct parameters', async function () { 834 it('Should succeed with the correct parameters', async function () {
759 await removeVideo(server.url, server.accessToken, videoId) 835 await removeVideo(server.url, server.accessToken, video.uuid)
760 }) 836 })
761 }) 837 })
762 838
diff --git a/server/tests/api/live/index.ts b/server/tests/api/live/index.ts
index c733f564e..e6bcef49f 100644
--- a/server/tests/api/live/index.ts
+++ b/server/tests/api/live/index.ts
@@ -1,4 +1,6 @@
1import './live-constraints' 1import './live-constraints'
2import './live-socket-messages'
2import './live-permanent' 3import './live-permanent'
3import './live-save-replay' 4import './live-save-replay'
5import './live-views'
4import './live' 6import './live'
diff --git a/server/tests/api/live/live-permanent.ts b/server/tests/api/live/live-permanent.ts
index d52e8c7e4..71b7d28a8 100644
--- a/server/tests/api/live/live-permanent.ts
+++ b/server/tests/api/live/live-permanent.ts
@@ -27,7 +27,7 @@ import {
27 27
28const expect = chai.expect 28const expect = chai.expect
29 29
30describe('Permenant live', function () { 30describe('Permanent live', function () {
31 let servers: ServerInfo[] = [] 31 let servers: ServerInfo[] = []
32 let videoUUID: string 32 let videoUUID: string
33 33
@@ -106,7 +106,7 @@ describe('Permenant live', function () {
106 }) 106 })
107 107
108 it('Should stream into this permanent live', async function () { 108 it('Should stream into this permanent live', async function () {
109 this.timeout(60000) 109 this.timeout(120000)
110 110
111 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, videoUUID) 111 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, videoUUID)
112 112
diff --git a/server/tests/api/live/live-socket-messages.ts b/server/tests/api/live/live-socket-messages.ts
new file mode 100644
index 000000000..e00909ade
--- /dev/null
+++ b/server/tests/api/live/live-socket-messages.ts
@@ -0,0 +1,196 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import { getLiveNotificationSocket } from '@shared/extra-utils/socket/socket-io'
6import { VideoPrivacy, VideoState } from '@shared/models'
7import {
8 cleanupTests,
9 createLive,
10 doubleFollow,
11 flushAndRunMultipleServers,
12 getVideoIdFromUUID,
13 sendRTMPStreamInVideo,
14 ServerInfo,
15 setAccessTokensToServers,
16 setDefaultVideoChannel,
17 stopFfmpeg,
18 updateCustomSubConfig,
19 viewVideo,
20 wait,
21 waitJobs,
22 waitUntilLiveEnded,
23 waitUntilLivePublishedOnAllServers
24} from '../../../../shared/extra-utils'
25
26const expect = chai.expect
27
28describe('Test live', function () {
29 let servers: ServerInfo[] = []
30
31 before(async function () {
32 this.timeout(120000)
33
34 servers = await flushAndRunMultipleServers(2)
35
36 // Get the access tokens
37 await setAccessTokensToServers(servers)
38 await setDefaultVideoChannel(servers)
39
40 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
41 live: {
42 enabled: true,
43 allowReplay: true,
44 transcoding: {
45 enabled: false
46 }
47 }
48 })
49
50 // Server 1 and server 2 follow each other
51 await doubleFollow(servers[0], servers[1])
52 })
53
54 describe('Live socket messages', function () {
55
56 async function createLiveWrapper () {
57 const liveAttributes = {
58 name: 'live video',
59 channelId: servers[0].videoChannel.id,
60 privacy: VideoPrivacy.PUBLIC
61 }
62
63 const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes)
64 return res.body.video.uuid
65 }
66
67 it('Should correctly send a message when the live starts and ends', async function () {
68 this.timeout(60000)
69
70 const localStateChanges: VideoState[] = []
71 const remoteStateChanges: VideoState[] = []
72
73 const liveVideoUUID = await createLiveWrapper()
74 await waitJobs(servers)
75
76 {
77 const videoId = await getVideoIdFromUUID(servers[0].url, liveVideoUUID)
78
79 const localSocket = getLiveNotificationSocket(servers[0].url)
80 localSocket.on('state-change', data => localStateChanges.push(data.state))
81 localSocket.emit('subscribe', { videoId })
82 }
83
84 {
85 const videoId = await getVideoIdFromUUID(servers[1].url, liveVideoUUID)
86
87 const remoteSocket = getLiveNotificationSocket(servers[1].url)
88 remoteSocket.on('state-change', data => remoteStateChanges.push(data.state))
89 remoteSocket.emit('subscribe', { videoId })
90 }
91
92 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
93
94 await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
95 await waitJobs(servers)
96
97 for (const stateChanges of [ localStateChanges, remoteStateChanges ]) {
98 expect(stateChanges).to.have.length.at.least(1)
99 expect(stateChanges[stateChanges.length - 1]).to.equal(VideoState.PUBLISHED)
100 }
101
102 await stopFfmpeg(command)
103
104 for (const server of servers) {
105 await waitUntilLiveEnded(server.url, server.accessToken, liveVideoUUID)
106 }
107 await waitJobs(servers)
108
109 for (const stateChanges of [ localStateChanges, remoteStateChanges ]) {
110 expect(stateChanges).to.have.length.at.least(2)
111 expect(stateChanges[stateChanges.length - 1]).to.equal(VideoState.LIVE_ENDED)
112 }
113 })
114
115 it('Should correctly send views change notification', async function () {
116 this.timeout(60000)
117
118 let localLastVideoViews = 0
119 let remoteLastVideoViews = 0
120
121 const liveVideoUUID = await createLiveWrapper()
122 await waitJobs(servers)
123
124 {
125 const videoId = await getVideoIdFromUUID(servers[0].url, liveVideoUUID)
126
127 const localSocket = getLiveNotificationSocket(servers[0].url)
128 localSocket.on('views-change', data => { localLastVideoViews = data.views })
129 localSocket.emit('subscribe', { videoId })
130 }
131
132 {
133 const videoId = await getVideoIdFromUUID(servers[1].url, liveVideoUUID)
134
135 const remoteSocket = getLiveNotificationSocket(servers[1].url)
136 remoteSocket.on('views-change', data => { remoteLastVideoViews = data.views })
137 remoteSocket.emit('subscribe', { videoId })
138 }
139
140 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
141
142 await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
143 await waitJobs(servers)
144
145 expect(localLastVideoViews).to.equal(0)
146 expect(remoteLastVideoViews).to.equal(0)
147
148 await viewVideo(servers[0].url, liveVideoUUID)
149 await viewVideo(servers[1].url, liveVideoUUID)
150
151 await waitJobs(servers)
152 await wait(5000)
153 await waitJobs(servers)
154
155 expect(localLastVideoViews).to.equal(2)
156 expect(remoteLastVideoViews).to.equal(2)
157
158 await stopFfmpeg(command)
159 })
160
161 it('Should not receive a notification after unsubscribe', async function () {
162 this.timeout(120000)
163
164 const stateChanges: VideoState[] = []
165
166 const liveVideoUUID = await createLiveWrapper()
167 await waitJobs(servers)
168
169 const videoId = await getVideoIdFromUUID(servers[0].url, liveVideoUUID)
170
171 const socket = getLiveNotificationSocket(servers[0].url)
172 socket.on('state-change', data => stateChanges.push(data.state))
173 socket.emit('subscribe', { videoId })
174
175 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
176
177 await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
178 await waitJobs(servers)
179
180 // Notifier waits before sending a notification
181 await wait(10000)
182
183 expect(stateChanges).to.have.lengthOf(1)
184 socket.emit('unsubscribe', { videoId })
185
186 await stopFfmpeg(command)
187 await waitJobs(servers)
188
189 expect(stateChanges).to.have.lengthOf(1)
190 })
191 })
192
193 after(async function () {
194 await cleanupTests(servers)
195 })
196})
diff --git a/server/tests/api/live/live-views.ts b/server/tests/api/live/live-views.ts
new file mode 100644
index 000000000..a44d21ffa
--- /dev/null
+++ b/server/tests/api/live/live-views.ts
@@ -0,0 +1,130 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import { FfmpegCommand } from 'fluent-ffmpeg'
6import { VideoDetails, VideoPrivacy } from '@shared/models'
7import {
8 cleanupTests,
9 createLive,
10 doubleFollow,
11 flushAndRunMultipleServers,
12 getVideo,
13 sendRTMPStreamInVideo,
14 ServerInfo,
15 setAccessTokensToServers,
16 setDefaultVideoChannel,
17 stopFfmpeg,
18 updateCustomSubConfig,
19 viewVideo,
20 wait,
21 waitJobs,
22 waitUntilLivePublishedOnAllServers
23} from '../../../../shared/extra-utils'
24
25const expect = chai.expect
26
27describe('Test live', function () {
28 let servers: ServerInfo[] = []
29
30 before(async function () {
31 this.timeout(120000)
32
33 servers = await flushAndRunMultipleServers(2)
34
35 // Get the access tokens
36 await setAccessTokensToServers(servers)
37 await setDefaultVideoChannel(servers)
38
39 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
40 live: {
41 enabled: true,
42 allowReplay: true,
43 transcoding: {
44 enabled: false
45 }
46 }
47 })
48
49 // Server 1 and server 2 follow each other
50 await doubleFollow(servers[0], servers[1])
51 })
52
53 describe('Live views', function () {
54 let liveVideoId: string
55 let command: FfmpegCommand
56
57 async function countViews (expected: number) {
58 for (const server of servers) {
59 const res = await getVideo(server.url, liveVideoId)
60 const video: VideoDetails = res.body
61
62 expect(video.views).to.equal(expected)
63 }
64 }
65
66 before(async function () {
67 this.timeout(30000)
68
69 const liveAttributes = {
70 name: 'live video',
71 channelId: servers[0].videoChannel.id,
72 privacy: VideoPrivacy.PUBLIC
73 }
74
75 const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes)
76 liveVideoId = res.body.video.uuid
77
78 command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId)
79 await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
80 await waitJobs(servers)
81 })
82
83 it('Should display no views for a live', async function () {
84 await countViews(0)
85 })
86
87 it('Should view a live twice and display 1 view', async function () {
88 this.timeout(30000)
89
90 await viewVideo(servers[0].url, liveVideoId)
91 await viewVideo(servers[0].url, liveVideoId)
92
93 await wait(7000)
94
95 await waitJobs(servers)
96
97 await countViews(1)
98 })
99
100 it('Should wait and display 0 views', async function () {
101 this.timeout(30000)
102
103 await wait(12000)
104 await waitJobs(servers)
105
106 await countViews(0)
107 })
108
109 it('Should view a live on a remote and on local and display 2 views', async function () {
110 this.timeout(30000)
111
112 await viewVideo(servers[0].url, liveVideoId)
113 await viewVideo(servers[1].url, liveVideoId)
114 await viewVideo(servers[1].url, liveVideoId)
115
116 await wait(7000)
117 await waitJobs(servers)
118
119 await countViews(2)
120 })
121
122 after(async function () {
123 await stopFfmpeg(command)
124 })
125 })
126
127 after(async function () {
128 await cleanupTests(servers)
129 })
130})
diff --git a/server/tests/api/live/live.ts b/server/tests/api/live/live.ts
index 57fb58150..50397924e 100644
--- a/server/tests/api/live/live.ts
+++ b/server/tests/api/live/live.ts
@@ -2,10 +2,8 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { FfmpegCommand } from 'fluent-ffmpeg'
6import { join } from 'path' 5import { join } from 'path'
7import { ffprobePromise, getVideoStreamFromFile } from '@server/helpers/ffprobe-utils' 6import { ffprobePromise, getVideoStreamFromFile } from '@server/helpers/ffprobe-utils'
8import { getLiveNotificationSocket } from '@shared/extra-utils/socket/socket-io'
9import { LiveVideo, LiveVideoCreate, Video, VideoDetails, VideoPrivacy, VideoState, VideoStreamingPlaylistType } from '@shared/models' 7import { LiveVideo, LiveVideoCreate, Video, VideoDetails, VideoPrivacy, VideoState, VideoStreamingPlaylistType } from '@shared/models'
10import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 8import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
11import { 9import {
@@ -22,7 +20,6 @@ import {
22 getMyVideosWithFilter, 20 getMyVideosWithFilter,
23 getPlaylist, 21 getPlaylist,
24 getVideo, 22 getVideo,
25 getVideoIdFromUUID,
26 getVideosList, 23 getVideosList,
27 getVideosWithFilters, 24 getVideosWithFilters,
28 killallServers, 25 killallServers,
@@ -40,11 +37,11 @@ import {
40 updateCustomSubConfig, 37 updateCustomSubConfig,
41 updateLive, 38 updateLive,
42 uploadVideoAndGetId, 39 uploadVideoAndGetId,
43 viewVideo,
44 wait, 40 wait,
45 waitJobs, 41 waitJobs,
46 waitUntilLiveEnded, 42 waitUntilLiveEnded,
47 waitUntilLivePublished, 43 waitUntilLivePublished,
44 waitUntilLivePublishedOnAllServers,
48 waitUntilLiveSegmentGeneration 45 waitUntilLiveSegmentGeneration
49} from '../../../../shared/extra-utils' 46} from '../../../../shared/extra-utils'
50 47
@@ -53,12 +50,6 @@ const expect = chai.expect
53describe('Test live', function () { 50describe('Test live', function () {
54 let servers: ServerInfo[] = [] 51 let servers: ServerInfo[] = []
55 52
56 async function waitUntilLivePublishedOnAllServers (videoId: string) {
57 for (const server of servers) {
58 await waitUntilLivePublished(server.url, server.accessToken, videoId)
59 }
60 }
61
62 before(async function () { 53 before(async function () {
63 this.timeout(120000) 54 this.timeout(120000)
64 55
@@ -247,7 +238,7 @@ describe('Test live', function () {
247 liveVideoId = resLive.body.video.uuid 238 liveVideoId = resLive.body.video.uuid
248 239
249 command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId) 240 command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId)
250 await waitUntilLivePublishedOnAllServers(liveVideoId) 241 await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
251 await waitJobs(servers) 242 await waitJobs(servers)
252 }) 243 })
253 244
@@ -461,7 +452,7 @@ describe('Test live', function () {
461 liveVideoId = await createLiveWrapper(false) 452 liveVideoId = await createLiveWrapper(false)
462 453
463 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId) 454 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId)
464 await waitUntilLivePublishedOnAllServers(liveVideoId) 455 await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
465 await waitJobs(servers) 456 await waitJobs(servers)
466 457
467 await testVideoResolutions(liveVideoId, [ 720 ]) 458 await testVideoResolutions(liveVideoId, [ 720 ])
@@ -477,7 +468,7 @@ describe('Test live', function () {
477 liveVideoId = await createLiveWrapper(false) 468 liveVideoId = await createLiveWrapper(false)
478 469
479 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId) 470 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId)
480 await waitUntilLivePublishedOnAllServers(liveVideoId) 471 await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
481 await waitJobs(servers) 472 await waitJobs(servers)
482 473
483 await testVideoResolutions(liveVideoId, resolutions) 474 await testVideoResolutions(liveVideoId, resolutions)
@@ -494,7 +485,7 @@ describe('Test live', function () {
494 liveVideoId = await createLiveWrapper(true) 485 liveVideoId = await createLiveWrapper(true)
495 486
496 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId, 'video_short2.webm') 487 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId, 'video_short2.webm')
497 await waitUntilLivePublishedOnAllServers(liveVideoId) 488 await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
498 await waitJobs(servers) 489 await waitJobs(servers)
499 490
500 await testVideoResolutions(liveVideoId, resolutions) 491 await testVideoResolutions(liveVideoId, resolutions)
@@ -504,7 +495,7 @@ describe('Test live', function () {
504 495
505 await waitJobs(servers) 496 await waitJobs(servers)
506 497
507 await waitUntilLivePublishedOnAllServers(liveVideoId) 498 await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
508 499
509 const bitrateLimits = { 500 const bitrateLimits = {
510 720: 5000 * 1000, // 60FPS 501 720: 5000 * 1000, // 60FPS
@@ -559,216 +550,6 @@ describe('Test live', function () {
559 }) 550 })
560 }) 551 })
561 552
562 describe('Live views', function () {
563 let liveVideoId: string
564 let command: FfmpegCommand
565
566 async function countViews (expected: number) {
567 for (const server of servers) {
568 const res = await getVideo(server.url, liveVideoId)
569 const video: VideoDetails = res.body
570
571 expect(video.views).to.equal(expected)
572 }
573 }
574
575 before(async function () {
576 this.timeout(30000)
577
578 const liveAttributes = {
579 name: 'live video',
580 channelId: servers[0].videoChannel.id,
581 privacy: VideoPrivacy.PUBLIC
582 }
583
584 const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes)
585 liveVideoId = res.body.video.uuid
586
587 command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoId)
588 await waitUntilLivePublishedOnAllServers(liveVideoId)
589 await waitJobs(servers)
590 })
591
592 it('Should display no views for a live', async function () {
593 await countViews(0)
594 })
595
596 it('Should view a live twice and display 1 view', async function () {
597 this.timeout(30000)
598
599 await viewVideo(servers[0].url, liveVideoId)
600 await viewVideo(servers[0].url, liveVideoId)
601
602 await wait(7000)
603
604 await waitJobs(servers)
605
606 await countViews(1)
607 })
608
609 it('Should wait and display 0 views', async function () {
610 this.timeout(30000)
611
612 await wait(7000)
613 await waitJobs(servers)
614
615 await countViews(0)
616 })
617
618 it('Should view a live on a remote and on local and display 2 views', async function () {
619 this.timeout(30000)
620
621 await viewVideo(servers[0].url, liveVideoId)
622 await viewVideo(servers[1].url, liveVideoId)
623 await viewVideo(servers[1].url, liveVideoId)
624
625 await wait(7000)
626 await waitJobs(servers)
627
628 await countViews(2)
629 })
630
631 after(async function () {
632 await stopFfmpeg(command)
633 })
634 })
635
636 describe('Live socket messages', function () {
637
638 async function createLiveWrapper () {
639 const liveAttributes = {
640 name: 'live video',
641 channelId: servers[0].videoChannel.id,
642 privacy: VideoPrivacy.PUBLIC
643 }
644
645 const res = await createLive(servers[0].url, servers[0].accessToken, liveAttributes)
646 return res.body.video.uuid
647 }
648
649 it('Should correctly send a message when the live starts and ends', async function () {
650 this.timeout(60000)
651
652 const localStateChanges: VideoState[] = []
653 const remoteStateChanges: VideoState[] = []
654
655 const liveVideoUUID = await createLiveWrapper()
656 await waitJobs(servers)
657
658 {
659 const videoId = await getVideoIdFromUUID(servers[0].url, liveVideoUUID)
660
661 const localSocket = getLiveNotificationSocket(servers[0].url)
662 localSocket.on('state-change', data => localStateChanges.push(data.state))
663 localSocket.emit('subscribe', { videoId })
664 }
665
666 {
667 const videoId = await getVideoIdFromUUID(servers[1].url, liveVideoUUID)
668
669 const remoteSocket = getLiveNotificationSocket(servers[1].url)
670 remoteSocket.on('state-change', data => remoteStateChanges.push(data.state))
671 remoteSocket.emit('subscribe', { videoId })
672 }
673
674 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
675
676 await waitUntilLivePublishedOnAllServers(liveVideoUUID)
677 await waitJobs(servers)
678
679 for (const stateChanges of [ localStateChanges, remoteStateChanges ]) {
680 expect(stateChanges).to.have.length.at.least(1)
681 expect(stateChanges[stateChanges.length - 1]).to.equal(VideoState.PUBLISHED)
682 }
683
684 await stopFfmpeg(command)
685
686 for (const server of servers) {
687 await waitUntilLiveEnded(server.url, server.accessToken, liveVideoUUID)
688 }
689 await waitJobs(servers)
690
691 for (const stateChanges of [ localStateChanges, remoteStateChanges ]) {
692 expect(stateChanges).to.have.length.at.least(2)
693 expect(stateChanges[stateChanges.length - 1]).to.equal(VideoState.LIVE_ENDED)
694 }
695 })
696
697 it('Should correctly send views change notification', async function () {
698 this.timeout(60000)
699
700 let localLastVideoViews = 0
701 let remoteLastVideoViews = 0
702
703 const liveVideoUUID = await createLiveWrapper()
704 await waitJobs(servers)
705
706 {
707 const videoId = await getVideoIdFromUUID(servers[0].url, liveVideoUUID)
708
709 const localSocket = getLiveNotificationSocket(servers[0].url)
710 localSocket.on('views-change', data => { localLastVideoViews = data.views })
711 localSocket.emit('subscribe', { videoId })
712 }
713
714 {
715 const videoId = await getVideoIdFromUUID(servers[1].url, liveVideoUUID)
716
717 const remoteSocket = getLiveNotificationSocket(servers[1].url)
718 remoteSocket.on('views-change', data => { remoteLastVideoViews = data.views })
719 remoteSocket.emit('subscribe', { videoId })
720 }
721
722 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
723
724 await waitUntilLivePublishedOnAllServers(liveVideoUUID)
725 await waitJobs(servers)
726
727 expect(localLastVideoViews).to.equal(0)
728 expect(remoteLastVideoViews).to.equal(0)
729
730 await viewVideo(servers[0].url, liveVideoUUID)
731 await viewVideo(servers[1].url, liveVideoUUID)
732
733 await waitJobs(servers)
734 await wait(5000)
735 await waitJobs(servers)
736
737 expect(localLastVideoViews).to.equal(2)
738 expect(remoteLastVideoViews).to.equal(2)
739
740 await stopFfmpeg(command)
741 })
742
743 it('Should not receive a notification after unsubscribe', async function () {
744 this.timeout(60000)
745
746 const stateChanges: VideoState[] = []
747
748 const liveVideoUUID = await createLiveWrapper()
749 await waitJobs(servers)
750
751 const videoId = await getVideoIdFromUUID(servers[0].url, liveVideoUUID)
752
753 const socket = getLiveNotificationSocket(servers[0].url)
754 socket.on('state-change', data => stateChanges.push(data.state))
755 socket.emit('subscribe', { videoId })
756
757 const command = await sendRTMPStreamInVideo(servers[0].url, servers[0].accessToken, liveVideoUUID)
758
759 await waitUntilLivePublishedOnAllServers(liveVideoUUID)
760 await waitJobs(servers)
761
762 expect(stateChanges).to.have.lengthOf(1)
763 socket.emit('unsubscribe', { videoId })
764
765 await stopFfmpeg(command)
766 await waitJobs(servers)
767
768 expect(stateChanges).to.have.lengthOf(1)
769 })
770 })
771
772 describe('After a server restart', function () { 553 describe('After a server restart', function () {
773 let liveVideoId: string 554 let liveVideoId: string
774 let liveVideoReplayId: string 555 let liveVideoReplayId: string
diff --git a/server/tests/api/moderation/blocklist.ts b/server/tests/api/moderation/blocklist.ts
index e8202aff1..793abbcb4 100644
--- a/server/tests/api/moderation/blocklist.ts
+++ b/server/tests/api/moderation/blocklist.ts
@@ -1,46 +1,50 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
5import { AccountBlock, ServerBlock, Video, UserNotification, UserNotificationType } from '../../../../shared/index' 4import * as chai from 'chai'
6import { 5import {
6 addAccountToAccountBlocklist,
7 addAccountToServerBlocklist,
8 addServerToAccountBlocklist,
9 addServerToServerBlocklist,
10 addVideoCommentReply,
11 addVideoCommentThread,
7 cleanupTests, 12 cleanupTests,
8 createUser, 13 createUser,
9 deleteVideoComment, 14 deleteVideoComment,
10 doubleFollow, 15 doubleFollow,
16 findCommentId,
11 flushAndRunMultipleServers, 17 flushAndRunMultipleServers,
12 ServerInfo,
13 uploadVideo,
14 userLogin,
15 follow, 18 follow,
16 unfollow
17} from '../../../../shared/extra-utils/index'
18import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
19import { getVideosList, getVideosListWithToken } from '../../../../shared/extra-utils/videos/videos'
20import {
21 addVideoCommentReply,
22 addVideoCommentThread,
23 getVideoCommentThreads,
24 getVideoThreadComments,
25 findCommentId
26} from '../../../../shared/extra-utils/videos/video-comments'
27import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
28import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
29import {
30 addAccountToAccountBlocklist,
31 addAccountToServerBlocklist,
32 addServerToAccountBlocklist,
33 addServerToServerBlocklist,
34 getAccountBlocklistByAccount, 19 getAccountBlocklistByAccount,
35 getAccountBlocklistByServer, 20 getAccountBlocklistByServer,
36 getServerBlocklistByAccount, 21 getServerBlocklistByAccount,
37 getServerBlocklistByServer, 22 getServerBlocklistByServer,
23 getUserNotifications,
24 getVideoCommentThreads,
25 getVideosList,
26 getVideosListWithToken,
27 getVideoThreadComments,
38 removeAccountFromAccountBlocklist, 28 removeAccountFromAccountBlocklist,
39 removeAccountFromServerBlocklist, 29 removeAccountFromServerBlocklist,
40 removeServerFromAccountBlocklist, 30 removeServerFromAccountBlocklist,
41 removeServerFromServerBlocklist 31 removeServerFromServerBlocklist,
42} from '../../../../shared/extra-utils/users/blocklist' 32 ServerInfo,
43import { getUserNotifications } from '../../../../shared/extra-utils/users/user-notifications' 33 setAccessTokensToServers,
34 unfollow,
35 uploadVideo,
36 userLogin,
37 waitJobs
38} from '@shared/extra-utils'
39import {
40 AccountBlock,
41 ServerBlock,
42 UserNotification,
43 UserNotificationType,
44 Video,
45 VideoComment,
46 VideoCommentThreadTree
47} from '@shared/models'
44 48
45const expect = chai.expect 49const expect = chai.expect
46 50
@@ -211,7 +215,7 @@ describe('Test blocklist', function () {
211 215
212 const threads: VideoComment[] = resThreads.body.data 216 const threads: VideoComment[] = resThreads.body.data
213 expect(threads).to.have.lengthOf(1) 217 expect(threads).to.have.lengthOf(1)
214 expect(threads[0].totalReplies).to.equal(0) 218 expect(threads[0].totalReplies).to.equal(1)
215 219
216 const t = threads.find(t => t.text === 'comment user 1') 220 const t = threads.find(t => t.text === 'comment user 1')
217 expect(t).to.be.undefined 221 expect(t).to.be.undefined
@@ -561,7 +565,7 @@ describe('Test blocklist', function () {
561 threads = threads.filter(t => t.isDeleted === false) 565 threads = threads.filter(t => t.isDeleted === false)
562 566
563 expect(threads).to.have.lengthOf(1) 567 expect(threads).to.have.lengthOf(1)
564 expect(threads[0].totalReplies).to.equal(0) 568 expect(threads[0].totalReplies).to.equal(1)
565 569
566 const t = threads.find(t => t.text === 'comment user 1') 570 const t = threads.find(t => t.text === 'comment user 1')
567 expect(t).to.be.undefined 571 expect(t).to.be.undefined
diff --git a/server/tests/api/notifications/comments-notifications.ts b/server/tests/api/notifications/comments-notifications.ts
index 5e4ab0d6c..d2badf237 100644
--- a/server/tests/api/notifications/comments-notifications.ts
+++ b/server/tests/api/notifications/comments-notifications.ts
@@ -2,20 +2,25 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { cleanupTests, getVideoCommentThreads, getVideoThreadComments, updateMyUser } from '../../../../shared/extra-utils'
6import { ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index'
7import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
8import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
9import { addAccountToAccountBlocklist, removeAccountFromAccountBlocklist } from '../../../../shared/extra-utils/users/blocklist'
10import { 5import {
6 addAccountToAccountBlocklist,
7 addVideoCommentReply,
8 addVideoCommentThread,
11 checkCommentMention, 9 checkCommentMention,
12 CheckerBaseParams, 10 CheckerBaseParams,
13 checkNewCommentOnMyVideo, 11 checkNewCommentOnMyVideo,
14 prepareNotificationsTest 12 cleanupTests,
15} from '../../../../shared/extra-utils/users/user-notifications' 13 getVideoCommentThreads,
16import { addVideoCommentReply, addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments' 14 getVideoThreadComments,
17import { UserNotification } from '../../../../shared/models/users' 15 MockSmtpServer,
18import { VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' 16 prepareNotificationsTest,
17 removeAccountFromAccountBlocklist,
18 ServerInfo,
19 updateMyUser,
20 uploadVideo,
21 waitJobs
22} from '@shared/extra-utils'
23import { UserNotification, VideoCommentThreadTree } from '@shared/models'
19 24
20const expect = chai.expect 25const expect = chai.expect
21 26
diff --git a/server/tests/api/notifications/moderation-notifications.ts b/server/tests/api/notifications/moderation-notifications.ts
index 4ce6675b6..3425480ae 100644
--- a/server/tests/api/notifications/moderation-notifications.ts
+++ b/server/tests/api/notifications/moderation-notifications.ts
@@ -1,7 +1,7 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { v4 as uuidv4 } from 'uuid' 4import { buildUUID } from '@server/helpers/uuid'
5import { AbuseState } from '@shared/models' 5import { AbuseState } from '@shared/models'
6import { 6import {
7 addAbuseMessage, 7 addAbuseMessage,
@@ -85,7 +85,7 @@ describe('Test moderation notifications', function () {
85 it('Should send a notification to moderators on local video abuse', async function () { 85 it('Should send a notification to moderators on local video abuse', async function () {
86 this.timeout(20000) 86 this.timeout(20000)
87 87
88 const name = 'video for abuse ' + uuidv4() 88 const name = 'video for abuse ' + buildUUID()
89 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) 89 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
90 const video = resVideo.body.video 90 const video = resVideo.body.video
91 91
@@ -98,7 +98,7 @@ describe('Test moderation notifications', function () {
98 it('Should send a notification to moderators on remote video abuse', async function () { 98 it('Should send a notification to moderators on remote video abuse', async function () {
99 this.timeout(20000) 99 this.timeout(20000)
100 100
101 const name = 'video for abuse ' + uuidv4() 101 const name = 'video for abuse ' + buildUUID()
102 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) 102 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
103 const video = resVideo.body.video 103 const video = resVideo.body.video
104 104
@@ -114,10 +114,10 @@ describe('Test moderation notifications', function () {
114 it('Should send a notification to moderators on local comment abuse', async function () { 114 it('Should send a notification to moderators on local comment abuse', async function () {
115 this.timeout(20000) 115 this.timeout(20000)
116 116
117 const name = 'video for abuse ' + uuidv4() 117 const name = 'video for abuse ' + buildUUID()
118 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) 118 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
119 const video = resVideo.body.video 119 const video = resVideo.body.video
120 const resComment = await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + uuidv4()) 120 const resComment = await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + buildUUID())
121 const comment = resComment.body.comment 121 const comment = resComment.body.comment
122 122
123 await waitJobs(servers) 123 await waitJobs(servers)
@@ -131,10 +131,10 @@ describe('Test moderation notifications', function () {
131 it('Should send a notification to moderators on remote comment abuse', async function () { 131 it('Should send a notification to moderators on remote comment abuse', async function () {
132 this.timeout(20000) 132 this.timeout(20000)
133 133
134 const name = 'video for abuse ' + uuidv4() 134 const name = 'video for abuse ' + buildUUID()
135 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) 135 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
136 const video = resVideo.body.video 136 const video = resVideo.body.video
137 await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + uuidv4()) 137 await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + buildUUID())
138 138
139 await waitJobs(servers) 139 await waitJobs(servers)
140 140
@@ -188,7 +188,7 @@ describe('Test moderation notifications', function () {
188 token: userAccessToken 188 token: userAccessToken
189 } 189 }
190 190
191 const name = 'abuse ' + uuidv4() 191 const name = 'abuse ' + buildUUID()
192 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) 192 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
193 const video = resVideo.body.video 193 const video = resVideo.body.video
194 194
@@ -236,7 +236,7 @@ describe('Test moderation notifications', function () {
236 token: servers[0].accessToken 236 token: servers[0].accessToken
237 } 237 }
238 238
239 const name = 'abuse ' + uuidv4() 239 const name = 'abuse ' + buildUUID()
240 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) 240 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
241 const video = resVideo.body.video 241 const video = resVideo.body.video
242 242
@@ -307,7 +307,7 @@ describe('Test moderation notifications', function () {
307 it('Should send a notification to video owner on blacklist', async function () { 307 it('Should send a notification to video owner on blacklist', async function () {
308 this.timeout(10000) 308 this.timeout(10000)
309 309
310 const name = 'video for abuse ' + uuidv4() 310 const name = 'video for abuse ' + buildUUID()
311 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) 311 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
312 const uuid = resVideo.body.video.uuid 312 const uuid = resVideo.body.video.uuid
313 313
@@ -320,7 +320,7 @@ describe('Test moderation notifications', function () {
320 it('Should send a notification to video owner on unblacklist', async function () { 320 it('Should send a notification to video owner on unblacklist', async function () {
321 this.timeout(10000) 321 this.timeout(10000)
322 322
323 const name = 'video for abuse ' + uuidv4() 323 const name = 'video for abuse ' + buildUUID()
324 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name }) 324 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
325 const uuid = resVideo.body.video.uuid 325 const uuid = resVideo.body.video.uuid
326 326
@@ -507,7 +507,7 @@ describe('Test moderation notifications', function () {
507 it('Should send notification to moderators on new video with auto-blacklist', async function () { 507 it('Should send notification to moderators on new video with auto-blacklist', async function () {
508 this.timeout(40000) 508 this.timeout(40000)
509 509
510 videoName = 'video with auto-blacklist ' + uuidv4() 510 videoName = 'video with auto-blacklist ' + buildUUID()
511 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: videoName }) 511 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: videoName })
512 videoUUID = resVideo.body.video.uuid 512 videoUUID = resVideo.body.video.uuid
513 513
@@ -553,7 +553,7 @@ describe('Test moderation notifications', function () {
553 553
554 const updateAt = new Date(new Date().getTime() + 1000000) 554 const updateAt = new Date(new Date().getTime() + 1000000)
555 555
556 const name = 'video with auto-blacklist and future schedule ' + uuidv4() 556 const name = 'video with auto-blacklist and future schedule ' + buildUUID()
557 557
558 const data = { 558 const data = {
559 name, 559 name,
@@ -586,7 +586,7 @@ describe('Test moderation notifications', function () {
586 // In 2 seconds 586 // In 2 seconds
587 const updateAt = new Date(new Date().getTime() + 2000) 587 const updateAt = new Date(new Date().getTime() + 2000)
588 588
589 const name = 'video with schedule done and still auto-blacklisted ' + uuidv4() 589 const name = 'video with schedule done and still auto-blacklisted ' + buildUUID()
590 590
591 const data = { 591 const data = {
592 name, 592 name,
@@ -609,7 +609,7 @@ describe('Test moderation notifications', function () {
609 it('Should not send a notification to moderators on new video without auto-blacklist', async function () { 609 it('Should not send a notification to moderators on new video without auto-blacklist', async function () {
610 this.timeout(60000) 610 this.timeout(60000)
611 611
612 const name = 'video without auto-blacklist ' + uuidv4() 612 const name = 'video without auto-blacklist ' + buildUUID()
613 613
614 // admin with blacklist right will not be auto-blacklisted 614 // admin with blacklist right will not be auto-blacklisted
615 const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name }) 615 const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name })
diff --git a/server/tests/api/notifications/user-notifications.ts b/server/tests/api/notifications/user-notifications.ts
index 7e88d979b..e981c1718 100644
--- a/server/tests/api/notifications/user-notifications.ts
+++ b/server/tests/api/notifications/user-notifications.ts
@@ -2,7 +2,7 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { v4 as uuidv4 } from 'uuid' 5import { buildUUID } from '@server/helpers/uuid'
6import { 6import {
7 cleanupTests, 7 cleanupTests,
8 updateMyUser, 8 updateMyUser,
@@ -207,7 +207,7 @@ describe('Test user notifications', function () {
207 it('Should send a new video notification after a video import', async function () { 207 it('Should send a new video notification after a video import', async function () {
208 this.timeout(100000) 208 this.timeout(100000)
209 209
210 const name = 'video import ' + uuidv4() 210 const name = 'video import ' + buildUUID()
211 211
212 const attributes = { 212 const attributes = {
213 name, 213 name,
@@ -278,7 +278,7 @@ describe('Test user notifications', function () {
278 it('Should send a notification when an imported video is transcoded', async function () { 278 it('Should send a notification when an imported video is transcoded', async function () {
279 this.timeout(50000) 279 this.timeout(50000)
280 280
281 const name = 'video import ' + uuidv4() 281 const name = 'video import ' + buildUUID()
282 282
283 const attributes = { 283 const attributes = {
284 name, 284 name,
@@ -347,7 +347,7 @@ describe('Test user notifications', function () {
347 it('Should send a notification when the video import failed', async function () { 347 it('Should send a notification when the video import failed', async function () {
348 this.timeout(70000) 348 this.timeout(70000)
349 349
350 const name = 'video import ' + uuidv4() 350 const name = 'video import ' + buildUUID()
351 351
352 const attributes = { 352 const attributes = {
353 name, 353 name,
@@ -365,7 +365,7 @@ describe('Test user notifications', function () {
365 it('Should send a notification when the video import succeeded', async function () { 365 it('Should send a notification when the video import succeeded', async function () {
366 this.timeout(70000) 366 this.timeout(70000)
367 367
368 const name = 'video import ' + uuidv4() 368 const name = 'video import ' + buildUUID()
369 369
370 const attributes = { 370 const attributes = {
371 name, 371 name,
diff --git a/server/tests/api/search/index.ts b/server/tests/api/search/index.ts
index 232c1f2a4..a976d210d 100644
--- a/server/tests/api/search/index.ts
+++ b/server/tests/api/search/index.ts
@@ -1,5 +1,7 @@
1import './search-activitypub-video-playlists'
1import './search-activitypub-video-channels' 2import './search-activitypub-video-channels'
2import './search-activitypub-videos' 3import './search-activitypub-videos'
4import './search-channels'
3import './search-index' 5import './search-index'
6import './search-playlists'
4import './search-videos' 7import './search-videos'
5import './search-channels'
diff --git a/server/tests/api/search/search-activitypub-video-channels.ts b/server/tests/api/search/search-activitypub-video-channels.ts
index d7e3ed5be..e83eb7171 100644
--- a/server/tests/api/search/search-activitypub-video-channels.ts
+++ b/server/tests/api/search/search-activitypub-video-channels.ts
@@ -106,9 +106,25 @@ describe('Test ActivityPub video channels search', function () {
106 } 106 }
107 }) 107 })
108 108
109 it('Should search a local video channel with an alternative URL', async function () {
110 const search = 'http://localhost:' + servers[0].port + '/c/channel1_server1'
111
112 for (const token of [ undefined, servers[0].accessToken ]) {
113 const res = await searchVideoChannel(servers[0].url, search, token)
114
115 expect(res.body.total).to.equal(1)
116 expect(res.body.data).to.be.an('array')
117 expect(res.body.data).to.have.lengthOf(1)
118 expect(res.body.data[0].name).to.equal('channel1_server1')
119 expect(res.body.data[0].displayName).to.equal('Channel 1 server 1')
120 }
121 })
122
109 it('Should search a remote video channel with URL or handle', async function () { 123 it('Should search a remote video channel with URL or handle', async function () {
110 const searches = [ 124 const searches = [
111 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2', 125 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2',
126 'http://localhost:' + servers[1].port + '/c/channel1_server2',
127 'http://localhost:' + servers[1].port + '/c/channel1_server2/videos',
112 'channel1_server2@localhost:' + servers[1].port 128 'channel1_server2@localhost:' + servers[1].port
113 ] 129 ]
114 130
diff --git a/server/tests/api/search/search-activitypub-video-playlists.ts b/server/tests/api/search/search-activitypub-video-playlists.ts
new file mode 100644
index 000000000..4c08e9548
--- /dev/null
+++ b/server/tests/api/search/search-activitypub-video-playlists.ts
@@ -0,0 +1,212 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import {
6 addVideoInPlaylist,
7 cleanupTests,
8 createVideoPlaylist,
9 deleteVideoPlaylist,
10 flushAndRunMultipleServers,
11 getVideoPlaylistsList,
12 searchVideoPlaylists,
13 ServerInfo,
14 setAccessTokensToServers,
15 setDefaultVideoChannel,
16 uploadVideoAndGetId,
17 wait
18} from '../../../../shared/extra-utils'
19import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
20import { VideoPlaylist, VideoPlaylistPrivacy } from '../../../../shared/models/videos'
21
22const expect = chai.expect
23
24describe('Test ActivityPub playlists search', function () {
25 let servers: ServerInfo[]
26 let playlistServer1UUID: string
27 let playlistServer2UUID: string
28 let video2Server2: string
29
30 before(async function () {
31 this.timeout(120000)
32
33 servers = await flushAndRunMultipleServers(2)
34
35 await setAccessTokensToServers(servers)
36 await setDefaultVideoChannel(servers)
37
38 {
39 const video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 1' })).uuid
40 const video2 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 2' })).uuid
41
42 const attributes = {
43 displayName: 'playlist 1 on server 1',
44 privacy: VideoPlaylistPrivacy.PUBLIC,
45 videoChannelId: servers[0].videoChannel.id
46 }
47 const res = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs: attributes })
48 playlistServer1UUID = res.body.videoPlaylist.uuid
49
50 for (const videoId of [ video1, video2 ]) {
51 await addVideoInPlaylist({
52 url: servers[0].url,
53 token: servers[0].accessToken,
54 playlistId: playlistServer1UUID,
55 elementAttrs: { videoId }
56 })
57 }
58 }
59
60 {
61 const videoId = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 1' })).uuid
62 video2Server2 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 2' })).uuid
63
64 const attributes = {
65 displayName: 'playlist 1 on server 2',
66 privacy: VideoPlaylistPrivacy.PUBLIC,
67 videoChannelId: servers[1].videoChannel.id
68 }
69 const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs: attributes })
70 playlistServer2UUID = res.body.videoPlaylist.uuid
71
72 await addVideoInPlaylist({
73 url: servers[1].url,
74 token: servers[1].accessToken,
75 playlistId: playlistServer2UUID,
76 elementAttrs: { videoId }
77 })
78 }
79
80 await waitJobs(servers)
81 })
82
83 it('Should not find a remote playlist', async function () {
84 {
85 const search = 'http://localhost:' + servers[1].port + '/video-playlists/43'
86 const res = await searchVideoPlaylists(servers[0].url, search, servers[0].accessToken)
87
88 expect(res.body.total).to.equal(0)
89 expect(res.body.data).to.be.an('array')
90 expect(res.body.data).to.have.lengthOf(0)
91 }
92
93 {
94 // Without token
95 const search = 'http://localhost:' + servers[1].port + '/video-playlists/' + playlistServer2UUID
96 const res = await searchVideoPlaylists(servers[0].url, search)
97
98 expect(res.body.total).to.equal(0)
99 expect(res.body.data).to.be.an('array')
100 expect(res.body.data).to.have.lengthOf(0)
101 }
102 })
103
104 it('Should search a local playlist', async function () {
105 const search = 'http://localhost:' + servers[0].port + '/video-playlists/' + playlistServer1UUID
106 const res = await searchVideoPlaylists(servers[0].url, search)
107
108 expect(res.body.total).to.equal(1)
109 expect(res.body.data).to.be.an('array')
110 expect(res.body.data).to.have.lengthOf(1)
111 expect(res.body.data[0].displayName).to.equal('playlist 1 on server 1')
112 expect(res.body.data[0].videosLength).to.equal(2)
113 })
114
115 it('Should search a local playlist with an alternative URL', async function () {
116 const searches = [
117 'http://localhost:' + servers[0].port + '/videos/watch/playlist/' + playlistServer1UUID,
118 'http://localhost:' + servers[0].port + '/w/p/' + playlistServer1UUID
119 ]
120
121 for (const search of searches) {
122 for (const token of [ undefined, servers[0].accessToken ]) {
123 const res = await searchVideoPlaylists(servers[0].url, search, token)
124
125 expect(res.body.total).to.equal(1)
126 expect(res.body.data).to.be.an('array')
127 expect(res.body.data).to.have.lengthOf(1)
128 expect(res.body.data[0].displayName).to.equal('playlist 1 on server 1')
129 expect(res.body.data[0].videosLength).to.equal(2)
130 }
131 }
132 })
133
134 it('Should search a remote playlist', async function () {
135 const searches = [
136 'http://localhost:' + servers[1].port + '/video-playlists/' + playlistServer2UUID,
137 'http://localhost:' + servers[1].port + '/videos/watch/playlist/' + playlistServer2UUID,
138 'http://localhost:' + servers[1].port + '/w/p/' + playlistServer2UUID
139 ]
140
141 for (const search of searches) {
142 const res = await searchVideoPlaylists(servers[0].url, search, servers[0].accessToken)
143
144 expect(res.body.total).to.equal(1)
145 expect(res.body.data).to.be.an('array')
146 expect(res.body.data).to.have.lengthOf(1)
147 expect(res.body.data[0].displayName).to.equal('playlist 1 on server 2')
148 expect(res.body.data[0].videosLength).to.equal(1)
149 }
150 })
151
152 it('Should not list this remote playlist', async function () {
153 const res = await getVideoPlaylistsList(servers[0].url, 0, 10)
154 expect(res.body.total).to.equal(1)
155 expect(res.body.data).to.have.lengthOf(1)
156 expect(res.body.data[0].displayName).to.equal('playlist 1 on server 1')
157 })
158
159 it('Should update the playlist of server 2, and refresh it on server 1', async function () {
160 this.timeout(60000)
161
162 await addVideoInPlaylist({
163 url: servers[1].url,
164 token: servers[1].accessToken,
165 playlistId: playlistServer2UUID,
166 elementAttrs: { videoId: video2Server2 }
167 })
168
169 await waitJobs(servers)
170 // Expire playlist
171 await wait(10000)
172
173 // Will run refresh async
174 const search = 'http://localhost:' + servers[1].port + '/video-playlists/' + playlistServer2UUID
175 await searchVideoPlaylists(servers[0].url, search, servers[0].accessToken)
176
177 // Wait refresh
178 await wait(5000)
179
180 const res = await searchVideoPlaylists(servers[0].url, search, servers[0].accessToken)
181 expect(res.body.total).to.equal(1)
182 expect(res.body.data).to.have.lengthOf(1)
183
184 const playlist: VideoPlaylist = res.body.data[0]
185 expect(playlist.videosLength).to.equal(2)
186 })
187
188 it('Should delete playlist of server 2, and delete it on server 1', async function () {
189 this.timeout(60000)
190
191 await deleteVideoPlaylist(servers[1].url, servers[1].accessToken, playlistServer2UUID)
192
193 await waitJobs(servers)
194 // Expiration
195 await wait(10000)
196
197 // Will run refresh async
198 const search = 'http://localhost:' + servers[1].port + '/video-playlists/' + playlistServer2UUID
199 await searchVideoPlaylists(servers[0].url, search, servers[0].accessToken)
200
201 // Wait refresh
202 await wait(5000)
203
204 const res = await searchVideoPlaylists(servers[0].url, search, servers[0].accessToken)
205 expect(res.body.total).to.equal(0)
206 expect(res.body.data).to.have.lengthOf(0)
207 })
208
209 after(async function () {
210 await cleanupTests(servers)
211 })
212})
diff --git a/server/tests/api/search/search-activitypub-videos.ts b/server/tests/api/search/search-activitypub-videos.ts
index c62dfca0d..e9b4978da 100644
--- a/server/tests/api/search/search-activitypub-videos.ts
+++ b/server/tests/api/search/search-activitypub-videos.ts
@@ -77,14 +77,33 @@ describe('Test ActivityPub videos search', function () {
77 expect(res.body.data[0].name).to.equal('video 1 on server 1') 77 expect(res.body.data[0].name).to.equal('video 1 on server 1')
78 }) 78 })
79 79
80 it('Should search a local video with an alternative URL', async function () {
81 const search = 'http://localhost:' + servers[0].port + '/w/' + videoServer1UUID
82 const res1 = await searchVideo(servers[0].url, search)
83 const res2 = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
84
85 for (const res of [ res1, res2 ]) {
86 expect(res.body.total).to.equal(1)
87 expect(res.body.data).to.be.an('array')
88 expect(res.body.data).to.have.lengthOf(1)
89 expect(res.body.data[0].name).to.equal('video 1 on server 1')
90 }
91 })
92
80 it('Should search a remote video', async function () { 93 it('Should search a remote video', async function () {
81 const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID 94 const searches = [
82 const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken) 95 'http://localhost:' + servers[1].port + '/w/' + videoServer2UUID,
96 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID
97 ]
83 98
84 expect(res.body.total).to.equal(1) 99 for (const search of searches) {
85 expect(res.body.data).to.be.an('array') 100 const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
86 expect(res.body.data).to.have.lengthOf(1) 101
87 expect(res.body.data[0].name).to.equal('video 1 on server 2') 102 expect(res.body.total).to.equal(1)
103 expect(res.body.data).to.be.an('array')
104 expect(res.body.data).to.have.lengthOf(1)
105 expect(res.body.data[0].name).to.equal('video 1 on server 2')
106 }
88 }) 107 })
89 108
90 it('Should not list this remote video', async function () { 109 it('Should not list this remote video', async function () {
@@ -95,7 +114,7 @@ describe('Test ActivityPub videos search', function () {
95 }) 114 })
96 115
97 it('Should update video of server 2, and refresh it on server 1', async function () { 116 it('Should update video of server 2, and refresh it on server 1', async function () {
98 this.timeout(60000) 117 this.timeout(120000)
99 118
100 const channelAttributes = { 119 const channelAttributes = {
101 name: 'super_channel', 120 name: 'super_channel',
@@ -134,7 +153,7 @@ describe('Test ActivityPub videos search', function () {
134 }) 153 })
135 154
136 it('Should delete video of server 2, and delete it on server 1', async function () { 155 it('Should delete video of server 2, and delete it on server 1', async function () {
137 this.timeout(60000) 156 this.timeout(120000)
138 157
139 await removeVideo(servers[1].url, servers[1].accessToken, videoServer2UUID) 158 await removeVideo(servers[1].url, servers[1].accessToken, videoServer2UUID)
140 159
diff --git a/server/tests/api/search/search-index.ts b/server/tests/api/search/search-index.ts
index 849a8a893..00f79232a 100644
--- a/server/tests/api/search/search-index.ts
+++ b/server/tests/api/search/search-index.ts
@@ -2,19 +2,21 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { advancedVideoChannelSearch, searchVideoChannel } from '@shared/extra-utils/search/video-channels'
6import { Video, VideoChannel, VideoPlaylist, VideoPlaylistPrivacy, VideoPlaylistType, VideosSearchQuery } from '@shared/models'
5import { 7import {
8 advancedVideoPlaylistSearch,
9 advancedVideosSearch,
6 cleanupTests, 10 cleanupTests,
7 flushAndRunServer, 11 flushAndRunServer,
12 immutableAssign,
8 searchVideo, 13 searchVideo,
14 searchVideoPlaylists,
9 ServerInfo, 15 ServerInfo,
10 setAccessTokensToServers, 16 setAccessTokensToServers,
11 updateCustomSubConfig, 17 updateCustomSubConfig,
12 uploadVideo, 18 uploadVideo
13 advancedVideosSearch,
14 immutableAssign
15} from '../../../../shared/extra-utils' 19} from '../../../../shared/extra-utils'
16import { searchVideoChannel, advancedVideoChannelSearch } from '@shared/extra-utils/search/video-channels'
17import { VideosSearchQuery, Video, VideoChannel } from '@shared/models'
18 20
19const expect = chai.expect 21const expect = chai.expect
20 22
@@ -277,6 +279,56 @@ describe('Test videos search', function () {
277 }) 279 })
278 }) 280 })
279 281
282 describe('Playlists search', async function () {
283
284 it('Should make a simple search and not have results', async function () {
285 const res = await searchVideoPlaylists(server.url, 'a'.repeat(500))
286
287 expect(res.body.total).to.equal(0)
288 expect(res.body.data).to.have.lengthOf(0)
289 })
290
291 it('Should make a search and have results', async function () {
292 const res = await advancedVideoPlaylistSearch(server.url, { search: 'E2E playlist', sort: '-match' })
293
294 expect(res.body.total).to.be.greaterThan(0)
295 expect(res.body.data).to.have.length.greaterThan(0)
296
297 const videoPlaylist: VideoPlaylist = res.body.data[0]
298
299 expect(videoPlaylist.url).to.equal('https://peertube2.cpy.re/videos/watch/playlist/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a')
300 expect(videoPlaylist.thumbnailUrl).to.exist
301 expect(videoPlaylist.embedUrl).to.equal('https://peertube2.cpy.re/video-playlists/embed/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a')
302
303 expect(videoPlaylist.type.id).to.equal(VideoPlaylistType.REGULAR)
304 expect(videoPlaylist.privacy.id).to.equal(VideoPlaylistPrivacy.PUBLIC)
305 expect(videoPlaylist.videosLength).to.exist
306
307 expect(videoPlaylist.createdAt).to.exist
308 expect(videoPlaylist.updatedAt).to.exist
309
310 expect(videoPlaylist.uuid).to.equal('73804a40-da9a-40c2-b1eb-2c6d9eec8f0a')
311 expect(videoPlaylist.displayName).to.exist
312
313 expect(videoPlaylist.ownerAccount.url).to.equal('https://peertube2.cpy.re/accounts/chocobozzz')
314 expect(videoPlaylist.ownerAccount.name).to.equal('chocobozzz')
315 expect(videoPlaylist.ownerAccount.host).to.equal('peertube2.cpy.re')
316 expect(videoPlaylist.ownerAccount.avatar).to.exist
317
318 expect(videoPlaylist.videoChannel.url).to.equal('https://peertube2.cpy.re/video-channels/chocobozzz_channel')
319 expect(videoPlaylist.videoChannel.name).to.equal('chocobozzz_channel')
320 expect(videoPlaylist.videoChannel.host).to.equal('peertube2.cpy.re')
321 expect(videoPlaylist.videoChannel.avatar).to.exist
322 })
323
324 it('Should have a correct pagination', async function () {
325 const res = await advancedVideoChannelSearch(server.url, { search: 'root', start: 0, count: 2 })
326
327 expect(res.body.total).to.be.greaterThan(2)
328 expect(res.body.data).to.have.lengthOf(2)
329 })
330 })
331
280 after(async function () { 332 after(async function () {
281 await cleanupTests([ server ]) 333 await cleanupTests([ server ])
282 }) 334 })
diff --git a/server/tests/api/search/search-playlists.ts b/server/tests/api/search/search-playlists.ts
new file mode 100644
index 000000000..ab17d55e9
--- /dev/null
+++ b/server/tests/api/search/search-playlists.ts
@@ -0,0 +1,128 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import { VideoPlaylist, VideoPlaylistPrivacy } from '@shared/models'
6import {
7 addVideoInPlaylist,
8 advancedVideoPlaylistSearch,
9 cleanupTests,
10 createVideoPlaylist,
11 flushAndRunServer,
12 searchVideoPlaylists,
13 ServerInfo,
14 setAccessTokensToServers,
15 setDefaultVideoChannel,
16 uploadVideoAndGetId
17} from '../../../../shared/extra-utils'
18
19const expect = chai.expect
20
21describe('Test playlists search', function () {
22 let server: ServerInfo = null
23
24 before(async function () {
25 this.timeout(30000)
26
27 server = await flushAndRunServer(1)
28
29 await setAccessTokensToServers([ server ])
30 await setDefaultVideoChannel([ server ])
31
32 const videoId = (await uploadVideoAndGetId({ server: server, videoName: 'video' })).uuid
33
34 {
35 const attributes = {
36 displayName: 'Dr. Kenzo Tenma hospital videos',
37 privacy: VideoPlaylistPrivacy.PUBLIC,
38 videoChannelId: server.videoChannel.id
39 }
40 const res = await createVideoPlaylist({ url: server.url, token: server.accessToken, playlistAttrs: attributes })
41
42 await addVideoInPlaylist({
43 url: server.url,
44 token: server.accessToken,
45 playlistId: res.body.videoPlaylist.id,
46 elementAttrs: { videoId }
47 })
48 }
49
50 {
51 const attributes = {
52 displayName: 'Johan & Anna Libert musics',
53 privacy: VideoPlaylistPrivacy.PUBLIC,
54 videoChannelId: server.videoChannel.id
55 }
56 const res = await createVideoPlaylist({ url: server.url, token: server.accessToken, playlistAttrs: attributes })
57
58 await addVideoInPlaylist({
59 url: server.url,
60 token: server.accessToken,
61 playlistId: res.body.videoPlaylist.id,
62 elementAttrs: { videoId }
63 })
64 }
65
66 {
67 const attributes = {
68 displayName: 'Inspector Lunge playlist',
69 privacy: VideoPlaylistPrivacy.PUBLIC,
70 videoChannelId: server.videoChannel.id
71 }
72 await createVideoPlaylist({ url: server.url, token: server.accessToken, playlistAttrs: attributes })
73 }
74 })
75
76 it('Should make a simple search and not have results', async function () {
77 const res = await searchVideoPlaylists(server.url, 'abc')
78
79 expect(res.body.total).to.equal(0)
80 expect(res.body.data).to.have.lengthOf(0)
81 })
82
83 it('Should make a search and have results', async function () {
84 {
85 const search = {
86 search: 'tenma',
87 start: 0,
88 count: 1
89 }
90 const res = await advancedVideoPlaylistSearch(server.url, search)
91 expect(res.body.total).to.equal(1)
92 expect(res.body.data).to.have.lengthOf(1)
93
94 const playlist: VideoPlaylist = res.body.data[0]
95 expect(playlist.displayName).to.equal('Dr. Kenzo Tenma hospital videos')
96 expect(playlist.url).to.equal(server.url + '/video-playlists/' + playlist.uuid)
97 }
98
99 {
100 const search = {
101 search: 'Anna Livert',
102 start: 0,
103 count: 1
104 }
105 const res = await advancedVideoPlaylistSearch(server.url, search)
106 expect(res.body.total).to.equal(1)
107 expect(res.body.data).to.have.lengthOf(1)
108
109 const playlist: VideoPlaylist = res.body.data[0]
110 expect(playlist.displayName).to.equal('Johan & Anna Libert musics')
111 }
112 })
113
114 it('Should not display playlists without videos', async function () {
115 const search = {
116 search: 'Lunge',
117 start: 0,
118 count: 1
119 }
120 const res = await advancedVideoPlaylistSearch(server.url, search)
121 expect(res.body.total).to.equal(0)
122 expect(res.body.data).to.have.lengthOf(0)
123 })
124
125 after(async function () {
126 await cleanupTests([ server ])
127 })
128})
diff --git a/server/tests/api/server/bulk.ts b/server/tests/api/server/bulk.ts
index 51ba0e7af..80fa7fce6 100644
--- a/server/tests/api/server/bulk.ts
+++ b/server/tests/api/server/bulk.ts
@@ -2,12 +2,14 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { VideoComment } from '@shared/models/videos/video-comment.model' 5import { Video, VideoComment } from '@shared/models'
6import { 6import {
7 addVideoCommentReply,
7 addVideoCommentThread, 8 addVideoCommentThread,
8 bulkRemoveCommentsOf, 9 bulkRemoveCommentsOf,
9 cleanupTests, 10 cleanupTests,
10 createUser, 11 createUser,
12 doubleFollow,
11 flushAndRunMultipleServers, 13 flushAndRunMultipleServers,
12 getVideoCommentThreads, 14 getVideoCommentThreads,
13 getVideosList, 15 getVideosList,
@@ -15,11 +17,8 @@ import {
15 setAccessTokensToServers, 17 setAccessTokensToServers,
16 uploadVideo, 18 uploadVideo,
17 userLogin, 19 userLogin,
18 waitJobs, 20 waitJobs
19 addVideoCommentReply
20} from '../../../../shared/extra-utils/index' 21} from '../../../../shared/extra-utils/index'
21import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
22import { Video } from '@shared/models'
23 22
24const expect = chai.expect 23const expect = chai.expect
25 24
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts
index 1d9ea31df..19bf9582c 100644
--- a/server/tests/api/server/config.ts
+++ b/server/tests/api/server/config.ts
@@ -60,6 +60,7 @@ function checkInitialConfig (server: ServerInfo, data: CustomConfig) {
60 60
61 expect(data.signup.enabled).to.be.true 61 expect(data.signup.enabled).to.be.true
62 expect(data.signup.limit).to.equal(4) 62 expect(data.signup.limit).to.equal(4)
63 expect(data.signup.minimumAge).to.equal(16)
63 expect(data.signup.requiresEmailVerification).to.be.false 64 expect(data.signup.requiresEmailVerification).to.be.false
64 65
65 expect(data.admin.email).to.equal('admin' + server.internalServerNumber + '@example.com') 66 expect(data.admin.email).to.equal('admin' + server.internalServerNumber + '@example.com')
@@ -151,6 +152,7 @@ function checkUpdatedConfig (data: CustomConfig) {
151 expect(data.signup.enabled).to.be.false 152 expect(data.signup.enabled).to.be.false
152 expect(data.signup.limit).to.equal(5) 153 expect(data.signup.limit).to.equal(5)
153 expect(data.signup.requiresEmailVerification).to.be.false 154 expect(data.signup.requiresEmailVerification).to.be.false
155 expect(data.signup.minimumAge).to.equal(10)
154 156
155 // We override admin email in parallel tests, so skip this exception 157 // We override admin email in parallel tests, so skip this exception
156 if (parallelTests() === false) { 158 if (parallelTests() === false) {
@@ -316,7 +318,8 @@ describe('Test config', function () {
316 signup: { 318 signup: {
317 enabled: false, 319 enabled: false,
318 limit: 5, 320 limit: 5,
319 requiresEmailVerification: false 321 requiresEmailVerification: false,
322 minimumAge: 10
320 }, 323 },
321 admin: { 324 admin: {
322 email: 'superadmin1@example.com' 325 email: 'superadmin1@example.com'
diff --git a/server/tests/api/server/contact-form.ts b/server/tests/api/server/contact-form.ts
index 9b4af1915..8851ad55e 100644
--- a/server/tests/api/server/contact-form.ts
+++ b/server/tests/api/server/contact-form.ts
@@ -54,6 +54,10 @@ describe('Test contact form', function () {
54 }) 54 })
55 55
56 it('Should not be able to send another contact form because of the anti spam checker', async function () { 56 it('Should not be able to send another contact form because of the anti spam checker', async function () {
57 this.timeout(10000)
58
59 await wait(1000)
60
57 await sendContactForm({ 61 await sendContactForm({
58 url: server.url, 62 url: server.url,
59 fromEmail: 'toto@example.com', 63 fromEmail: 'toto@example.com',
diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts
index 8a91fbba3..3f2f71f46 100644
--- a/server/tests/api/server/follow-constraints.ts
+++ b/server/tests/api/server/follow-constraints.ts
@@ -18,6 +18,7 @@ import { unfollow } from '../../../../shared/extra-utils/server/follows'
18import { userLogin } from '../../../../shared/extra-utils/users/login' 18import { userLogin } from '../../../../shared/extra-utils/users/login'
19import { createUser } from '../../../../shared/extra-utils/users/users' 19import { createUser } from '../../../../shared/extra-utils/users/users'
20import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 20import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
21import { PeerTubeProblemDocument, ServerErrorCode } from '@shared/models'
21 22
22const expect = chai.expect 23const expect = chai.expect
23 24
@@ -153,7 +154,20 @@ describe('Test follow constraints', function () {
153 }) 154 })
154 155
155 it('Should not get the remote video', async function () { 156 it('Should not get the remote video', async function () {
156 await getVideo(servers[0].url, video2UUID, HttpStatusCode.FORBIDDEN_403) 157 const res = await getVideo(servers[0].url, video2UUID, HttpStatusCode.FORBIDDEN_403)
158
159 const error = res.body as PeerTubeProblemDocument
160
161 const doc = 'https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/does_not_respect_follow_constraints'
162 expect(error.type).to.equal(doc)
163 expect(error.code).to.equal(ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS)
164
165 expect(error.detail).to.equal('Cannot get this video regarding follow constraints')
166 expect(error.error).to.equal(error.detail)
167
168 expect(error.status).to.equal(HttpStatusCode.FORBIDDEN_403)
169
170 expect(error.originUrl).to.contains(servers[1].url)
157 }) 171 })
158 172
159 it('Should list local account videos', async function () { 173 it('Should list local account videos', async function () {
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts
index eb9ab10eb..9e5aa00c7 100644
--- a/server/tests/api/server/follows.ts
+++ b/server/tests/api/server/follows.ts
@@ -1,37 +1,35 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
5import { Video, VideoPrivacy } from '../../../../shared/models/videos' 4import * as chai from 'chai'
6import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
7import { cleanupTests, completeVideoCheck, deleteVideoComment } from '../../../../shared/extra-utils'
8import { 5import {
6 addVideoCommentReply,
7 addVideoCommentThread,
8 cleanupTests,
9 completeVideoCheck,
10 createUser,
11 createVideoCaption,
12 dateIsValid,
13 deleteVideoComment,
14 expectAccountFollows,
9 flushAndRunMultipleServers, 15 flushAndRunMultipleServers,
10 getVideosList,
11 ServerInfo,
12 setAccessTokensToServers,
13 uploadVideo
14} from '../../../../shared/extra-utils/index'
15import { dateIsValid } from '../../../../shared/extra-utils/miscs/miscs'
16import {
17 follow, 16 follow,
18 getFollowersListPaginationAndSort, 17 getFollowersListPaginationAndSort,
19 getFollowingListPaginationAndSort, 18 getFollowingListPaginationAndSort,
20 unfollow
21} from '../../../../shared/extra-utils/server/follows'
22import { expectAccountFollows } from '../../../../shared/extra-utils/users/accounts'
23import { userLogin } from '../../../../shared/extra-utils/users/login'
24import { createUser } from '../../../../shared/extra-utils/users/users'
25import {
26 addVideoCommentReply,
27 addVideoCommentThread,
28 getVideoCommentThreads, 19 getVideoCommentThreads,
29 getVideoThreadComments 20 getVideosList,
30} from '../../../../shared/extra-utils/videos/video-comments' 21 getVideoThreadComments,
31import { rateVideo } from '../../../../shared/extra-utils/videos/videos' 22 listVideoCaptions,
32import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 23 rateVideo,
33import { createVideoCaption, listVideoCaptions, testCaptionFile } from '../../../../shared/extra-utils/videos/video-captions' 24 ServerInfo,
34import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model' 25 setAccessTokensToServers,
26 testCaptionFile,
27 unfollow,
28 uploadVideo,
29 userLogin,
30 waitJobs
31} from '@shared/extra-utils'
32import { Video, VideoCaption, VideoComment, VideoCommentThreadTree, VideoPrivacy } from '@shared/models'
35 33
36const expect = chai.expect 34const expect = chai.expect
37 35
@@ -521,7 +519,7 @@ describe('Test follows', function () {
521 expect(deletedComment.text).to.equal('') 519 expect(deletedComment.text).to.equal('')
522 expect(deletedComment.inReplyToCommentId).to.be.null 520 expect(deletedComment.inReplyToCommentId).to.be.null
523 expect(deletedComment.account).to.be.null 521 expect(deletedComment.account).to.be.null
524 expect(deletedComment.totalReplies).to.equal(3) 522 expect(deletedComment.totalReplies).to.equal(2)
525 expect(dateIsValid(deletedComment.deletedAt as string)).to.be.true 523 expect(dateIsValid(deletedComment.deletedAt as string)).to.be.true
526 524
527 const res2 = await getVideoThreadComments(servers[0].url, video4.id, deletedComment.threadId) 525 const res2 = await getVideoThreadComments(servers[0].url, video4.id, deletedComment.threadId)
diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts
index 817c79f6e..d57d72f5e 100644
--- a/server/tests/api/server/handle-down.ts
+++ b/server/tests/api/server/handle-down.ts
@@ -4,7 +4,7 @@ import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { JobState, Video } from '../../../../shared/models' 5import { JobState, Video } from '../../../../shared/models'
6import { VideoPrivacy } from '../../../../shared/models/videos' 6import { VideoPrivacy } from '../../../../shared/models/videos'
7import { VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' 7import { VideoCommentThreadTree } from '../../../../shared/models/videos/comment/video-comment.model'
8 8
9import { 9import {
10 cleanupTests, 10 cleanupTests,
@@ -47,7 +47,7 @@ describe('Test handle downs', function () {
47 let missedVideo2: Video 47 let missedVideo2: Video
48 let unlistedVideo: Video 48 let unlistedVideo: Video
49 49
50 const videoIdsServer1: number[] = [] 50 const videoIdsServer1: string[] = []
51 51
52 const videoAttributes = { 52 const videoAttributes = {
53 name: 'my super name for server 1', 53 name: 'my super name for server 1',
@@ -346,10 +346,12 @@ describe('Test handle downs', function () {
346 // Wait video expiration 346 // Wait video expiration
347 await wait(11000) 347 await wait(11000)
348 348
349 for (let i = 0; i < 3; i++) { 349 for (let i = 0; i < 5; i++) {
350 await getVideo(servers[1].url, videoIdsServer1[i]) 350 try {
351 await waitJobs([ servers[1] ]) 351 await getVideo(servers[1].url, videoIdsServer1[i])
352 await wait(1500) 352 await waitJobs([ servers[1] ])
353 await wait(1500)
354 } catch {}
353 } 355 }
354 356
355 for (const id of videoIdsServer1) { 357 for (const id of videoIdsServer1) {
diff --git a/server/tests/api/server/homepage.ts b/server/tests/api/server/homepage.ts
new file mode 100644
index 000000000..e8ba89ca6
--- /dev/null
+++ b/server/tests/api/server/homepage.ts
@@ -0,0 +1,85 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import { HttpStatusCode } from '@shared/core-utils'
6import { CustomPage, ServerConfig } from '@shared/models'
7import {
8 cleanupTests,
9 flushAndRunServer,
10 getConfig,
11 getInstanceHomepage,
12 killallServers,
13 reRunServer,
14 ServerInfo,
15 setAccessTokensToServers,
16 updateInstanceHomepage
17} from '../../../../shared/extra-utils/index'
18
19const expect = chai.expect
20
21async function getHomepageState (server: ServerInfo) {
22 const res = await getConfig(server.url)
23
24 const config = res.body as ServerConfig
25 return config.homepage.enabled
26}
27
28describe('Test instance homepage actions', function () {
29 let server: ServerInfo
30
31 before(async function () {
32 this.timeout(30000)
33
34 server = await flushAndRunServer(1)
35 await setAccessTokensToServers([ server ])
36 })
37
38 it('Should not have a homepage', async function () {
39 const state = await getHomepageState(server)
40 expect(state).to.be.false
41
42 await getInstanceHomepage(server.url, HttpStatusCode.NOT_FOUND_404)
43 })
44
45 it('Should set a homepage', async function () {
46 await updateInstanceHomepage(server.url, server.accessToken, '<picsou-magazine></picsou-magazine>')
47
48 const res = await getInstanceHomepage(server.url)
49 const page: CustomPage = res.body
50 expect(page.content).to.equal('<picsou-magazine></picsou-magazine>')
51
52 const state = await getHomepageState(server)
53 expect(state).to.be.true
54 })
55
56 it('Should have the same homepage after a restart', async function () {
57 this.timeout(30000)
58
59 killallServers([ server ])
60
61 await reRunServer(server)
62
63 const res = await getInstanceHomepage(server.url)
64 const page: CustomPage = res.body
65 expect(page.content).to.equal('<picsou-magazine></picsou-magazine>')
66
67 const state = await getHomepageState(server)
68 expect(state).to.be.true
69 })
70
71 it('Should empty the homepage', async function () {
72 await updateInstanceHomepage(server.url, server.accessToken, '')
73
74 const res = await getInstanceHomepage(server.url)
75 const page: CustomPage = res.body
76 expect(page.content).to.be.empty
77
78 const state = await getHomepageState(server)
79 expect(state).to.be.false
80 })
81
82 after(async function () {
83 await cleanupTests([ server ])
84 })
85})
diff --git a/server/tests/api/server/index.ts b/server/tests/api/server/index.ts
index be743973a..56e6eb5da 100644
--- a/server/tests/api/server/index.ts
+++ b/server/tests/api/server/index.ts
@@ -5,6 +5,7 @@ import './email'
5import './follow-constraints' 5import './follow-constraints'
6import './follows' 6import './follows'
7import './follows-moderation' 7import './follows-moderation'
8import './homepage'
8import './handle-down' 9import './handle-down'
9import './jobs' 10import './jobs'
10import './logs' 11import './logs'
diff --git a/server/tests/api/server/plugins.ts b/server/tests/api/server/plugins.ts
index f4190c352..6b61c7c33 100644
--- a/server/tests/api/server/plugins.ts
+++ b/server/tests/api/server/plugins.ts
@@ -2,6 +2,7 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { HttpStatusCode } from '@shared/core-utils'
5import { 6import {
6 cleanupTests, 7 cleanupTests,
7 closeAllSequelize, 8 closeAllSequelize,
@@ -10,6 +11,7 @@ import {
10 getMyUserInformation, 11 getMyUserInformation,
11 getPlugin, 12 getPlugin,
12 getPluginPackageJSON, 13 getPluginPackageJSON,
14 getPluginTestPath,
13 getPublicSettings, 15 getPublicSettings,
14 installPlugin, 16 installPlugin,
15 killallServers, 17 killallServers,
@@ -28,14 +30,8 @@ import {
28 updatePluginSettings, 30 updatePluginSettings,
29 wait, 31 wait,
30 waitUntilLog 32 waitUntilLog
31} from '../../../../shared/extra-utils' 33} from '@shared/extra-utils'
32import { PeerTubePluginIndex } from '../../../../shared/models/plugins/peertube-plugin-index.model' 34import { PeerTubePlugin, PeerTubePluginIndex, PluginPackageJson, PluginType, PublicServerSetting, ServerConfig, User } from '@shared/models'
33import { PeerTubePlugin } from '../../../../shared/models/plugins/peertube-plugin.model'
34import { PluginPackageJson } from '../../../../shared/models/plugins/plugin-package-json.model'
35import { PluginType } from '../../../../shared/models/plugins/plugin.type'
36import { PublicServerSetting } from '../../../../shared/models/plugins/public-server.setting'
37import { ServerConfig } from '../../../../shared/models/server'
38import { User } from '../../../../shared/models/users'
39 35
40const expect = chai.expect 36const expect = chai.expect
41 37
@@ -406,6 +402,36 @@ describe('Test plugins', function () {
406 expect((res.body as User).theme).to.equal('instance-default') 402 expect((res.body as User).theme).to.equal('instance-default')
407 }) 403 })
408 404
405 it('Should not install a broken plugin', async function () {
406 this.timeout(60000)
407
408 async function check () {
409 const res = await listPlugins({
410 url: server.url,
411 accessToken: server.accessToken,
412 pluginType: PluginType.PLUGIN
413 })
414
415 const plugins: PeerTubePlugin[] = res.body.data
416
417 expect(plugins.find(p => p.name === 'test-broken')).to.not.exist
418 }
419
420 await installPlugin({
421 url: server.url,
422 accessToken: server.accessToken,
423 path: getPluginTestPath('-broken'),
424 expectedStatus: HttpStatusCode.BAD_REQUEST_400
425 })
426
427 await check()
428
429 killallServers([ server ])
430 await reRunServer(server)
431
432 await check()
433 })
434
409 after(async function () { 435 after(async function () {
410 await closeAllSequelize([ server ]) 436 await closeAllSequelize([ server ])
411 await cleanupTests([ server ]) 437 await cleanupTests([ server ])
diff --git a/server/tests/api/server/services.ts b/server/tests/api/server/services.ts
index f0fa91674..ea64e4040 100644
--- a/server/tests/api/server/services.ts
+++ b/server/tests/api/server/services.ts
@@ -67,61 +67,67 @@ describe('Test services', function () {
67 }) 67 })
68 68
69 it('Should have a valid oEmbed video response', async function () { 69 it('Should have a valid oEmbed video response', async function () {
70 const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/' + video.uuid 70 for (const basePath of [ '/videos/watch/', '/w/' ]) {
71 71 const oembedUrl = 'http://localhost:' + server.port + basePath + video.uuid
72 const res = await getOEmbed(server.url, oembedUrl) 72
73 const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' + 73 const res = await getOEmbed(server.url, oembedUrl)
74 `title="${video.name}" src="http://localhost:${server.port}/videos/embed/${video.uuid}" ` + 74 const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' +
75 'frameborder="0" allowfullscreen></iframe>' 75 `title="${video.name}" src="http://localhost:${server.port}/videos/embed/${video.uuid}" ` +
76 const expectedThumbnailUrl = 'http://localhost:' + server.port + video.previewPath 76 'frameborder="0" allowfullscreen></iframe>'
77 77 const expectedThumbnailUrl = 'http://localhost:' + server.port + video.previewPath
78 expect(res.body.html).to.equal(expectedHtml) 78
79 expect(res.body.title).to.equal(video.name) 79 expect(res.body.html).to.equal(expectedHtml)
80 expect(res.body.author_name).to.equal(server.videoChannel.displayName) 80 expect(res.body.title).to.equal(video.name)
81 expect(res.body.width).to.equal(560) 81 expect(res.body.author_name).to.equal(server.videoChannel.displayName)
82 expect(res.body.height).to.equal(315) 82 expect(res.body.width).to.equal(560)
83 expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl) 83 expect(res.body.height).to.equal(315)
84 expect(res.body.thumbnail_width).to.equal(850) 84 expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl)
85 expect(res.body.thumbnail_height).to.equal(480) 85 expect(res.body.thumbnail_width).to.equal(850)
86 expect(res.body.thumbnail_height).to.equal(480)
87 }
86 }) 88 })
87 89
88 it('Should have a valid playlist oEmbed response', async function () { 90 it('Should have a valid playlist oEmbed response', async function () {
89 const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/playlist/' + playlistUUID 91 for (const basePath of [ '/videos/watch/playlist/', '/w/p/' ]) {
90 92 const oembedUrl = 'http://localhost:' + server.port + basePath + playlistUUID
91 const res = await getOEmbed(server.url, oembedUrl) 93
92 const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' + 94 const res = await getOEmbed(server.url, oembedUrl)
93 `title="${playlistDisplayName}" src="http://localhost:${server.port}/video-playlists/embed/${playlistUUID}" ` + 95 const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' +
94 'frameborder="0" allowfullscreen></iframe>' 96 `title="${playlistDisplayName}" src="http://localhost:${server.port}/video-playlists/embed/${playlistUUID}" ` +
95 97 'frameborder="0" allowfullscreen></iframe>'
96 expect(res.body.html).to.equal(expectedHtml) 98
97 expect(res.body.title).to.equal('The Life and Times of Scrooge McDuck') 99 expect(res.body.html).to.equal(expectedHtml)
98 expect(res.body.author_name).to.equal(server.videoChannel.displayName) 100 expect(res.body.title).to.equal('The Life and Times of Scrooge McDuck')
99 expect(res.body.width).to.equal(560) 101 expect(res.body.author_name).to.equal(server.videoChannel.displayName)
100 expect(res.body.height).to.equal(315) 102 expect(res.body.width).to.equal(560)
101 expect(res.body.thumbnail_url).exist 103 expect(res.body.height).to.equal(315)
102 expect(res.body.thumbnail_width).to.equal(280) 104 expect(res.body.thumbnail_url).exist
103 expect(res.body.thumbnail_height).to.equal(157) 105 expect(res.body.thumbnail_width).to.equal(280)
106 expect(res.body.thumbnail_height).to.equal(157)
107 }
104 }) 108 })
105 109
106 it('Should have a valid oEmbed response with small max height query', async function () { 110 it('Should have a valid oEmbed response with small max height query', async function () {
107 const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/' + video.uuid 111 for (const basePath of [ '/videos/watch/', '/w/' ]) {
108 const format = 'json' 112 const oembedUrl = 'http://localhost:' + server.port + basePath + video.uuid
109 const maxHeight = 50 113 const format = 'json'
110 const maxWidth = 50 114 const maxHeight = 50
111 115 const maxWidth = 50
112 const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth) 116
113 const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' + 117 const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth)
114 `title="${video.name}" src="http://localhost:${server.port}/videos/embed/${video.uuid}" ` + 118 const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' +
115 'frameborder="0" allowfullscreen></iframe>' 119 `title="${video.name}" src="http://localhost:${server.port}/videos/embed/${video.uuid}" ` +
116 120 'frameborder="0" allowfullscreen></iframe>'
117 expect(res.body.html).to.equal(expectedHtml) 121
118 expect(res.body.title).to.equal(video.name) 122 expect(res.body.html).to.equal(expectedHtml)
119 expect(res.body.author_name).to.equal(server.videoChannel.displayName) 123 expect(res.body.title).to.equal(video.name)
120 expect(res.body.height).to.equal(50) 124 expect(res.body.author_name).to.equal(server.videoChannel.displayName)
121 expect(res.body.width).to.equal(50) 125 expect(res.body.height).to.equal(50)
122 expect(res.body).to.not.have.property('thumbnail_url') 126 expect(res.body.width).to.equal(50)
123 expect(res.body).to.not.have.property('thumbnail_width') 127 expect(res.body).to.not.have.property('thumbnail_url')
124 expect(res.body).to.not.have.property('thumbnail_height') 128 expect(res.body).to.not.have.property('thumbnail_width')
129 expect(res.body).to.not.have.property('thumbnail_height')
130 }
125 }) 131 })
126 132
127 after(async function () { 133 after(async function () {
diff --git a/server/tests/api/users/users-verification.ts b/server/tests/api/users/users-verification.ts
index 1a9a519a0..e0f2f2112 100644
--- a/server/tests/api/users/users-verification.ts
+++ b/server/tests/api/users/users-verification.ts
@@ -19,6 +19,7 @@ import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/l
19import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' 19import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
20import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 20import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
21import { User } from '../../../../shared/models/users' 21import { User } from '../../../../shared/models/users'
22import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
22 23
23const expect = chai.expect 24const expect = chai.expect
24 25
@@ -89,8 +90,8 @@ describe('Test users account verification', function () {
89 }) 90 })
90 91
91 it('Should not allow login for user with unverified email', async function () { 92 it('Should not allow login for user with unverified email', async function () {
92 const resLogin = await login(server.url, server.client, user1, 400) 93 const resLogin = await login(server.url, server.client, user1, HttpStatusCode.BAD_REQUEST_400)
93 expect(resLogin.body.error).to.contain('User email is not verified.') 94 expect(resLogin.body.detail).to.contain('User email is not verified.')
94 }) 95 })
95 96
96 it('Should verify the user via email and allow login', async function () { 97 it('Should verify the user via email and allow login', async function () {
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts
index cea98aac7..87ba775f6 100644
--- a/server/tests/api/users/users.ts
+++ b/server/tests/api/users/users.ts
@@ -3,7 +3,7 @@
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { AbuseState, AbuseUpdate, MyUser, User, UserRole, Video, VideoPlaylistType } from '@shared/models' 5import { AbuseState, AbuseUpdate, MyUser, User, UserRole, Video, VideoPlaylistType } from '@shared/models'
6import { CustomConfig } from '@shared/models/server' 6import { CustomConfig, OAuth2ErrorCode } from '@shared/models/server'
7import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 7import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
8import { 8import {
9 addVideoCommentThread, 9 addVideoCommentThread,
@@ -93,16 +93,20 @@ describe('Test users', function () {
93 const client = { id: 'client', secret: server.client.secret } 93 const client = { id: 'client', secret: server.client.secret }
94 const res = await login(server.url, client, server.user, HttpStatusCode.BAD_REQUEST_400) 94 const res = await login(server.url, client, server.user, HttpStatusCode.BAD_REQUEST_400)
95 95
96 expect(res.body.code).to.equal('invalid_client') 96 expect(res.body.code).to.equal(OAuth2ErrorCode.INVALID_CLIENT)
97 expect(res.body.error).to.contain('client is invalid') 97 expect(res.body.error).to.contain('client is invalid')
98 expect(res.body.type.startsWith('https://')).to.be.true
99 expect(res.body.type).to.contain(OAuth2ErrorCode.INVALID_CLIENT)
98 }) 100 })
99 101
100 it('Should not login with an invalid client secret', async function () { 102 it('Should not login with an invalid client secret', async function () {
101 const client = { id: server.client.id, secret: 'coucou' } 103 const client = { id: server.client.id, secret: 'coucou' }
102 const res = await login(server.url, client, server.user, HttpStatusCode.BAD_REQUEST_400) 104 const res = await login(server.url, client, server.user, HttpStatusCode.BAD_REQUEST_400)
103 105
104 expect(res.body.code).to.equal('invalid_client') 106 expect(res.body.code).to.equal(OAuth2ErrorCode.INVALID_CLIENT)
105 expect(res.body.error).to.contain('client is invalid') 107 expect(res.body.error).to.contain('client is invalid')
108 expect(res.body.type.startsWith('https://')).to.be.true
109 expect(res.body.type).to.contain(OAuth2ErrorCode.INVALID_CLIENT)
106 }) 110 })
107 }) 111 })
108 112
@@ -112,16 +116,20 @@ describe('Test users', function () {
112 const user = { username: 'captain crochet', password: server.user.password } 116 const user = { username: 'captain crochet', password: server.user.password }
113 const res = await login(server.url, server.client, user, HttpStatusCode.BAD_REQUEST_400) 117 const res = await login(server.url, server.client, user, HttpStatusCode.BAD_REQUEST_400)
114 118
115 expect(res.body.code).to.equal('invalid_grant') 119 expect(res.body.code).to.equal(OAuth2ErrorCode.INVALID_GRANT)
116 expect(res.body.error).to.contain('credentials are invalid') 120 expect(res.body.error).to.contain('credentials are invalid')
121 expect(res.body.type.startsWith('https://')).to.be.true
122 expect(res.body.type).to.contain(OAuth2ErrorCode.INVALID_GRANT)
117 }) 123 })
118 124
119 it('Should not login with an invalid password', async function () { 125 it('Should not login with an invalid password', async function () {
120 const user = { username: server.user.username, password: 'mew_three' } 126 const user = { username: server.user.username, password: 'mew_three' }
121 const res = await login(server.url, server.client, user, HttpStatusCode.BAD_REQUEST_400) 127 const res = await login(server.url, server.client, user, HttpStatusCode.BAD_REQUEST_400)
122 128
123 expect(res.body.code).to.equal('invalid_grant') 129 expect(res.body.code).to.equal(OAuth2ErrorCode.INVALID_GRANT)
124 expect(res.body.error).to.contain('credentials are invalid') 130 expect(res.body.error).to.contain('credentials are invalid')
131 expect(res.body.type.startsWith('https://')).to.be.true
132 expect(res.body.type).to.contain(OAuth2ErrorCode.INVALID_GRANT)
125 }) 133 })
126 134
127 it('Should not be able to upload a video', async function () { 135 it('Should not be able to upload a video', async function () {
diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts
index 41cd814e0..a8c8a889b 100644
--- a/server/tests/api/videos/multiple-servers.ts
+++ b/server/tests/api/videos/multiple-servers.ts
@@ -1,13 +1,12 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
5import { join } from 'path' 4import * as chai from 'chai'
6import * as request from 'supertest' 5import * as request from 'supertest'
7import { VideoPrivacy } from '../../../../shared/models/videos' 6import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
8import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
9import { 7import {
10 addVideoChannel, 8 addVideoChannel,
9 buildAbsoluteFixturePath,
11 checkTmpIsEmpty, 10 checkTmpIsEmpty,
12 checkVideoFilesWereRemoved, 11 checkVideoFilesWereRemoved,
13 cleanupTests, 12 cleanupTests,
@@ -32,16 +31,16 @@ import {
32 wait, 31 wait,
33 webtorrentAdd 32 webtorrentAdd
34} from '../../../../shared/extra-utils' 33} from '../../../../shared/extra-utils'
34import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
35import { 35import {
36 addVideoCommentReply, 36 addVideoCommentReply,
37 addVideoCommentThread, 37 addVideoCommentThread,
38 deleteVideoComment, 38 deleteVideoComment,
39 findCommentId,
39 getVideoCommentThreads, 40 getVideoCommentThreads,
40 getVideoThreadComments, 41 getVideoThreadComments
41 findCommentId
42} from '../../../../shared/extra-utils/videos/video-comments' 42} from '../../../../shared/extra-utils/videos/video-comments'
43import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 43import { VideoComment, VideoCommentThreadTree, VideoPrivacy } from '../../../../shared/models/videos'
44import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
45 44
46const expect = chai.expect 45const expect = chai.expect
47 46
@@ -935,7 +934,7 @@ describe('Test multiple servers', function () {
935 expect(deletedComment.text).to.equal('') 934 expect(deletedComment.text).to.equal('')
936 expect(deletedComment.inReplyToCommentId).to.be.null 935 expect(deletedComment.inReplyToCommentId).to.be.null
937 expect(deletedComment.account).to.be.null 936 expect(deletedComment.account).to.be.null
938 expect(deletedComment.totalReplies).to.equal(3) 937 expect(deletedComment.totalReplies).to.equal(2)
939 expect(dateIsValid(deletedComment.createdAt as string)).to.be.true 938 expect(dateIsValid(deletedComment.createdAt as string)).to.be.true
940 expect(dateIsValid(deletedComment.updatedAt as string)).to.be.true 939 expect(dateIsValid(deletedComment.updatedAt as string)).to.be.true
941 expect(dateIsValid(deletedComment.deletedAt as string)).to.be.true 940 expect(dateIsValid(deletedComment.deletedAt as string)).to.be.true
@@ -977,7 +976,7 @@ describe('Test multiple servers', function () {
977 expect(comment.createdAt).to.not.be.null 976 expect(comment.createdAt).to.not.be.null
978 expect(comment.deletedAt).to.not.be.null 977 expect(comment.deletedAt).to.not.be.null
979 expect(comment.account).to.be.null 978 expect(comment.account).to.be.null
980 expect(comment.totalReplies).to.equal(3) 979 expect(comment.totalReplies).to.equal(2)
981 } 980 }
982 } 981 }
983 }) 982 })
@@ -1019,9 +1018,7 @@ describe('Test multiple servers', function () {
1019 .field('privacy', '1') 1018 .field('privacy', '1')
1020 .field('channelId', '1') 1019 .field('channelId', '1')
1021 1020
1022 const filePath = join(__dirname, '..', '..', 'fixtures', 'video_short.webm') 1021 await req.attach('videofile', buildAbsoluteFixturePath('video_short.webm'))
1023
1024 await req.attach('videofile', filePath)
1025 .expect(HttpStatusCode.OK_200) 1022 .expect(HttpStatusCode.OK_200)
1026 1023
1027 await waitJobs(servers) 1024 await waitJobs(servers)
diff --git a/server/tests/api/videos/resumable-upload.ts b/server/tests/api/videos/resumable-upload.ts
index af9221c43..4fc3317df 100644
--- a/server/tests/api/videos/resumable-upload.ts
+++ b/server/tests/api/videos/resumable-upload.ts
@@ -8,6 +8,7 @@ import { HttpStatusCode } from '@shared/core-utils'
8import { 8import {
9 buildAbsoluteFixturePath, 9 buildAbsoluteFixturePath,
10 buildServerDirectory, 10 buildServerDirectory,
11 cleanupTests,
11 flushAndRunServer, 12 flushAndRunServer,
12 getMyUserInformation, 13 getMyUserInformation,
13 prepareResumableUpload, 14 prepareResumableUpload,
@@ -184,4 +185,7 @@ describe('Test resumable upload', function () {
184 }) 185 })
185 }) 186 })
186 187
188 after(async function () {
189 await cleanupTests([ server ])
190 })
187}) 191})
diff --git a/server/tests/api/videos/video-change-ownership.ts b/server/tests/api/videos/video-change-ownership.ts
index fad4c8b1f..a3384851b 100644
--- a/server/tests/api/videos/video-change-ownership.ts
+++ b/server/tests/api/videos/video-change-ownership.ts
@@ -1,11 +1,13 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
4import * as chai from 'chai'
5import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
5import { 6import {
6 acceptChangeOwnership, 7 acceptChangeOwnership,
7 changeVideoOwnership, 8 changeVideoOwnership,
8 cleanupTests, 9 cleanupTests,
10 createLive,
9 createUser, 11 createUser,
10 doubleFollow, 12 doubleFollow,
11 flushAndRunMultipleServers, 13 flushAndRunMultipleServers,
@@ -17,13 +19,14 @@ import {
17 refuseChangeOwnership, 19 refuseChangeOwnership,
18 ServerInfo, 20 ServerInfo,
19 setAccessTokensToServers, 21 setAccessTokensToServers,
22 setDefaultVideoChannel,
23 updateCustomSubConfig,
20 uploadVideo, 24 uploadVideo,
21 userLogin 25 userLogin
22} from '../../../../shared/extra-utils' 26} from '../../../../shared/extra-utils'
23import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 27import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
24import { User } from '../../../../shared/models/users' 28import { User } from '../../../../shared/models/users'
25import { VideoDetails } from '../../../../shared/models/videos' 29import { VideoDetails, VideoPrivacy } from '../../../../shared/models/videos'
26import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
27 30
28const expect = chai.expect 31const expect = chai.expect
29 32
@@ -37,15 +40,32 @@ describe('Test video change ownership - nominal', function () {
37 username: 'second', 40 username: 'second',
38 password: 'My other password' 41 password: 'My other password'
39 } 42 }
43
40 let firstUserAccessToken = '' 44 let firstUserAccessToken = ''
45 let firstUserChannelId: number
46
41 let secondUserAccessToken = '' 47 let secondUserAccessToken = ''
48 let secondUserChannelId: number
49
42 let lastRequestChangeOwnershipId = '' 50 let lastRequestChangeOwnershipId = ''
43 51
52 let liveId: number
53
44 before(async function () { 54 before(async function () {
45 this.timeout(50000) 55 this.timeout(50000)
46 56
47 servers = await flushAndRunMultipleServers(2) 57 servers = await flushAndRunMultipleServers(2)
48 await setAccessTokensToServers(servers) 58 await setAccessTokensToServers(servers)
59 await setDefaultVideoChannel(servers)
60
61 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
62 transcoding: {
63 enabled: false
64 },
65 live: {
66 enabled: true
67 }
68 })
49 69
50 const videoQuota = 42000000 70 const videoQuota = 42000000
51 await createUser({ 71 await createUser({
@@ -66,22 +86,35 @@ describe('Test video change ownership - nominal', function () {
66 firstUserAccessToken = await userLogin(servers[0], firstUser) 86 firstUserAccessToken = await userLogin(servers[0], firstUser)
67 secondUserAccessToken = await userLogin(servers[0], secondUser) 87 secondUserAccessToken = await userLogin(servers[0], secondUser)
68 88
69 const videoAttributes = { 89 {
70 name: 'my super name', 90 const res = await getMyUserInformation(servers[0].url, firstUserAccessToken)
71 description: 'my super description' 91 const firstUserInformation: User = res.body
92 firstUserChannelId = firstUserInformation.videoChannels[0].id
72 } 93 }
73 await uploadVideo(servers[0].url, firstUserAccessToken, videoAttributes)
74 94
75 await waitJobs(servers) 95 {
96 const res = await getMyUserInformation(servers[0].url, secondUserAccessToken)
97 const secondUserInformation: User = res.body
98 secondUserChannelId = secondUserInformation.videoChannels[0].id
99 }
76 100
77 const res = await getVideosList(servers[0].url) 101 {
78 const videos = res.body.data 102 const videoAttributes = {
103 name: 'my super name',
104 description: 'my super description'
105 }
106 const res = await uploadVideo(servers[0].url, firstUserAccessToken, videoAttributes)
79 107
80 expect(videos.length).to.equal(1) 108 const resVideo = await getVideo(servers[0].url, res.body.video.id)
109 servers[0].video = resVideo.body
110 }
81 111
82 const video = videos.find(video => video.name === 'my super name') 112 {
83 expect(video.channel.name).to.equal('first_channel') 113 const attributes = { name: 'live', channelId: firstUserChannelId, privacy: VideoPrivacy.PUBLIC }
84 servers[0].video = video 114 const res = await createLive(servers[0].url, firstUserAccessToken, attributes)
115
116 liveId = res.body.video.id
117 }
85 118
86 await doubleFollow(servers[0], servers[1]) 119 await doubleFollow(servers[0], servers[1])
87 }) 120 })
@@ -175,19 +208,19 @@ describe('Test video change ownership - nominal', function () {
175 it('Should not be possible to accept the change of ownership from first user', async function () { 208 it('Should not be possible to accept the change of ownership from first user', async function () {
176 this.timeout(10000) 209 this.timeout(10000)
177 210
178 const secondUserInformationResponse = await getMyUserInformation(servers[0].url, secondUserAccessToken) 211 await acceptChangeOwnership(
179 const secondUserInformation: User = secondUserInformationResponse.body 212 servers[0].url,
180 const channelId = secondUserInformation.videoChannels[0].id 213 firstUserAccessToken,
181 await acceptChangeOwnership(servers[0].url, firstUserAccessToken, lastRequestChangeOwnershipId, channelId, HttpStatusCode.FORBIDDEN_403) 214 lastRequestChangeOwnershipId,
215 secondUserChannelId,
216 HttpStatusCode.FORBIDDEN_403
217 )
182 }) 218 })
183 219
184 it('Should be possible to accept the change of ownership from second user', async function () { 220 it('Should be possible to accept the change of ownership from second user', async function () {
185 this.timeout(10000) 221 this.timeout(10000)
186 222
187 const secondUserInformationResponse = await getMyUserInformation(servers[0].url, secondUserAccessToken) 223 await acceptChangeOwnership(servers[0].url, secondUserAccessToken, lastRequestChangeOwnershipId, secondUserChannelId)
188 const secondUserInformation: User = secondUserInformationResponse.body
189 const channelId = secondUserInformation.videoChannels[0].id
190 await acceptChangeOwnership(servers[0].url, secondUserAccessToken, lastRequestChangeOwnershipId, channelId)
191 224
192 await waitJobs(servers) 225 await waitJobs(servers)
193 }) 226 })
@@ -204,6 +237,37 @@ describe('Test video change ownership - nominal', function () {
204 } 237 }
205 }) 238 })
206 239
240 it('Should send a request to change ownership of a live', async function () {
241 this.timeout(15000)
242
243 await changeVideoOwnership(servers[0].url, firstUserAccessToken, liveId, secondUser.username)
244
245 const resSecondUser = await getVideoChangeOwnershipList(servers[0].url, secondUserAccessToken)
246
247 expect(resSecondUser.body.total).to.equal(3)
248 expect(resSecondUser.body.data.length).to.equal(3)
249
250 lastRequestChangeOwnershipId = resSecondUser.body.data[0].id
251 })
252
253 it('Should accept a live ownership change', async function () {
254 this.timeout(20000)
255
256 await acceptChangeOwnership(servers[0].url, secondUserAccessToken, lastRequestChangeOwnershipId, secondUserChannelId)
257
258 await waitJobs(servers)
259
260 for (const server of servers) {
261 const res = await getVideo(server.url, servers[0].video.uuid)
262
263 const video: VideoDetails = res.body
264
265 expect(video.name).to.equal('my super name')
266 expect(video.channel.displayName).to.equal('Main second channel')
267 expect(video.channel.name).to.equal('second_channel')
268 }
269 })
270
207 after(async function () { 271 after(async function () {
208 await cleanupTests(servers) 272 await cleanupTests(servers)
209 }) 273 })
diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts
index 7e7ad028c..865098777 100644
--- a/server/tests/api/videos/video-channels.ts
+++ b/server/tests/api/videos/video-channels.ts
@@ -15,6 +15,7 @@ import {
15 getVideoChannel, 15 getVideoChannel,
16 getVideoChannelVideos, 16 getVideoChannelVideos,
17 setDefaultVideoChannel, 17 setDefaultVideoChannel,
18 testFileExistsOrNot,
18 testImage, 19 testImage,
19 updateVideo, 20 updateVideo,
20 updateVideoChannelImage, 21 updateVideoChannelImage,
@@ -53,6 +54,9 @@ describe('Test video channels', function () {
53 let videoUUID: string 54 let videoUUID: string
54 let accountName: string 55 let accountName: string
55 56
57 const avatarPaths: { [ port: number ]: string } = {}
58 const bannerPaths: { [ port: number ]: string } = {}
59
56 before(async function () { 60 before(async function () {
57 this.timeout(60000) 61 this.timeout(60000)
58 62
@@ -287,9 +291,11 @@ describe('Test video channels', function () {
287 for (const server of servers) { 291 for (const server of servers) {
288 const videoChannel = await findChannel(server, secondVideoChannelId) 292 const videoChannel = await findChannel(server, secondVideoChannelId)
289 293
290 await testImage(server.url, 'avatar-resized', videoChannel.avatar.path, '.png') 294 avatarPaths[server.port] = videoChannel.avatar.path
295 await testImage(server.url, 'avatar-resized', avatarPaths[server.port], '.png')
296 await testFileExistsOrNot(server, 'avatars', basename(avatarPaths[server.port]), true)
291 297
292 const row = await getActorImage(server.internalServerNumber, basename(videoChannel.avatar.path)) 298 const row = await getActorImage(server.internalServerNumber, basename(avatarPaths[server.port]))
293 expect(row.height).to.equal(ACTOR_IMAGES_SIZE.AVATARS.height) 299 expect(row.height).to.equal(ACTOR_IMAGES_SIZE.AVATARS.height)
294 expect(row.width).to.equal(ACTOR_IMAGES_SIZE.AVATARS.width) 300 expect(row.width).to.equal(ACTOR_IMAGES_SIZE.AVATARS.width)
295 } 301 }
@@ -314,9 +320,11 @@ describe('Test video channels', function () {
314 const res = await getVideoChannel(server.url, 'second_video_channel@' + servers[0].host) 320 const res = await getVideoChannel(server.url, 'second_video_channel@' + servers[0].host)
315 const videoChannel = res.body 321 const videoChannel = res.body
316 322
317 await testImage(server.url, 'banner-resized', videoChannel.banner.path) 323 bannerPaths[server.port] = videoChannel.banner.path
324 await testImage(server.url, 'banner-resized', bannerPaths[server.port])
325 await testFileExistsOrNot(server, 'avatars', basename(bannerPaths[server.port]), true)
318 326
319 const row = await getActorImage(server.internalServerNumber, basename(videoChannel.banner.path)) 327 const row = await getActorImage(server.internalServerNumber, basename(bannerPaths[server.port]))
320 expect(row.height).to.equal(ACTOR_IMAGES_SIZE.BANNERS.height) 328 expect(row.height).to.equal(ACTOR_IMAGES_SIZE.BANNERS.height)
321 expect(row.width).to.equal(ACTOR_IMAGES_SIZE.BANNERS.width) 329 expect(row.width).to.equal(ACTOR_IMAGES_SIZE.BANNERS.width)
322 } 330 }
@@ -336,6 +344,7 @@ describe('Test video channels', function () {
336 344
337 for (const server of servers) { 345 for (const server of servers) {
338 const videoChannel = await findChannel(server, secondVideoChannelId) 346 const videoChannel = await findChannel(server, secondVideoChannelId)
347 await testFileExistsOrNot(server, 'avatars', basename(avatarPaths[server.port]), false)
339 348
340 expect(videoChannel.avatar).to.be.null 349 expect(videoChannel.avatar).to.be.null
341 } 350 }
@@ -355,6 +364,7 @@ describe('Test video channels', function () {
355 364
356 for (const server of servers) { 365 for (const server of servers) {
357 const videoChannel = await findChannel(server, secondVideoChannelId) 366 const videoChannel = await findChannel(server, secondVideoChannelId)
367 await testFileExistsOrNot(server, 'avatars', basename(bannerPaths[server.port]), false)
358 368
359 expect(videoChannel.banner).to.be.null 369 expect(videoChannel.banner).to.be.null
360 } 370 }
diff --git a/server/tests/api/videos/video-comments.ts b/server/tests/api/videos/video-comments.ts
index 615e0ea45..b6b002307 100644
--- a/server/tests/api/videos/video-comments.ts
+++ b/server/tests/api/videos/video-comments.ts
@@ -2,7 +2,7 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5 5import { VideoComment, VideoCommentAdmin, VideoCommentThreadTree } from '@shared/models'
6import { cleanupTests, testImage } from '../../../../shared/extra-utils' 6import { cleanupTests, testImage } from '../../../../shared/extra-utils'
7import { 7import {
8 createUser, 8 createUser,
@@ -22,7 +22,6 @@ import {
22 getVideoCommentThreads, 22 getVideoCommentThreads,
23 getVideoThreadComments 23 getVideoThreadComments
24} from '../../../../shared/extra-utils/videos/video-comments' 24} from '../../../../shared/extra-utils/videos/video-comments'
25import { VideoComment, VideoCommentAdmin, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
26 25
27const expect = chai.expect 26const expect = chai.expect
28 27
@@ -232,7 +231,7 @@ describe('Test video comments', function () {
232 expect(res.body.data[0].isDeleted).to.be.true 231 expect(res.body.data[0].isDeleted).to.be.true
233 expect(res.body.data[0].deletedAt).to.not.be.null 232 expect(res.body.data[0].deletedAt).to.not.be.null
234 expect(res.body.data[0].account).to.be.null 233 expect(res.body.data[0].account).to.be.null
235 expect(res.body.data[0].totalReplies).to.equal(3) 234 expect(res.body.data[0].totalReplies).to.equal(2)
236 expect(res.body.data[1].text).to.equal('super thread 2') 235 expect(res.body.data[1].text).to.equal('super thread 2')
237 expect(res.body.data[1].totalReplies).to.equal(0) 236 expect(res.body.data[1].totalReplies).to.equal(0)
238 expect(res.body.data[2].text).to.equal('super thread 3') 237 expect(res.body.data[2].text).to.equal('super thread 3')
diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts
index 9dad58c8c..da8de054b 100644
--- a/server/tests/api/videos/video-playlists.ts
+++ b/server/tests/api/videos/video-playlists.ts
@@ -56,7 +56,7 @@ import {
56 removeServerFromServerBlocklist 56 removeServerFromServerBlocklist
57} from '../../../../shared/extra-utils/users/blocklist' 57} from '../../../../shared/extra-utils/users/blocklist'
58import { User } from '../../../../shared/models/users' 58import { User } from '../../../../shared/models/users'
59import { VideoPrivacy } from '../../../../shared/models/videos' 59import { VideoPlaylistCreateResult, VideoPrivacy } from '../../../../shared/models/videos'
60import { VideoExistInPlaylist } from '../../../../shared/models/videos/playlist/video-exist-in-playlist.model' 60import { VideoExistInPlaylist } from '../../../../shared/models/videos/playlist/video-exist-in-playlist.model'
61import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../../shared/models/videos/playlist/video-playlist-element.model' 61import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../../shared/models/videos/playlist/video-playlist-element.model'
62import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' 62import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
@@ -427,31 +427,45 @@ describe('Test video playlists', function () {
427 expect(data).to.have.lengthOf(0) 427 expect(data).to.have.lengthOf(0)
428 } 428 }
429 }) 429 })
430 })
430 431
431 it('Should not list unlisted or private playlists', async function () { 432 describe('Playlist rights', function () {
433 let unlistedPlaylist: VideoPlaylistCreateResult
434 let privatePlaylist: VideoPlaylistCreateResult
435
436 before(async function () {
432 this.timeout(30000) 437 this.timeout(30000)
433 438
434 await createVideoPlaylist({ 439 {
435 url: servers[1].url, 440 const res = await createVideoPlaylist({
436 token: servers[1].accessToken, 441 url: servers[1].url,
437 playlistAttrs: { 442 token: servers[1].accessToken,
438 displayName: 'playlist unlisted', 443 playlistAttrs: {
439 privacy: VideoPlaylistPrivacy.UNLISTED 444 displayName: 'playlist unlisted',
440 } 445 privacy: VideoPlaylistPrivacy.UNLISTED,
441 }) 446 videoChannelId: servers[1].videoChannel.id
447 }
448 })
449 unlistedPlaylist = res.body.videoPlaylist
450 }
442 451
443 await createVideoPlaylist({ 452 {
444 url: servers[1].url, 453 const res = await createVideoPlaylist({
445 token: servers[1].accessToken, 454 url: servers[1].url,
446 playlistAttrs: { 455 token: servers[1].accessToken,
447 displayName: 'playlist private', 456 playlistAttrs: {
448 privacy: VideoPlaylistPrivacy.PRIVATE 457 displayName: 'playlist private',
449 } 458 privacy: VideoPlaylistPrivacy.PRIVATE
450 }) 459 }
460 })
461 privatePlaylist = res.body.videoPlaylist
462 }
451 463
452 await waitJobs(servers) 464 await waitJobs(servers)
453 await wait(3000) 465 await wait(3000)
466 })
454 467
468 it('Should not list unlisted or private playlists', async function () {
455 for (const server of servers) { 469 for (const server of servers) {
456 const results = [ 470 const results = [
457 await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'), 471 await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'),
@@ -469,6 +483,27 @@ describe('Test video playlists', function () {
469 } 483 }
470 } 484 }
471 }) 485 })
486
487 it('Should not get unlisted playlist using only the id', async function () {
488 await getVideoPlaylist(servers[1].url, unlistedPlaylist.id, 404)
489 })
490
491 it('Should get unlisted plyaylist using uuid or shortUUID', async function () {
492 await getVideoPlaylist(servers[1].url, unlistedPlaylist.uuid)
493 await getVideoPlaylist(servers[1].url, unlistedPlaylist.shortUUID)
494 })
495
496 it('Should not get private playlist without token', async function () {
497 for (const id of [ privatePlaylist.id, privatePlaylist.uuid, privatePlaylist.shortUUID ]) {
498 await getVideoPlaylist(servers[1].url, id, 401)
499 }
500 })
501
502 it('Should get private playlist with a token', async function () {
503 for (const id of [ privatePlaylist.id, privatePlaylist.uuid, privatePlaylist.shortUUID ]) {
504 await getVideoPlaylistWithToken(servers[1].url, servers[1].accessToken, id)
505 }
506 })
472 }) 507 })
473 508
474 describe('Update playlists', function () { 509 describe('Update playlists', function () {
diff --git a/server/tests/api/videos/video-privacy.ts b/server/tests/api/videos/video-privacy.ts
index fed6ca0e0..950aeb7cf 100644
--- a/server/tests/api/videos/video-privacy.ts
+++ b/server/tests/api/videos/video-privacy.ts
@@ -1,8 +1,9 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai'
4import 'mocha' 3import 'mocha'
5import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum' 4import * as chai from 'chai'
5import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
6import { Video, VideoCreateResult } from '@shared/models'
6import { 7import {
7 cleanupTests, 8 cleanupTests,
8 flushAndRunServer, 9 flushAndRunServer,
@@ -13,12 +14,11 @@ import {
13 uploadVideo 14 uploadVideo
14} from '../../../../shared/extra-utils/index' 15} from '../../../../shared/extra-utils/index'
15import { doubleFollow } from '../../../../shared/extra-utils/server/follows' 16import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
17import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
16import { userLogin } from '../../../../shared/extra-utils/users/login' 18import { userLogin } from '../../../../shared/extra-utils/users/login'
17import { createUser } from '../../../../shared/extra-utils/users/users' 19import { createUser } from '../../../../shared/extra-utils/users/users'
18import { getMyVideos, getVideo, getVideoWithToken, updateVideo } from '../../../../shared/extra-utils/videos/videos' 20import { getMyVideos, getVideo, getVideoWithToken, updateVideo } from '../../../../shared/extra-utils/videos/videos'
19import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 21import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
20import { Video } from '@shared/models'
21import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
22 22
23const expect = chai.expect 23const expect = chai.expect
24 24
@@ -32,7 +32,7 @@ describe('Test video privacy', function () {
32 let internalVideoId: number 32 let internalVideoId: number
33 let internalVideoUUID: string 33 let internalVideoUUID: string
34 34
35 let unlistedVideoUUID: string 35 let unlistedVideo: VideoCreateResult
36 let nonFederatedUnlistedVideoUUID: string 36 let nonFederatedUnlistedVideoUUID: string
37 37
38 let now: number 38 let now: number
@@ -59,231 +59,246 @@ describe('Test video privacy', function () {
59 await doubleFollow(servers[0], servers[1]) 59 await doubleFollow(servers[0], servers[1])
60 }) 60 })
61 61
62 it('Should upload a private and internal videos on server 1', async function () { 62 describe('Private and internal videos', function () {
63 this.timeout(10000)
64 63
65 for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) { 64 it('Should upload a private and internal videos on server 1', async function () {
66 const attributes = { privacy } 65 this.timeout(10000)
67 await uploadVideo(servers[0].url, servers[0].accessToken, attributes)
68 }
69 66
70 await waitJobs(servers) 67 for (const privacy of [ VideoPrivacy.PRIVATE, VideoPrivacy.INTERNAL ]) {
71 }) 68 const attributes = { privacy }
69 await uploadVideo(servers[0].url, servers[0].accessToken, attributes)
70 }
72 71
73 it('Should not have these private and internal videos on server 2', async function () { 72 await waitJobs(servers)
74 const res = await getVideosList(servers[1].url) 73 })
75 74
76 expect(res.body.total).to.equal(0) 75 it('Should not have these private and internal videos on server 2', async function () {
77 expect(res.body.data).to.have.lengthOf(0) 76 const res = await getVideosList(servers[1].url)
78 })
79 77
80 it('Should not list the private and internal videos for an unauthenticated user on server 1', async function () { 78 expect(res.body.total).to.equal(0)
81 const res = await getVideosList(servers[0].url) 79 expect(res.body.data).to.have.lengthOf(0)
80 })
82 81
83 expect(res.body.total).to.equal(0) 82 it('Should not list the private and internal videos for an unauthenticated user on server 1', async function () {
84 expect(res.body.data).to.have.lengthOf(0) 83 const res = await getVideosList(servers[0].url)
85 }) 84
85 expect(res.body.total).to.equal(0)
86 expect(res.body.data).to.have.lengthOf(0)
87 })
86 88
87 it('Should not list the private video and list the internal video for an authenticated user on server 1', async function () { 89 it('Should not list the private video and list the internal video for an authenticated user on server 1', async function () {
88 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) 90 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
89 91
90 expect(res.body.total).to.equal(1) 92 expect(res.body.total).to.equal(1)
91 expect(res.body.data).to.have.lengthOf(1) 93 expect(res.body.data).to.have.lengthOf(1)
92 94
93 expect(res.body.data[0].privacy.id).to.equal(VideoPrivacy.INTERNAL) 95 expect(res.body.data[0].privacy.id).to.equal(VideoPrivacy.INTERNAL)
94 }) 96 })
95 97
96 it('Should list my (private and internal) videos', async function () { 98 it('Should list my (private and internal) videos', async function () {
97 const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 10) 99 const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 10)
98 100
99 expect(res.body.total).to.equal(2) 101 expect(res.body.total).to.equal(2)
100 expect(res.body.data).to.have.lengthOf(2) 102 expect(res.body.data).to.have.lengthOf(2)
101 103
102 const videos: Video[] = res.body.data 104 const videos: Video[] = res.body.data
103 105
104 const privateVideo = videos.find(v => v.privacy.id === VideoPrivacy.PRIVATE) 106 const privateVideo = videos.find(v => v.privacy.id === VideoPrivacy.PRIVATE)
105 privateVideoId = privateVideo.id 107 privateVideoId = privateVideo.id
106 privateVideoUUID = privateVideo.uuid 108 privateVideoUUID = privateVideo.uuid
107 109
108 const internalVideo = videos.find(v => v.privacy.id === VideoPrivacy.INTERNAL) 110 const internalVideo = videos.find(v => v.privacy.id === VideoPrivacy.INTERNAL)
109 internalVideoId = internalVideo.id 111 internalVideoId = internalVideo.id
110 internalVideoUUID = internalVideo.uuid 112 internalVideoUUID = internalVideo.uuid
111 }) 113 })
112 114
113 it('Should not be able to watch the private/internal video with non authenticated user', async function () { 115 it('Should not be able to watch the private/internal video with non authenticated user', async function () {
114 await getVideo(servers[0].url, privateVideoUUID, HttpStatusCode.UNAUTHORIZED_401) 116 await getVideo(servers[0].url, privateVideoUUID, HttpStatusCode.UNAUTHORIZED_401)
115 await getVideo(servers[0].url, internalVideoUUID, HttpStatusCode.UNAUTHORIZED_401) 117 await getVideo(servers[0].url, internalVideoUUID, HttpStatusCode.UNAUTHORIZED_401)
116 }) 118 })
117 119
118 it('Should not be able to watch the private video with another user', async function () { 120 it('Should not be able to watch the private video with another user', async function () {
119 this.timeout(10000) 121 this.timeout(10000)
120 122
121 const user = { 123 const user = {
122 username: 'hello', 124 username: 'hello',
123 password: 'super password' 125 password: 'super password'
124 } 126 }
125 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) 127 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
126 128
127 anotherUserToken = await userLogin(servers[0], user) 129 anotherUserToken = await userLogin(servers[0], user)
128 await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, HttpStatusCode.FORBIDDEN_403) 130 await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, HttpStatusCode.FORBIDDEN_403)
129 }) 131 })
130 132
131 it('Should be able to watch the internal video with another user', async function () { 133 it('Should be able to watch the internal video with another user', async function () {
132 await getVideoWithToken(servers[0].url, anotherUserToken, internalVideoUUID, HttpStatusCode.OK_200) 134 await getVideoWithToken(servers[0].url, anotherUserToken, internalVideoUUID, HttpStatusCode.OK_200)
133 }) 135 })
134 136
135 it('Should be able to watch the private video with the correct user', async function () { 137 it('Should be able to watch the private video with the correct user', async function () {
136 await getVideoWithToken(servers[0].url, servers[0].accessToken, privateVideoUUID, HttpStatusCode.OK_200) 138 await getVideoWithToken(servers[0].url, servers[0].accessToken, privateVideoUUID, HttpStatusCode.OK_200)
139 })
137 }) 140 })
138 141
139 it('Should upload an unlisted video on server 2', async function () { 142 describe('Unlisted videos', function () {
140 this.timeout(60000)
141 143
142 const attributes = { 144 it('Should upload an unlisted video on server 2', async function () {
143 name: 'unlisted video', 145 this.timeout(60000)
144 privacy: VideoPrivacy.UNLISTED
145 }
146 await uploadVideo(servers[1].url, servers[1].accessToken, attributes)
147 146
148 // Server 2 has transcoding enabled 147 const attributes = {
149 await waitJobs(servers) 148 name: 'unlisted video',
150 }) 149 privacy: VideoPrivacy.UNLISTED
150 }
151 await uploadVideo(servers[1].url, servers[1].accessToken, attributes)
151 152
152 it('Should not have this unlisted video listed on server 1 and 2', async function () { 153 // Server 2 has transcoding enabled
153 for (const server of servers) { 154 await waitJobs(servers)
154 const res = await getVideosList(server.url) 155 })
155 156
156 expect(res.body.total).to.equal(0) 157 it('Should not have this unlisted video listed on server 1 and 2', async function () {
157 expect(res.body.data).to.have.lengthOf(0) 158 for (const server of servers) {
158 } 159 const res = await getVideosList(server.url)
159 })
160 160
161 it('Should list my (unlisted) videos', async function () { 161 expect(res.body.total).to.equal(0)
162 const res = await getMyVideos(servers[1].url, servers[1].accessToken, 0, 1) 162 expect(res.body.data).to.have.lengthOf(0)
163 }
164 })
163 165
164 expect(res.body.total).to.equal(1) 166 it('Should list my (unlisted) videos', async function () {
165 expect(res.body.data).to.have.lengthOf(1) 167 const res = await getMyVideos(servers[1].url, servers[1].accessToken, 0, 1)
166 168
167 unlistedVideoUUID = res.body.data[0].uuid 169 expect(res.body.total).to.equal(1)
168 }) 170 expect(res.body.data).to.have.lengthOf(1)
169 171
170 it('Should be able to get this unlisted video', async function () { 172 unlistedVideo = res.body.data[0]
171 for (const server of servers) { 173 })
172 const res = await getVideo(server.url, unlistedVideoUUID)
173 174
174 expect(res.body.name).to.equal('unlisted video') 175 it('Should not be able to get this unlisted video using its id', async function () {
175 } 176 await getVideo(servers[1].url, unlistedVideo.id, 404)
176 }) 177 })
177 178
178 it('Should upload a non-federating unlisted video to server 1', async function () { 179 it('Should be able to get this unlisted video using its uuid/shortUUID', async function () {
179 this.timeout(30000) 180 for (const server of servers) {
181 for (const id of [ unlistedVideo.uuid, unlistedVideo.shortUUID ]) {
182 const res = await getVideo(server.url, id)
180 183
181 const attributes = { 184 expect(res.body.name).to.equal('unlisted video')
182 name: 'unlisted video', 185 }
183 privacy: VideoPrivacy.UNLISTED 186 }
184 } 187 })
185 await uploadVideo(servers[0].url, servers[0].accessToken, attributes)
186 188
187 await waitJobs(servers) 189 it('Should upload a non-federating unlisted video to server 1', async function () {
188 }) 190 this.timeout(30000)
191
192 const attributes = {
193 name: 'unlisted video',
194 privacy: VideoPrivacy.UNLISTED
195 }
196 await uploadVideo(servers[0].url, servers[0].accessToken, attributes)
189 197
190 it('Should list my new unlisted video', async function () { 198 await waitJobs(servers)
191 const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 3) 199 })
192 200
193 expect(res.body.total).to.equal(3) 201 it('Should list my new unlisted video', async function () {
194 expect(res.body.data).to.have.lengthOf(3) 202 const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 3)
195 203
196 nonFederatedUnlistedVideoUUID = res.body.data[0].uuid 204 expect(res.body.total).to.equal(3)
197 }) 205 expect(res.body.data).to.have.lengthOf(3)
198 206
199 it('Should be able to get non-federated unlisted video from origin', async function () { 207 nonFederatedUnlistedVideoUUID = res.body.data[0].uuid
200 const res = await getVideo(servers[0].url, nonFederatedUnlistedVideoUUID) 208 })
201 209
202 expect(res.body.name).to.equal('unlisted video') 210 it('Should be able to get non-federated unlisted video from origin', async function () {
203 }) 211 const res = await getVideo(servers[0].url, nonFederatedUnlistedVideoUUID)
204 212
205 it('Should not be able to get non-federated unlisted video from federated server', async function () { 213 expect(res.body.name).to.equal('unlisted video')
206 await getVideo(servers[1].url, nonFederatedUnlistedVideoUUID, HttpStatusCode.NOT_FOUND_404) 214 })
215
216 it('Should not be able to get non-federated unlisted video from federated server', async function () {
217 await getVideo(servers[1].url, nonFederatedUnlistedVideoUUID, HttpStatusCode.NOT_FOUND_404)
218 })
207 }) 219 })
208 220
209 it('Should update the private and internal videos to public on server 1', async function () { 221 describe('Privacy update', function () {
210 this.timeout(10000)
211 222
212 now = Date.now() 223 it('Should update the private and internal videos to public on server 1', async function () {
224 this.timeout(10000)
213 225
214 { 226 now = Date.now()
215 const attribute = {
216 name: 'private video becomes public',
217 privacy: VideoPrivacy.PUBLIC
218 }
219 227
220 await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, attribute) 228 {
221 } 229 const attribute = {
230 name: 'private video becomes public',
231 privacy: VideoPrivacy.PUBLIC
232 }
222 233
223 { 234 await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, attribute)
224 const attribute = {
225 name: 'internal video becomes public',
226 privacy: VideoPrivacy.PUBLIC
227 } 235 }
228 await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, attribute)
229 }
230 236
231 await waitJobs(servers) 237 {
232 }) 238 const attribute = {
239 name: 'internal video becomes public',
240 privacy: VideoPrivacy.PUBLIC
241 }
242 await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, attribute)
243 }
233 244
234 it('Should have this new public video listed on server 1 and 2', async function () { 245 await waitJobs(servers)
235 for (const server of servers) { 246 })
236 const res = await getVideosList(server.url)
237 expect(res.body.total).to.equal(2)
238 expect(res.body.data).to.have.lengthOf(2)
239 247
240 const videos: Video[] = res.body.data 248 it('Should have this new public video listed on server 1 and 2', async function () {
241 const privateVideo = videos.find(v => v.name === 'private video becomes public') 249 for (const server of servers) {
242 const internalVideo = videos.find(v => v.name === 'internal video becomes public') 250 const res = await getVideosList(server.url)
251 expect(res.body.total).to.equal(2)
252 expect(res.body.data).to.have.lengthOf(2)
243 253
244 expect(privateVideo).to.not.be.undefined 254 const videos: Video[] = res.body.data
245 expect(internalVideo).to.not.be.undefined 255 const privateVideo = videos.find(v => v.name === 'private video becomes public')
256 const internalVideo = videos.find(v => v.name === 'internal video becomes public')
246 257
247 expect(new Date(privateVideo.publishedAt).getTime()).to.be.at.least(now) 258 expect(privateVideo).to.not.be.undefined
248 // We don't change the publish date of internal videos 259 expect(internalVideo).to.not.be.undefined
249 expect(new Date(internalVideo.publishedAt).getTime()).to.be.below(now)
250 260
251 expect(privateVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC) 261 expect(new Date(privateVideo.publishedAt).getTime()).to.be.at.least(now)
252 expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC) 262 // We don't change the publish date of internal videos
253 } 263 expect(new Date(internalVideo.publishedAt).getTime()).to.be.below(now)
254 })
255 264
256 it('Should set these videos as private and internal', async function () { 265 expect(privateVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC)
257 this.timeout(10000) 266 expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PUBLIC)
267 }
268 })
258 269
259 await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, { privacy: VideoPrivacy.PRIVATE }) 270 it('Should set these videos as private and internal', async function () {
260 await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, { privacy: VideoPrivacy.INTERNAL }) 271 this.timeout(10000)
261 272
262 await waitJobs(servers) 273 await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, { privacy: VideoPrivacy.PRIVATE })
274 await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, { privacy: VideoPrivacy.INTERNAL })
263 275
264 for (const server of servers) { 276 await waitJobs(servers)
265 const res = await getVideosList(server.url)
266 277
267 expect(res.body.total).to.equal(0) 278 for (const server of servers) {
268 expect(res.body.data).to.have.lengthOf(0) 279 const res = await getVideosList(server.url)
269 } 280
281 expect(res.body.total).to.equal(0)
282 expect(res.body.data).to.have.lengthOf(0)
283 }
270 284
271 { 285 {
272 const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 5) 286 const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 5)
273 const videos = res.body.data 287 const videos = res.body.data
274 288
275 expect(res.body.total).to.equal(3) 289 expect(res.body.total).to.equal(3)
276 expect(videos).to.have.lengthOf(3) 290 expect(videos).to.have.lengthOf(3)
277 291
278 const privateVideo = videos.find(v => v.name === 'private video becomes public') 292 const privateVideo = videos.find(v => v.name === 'private video becomes public')
279 const internalVideo = videos.find(v => v.name === 'internal video becomes public') 293 const internalVideo = videos.find(v => v.name === 'internal video becomes public')
280 294
281 expect(privateVideo).to.not.be.undefined 295 expect(privateVideo).to.not.be.undefined
282 expect(internalVideo).to.not.be.undefined 296 expect(internalVideo).to.not.be.undefined
283 297
284 expect(privateVideo.privacy.id).to.equal(VideoPrivacy.INTERNAL) 298 expect(privateVideo.privacy.id).to.equal(VideoPrivacy.INTERNAL)
285 expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PRIVATE) 299 expect(internalVideo.privacy.id).to.equal(VideoPrivacy.PRIVATE)
286 } 300 }
301 })
287 }) 302 })
288 303
289 after(async function () { 304 after(async function () {
diff --git a/server/tests/api/videos/videos-filter.ts b/server/tests/api/videos/videos-filter.ts
index 2961c8e78..7428b82c5 100644
--- a/server/tests/api/videos/videos-filter.ts
+++ b/server/tests/api/videos/videos-filter.ts
@@ -47,13 +47,13 @@ async function getVideosNames (server: ServerInfo, token: string, filter: string
47 return videosResults 47 return videosResults
48} 48}
49 49
50describe('Test videos filter validator', function () { 50describe('Test videos filter', function () {
51 let servers: ServerInfo[] 51 let servers: ServerInfo[]
52 52
53 // --------------------------------------------------------------- 53 // ---------------------------------------------------------------
54 54
55 before(async function () { 55 before(async function () {
56 this.timeout(120000) 56 this.timeout(160000)
57 57
58 servers = await flushAndRunMultipleServers(2) 58 servers = await flushAndRunMultipleServers(2)
59 59
diff --git a/server/tests/api/videos/videos-overview.ts b/server/tests/api/videos/videos-overview.ts
index 7889bcf80..c266a1dc5 100644
--- a/server/tests/api/videos/videos-overview.ts
+++ b/server/tests/api/videos/videos-overview.ts
@@ -45,7 +45,7 @@ describe('Test a videos overview', function () {
45 }) 45 })
46 46
47 it('Should upload 5 videos in a specific category, tag and channel but not include them in overview', async function () { 47 it('Should upload 5 videos in a specific category, tag and channel but not include them in overview', async function () {
48 this.timeout(15000) 48 this.timeout(30000)
49 49
50 await wait(3000) 50 await wait(3000)
51 51
@@ -61,7 +61,7 @@ describe('Test a videos overview', function () {
61 }) 61 })
62 62
63 it('Should upload another video and include all videos in the overview', async function () { 63 it('Should upload another video and include all videos in the overview', async function () {
64 this.timeout(15000) 64 this.timeout(30000)
65 65
66 for (let i = 1; i < 6; i++) { 66 for (let i = 1; i < 6; i++) {
67 await uploadVideo(server.url, server.accessToken, { 67 await uploadVideo(server.url, server.accessToken, {
diff --git a/server/tests/cli/prune-storage.ts b/server/tests/cli/prune-storage.ts
index 591ed217f..a0af09de8 100644
--- a/server/tests/cli/prune-storage.ts
+++ b/server/tests/cli/prune-storage.ts
@@ -2,7 +2,10 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import { waitJobs } from '../../../shared/extra-utils/server/jobs' 5import { createFile, readdir } from 'fs-extra'
6import { join } from 'path'
7import { buildUUID } from '@server/helpers/uuid'
8import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
6import { 9import {
7 buildServerDirectory, 10 buildServerDirectory,
8 cleanupTests, 11 cleanupTests,
@@ -12,6 +15,7 @@ import {
12 flushAndRunMultipleServers, 15 flushAndRunMultipleServers,
13 getAccount, 16 getAccount,
14 getEnvCli, 17 getEnvCli,
18 killallServers,
15 makeGetRequest, 19 makeGetRequest,
16 ServerInfo, 20 ServerInfo,
17 setAccessTokensToServers, 21 setAccessTokensToServers,
@@ -20,11 +24,8 @@ import {
20 uploadVideo, 24 uploadVideo,
21 wait 25 wait
22} from '../../../shared/extra-utils' 26} from '../../../shared/extra-utils'
27import { waitJobs } from '../../../shared/extra-utils/server/jobs'
23import { Account, VideoPlaylistPrivacy } from '../../../shared/models' 28import { Account, VideoPlaylistPrivacy } from '../../../shared/models'
24import { createFile, readdir } from 'fs-extra'
25import { v4 as uuidv4 } from 'uuid'
26import { join } from 'path'
27import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
28 29
29const expect = chai.expect 30const expect = chai.expect
30 31
@@ -116,6 +117,9 @@ describe('Test prune storage scripts', function () {
116 await wait(1000) 117 await wait(1000)
117 118
118 await waitJobs(servers) 119 await waitJobs(servers)
120 killallServers(servers)
121
122 await wait(1000)
119 }) 123 })
120 124
121 it('Should have the files on the disk', async function () { 125 it('Should have the files on the disk', async function () {
@@ -127,8 +131,8 @@ describe('Test prune storage scripts', function () {
127 { 131 {
128 const base = buildServerDirectory(servers[0], 'videos') 132 const base = buildServerDirectory(servers[0], 'videos')
129 133
130 const n1 = uuidv4() + '.mp4' 134 const n1 = buildUUID() + '.mp4'
131 const n2 = uuidv4() + '.webm' 135 const n2 = buildUUID() + '.webm'
132 136
133 await createFile(join(base, n1)) 137 await createFile(join(base, n1))
134 await createFile(join(base, n2)) 138 await createFile(join(base, n2))
@@ -139,8 +143,8 @@ describe('Test prune storage scripts', function () {
139 { 143 {
140 const base = buildServerDirectory(servers[0], 'torrents') 144 const base = buildServerDirectory(servers[0], 'torrents')
141 145
142 const n1 = uuidv4() + '-240.torrent' 146 const n1 = buildUUID() + '-240.torrent'
143 const n2 = uuidv4() + '-480.torrent' 147 const n2 = buildUUID() + '-480.torrent'
144 148
145 await createFile(join(base, n1)) 149 await createFile(join(base, n1))
146 await createFile(join(base, n2)) 150 await createFile(join(base, n2))
@@ -151,8 +155,8 @@ describe('Test prune storage scripts', function () {
151 { 155 {
152 const base = buildServerDirectory(servers[0], 'thumbnails') 156 const base = buildServerDirectory(servers[0], 'thumbnails')
153 157
154 const n1 = uuidv4() + '.jpg' 158 const n1 = buildUUID() + '.jpg'
155 const n2 = uuidv4() + '.jpg' 159 const n2 = buildUUID() + '.jpg'
156 160
157 await createFile(join(base, n1)) 161 await createFile(join(base, n1))
158 await createFile(join(base, n2)) 162 await createFile(join(base, n2))
@@ -163,8 +167,8 @@ describe('Test prune storage scripts', function () {
163 { 167 {
164 const base = buildServerDirectory(servers[0], 'previews') 168 const base = buildServerDirectory(servers[0], 'previews')
165 169
166 const n1 = uuidv4() + '.jpg' 170 const n1 = buildUUID() + '.jpg'
167 const n2 = uuidv4() + '.jpg' 171 const n2 = buildUUID() + '.jpg'
168 172
169 await createFile(join(base, n1)) 173 await createFile(join(base, n1))
170 await createFile(join(base, n2)) 174 await createFile(join(base, n2))
@@ -175,8 +179,8 @@ describe('Test prune storage scripts', function () {
175 { 179 {
176 const base = buildServerDirectory(servers[0], 'avatars') 180 const base = buildServerDirectory(servers[0], 'avatars')
177 181
178 const n1 = uuidv4() + '.png' 182 const n1 = buildUUID() + '.png'
179 const n2 = uuidv4() + '.jpg' 183 const n2 = buildUUID() + '.jpg'
180 184
181 await createFile(join(base, n1)) 185 await createFile(join(base, n1))
182 await createFile(join(base, n2)) 186 await createFile(join(base, n2))
diff --git a/server/tests/client.ts b/server/tests/client.ts
index 3c99bcd1f..7c4fb4e46 100644
--- a/server/tests/client.ts
+++ b/server/tests/client.ts
@@ -2,8 +2,9 @@
2 2
3import 'mocha' 3import 'mocha'
4import * as chai from 'chai' 4import * as chai from 'chai'
5import * as request from 'supertest' 5import { omit } from 'lodash'
6import { Account, VideoPlaylistPrivacy } from '@shared/models' 6import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
7import { Account, CustomConfig, HTMLServerConfig, ServerConfig, VideoPlaylistCreateResult, VideoPlaylistPrivacy } from '@shared/models'
7import { 8import {
8 addVideoInPlaylist, 9 addVideoInPlaylist,
9 cleanupTests, 10 cleanupTests,
@@ -11,8 +12,10 @@ import {
11 doubleFollow, 12 doubleFollow,
12 flushAndRunMultipleServers, 13 flushAndRunMultipleServers,
13 getAccount, 14 getAccount,
15 getConfig,
14 getCustomConfig, 16 getCustomConfig,
15 getVideosList, 17 getVideosList,
18 makeGetRequest,
16 makeHTMLRequest, 19 makeHTMLRequest,
17 ServerInfo, 20 ServerInfo,
18 setAccessTokensToServers, 21 setAccessTokensToServers,
@@ -24,14 +27,16 @@ import {
24 uploadVideo, 27 uploadVideo,
25 waitJobs 28 waitJobs
26} from '../../shared/extra-utils' 29} from '../../shared/extra-utils'
27import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
28 30
29const expect = chai.expect 31const expect = chai.expect
30 32
31function checkIndexTags (html: string, title: string, description: string, css: string) { 33function checkIndexTags (html: string, title: string, description: string, css: string, config: ServerConfig) {
32 expect(html).to.contain('<title>' + title + '</title>') 34 expect(html).to.contain('<title>' + title + '</title>')
33 expect(html).to.contain('<meta name="description" content="' + description + '" />') 35 expect(html).to.contain('<meta name="description" content="' + description + '" />')
34 expect(html).to.contain('<style class="custom-css-style">' + css + '</style>') 36 expect(html).to.contain('<style class="custom-css-style">' + css + '</style>')
37
38 const htmlConfig: HTMLServerConfig = omit(config, 'signup')
39 expect(html).to.contain(`<script type="application/javascript">window.PeerTubeServerConfig = '${JSON.stringify(htmlConfig)}'</script>`)
35} 40}
36 41
37describe('Test a client controllers', function () { 42describe('Test a client controllers', function () {
@@ -44,10 +49,16 @@ describe('Test a client controllers', function () {
44 49
45 const playlistName = 'super playlist name' 50 const playlistName = 'super playlist name'
46 const playlistDescription = 'super playlist description' 51 const playlistDescription = 'super playlist description'
47 let playlistUUID: string 52 let playlist: VideoPlaylistCreateResult
48 53
49 const channelDescription = 'my super channel description' 54 const channelDescription = 'my super channel description'
50 55
56 const watchVideoBasePaths = [ '/videos/watch/', '/w/' ]
57 const watchPlaylistBasePaths = [ '/videos/watch/playlist/', '/w/p/' ]
58
59 let videoIds: (string | number)[] = []
60 let playlistIds: (string | number)[] = []
61
51 before(async function () { 62 before(async function () {
52 this.timeout(120000) 63 this.timeout(120000)
53 64
@@ -70,7 +81,9 @@ describe('Test a client controllers', function () {
70 const videos = resVideosRequest.body.data 81 const videos = resVideosRequest.body.data
71 expect(videos.length).to.equal(1) 82 expect(videos.length).to.equal(1)
72 83
73 servers[0].video = videos[0] 84 const video = videos[0]
85 servers[0].video = video
86 videoIds = [ video.id, video.uuid, video.shortUUID ]
74 87
75 // Playlist 88 // Playlist
76 89
@@ -82,16 +95,14 @@ describe('Test a client controllers', function () {
82 } 95 }
83 96
84 const resVideoPlaylistRequest = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs }) 97 const resVideoPlaylistRequest = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs })
85 98 playlist = resVideoPlaylistRequest.body.videoPlaylist
86 const playlist = resVideoPlaylistRequest.body.videoPlaylist 99 playlistIds = [ playlist.id, playlist.shortUUID, playlist.uuid ]
87 const playlistId = playlist.id
88 playlistUUID = playlist.uuid
89 100
90 await addVideoInPlaylist({ 101 await addVideoInPlaylist({
91 url: servers[0].url, 102 url: servers[0].url,
92 token: servers[0].accessToken, 103 token: servers[0].accessToken,
93 playlistId, 104 playlistId: playlist.shortUUID,
94 elementAttrs: { videoId: servers[0].video.id } 105 elementAttrs: { videoId: video.id }
95 }) 106 })
96 107
97 // Account 108 // Account
@@ -105,201 +116,277 @@ describe('Test a client controllers', function () {
105 }) 116 })
106 117
107 describe('oEmbed', function () { 118 describe('oEmbed', function () {
119
108 it('Should have valid oEmbed discovery tags for videos', async function () { 120 it('Should have valid oEmbed discovery tags for videos', async function () {
109 const path = '/videos/watch/' + servers[0].video.uuid 121 for (const basePath of watchVideoBasePaths) {
110 const res = await request(servers[0].url) 122 for (const id of videoIds) {
111 .get(path) 123 const res = await makeGetRequest({
112 .set('Accept', 'text/html') 124 url: servers[0].url,
113 .expect(HttpStatusCode.OK_200) 125 path: basePath + id,
126 accept: 'text/html',
127 statusCodeExpected: HttpStatusCode.OK_200
128 })
129
130 const port = servers[0].port
131
132 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
133 `url=http%3A%2F%2Flocalhost%3A${port}%2Fw%2F${servers[0].video.uuid}" ` +
134 `title="${servers[0].video.name}" />`
135
136 expect(res.text).to.contain(expectedLink)
137 }
138 }
139 })
114 140
115 const port = servers[0].port 141 it('Should have valid oEmbed discovery tags for a playlist', async function () {
142 for (const basePath of watchPlaylistBasePaths) {
143 for (const id of playlistIds) {
144 const res = await makeGetRequest({
145 url: servers[0].url,
146 path: basePath + id,
147 accept: 'text/html',
148 statusCodeExpected: HttpStatusCode.OK_200
149 })
150
151 const port = servers[0].port
152
153 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' +
154 `url=http%3A%2F%2Flocalhost%3A${port}%2Fw%2Fp%2F${playlist.uuid}" ` +
155 `title="${playlistName}" />`
156
157 expect(res.text).to.contain(expectedLink)
158 }
159 }
160 })
161 })
116 162
117 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' + 163 describe('Open Graph', function () {
118 `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2F${servers[0].video.uuid}" ` +
119 `title="${servers[0].video.name}" />`
120 164
121 expect(res.text).to.contain(expectedLink) 165 async function accountPageTest (path: string) {
122 }) 166 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
167 const text = res.text
123 168
124 it('Should have valid oEmbed discovery tags for a playlist', async function () { 169 expect(text).to.contain(`<meta property="og:title" content="${account.displayName}" />`)
125 const res = await request(servers[0].url) 170 expect(text).to.contain(`<meta property="og:description" content="${account.description}" />`)
126 .get('/videos/watch/playlist/' + playlistUUID) 171 expect(text).to.contain('<meta property="og:type" content="website" />')
127 .set('Accept', 'text/html') 172 expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/accounts/${servers[0].user.username}" />`)
128 .expect(HttpStatusCode.OK_200) 173 }
129 174
130 const port = servers[0].port 175 async function channelPageTest (path: string) {
176 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
177 const text = res.text
131 178
132 const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' + 179 expect(text).to.contain(`<meta property="og:title" content="${servers[0].videoChannel.displayName}" />`)
133 `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2Fplaylist%2F${playlistUUID}" ` + 180 expect(text).to.contain(`<meta property="og:description" content="${channelDescription}" />`)
134 `title="${playlistName}" />` 181 expect(text).to.contain('<meta property="og:type" content="website" />')
182 expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].videoChannel.name}" />`)
183 }
135 184
136 expect(res.text).to.contain(expectedLink) 185 async function watchVideoPageTest (path: string) {
137 }) 186 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
138 }) 187 const text = res.text
139 188
140 describe('Open Graph', function () { 189 expect(text).to.contain(`<meta property="og:title" content="${videoName}" />`)
190 expect(text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`)
191 expect(text).to.contain('<meta property="og:type" content="video" />')
192 expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/w/${servers[0].video.uuid}" />`)
193 }
194
195 async function watchPlaylistPageTest (path: string) {
196 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
197 const text = res.text
198
199 expect(text).to.contain(`<meta property="og:title" content="${playlistName}" />`)
200 expect(text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`)
201 expect(text).to.contain('<meta property="og:type" content="video" />')
202 expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/w/p/${playlist.uuid}" />`)
203 }
141 204
142 it('Should have valid Open Graph tags on the account page', async function () { 205 it('Should have valid Open Graph tags on the account page', async function () {
143 const res = await request(servers[0].url) 206 await accountPageTest('/accounts/' + servers[0].user.username)
144 .get('/accounts/' + servers[0].user.username) 207 await accountPageTest('/a/' + servers[0].user.username)
145 .set('Accept', 'text/html') 208 await accountPageTest('/@' + servers[0].user.username)
146 .expect(HttpStatusCode.OK_200)
147
148 expect(res.text).to.contain(`<meta property="og:title" content="${account.displayName}" />`)
149 expect(res.text).to.contain(`<meta property="og:description" content="${account.description}" />`)
150 expect(res.text).to.contain('<meta property="og:type" content="website" />')
151 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/accounts/${servers[0].user.username}" />`)
152 }) 209 })
153 210
154 it('Should have valid Open Graph tags on the channel page', async function () { 211 it('Should have valid Open Graph tags on the channel page', async function () {
155 const res = await request(servers[0].url) 212 await channelPageTest('/video-channels/' + servers[0].videoChannel.name)
156 .get('/video-channels/' + servers[0].videoChannel.name) 213 await channelPageTest('/c/' + servers[0].videoChannel.name)
157 .set('Accept', 'text/html') 214 await channelPageTest('/@' + servers[0].videoChannel.name)
158 .expect(HttpStatusCode.OK_200)
159
160 expect(res.text).to.contain(`<meta property="og:title" content="${servers[0].videoChannel.displayName}" />`)
161 expect(res.text).to.contain(`<meta property="og:description" content="${channelDescription}" />`)
162 expect(res.text).to.contain('<meta property="og:type" content="website" />')
163 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].videoChannel.name}" />`)
164 }) 215 })
165 216
166 it('Should have valid Open Graph tags on the watch page with video id', async function () { 217 it('Should have valid Open Graph tags on the watch page', async function () {
167 const res = await request(servers[0].url) 218 for (const path of watchVideoBasePaths) {
168 .get('/videos/watch/' + servers[0].video.id) 219 for (const id of videoIds) {
169 .set('Accept', 'text/html') 220 await watchVideoPageTest(path + id)
170 .expect(HttpStatusCode.OK_200) 221 }
171 222 }
172 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
173 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`)
174 expect(res.text).to.contain('<meta property="og:type" content="video" />')
175 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
176 })
177
178 it('Should have valid Open Graph tags on the watch page with video uuid', async function () {
179 const res = await request(servers[0].url)
180 .get('/videos/watch/' + servers[0].video.uuid)
181 .set('Accept', 'text/html')
182 .expect(HttpStatusCode.OK_200)
183
184 expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`)
185 expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`)
186 expect(res.text).to.contain('<meta property="og:type" content="video" />')
187 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
188 }) 223 })
189 224
190 it('Should have valid Open Graph tags on the watch playlist page', async function () { 225 it('Should have valid Open Graph tags on the watch playlist page', async function () {
191 const res = await request(servers[0].url) 226 for (const path of watchPlaylistBasePaths) {
192 .get('/videos/watch/playlist/' + playlistUUID) 227 for (const id of playlistIds) {
193 .set('Accept', 'text/html') 228 await watchPlaylistPageTest(path + id)
194 .expect(HttpStatusCode.OK_200) 229 }
195 230 }
196 expect(res.text).to.contain(`<meta property="og:title" content="${playlistName}" />`)
197 expect(res.text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`)
198 expect(res.text).to.contain('<meta property="og:type" content="video" />')
199 expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/playlist/${playlistUUID}" />`)
200 }) 231 })
201 }) 232 })
202 233
203 describe('Twitter card', async function () { 234 describe('Twitter card', async function () {
204 235
205 it('Should have valid twitter card on the watch video page', async function () { 236 describe('Not whitelisted', function () {
206 const res = await request(servers[0].url)
207 .get('/videos/watch/' + servers[0].video.uuid)
208 .set('Accept', 'text/html')
209 .expect(HttpStatusCode.OK_200)
210 237
211 expect(res.text).to.contain('<meta property="twitter:card" content="summary_large_image" />') 238 async function accountPageTest (path: string) {
212 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') 239 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
213 expect(res.text).to.contain(`<meta property="twitter:title" content="${videoName}" />`) 240 const text = res.text
214 expect(res.text).to.contain(`<meta property="twitter:description" content="${videoDescriptionPlainText}" />`)
215 })
216 241
217 it('Should have valid twitter card on the watch playlist page', async function () { 242 expect(text).to.contain('<meta property="twitter:card" content="summary" />')
218 const res = await request(servers[0].url) 243 expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
219 .get('/videos/watch/playlist/' + playlistUUID) 244 expect(text).to.contain(`<meta property="twitter:title" content="${account.name}" />`)
220 .set('Accept', 'text/html') 245 expect(text).to.contain(`<meta property="twitter:description" content="${account.description}" />`)
221 .expect(HttpStatusCode.OK_200) 246 }
222 247
223 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />') 248 async function channelPageTest (path: string) {
224 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') 249 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
225 expect(res.text).to.contain(`<meta property="twitter:title" content="${playlistName}" />`) 250 const text = res.text
226 expect(res.text).to.contain(`<meta property="twitter:description" content="${playlistDescription}" />`)
227 })
228 251
229 it('Should have valid twitter card on the account page', async function () { 252 expect(text).to.contain('<meta property="twitter:card" content="summary" />')
230 const res = await request(servers[0].url) 253 expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
231 .get('/accounts/' + account.name) 254 expect(text).to.contain(`<meta property="twitter:title" content="${servers[0].videoChannel.displayName}" />`)
232 .set('Accept', 'text/html') 255 expect(text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`)
233 .expect(HttpStatusCode.OK_200) 256 }
234 257
235 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />') 258 async function watchVideoPageTest (path: string) {
236 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') 259 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
237 expect(res.text).to.contain(`<meta property="twitter:title" content="${account.name}" />`) 260 const text = res.text
238 expect(res.text).to.contain(`<meta property="twitter:description" content="${account.description}" />`) 261
239 }) 262 expect(text).to.contain('<meta property="twitter:card" content="summary_large_image" />')
263 expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
264 expect(text).to.contain(`<meta property="twitter:title" content="${videoName}" />`)
265 expect(text).to.contain(`<meta property="twitter:description" content="${videoDescriptionPlainText}" />`)
266 }
240 267
241 it('Should have valid twitter card on the channel page', async function () { 268 async function watchPlaylistPageTest (path: string) {
242 const res = await request(servers[0].url) 269 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
243 .get('/video-channels/' + servers[0].videoChannel.name) 270 const text = res.text
244 .set('Accept', 'text/html') 271
245 .expect(HttpStatusCode.OK_200) 272 expect(text).to.contain('<meta property="twitter:card" content="summary" />')
273 expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
274 expect(text).to.contain(`<meta property="twitter:title" content="${playlistName}" />`)
275 expect(text).to.contain(`<meta property="twitter:description" content="${playlistDescription}" />`)
276 }
246 277
247 expect(res.text).to.contain('<meta property="twitter:card" content="summary" />') 278 it('Should have valid twitter card on the watch video page', async function () {
248 expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') 279 for (const path of watchVideoBasePaths) {
249 expect(res.text).to.contain(`<meta property="twitter:title" content="${servers[0].videoChannel.displayName}" />`) 280 for (const id of videoIds) {
250 expect(res.text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`) 281 await watchVideoPageTest(path + id)
282 }
283 }
284 })
285
286 it('Should have valid twitter card on the watch playlist page', async function () {
287 for (const path of watchPlaylistBasePaths) {
288 for (const id of playlistIds) {
289 await watchPlaylistPageTest(path + id)
290 }
291 }
292 })
293
294 it('Should have valid twitter card on the account page', async function () {
295 await accountPageTest('/accounts/' + account.name)
296 await accountPageTest('/a/' + account.name)
297 await accountPageTest('/@' + account.name)
298 })
299
300 it('Should have valid twitter card on the channel page', async function () {
301 await channelPageTest('/video-channels/' + servers[0].videoChannel.name)
302 await channelPageTest('/c/' + servers[0].videoChannel.name)
303 await channelPageTest('/@' + servers[0].videoChannel.name)
304 })
251 }) 305 })
252 306
253 it('Should have valid twitter card if Twitter is whitelisted', async function () { 307 describe('Whitelisted', function () {
254 const res1 = await getCustomConfig(servers[0].url, servers[0].accessToken) 308
255 const config = res1.body 309 before(async function () {
256 config.services.twitter = { 310 const res = await getCustomConfig(servers[0].url, servers[0].accessToken)
257 username: '@Kuja', 311 const config = res.body as CustomConfig
258 whitelisted: true 312 config.services.twitter = {
313 username: '@Kuja',
314 whitelisted: true
315 }
316
317 await updateCustomConfig(servers[0].url, servers[0].accessToken, config)
318 })
319
320 async function accountPageTest (path: string) {
321 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
322 const text = res.text
323
324 expect(text).to.contain('<meta property="twitter:card" content="summary" />')
325 expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />')
259 } 326 }
260 await updateCustomConfig(servers[0].url, servers[0].accessToken, config)
261 327
262 const resVideoRequest = await request(servers[0].url) 328 async function channelPageTest (path: string) {
263 .get('/videos/watch/' + servers[0].video.uuid) 329 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
264 .set('Accept', 'text/html') 330 const text = res.text
265 .expect(HttpStatusCode.OK_200)
266 331
267 expect(resVideoRequest.text).to.contain('<meta property="twitter:card" content="player" />') 332 expect(text).to.contain('<meta property="twitter:card" content="summary" />')
268 expect(resVideoRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />') 333 expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />')
334 }
269 335
270 const resVideoPlaylistRequest = await request(servers[0].url) 336 async function watchVideoPageTest (path: string) {
271 .get('/videos/watch/playlist/' + playlistUUID) 337 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
272 .set('Accept', 'text/html') 338 const text = res.text
273 .expect(HttpStatusCode.OK_200)
274 339
275 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:card" content="player" />') 340 expect(text).to.contain('<meta property="twitter:card" content="player" />')
276 expect(resVideoPlaylistRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />') 341 expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />')
342 }
277 343
278 const resAccountRequest = await request(servers[0].url) 344 async function watchPlaylistPageTest (path: string) {
279 .get('/accounts/' + account.name) 345 const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
280 .set('Accept', 'text/html') 346 const text = res.text
281 .expect(HttpStatusCode.OK_200)
282 347
283 expect(resAccountRequest.text).to.contain('<meta property="twitter:card" content="summary" />') 348 expect(text).to.contain('<meta property="twitter:card" content="player" />')
284 expect(resAccountRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />') 349 expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />')
350 }
285 351
286 const resChannelRequest = await request(servers[0].url) 352 it('Should have valid twitter card on the watch video page', async function () {
287 .get('/video-channels/' + servers[0].videoChannel.name) 353 for (const path of watchVideoBasePaths) {
288 .set('Accept', 'text/html') 354 for (const id of videoIds) {
289 .expect(HttpStatusCode.OK_200) 355 await watchVideoPageTest(path + id)
356 }
357 }
358 })
359
360 it('Should have valid twitter card on the watch playlist page', async function () {
361 for (const path of watchPlaylistBasePaths) {
362 for (const id of playlistIds) {
363 await watchPlaylistPageTest(path + id)
364 }
365 }
366 })
290 367
291 expect(resChannelRequest.text).to.contain('<meta property="twitter:card" content="summary" />') 368 it('Should have valid twitter card on the account page', async function () {
292 expect(resChannelRequest.text).to.contain('<meta property="twitter:site" content="@Kuja" />') 369 await accountPageTest('/accounts/' + account.name)
370 await accountPageTest('/a/' + account.name)
371 await accountPageTest('/@' + account.name)
372 })
373
374 it('Should have valid twitter card on the channel page', async function () {
375 await channelPageTest('/video-channels/' + servers[0].videoChannel.name)
376 await channelPageTest('/c/' + servers[0].videoChannel.name)
377 await channelPageTest('/@' + servers[0].videoChannel.name)
378 })
293 }) 379 })
294 }) 380 })
295 381
296 describe('Index HTML', function () { 382 describe('Index HTML', function () {
297 383
298 it('Should have valid index html tags (title, description...)', async function () { 384 it('Should have valid index html tags (title, description...)', async function () {
385 const resConfig = await getConfig(servers[0].url)
299 const res = await makeHTMLRequest(servers[0].url, '/videos/trending') 386 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
300 387
301 const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.' 388 const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.'
302 checkIndexTags(res.text, 'PeerTube', description, '') 389 checkIndexTags(res.text, 'PeerTube', description, '', resConfig.body)
303 }) 390 })
304 391
305 it('Should update the customized configuration and have the correct index html tags', async function () { 392 it('Should update the customized configuration and have the correct index html tags', async function () {
@@ -318,35 +405,65 @@ describe('Test a client controllers', function () {
318 } 405 }
319 }) 406 })
320 407
408 const resConfig = await getConfig(servers[0].url)
321 const res = await makeHTMLRequest(servers[0].url, '/videos/trending') 409 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
322 410
323 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }') 411 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
324 }) 412 })
325 413
326 it('Should have valid index html updated tags (title, description...)', async function () { 414 it('Should have valid index html updated tags (title, description...)', async function () {
415 const resConfig = await getConfig(servers[0].url)
327 const res = await makeHTMLRequest(servers[0].url, '/videos/trending') 416 const res = await makeHTMLRequest(servers[0].url, '/videos/trending')
328 417
329 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }') 418 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
330 }) 419 })
331 420
332 it('Should use the original video URL for the canonical tag', async function () { 421 it('Should use the original video URL for the canonical tag', async function () {
333 const res = await makeHTMLRequest(servers[1].url, '/videos/watch/' + servers[0].video.uuid) 422 for (const basePath of watchVideoBasePaths) {
334 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`) 423 for (const id of videoIds) {
424 const res = await makeHTMLRequest(servers[1].url, basePath + id)
425 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`)
426 }
427 }
335 }) 428 })
336 429
337 it('Should use the original account URL for the canonical tag', async function () { 430 it('Should use the original account URL for the canonical tag', async function () {
338 const res = await makeHTMLRequest(servers[1].url, '/accounts/root@' + servers[0].host) 431 const accountURLtest = (res) => {
339 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/accounts/root" />`) 432 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/accounts/root" />`)
433 }
434
435 accountURLtest(await makeHTMLRequest(servers[1].url, '/accounts/root@' + servers[0].host))
436 accountURLtest(await makeHTMLRequest(servers[1].url, '/a/root@' + servers[0].host))
437 accountURLtest(await makeHTMLRequest(servers[1].url, '/@root@' + servers[0].host))
340 }) 438 })
341 439
342 it('Should use the original channel URL for the canonical tag', async function () { 440 it('Should use the original channel URL for the canonical tag', async function () {
343 const res = await makeHTMLRequest(servers[1].url, '/video-channels/root_channel@' + servers[0].host) 441 const channelURLtests = (res) => {
344 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-channels/root_channel" />`) 442 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-channels/root_channel" />`)
443 }
444
445 channelURLtests(await makeHTMLRequest(servers[1].url, '/video-channels/root_channel@' + servers[0].host))
446 channelURLtests(await makeHTMLRequest(servers[1].url, '/c/root_channel@' + servers[0].host))
447 channelURLtests(await makeHTMLRequest(servers[1].url, '/@root_channel@' + servers[0].host))
345 }) 448 })
346 449
347 it('Should use the original playlist URL for the canonical tag', async function () { 450 it('Should use the original playlist URL for the canonical tag', async function () {
348 const res = await makeHTMLRequest(servers[1].url, '/videos/watch/playlist/' + playlistUUID) 451 for (const basePath of watchPlaylistBasePaths) {
349 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-playlists/${playlistUUID}" />`) 452 for (const id of playlistIds) {
453 const res = await makeHTMLRequest(servers[1].url, basePath + id)
454 expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-playlists/${playlist.uuid}" />`)
455 }
456 }
457 })
458 })
459
460 describe('Embed HTML', function () {
461
462 it('Should have the correct embed html tags', async function () {
463 const resConfig = await getConfig(servers[0].url)
464 const res = await makeHTMLRequest(servers[0].url, servers[0].video.embedPath)
465
466 checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body)
350 }) 467 })
351 }) 468 })
352 469
diff --git a/server/tests/external-plugins/auto-block-videos.ts b/server/tests/external-plugins/auto-block-videos.ts
index 1b91d141e..18ea17d78 100644
--- a/server/tests/external-plugins/auto-block-videos.ts
+++ b/server/tests/external-plugins/auto-block-videos.ts
@@ -40,6 +40,7 @@ describe('Official plugin auto-block videos', function () {
40 let blocklistServer: MockBlocklist 40 let blocklistServer: MockBlocklist
41 let server1Videos: Video[] = [] 41 let server1Videos: Video[] = []
42 let server2Videos: Video[] = [] 42 let server2Videos: Video[] = []
43 let port: number
43 44
44 before(async function () { 45 before(async function () {
45 this.timeout(60000) 46 this.timeout(60000)
@@ -56,7 +57,7 @@ describe('Official plugin auto-block videos', function () {
56 } 57 }
57 58
58 blocklistServer = new MockBlocklist() 59 blocklistServer = new MockBlocklist()
59 await blocklistServer.initialize() 60 port = await blocklistServer.initialize()
60 61
61 await uploadVideoAndGetId({ server: servers[0], videoName: 'video server 1' }) 62 await uploadVideoAndGetId({ server: servers[0], videoName: 'video server 1' })
62 await uploadVideoAndGetId({ server: servers[1], videoName: 'video server 2' }) 63 await uploadVideoAndGetId({ server: servers[1], videoName: 'video server 2' })
@@ -82,7 +83,7 @@ describe('Official plugin auto-block videos', function () {
82 accessToken: servers[0].accessToken, 83 accessToken: servers[0].accessToken,
83 npmName: 'peertube-plugin-auto-block-videos', 84 npmName: 'peertube-plugin-auto-block-videos',
84 settings: { 85 settings: {
85 'blocklist-urls': 'http://localhost:42100/blocklist', 86 'blocklist-urls': `http://localhost:${port}/blocklist`,
86 'check-seconds-interval': 1 87 'check-seconds-interval': 1
87 } 88 }
88 }) 89 })
diff --git a/server/tests/external-plugins/auto-mute.ts b/server/tests/external-plugins/auto-mute.ts
index 687f56e98..09355d932 100644
--- a/server/tests/external-plugins/auto-mute.ts
+++ b/server/tests/external-plugins/auto-mute.ts
@@ -31,6 +31,7 @@ describe('Official plugin auto-mute', function () {
31 const autoMuteListPath = '/plugins/auto-mute/router/api/v1/mute-list' 31 const autoMuteListPath = '/plugins/auto-mute/router/api/v1/mute-list'
32 let servers: ServerInfo[] 32 let servers: ServerInfo[]
33 let blocklistServer: MockBlocklist 33 let blocklistServer: MockBlocklist
34 let port: number
34 35
35 before(async function () { 36 before(async function () {
36 this.timeout(30000) 37 this.timeout(30000)
@@ -47,7 +48,7 @@ describe('Official plugin auto-mute', function () {
47 } 48 }
48 49
49 blocklistServer = new MockBlocklist() 50 blocklistServer = new MockBlocklist()
50 await blocklistServer.initialize() 51 port = await blocklistServer.initialize()
51 52
52 await uploadVideoAndGetId({ server: servers[0], videoName: 'video server 1' }) 53 await uploadVideoAndGetId({ server: servers[0], videoName: 'video server 1' })
53 await uploadVideoAndGetId({ server: servers[1], videoName: 'video server 2' }) 54 await uploadVideoAndGetId({ server: servers[1], videoName: 'video server 2' })
@@ -61,7 +62,7 @@ describe('Official plugin auto-mute', function () {
61 accessToken: servers[0].accessToken, 62 accessToken: servers[0].accessToken,
62 npmName: 'peertube-plugin-auto-mute', 63 npmName: 'peertube-plugin-auto-mute',
63 settings: { 64 settings: {
64 'blocklist-urls': 'http://localhost:42100/blocklist', 65 'blocklist-urls': `http://localhost:${port}/blocklist`,
65 'check-seconds-interval': 1 66 'check-seconds-interval': 1
66 } 67 }
67 }) 68 })
diff --git a/server/tests/api/activitypub/json/mastodon/bad-body-http-signature.json b/server/tests/fixtures/ap-json/mastodon/bad-body-http-signature.json
index 4e7bc3af5..4e7bc3af5 100644
--- a/server/tests/api/activitypub/json/mastodon/bad-body-http-signature.json
+++ b/server/tests/fixtures/ap-json/mastodon/bad-body-http-signature.json
diff --git a/server/tests/api/activitypub/json/mastodon/bad-http-signature.json b/server/tests/fixtures/ap-json/mastodon/bad-http-signature.json
index 098597db0..098597db0 100644
--- a/server/tests/api/activitypub/json/mastodon/bad-http-signature.json
+++ b/server/tests/fixtures/ap-json/mastodon/bad-http-signature.json
diff --git a/server/tests/api/activitypub/json/mastodon/bad-public-key.json b/server/tests/fixtures/ap-json/mastodon/bad-public-key.json
index 73d18b3ad..73d18b3ad 100644
--- a/server/tests/api/activitypub/json/mastodon/bad-public-key.json
+++ b/server/tests/fixtures/ap-json/mastodon/bad-public-key.json
diff --git a/server/tests/api/activitypub/json/mastodon/create-bad-signature.json b/server/tests/fixtures/ap-json/mastodon/create-bad-signature.json
index 2cd037241..2cd037241 100644
--- a/server/tests/api/activitypub/json/mastodon/create-bad-signature.json
+++ b/server/tests/fixtures/ap-json/mastodon/create-bad-signature.json
diff --git a/server/tests/api/activitypub/json/mastodon/create.json b/server/tests/fixtures/ap-json/mastodon/create.json
index 0be271bb8..0be271bb8 100644
--- a/server/tests/api/activitypub/json/mastodon/create.json
+++ b/server/tests/fixtures/ap-json/mastodon/create.json
diff --git a/server/tests/api/activitypub/json/mastodon/http-signature.json b/server/tests/fixtures/ap-json/mastodon/http-signature.json
index 4e7bc3af5..4e7bc3af5 100644
--- a/server/tests/api/activitypub/json/mastodon/http-signature.json
+++ b/server/tests/fixtures/ap-json/mastodon/http-signature.json
diff --git a/server/tests/api/activitypub/json/mastodon/public-key.json b/server/tests/fixtures/ap-json/mastodon/public-key.json
index b7b9b8308..b7b9b8308 100644
--- a/server/tests/api/activitypub/json/mastodon/public-key.json
+++ b/server/tests/fixtures/ap-json/mastodon/public-key.json
diff --git a/server/tests/api/activitypub/json/peertube/announce-without-context.json b/server/tests/fixtures/ap-json/peertube/announce-without-context.json
index 5f2af0cde..5f2af0cde 100644
--- a/server/tests/api/activitypub/json/peertube/announce-without-context.json
+++ b/server/tests/fixtures/ap-json/peertube/announce-without-context.json
diff --git a/server/tests/api/activitypub/json/peertube/invalid-keys.json b/server/tests/fixtures/ap-json/peertube/invalid-keys.json
index 0544e96b9..0544e96b9 100644
--- a/server/tests/api/activitypub/json/peertube/invalid-keys.json
+++ b/server/tests/fixtures/ap-json/peertube/invalid-keys.json
diff --git a/server/tests/api/activitypub/json/peertube/keys.json b/server/tests/fixtures/ap-json/peertube/keys.json
index 1a7700865..1a7700865 100644
--- a/server/tests/api/activitypub/json/peertube/keys.json
+++ b/server/tests/fixtures/ap-json/peertube/keys.json
diff --git a/server/tests/fixtures/peertube-plugin-test-broken/main.js b/server/tests/fixtures/peertube-plugin-test-broken/main.js
new file mode 100644
index 000000000..afdb6f7a0
--- /dev/null
+++ b/server/tests/fixtures/peertube-plugin-test-broken/main.js
@@ -0,0 +1,12 @@
1async function register (options) {
2 options.unknownFunction()
3}
4
5async function unregister () {
6 return
7}
8
9module.exports = {
10 register,
11 unregister
12}
diff --git a/server/tests/fixtures/peertube-plugin-test-three/package.json b/server/tests/fixtures/peertube-plugin-test-broken/package.json
index 41d4c93fe..fd03df216 100644
--- a/server/tests/fixtures/peertube-plugin-test-three/package.json
+++ b/server/tests/fixtures/peertube-plugin-test-broken/package.json
@@ -1,7 +1,7 @@
1{ 1{
2 "name": "peertube-plugin-test-three", 2 "name": "peertube-plugin-test-broken",
3 "version": "0.0.1", 3 "version": "0.0.1",
4 "description": "Plugin test 3", 4 "description": "Plugin test broken",
5 "engine": { 5 "engine": {
6 "peertube": ">=1.3.0" 6 "peertube": ">=1.3.0"
7 }, 7 },
diff --git a/server/tests/fixtures/peertube-plugin-test-two/languages/fr.json b/server/tests/fixtures/peertube-plugin-test-filter-translations/languages/fr.json
index 52d8313df..52d8313df 100644
--- a/server/tests/fixtures/peertube-plugin-test-two/languages/fr.json
+++ b/server/tests/fixtures/peertube-plugin-test-filter-translations/languages/fr.json
diff --git a/server/tests/fixtures/peertube-plugin-test-two/languages/it.json b/server/tests/fixtures/peertube-plugin-test-filter-translations/languages/it.json
index 9e187d83b..9e187d83b 100644
--- a/server/tests/fixtures/peertube-plugin-test-two/languages/it.json
+++ b/server/tests/fixtures/peertube-plugin-test-filter-translations/languages/it.json
diff --git a/server/tests/fixtures/peertube-plugin-test-two/main.js b/server/tests/fixtures/peertube-plugin-test-filter-translations/main.js
index 71c11b2ba..71c11b2ba 100644
--- a/server/tests/fixtures/peertube-plugin-test-two/main.js
+++ b/server/tests/fixtures/peertube-plugin-test-filter-translations/main.js
diff --git a/server/tests/fixtures/peertube-plugin-test-two/package.json b/server/tests/fixtures/peertube-plugin-test-filter-translations/package.json
index 926f2d69b..2adce4743 100644
--- a/server/tests/fixtures/peertube-plugin-test-two/package.json
+++ b/server/tests/fixtures/peertube-plugin-test-filter-translations/package.json
@@ -1,7 +1,7 @@
1{ 1{
2 "name": "peertube-plugin-test-two", 2 "name": "peertube-plugin-test-filter-translations",
3 "version": "0.0.1", 3 "version": "0.0.1",
4 "description": "Plugin test 2", 4 "description": "Plugin test filter and translations",
5 "engine": { 5 "engine": {
6 "peertube": ">=1.3.0" 6 "peertube": ">=1.3.0"
7 }, 7 },
diff --git a/server/tests/fixtures/peertube-plugin-test-three/main.js b/server/tests/fixtures/peertube-plugin-test-video-constants/main.js
index f2b89bcf0..3e650e0a1 100644
--- a/server/tests/fixtures/peertube-plugin-test-three/main.js
+++ b/server/tests/fixtures/peertube-plugin-test-video-constants/main.js
@@ -11,8 +11,10 @@ async function register ({
11}) { 11}) {
12 videoLanguageManager.addLanguage('al_bhed', 'Al Bhed') 12 videoLanguageManager.addLanguage('al_bhed', 'Al Bhed')
13 videoLanguageManager.addLanguage('al_bhed2', 'Al Bhed 2') 13 videoLanguageManager.addLanguage('al_bhed2', 'Al Bhed 2')
14 videoLanguageManager.addLanguage('al_bhed3', 'Al Bhed 3')
14 videoLanguageManager.deleteLanguage('en') 15 videoLanguageManager.deleteLanguage('en')
15 videoLanguageManager.deleteLanguage('fr') 16 videoLanguageManager.deleteLanguage('fr')
17 videoLanguageManager.deleteLanguage('al_bhed3')
16 18
17 videoCategoryManager.addCategory(42, 'Best category') 19 videoCategoryManager.addCategory(42, 'Best category')
18 videoCategoryManager.addCategory(43, 'High best category') 20 videoCategoryManager.addCategory(43, 'High best category')
diff --git a/server/tests/fixtures/peertube-plugin-test-video-constants/package.json b/server/tests/fixtures/peertube-plugin-test-video-constants/package.json
new file mode 100644
index 000000000..0fcf39933
--- /dev/null
+++ b/server/tests/fixtures/peertube-plugin-test-video-constants/package.json
@@ -0,0 +1,20 @@
1{
2 "name": "peertube-plugin-test-video-constants",
3 "version": "0.0.1",
4 "description": "Plugin test video constants",
5 "engine": {
6 "peertube": ">=1.3.0"
7 },
8 "keywords": [
9 "peertube",
10 "plugin"
11 ],
12 "homepage": "https://github.com/Chocobozzz/PeerTube",
13 "author": "Chocobozzz",
14 "bugs": "https://github.com/Chocobozzz/PeerTube/issues",
15 "library": "./main.js",
16 "staticDirs": {},
17 "css": [],
18 "clientScripts": [],
19 "translations": {}
20}
diff --git a/server/tests/fixtures/peertube-plugin-test/main.js b/server/tests/fixtures/peertube-plugin-test/main.js
index ee0bc39f3..f8e6f0b98 100644
--- a/server/tests/fixtures/peertube-plugin-test/main.js
+++ b/server/tests/fixtures/peertube-plugin-test/main.js
@@ -19,7 +19,9 @@ async function register ({ registerHook, registerSetting, settingsManager, stora
19 'action:api.user.created', 19 'action:api.user.created',
20 'action:api.user.deleted', 20 'action:api.user.deleted',
21 'action:api.user.updated', 21 'action:api.user.updated',
22 'action:api.user.oauth2-got-token' 22 'action:api.user.oauth2-got-token',
23
24 'action:api.video-playlist-element.created'
23 ] 25 ]
24 26
25 for (const h of actionHooks) { 27 for (const h of actionHooks) {
@@ -241,6 +243,10 @@ async function register ({ registerHook, registerSetting, settingsManager, stora
241 'filter:api.search.video-channels.local.list.result', 243 'filter:api.search.video-channels.local.list.result',
242 'filter:api.search.video-channels.index.list.params', 244 'filter:api.search.video-channels.index.list.params',
243 'filter:api.search.video-channels.index.list.result', 245 'filter:api.search.video-channels.index.list.result',
246 'filter:api.search.video-playlists.local.list.params',
247 'filter:api.search.video-playlists.local.list.result',
248 'filter:api.search.video-playlists.index.list.params',
249 'filter:api.search.video-playlists.index.list.result'
244 ] 250 ]
245 251
246 for (const h of searchHooks) { 252 for (const h of searchHooks) {
diff --git a/server/tests/plugins/action-hooks.ts b/server/tests/plugins/action-hooks.ts
index ac9f2cea5..0f57ef7fe 100644
--- a/server/tests/plugins/action-hooks.ts
+++ b/server/tests/plugins/action-hooks.ts
@@ -1,13 +1,15 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { ServerHookName, VideoPrivacy } from '@shared/models' 4import { ServerHookName, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models'
5import { 5import {
6 addVideoCommentReply, 6 addVideoCommentReply,
7 addVideoCommentThread, 7 addVideoCommentThread,
8 addVideoInPlaylist,
8 blockUser, 9 blockUser,
9 createLive, 10 createLive,
10 createUser, 11 createUser,
12 createVideoPlaylist,
11 deleteVideoComment, 13 deleteVideoComment,
12 getPluginTestPath, 14 getPluginTestPath,
13 installPlugin, 15 installPlugin,
@@ -69,6 +71,7 @@ describe('Test plugin action hooks', function () {
69 }) 71 })
70 72
71 describe('Videos hooks', function () { 73 describe('Videos hooks', function () {
74
72 it('Should run action:api.video.uploaded', async function () { 75 it('Should run action:api.video.uploaded', async function () {
73 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' }) 76 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' })
74 videoUUID = res.body.video.uuid 77 videoUUID = res.body.video.uuid
@@ -177,6 +180,41 @@ describe('Test plugin action hooks', function () {
177 }) 180 })
178 }) 181 })
179 182
183 describe('Playlist hooks', function () {
184 let playlistId: number
185 let videoId: number
186
187 before(async function () {
188 {
189 const res = await createVideoPlaylist({
190 url: servers[0].url,
191 token: servers[0].accessToken,
192 playlistAttrs: {
193 displayName: 'My playlist',
194 privacy: VideoPlaylistPrivacy.PRIVATE
195 }
196 })
197 playlistId = res.body.videoPlaylist.id
198 }
199
200 {
201 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'my super name' })
202 videoId = res.body.video.id
203 }
204 })
205
206 it('Should run action:api.video-playlist-element.created', async function () {
207 await addVideoInPlaylist({
208 url: servers[0].url,
209 token: servers[0].accessToken,
210 playlistId,
211 elementAttrs: { videoId }
212 })
213
214 await checkHook('action:api.video-playlist-element.created')
215 })
216 })
217
180 after(async function () { 218 after(async function () {
181 await cleanupTests(servers) 219 await cleanupTests(servers)
182 }) 220 })
diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts
index 7d4f7abb4..644b41dea 100644
--- a/server/tests/plugins/filter-hooks.ts
+++ b/server/tests/plugins/filter-hooks.ts
@@ -8,6 +8,7 @@ import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-code
8import { 8import {
9 addVideoCommentReply, 9 addVideoCommentReply,
10 addVideoCommentThread, 10 addVideoCommentThread,
11 advancedVideoPlaylistSearch,
11 advancedVideosSearch, 12 advancedVideosSearch,
12 createLive, 13 createLive,
13 createVideoPlaylist, 14 createVideoPlaylist,
@@ -38,6 +39,7 @@ import {
38import { cleanupTests, flushAndRunMultipleServers, ServerInfo, waitUntilLog } from '../../../shared/extra-utils/server/servers' 39import { cleanupTests, flushAndRunMultipleServers, ServerInfo, waitUntilLog } from '../../../shared/extra-utils/server/servers'
39import { getGoodVideoUrl, getMyVideoImports, importVideo } from '../../../shared/extra-utils/videos/video-imports' 40import { getGoodVideoUrl, getMyVideoImports, importVideo } from '../../../shared/extra-utils/videos/video-imports'
40import { 41import {
42 VideoCommentThreadTree,
41 VideoDetails, 43 VideoDetails,
42 VideoImport, 44 VideoImport,
43 VideoImportState, 45 VideoImportState,
@@ -45,7 +47,6 @@ import {
45 VideoPlaylistPrivacy, 47 VideoPlaylistPrivacy,
46 VideoPrivacy 48 VideoPrivacy
47} from '../../../shared/models/videos' 49} from '../../../shared/models/videos'
48import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model'
49 50
50const expect = chai.expect 51const expect = chai.expect
51 52
@@ -71,7 +72,7 @@ describe('Test plugin filter hooks', function () {
71 await installPlugin({ 72 await installPlugin({
72 url: servers[0].url, 73 url: servers[0].url,
73 accessToken: servers[0].accessToken, 74 accessToken: servers[0].accessToken,
74 path: getPluginTestPath('-two') 75 path: getPluginTestPath('-filter-translations')
75 }) 76 })
76 77
77 for (let i = 0; i < 10; i++) { 78 for (let i = 0; i < 10; i++) {
@@ -326,7 +327,7 @@ describe('Test plugin filter hooks', function () {
326 }) 327 })
327 328
328 it('Should blacklist on remote upload', async function () { 329 it('Should blacklist on remote upload', async function () {
329 this.timeout(60000) 330 this.timeout(120000)
330 331
331 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'remote please blacklist me' }) 332 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'remote please blacklist me' })
332 await waitJobs(servers) 333 await waitJobs(servers)
@@ -335,7 +336,7 @@ describe('Test plugin filter hooks', function () {
335 }) 336 })
336 337
337 it('Should blacklist on remote update', async function () { 338 it('Should blacklist on remote update', async function () {
338 this.timeout(60000) 339 this.timeout(120000)
339 340
340 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video' }) 341 const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video' })
341 await waitJobs(servers) 342 await waitJobs(servers)
@@ -372,7 +373,7 @@ describe('Test plugin filter hooks', function () {
372 const downloadVideos: VideoDetails[] = [] 373 const downloadVideos: VideoDetails[] = []
373 374
374 before(async function () { 375 before(async function () {
375 this.timeout(60000) 376 this.timeout(120000)
376 377
377 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, { 378 await updateCustomSubConfig(servers[0].url, servers[0].accessToken, {
378 transcoding: { 379 transcoding: {
@@ -525,6 +526,27 @@ describe('Test plugin filter hooks', function () {
525 await waitUntilLog(servers[0], 'Run hook filter:api.search.video-channels.index.list.params', 1) 526 await waitUntilLog(servers[0], 'Run hook filter:api.search.video-channels.index.list.params', 1)
526 await waitUntilLog(servers[0], 'Run hook filter:api.search.video-channels.index.list.result', 1) 527 await waitUntilLog(servers[0], 'Run hook filter:api.search.video-channels.index.list.result', 1)
527 }) 528 })
529
530 it('Should run filter:api.search.video-playlists.local.list.{params,result}', async function () {
531 await advancedVideoPlaylistSearch(servers[0].url, {
532 search: 'Sun Jian'
533 })
534
535 await waitUntilLog(servers[0], 'Run hook filter:api.search.video-playlists.local.list.params', 1)
536 await waitUntilLog(servers[0], 'Run hook filter:api.search.video-playlists.local.list.result', 1)
537 })
538
539 it('Should run filter:api.search.video-playlists.index.list.{params,result}', async function () {
540 await advancedVideoPlaylistSearch(servers[0].url, {
541 search: 'Sun Jian',
542 searchTarget: 'search-index'
543 })
544
545 await waitUntilLog(servers[0], 'Run hook filter:api.search.video-playlists.local.list.params', 1)
546 await waitUntilLog(servers[0], 'Run hook filter:api.search.video-playlists.local.list.result', 1)
547 await waitUntilLog(servers[0], 'Run hook filter:api.search.video-playlists.index.list.params', 1)
548 await waitUntilLog(servers[0], 'Run hook filter:api.search.video-playlists.index.list.result', 1)
549 })
528 }) 550 })
529 551
530 after(async function () { 552 after(async function () {
diff --git a/server/tests/plugins/html-injection.ts b/server/tests/plugins/html-injection.ts
index 293c1df21..4fa8caa3a 100644
--- a/server/tests/plugins/html-injection.ts
+++ b/server/tests/plugins/html-injection.ts
@@ -15,7 +15,7 @@ import {
15 15
16const expect = chai.expect 16const expect = chai.expect
17 17
18describe('Test plugins HTML inection', function () { 18describe('Test plugins HTML injection', function () {
19 let server: ServerInfo = null 19 let server: ServerInfo = null
20 20
21 before(async function () { 21 before(async function () {
diff --git a/server/tests/plugins/plugin-helpers.ts b/server/tests/plugins/plugin-helpers.ts
index f72de8229..0296d6eb7 100644
--- a/server/tests/plugins/plugin-helpers.ts
+++ b/server/tests/plugins/plugin-helpers.ts
@@ -144,7 +144,7 @@ describe('Test plugin helpers', function () {
144 let videoUUIDServer1: string 144 let videoUUIDServer1: string
145 145
146 before(async function () { 146 before(async function () {
147 this.timeout(30000) 147 this.timeout(60000)
148 148
149 { 149 {
150 const res = await uploadVideoAndGetId({ server: servers[0], videoName: 'video server 1' }) 150 const res = await uploadVideoAndGetId({ server: servers[0], videoName: 'video server 1' })
diff --git a/server/tests/plugins/translations.ts b/server/tests/plugins/translations.ts
index 8dc2043b8..9fd2ba1c5 100644
--- a/server/tests/plugins/translations.ts
+++ b/server/tests/plugins/translations.ts
@@ -31,7 +31,7 @@ describe('Test plugin translations', function () {
31 await installPlugin({ 31 await installPlugin({
32 url: server.url, 32 url: server.url,
33 accessToken: server.accessToken, 33 accessToken: server.accessToken,
34 path: getPluginTestPath('-two') 34 path: getPluginTestPath('-filter-translations')
35 }) 35 })
36 }) 36 })
37 37
@@ -48,7 +48,7 @@ describe('Test plugin translations', function () {
48 'peertube-plugin-test': { 48 'peertube-plugin-test': {
49 Hi: 'Coucou' 49 Hi: 'Coucou'
50 }, 50 },
51 'peertube-plugin-test-two': { 51 'peertube-plugin-test-filter-translations': {
52 'Hello world': 'Bonjour le monde' 52 'Hello world': 'Bonjour le monde'
53 } 53 }
54 }) 54 })
@@ -58,14 +58,14 @@ describe('Test plugin translations', function () {
58 const res = await getPluginTranslations({ url: server.url, locale: 'it-IT' }) 58 const res = await getPluginTranslations({ url: server.url, locale: 'it-IT' })
59 59
60 expect(res.body).to.deep.equal({ 60 expect(res.body).to.deep.equal({
61 'peertube-plugin-test-two': { 61 'peertube-plugin-test-filter-translations': {
62 'Hello world': 'Ciao, mondo!' 62 'Hello world': 'Ciao, mondo!'
63 } 63 }
64 }) 64 })
65 }) 65 })
66 66
67 it('Should remove the plugin and remove the locales', async function () { 67 it('Should remove the plugin and remove the locales', async function () {
68 await uninstallPlugin({ url: server.url, accessToken: server.accessToken, npmName: 'peertube-plugin-test-two' }) 68 await uninstallPlugin({ url: server.url, accessToken: server.accessToken, npmName: 'peertube-plugin-test-filter-translations' })
69 69
70 { 70 {
71 const res = await getPluginTranslations({ url: server.url, locale: 'fr-FR' }) 71 const res = await getPluginTranslations({ url: server.url, locale: 'fr-FR' })
diff --git a/server/tests/plugins/video-constants.ts b/server/tests/plugins/video-constants.ts
index 5ee41fee1..eb014c596 100644
--- a/server/tests/plugins/video-constants.ts
+++ b/server/tests/plugins/video-constants.ts
@@ -32,7 +32,7 @@ describe('Test plugin altering video constants', function () {
32 await installPlugin({ 32 await installPlugin({
33 url: server.url, 33 url: server.url,
34 accessToken: server.accessToken, 34 accessToken: server.accessToken,
35 path: getPluginTestPath('-three') 35 path: getPluginTestPath('-video-constants')
36 }) 36 })
37 }) 37 })
38 38
@@ -45,6 +45,7 @@ describe('Test plugin altering video constants', function () {
45 45
46 expect(languages['al_bhed']).to.equal('Al Bhed') 46 expect(languages['al_bhed']).to.equal('Al Bhed')
47 expect(languages['al_bhed2']).to.equal('Al Bhed 2') 47 expect(languages['al_bhed2']).to.equal('Al Bhed 2')
48 expect(languages['al_bhed3']).to.not.exist
48 }) 49 })
49 50
50 it('Should have updated categories', async function () { 51 it('Should have updated categories', async function () {
@@ -116,7 +117,7 @@ describe('Test plugin altering video constants', function () {
116 }) 117 })
117 118
118 it('Should uninstall the plugin and reset languages, categories, licences and privacies', async function () { 119 it('Should uninstall the plugin and reset languages, categories, licences and privacies', async function () {
119 await uninstallPlugin({ url: server.url, accessToken: server.accessToken, npmName: 'peertube-plugin-test-three' }) 120 await uninstallPlugin({ url: server.url, accessToken: server.accessToken, npmName: 'peertube-plugin-test-video-constants' })
120 121
121 { 122 {
122 const res = await getVideoLanguages(server.url) 123 const res = await getVideoLanguages(server.url)
@@ -127,6 +128,7 @@ describe('Test plugin altering video constants', function () {
127 128
128 expect(languages['al_bhed']).to.not.exist 129 expect(languages['al_bhed']).to.not.exist
129 expect(languages['al_bhed2']).to.not.exist 130 expect(languages['al_bhed2']).to.not.exist
131 expect(languages['al_bhed3']).to.not.exist
130 } 132 }
131 133
132 { 134 {
diff --git a/server/tests/register.ts b/server/tests/register.ts
new file mode 100644
index 000000000..af6c8c644
--- /dev/null
+++ b/server/tests/register.ts
@@ -0,0 +1,3 @@
1import { registerTSPaths } from '../helpers/register-ts-paths'
2
3registerTSPaths()