From 37a44fc915eef2140e22ceb96aba6b6eb2509007 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 17 Jun 2021 16:02:38 +0200 Subject: Add ability to search playlists --- server/tests/api/search/index.ts | 4 +- .../search/search-activitypub-video-channels.ts | 16 ++ .../search/search-activitypub-video-playlists.ts | 212 +++++++++++++++++++++ .../tests/api/search/search-activitypub-videos.ts | 35 +++- server/tests/api/search/search-index.ts | 62 +++++- server/tests/api/search/search-playlists.ts | 128 +++++++++++++ 6 files changed, 443 insertions(+), 14 deletions(-) create mode 100644 server/tests/api/search/search-activitypub-video-playlists.ts create mode 100644 server/tests/api/search/search-playlists.ts (limited to 'server/tests/api/search') 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 @@ +import './search-activitypub-video-playlists' import './search-activitypub-video-channels' import './search-activitypub-videos' +import './search-channels' import './search-index' +import './search-playlists' import './search-videos' -import './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 () { } }) + it('Should search a local video channel with an alternative URL', async function () { + const search = 'http://localhost:' + servers[0].port + '/c/channel1_server1' + + for (const token of [ undefined, servers[0].accessToken ]) { + const res = await searchVideoChannel(servers[0].url, search, token) + + expect(res.body.total).to.equal(1) + expect(res.body.data).to.be.an('array') + expect(res.body.data).to.have.lengthOf(1) + expect(res.body.data[0].name).to.equal('channel1_server1') + expect(res.body.data[0].displayName).to.equal('Channel 1 server 1') + } + }) + it('Should search a remote video channel with URL or handle', async function () { const searches = [ 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2', + 'http://localhost:' + servers[1].port + '/c/channel1_server2', + 'http://localhost:' + servers[1].port + '/c/channel1_server2/videos', 'channel1_server2@localhost:' + servers[1].port ] 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 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import 'mocha' +import * as chai from 'chai' +import { + addVideoInPlaylist, + cleanupTests, + createVideoPlaylist, + deleteVideoPlaylist, + flushAndRunMultipleServers, + getVideoPlaylistsList, + searchVideoPlaylists, + ServerInfo, + setAccessTokensToServers, + setDefaultVideoChannel, + uploadVideoAndGetId, + wait +} from '../../../../shared/extra-utils' +import { waitJobs } from '../../../../shared/extra-utils/server/jobs' +import { VideoPlaylist, VideoPlaylistPrivacy } from '../../../../shared/models/videos' + +const expect = chai.expect + +describe('Test ActivityPub playlists search', function () { + let servers: ServerInfo[] + let playlistServer1UUID: string + let playlistServer2UUID: string + let video2Server2: string + + before(async function () { + this.timeout(120000) + + servers = await flushAndRunMultipleServers(2) + + await setAccessTokensToServers(servers) + await setDefaultVideoChannel(servers) + + { + const video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 1' })).uuid + const video2 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 2' })).uuid + + const attributes = { + displayName: 'playlist 1 on server 1', + privacy: VideoPlaylistPrivacy.PUBLIC, + videoChannelId: servers[0].videoChannel.id + } + const res = await createVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistAttrs: attributes }) + playlistServer1UUID = res.body.videoPlaylist.uuid + + for (const videoId of [ video1, video2 ]) { + await addVideoInPlaylist({ + url: servers[0].url, + token: servers[0].accessToken, + playlistId: playlistServer1UUID, + elementAttrs: { videoId } + }) + } + } + + { + const videoId = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 1' })).uuid + video2Server2 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 2' })).uuid + + const attributes = { + displayName: 'playlist 1 on server 2', + privacy: VideoPlaylistPrivacy.PUBLIC, + videoChannelId: servers[1].videoChannel.id + } + const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs: attributes }) + playlistServer2UUID = res.body.videoPlaylist.uuid + + await addVideoInPlaylist({ + url: servers[1].url, + token: servers[1].accessToken, + playlistId: playlistServer2UUID, + elementAttrs: { videoId } + }) + } + + await waitJobs(servers) + }) + + it('Should not find a remote playlist', async function () { + { + const search = 'http://localhost:' + servers[1].port + '/video-playlists/43' + const res = await searchVideoPlaylists(servers[0].url, search, servers[0].accessToken) + + expect(res.body.total).to.equal(0) + expect(res.body.data).to.be.an('array') + expect(res.body.data).to.have.lengthOf(0) + } + + { + // Without token + const search = 'http://localhost:' + servers[1].port + '/video-playlists/' + playlistServer2UUID + const res = await searchVideoPlaylists(servers[0].url, search) + + expect(res.body.total).to.equal(0) + expect(res.body.data).to.be.an('array') + expect(res.body.data).to.have.lengthOf(0) + } + }) + + it('Should search a local playlist', async function () { + const search = 'http://localhost:' + servers[0].port + '/video-playlists/' + playlistServer1UUID + const res = await searchVideoPlaylists(servers[0].url, search) + + expect(res.body.total).to.equal(1) + expect(res.body.data).to.be.an('array') + expect(res.body.data).to.have.lengthOf(1) + expect(res.body.data[0].displayName).to.equal('playlist 1 on server 1') + expect(res.body.data[0].videosLength).to.equal(2) + }) + + it('Should search a local playlist with an alternative URL', async function () { + const searches = [ + 'http://localhost:' + servers[0].port + '/videos/watch/playlist/' + playlistServer1UUID, + 'http://localhost:' + servers[0].port + '/w/p/' + playlistServer1UUID + ] + + for (const search of searches) { + for (const token of [ undefined, servers[0].accessToken ]) { + const res = await searchVideoPlaylists(servers[0].url, search, token) + + expect(res.body.total).to.equal(1) + expect(res.body.data).to.be.an('array') + expect(res.body.data).to.have.lengthOf(1) + expect(res.body.data[0].displayName).to.equal('playlist 1 on server 1') + expect(res.body.data[0].videosLength).to.equal(2) + } + } + }) + + it('Should search a remote playlist', async function () { + const searches = [ + 'http://localhost:' + servers[1].port + '/video-playlists/' + playlistServer2UUID, + 'http://localhost:' + servers[1].port + '/videos/watch/playlist/' + playlistServer2UUID, + 'http://localhost:' + servers[1].port + '/w/p/' + playlistServer2UUID + ] + + for (const search of searches) { + const res = await searchVideoPlaylists(servers[0].url, search, servers[0].accessToken) + + expect(res.body.total).to.equal(1) + expect(res.body.data).to.be.an('array') + expect(res.body.data).to.have.lengthOf(1) + expect(res.body.data[0].displayName).to.equal('playlist 1 on server 2') + expect(res.body.data[0].videosLength).to.equal(1) + } + }) + + it('Should not list this remote playlist', async function () { + const res = await getVideoPlaylistsList(servers[0].url, 0, 10) + expect(res.body.total).to.equal(1) + expect(res.body.data).to.have.lengthOf(1) + expect(res.body.data[0].displayName).to.equal('playlist 1 on server 1') + }) + + it('Should update the playlist of server 2, and refresh it on server 1', async function () { + this.timeout(60000) + + await addVideoInPlaylist({ + url: servers[1].url, + token: servers[1].accessToken, + playlistId: playlistServer2UUID, + elementAttrs: { videoId: video2Server2 } + }) + + await waitJobs(servers) + // Expire playlist + await wait(10000) + + // Will run refresh async + const search = 'http://localhost:' + servers[1].port + '/video-playlists/' + playlistServer2UUID + await searchVideoPlaylists(servers[0].url, search, servers[0].accessToken) + + // Wait refresh + await wait(5000) + + const res = await searchVideoPlaylists(servers[0].url, search, servers[0].accessToken) + expect(res.body.total).to.equal(1) + expect(res.body.data).to.have.lengthOf(1) + + const playlist: VideoPlaylist = res.body.data[0] + expect(playlist.videosLength).to.equal(2) + }) + + it('Should delete playlist of server 2, and delete it on server 1', async function () { + this.timeout(60000) + + await deleteVideoPlaylist(servers[1].url, servers[1].accessToken, playlistServer2UUID) + + await waitJobs(servers) + // Expiration + await wait(10000) + + // Will run refresh async + const search = 'http://localhost:' + servers[1].port + '/video-playlists/' + playlistServer2UUID + await searchVideoPlaylists(servers[0].url, search, servers[0].accessToken) + + // Wait refresh + await wait(5000) + + const res = await searchVideoPlaylists(servers[0].url, search, servers[0].accessToken) + expect(res.body.total).to.equal(0) + expect(res.body.data).to.have.lengthOf(0) + }) + + after(async function () { + await cleanupTests(servers) + }) +}) 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 () { expect(res.body.data[0].name).to.equal('video 1 on server 1') }) + it('Should search a local video with an alternative URL', async function () { + const search = 'http://localhost:' + servers[0].port + '/w/' + videoServer1UUID + const res1 = await searchVideo(servers[0].url, search) + const res2 = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken) + + for (const res of [ res1, res2 ]) { + expect(res.body.total).to.equal(1) + expect(res.body.data).to.be.an('array') + expect(res.body.data).to.have.lengthOf(1) + expect(res.body.data[0].name).to.equal('video 1 on server 1') + } + }) + it('Should search a remote video', async function () { - const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID - const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken) + const searches = [ + 'http://localhost:' + servers[1].port + '/w/' + videoServer2UUID, + 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID + ] - expect(res.body.total).to.equal(1) - expect(res.body.data).to.be.an('array') - expect(res.body.data).to.have.lengthOf(1) - expect(res.body.data[0].name).to.equal('video 1 on server 2') + for (const search of searches) { + const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken) + + expect(res.body.total).to.equal(1) + expect(res.body.data).to.be.an('array') + expect(res.body.data).to.have.lengthOf(1) + expect(res.body.data[0].name).to.equal('video 1 on server 2') + } }) it('Should not list this remote video', async function () { @@ -95,7 +114,7 @@ describe('Test ActivityPub videos search', function () { }) it('Should update video of server 2, and refresh it on server 1', async function () { - this.timeout(60000) + this.timeout(120000) const channelAttributes = { name: 'super_channel', @@ -134,7 +153,7 @@ describe('Test ActivityPub videos search', function () { }) it('Should delete video of server 2, and delete it on server 1', async function () { - this.timeout(60000) + this.timeout(120000) await removeVideo(servers[1].url, servers[1].accessToken, videoServer2UUID) 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 @@ import 'mocha' import * as chai from 'chai' +import { advancedVideoChannelSearch, searchVideoChannel } from '@shared/extra-utils/search/video-channels' +import { Video, VideoChannel, VideoPlaylist, VideoPlaylistPrivacy, VideoPlaylistType, VideosSearchQuery } from '@shared/models' import { + advancedVideoPlaylistSearch, + advancedVideosSearch, cleanupTests, flushAndRunServer, + immutableAssign, searchVideo, + searchVideoPlaylists, ServerInfo, setAccessTokensToServers, updateCustomSubConfig, - uploadVideo, - advancedVideosSearch, - immutableAssign + uploadVideo } from '../../../../shared/extra-utils' -import { searchVideoChannel, advancedVideoChannelSearch } from '@shared/extra-utils/search/video-channels' -import { VideosSearchQuery, Video, VideoChannel } from '@shared/models' const expect = chai.expect @@ -277,6 +279,56 @@ describe('Test videos search', function () { }) }) + describe('Playlists search', async function () { + + it('Should make a simple search and not have results', async function () { + const res = await searchVideoPlaylists(server.url, 'a'.repeat(500)) + + expect(res.body.total).to.equal(0) + expect(res.body.data).to.have.lengthOf(0) + }) + + it('Should make a search and have results', async function () { + const res = await advancedVideoPlaylistSearch(server.url, { search: 'E2E playlist', sort: '-match' }) + + expect(res.body.total).to.be.greaterThan(0) + expect(res.body.data).to.have.length.greaterThan(0) + + const videoPlaylist: VideoPlaylist = res.body.data[0] + + expect(videoPlaylist.url).to.equal('https://peertube2.cpy.re/videos/watch/playlist/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a') + expect(videoPlaylist.thumbnailUrl).to.exist + expect(videoPlaylist.embedUrl).to.equal('https://peertube2.cpy.re/video-playlists/embed/73804a40-da9a-40c2-b1eb-2c6d9eec8f0a') + + expect(videoPlaylist.type.id).to.equal(VideoPlaylistType.REGULAR) + expect(videoPlaylist.privacy.id).to.equal(VideoPlaylistPrivacy.PUBLIC) + expect(videoPlaylist.videosLength).to.exist + + expect(videoPlaylist.createdAt).to.exist + expect(videoPlaylist.updatedAt).to.exist + + expect(videoPlaylist.uuid).to.equal('73804a40-da9a-40c2-b1eb-2c6d9eec8f0a') + expect(videoPlaylist.displayName).to.exist + + expect(videoPlaylist.ownerAccount.url).to.equal('https://peertube2.cpy.re/accounts/chocobozzz') + expect(videoPlaylist.ownerAccount.name).to.equal('chocobozzz') + expect(videoPlaylist.ownerAccount.host).to.equal('peertube2.cpy.re') + expect(videoPlaylist.ownerAccount.avatar).to.exist + + expect(videoPlaylist.videoChannel.url).to.equal('https://peertube2.cpy.re/video-channels/chocobozzz_channel') + expect(videoPlaylist.videoChannel.name).to.equal('chocobozzz_channel') + expect(videoPlaylist.videoChannel.host).to.equal('peertube2.cpy.re') + expect(videoPlaylist.videoChannel.avatar).to.exist + }) + + it('Should have a correct pagination', async function () { + const res = await advancedVideoChannelSearch(server.url, { search: 'root', start: 0, count: 2 }) + + expect(res.body.total).to.be.greaterThan(2) + expect(res.body.data).to.have.lengthOf(2) + }) + }) + after(async function () { await cleanupTests([ server ]) }) 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 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import 'mocha' +import * as chai from 'chai' +import { VideoPlaylist, VideoPlaylistPrivacy } from '@shared/models' +import { + addVideoInPlaylist, + advancedVideoPlaylistSearch, + cleanupTests, + createVideoPlaylist, + flushAndRunServer, + searchVideoPlaylists, + ServerInfo, + setAccessTokensToServers, + setDefaultVideoChannel, + uploadVideoAndGetId +} from '../../../../shared/extra-utils' + +const expect = chai.expect + +describe('Test playlists search', function () { + let server: ServerInfo = null + + before(async function () { + this.timeout(30000) + + server = await flushAndRunServer(1) + + await setAccessTokensToServers([ server ]) + await setDefaultVideoChannel([ server ]) + + const videoId = (await uploadVideoAndGetId({ server: server, videoName: 'video' })).uuid + + { + const attributes = { + displayName: 'Dr. Kenzo Tenma hospital videos', + privacy: VideoPlaylistPrivacy.PUBLIC, + videoChannelId: server.videoChannel.id + } + const res = await createVideoPlaylist({ url: server.url, token: server.accessToken, playlistAttrs: attributes }) + + await addVideoInPlaylist({ + url: server.url, + token: server.accessToken, + playlistId: res.body.videoPlaylist.id, + elementAttrs: { videoId } + }) + } + + { + const attributes = { + displayName: 'Johan & Anna Libert musics', + privacy: VideoPlaylistPrivacy.PUBLIC, + videoChannelId: server.videoChannel.id + } + const res = await createVideoPlaylist({ url: server.url, token: server.accessToken, playlistAttrs: attributes }) + + await addVideoInPlaylist({ + url: server.url, + token: server.accessToken, + playlistId: res.body.videoPlaylist.id, + elementAttrs: { videoId } + }) + } + + { + const attributes = { + displayName: 'Inspector Lunge playlist', + privacy: VideoPlaylistPrivacy.PUBLIC, + videoChannelId: server.videoChannel.id + } + await createVideoPlaylist({ url: server.url, token: server.accessToken, playlistAttrs: attributes }) + } + }) + + it('Should make a simple search and not have results', async function () { + const res = await searchVideoPlaylists(server.url, 'abc') + + expect(res.body.total).to.equal(0) + expect(res.body.data).to.have.lengthOf(0) + }) + + it('Should make a search and have results', async function () { + { + const search = { + search: 'tenma', + start: 0, + count: 1 + } + const res = await advancedVideoPlaylistSearch(server.url, search) + expect(res.body.total).to.equal(1) + expect(res.body.data).to.have.lengthOf(1) + + const playlist: VideoPlaylist = res.body.data[0] + expect(playlist.displayName).to.equal('Dr. Kenzo Tenma hospital videos') + expect(playlist.url).to.equal(server.url + '/video-playlists/' + playlist.uuid) + } + + { + const search = { + search: 'Anna Livert', + start: 0, + count: 1 + } + const res = await advancedVideoPlaylistSearch(server.url, search) + expect(res.body.total).to.equal(1) + expect(res.body.data).to.have.lengthOf(1) + + const playlist: VideoPlaylist = res.body.data[0] + expect(playlist.displayName).to.equal('Johan & Anna Libert musics') + } + }) + + it('Should not display playlists without videos', async function () { + const search = { + search: 'Lunge', + start: 0, + count: 1 + } + const res = await advancedVideoPlaylistSearch(server.url, search) + expect(res.body.total).to.equal(0) + expect(res.body.data).to.have.lengthOf(0) + }) + + after(async function () { + await cleanupTests([ server ]) + }) +}) -- cgit v1.2.3