aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/api/search
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2023-07-31 14:34:36 +0200
committerChocobozzz <me@florianbigard.com>2023-08-11 15:02:33 +0200
commit3a4992633ee62d5edfbb484d9c6bcb3cf158489d (patch)
treee4510b39bdac9c318fdb4b47018d08f15368b8f0 /server/tests/api/search
parent04d1da5621d25d59bd5fa1543b725c497bf5d9a8 (diff)
downloadPeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.gz
PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.zst
PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.zip
Migrate server to ESM
Sorry for the very big commit that may lead to git log issues and merge conflicts, but it's a major step forward: * Server can be faster at startup because imports() are async and we can easily lazy import big modules * Angular doesn't seem to support ES import (with .js extension), so we had to correctly organize peertube into a monorepo: * Use yarn workspace feature * Use typescript reference projects for dependencies * Shared projects have been moved into "packages", each one is now a node module (with a dedicated package.json/tsconfig.json) * server/tools have been moved into apps/ and is now a dedicated app bundled and published on NPM so users don't have to build peertube cli tools manually * server/tests have been moved into packages/ so we don't compile them every time we want to run the server * Use isolatedModule option: * Had to move from const enum to const (https://www.typescriptlang.org/docs/handbook/enums.html#objects-vs-enums) * Had to explictely specify "type" imports when used in decorators * Prefer tsx (that uses esbuild under the hood) instead of ts-node to load typescript files (tests with mocha or scripts): * To reduce test complexity as esbuild doesn't support decorator metadata, we only test server files that do not import server models * We still build tests files into js files for a faster CI * Remove unmaintained peertube CLI import script * Removed some barrels to speed up execution (less imports)
Diffstat (limited to 'server/tests/api/search')
-rw-r--r--server/tests/api/search/index.ts7
-rw-r--r--server/tests/api/search/search-activitypub-video-channels.ts255
-rw-r--r--server/tests/api/search/search-activitypub-video-playlists.ts214
-rw-r--r--server/tests/api/search/search-activitypub-videos.ts196
-rw-r--r--server/tests/api/search/search-channels.ts159
-rw-r--r--server/tests/api/search/search-index.ts432
-rw-r--r--server/tests/api/search/search-playlists.ts180
-rw-r--r--server/tests/api/search/search-videos.ts568
8 files changed, 0 insertions, 2011 deletions
diff --git a/server/tests/api/search/index.ts b/server/tests/api/search/index.ts
deleted file mode 100644
index a976d210d..000000000
--- a/server/tests/api/search/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
1import './search-activitypub-video-playlists'
2import './search-activitypub-video-channels'
3import './search-activitypub-videos'
4import './search-channels'
5import './search-index'
6import './search-playlists'
7import './search-videos'
diff --git a/server/tests/api/search/search-activitypub-video-channels.ts b/server/tests/api/search/search-activitypub-video-channels.ts
deleted file mode 100644
index 003bd34d0..000000000
--- a/server/tests/api/search/search-activitypub-video-channels.ts
+++ /dev/null
@@ -1,255 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { wait } from '@shared/core-utils'
5import { VideoChannel } from '@shared/models'
6import {
7 cleanupTests,
8 createMultipleServers,
9 PeerTubeServer,
10 SearchCommand,
11 setAccessTokensToServers,
12 setDefaultAccountAvatar,
13 setDefaultVideoChannel,
14 waitJobs
15} from '@shared/server-commands'
16
17describe('Test ActivityPub video channels search', function () {
18 let servers: PeerTubeServer[]
19 let userServer2Token: string
20 let videoServer2UUID: string
21 let channelIdServer2: number
22 let command: SearchCommand
23
24 before(async function () {
25 this.timeout(120000)
26
27 servers = await createMultipleServers(2)
28
29 await setAccessTokensToServers(servers)
30 await setDefaultVideoChannel(servers)
31 await setDefaultAccountAvatar(servers)
32
33 {
34 await servers[0].users.create({ username: 'user1_server1', password: 'password' })
35 const channel = {
36 name: 'channel1_server1',
37 displayName: 'Channel 1 server 1'
38 }
39 await servers[0].channels.create({ attributes: channel })
40 }
41
42 {
43 const user = { username: 'user1_server2', password: 'password' }
44 await servers[1].users.create({ username: user.username, password: user.password })
45 userServer2Token = await servers[1].login.getAccessToken(user)
46
47 const channel = {
48 name: 'channel1_server2',
49 displayName: 'Channel 1 server 2'
50 }
51 const created = await servers[1].channels.create({ token: userServer2Token, attributes: channel })
52 channelIdServer2 = created.id
53
54 const attributes = { name: 'video 1 server 2', channelId: channelIdServer2 }
55 const { uuid } = await servers[1].videos.upload({ token: userServer2Token, attributes })
56 videoServer2UUID = uuid
57 }
58
59 await waitJobs(servers)
60
61 command = servers[0].search
62 })
63
64 it('Should not find a remote video channel', async function () {
65 this.timeout(15000)
66
67 {
68 const search = servers[1].url + '/video-channels/channel1_server3'
69 const body = await command.searchChannels({ search, token: servers[0].accessToken })
70
71 expect(body.total).to.equal(0)
72 expect(body.data).to.be.an('array')
73 expect(body.data).to.have.lengthOf(0)
74 }
75
76 {
77 // Without token
78 const search = servers[1].url + '/video-channels/channel1_server2'
79 const body = await command.searchChannels({ search })
80
81 expect(body.total).to.equal(0)
82 expect(body.data).to.be.an('array')
83 expect(body.data).to.have.lengthOf(0)
84 }
85 })
86
87 it('Should search a local video channel', async function () {
88 const searches = [
89 servers[0].url + '/video-channels/channel1_server1',
90 'channel1_server1@' + servers[0].host
91 ]
92
93 for (const search of searches) {
94 const body = await command.searchChannels({ search })
95
96 expect(body.total).to.equal(1)
97 expect(body.data).to.be.an('array')
98 expect(body.data).to.have.lengthOf(1)
99 expect(body.data[0].name).to.equal('channel1_server1')
100 expect(body.data[0].displayName).to.equal('Channel 1 server 1')
101 }
102 })
103
104 it('Should search a local video channel with an alternative URL', async function () {
105 const search = servers[0].url + '/c/channel1_server1'
106
107 for (const token of [ undefined, servers[0].accessToken ]) {
108 const body = await command.searchChannels({ search, token })
109
110 expect(body.total).to.equal(1)
111 expect(body.data).to.be.an('array')
112 expect(body.data).to.have.lengthOf(1)
113 expect(body.data[0].name).to.equal('channel1_server1')
114 expect(body.data[0].displayName).to.equal('Channel 1 server 1')
115 }
116 })
117
118 it('Should search a local video channel with a query in URL', async function () {
119 const searches = [
120 servers[0].url + '/video-channels/channel1_server1',
121 servers[0].url + '/c/channel1_server1'
122 ]
123
124 for (const search of searches) {
125 for (const token of [ undefined, servers[0].accessToken ]) {
126 const body = await command.searchChannels({ search: search + '?param=2', token })
127
128 expect(body.total).to.equal(1)
129 expect(body.data).to.be.an('array')
130 expect(body.data).to.have.lengthOf(1)
131 expect(body.data[0].name).to.equal('channel1_server1')
132 expect(body.data[0].displayName).to.equal('Channel 1 server 1')
133 }
134 }
135 })
136
137 it('Should search a remote video channel with URL or handle', async function () {
138 const searches = [
139 servers[1].url + '/video-channels/channel1_server2',
140 servers[1].url + '/c/channel1_server2',
141 servers[1].url + '/c/channel1_server2/videos',
142 'channel1_server2@' + servers[1].host
143 ]
144
145 for (const search of searches) {
146 const body = await command.searchChannels({ search, token: servers[0].accessToken })
147
148 expect(body.total).to.equal(1)
149 expect(body.data).to.be.an('array')
150 expect(body.data).to.have.lengthOf(1)
151 expect(body.data[0].name).to.equal('channel1_server2')
152 expect(body.data[0].displayName).to.equal('Channel 1 server 2')
153 }
154 })
155
156 it('Should not list this remote video channel', async function () {
157 const body = await servers[0].channels.list()
158 expect(body.total).to.equal(3)
159 expect(body.data).to.have.lengthOf(3)
160 expect(body.data[0].name).to.equal('channel1_server1')
161 expect(body.data[1].name).to.equal('user1_server1_channel')
162 expect(body.data[2].name).to.equal('root_channel')
163 })
164
165 it('Should list video channel videos of server 2 without token', async function () {
166 this.timeout(30000)
167
168 await waitJobs(servers)
169
170 const { total, data } = await servers[0].videos.listByChannel({
171 token: null,
172 handle: 'channel1_server2@' + servers[1].host
173 })
174 expect(total).to.equal(0)
175 expect(data).to.have.lengthOf(0)
176 })
177
178 it('Should list video channel videos of server 2 with token', async function () {
179 const { total, data } = await servers[0].videos.listByChannel({
180 handle: 'channel1_server2@' + servers[1].host
181 })
182
183 expect(total).to.equal(1)
184 expect(data[0].name).to.equal('video 1 server 2')
185 })
186
187 it('Should update video channel of server 2, and refresh it on server 1', async function () {
188 this.timeout(120000)
189
190 await servers[1].channels.update({
191 token: userServer2Token,
192 channelName: 'channel1_server2',
193 attributes: { displayName: 'channel updated' }
194 })
195 await servers[1].users.updateMe({ token: userServer2Token, displayName: 'user updated' })
196
197 await waitJobs(servers)
198 // Expire video channel
199 await wait(10000)
200
201 const search = servers[1].url + '/video-channels/channel1_server2'
202 const body = await command.searchChannels({ search, token: servers[0].accessToken })
203 expect(body.total).to.equal(1)
204 expect(body.data).to.have.lengthOf(1)
205
206 const videoChannel: VideoChannel = body.data[0]
207 expect(videoChannel.displayName).to.equal('channel updated')
208
209 // We don't return the owner account for now
210 // expect(videoChannel.ownerAccount.displayName).to.equal('user updated')
211 })
212
213 it('Should update and add a video on server 2, and update it on server 1 after a search', async function () {
214 this.timeout(120000)
215
216 await servers[1].videos.update({ token: userServer2Token, id: videoServer2UUID, attributes: { name: 'video 1 updated' } })
217 await servers[1].videos.upload({ token: userServer2Token, attributes: { name: 'video 2 server 2', channelId: channelIdServer2 } })
218
219 await waitJobs(servers)
220
221 // Expire video channel
222 await wait(10000)
223
224 const search = servers[1].url + '/video-channels/channel1_server2'
225 await command.searchChannels({ search, token: servers[0].accessToken })
226
227 await waitJobs(servers)
228
229 const handle = 'channel1_server2@' + servers[1].host
230 const { total, data } = await servers[0].videos.listByChannel({ handle, sort: '-createdAt' })
231
232 expect(total).to.equal(2)
233 expect(data[0].name).to.equal('video 2 server 2')
234 expect(data[1].name).to.equal('video 1 updated')
235 })
236
237 it('Should delete video channel of server 2, and delete it on server 1', async function () {
238 this.timeout(120000)
239
240 await servers[1].channels.delete({ token: userServer2Token, channelName: 'channel1_server2' })
241
242 await waitJobs(servers)
243 // Expire video
244 await wait(10000)
245
246 const search = servers[1].url + '/video-channels/channel1_server2'
247 const body = await command.searchChannels({ search, token: servers[0].accessToken })
248 expect(body.total).to.equal(0)
249 expect(body.data).to.have.lengthOf(0)
250 })
251
252 after(async function () {
253 await cleanupTests(servers)
254 })
255})
diff --git a/server/tests/api/search/search-activitypub-video-playlists.ts b/server/tests/api/search/search-activitypub-video-playlists.ts
deleted file mode 100644
index 2bb5d869a..000000000
--- a/server/tests/api/search/search-activitypub-video-playlists.ts
+++ /dev/null
@@ -1,214 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { wait } from '@shared/core-utils'
5import { VideoPlaylistPrivacy } from '@shared/models'
6import {
7 cleanupTests,
8 createMultipleServers,
9 PeerTubeServer,
10 SearchCommand,
11 setAccessTokensToServers,
12 setDefaultAccountAvatar,
13 setDefaultVideoChannel,
14 waitJobs
15} from '@shared/server-commands'
16
17describe('Test ActivityPub playlists search', function () {
18 let servers: PeerTubeServer[]
19 let playlistServer1UUID: string
20 let playlistServer2UUID: string
21 let video2Server2: string
22
23 let command: SearchCommand
24
25 before(async function () {
26 this.timeout(240000)
27
28 servers = await createMultipleServers(2)
29
30 await setAccessTokensToServers(servers)
31 await setDefaultVideoChannel(servers)
32 await setDefaultAccountAvatar(servers)
33
34 {
35 const video1 = (await servers[0].videos.quickUpload({ name: 'video 1' })).uuid
36 const video2 = (await servers[0].videos.quickUpload({ name: 'video 2' })).uuid
37
38 const attributes = {
39 displayName: 'playlist 1 on server 1',
40 privacy: VideoPlaylistPrivacy.PUBLIC,
41 videoChannelId: servers[0].store.channel.id
42 }
43 const created = await servers[0].playlists.create({ attributes })
44 playlistServer1UUID = created.uuid
45
46 for (const videoId of [ video1, video2 ]) {
47 await servers[0].playlists.addElement({ playlistId: playlistServer1UUID, attributes: { videoId } })
48 }
49 }
50
51 {
52 const videoId = (await servers[1].videos.quickUpload({ name: 'video 1' })).uuid
53 video2Server2 = (await servers[1].videos.quickUpload({ name: 'video 2' })).uuid
54
55 const attributes = {
56 displayName: 'playlist 1 on server 2',
57 privacy: VideoPlaylistPrivacy.PUBLIC,
58 videoChannelId: servers[1].store.channel.id
59 }
60 const created = await servers[1].playlists.create({ attributes })
61 playlistServer2UUID = created.uuid
62
63 await servers[1].playlists.addElement({ playlistId: playlistServer2UUID, attributes: { videoId } })
64 }
65
66 await waitJobs(servers)
67
68 command = servers[0].search
69 })
70
71 it('Should not find a remote playlist', async function () {
72 {
73 const search = servers[1].url + '/video-playlists/43'
74 const body = await command.searchPlaylists({ search, token: servers[0].accessToken })
75
76 expect(body.total).to.equal(0)
77 expect(body.data).to.be.an('array')
78 expect(body.data).to.have.lengthOf(0)
79 }
80
81 {
82 // Without token
83 const search = servers[1].url + '/video-playlists/' + playlistServer2UUID
84 const body = await command.searchPlaylists({ search })
85
86 expect(body.total).to.equal(0)
87 expect(body.data).to.be.an('array')
88 expect(body.data).to.have.lengthOf(0)
89 }
90 })
91
92 it('Should search a local playlist', async function () {
93 const search = servers[0].url + '/video-playlists/' + playlistServer1UUID
94 const body = await command.searchPlaylists({ search })
95
96 expect(body.total).to.equal(1)
97 expect(body.data).to.be.an('array')
98 expect(body.data).to.have.lengthOf(1)
99 expect(body.data[0].displayName).to.equal('playlist 1 on server 1')
100 expect(body.data[0].videosLength).to.equal(2)
101 })
102
103 it('Should search a local playlist with an alternative URL', async function () {
104 const searches = [
105 servers[0].url + '/videos/watch/playlist/' + playlistServer1UUID,
106 servers[0].url + '/w/p/' + playlistServer1UUID
107 ]
108
109 for (const search of searches) {
110 for (const token of [ undefined, servers[0].accessToken ]) {
111 const body = await command.searchPlaylists({ search, token })
112
113 expect(body.total).to.equal(1)
114 expect(body.data).to.be.an('array')
115 expect(body.data).to.have.lengthOf(1)
116 expect(body.data[0].displayName).to.equal('playlist 1 on server 1')
117 expect(body.data[0].videosLength).to.equal(2)
118 }
119 }
120 })
121
122 it('Should search a local playlist with a query in URL', async function () {
123 const searches = [
124 servers[0].url + '/videos/watch/playlist/' + playlistServer1UUID,
125 servers[0].url + '/w/p/' + playlistServer1UUID
126 ]
127
128 for (const search of searches) {
129 for (const token of [ undefined, servers[0].accessToken ]) {
130 const body = await command.searchPlaylists({ search: search + '?param=1', token })
131
132 expect(body.total).to.equal(1)
133 expect(body.data).to.be.an('array')
134 expect(body.data).to.have.lengthOf(1)
135 expect(body.data[0].displayName).to.equal('playlist 1 on server 1')
136 expect(body.data[0].videosLength).to.equal(2)
137 }
138 }
139 })
140
141 it('Should search a remote playlist', async function () {
142 const searches = [
143 servers[1].url + '/video-playlists/' + playlistServer2UUID,
144 servers[1].url + '/videos/watch/playlist/' + playlistServer2UUID,
145 servers[1].url + '/w/p/' + playlistServer2UUID
146 ]
147
148 for (const search of searches) {
149 const body = await command.searchPlaylists({ search, token: servers[0].accessToken })
150
151 expect(body.total).to.equal(1)
152 expect(body.data).to.be.an('array')
153 expect(body.data).to.have.lengthOf(1)
154 expect(body.data[0].displayName).to.equal('playlist 1 on server 2')
155 expect(body.data[0].videosLength).to.equal(1)
156 }
157 })
158
159 it('Should not list this remote playlist', async function () {
160 const body = await servers[0].playlists.list({ start: 0, count: 10 })
161 expect(body.total).to.equal(1)
162 expect(body.data).to.have.lengthOf(1)
163 expect(body.data[0].displayName).to.equal('playlist 1 on server 1')
164 })
165
166 it('Should update the playlist of server 2, and refresh it on server 1', async function () {
167 this.timeout(60000)
168
169 await servers[1].playlists.addElement({ playlistId: playlistServer2UUID, attributes: { videoId: video2Server2 } })
170
171 await waitJobs(servers)
172 // Expire playlist
173 await wait(10000)
174
175 // Will run refresh async
176 const search = servers[1].url + '/video-playlists/' + playlistServer2UUID
177 await command.searchPlaylists({ search, token: servers[0].accessToken })
178
179 // Wait refresh
180 await wait(5000)
181
182 const body = await command.searchPlaylists({ search, token: servers[0].accessToken })
183 expect(body.total).to.equal(1)
184 expect(body.data).to.have.lengthOf(1)
185
186 const playlist = body.data[0]
187 expect(playlist.videosLength).to.equal(2)
188 })
189
190 it('Should delete playlist of server 2, and delete it on server 1', async function () {
191 this.timeout(60000)
192
193 await servers[1].playlists.delete({ playlistId: playlistServer2UUID })
194
195 await waitJobs(servers)
196 // Expiration
197 await wait(10000)
198
199 // Will run refresh async
200 const search = servers[1].url + '/video-playlists/' + playlistServer2UUID
201 await command.searchPlaylists({ search, token: servers[0].accessToken })
202
203 // Wait refresh
204 await wait(5000)
205
206 const body = await command.searchPlaylists({ search, token: servers[0].accessToken })
207 expect(body.total).to.equal(0)
208 expect(body.data).to.have.lengthOf(0)
209 })
210
211 after(async function () {
212 await cleanupTests(servers)
213 })
214})
diff --git a/server/tests/api/search/search-activitypub-videos.ts b/server/tests/api/search/search-activitypub-videos.ts
deleted file mode 100644
index 4c7118422..000000000
--- a/server/tests/api/search/search-activitypub-videos.ts
+++ /dev/null
@@ -1,196 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { wait } from '@shared/core-utils'
5import { VideoPrivacy } from '@shared/models'
6import {
7 cleanupTests,
8 createMultipleServers,
9 PeerTubeServer,
10 SearchCommand,
11 setAccessTokensToServers,
12 setDefaultAccountAvatar,
13 setDefaultVideoChannel,
14 waitJobs
15} from '@shared/server-commands'
16
17describe('Test ActivityPub videos search', function () {
18 let servers: PeerTubeServer[]
19 let videoServer1UUID: string
20 let videoServer2UUID: string
21
22 let command: SearchCommand
23
24 before(async function () {
25 this.timeout(120000)
26
27 servers = await createMultipleServers(2)
28
29 await setAccessTokensToServers(servers)
30 await setDefaultVideoChannel(servers)
31 await setDefaultAccountAvatar(servers)
32
33 {
34 const { uuid } = await servers[0].videos.upload({ attributes: { name: 'video 1 on server 1' } })
35 videoServer1UUID = uuid
36 }
37
38 {
39 const { uuid } = await servers[1].videos.upload({ attributes: { name: 'video 1 on server 2' } })
40 videoServer2UUID = uuid
41 }
42
43 await waitJobs(servers)
44
45 command = servers[0].search
46 })
47
48 it('Should not find a remote video', async function () {
49 {
50 const search = servers[1].url + '/videos/watch/43'
51 const body = await command.searchVideos({ search, token: servers[0].accessToken })
52
53 expect(body.total).to.equal(0)
54 expect(body.data).to.be.an('array')
55 expect(body.data).to.have.lengthOf(0)
56 }
57
58 {
59 // Without token
60 const search = servers[1].url + '/videos/watch/' + videoServer2UUID
61 const body = await command.searchVideos({ search })
62
63 expect(body.total).to.equal(0)
64 expect(body.data).to.be.an('array')
65 expect(body.data).to.have.lengthOf(0)
66 }
67 })
68
69 it('Should search a local video', async function () {
70 const search = servers[0].url + '/videos/watch/' + videoServer1UUID
71 const body = await command.searchVideos({ search })
72
73 expect(body.total).to.equal(1)
74 expect(body.data).to.be.an('array')
75 expect(body.data).to.have.lengthOf(1)
76 expect(body.data[0].name).to.equal('video 1 on server 1')
77 })
78
79 it('Should search a local video with an alternative URL', async function () {
80 const search = servers[0].url + '/w/' + videoServer1UUID
81 const body1 = await command.searchVideos({ search })
82 const body2 = await command.searchVideos({ search, token: servers[0].accessToken })
83
84 for (const body of [ body1, body2 ]) {
85 expect(body.total).to.equal(1)
86 expect(body.data).to.be.an('array')
87 expect(body.data).to.have.lengthOf(1)
88 expect(body.data[0].name).to.equal('video 1 on server 1')
89 }
90 })
91
92 it('Should search a local video with a query in URL', async function () {
93 const searches = [
94 servers[0].url + '/w/' + videoServer1UUID,
95 servers[0].url + '/videos/watch/' + videoServer1UUID
96 ]
97
98 for (const search of searches) {
99 for (const token of [ undefined, servers[0].accessToken ]) {
100 const body = await command.searchVideos({ search: search + '?startTime=4', token })
101
102 expect(body.total).to.equal(1)
103 expect(body.data).to.be.an('array')
104 expect(body.data).to.have.lengthOf(1)
105 expect(body.data[0].name).to.equal('video 1 on server 1')
106 }
107 }
108 })
109
110 it('Should search a remote video', async function () {
111 const searches = [
112 servers[1].url + '/w/' + videoServer2UUID,
113 servers[1].url + '/videos/watch/' + videoServer2UUID
114 ]
115
116 for (const search of searches) {
117 const body = await command.searchVideos({ search, token: servers[0].accessToken })
118
119 expect(body.total).to.equal(1)
120 expect(body.data).to.be.an('array')
121 expect(body.data).to.have.lengthOf(1)
122 expect(body.data[0].name).to.equal('video 1 on server 2')
123 }
124 })
125
126 it('Should not list this remote video', async function () {
127 const { total, data } = await servers[0].videos.list()
128 expect(total).to.equal(1)
129 expect(data).to.have.lengthOf(1)
130 expect(data[0].name).to.equal('video 1 on server 1')
131 })
132
133 it('Should update video of server 2, and refresh it on server 1', async function () {
134 this.timeout(120000)
135
136 const channelAttributes = {
137 name: 'super_channel',
138 displayName: 'super channel'
139 }
140 const created = await servers[1].channels.create({ attributes: channelAttributes })
141 const videoChannelId = created.id
142
143 const attributes = {
144 name: 'updated',
145 tag: [ 'tag1', 'tag2' ],
146 privacy: VideoPrivacy.UNLISTED,
147 channelId: videoChannelId
148 }
149 await servers[1].videos.update({ id: videoServer2UUID, attributes })
150
151 await waitJobs(servers)
152 // Expire video
153 await wait(10000)
154
155 // Will run refresh async
156 const search = servers[1].url + '/videos/watch/' + videoServer2UUID
157 await command.searchVideos({ search, token: servers[0].accessToken })
158
159 // Wait refresh
160 await wait(5000)
161
162 const body = await command.searchVideos({ search, token: servers[0].accessToken })
163 expect(body.total).to.equal(1)
164 expect(body.data).to.have.lengthOf(1)
165
166 const video = body.data[0]
167 expect(video.name).to.equal('updated')
168 expect(video.channel.name).to.equal('super_channel')
169 expect(video.privacy.id).to.equal(VideoPrivacy.UNLISTED)
170 })
171
172 it('Should delete video of server 2, and delete it on server 1', async function () {
173 this.timeout(120000)
174
175 await servers[1].videos.remove({ id: videoServer2UUID })
176
177 await waitJobs(servers)
178 // Expire video
179 await wait(10000)
180
181 // Will run refresh async
182 const search = servers[1].url + '/videos/watch/' + videoServer2UUID
183 await command.searchVideos({ search, token: servers[0].accessToken })
184
185 // Wait refresh
186 await wait(5000)
187
188 const body = await command.searchVideos({ search, token: servers[0].accessToken })
189 expect(body.total).to.equal(0)
190 expect(body.data).to.have.lengthOf(0)
191 })
192
193 after(async function () {
194 await cleanupTests(servers)
195 })
196})
diff --git a/server/tests/api/search/search-channels.ts b/server/tests/api/search/search-channels.ts
deleted file mode 100644
index c6b098a93..000000000
--- a/server/tests/api/search/search-channels.ts
+++ /dev/null
@@ -1,159 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { VideoChannel } from '@shared/models'
5import {
6 cleanupTests,
7 createSingleServer,
8 doubleFollow,
9 PeerTubeServer,
10 SearchCommand,
11 setAccessTokensToServers,
12 setDefaultAccountAvatar,
13 setDefaultChannelAvatar
14} from '@shared/server-commands'
15
16describe('Test channels search', function () {
17 let server: PeerTubeServer
18 let remoteServer: PeerTubeServer
19 let command: SearchCommand
20
21 before(async function () {
22 this.timeout(120000)
23
24 const servers = await Promise.all([
25 createSingleServer(1),
26 createSingleServer(2)
27 ])
28 server = servers[0]
29 remoteServer = servers[1]
30
31 await setAccessTokensToServers([ server, remoteServer ])
32 await setDefaultChannelAvatar(server)
33 await setDefaultAccountAvatar(server)
34
35 await servers[1].config.disableTranscoding()
36
37 {
38 await server.users.create({ username: 'user1' })
39 const channel = {
40 name: 'squall_channel',
41 displayName: 'Squall channel'
42 }
43 await server.channels.create({ attributes: channel })
44 }
45
46 {
47 await remoteServer.users.create({ username: 'user1' })
48 const channel = {
49 name: 'zell_channel',
50 displayName: 'Zell channel'
51 }
52 const { id } = await remoteServer.channels.create({ attributes: channel })
53
54 await remoteServer.videos.upload({ attributes: { channelId: id } })
55 }
56
57 await doubleFollow(server, remoteServer)
58
59 command = server.search
60 })
61
62 it('Should make a simple search and not have results', async function () {
63 const body = await command.searchChannels({ search: 'abc' })
64
65 expect(body.total).to.equal(0)
66 expect(body.data).to.have.lengthOf(0)
67 })
68
69 it('Should make a search and have results', async function () {
70 {
71 const search = {
72 search: 'Squall',
73 start: 0,
74 count: 1
75 }
76 const body = await command.advancedChannelSearch({ search })
77 expect(body.total).to.equal(1)
78 expect(body.data).to.have.lengthOf(1)
79
80 const channel: VideoChannel = body.data[0]
81 expect(channel.name).to.equal('squall_channel')
82 expect(channel.displayName).to.equal('Squall channel')
83 }
84
85 {
86 const search = {
87 search: 'Squall',
88 start: 1,
89 count: 1
90 }
91
92 const body = await command.advancedChannelSearch({ search })
93 expect(body.total).to.equal(1)
94 expect(body.data).to.have.lengthOf(0)
95 }
96 })
97
98 it('Should filter by host', async function () {
99 {
100 const search = { search: 'channel', host: remoteServer.host }
101
102 const body = await command.advancedChannelSearch({ search })
103 expect(body.total).to.equal(1)
104 expect(body.data).to.have.lengthOf(1)
105 expect(body.data[0].displayName).to.equal('Zell channel')
106 }
107
108 {
109 const search = { search: 'Sq', host: server.host }
110
111 const body = await command.advancedChannelSearch({ search })
112 expect(body.total).to.equal(1)
113 expect(body.data).to.have.lengthOf(1)
114 expect(body.data[0].displayName).to.equal('Squall channel')
115 }
116
117 {
118 const search = { search: 'Squall', host: 'example.com' }
119
120 const body = await command.advancedChannelSearch({ search })
121 expect(body.total).to.equal(0)
122 expect(body.data).to.have.lengthOf(0)
123 }
124 })
125
126 it('Should filter by names', async function () {
127 {
128 const body = await command.advancedChannelSearch({ search: { handles: [ 'squall_channel', 'zell_channel' ] } })
129 expect(body.total).to.equal(1)
130 expect(body.data).to.have.lengthOf(1)
131 expect(body.data[0].displayName).to.equal('Squall channel')
132 }
133
134 {
135 const body = await command.advancedChannelSearch({ search: { handles: [ 'squall_channel@' + server.host ] } })
136 expect(body.total).to.equal(1)
137 expect(body.data).to.have.lengthOf(1)
138 expect(body.data[0].displayName).to.equal('Squall channel')
139 }
140
141 {
142 const body = await command.advancedChannelSearch({ search: { handles: [ 'chocobozzz_channel' ] } })
143 expect(body.total).to.equal(0)
144 expect(body.data).to.have.lengthOf(0)
145 }
146
147 {
148 const body = await command.advancedChannelSearch({ search: { handles: [ 'squall_channel', 'zell_channel@' + remoteServer.host ] } })
149 expect(body.total).to.equal(2)
150 expect(body.data).to.have.lengthOf(2)
151 expect(body.data[0].displayName).to.equal('Squall channel')
152 expect(body.data[1].displayName).to.equal('Zell channel')
153 }
154 })
155
156 after(async function () {
157 await cleanupTests([ server, remoteServer ])
158 })
159})
diff --git a/server/tests/api/search/search-index.ts b/server/tests/api/search/search-index.ts
deleted file mode 100644
index cbe628ccc..000000000
--- a/server/tests/api/search/search-index.ts
+++ /dev/null
@@ -1,432 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import {
5 BooleanBothQuery,
6 VideoChannelsSearchQuery,
7 VideoPlaylistPrivacy,
8 VideoPlaylistsSearchQuery,
9 VideoPlaylistType,
10 VideosSearchQuery
11} from '@shared/models'
12import { cleanupTests, createSingleServer, PeerTubeServer, SearchCommand, setAccessTokensToServers } from '@shared/server-commands'
13
14describe('Test index search', function () {
15 const localVideoName = 'local video' + new Date().toISOString()
16
17 let server: PeerTubeServer = null
18 let command: SearchCommand
19
20 before(async function () {
21 this.timeout(30000)
22
23 server = await createSingleServer(1)
24
25 await setAccessTokensToServers([ server ])
26
27 await server.videos.upload({ attributes: { name: localVideoName } })
28
29 command = server.search
30 })
31
32 describe('Default search', async function () {
33
34 it('Should make a local videos search by default', async function () {
35 await server.config.updateCustomSubConfig({
36 newConfig: {
37 search: {
38 searchIndex: {
39 enabled: true,
40 isDefaultSearch: false,
41 disableLocalSearch: false
42 }
43 }
44 }
45 })
46
47 const body = await command.searchVideos({ search: 'local video' })
48
49 expect(body.total).to.equal(1)
50 expect(body.data[0].name).to.equal(localVideoName)
51 })
52
53 it('Should make a local channels search by default', async function () {
54 const body = await command.searchChannels({ search: 'root' })
55
56 expect(body.total).to.equal(1)
57 expect(body.data[0].name).to.equal('root_channel')
58 expect(body.data[0].host).to.equal(server.host)
59 })
60
61 it('Should make an index videos search by default', async function () {
62 await server.config.updateCustomSubConfig({
63 newConfig: {
64 search: {
65 searchIndex: {
66 enabled: true,
67 isDefaultSearch: true,
68 disableLocalSearch: false
69 }
70 }
71 }
72 })
73
74 const body = await command.searchVideos({ search: 'local video' })
75 expect(body.total).to.be.greaterThan(2)
76 })
77
78 it('Should make an index channels search by default', async function () {
79 const body = await command.searchChannels({ search: 'root' })
80 expect(body.total).to.be.greaterThan(2)
81 })
82 })
83
84 describe('Videos search', async function () {
85
86 async function check (search: VideosSearchQuery, exists = true) {
87 const body = await command.advancedVideoSearch({ search })
88
89 if (exists === false) {
90 expect(body.total).to.equal(0)
91 expect(body.data).to.have.lengthOf(0)
92 return
93 }
94
95 expect(body.total).to.equal(1)
96 expect(body.data).to.have.lengthOf(1)
97
98 const video = body.data[0]
99
100 expect(video.name).to.equal('What is PeerTube?')
101 expect(video.category.label).to.equal('Science & Technology')
102 expect(video.licence.label).to.equal('Attribution - Share Alike')
103 expect(video.privacy.label).to.equal('Public')
104 expect(video.duration).to.equal(113)
105 expect(video.thumbnailUrl.startsWith('https://framatube.org/static/thumbnails')).to.be.true
106
107 expect(video.account.host).to.equal('framatube.org')
108 expect(video.account.name).to.equal('framasoft')
109 expect(video.account.url).to.equal('https://framatube.org/accounts/framasoft')
110 expect(video.account.avatars.length).to.equal(2, 'Account should have one avatar image')
111
112 expect(video.channel.host).to.equal('framatube.org')
113 expect(video.channel.name).to.equal('joinpeertube')
114 expect(video.channel.url).to.equal('https://framatube.org/video-channels/joinpeertube')
115 expect(video.channel.avatars.length).to.equal(2, 'Channel should have one avatar image')
116 }
117
118 const baseSearch: VideosSearchQuery = {
119 search: 'what is peertube',
120 start: 0,
121 count: 2,
122 categoryOneOf: [ 15 ],
123 licenceOneOf: [ 2 ],
124 tagsAllOf: [ 'framasoft', 'peertube' ],
125 startDate: '2018-10-01T10:50:46.396Z',
126 endDate: '2018-10-01T10:55:46.396Z'
127 }
128
129 it('Should make a simple search and not have results', async function () {
130 const body = await command.searchVideos({ search: 'djidane'.repeat(50) })
131
132 expect(body.total).to.equal(0)
133 expect(body.data).to.have.lengthOf(0)
134 })
135
136 it('Should make a simple search and have results', async function () {
137 const body = await command.searchVideos({ search: 'What is PeerTube' })
138
139 expect(body.total).to.be.greaterThan(1)
140 })
141
142 it('Should make a simple search', async function () {
143 await check(baseSearch)
144 })
145
146 it('Should search by start date', async function () {
147 const search = { ...baseSearch, startDate: '2018-10-01T10:54:46.396Z' }
148 await check(search, false)
149 })
150
151 it('Should search by tags', async function () {
152 const search = { ...baseSearch, tagsAllOf: [ 'toto', 'framasoft' ] }
153 await check(search, false)
154 })
155
156 it('Should search by duration', async function () {
157 const search = { ...baseSearch, durationMin: 2000 }
158 await check(search, false)
159 })
160
161 it('Should search by nsfw attribute', async function () {
162 {
163 const search = { ...baseSearch, nsfw: 'true' as BooleanBothQuery }
164 await check(search, false)
165 }
166
167 {
168 const search = { ...baseSearch, nsfw: 'false' as BooleanBothQuery }
169 await check(search, true)
170 }
171
172 {
173 const search = { ...baseSearch, nsfw: 'both' as BooleanBothQuery }
174 await check(search, true)
175 }
176 })
177
178 it('Should search by host', async function () {
179 {
180 const search = { ...baseSearch, host: 'example.com' }
181 await check(search, false)
182 }
183
184 {
185 const search = { ...baseSearch, host: 'framatube.org' }
186 await check(search, true)
187 }
188 })
189
190 it('Should search by uuids', async function () {
191 const goodUUID = '9c9de5e8-0a1e-484a-b099-e80766180a6d'
192 const goodShortUUID = 'kkGMgK9ZtnKfYAgnEtQxbv'
193 const badUUID = 'c29c5b77-4a04-493d-96a9-2e9267e308f0'
194 const badShortUUID = 'rP5RgUeX9XwTSrspCdkDej'
195
196 {
197 const uuidsMatrix = [
198 [ goodUUID ],
199 [ goodUUID, badShortUUID ],
200 [ badShortUUID, goodShortUUID ],
201 [ goodUUID, goodShortUUID ]
202 ]
203
204 for (const uuids of uuidsMatrix) {
205 const search = { ...baseSearch, uuids }
206 await check(search, true)
207 }
208 }
209
210 {
211 const uuidsMatrix = [
212 [ badUUID ],
213 [ badShortUUID ]
214 ]
215
216 for (const uuids of uuidsMatrix) {
217 const search = { ...baseSearch, uuids }
218 await check(search, false)
219 }
220 }
221 })
222
223 it('Should have a correct pagination', async function () {
224 const search = {
225 search: 'video',
226 start: 0,
227 count: 5
228 }
229
230 const body = await command.advancedVideoSearch({ search })
231
232 expect(body.total).to.be.greaterThan(5)
233 expect(body.data).to.have.lengthOf(5)
234 })
235
236 it('Should use the nsfw instance policy as default', async function () {
237 let nsfwUUID: string
238
239 {
240 await server.config.updateCustomSubConfig({
241 newConfig: {
242 instance: { defaultNSFWPolicy: 'display' }
243 }
244 })
245
246 const body = await command.searchVideos({ search: 'NSFW search index', sort: '-match' })
247 expect(body.data).to.have.length.greaterThan(0)
248
249 const video = body.data[0]
250 expect(video.nsfw).to.be.true
251
252 nsfwUUID = video.uuid
253 }
254
255 {
256 await server.config.updateCustomSubConfig({
257 newConfig: {
258 instance: { defaultNSFWPolicy: 'do_not_list' }
259 }
260 })
261
262 const body = await command.searchVideos({ search: 'NSFW search index', sort: '-match' })
263
264 try {
265 expect(body.data).to.have.lengthOf(0)
266 } catch {
267 const video = body.data[0]
268
269 expect(video.uuid).not.equal(nsfwUUID)
270 }
271 }
272 })
273 })
274
275 describe('Channels search', async function () {
276
277 async function check (search: VideoChannelsSearchQuery, exists = true) {
278 const body = await command.advancedChannelSearch({ search })
279
280 if (exists === false) {
281 expect(body.total).to.equal(0)
282 expect(body.data).to.have.lengthOf(0)
283 return
284 }
285
286 expect(body.total).to.be.greaterThan(0)
287 expect(body.data).to.have.length.greaterThan(0)
288
289 const videoChannel = body.data[0]
290 expect(videoChannel.url).to.equal('https://framatube.org/video-channels/bf54d359-cfad-4935-9d45-9d6be93f63e8')
291 expect(videoChannel.host).to.equal('framatube.org')
292 expect(videoChannel.avatars.length).to.equal(2, 'Channel should have two avatar images')
293 expect(videoChannel.displayName).to.exist
294
295 expect(videoChannel.ownerAccount.url).to.equal('https://framatube.org/accounts/framasoft')
296 expect(videoChannel.ownerAccount.name).to.equal('framasoft')
297 expect(videoChannel.ownerAccount.host).to.equal('framatube.org')
298 expect(videoChannel.ownerAccount.avatars.length).to.equal(2, 'Account should have two avatar images')
299 }
300
301 it('Should make a simple search and not have results', async function () {
302 const body = await command.searchChannels({ search: 'a'.repeat(500) })
303
304 expect(body.total).to.equal(0)
305 expect(body.data).to.have.lengthOf(0)
306 })
307
308 it('Should make a search and have results', async function () {
309 await check({ search: 'Framasoft', sort: 'createdAt' }, true)
310 })
311
312 it('Should make host search and have appropriate results', async function () {
313 await check({ search: 'Framasoft videos', host: 'example.com' }, false)
314 await check({ search: 'Framasoft videos', host: 'framatube.org' }, true)
315 })
316
317 it('Should make handles search and have appropriate results', async function () {
318 await check({ handles: [ 'bf54d359-cfad-4935-9d45-9d6be93f63e8@framatube.org' ] }, true)
319 await check({ handles: [ 'jeanine', 'bf54d359-cfad-4935-9d45-9d6be93f63e8@framatube.org' ] }, true)
320 await check({ handles: [ 'jeanine', 'chocobozzz_channel2@peertube2.cpy.re' ] }, false)
321 })
322
323 it('Should have a correct pagination', async function () {
324 const body = await command.advancedChannelSearch({ search: { search: 'root', start: 0, count: 2 } })
325
326 expect(body.total).to.be.greaterThan(2)
327 expect(body.data).to.have.lengthOf(2)
328 })
329 })
330
331 describe('Playlists search', async function () {
332
333 async function check (search: VideoPlaylistsSearchQuery, exists = true) {
334 const body = await command.advancedPlaylistSearch({ search })
335
336 if (exists === false) {
337 expect(body.total).to.equal(0)
338 expect(body.data).to.have.lengthOf(0)
339 return
340 }
341
342 expect(body.total).to.be.greaterThan(0)
343 expect(body.data).to.have.length.greaterThan(0)
344
345 const videoPlaylist = body.data[0]
346
347 expect(videoPlaylist.url).to.equal('https://peertube2.cpy.re/videos/watch/playlist/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a')
348 expect(videoPlaylist.thumbnailUrl).to.exist
349 expect(videoPlaylist.embedUrl).to.equal('https://peertube2.cpy.re/video-playlists/embed/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a')
350
351 expect(videoPlaylist.type.id).to.equal(VideoPlaylistType.REGULAR)
352 expect(videoPlaylist.privacy.id).to.equal(VideoPlaylistPrivacy.PUBLIC)
353 expect(videoPlaylist.videosLength).to.exist
354
355 expect(videoPlaylist.createdAt).to.exist
356 expect(videoPlaylist.updatedAt).to.exist
357
358 expect(videoPlaylist.uuid).to.equal('73804a40-da9a-40c2-b1eb-2c6d9eec8f0a')
359 expect(videoPlaylist.displayName).to.exist
360
361 expect(videoPlaylist.ownerAccount.url).to.equal('https://peertube2.cpy.re/accounts/chocobozzz')
362 expect(videoPlaylist.ownerAccount.name).to.equal('chocobozzz')
363 expect(videoPlaylist.ownerAccount.host).to.equal('peertube2.cpy.re')
364 expect(videoPlaylist.ownerAccount.avatars.length).to.equal(2, 'Account should have two avatar images')
365
366 expect(videoPlaylist.videoChannel.url).to.equal('https://peertube2.cpy.re/video-channels/chocobozzz_channel')
367 expect(videoPlaylist.videoChannel.name).to.equal('chocobozzz_channel')
368 expect(videoPlaylist.videoChannel.host).to.equal('peertube2.cpy.re')
369 expect(videoPlaylist.videoChannel.avatars.length).to.equal(2, 'Channel should have two avatar images')
370 }
371
372 it('Should make a simple search and not have results', async function () {
373 const body = await command.searchPlaylists({ search: 'a'.repeat(500) })
374
375 expect(body.total).to.equal(0)
376 expect(body.data).to.have.lengthOf(0)
377 })
378
379 it('Should make a search and have results', async function () {
380 await check({ search: 'E2E playlist', sort: '-match' }, true)
381 })
382
383 it('Should make host search and have appropriate results', async function () {
384 await check({ search: 'E2E playlist', host: 'example.com' }, false)
385 await check({ search: 'E2E playlist', host: 'peertube2.cpy.re', sort: '-match' }, true)
386 })
387
388 it('Should make a search by uuids and have appropriate results', async function () {
389 const goodUUID = '73804a40-da9a-40c2-b1eb-2c6d9eec8f0a'
390 const goodShortUUID = 'fgei1ws1oa6FCaJ2qZPG29'
391 const badUUID = 'c29c5b77-4a04-493d-96a9-2e9267e308f0'
392 const badShortUUID = 'rP5RgUeX9XwTSrspCdkDej'
393
394 {
395 const uuidsMatrix = [
396 [ goodUUID ],
397 [ goodUUID, badShortUUID ],
398 [ badShortUUID, goodShortUUID ],
399 [ goodUUID, goodShortUUID ]
400 ]
401
402 for (const uuids of uuidsMatrix) {
403 const search = { search: 'E2E playlist', sort: '-match', uuids }
404 await check(search, true)
405 }
406 }
407
408 {
409 const uuidsMatrix = [
410 [ badUUID ],
411 [ badShortUUID ]
412 ]
413
414 for (const uuids of uuidsMatrix) {
415 const search = { search: 'E2E playlist', sort: '-match', uuids }
416 await check(search, false)
417 }
418 }
419 })
420
421 it('Should have a correct pagination', async function () {
422 const body = await command.advancedChannelSearch({ search: { search: 'root', start: 0, count: 2 } })
423
424 expect(body.total).to.be.greaterThan(2)
425 expect(body.data).to.have.lengthOf(2)
426 })
427 })
428
429 after(async function () {
430 await cleanupTests([ server ])
431 })
432})
diff --git a/server/tests/api/search/search-playlists.ts b/server/tests/api/search/search-playlists.ts
deleted file mode 100644
index a357674c2..000000000
--- a/server/tests/api/search/search-playlists.ts
+++ /dev/null
@@ -1,180 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { VideoPlaylistPrivacy } from '@shared/models'
5import {
6 cleanupTests,
7 createSingleServer,
8 doubleFollow,
9 PeerTubeServer,
10 SearchCommand,
11 setAccessTokensToServers,
12 setDefaultAccountAvatar,
13 setDefaultChannelAvatar,
14 setDefaultVideoChannel
15} from '@shared/server-commands'
16
17describe('Test playlists search', function () {
18 let server: PeerTubeServer
19 let remoteServer: PeerTubeServer
20 let command: SearchCommand
21 let playlistUUID: string
22 let playlistShortUUID: string
23
24 before(async function () {
25 this.timeout(120000)
26
27 const servers = await Promise.all([
28 createSingleServer(1),
29 createSingleServer(2)
30 ])
31 server = servers[0]
32 remoteServer = servers[1]
33
34 await setAccessTokensToServers([ remoteServer, server ])
35 await setDefaultVideoChannel([ remoteServer, server ])
36 await setDefaultChannelAvatar([ remoteServer, server ])
37 await setDefaultAccountAvatar([ remoteServer, server ])
38
39 await servers[1].config.disableTranscoding()
40
41 {
42 const videoId = (await server.videos.upload()).uuid
43
44 const attributes = {
45 displayName: 'Dr. Kenzo Tenma hospital videos',
46 privacy: VideoPlaylistPrivacy.PUBLIC,
47 videoChannelId: server.store.channel.id
48 }
49 const created = await server.playlists.create({ attributes })
50 playlistUUID = created.uuid
51 playlistShortUUID = created.shortUUID
52
53 await server.playlists.addElement({ playlistId: created.id, attributes: { videoId } })
54 }
55
56 {
57 const videoId = (await remoteServer.videos.upload()).uuid
58
59 const attributes = {
60 displayName: 'Johan & Anna Libert music videos',
61 privacy: VideoPlaylistPrivacy.PUBLIC,
62 videoChannelId: remoteServer.store.channel.id
63 }
64 const created = await remoteServer.playlists.create({ attributes })
65
66 await remoteServer.playlists.addElement({ playlistId: created.id, attributes: { videoId } })
67 }
68
69 {
70 const attributes = {
71 displayName: 'Inspector Lunge playlist',
72 privacy: VideoPlaylistPrivacy.PUBLIC,
73 videoChannelId: server.store.channel.id
74 }
75 await server.playlists.create({ attributes })
76 }
77
78 await doubleFollow(server, remoteServer)
79
80 command = server.search
81 })
82
83 it('Should make a simple search and not have results', async function () {
84 const body = await command.searchPlaylists({ search: 'abc' })
85
86 expect(body.total).to.equal(0)
87 expect(body.data).to.have.lengthOf(0)
88 })
89
90 it('Should make a search and have results', async function () {
91 {
92 const search = {
93 search: 'tenma',
94 start: 0,
95 count: 1
96 }
97 const body = await command.advancedPlaylistSearch({ search })
98 expect(body.total).to.equal(1)
99 expect(body.data).to.have.lengthOf(1)
100
101 const playlist = body.data[0]
102 expect(playlist.displayName).to.equal('Dr. Kenzo Tenma hospital videos')
103 expect(playlist.url).to.equal(server.url + '/video-playlists/' + playlist.uuid)
104 }
105
106 {
107 const search = {
108 search: 'Anna Livert music',
109 start: 0,
110 count: 1
111 }
112 const body = await command.advancedPlaylistSearch({ search })
113 expect(body.total).to.equal(1)
114 expect(body.data).to.have.lengthOf(1)
115
116 const playlist = body.data[0]
117 expect(playlist.displayName).to.equal('Johan & Anna Libert music videos')
118 }
119 })
120
121 it('Should filter by host', async function () {
122 {
123 const search = { search: 'tenma', host: server.host }
124 const body = await command.advancedPlaylistSearch({ search })
125 expect(body.total).to.equal(1)
126 expect(body.data).to.have.lengthOf(1)
127
128 const playlist = body.data[0]
129 expect(playlist.displayName).to.equal('Dr. Kenzo Tenma hospital videos')
130 }
131
132 {
133 const search = { search: 'Anna', host: 'example.com' }
134 const body = await command.advancedPlaylistSearch({ search })
135 expect(body.total).to.equal(0)
136 expect(body.data).to.have.lengthOf(0)
137 }
138
139 {
140 const search = { search: 'video', host: remoteServer.host }
141 const body = await command.advancedPlaylistSearch({ search })
142 expect(body.total).to.equal(1)
143 expect(body.data).to.have.lengthOf(1)
144
145 const playlist = body.data[0]
146 expect(playlist.displayName).to.equal('Johan & Anna Libert music videos')
147 }
148 })
149
150 it('Should filter by UUIDs', async function () {
151 for (const uuid of [ playlistUUID, playlistShortUUID ]) {
152 const body = await command.advancedPlaylistSearch({ search: { uuids: [ uuid ] } })
153
154 expect(body.total).to.equal(1)
155 expect(body.data[0].displayName).to.equal('Dr. Kenzo Tenma hospital videos')
156 }
157
158 {
159 const body = await command.advancedPlaylistSearch({ search: { uuids: [ 'dfd70b83-639f-4980-94af-304a56ab4b35' ] } })
160
161 expect(body.total).to.equal(0)
162 expect(body.data).to.have.lengthOf(0)
163 }
164 })
165
166 it('Should not display playlists without videos', async function () {
167 const search = {
168 search: 'Lunge',
169 start: 0,
170 count: 1
171 }
172 const body = await command.advancedPlaylistSearch({ search })
173 expect(body.total).to.equal(0)
174 expect(body.data).to.have.lengthOf(0)
175 })
176
177 after(async function () {
178 await cleanupTests([ server, remoteServer ])
179 })
180})
diff --git a/server/tests/api/search/search-videos.ts b/server/tests/api/search/search-videos.ts
deleted file mode 100644
index f7f50147d..000000000
--- a/server/tests/api/search/search-videos.ts
+++ /dev/null
@@ -1,568 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { wait } from '@shared/core-utils'
5import { VideoPrivacy } from '@shared/models'
6import {
7 cleanupTests,
8 createSingleServer,
9 doubleFollow,
10 PeerTubeServer,
11 SearchCommand,
12 setAccessTokensToServers,
13 setDefaultAccountAvatar,
14 setDefaultChannelAvatar,
15 setDefaultVideoChannel,
16 stopFfmpeg
17} from '@shared/server-commands'
18
19describe('Test videos search', function () {
20 let server: PeerTubeServer
21 let remoteServer: PeerTubeServer
22 let startDate: string
23 let videoUUID: string
24 let videoShortUUID: string
25
26 let command: SearchCommand
27
28 before(async function () {
29 this.timeout(360000)
30
31 const servers = await Promise.all([
32 createSingleServer(1),
33 createSingleServer(2)
34 ])
35 server = servers[0]
36 remoteServer = servers[1]
37
38 await setAccessTokensToServers([ server, remoteServer ])
39 await setDefaultVideoChannel([ server, remoteServer ])
40 await setDefaultChannelAvatar(server)
41 await setDefaultAccountAvatar(servers)
42
43 {
44 const attributes1 = {
45 name: '1111 2222 3333',
46 fixture: '60fps_720p_small.mp4', // 2 seconds
47 category: 1,
48 licence: 1,
49 nsfw: false,
50 language: 'fr'
51 }
52 await server.videos.upload({ attributes: attributes1 })
53
54 const attributes2 = { ...attributes1, name: attributes1.name + ' - 2', fixture: 'video_short.mp4' }
55 await server.videos.upload({ attributes: attributes2 })
56
57 {
58 const attributes3 = { ...attributes1, name: attributes1.name + ' - 3', language: undefined }
59 const { id, uuid, shortUUID } = await server.videos.upload({ attributes: attributes3 })
60 videoUUID = uuid
61 videoShortUUID = shortUUID
62
63 await server.captions.add({
64 language: 'en',
65 videoId: id,
66 fixture: 'subtitle-good2.vtt',
67 mimeType: 'application/octet-stream'
68 })
69
70 await server.captions.add({
71 language: 'aa',
72 videoId: id,
73 fixture: 'subtitle-good2.vtt',
74 mimeType: 'application/octet-stream'
75 })
76 }
77
78 const attributes4 = { ...attributes1, name: attributes1.name + ' - 4', language: 'pl', nsfw: true }
79 await server.videos.upload({ attributes: attributes4 })
80
81 await wait(1000)
82
83 startDate = new Date().toISOString()
84
85 const attributes5 = { ...attributes1, name: attributes1.name + ' - 5', licence: 2, language: undefined }
86 await server.videos.upload({ attributes: attributes5 })
87
88 const attributes6 = { ...attributes1, name: attributes1.name + ' - 6', tags: [ 't1', 't2' ] }
89 await server.videos.upload({ attributes: attributes6 })
90
91 const attributes7 = { ...attributes1, name: attributes1.name + ' - 7', originallyPublishedAt: '2019-02-12T09:58:08.286Z' }
92 await server.videos.upload({ attributes: attributes7 })
93
94 const attributes8 = { ...attributes1, name: attributes1.name + ' - 8', licence: 4 }
95 await server.videos.upload({ attributes: attributes8 })
96 }
97
98 {
99 const attributes = {
100 name: '3333 4444 5555',
101 fixture: 'video_short.mp4',
102 category: 2,
103 licence: 2,
104 language: 'en'
105 }
106 await server.videos.upload({ attributes })
107
108 await server.videos.upload({ attributes: { ...attributes, name: attributes.name + ' duplicate' } })
109 }
110
111 {
112 const attributes = {
113 name: '6666 7777 8888',
114 fixture: 'video_short.mp4',
115 category: 3,
116 licence: 3,
117 language: 'pl'
118 }
119 await server.videos.upload({ attributes })
120 }
121
122 {
123 const attributes1 = {
124 name: '9999',
125 tags: [ 'aaaa', 'bbbb', 'cccc' ],
126 category: 1
127 }
128 await server.videos.upload({ attributes: attributes1 })
129 await server.videos.upload({ attributes: { ...attributes1, category: 2 } })
130
131 await server.videos.upload({ attributes: { ...attributes1, tags: [ 'cccc', 'dddd' ] } })
132 await server.videos.upload({ attributes: { ...attributes1, tags: [ 'eeee', 'ffff' ] } })
133 }
134
135 {
136 const attributes1 = {
137 name: 'aaaa 2',
138 category: 1
139 }
140 await server.videos.upload({ attributes: attributes1 })
141 await server.videos.upload({ attributes: { ...attributes1, category: 2 } })
142 }
143
144 {
145 await remoteServer.videos.upload({ attributes: { name: 'remote video 1' } })
146 await remoteServer.videos.upload({ attributes: { name: 'remote video 2' } })
147 }
148
149 await doubleFollow(server, remoteServer)
150
151 command = server.search
152 })
153
154 it('Should make a simple search and not have results', async function () {
155 const body = await command.searchVideos({ search: 'abc' })
156
157 expect(body.total).to.equal(0)
158 expect(body.data).to.have.lengthOf(0)
159 })
160
161 it('Should make a simple search and have results', async function () {
162 const body = await command.searchVideos({ search: '4444 5555 duplicate' })
163
164 expect(body.total).to.equal(2)
165
166 const videos = body.data
167 expect(videos).to.have.lengthOf(2)
168
169 // bestmatch
170 expect(videos[0].name).to.equal('3333 4444 5555 duplicate')
171 expect(videos[1].name).to.equal('3333 4444 5555')
172 })
173
174 it('Should make a search on tags too, and have results', async function () {
175 const search = {
176 search: 'aaaa',
177 categoryOneOf: [ 1 ]
178 }
179 const body = await command.advancedVideoSearch({ search })
180
181 expect(body.total).to.equal(2)
182
183 const videos = body.data
184 expect(videos).to.have.lengthOf(2)
185
186 // bestmatch
187 expect(videos[0].name).to.equal('aaaa 2')
188 expect(videos[1].name).to.equal('9999')
189 })
190
191 it('Should filter on tags without a search', async function () {
192 const search = {
193 tagsAllOf: [ 'bbbb' ]
194 }
195 const body = await command.advancedVideoSearch({ search })
196
197 expect(body.total).to.equal(2)
198
199 const videos = body.data
200 expect(videos).to.have.lengthOf(2)
201
202 expect(videos[0].name).to.equal('9999')
203 expect(videos[1].name).to.equal('9999')
204 })
205
206 it('Should filter on category without a search', async function () {
207 const search = {
208 categoryOneOf: [ 3 ]
209 }
210 const body = await command.advancedVideoSearch({ search })
211
212 expect(body.total).to.equal(1)
213
214 const videos = body.data
215 expect(videos).to.have.lengthOf(1)
216
217 expect(videos[0].name).to.equal('6666 7777 8888')
218 })
219
220 it('Should search by tags (one of)', async function () {
221 const query = {
222 search: '9999',
223 categoryOneOf: [ 1 ],
224 tagsOneOf: [ 'aAaa', 'ffff' ]
225 }
226
227 {
228 const body = await command.advancedVideoSearch({ search: query })
229 expect(body.total).to.equal(2)
230 }
231
232 {
233 const body = await command.advancedVideoSearch({ search: { ...query, tagsOneOf: [ 'blabla' ] } })
234 expect(body.total).to.equal(0)
235 }
236 })
237
238 it('Should search by tags (all of)', async function () {
239 const query = {
240 search: '9999',
241 categoryOneOf: [ 1 ],
242 tagsAllOf: [ 'CCcc' ]
243 }
244
245 {
246 const body = await command.advancedVideoSearch({ search: query })
247 expect(body.total).to.equal(2)
248 }
249
250 {
251 const body = await command.advancedVideoSearch({ search: { ...query, tagsAllOf: [ 'blAbla' ] } })
252 expect(body.total).to.equal(0)
253 }
254
255 {
256 const body = await command.advancedVideoSearch({ search: { ...query, tagsAllOf: [ 'bbbb', 'CCCC' ] } })
257 expect(body.total).to.equal(1)
258 }
259 })
260
261 it('Should search by category', async function () {
262 const query = {
263 search: '6666',
264 categoryOneOf: [ 3 ]
265 }
266
267 {
268 const body = await command.advancedVideoSearch({ search: query })
269 expect(body.total).to.equal(1)
270 expect(body.data[0].name).to.equal('6666 7777 8888')
271 }
272
273 {
274 const body = await command.advancedVideoSearch({ search: { ...query, categoryOneOf: [ 2 ] } })
275 expect(body.total).to.equal(0)
276 }
277 })
278
279 it('Should search by licence', async function () {
280 const query = {
281 search: '4444 5555',
282 licenceOneOf: [ 2 ]
283 }
284
285 {
286 const body = await command.advancedVideoSearch({ search: query })
287 expect(body.total).to.equal(2)
288 expect(body.data[0].name).to.equal('3333 4444 5555')
289 expect(body.data[1].name).to.equal('3333 4444 5555 duplicate')
290 }
291
292 {
293 const body = await command.advancedVideoSearch({ search: { ...query, licenceOneOf: [ 3 ] } })
294 expect(body.total).to.equal(0)
295 }
296 })
297
298 it('Should search by languages', async function () {
299 const query = {
300 search: '1111 2222 3333',
301 languageOneOf: [ 'pl', 'en' ]
302 }
303
304 {
305 const body = await command.advancedVideoSearch({ search: query })
306 expect(body.total).to.equal(2)
307 expect(body.data[0].name).to.equal('1111 2222 3333 - 3')
308 expect(body.data[1].name).to.equal('1111 2222 3333 - 4')
309 }
310
311 {
312 const body = await command.advancedVideoSearch({ search: { ...query, languageOneOf: [ 'pl', 'en', '_unknown' ] } })
313 expect(body.total).to.equal(3)
314 expect(body.data[0].name).to.equal('1111 2222 3333 - 3')
315 expect(body.data[1].name).to.equal('1111 2222 3333 - 4')
316 expect(body.data[2].name).to.equal('1111 2222 3333 - 5')
317 }
318
319 {
320 const body = await command.advancedVideoSearch({ search: { ...query, languageOneOf: [ 'eo' ] } })
321 expect(body.total).to.equal(0)
322 }
323 })
324
325 it('Should search by start date', async function () {
326 const query = {
327 search: '1111 2222 3333',
328 startDate
329 }
330
331 const body = await command.advancedVideoSearch({ search: query })
332 expect(body.total).to.equal(4)
333
334 const videos = body.data
335 expect(videos[0].name).to.equal('1111 2222 3333 - 5')
336 expect(videos[1].name).to.equal('1111 2222 3333 - 6')
337 expect(videos[2].name).to.equal('1111 2222 3333 - 7')
338 expect(videos[3].name).to.equal('1111 2222 3333 - 8')
339 })
340
341 it('Should make an advanced search', async function () {
342 const query = {
343 search: '1111 2222 3333',
344 languageOneOf: [ 'pl', 'fr' ],
345 durationMax: 4,
346 nsfw: 'false' as 'false',
347 licenceOneOf: [ 1, 4 ]
348 }
349
350 const body = await command.advancedVideoSearch({ search: query })
351 expect(body.total).to.equal(4)
352
353 const videos = body.data
354 expect(videos[0].name).to.equal('1111 2222 3333')
355 expect(videos[1].name).to.equal('1111 2222 3333 - 6')
356 expect(videos[2].name).to.equal('1111 2222 3333 - 7')
357 expect(videos[3].name).to.equal('1111 2222 3333 - 8')
358 })
359
360 it('Should make an advanced search and sort results', async function () {
361 const query = {
362 search: '1111 2222 3333',
363 languageOneOf: [ 'pl', 'fr' ],
364 durationMax: 4,
365 nsfw: 'false' as 'false',
366 licenceOneOf: [ 1, 4 ],
367 sort: '-name'
368 }
369
370 const body = await command.advancedVideoSearch({ search: query })
371 expect(body.total).to.equal(4)
372
373 const videos = body.data
374 expect(videos[0].name).to.equal('1111 2222 3333 - 8')
375 expect(videos[1].name).to.equal('1111 2222 3333 - 7')
376 expect(videos[2].name).to.equal('1111 2222 3333 - 6')
377 expect(videos[3].name).to.equal('1111 2222 3333')
378 })
379
380 it('Should make an advanced search and only show the first result', async function () {
381 const query = {
382 search: '1111 2222 3333',
383 languageOneOf: [ 'pl', 'fr' ],
384 durationMax: 4,
385 nsfw: 'false' as 'false',
386 licenceOneOf: [ 1, 4 ],
387 sort: '-name',
388 start: 0,
389 count: 1
390 }
391
392 const body = await command.advancedVideoSearch({ search: query })
393 expect(body.total).to.equal(4)
394
395 const videos = body.data
396 expect(videos[0].name).to.equal('1111 2222 3333 - 8')
397 })
398
399 it('Should make an advanced search and only show the last result', async function () {
400 const query = {
401 search: '1111 2222 3333',
402 languageOneOf: [ 'pl', 'fr' ],
403 durationMax: 4,
404 nsfw: 'false' as 'false',
405 licenceOneOf: [ 1, 4 ],
406 sort: '-name',
407 start: 3,
408 count: 1
409 }
410
411 const body = await command.advancedVideoSearch({ search: query })
412 expect(body.total).to.equal(4)
413
414 const videos = body.data
415 expect(videos[0].name).to.equal('1111 2222 3333')
416 })
417
418 it('Should search on originally published date', async function () {
419 const baseQuery = {
420 search: '1111 2222 3333',
421 languageOneOf: [ 'pl', 'fr' ],
422 durationMax: 4,
423 nsfw: 'false' as 'false',
424 licenceOneOf: [ 1, 4 ]
425 }
426
427 {
428 const query = { ...baseQuery, originallyPublishedStartDate: '2019-02-11T09:58:08.286Z' }
429 const body = await command.advancedVideoSearch({ search: query })
430
431 expect(body.total).to.equal(1)
432 expect(body.data[0].name).to.equal('1111 2222 3333 - 7')
433 }
434
435 {
436 const query = { ...baseQuery, originallyPublishedEndDate: '2019-03-11T09:58:08.286Z' }
437 const body = await command.advancedVideoSearch({ search: query })
438
439 expect(body.total).to.equal(1)
440 expect(body.data[0].name).to.equal('1111 2222 3333 - 7')
441 }
442
443 {
444 const query = { ...baseQuery, originallyPublishedEndDate: '2019-01-11T09:58:08.286Z' }
445 const body = await command.advancedVideoSearch({ search: query })
446
447 expect(body.total).to.equal(0)
448 }
449
450 {
451 const query = { ...baseQuery, originallyPublishedStartDate: '2019-03-11T09:58:08.286Z' }
452 const body = await command.advancedVideoSearch({ search: query })
453
454 expect(body.total).to.equal(0)
455 }
456
457 {
458 const query = {
459 ...baseQuery,
460 originallyPublishedStartDate: '2019-01-11T09:58:08.286Z',
461 originallyPublishedEndDate: '2019-01-10T09:58:08.286Z'
462 }
463 const body = await command.advancedVideoSearch({ search: query })
464
465 expect(body.total).to.equal(0)
466 }
467
468 {
469 const query = {
470 ...baseQuery,
471 originallyPublishedStartDate: '2019-01-11T09:58:08.286Z',
472 originallyPublishedEndDate: '2019-04-11T09:58:08.286Z'
473 }
474 const body = await command.advancedVideoSearch({ search: query })
475
476 expect(body.total).to.equal(1)
477 expect(body.data[0].name).to.equal('1111 2222 3333 - 7')
478 }
479 })
480
481 it('Should search by UUID', async function () {
482 const search = videoUUID
483 const body = await command.advancedVideoSearch({ search: { search } })
484
485 expect(body.total).to.equal(1)
486 expect(body.data[0].name).to.equal('1111 2222 3333 - 3')
487 })
488
489 it('Should filter by UUIDs', async function () {
490 for (const uuid of [ videoUUID, videoShortUUID ]) {
491 const body = await command.advancedVideoSearch({ search: { uuids: [ uuid ] } })
492
493 expect(body.total).to.equal(1)
494 expect(body.data[0].name).to.equal('1111 2222 3333 - 3')
495 }
496
497 {
498 const body = await command.advancedVideoSearch({ search: { uuids: [ 'dfd70b83-639f-4980-94af-304a56ab4b35' ] } })
499
500 expect(body.total).to.equal(0)
501 expect(body.data).to.have.lengthOf(0)
502 }
503 })
504
505 it('Should search by host', async function () {
506 {
507 const body = await command.advancedVideoSearch({ search: { search: '6666 7777 8888', host: server.host } })
508 expect(body.total).to.equal(1)
509 expect(body.data[0].name).to.equal('6666 7777 8888')
510 }
511
512 {
513 const body = await command.advancedVideoSearch({ search: { search: '1111', host: 'example.com' } })
514 expect(body.total).to.equal(0)
515 expect(body.data).to.have.lengthOf(0)
516 }
517
518 {
519 const body = await command.advancedVideoSearch({ search: { search: 'remote', host: remoteServer.host } })
520 expect(body.total).to.equal(2)
521 expect(body.data).to.have.lengthOf(2)
522 expect(body.data[0].name).to.equal('remote video 1')
523 expect(body.data[1].name).to.equal('remote video 2')
524 }
525 })
526
527 it('Should search by live', async function () {
528 this.timeout(120000)
529
530 {
531 const newConfig = {
532 search: {
533 searchIndex: { enabled: false }
534 },
535 live: { enabled: true }
536 }
537 await server.config.updateCustomSubConfig({ newConfig })
538 }
539
540 {
541 const body = await command.advancedVideoSearch({ search: { isLive: true } })
542
543 expect(body.total).to.equal(0)
544 expect(body.data).to.have.lengthOf(0)
545 }
546
547 {
548 const liveCommand = server.live
549
550 const liveAttributes = { name: 'live', privacy: VideoPrivacy.PUBLIC, channelId: server.store.channel.id }
551 const live = await liveCommand.create({ fields: liveAttributes })
552
553 const ffmpegCommand = await liveCommand.sendRTMPStreamInVideo({ videoId: live.id })
554 await liveCommand.waitUntilPublished({ videoId: live.id })
555
556 const body = await command.advancedVideoSearch({ search: { isLive: true } })
557
558 expect(body.total).to.equal(1)
559 expect(body.data[0].name).to.equal('live')
560
561 await stopFfmpeg(ffmpegCommand)
562 }
563 })
564
565 after(async function () {
566 await cleanupTests([ server ])
567 })
568})