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", () => {
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)", () =>
client.get(endpoint)
.then(res => assert.strictEqual(res.status, 400))
);
it("Should return 400 if no username parameter specified", () =>
client.get(endpoint)
.then(res => assert.strictEqual(res.status, 400))
);
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))
);
it("Should not allow usernames more than 64 characters", () => validateStatus("0".repeat(65), 400));
it("Should not allow usernames less than 3 characters", () => validateStatus("aa", 400));
it("Should return 404 if escaped backslashes present", () => validateStatus("%redos\\\\_", 404));
it("Should return 404 if backslashes present", () => validateStatus(`\\%redos\\_`, 404));
});

View file

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

View file

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

View file

@ -1,3 +1,5 @@
import crypto from "crypto";
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 (?)';
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) => {
for (const user of Object.values(users))
await insertVip(db, user.pubID);

View file

@ -1,7 +1,7 @@
import { IDatabase } from "../../src/databases/IDatabase";
import { Service, VideoIDHash, VideoID } from "../../src/types/segments.model";
import { HashedUserID, UserID } from "../../src/types/user.model";
import { genRandom } from "./getRandom";
import { genRandomValue } from "./getRandom";
import { getHash } from "../../src/utils/getHash";
type insertSegmentParams = {
@ -44,21 +44,21 @@ const defaultSegmentParams: insertSegmentParams = {
};
// 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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
// corrections for parameters
const identifier = `${fnname}-${testcase}`;
const correctedParams = params;
const correctedParams = { ...defaultSegmentParams, ...params };
// generate defaults
const videoID = (params.videoID || `vid-${identifier}`) as VideoID;
const userID = (params.userID || `user-${identifier}`) as UserID;
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.hashedVideoID) correctedParams.hashedVideoID = getHash(videoID);
// convert bool to 0 | 1
correctedParams.locked = Number(params.locked);
correctedParams.hidden = Number(params.hidden);
correctedParams.shadowHidden = Number(params.shadowHidden);
correctedParams.locked = Number(correctedParams.locked);
correctedParams.hidden = Number(correctedParams.hidden);
correctedParams.shadowHidden = Number(correctedParams.shadowHidden);
await db.prepare("run", query, Object.values(correctedParams));
};