From ed14d1ebd7c8d9428ac58b3a6280e3df6686aec1 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 5 Jun 2023 10:05:49 +0200 Subject: [PATCH] Invalidate cache feed even after server restart --- server/middlewares/cache/shared/api-cache.ts | 6 +- server/tests/feeds/feeds.ts | 110 +++++++++++++++---- 2 files changed, 93 insertions(+), 23 deletions(-) diff --git a/server/middlewares/cache/shared/api-cache.ts b/server/middlewares/cache/shared/api-cache.ts index c6197b972..b50b7dce4 100644 --- a/server/middlewares/cache/shared/api-cache.ts +++ b/server/middlewares/cache/shared/api-cache.ts @@ -35,7 +35,11 @@ export class ApiCache { // Cache keys per group private groups: { [groupIndex: string]: string[] } = {} + private readonly seed: number + constructor (options: APICacheOptions) { + this.seed = new Date().getTime() + this.options = { headerBlacklist: [], excludeStatus: [], @@ -88,7 +92,7 @@ export class ApiCache { } private getCacheKey (req: express.Request) { - return Redis.Instance.getPrefix() + 'api-cache-' + req.originalUrl + return Redis.Instance.getPrefix() + 'api-cache-' + this.seed + '-' + req.originalUrl } private shouldCacheResponse (response: express.Response) { diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts index 286c03596..8433c873e 100644 --- a/server/tests/feeds/feeds.ts +++ b/server/tests/feeds/feeds.ts @@ -14,6 +14,7 @@ import { PluginsCommand, setAccessTokensToServers, setDefaultChannelAvatar, + setDefaultVideoChannel, stopFfmpeg, waitJobs } from '@shared/server-commands' @@ -53,6 +54,7 @@ describe('Test syndication feeds', () => { await setAccessTokensToServers([ ...servers, serverHLSOnly ]) await setDefaultChannelAvatar(servers[0]) + await setDefaultVideoChannel(servers) await doubleFollow(servers[0], servers[1]) await servers[0].config.enableLive({ allowReplay: false, transcoding: false }) @@ -137,28 +139,6 @@ describe('Test syndication feeds', () => { }) }) - it('Should serve the endpoint as a cached request', async function () { - const res = await makeGetRequest({ - url: servers[0].url, - path: '/feeds/videos.xml', - accept: 'application/xml', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.headers['x-api-cache-cached']).to.equal('true') - }) - - it('Should not serve the endpoint as a cached request', async function () { - const res = await makeGetRequest({ - url: servers[0].url, - path: '/feeds/videos.xml?v=186', - accept: 'application/xml', - expectedStatus: HttpStatusCode.OK_200 - }) - - expect(res.headers['x-api-cache-cached']).to.not.exist - }) - it('Should refuse to serve the endpoint without accept header', async function () { await makeGetRequest({ url: servers[0].url, path: '/feeds/videos.xml', expectedStatus: HttpStatusCode.NOT_ACCEPTABLE_406 }) }) @@ -614,6 +594,92 @@ describe('Test syndication feeds', () => { }) + describe('Cache', function () { + const uuids: string[] = [] + + function doPodcastRequest () { + return makeGetRequest({ + url: servers[0].url, + path: '/feeds/podcast/videos.xml', + query: { videoChannelId: servers[0].store.channel.id }, + accept: 'application/xml', + expectedStatus: HttpStatusCode.OK_200 + }) + } + + function doVideosRequest (query: { [id: string]: string } = {}) { + return makeGetRequest({ + url: servers[0].url, + path: '/feeds/videos.xml', + query, + accept: 'application/xml', + expectedStatus: HttpStatusCode.OK_200 + }) + } + + before(async function () { + { + const { uuid } = await servers[0].videos.quickUpload({ name: 'cache 1' }) + uuids.push(uuid) + } + + { + const { uuid } = await servers[0].videos.quickUpload({ name: 'cache 2' }) + uuids.push(uuid) + } + }) + + it('Should serve the videos endpoint as a cached request', async function () { + await doVideosRequest() + + const res = await doVideosRequest() + + expect(res.headers['x-api-cache-cached']).to.equal('true') + }) + + it('Should not serve the videos endpoint as a cached request', async function () { + const res = await doVideosRequest({ v: '186' }) + + expect(res.headers['x-api-cache-cached']).to.not.exist + }) + + it('Should invalidate the podcast feed cache after video deletion', async function () { + await doPodcastRequest() + + { + const res = await doPodcastRequest() + expect(res.headers['x-api-cache-cached']).to.exist + } + + await servers[0].videos.remove({ id: uuids[0] }) + + { + const res = await doPodcastRequest() + expect(res.headers['x-api-cache-cached']).to.not.exist + } + }) + + it('Should invalidate the podcast feed cache after video deletion, even after server restart', async function () { + this.timeout(120000) + + await doPodcastRequest() + + { + const res = await doPodcastRequest() + expect(res.headers['x-api-cache-cached']).to.exist + } + + await servers[0].kill() + await servers[0].run() + + await servers[0].videos.remove({ id: uuids[1] }) + + const res = await doPodcastRequest() + expect(res.headers['x-api-cache-cached']).to.not.exist + }) + + }) + after(async function () { await servers[0].plugins.uninstall({ npmName: 'peertube-plugin-test-podcast-custom-tags' })