change redis for ioredis, add mocks during tests

This commit is contained in:
Djkáťo 2023-10-02 16:27:08 +02:00
parent 2a1293ec7a
commit 2c47290eff
5 changed files with 244 additions and 110 deletions

View file

@ -7,6 +7,3 @@
- `src/APL/index.ts`: added redis-apl export - `src/APL/index.ts`: added redis-apl export
- `src/APL/redis-apl.ts`: created Redis APL - `src/APL/redis-apl.ts`: created Redis APL
- `src/APL/redis-apl.test.ts`: Tests for Redis APL - `src/APL/redis-apl.test.ts`: Tests for Redis APL
### Changed
- npm run lint changed a lot of files, guess it wasn't ran in a while :)

217
package-lock.json generated
View file

@ -10,9 +10,9 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"debug": "4.3.4", "debug": "4.3.4",
"ioredis": "^5.3.2",
"jose": "4.14.4", "jose": "4.14.4",
"raw-body": "2.5.2", "raw-body": "2.5.2",
"redis": "^4.6.10",
"retes": "0.33.0", "retes": "0.33.0",
"uuid": "9.0.0" "uuid": "9.0.0"
}, },
@ -41,6 +41,7 @@
"eslint-plugin-simple-import-sort": "^8.0.0", "eslint-plugin-simple-import-sort": "^8.0.0",
"graphql": "16.8.0", "graphql": "16.8.0",
"husky": "^8.0.1", "husky": "^8.0.1",
"ioredis-mock": "^8.9.0",
"jsdom": "^20.0.3", "jsdom": "^20.0.3",
"lint-staged": "^13.0.3", "lint-staged": "^13.0.3",
"next": "^12.3.0", "next": "^12.3.0",
@ -1162,6 +1163,17 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true "dev": true
}, },
"node_modules/@ioredis/as-callback": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@ioredis/as-callback/-/as-callback-3.0.0.tgz",
"integrity": "sha512-Kqv1rZ3WbgOrS+hgzJ5xG5WQuhvzzSTRYvNeyPMLOAM78MHSnuKI20JeJGbpuAt//LCuP0vsexZcorqW7kWhJg==",
"dev": true
},
"node_modules/@ioredis/commands": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
},
"node_modules/@istanbuljs/schema": { "node_modules/@istanbuljs/schema": {
"version": "0.1.3", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
@ -1534,64 +1546,6 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/@redis/bloom": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz",
"integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/client": {
"version": "1.5.11",
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.11.tgz",
"integrity": "sha512-cV7yHcOAtNQ5x/yQl7Yw1xf53kO0FNDTdDU6bFIMbW6ljB7U7ns0YRM+QIkpoqTAt6zK5k9Fq0QWlUbLcq9AvA==",
"dependencies": {
"cluster-key-slot": "1.1.2",
"generic-pool": "3.9.0",
"yallist": "4.0.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@redis/client/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/@redis/graph": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz",
"integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/json": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.6.tgz",
"integrity": "sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/search": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.5.tgz",
"integrity": "sha512-hPP8w7GfGsbtYEJdn4n7nXa6xt6hVZnnDktKW4ArMaFQ/m/aR7eFvsLQmG/mn1Upq99btPJk+F27IQ2dYpCoUg==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/time-series": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.5.tgz",
"integrity": "sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@swc/helpers": { "node_modules/@swc/helpers": {
"version": "0.4.11", "version": "0.4.11",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz",
@ -1747,6 +1701,16 @@
"@types/ms": "*" "@types/ms": "*"
} }
}, },
"node_modules/@types/ioredis-mock": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/@types/ioredis-mock/-/ioredis-mock-8.2.3.tgz",
"integrity": "sha512-7veA+v2QXjPBvmuYDSyXcfcgCzlpMxa9z51g1+bZXLZ97teCmEs9qYiK9X/h7camGAJJvTiFHiE4mT8CNaqQlA==",
"dev": true,
"peer": true,
"dependencies": {
"ioredis": ">=5"
}
},
"node_modules/@types/is-ci": { "node_modules/@types/is-ci": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/is-ci/-/is-ci-3.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/is-ci/-/is-ci-3.0.1.tgz",
@ -3466,6 +3430,14 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"engines": {
"node": ">=0.10"
}
},
"node_modules/depd": { "node_modules/depd": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@ -4970,6 +4942,32 @@
"reusify": "^1.0.4" "reusify": "^1.0.4"
} }
}, },
"node_modules/fengari": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/fengari/-/fengari-0.1.4.tgz",
"integrity": "sha512-6ujqUuiIYmcgkGz8MGAdERU57EIluGGPSUgGPTsco657EHa+srq0S3/YUl/r9kx1+D+d4rGfYObd+m8K22gB1g==",
"dev": true,
"dependencies": {
"readline-sync": "^1.4.9",
"sprintf-js": "^1.1.1",
"tmp": "^0.0.33"
}
},
"node_modules/fengari-interop": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/fengari-interop/-/fengari-interop-0.1.3.tgz",
"integrity": "sha512-EtZ+oTu3kEwVJnoymFPBVLIbQcCoy9uWCVnMA6h3M/RqHkUBsLYp29+RRHf9rKr6GwjubWREU1O7RretFIXjHw==",
"dev": true,
"peerDependencies": {
"fengari": "^0.1.0"
}
},
"node_modules/fengari/node_modules/sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
"dev": true
},
"node_modules/file-entry-cache": { "node_modules/file-entry-cache": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@ -5164,14 +5162,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/generic-pool": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
"integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==",
"engines": {
"node": ">= 4"
}
},
"node_modules/gensync": { "node_modules/gensync": {
"version": "1.0.0-beta.2", "version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@ -5655,6 +5645,49 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/ioredis": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz",
"integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==",
"dependencies": {
"@ioredis/commands": "^1.1.1",
"cluster-key-slot": "^1.1.0",
"debug": "^4.3.4",
"denque": "^2.1.0",
"lodash.defaults": "^4.2.0",
"lodash.isarguments": "^3.1.0",
"redis-errors": "^1.2.0",
"redis-parser": "^3.0.0",
"standard-as-callback": "^2.1.0"
},
"engines": {
"node": ">=12.22.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/ioredis"
}
},
"node_modules/ioredis-mock": {
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/ioredis-mock/-/ioredis-mock-8.9.0.tgz",
"integrity": "sha512-yIglcCkI1lvhwJVoMsR51fotZVsPsSk07ecTCgRTRlicG0Vq3lke6aAaHklyjmRNRsdYAgswqC2A0bPtQK4LSw==",
"dev": true,
"dependencies": {
"@ioredis/as-callback": "^3.0.0",
"@ioredis/commands": "^1.2.0",
"fengari": "^0.1.4",
"fengari-interop": "^0.1.3",
"semver": "^7.5.4"
},
"engines": {
"node": ">=12.22"
},
"peerDependencies": {
"@types/ioredis-mock": "^8",
"ioredis": "^5"
}
},
"node_modules/is-arguments": { "node_modules/is-arguments": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
@ -6489,6 +6522,16 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
},
"node_modules/lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
},
"node_modules/lodash.merge": { "node_modules/lodash.merge": {
"version": "4.6.2", "version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
@ -7898,6 +7941,15 @@
"node": ">=8.10.0" "node": ">=8.10.0"
} }
}, },
"node_modules/readline-sync": {
"version": "1.4.10",
"resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz",
"integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==",
"dev": true,
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/redent": { "node_modules/redent": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
@ -7911,17 +7963,23 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/redis": { "node_modules/redis-errors": {
"version": "4.6.10", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/redis/-/redis-4.6.10.tgz", "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
"integrity": "sha512-mmbyhuKgDiJ5TWUhiKhBssz+mjsuSI/lSZNPI9QvZOYzWvYGejtb+W3RlDDf8LD6Bdl5/mZeG8O1feUGhXTxEg==", "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
"engines": {
"node": ">=4"
}
},
"node_modules/redis-parser": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
"dependencies": { "dependencies": {
"@redis/bloom": "1.2.0", "redis-errors": "^1.0.0"
"@redis/client": "1.5.11", },
"@redis/graph": "1.1.0", "engines": {
"@redis/json": "1.0.6", "node": ">=4"
"@redis/search": "1.1.5",
"@redis/time-series": "1.0.5"
} }
}, },
"node_modules/reflect.getprototypeof": { "node_modules/reflect.getprototypeof": {
@ -8673,6 +8731,11 @@
"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
"dev": true "dev": true
}, },
"node_modules/standard-as-callback": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
},
"node_modules/statuses": { "node_modules/statuses": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",

View file

@ -25,9 +25,9 @@
}, },
"dependencies": { "dependencies": {
"debug": "4.3.4", "debug": "4.3.4",
"ioredis": "^5.3.2",
"jose": "4.14.4", "jose": "4.14.4",
"raw-body": "2.5.2", "raw-body": "2.5.2",
"redis": "^4.6.10",
"retes": "0.33.0", "retes": "0.33.0",
"uuid": "9.0.0" "uuid": "9.0.0"
}, },
@ -56,6 +56,7 @@
"eslint-plugin-simple-import-sort": "^8.0.0", "eslint-plugin-simple-import-sort": "^8.0.0",
"graphql": "16.8.0", "graphql": "16.8.0",
"husky": "^8.0.1", "husky": "^8.0.1",
"ioredis-mock": "^8.9.0",
"jsdom": "^20.0.3", "jsdom": "^20.0.3",
"lint-staged": "^13.0.3", "lint-staged": "^13.0.3",
"next": "^12.3.0", "next": "^12.3.0",

