chore: Fix Redis mock not used consistently in tests (#9716)

This commit is contained in:
Tom Moor
2025-07-23 09:38:24 -04:00
committed by GitHub
parent b4836cd922
commit cf2f13193f
7 changed files with 77 additions and 47 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ build:
docker compose build --pull outline
test:
docker compose up -d redis postgres
docker compose up -d postgres
NODE_ENV=test yarn sequelize db:drop
NODE_ENV=test yarn sequelize db:create
NODE_ENV=test yarn sequelize db:migrate
+3 -3
View File
@@ -24,8 +24,8 @@ import { checkUpdates } from "./utils/updates";
import onerror from "./onerror";
import ShutdownHelper, { ShutdownOrder } from "./utils/ShutdownHelper";
import { checkConnection, sequelize } from "./storage/database";
import RedisAdapter from "./storage/redis";
import Metrics from "./logging/Metrics";
import Redis from "@server/storage/redis";
import Metrics from "@server/logging/Metrics";
import { PluginManager } from "./utils/PluginManager";
// The number of processes to run, defaults to the number of CPU's available
@@ -149,7 +149,7 @@ async function start(_id: number, disconnect: () => void) {
}
try {
await RedisAdapter.defaultClient.ping();
await Redis.defaultClient.ping();
} catch (err) {
Logger.error("Redis ping failed", err);
ctx.status = 500;
+53 -22
View File
@@ -1,29 +1,60 @@
import { createQueue } from "@server/queues/queue";
export const globalEventQueue = createQueue("globalEvents", {
attempts: 5,
backoff: {
type: "exponential",
delay: 1000,
let _globalEventQueue: ReturnType<typeof createQueue> | undefined;
let _processorEventQueue: ReturnType<typeof createQueue> | undefined;
let _websocketQueue: ReturnType<typeof createQueue> | undefined;
let _taskQueue: ReturnType<typeof createQueue> | undefined;
export const globalEventQueue = new Proxy(
{} as ReturnType<typeof createQueue>,
{
get(_target, prop) {
_globalEventQueue ||= createQueue("globalEvents", {
attempts: 5,
backoff: {
type: "exponential",
delay: 1000,
},
});
return _globalEventQueue[prop as keyof typeof _globalEventQueue];
},
}
);
export const processorEventQueue = new Proxy(
{} as ReturnType<typeof createQueue>,
{
get(_target, prop) {
_processorEventQueue ||= createQueue("processorEvents", {
attempts: 5,
backoff: {
type: "exponential",
delay: 10 * 1000,
},
});
return _processorEventQueue[prop as keyof typeof _processorEventQueue];
},
}
);
export const websocketQueue = new Proxy({} as ReturnType<typeof createQueue>, {
get(_target, prop) {
_websocketQueue ||= createQueue("websockets", {
timeout: 10 * 1000,
});
return _websocketQueue[prop as keyof typeof _websocketQueue];
},
});
export const processorEventQueue = createQueue("processorEvents", {
attempts: 5,
backoff: {
type: "exponential",
delay: 10 * 1000,
},
});
export const websocketQueue = createQueue("websockets", {
timeout: 10 * 1000,
});
export const taskQueue = createQueue("tasks", {
attempts: 5,
backoff: {
type: "exponential",
delay: 10 * 1000,
export const taskQueue = new Proxy({} as ReturnType<typeof createQueue>, {
get(_target, prop) {
_taskQueue ||= createQueue("tasks", {
attempts: 5,
backoff: {
type: "exponential",
delay: 10 * 1000,
},
});
return _taskQueue[prop as keyof typeof _taskQueue];
},
});
+1 -1
View File
@@ -4,7 +4,7 @@ import snakeCase from "lodash/snakeCase";
import { Second } from "@shared/utils/time";
import env from "@server/env";
import Metrics from "@server/logging/Metrics";
import Redis from "@server/storage/redis";
import Redis from "../storage/redis";
import ShutdownHelper, { ShutdownOrder } from "@server/utils/ShutdownHelper";
export function createQueue(
-10
View File
@@ -1,20 +1,14 @@
import "reflect-metadata";
import sharedEnv from "@shared/env";
import env from "@server/env";
import Redis from "@server/storage/redis";
require("@server/storage/database");
jest.mock("bull");
// Enable mocks for Redis-related modules
jest.mock("@server/storage/redis");
jest.mock("@server/utils/MutexLock");
jest.mock("@server/utils/CacheHelper");
// This is needed for the relative manual mock to be picked up
jest.mock("../queues");
// We never want to make real S3 requests in test environment
jest.mock("@aws-sdk/client-s3", () => ({
S3Client: jest.fn(() => ({
@@ -39,10 +33,6 @@ jest.mock("@aws-sdk/s3-request-presigner", () => ({
getSignedUrl: jest.fn(),
}));
afterAll(() => {
Redis.defaultClient.disconnect();
});
beforeEach(() => {
env.URL = sharedEnv.URL = "https://app.outline.dev";
});
+14 -7
View File
@@ -20,13 +20,20 @@ export default class RateLimiter {
duration: env.RATE_LIMITER_DURATION_WINDOW,
});
static readonly defaultRateLimiter = new RateLimiterRedis({
storeClient: Redis.defaultClient,
points: env.RATE_LIMITER_REQUESTS,
duration: env.RATE_LIMITER_DURATION_WINDOW,
keyPrefix: this.RATE_LIMITER_REDIS_KEY_PREFIX,
insuranceLimiter: this.insuranceRateLimiter,
});
private static _defaultRateLimiter: RateLimiterRedis | undefined;
static get defaultRateLimiter(): RateLimiterRedis {
if (!this._defaultRateLimiter) {
this._defaultRateLimiter = new RateLimiterRedis({
storeClient: Redis.defaultClient,
points: env.RATE_LIMITER_REQUESTS,
duration: env.RATE_LIMITER_DURATION_WINDOW,
keyPrefix: this.RATE_LIMITER_REDIS_KEY_PREFIX,
insuranceLimiter: this.insuranceRateLimiter,
});
}
return this._defaultRateLimiter;
}
static getRateLimiter(path: string): RateLimiterRedis {
return this.rateLimiterMap.get(path) || this.defaultRateLimiter;
+5 -3
View File
@@ -1,6 +1,6 @@
import { randomInt } from "crypto";
import { Minute } from "@shared/utils/time";
import RedisAdapter from "@server/storage/redis";
import Redis from "@server/storage/redis";
/**
* This class manages verification codes for email authentication.
@@ -8,9 +8,11 @@ import RedisAdapter from "@server/storage/redis";
*/
export class VerificationCode {
/**
* Redis client instance
* Redis client instance (lazy initialized)
*/
private static redis = RedisAdapter.defaultClient;
private static get redis() {
return Redis.defaultClient;
}
/**
* TTL for verification codes in milliseconds (10 minutes)