lockCategoriesHTTP

- highLoad
- compact getUserID
- add genRandomValue method
This commit is contained in:
Michael C 2023-09-27 23:19:25 -04:00
parent 5e3ec895d8
commit 7364499f11
No known key found for this signature in database
GPG key ID: FFB04FB3B878B7B4
6 changed files with 87 additions and 229 deletions

View file

@ -104,38 +104,17 @@ describe("getUserID", () => {
}); });
describe("getUserID 400/ 404", () => { describe("getUserID 400/ 404", () => {
const validateStatus = (query: string, status: number) =>
getUserName(query)
.then(res => assert.strictEqual(res.status, status));
it("Should be able to get a 400 (No username parameter)", () => it("Should be able to get a 400 (No username parameter)", () =>
client.get(endpoint) client.get(endpoint)
.then(res => assert.strictEqual(res.status, 400)) .then(res => assert.strictEqual(res.status, 400))
); );
it("Should return 400 if no username parameter specified", () => it("Should not allow usernames more than 64 characters", () => validateStatus("0".repeat(65), 400));
client.get(endpoint) it("Should not allow usernames less than 3 characters", () => validateStatus("aa", 400));
.then(res => assert.strictEqual(res.status, 400)) it("Should return 404 if escaped backslashes present", () => validateStatus("%redos\\\\_", 404));
); it("Should return 404 if backslashes present", () => validateStatus(`\\%redos\\_`, 404));
it("Should not allow usernames more than 64 characters", () =>
getUserName("0".repeat(65))
.then(res => assert.strictEqual(res.status, 400))
);
it("Should not allow usernames less than 3 characters", () =>
getUserName("aa")
.then(res => assert.strictEqual(res.status, 400))
);
it("Should return 400 (username longer than 64 chars)", () =>
getUserName(users["public_1"].username+0)
.then(res => assert.strictEqual(res.status, 400))
);
it("Should return 404 if escaped backslashes present", () =>
getUserName("%redos\\\\_")
.then(res => assert.strictEqual(res.status, 404))
);
it("Should return 404 if backslashes present", () =>
getUserName(`\\%redos\\_`)
.then(res => assert.strictEqual(res.status, 404))
);
}); });

View file

@ -13,24 +13,18 @@ describe("High load test", () => {
sinon.restore(); sinon.restore();
}); });
it("Should return 503 on getTopUsers", async () => { it("Should return 503 on getTopUsers", () =>
await client.get("/api/getTopUsers?sortType=0") client.get("/api/getTopUsers?sortType=0")
.then(res => { .then(res => assert.strictEqual(res.status, 503))
assert.strictEqual(res.status, 503); );
});
});
it("Should return 503 on getTopCategoryUsers", async () => { it("Should return 503 on getTopCategoryUsers", () =>
await client.get("/api/getTopCategoryUsers?sortType=0&category=sponsor") client.get("/api/getTopCategoryUsers?sortType=0&category=sponsor")
.then(res => { .then(res => assert.strictEqual(res.status, 503))
assert.strictEqual(res.status, 503); );
});
});
it("Should return 0 on getTotalStats", async () => { it("Should return 0 on getTotalStats", () =>
await client.get("/api/getTotalStats") client.get("/api/getTotalStats")
.then(res => { .then(res => assert.strictEqual(res.status, 200))
assert.strictEqual(res.status, 200); );
});
});
}); });

View file

