mirror of
https://github.com/ajayyy/SponsorBlockServer.git
synced 2025-12-14 15:37:07 +03:00
@@ -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:
|
||||||
4
ci.json
4
ci.json
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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
32
test/cases/redisTest.ts
Normal 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();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
@@ -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
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user