View file

@ -1,10 +1,11 @@
import { afterEach, describe, expect, it } from "vitest"; import { afterEach, describe, expect, it } from "vitest";
import Redis from "ioredis-mock"
import { AuthData } from "./apl"; import { AuthData } from "./apl";
import { RedisAPL } from "./redis-apl"; import { RedisAPL } from "./redis-apl";
// Obviously, for this test to pass you need to have a docker container running redis :) const appApiBaseUrl = "https://localhost:4321/"
const localRedisServerUrl = new URL("redis://127.0.0.1:6379/1"); const redisClient = new Redis()
const stubAuthData: AuthData = { const stubAuthData: AuthData = {
domain: "example.com", domain: "example.com",
token: "example-token", token: "example-token",
@ -15,21 +16,20 @@ const stubAuthData: AuthData = {
describe("APL", () => { describe("APL", () => {
afterEach(async () => { afterEach(async () => {
const apl = new RedisAPL(localRedisServerUrl, stubAuthData.appId); const apl = new RedisAPL({ client: redisClient, appApiBaseUrl: appApiBaseUrl });
await apl.delete(stubAuthData.saleorApiUrl); await apl.delete(stubAuthData.saleorApiUrl);
}); });
describe("redisAPL", () => { describe("redisAPL", () => {
describe("get", () => { describe("get", () => {
it("Returns auth data for existing api url", async () => { it("Returns auth data for existing api url", async () => {
const apl = new RedisAPL(localRedisServerUrl, stubAuthData.appId); const apl = new RedisAPL({ client: redisClient, appApiBaseUrl: appApiBaseUrl });
await apl.set(stubAuthData); await apl.set(stubAuthData);
expect(await apl.get(stubAuthData.saleorApiUrl)).toStrictEqual(stubAuthData); expect(await apl.get(stubAuthData.saleorApiUrl)).toStrictEqual(stubAuthData);
}); });
it("Returns undefined for unknown api url", async () => { it("Returns undefined for unknown api url", async () => {
const apl = new RedisAPL(localRedisServerUrl, stubAuthData.appId); const apl = new RedisAPL({ client: redisClient, appApiBaseUrl: appApiBaseUrl });
expect(await apl.get("unknown-domain.example.com")).toBeUndefined(); expect(await apl.get("unknown-domain.example.com")).toBeUndefined();
}); });
@ -37,7 +37,7 @@ describe("APL", () => {
describe("set", () => { describe("set", () => {
it("should save to redis and return value afterwards", async () => { it("should save to redis and return value afterwards", async () => {
const apl = new RedisAPL(localRedisServerUrl, stubAuthData.appId); const apl = new RedisAPL({ client: redisClient, appApiBaseUrl: appApiBaseUrl });
await apl.set(stubAuthData); await apl.set(stubAuthData);
expect(await apl.get(stubAuthData.saleorApiUrl)).toStrictEqual(stubAuthData); expect(await apl.get(stubAuthData.saleorApiUrl)).toStrictEqual(stubAuthData);
@ -46,11 +46,48 @@ describe("APL", () => {
describe("delete", () => { describe("delete", () => {
it("Should delete when called with known domain", async () => { it("Should delete when called with known domain", async () => {
const apl = new RedisAPL(localRedisServerUrl, stubAuthData.appId); const apl = new RedisAPL({ client: redisClient, appApiBaseUrl: appApiBaseUrl });
await apl.delete("api.random.sk"); await apl.delete(stubAuthData.saleorApiUrl);
expect(await apl.get(stubAuthData.saleorApiUrl)).toBeUndefined(); expect(await apl.get(stubAuthData.saleorApiUrl)).toBeUndefined();
}); });
it("Should not delete when called with different domain", async () => {
const apl = new RedisAPL({ client: redisClient, appApiBaseUrl: appApiBaseUrl });
const otherAppApiBaseUrl = "https://localhost:4322/"
const apl2 = new RedisAPL({ client: redisClient, appApiBaseUrl: otherAppApiBaseUrl });
const otherStubAuthData: AuthData = {
saleorApiUrl: "https://example.com/graphql",
token: "Another token",
domain: "example.net",
jwks: "{}",
appId: "22"
}
await apl.set(stubAuthData)
await apl2.set(otherStubAuthData)
/* good for debugging if something breaks :)
await redisClient.keys("*", (err, keys) => {
if (err) return console.log(err)
if (keys) {
keys.map(async (key) => {
let val = await redisClient.get(key)
console.log(`${key}:${val}`)
})
}
})
*/
expect(stubAuthData != otherStubAuthData).toBeTruthy()
expect(await apl.get(stubAuthData.saleorApiUrl)).toStrictEqual(stubAuthData);
expect(await apl2.get(otherStubAuthData.saleorApiUrl)).toStrictEqual(otherStubAuthData);
await apl.delete(stubAuthData.saleorApiUrl);
expect(await apl.get(stubAuthData.saleorApiUrl)).toBeUndefined();
expect(await apl2.get(otherStubAuthData.saleorApiUrl)).toStrictEqual(otherStubAuthData);
await apl2.delete(otherStubAuthData.saleorApiUrl);
expect(await apl.get(stubAuthData.saleorApiUrl)).toBeUndefined();
expect(await apl2.get(otherStubAuthData.saleorApiUrl)).toBeUndefined();
});
}); });
}); });
}); });

View file

@ -1,10 +1,18 @@
import { createClient } from "redis"; import Redis from "ioredis";
import { APL, AplConfiguredResult, AplReadyResult, AuthData } from "./apl"; import { APL, AplConfiguredResult, AplReadyResult, AuthData } from "./apl";
import { createAPLDebug } from "./apl-debug"; import { createAPLDebug } from "./apl-debug";
const debug = createAPLDebug("UpstashAPL"); const debug = createAPLDebug("RedisAPL");
export type RedisAPLClientArgs = {
client: Redis,
appApiBaseUrl: string
}
export type RedisAPLUrlArgs = {
redisUrl: URL
appApiBaseUrl: string
}
/** /**
* Redis APL * Redis APL
* @param redisUrl - in format redis[s]://[[username][:password]@][host][:port][/db-number], * @param redisUrl - in format redis[s]://[[username][:password]@][host][:port][/db-number],
@ -13,15 +21,42 @@ const debug = createAPLDebug("UpstashAPL");
*/ */
export class RedisAPL implements APL { export class RedisAPL implements APL {
private client; private client;
private appApiBaseUrl; private appApiBaseUrl;
constructor(redisURL: URL, appApiBaseUrl: string) { constructor(args: RedisAPLClientArgs | RedisAPLUrlArgs) {
if (!redisURL) throw new Error("No redis url defined"); if (!args.appApiBaseUrl) throw new Error("The RedisAPL requires to know the app api url beforehand");
if (!appApiBaseUrl) throw new Error("The RedisAPL requires to know the app ID beforehand"); this.appApiBaseUrl = args.appApiBaseUrl;
this.appApiBaseUrl = appApiBaseUrl;
this.client = createClient({ url: redisURL.toString() }); if (('client' in args) && args.client) {
debug("RedisAPL: createClient.url : %j", redisURL.toString()); this.client = args.client
debug("RedisAPL: created redis client");
}
else if (('redisUrl' in args) && args.redisUrl) {
let redisUrl = args.redisUrl
let port, db;
if (redisUrl.pathname) {
const parsed_port = parseInt(redisUrl.pathname)
db = typeof parsed_port === "number" ? parsed_port : undefined
}
if (redisUrl.port) {
const parsed_port = parseInt(redisUrl.port)
port = typeof parsed_port === "number" ? parsed_port : undefined
}
this.client = new Redis({
port: port,
host: redisUrl.host,
username: redisUrl.username,
password: redisUrl.password,
db: db,
lazyConnect: true
});
debug("RedisAPL: created redis client");
}
else {
throw new Error("RedisAPL: No redis url or client defined")
}
} }
private prepareKey(saleorApiUrl: string) { private prepareKey(saleorApiUrl: string) {
@ -29,34 +64,31 @@ export class RedisAPL implements APL {
} }
async get(saleorApiUrl: string): Promise<AuthData | undefined> { async get(saleorApiUrl: string): Promise<AuthData | undefined> {
await this.client.connect();
try { try {
const res = await this.client.get(this.prepareKey(saleorApiUrl)); const res = await this.client.get(this.prepareKey(saleorApiUrl));
debug("RedisAPL: get - received: %j", res); debug("RedisAPL: get - received: %j", res);
if (res) { if (res) {
await this.client.disconnect(); await this.client.quit();
return JSON.parse(res) as AuthData; return JSON.parse(res) as AuthData;
} }
await this.client.disconnect(); await this.client.quit();
return undefined; return undefined;
} catch (e) { } catch (e) {
await this.client.disconnect(); await this.client.quit();
return undefined; return undefined;
} }
} }
async set(authData: AuthData): Promise<void> { async set(authData: AuthData): Promise<void> {
await this.client.connect();
await this.client.set(this.prepareKey(authData.saleorApiUrl), JSON.stringify(authData)); await this.client.set(this.prepareKey(authData.saleorApiUrl), JSON.stringify(authData));
debug("RedisAPL: set - set sucessfully: %j", authData); debug("RedisAPL: set - set sucessfully: %j", authData);
await this.client.disconnect(); await this.client.quit();
} }
async delete(saleorApiUrl: string): Promise<void> { async delete(saleorApiUrl: string): Promise<void> {
await this.client.connect(); const val = await this.client.getdel(this.prepareKey(saleorApiUrl));
const val = await this.client.getDel(this.prepareKey(saleorApiUrl));
debug("RedisAPL: del - deleted successfuly: %j", val); debug("RedisAPL: del - deleted successfuly: %j", val);
await this.client.disconnect(); await this.client.quit();
} }
async getAll(): Promise<AuthData[]> { async getAll(): Promise<AuthData[]> {
@ -64,10 +96,14 @@ export class RedisAPL implements APL {
} }
async isReady(): Promise<AplReadyResult> { async isReady(): Promise<AplReadyResult> {
return { ready: this.client.isReady } as AplReadyResult; const ready = await this.client.info() ? true : false
await this.client.quit();
return { ready: ready } as AplReadyResult;
} }
async isConfigured(): Promise<AplConfiguredResult> { async isConfigured(): Promise<AplConfiguredResult> {
return { configured: this.client.isReady } as AplConfiguredResult; const ready = await this.client.info() ? true : false
await this.client.quit();
return { configured: ready } as AplConfiguredResult;
} }
} }