@ -1,9 +1,11 @@
import assert from "assert"; import assert from "assert";
import { client } from "../utils/httpClient"; import { client } from "../utils/httpClient";
import { getHash } from "../../src/utils/getHash";
import { db } from "../../src/databases/databases"; import { db } from "../../src/databases/databases";
import { UserID } from "../../src/types/user.model"; import { UserID } from "../../src/types/user.model";
import { Category, VideoID } from "../../src/types/segments.model"; import { Category, VideoID } from "../../src/types/segments.model";
import { insertVipUser } from "../utils/queryGen";
import { genUser } from "../utils/genUser";
import { genRandomValue } from "../utils/getRandom";
interface LockCategory { interface LockCategory {
category: Category, category: Category,
@ -11,12 +13,10 @@ interface LockCategory {
videoID: VideoID, videoID: VideoID,
userID: UserID userID: UserID
} }
const lockVIPUser = "lockCategoriesHttpVIPUser";
const lockVIPUserHash = getHash(lockVIPUser);
const endpoint = "/api/lockCategories"; const endpoint = "/api/lockCategories";
const lockUser = genUser("lockCategoriesHttp", "vip");
const checkLockCategories = (videoID: string): Promise<LockCategory[]> => db.prepare("all", 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', [videoID]); const checkLockCategories = (videoID: string): Promise<LockCategory[]> => db.prepare("all", 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', [videoID]);
const goodResponse = (): any => ({ const goodResponse = (): any => ({
videoID: "test-videoid", videoID: "test-videoid",
userID: "not-vip-test-userid", userID: "not-vip-test-userid",
@ -24,229 +24,109 @@ const goodResponse = (): any => ({
actionTypes: ["skip"] actionTypes: ["skip"]
}); });
const errTest = (method = "POST", override: any): Promise<void> => {
const data = { ...goodResponse(), ...override };
return client(endpoint, { method, data })
.then(res => assert.strictEqual(res.status, 400));
};
const statusTest = (method = "POST", data: any, status: number): Promise<void> =>
client(endpoint, { method, data })
.then(res => assert.strictEqual(res.status, status));
describe("POST lockCategories HTTP submitting", () => { describe("POST lockCategories HTTP submitting", () => {
before(async () => { before(async () => {
const insertVipUserQuery = 'INSERT INTO "vipUsers" ("userID") VALUES (?)'; await insertVipUser(db, lockUser);
await db.prepare("run", insertVipUserQuery, [lockVIPUserHash]);
}); });
it("Should update the database version when starting the application", async () => { it("should be able to add poi type category by type skip", () => {
const version = (await db.prepare("get", "SELECT key, value FROM config where key = ?", ["version"])).value; const videoID = genRandomValue("video","lockCategoriesHttp");
assert.ok(version > 1); const json = {
});
it("should be able to add poi type category by type skip", (done) => {
const videoID = "add-record-poi";
client.post(endpoint, {
videoID, videoID,
userID: lockVIPUser, userID: lockUser.privID,
categories: ["poi_highlight"], categories: ["poi_highlight"],
actionTypes: ["skip"] actionTypes: ["skip"]
}) };
.then(res => { return statusTest("POST", json, 200)
assert.strictEqual(res.status, 200); .then(() => checkLockCategories(videoID))
checkLockCategories(videoID) .then(result => {
.then(result => { assert.strictEqual(result.length, 1);
assert.strictEqual(result.length, 1); assert.strictEqual(result[0].category, "poi_highlight");
assert.strictEqual(result[0], "poi_highlight"); });
});
done();
})
.catch(err => done(err));
}); });
it("Should not add lock of invalid type", (done) => { it("Should not add lock of invalid type", () => {
const videoID = "add_invalid_type"; const videoID = genRandomValue("video","lockCategoriesHttp");
client.post(endpoint, { const json = {
videoID, videoID,
userID: lockVIPUser, userID: lockUser.privID,
categories: ["future_unused_invalid_type"], categories: ["future_unused_invalid_type"],
actionTypes: ["skip"] actionTypes: ["skip"]
}) };
.then(res => { return statusTest("POST", json, 200)
assert.strictEqual(res.status, 200); .then(() => checkLockCategories(videoID))
checkLockCategories(videoID) .then(result => assert.strictEqual(result.length, 0));
.then(result => {
assert.strictEqual(result.length, 0);
});
done();
})
.catch(err => done(err));
}); });
}); });
describe("DELETE lockCategories 403/400 tests", () => { describe("DELETE lockCategories 403/400 tests", () => {
it(" Should return 400 for no data", (done) => { it("Should return 400 for no data", () => statusTest("DELETE", {}, 400));
client.delete(endpoint, {}) it("Should return 400 for no data", () => statusTest("POST", {}, 400));
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it("Should return 400 for no categories", (done) => { it("Should return 400 for no categories", () => {
const json: any = { const json: any = {
videoID: "test", videoID: "test",
userID: "test", userID: "test",
categories: [], categories: [],
}; };
client.delete(endpoint, json) return statusTest("DELETE", json, 400);
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
}); });
it("Should return 400 for no userID", (done) => { it("Should return 400 for no userID", () => {
const json: any = { const json: any = {
videoID: "test", videoID: "test",
userID: null, userID: null,
categories: ["sponsor"], categories: ["sponsor"],
}; };
return statusTest("POST", json, 400);
client.post(endpoint, json)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
}); });
it("Should return 400 for no videoID", (done) => { it("Should return 400 for no videoID", () => {
const json: any = { const json: any = {
videoID: null, videoID: null,
userID: "test", userID: "test",
categories: ["sponsor"], categories: ["sponsor"],
}; };
return statusTest("POST", json, 400);
client.post(endpoint, json)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
}); });
it("Should return 400 for invalid category array", (done) => { it("Should return 400 for invalid category array", () => {
const json = { const json = {
videoID: "test", videoID: "test",
userID: "test", userID: "test",
categories: {}, categories: {},
}; };
return statusTest("POST", json, 400);
client.post(endpoint, json)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it("Should return 400 for bad format categories", (done) => {
const json = {
videoID: "test",
userID: "test",
categories: "sponsor",
};
client.post(endpoint, json)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it("Should return 403 if user is not VIP", (done) => {
const json = {
videoID: "test",
userID: "test",
categories: [
"sponsor",
],
};
client.post(endpoint, json)
.then(res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
}); });
}); });
describe("manual DELETE/POST lockCategories 400 tests", () => { describe("manual DELETE/POST lockCategories 400 tests", () => {
it("DELETE Should return 400 for no data", (done) => { it("DELETE Should return 400 for no data", () => statusTest("DELETE", {}, 400));
client.delete(endpoint, { data: {} }) it("POST Should return 400 for no data", () => statusTest("POST", {}, 400));
.then(res => {
assert.strictEqual(res.status, 400); it("DELETE Should return 400 for bad format categories", () => errTest("DELETE", { categories: "sponsor" }));
done(); it("POST Should return 400 for bad format categories", () => errTest("POST", { categories: "sponsor" }));
})
.catch(err => done(err)); it("DELETE Should return 403 if user is not VIP", () => statusTest("DELETE", goodResponse(), 403));
}); it("POST Should return 403 if user is not VIP", () => statusTest("POST", goodResponse(), 403));
it("POST Should return 400 for no data", (done) => {
client.post(endpoint, {})
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it("DELETE Should return 400 for bad format categories", (done) => {
const data = goodResponse();
data.categories = "sponsor";
client.delete(endpoint, { data })
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it("POST Should return 400 for bad format categories", (done) => {
const data = goodResponse();
data.categories = "sponsor";
client.post(endpoint, data)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it("DELETE Should return 403 if user is not VIP", (done) => {
const data = goodResponse();
client.delete(endpoint, { data })
.then(res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
});
it("POST Should return 403 if user is not VIP", (done) => {
const data = goodResponse();
client.post(endpoint, data)
.then(res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
});
}); });
describe("array of DELETE/POST lockCategories 400 tests", () => { describe("array of DELETE/POST lockCategories 400 tests", () => {
for (const key of [ "videoID", "userID", "categories" ]) { for (const key of [ "videoID", "userID", "categories" ]) {
for (const method of ["DELETE", "POST"]) { for (const method of ["DELETE", "POST"]) {
it(`${method} - Should return 400 for invalid ${key}`, (done) => { it(`${method} - Should return 400 for invalid ${key}`, () =>
const data = goodResponse(); errTest(method, { [key]: null })
data[key] = null; );
client(endpoint, { data, method })
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
} }
} }
}); });

View file

@ -1,3 +1,5 @@
import crypto from "crypto"; import crypto from "crypto";
export const genRandom = (bytes=8) => crypto.pseudoRandomBytes(bytes).toString("hex"); export const genRandom = (bytes=8) => crypto.pseudoRandomBytes(bytes).toString("hex");
export const genRandomValue = (prefix: string, identifier: string, bytes=8) => `${prefix}-${identifier}-${genRandom(bytes)}`;

View file

@ -11,6 +11,9 @@ export const insertVip = async (db: IDatabase, userID: HashedUserID) => {
const query = 'INSERT INTO "vipUsers" ("userID") VALUES (?)'; const query = 'INSERT INTO "vipUsers" ("userID") VALUES (?)';
await db.prepare("run", query, [userID]); await db.prepare("run", query, [userID]);
}; };
export const insertVipUser = async (db: IDatabase, user: User) => {
await insertVip(db, user.pubID);
};
export const insertVipBulk = async (db: IDatabase, users: userArray) => { export const insertVipBulk = async (db: IDatabase, users: userArray) => {
for (const user of Object.values(users)) for (const user of Object.values(users))
await insertVip(db, user.pubID); await insertVip(db, user.pubID);

View file

@ -1,7 +1,7 @@
import { IDatabase } from "../../src/databases/IDatabase"; import { IDatabase } from "../../src/databases/IDatabase";
import { Service, VideoIDHash, VideoID } from "../../src/types/segments.model"; import { Service, VideoIDHash, VideoID } from "../../src/types/segments.model";
import { HashedUserID, UserID } from "../../src/types/user.model"; import { HashedUserID, UserID } from "../../src/types/user.model";
import { genRandom } from "./getRandom"; import { genRandomValue } from "./getRandom";
import { getHash } from "../../src/utils/getHash"; import { getHash } from "../../src/utils/getHash";
type insertSegmentParams = { type insertSegmentParams = {
@ -44,21 +44,21 @@ const defaultSegmentParams: insertSegmentParams = {
}; };
// sponsorTimes // sponsorTimes
export const insertSegment = async(db: IDatabase, fnname: string, testcase: string, params: insertSegmentParams = defaultSegmentParams) => { export const insertSegment = async(db: IDatabase, fnname: string, testcase: string, params: insertSegmentParams = {}) => {
const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID", "description") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID", "description") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
// corrections for parameters // corrections for parameters
const identifier = `${fnname}-${testcase}`; const identifier = `${fnname}-${testcase}`;
const correctedParams = params; const correctedParams = { ...defaultSegmentParams, ...params };
// generate defaults // generate defaults
const videoID = (params.videoID || `vid-${identifier}`) as VideoID; const videoID = (params.videoID || `vid-${identifier}`) as VideoID;
const userID = (params.userID || `user-${identifier}`) as UserID; const userID = (params.userID || `user-${identifier}`) as UserID;
if (!params.videoID) correctedParams.videoID = videoID; if (!params.videoID) correctedParams.videoID = videoID;
if (!params.UUID) correctedParams.UUID = `uuid-${identifier}-${genRandom(2)}`; if (!params.UUID) correctedParams.UUID = genRandomValue("uuid", identifier, 2);
if (!params.userID) correctedParams.userID = getHash(userID); if (!params.userID) correctedParams.userID = getHash(userID);
if (!params.hashedVideoID) correctedParams.hashedVideoID = getHash(videoID); if (!params.hashedVideoID) correctedParams.hashedVideoID = getHash(videoID);
// convert bool to 0 | 1 // convert bool to 0 | 1
correctedParams.locked = Number(params.locked); correctedParams.locked = Number(correctedParams.locked);
correctedParams.hidden = Number(params.hidden); correctedParams.hidden = Number(correctedParams.hidden);
correctedParams.shadowHidden = Number(params.shadowHidden); correctedParams.shadowHidden = Number(correctedParams.shadowHidden);
await db.prepare("run", query, Object.values(correctedParams)); await db.prepare("run", query, Object.values(correctedParams));
}; };