Merge pull request #429 from mchangrh/redis-test

add redis tests
This commit is contained in:
Ajay Ramachandran
2021-12-20 22:50:21 -05:00
committed by GitHub
10 changed files with 61 additions and 7 deletions

View File

@@ -1,10 +1,10 @@
name: PostgreSQL CI name: PostgreSQL + Redis CI
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
build: build:
name: Run Tests with PostgreSQL name: Run Tests with PostgreSQL and Redis
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View File

@@ -16,6 +16,10 @@
"host": "localhost", "host": "localhost",
"port": 5432 "port": 5432
}, },
"redis": {
"host": "localhost",
"port": 6379
},
"createDatabaseIfNotExist": true, "createDatabaseIfNotExist": true,
"schemaFolder": "./databases", "schemaFolder": "./databases",
"dbSchema": "./databases/_sponsorTimes.db.sql", "dbSchema": "./databases/_sponsorTimes.db.sql",

View File

@@ -6,4 +6,8 @@ services:
- POSTGRES_USER=${PG_USER} - POSTGRES_USER=${PG_USER}
- POSTGRES_PASSWORD=${PG_PASS} - POSTGRES_PASSWORD=${PG_PASS}
ports: ports:
- 5432:5432 - 5432:5432
redis:
image: redis:alpine
ports:
- 6379:6379

View File

@@ -8,6 +8,7 @@
"dev": "nodemon", "dev": "nodemon",
"dev:bash": "nodemon -x 'npm test ; npm start'", "dev:bash": "nodemon -x 'npm test ; npm start'",
"postgres:docker": "docker run --rm -p 5432:5432 -e POSTGRES_USER=ci_db_user -e POSTGRES_PASSWORD=ci_db_pass postgres:alpine", "postgres:docker": "docker run --rm -p 5432:5432 -e POSTGRES_USER=ci_db_user -e POSTGRES_PASSWORD=ci_db_pass postgres:alpine",
"redis:docker": "docker run --rm -p 6379:6379 redis:alpine",
"start": "ts-node src/index.ts", "start": "ts-node src/index.ts",
"tsc": "tsc -p tsconfig.json", "tsc": "tsc -p tsconfig.json",
"lint": "eslint src test", "lint": "eslint src test",

View File

@@ -8,6 +8,7 @@ interface RedisSB {
set(key: string, value: string, callback?: Callback<string | null>): void; set(key: string, value: string, callback?: Callback<string | null>): void;
setAsync?(key: string, value: string): Promise<{err: Error | null, reply: string | null}>; setAsync?(key: string, value: string): Promise<{err: Error | null, reply: string | null}>;
delAsync?(...keys: [string]): Promise<Error | null>; delAsync?(...keys: [string]): Promise<Error | null>;
close?(flush?: boolean): void;
} }
let exportObject: RedisSB = { let exportObject: RedisSB = {
@@ -29,6 +30,7 @@ if (config.redis) {
exportObject.getAsync = (key) => new Promise((resolve) => client.get(key, (err, reply) => resolve({ err, reply }))); exportObject.getAsync = (key) => new Promise((resolve) => client.get(key, (err, reply) => resolve({ err, reply })));
exportObject.setAsync = (key, value) => new Promise((resolve) => client.set(key, value, (err, reply) => resolve({ err, reply }))); exportObject.setAsync = (key, value) => new Promise((resolve) => client.set(key, value, (err, reply) => resolve({ err, reply })));
exportObject.delAsync = (...keys) => new Promise((resolve) => client.del(keys, (err) => resolve(err))); exportObject.delAsync = (...keys) => new Promise((resolve) => client.del(keys, (err) => resolve(err)));
exportObject.close = (flush) => client.end(flush);
client.on("error", function(error) { client.on("error", function(error) {
Logger.error(error); Logger.error(error);

View File

@@ -1,5 +1,5 @@
import { db } from "../../src/databases/databases"; import { db } from "../../src/databases/databases";
import { partialDeepEquals } from "../utils/partialDeepEquals"; import { partialDeepEquals, arrayPartialDeepEquals } from "../utils/partialDeepEquals";
import { getHash } from "../../src/utils/getHash"; import { getHash } from "../../src/utils/getHash";
import { ImportMock, } from "ts-mock-imports"; import { ImportMock, } from "ts-mock-imports";
import * as YouTubeAPIModule from "../../src/utils/youtubeApi"; import * as YouTubeAPIModule from "../../src/utils/youtubeApi";
@@ -434,7 +434,7 @@ describe("getSkipSegmentsByHash", () => {
}] }]
}]; }];
assert.ok(partialDeepEquals(data, expected, false) || partialDeepEquals(data, expected2, false)); assert.ok(arrayPartialDeepEquals(data, expected) || arrayPartialDeepEquals(data, expected2));
assert.strictEqual(data[0].segments.length, 3); assert.strictEqual(data[0].segments.length, 3);
done(); done();
}) })

