From: Chocobozzz Date: Tue, 6 Jul 2021 08:21:35 +0000 (+0200) Subject: Introduce feed command X-Git-Tag: v3.4.0-rc.1~200^2~56 X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=c1bc8ee4783d6ce3102524e6c2a02b2f0f6aab6d;p=github%2FChocobozzz%2FPeerTube.git Introduce feed command --- diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts index 7bad81751..4d29a2e39 100644 --- a/server/tests/feeds/feeds.ts +++ b/server/tests/feeds/feeds.ts @@ -11,16 +11,15 @@ import { import { addUserSubscription, listUserSubscriptionVideos } from '@shared/extra-utils/users/user-subscriptions' import { VideoPrivacy } from '@shared/models' import { ScopedToken } from '@shared/models/users/user-scoped-token' +import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' import { cleanupTests, createUser, doubleFollow, flushAndRunMultipleServers, flushAndRunServer, - getJSONfeed, getMyUserInformation, getUserScopedTokens, - getXMLfeed, renewUserScopedTokens, ServerInfo, setAccessTokensToServers, @@ -31,7 +30,6 @@ import { import { waitJobs } from '../../../shared/extra-utils/server/jobs' import { addVideoCommentThread } from '../../../shared/extra-utils/videos/video-comments' import { User } from '../../../shared/models/users' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' chai.use(require('chai-xml')) chai.use(require('chai-json-schema')) @@ -118,18 +116,18 @@ describe('Test syndication feeds', () => { it('Should be well formed XML (covers RSS 2.0 and ATOM 1.0 endpoints)', async function () { for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { - const rss = await getXMLfeed(servers[0].url, feed) - expect(rss.text).xml.to.be.valid() + const rss = await servers[0].feedCommand.getXML({ feed }) + expect(rss).xml.to.be.valid() - const atom = await getXMLfeed(servers[0].url, feed, 'atom') - expect(atom.text).xml.to.be.valid() + const atom = await servers[0].feedCommand.getXML({ feed, format: 'atom' }) + expect(atom).xml.to.be.valid() } }) it('Should be well formed JSON (covers JSON feed 1.0 endpoint)', async function () { for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { - const json = await getJSONfeed(servers[0].url, feed) - expect(JSON.parse(json.text)).to.be.jsonSchema({ type: 'object' }) + const jsonText = await servers[0].feedCommand.getJSON({ feed }) + expect(JSON.parse(jsonText)).to.be.jsonSchema({ type: 'object' }) } }) }) @@ -138,10 +136,10 @@ describe('Test syndication feeds', () => { it('Should contain a valid enclosure (covers RSS 2.0 endpoint)', async function () { for (const server of servers) { - const rss = await getXMLfeed(server.url, 'videos') - expect(xmlParser.validate(rss.text)).to.be.true + const rss = await server.feedCommand.getXML({ feed: 'videos' }) + expect(xmlParser.validate(rss)).to.be.true - const xmlDoc = xmlParser.parse(rss.text, { parseAttributeValue: true, ignoreAttributes: false }) + const xmlDoc = xmlParser.parse(rss, { parseAttributeValue: true, ignoreAttributes: false }) const enclosure = xmlDoc.rss.channel.item[0].enclosure expect(enclosure).to.exist @@ -153,8 +151,8 @@ describe('Test syndication feeds', () => { it('Should contain a valid \'attachments\' object (covers JSON feed 1.0 endpoint)', async function () { for (const server of servers) { - const json = await getJSONfeed(server.url, 'videos') - const jsonObj = JSON.parse(json.text) + const json = await server.feedCommand.getJSON({ feed: 'videos' }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(2) expect(jsonObj.items[0].attachments).to.exist expect(jsonObj.items[0].attachments.length).to.be.eq(1) @@ -166,16 +164,16 @@ describe('Test syndication feeds', () => { it('Should filter by account', async function () { { - const json = await getJSONfeed(servers[0].url, 'videos', { accountId: rootAccountId }) - const jsonObj = JSON.parse(json.text) + const json = await servers[0].feedCommand.getJSON({ feed: 'videos', query: { accountId: rootAccountId } }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(1) expect(jsonObj.items[0].title).to.equal('my super name for server 1') expect(jsonObj.items[0].author.name).to.equal('root') } { - const json = await getJSONfeed(servers[0].url, 'videos', { accountId: userAccountId }) - const jsonObj = JSON.parse(json.text) + const json = await servers[0].feedCommand.getJSON({ feed: 'videos', query: { accountId: userAccountId } }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(1) expect(jsonObj.items[0].title).to.equal('user video') expect(jsonObj.items[0].author.name).to.equal('john') @@ -183,15 +181,15 @@ describe('Test syndication feeds', () => { for (const server of servers) { { - const json = await getJSONfeed(server.url, 'videos', { accountName: 'root@localhost:' + servers[0].port }) - const jsonObj = JSON.parse(json.text) + const json = await server.feedCommand.getJSON({ feed: 'videos', query: { accountName: 'root@localhost:' + servers[0].port } }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(1) expect(jsonObj.items[0].title).to.equal('my super name for server 1') } { - const json = await getJSONfeed(server.url, 'videos', { accountName: 'john@localhost:' + servers[0].port }) - const jsonObj = JSON.parse(json.text) + const json = await server.feedCommand.getJSON({ feed: 'videos', query: { accountName: 'john@localhost:' + servers[0].port } }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(1) expect(jsonObj.items[0].title).to.equal('user video') } @@ -200,16 +198,16 @@ describe('Test syndication feeds', () => { it('Should filter by video channel', async function () { { - const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: rootChannelId }) - const jsonObj = JSON.parse(json.text) + const json = await servers[0].feedCommand.getJSON({ feed: 'videos', query: { videoChannelId: rootChannelId } }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(1) expect(jsonObj.items[0].title).to.equal('my super name for server 1') expect(jsonObj.items[0].author.name).to.equal('root') } { - const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: userChannelId }) - const jsonObj = JSON.parse(json.text) + const json = await servers[0].feedCommand.getJSON({ feed: 'videos', query: { videoChannelId: userChannelId } }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(1) expect(jsonObj.items[0].title).to.equal('user video') expect(jsonObj.items[0].author.name).to.equal('john') @@ -217,15 +215,17 @@ describe('Test syndication feeds', () => { for (const server of servers) { { - const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'root_channel@localhost:' + servers[0].port }) - const jsonObj = JSON.parse(json.text) + const query = { videoChannelName: 'root_channel@localhost:' + servers[0].port } + const json = await server.feedCommand.getJSON({ feed: 'videos', query }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(1) expect(jsonObj.items[0].title).to.equal('my super name for server 1') } { - const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'john_channel@localhost:' + servers[0].port }) - const jsonObj = JSON.parse(json.text) + const query = { videoChannelName: 'john_channel@localhost:' + servers[0].port } + const json = await server.feedCommand.getJSON({ feed: 'videos', query }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(1) expect(jsonObj.items[0].title).to.equal('user video') } @@ -239,8 +239,8 @@ describe('Test syndication feeds', () => { await waitJobs([ serverHLSOnly ]) - const json = await getJSONfeed(serverHLSOnly.url, 'videos') - const jsonObj = JSON.parse(json.text) + const json = await serverHLSOnly.feedCommand.getJSON({ feed: 'videos' }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(1) expect(jsonObj.items[0].attachments).to.exist expect(jsonObj.items[0].attachments.length).to.be.eq(4) @@ -257,9 +257,9 @@ describe('Test syndication feeds', () => { it('Should contain valid comments (covers JSON feed 1.0 endpoint) and not from unlisted videos', async function () { for (const server of servers) { - const json = await getJSONfeed(server.url, 'video-comments') + const json = await server.feedCommand.getJSON({ feed: 'video-comments' }) - const jsonObj = JSON.parse(json.text) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(2) expect(jsonObj.items[0].html_content).to.equal('super comment 2') expect(jsonObj.items[1].html_content).to.equal('super comment 1') @@ -274,8 +274,8 @@ describe('Test syndication feeds', () => { await addAccountToServerBlocklist(servers[1].url, servers[1].accessToken, remoteHandle) { - const json = await getJSONfeed(servers[1].url, 'video-comments', { version: 2 }) - const jsonObj = JSON.parse(json.text) + const json = await servers[1].feedCommand.getJSON({ feed: 'video-comments', query: { version: 2 } }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(0) } @@ -287,16 +287,16 @@ describe('Test syndication feeds', () => { await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, 'super comment') await waitJobs(servers) - const json = await getJSONfeed(servers[1].url, 'video-comments', { version: 3 }) - const jsonObj = JSON.parse(json.text) + const json = await servers[1].feedCommand.getJSON({ feed: 'video-comments', query: { version: 3 } }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(3) } await addAccountToAccountBlocklist(servers[1].url, servers[1].accessToken, remoteHandle) { - const json = await getJSONfeed(servers[1].url, 'video-comments', { version: 4 }) - const jsonObj = JSON.parse(json.text) + const json = await servers[1].feedCommand.getJSON({ feed: 'video-comments', query: { version: 4 } }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(2) } }) @@ -327,31 +327,30 @@ describe('Test syndication feeds', () => { const res = await listUserSubscriptionVideos(servers[0].url, feeduserAccessToken) expect(res.body.total).to.equal(0) - const json = await getJSONfeed(servers[0].url, 'subscriptions', { accountId: feeduserAccountId, token: feeduserFeedToken }) - const jsonObj = JSON.parse(json.text) + const query = { accountId: feeduserAccountId, token: feeduserFeedToken } + const json = await servers[0].feedCommand.getJSON({ feed: 'subscriptions', query }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(0) // no subscription, it should not list the instance's videos but list 0 videos } }) it('Should fail with an invalid token', async function () { - await getJSONfeed(servers[0].url, 'subscriptions', { accountId: feeduserAccountId, token: 'toto' }, HttpStatusCode.FORBIDDEN_403) + const query = { accountId: feeduserAccountId, token: 'toto' } + await servers[0].feedCommand.getJSON({ feed: 'subscriptions', query, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) }) it('Should fail with a token of another user', async function () { - await getJSONfeed( - servers[0].url, - 'subscriptions', - { accountId: feeduserAccountId, token: userFeedToken }, - HttpStatusCode.FORBIDDEN_403 - ) + const query = { accountId: feeduserAccountId, token: userFeedToken } + await servers[0].feedCommand.getJSON({ feed: 'subscriptions', query, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) }) it('Should list no videos for a user with videos but no subscriptions', async function () { const res = await listUserSubscriptionVideos(servers[0].url, userAccessToken) expect(res.body.total).to.equal(0) - const json = await getJSONfeed(servers[0].url, 'subscriptions', { accountId: userAccountId, token: userFeedToken }) - const jsonObj = JSON.parse(json.text) + const query = { accountId: userAccountId, token: userFeedToken } + const json = await servers[0].feedCommand.getJSON({ feed: 'subscriptions', query }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(0) // no subscription, it should not list the instance's videos but list 0 videos }) @@ -366,8 +365,9 @@ describe('Test syndication feeds', () => { expect(res.body.total).to.equal(1) expect(res.body.data[0].name).to.equal('user video') - const json = await getJSONfeed(servers[0].url, 'subscriptions', { accountId: userAccountId, token: userFeedToken, version: 1 }) - const jsonObj = JSON.parse(json.text) + const query = { accountId: userAccountId, token: userFeedToken, version: 1 } + const json = await servers[0].feedCommand.getJSON({ feed: 'subscriptions', query }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(1) // subscribed to self, it should not list the instance's videos but list john's } }) @@ -382,8 +382,9 @@ describe('Test syndication feeds', () => { const res = await listUserSubscriptionVideos(servers[0].url, userAccessToken) expect(res.body.total).to.equal(2, "there should be 2 videos part of the subscription") - const json = await getJSONfeed(servers[0].url, 'subscriptions', { accountId: userAccountId, token: userFeedToken, version: 2 }) - const jsonObj = JSON.parse(json.text) + const query = { accountId: userAccountId, token: userFeedToken, version: 2 } + const json = await servers[0].feedCommand.getJSON({ feed: 'subscriptions', query }) + const jsonObj = JSON.parse(json) expect(jsonObj.items.length).to.be.equal(2) // subscribed to root, it should not list the instance's videos but list root/john's } }) @@ -391,12 +392,8 @@ describe('Test syndication feeds', () => { it('Should renew the token, and so have an invalid old token', async function () { await renewUserScopedTokens(servers[0].url, userAccessToken) - await getJSONfeed( - servers[0].url, - 'subscriptions', - { accountId: userAccountId, token: userFeedToken, version: 3 }, - HttpStatusCode.FORBIDDEN_403 - ) + const query = { accountId: userAccountId, token: userFeedToken, version: 3 } + await servers[0].feedCommand.getJSON({ feed: 'subscriptions', query, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) }) it('Should succeed with the new token', async function () { @@ -404,7 +401,8 @@ describe('Test syndication feeds', () => { const token: ScopedToken = res2.body userFeedToken = token.feedToken - await getJSONfeed(servers[0].url, 'subscriptions', { accountId: userAccountId, token: userFeedToken, version: 4 }) + const query = { accountId: userAccountId, token: userFeedToken, version: 4 } + await servers[0].feedCommand.getJSON({ feed: 'subscriptions', query }) }) }) diff --git a/shared/extra-utils/feeds/feeds.ts b/shared/extra-utils/feeds/feeds.ts index ce0a98c6d..012ce6cfe 100644 --- a/shared/extra-utils/feeds/feeds.ts +++ b/shared/extra-utils/feeds/feeds.ts @@ -1,33 +1,42 @@ -import * as request from 'supertest' + import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' type FeedType = 'videos' | 'video-comments' | 'subscriptions' -function getXMLfeed (url: string, feed: FeedType, format?: string) { - const path = '/feeds/' + feed + '.xml' +export class FeedCommand extends AbstractCommand { - return request(url) - .get(path) - .query((format) ? { format: format } : {}) - .set('Accept', 'application/xml') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /xml/) -} + getXML (options: OverrideCommandOptions & { + feed: FeedType + format?: string + }) { + const { feed, format } = options + const path = '/feeds/' + feed + '.xml' -function getJSONfeed (url: string, feed: FeedType, query: any = {}, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/feeds/' + feed + '.json' + return this.getRequestText({ + ...options, - return request(url) - .get(path) - .query(query) - .set('Accept', 'application/json') - .expect(statusCodeExpected) - .expect('Content-Type', /json/) -} + path, + query: format ? { format } : undefined, + accept: 'application/xml', + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getJSON (options: OverrideCommandOptions & { + feed: FeedType + query?: { [ id: string ]: any } + }) { + const { feed, query } = options + const path = '/feeds/' + feed + '.json' -// --------------------------------------------------------------------------- + return this.getRequestText({ + ...options, -export { - getXMLfeed, - getJSONfeed + path, + query, + accept: 'application/json', + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } } diff --git a/shared/extra-utils/feeds/index.ts b/shared/extra-utils/feeds/index.ts new file mode 100644 index 000000000..4634cb163 --- /dev/null +++ b/shared/extra-utils/feeds/index.ts @@ -0,0 +1 @@ +export * from './feeds' diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts index eb59ca600..8c26a3699 100644 --- a/shared/extra-utils/requests/requests.ts +++ b/shared/extra-utils/requests/requests.ts @@ -182,10 +182,14 @@ function decodeQueryString (path: string) { return decode(path.split('?')[1]) } -function unwrap (test: request.Test): Promise { +function unwrapBody (test: request.Test): Promise { return test.then(res => res.body) } +function unwrapText (test: request.Test): Promise { + return test.then(res => res.text) +} + // --------------------------------------------------------------------------- export { @@ -198,6 +202,7 @@ export { makePutBodyRequest, makeDeleteRequest, makeRawRequest, - unwrap, + unwrapBody, + unwrapText, updateImageRequest } diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index e07926065..b64c9eec6 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -9,6 +9,7 @@ import { VideoChannel } from '../../models/videos' import { BulkCommand } from '../bulk' import { CLICommand } from '../cli' import { CustomPagesCommand } from '../custom-pages' +import { FeedCommand } from '../feeds' import { buildServerDirectory, getFileSize, isGithubCI, root, wait } from '../miscs/miscs' import { makeGetRequest } from '../requests/requests' @@ -67,6 +68,7 @@ interface ServerInfo { bulkCommand?: BulkCommand cliCommand?: CLICommand customPageCommand?: CustomPagesCommand + feedCommand?: FeedCommand } function parallelTests () { @@ -275,6 +277,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.bulkCommand = new BulkCommand(server) server.cliCommand = new CLICommand(server) server.customPageCommand = new CustomPagesCommand(server) + server.feedCommand = new FeedCommand(server) res(server) }) diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index d8eba373d..53c644124 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -1,5 +1,5 @@ import { HttpStatusCode } from '@shared/core-utils' -import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, unwrap } from '../requests/requests' +import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, unwrap, unwrapBody, unwrapText } from '../requests/requests' import { ServerInfo } from '../server/servers' export interface OverrideCommandOptions { @@ -12,6 +12,12 @@ interface CommonCommandOptions extends OverrideCommandOptions { defaultExpectedStatus: number } +interface GetCommandOptions extends CommonCommandOptions { + query?: { [ id: string ]: string } + contentType?: string + accept?: string +} + abstract class AbstractCommand { private expectedStatus: HttpStatusCode @@ -30,8 +36,12 @@ abstract class AbstractCommand { this.expectedStatus = status } - protected getRequestBody (options: CommonCommandOptions) { - return unwrap(makeGetRequest(this.buildCommonRequestOptions(options))) + protected getRequestBody (options: GetCommandOptions) { + return unwrapBody(this.getRequest(options)) + } + + protected getRequestText (options: GetCommandOptions) { + return unwrapText(this.getRequest(options)) } protected putBodyRequest (options: CommonCommandOptions & { @@ -68,6 +78,18 @@ abstract class AbstractCommand { statusCodeExpected: expectedStatus ?? this.expectedStatus ?? defaultExpectedStatus } } + + private getRequest (options: GetCommandOptions) { + const { query, contentType, accept } = options + + return makeGetRequest({ + ...this.buildCommonRequestOptions(options), + + query, + contentType, + accept + }) + } } export {