diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index 325eac3335..eab8cd4c45 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -128,6 +128,7 @@ const environment = { PLUGIN_BUCKET_NAME: process.env.PLUGIN_BUCKET_NAME || DefaultBucketName.PLUGINS, USE_COUCH: process.env.USE_COUCH || true, + MOCK_REDIS: process.env.MOCK_REDIS, DEFAULT_LICENSE: process.env.DEFAULT_LICENSE, SERVICE: process.env.SERVICE || "budibase", LOG_LEVEL: process.env.LOG_LEVEL || "info", diff --git a/packages/backend-core/src/redis/redis.ts b/packages/backend-core/src/redis/redis.ts index 48057dec0b..636544897d 100644 --- a/packages/backend-core/src/redis/redis.ts +++ b/packages/backend-core/src/redis/redis.ts @@ -1,6 +1,7 @@ import env from "../environment" -// ioredis mock is all in memory import Redis from "ioredis" +// ioredis mock is all in memory +const MockRedis = require("ioredis-mock") import { addDbPrefix, removeDbPrefix, @@ -18,9 +19,14 @@ const DEFAULT_SELECT_DB = SelectableDatabase.DEFAULT // for testing just generate the client once let CLOSED = false let CLIENTS: { [key: number]: any } = {} - +0 let CONNECTED = false +// mock redis always connected +if (env.MOCK_REDIS) { + CONNECTED = true +} + function pickClient(selectDb: number): any { return CLIENTS[selectDb] } @@ -50,6 +56,7 @@ function connectionError( * will return the ioredis client which will be ready to use. */ function init(selectDb = DEFAULT_SELECT_DB) { + const RedisCore = env.MOCK_REDIS ? MockRedis : Redis let timeout: NodeJS.Timeout CLOSED = false let client = pickClient(selectDb) @@ -57,6 +64,10 @@ function init(selectDb = DEFAULT_SELECT_DB) { if (client && CONNECTED) { return } + // testing uses a single in memory client + if (env.MOCK_REDIS) { + CLIENTS[selectDb] = new RedisCore(getRedisOptions()) + } // start the timer - only allowed 5 seconds to connect timeout = setTimeout(() => { if (!CONNECTED) { @@ -75,11 +86,11 @@ function init(selectDb = DEFAULT_SELECT_DB) { const { redisProtocolUrl, opts, host, port } = getRedisOptions() if (CLUSTERED) { - client = new Redis.Cluster([{ host, port }], opts) + client = new RedisCore.Cluster([{ host, port }], opts) } else if (redisProtocolUrl) { - client = new Redis(redisProtocolUrl) + client = new RedisCore(redisProtocolUrl) } else { - client = new Redis(opts) + client = new RedisCore(opts) } // attach handlers client.on("end", (err: Error) => { diff --git a/packages/server/package.json b/packages/server/package.json index 472d221aa9..dc8401ea53 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -122,8 +122,8 @@ "validate.js": "0.13.1", "vm2": "3.9.17", "worker-farm": "1.7.0", - "yargs": "13.2.4", - "xml2js": "0.5.0" + "xml2js": "0.5.0", + "yargs": "13.2.4" }, "devDependencies": { "@babel/core": "7.17.4", @@ -175,7 +175,8 @@ "ts-node": "10.8.1", "tsconfig-paths": "4.0.0", "typescript": "4.7.3", - "update-dotenv": "1.1.1" + "update-dotenv": "1.1.1", + "ioredis-mock": "^8.7.0" }, "optionalDependencies": { "oracledb": "5.3.0" diff --git a/packages/server/src/api/routes/tests/view.spec.js b/packages/server/src/api/routes/tests/view.spec.js index 522987ab29..df07ffa4af 100644 --- a/packages/server/src/api/routes/tests/view.spec.js +++ b/packages/server/src/api/routes/tests/view.spec.js @@ -114,8 +114,8 @@ describe("/views", () => { expect(res.body.tableId).toBe(table._id) const updatedTable = await config.getTable(table._id) - expect(updatedTable.views).toEqual({ - TestView: { + const expectedObj = expect.objectContaining({ + TestView: expect.objectContaining({ field: "Price", calculation: "stats", tableId: table._id, @@ -143,8 +143,9 @@ describe("/views", () => { type: "string", }, }, - }, + }), }) + expect(updatedTable.views).toEqual(expectedObj) }) }) diff --git a/packages/server/src/utilities/redis.ts b/packages/server/src/utilities/redis.ts index 369c8b2e76..d833ed2c10 100644 --- a/packages/server/src/utilities/redis.ts +++ b/packages/server/src/utilities/redis.ts @@ -25,7 +25,9 @@ export async function init() { // Duplicate the socket client for pub/sub socketClient = await redis.clients.getSocketClient() - socketSubClient = socketClient.getClient().duplicate() + if (!env.isTest()) { + socketSubClient = socketClient.getClient().duplicate() + } } export async function shutdown() { diff --git a/packages/server/src/websockets/index.ts b/packages/server/src/websockets/index.ts index 9503041b15..bb530b559e 100644 --- a/packages/server/src/websockets/index.ts +++ b/packages/server/src/websockets/index.ts @@ -10,9 +10,12 @@ let gridSocket: GridSocket | undefined let builderSocket: BuilderSocket | undefined export const initialise = (app: Koa, server: http.Server) => { - clientAppSocket = new ClientAppSocket(app, server) - gridSocket = new GridSocket(app, server) - builderSocket = new BuilderSocket(app, server) + // have to remove these for testing until ioredis-mock can be fully removed + if (!env.isTest()) { + clientAppSocket = new ClientAppSocket(app, server) + gridSocket = new GridSocket(app, server) + builderSocket = new BuilderSocket(app, server) + } } export { clientAppSocket, gridSocket, builderSocket } diff --git a/yarn.lock b/yarn.lock index 51fb4bb034..05bbe68476 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2591,6 +2591,16 @@ resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== +"@ioredis/as-callback@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@ioredis/as-callback/-/as-callback-3.0.0.tgz#b96c9b05e6701e85ec6a5e62fa254071b0aec97f" + integrity sha512-Kqv1rZ3WbgOrS+hgzJ5xG5WQuhvzzSTRYvNeyPMLOAM78MHSnuKI20JeJGbpuAt//LCuP0vsexZcorqW7kWhJg== + +"@ioredis/commands@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" + integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== + "@isaacs/string-locale-compare@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz#291c227e93fd407a96ecd59879a35809120e432b" @@ -11956,7 +11966,7 @@ fecha@^4.2.0: resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== -fengari-interop@^0.1.2: +fengari-interop@^0.1.2, fengari-interop@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/fengari-interop/-/fengari-interop-0.1.3.tgz#3ad37a90e7430b69b365441e9fc0ba168942a146" integrity sha512-EtZ+oTu3kEwVJnoymFPBVLIbQcCoy9uWCVnMA6h3M/RqHkUBsLYp29+RRHf9rKr6GwjubWREU1O7RretFIXjHw== @@ -14003,6 +14013,17 @@ ioredis-mock@5.8.0: lodash "^4.17.21" standard-as-callback "^2.1.0" +ioredis-mock@^8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/ioredis-mock/-/ioredis-mock-8.7.0.tgz#9877a85e0d233e1b49123d1c6e320df01e9a1d36" + integrity sha512-BJcSjkR3sIMKbH93fpFzwlWi/jl1kd5I3vLvGQxnJ/W/6bD2ksrxnyQN186ljAp3Foz4p1ivViDE3rZeKEAluA== + dependencies: + "@ioredis/as-callback" "^3.0.0" + "@ioredis/commands" "^1.2.0" + fengari "^0.1.4" + fengari-interop "^0.1.3" + semver "^7.3.8" + ioredis@4.28.0: version "4.28.0" resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.0.tgz#5a2be3f37ff2075e2332f280eaeb02ab4d9ff0d3"