View File

@@ -3,7 +3,7 @@ import { getHash } from "../../../src/utils/getHash";
import assert from "assert"; import assert from "assert";
import { client } from "../../utils/httpClient"; import { client } from "../../utils/httpClient";
import { AxiosResponse } from "axios"; import { AxiosResponse } from "axios";
import { partialDeepEquals } from "../../utils/partialDeepEquals"; import { partialDeepEquals, arrayPartialDeepEquals } from "../../utils/partialDeepEquals";
const endpoint = "/api/ratings/rate"; const endpoint = "/api/ratings/rate";
const getRating = (hash: string, params?: unknown): Promise<AxiosResponse> => client.get(`${endpoint}/${hash}`, { params }); const getRating = (hash: string, params?: unknown): Promise<AxiosResponse> => client.get(`${endpoint}/${hash}`, { params });
@@ -58,6 +58,9 @@ describe("getRating", () => {
.catch(err => done(err)); .catch(err => done(err));
}); });
/*
This test will fail if tests are already ran with redis.
*/
it("Should be able to bulk fetch", (done) => { it("Should be able to bulk fetch", (done) => {
getBulkRating([videoOnePartialHash, videoTwoPartialHash]) getBulkRating([videoOnePartialHash, videoTwoPartialHash])
.then(res => { .then(res => {
@@ -80,7 +83,7 @@ describe("getRating", () => {
count: 10, count: 10,
hash: videoOneIDHash, hash: videoOneIDHash,
}]; }];
assert.ok(partialDeepEquals(res.data, expected)); assert.ok(arrayPartialDeepEquals(res.data, expected));
done(); done();
}) })
.catch(err => done(err)); .catch(err => done(err));

32
test/cases/redisTest.ts Normal file
View File

@@ -0,0 +1,32 @@
import { config } from "../../src/config";
import redis from "../../src/utils/redis";
import crypto from "crypto";
import assert from "assert";
const genRandom = (bytes=8) => crypto.pseudoRandomBytes(bytes).toString("hex");
const randKey1 = genRandom();
const randValue1 = genRandom();
const randKey2 = genRandom(16);
describe("redis test", function() {
before(async function() {
if (!config.redis) this.skip();
await redis.setAsync(randKey1, randValue1);
});
it("Should get stored value", (done) => {
redis.getAsync(randKey1)
.then(res => {
if (res.err) assert.fail(res.err);
assert.strictEqual(res.reply, randValue1);
done();
});
});
it("Should not be able to get not stored value", (done) => {
redis.getAsync(randKey2)
.then(res => {
if (res.reply || res.err ) assert.fail("Value should not be found")
done();
});
})
});

View File

@@ -9,6 +9,7 @@ import { initDb } from "../src/databases/databases";
import { ImportMock } from "ts-mock-imports"; import { ImportMock } from "ts-mock-imports";
import * as rateLimitMiddlewareModule from "../src/middleware/requestRateLimit"; import * as rateLimitMiddlewareModule from "../src/middleware/requestRateLimit";
import rateLimit from "express-rate-limit"; import rateLimit from "express-rate-limit";
import redis from "../src/utils/redis";
async function init() { async function init() {
ImportMock.mockFunction(rateLimitMiddlewareModule, "rateLimitMiddleware", rateLimit({ ImportMock.mockFunction(rateLimitMiddlewareModule, "rateLimitMiddleware", rateLimit({
@@ -56,6 +57,7 @@ async function init() {
mocha.run((failures) => { mocha.run((failures) => {
mockServer.close(); mockServer.close();
server.close(); server.close();
redis.close(true);
process.exitCode = failures ? 1 : 0; // exit with non-zero status if there were failures process.exitCode = failures ? 1 : 0; // exit with non-zero status if there were failures
}); });
}); });

View File

@@ -22,6 +22,12 @@ export const partialDeepEquals = (actual: Record<string, any>, expected: Record<
return true; return true;
}; };
export const arrayPartialDeepEquals = (actual: Array<any>, expected: Array<any>): boolean => {
for (const value of expected)
if (!actual.some(a => partialDeepEquals(a, value, false))) return false;
return true;
};
export const arrayDeepEquals = (actual: Record<string, any>, expected: Record<string, any>, print = true): boolean => { export const arrayDeepEquals = (actual: Record<string, any>, expected: Record<string, any>, print = true): boolean => {
if (actual.length !== expected.length) return false; if (actual.length !== expected.length) return false;
let flag = true; let flag = true;