Merge pull request #561 from mchangrh/test-helpers

long overdue test helpers (partial)
This commit is contained in:
Ajay Ramachandran
2023-10-15 02:18:31 -04:00
committed by GitHub
25 changed files with 1282 additions and 1606 deletions

View File

@@ -1,14 +1,14 @@
import { getHash } from "./getHash"; import { getHash } from "./getHash";
import { HashedValue } from "../types/hash.model"; import { HashedValue } from "../types/hash.model";
import { ActionType, VideoID, Service, Category } from "../types/segments.model"; import { ActionType, VideoID, Service, Category } from "../types/segments.model";
import { UserID } from "../types/user.model"; import { HashedUserID } from "../types/user.model";
export function getSubmissionUUID( export function getSubmissionUUID(
videoID: VideoID, videoID: VideoID,
category: Category, category: Category,
actionType: ActionType, actionType: ActionType,
description: string, description: string,
userID: UserID, userID: HashedUserID,
startTime: number, startTime: number,
endTime: number, endTime: number,
service: Service service: Service

22
test/case_boilerplate.txt Normal file
View File

@@ -0,0 +1,22 @@
import { db } from "../../src/databases/databases";
import assert from "assert";
import { client } from "../utils/httpClient";
import { genUsers, User } from "../utils/genUser";
import { insertSegment, insertVip } from "../utils/queryGen";
const endpoint = "/api/endpoint";
const postTestEndpoint = () => client({
method: "POST",
url: endpoint,
data: {
}
});
const cases = [
"firstCase",
"secondCase",
"thirdCase"
];
const users = genUsers("endpoint", cases);
const vipUser = genUser("endpoint", "vip");

View File

@@ -1,68 +1,57 @@
import assert from "assert"; import assert from "assert";
import { db } from "../../src/databases/databases"; import { db } from "../../src/databases/databases";
import { Feature, HashedUserID } from "../../src/types/user.model"; import { Feature } from "../../src/types/user.model";
import { hasFeature } from "../../src/utils/features"; import { hasFeature } from "../../src/utils/features";
import { getHash } from "../../src/utils/getHash";
import { client } from "../utils/httpClient"; import { client } from "../utils/httpClient";
import { grantFeature, insertVip } from "../utils/queryGen";
import { User, genUser, genUsers } from "../utils/genUser";
const endpoint = "/api/feature"; const endpoint = "/api/feature";
const postAddFeatures = (userID: string, adminUserID: string, feature: Feature, enabled: string) => client({ const postAddFeatures = (userID: string, adminUserID: string, feature: Feature, enabled: boolean) => client({
method: "POST", method: "POST",
url: endpoint, url: endpoint,
data: { data: {
userID, userID,
feature, feature,
enabled, enabled: String(enabled),
adminUserID adminUserID
} }
}); });
const privateVipUserID = "VIPUser-addFeatures"; const cases = [
const vipUserID = getHash(privateVipUserID); "grant",
"remove",
"update"
];
const users = genUsers("addFeatures", cases);
const vipUser = genUser("addFeatures", "vip");
const hashedUserID1 = "user1-addFeatures" as HashedUserID; const testedFeature = Feature.ChapterSubmitter;
const hashedUserID2 = "user2-addFeatures" as HashedUserID; const validFeatures = [testedFeature];
const hashedUserID3 = "user3-addFeatures" as HashedUserID;
const validFeatures = [Feature.ChapterSubmitter]; const updateValidateFeature = (user: User, feature: Feature, grant: boolean, issuer: User): Promise<void> =>
postAddFeatures(user.pubID, issuer.privID, feature, grant)
.then(res => assert.strictEqual(res.status, 200)) // ensure request was successful
.then(() => hasFeature(user.pubID, feature))
.then(result => assert.strictEqual(result, grant)); // ensure user has new feature
describe("addFeatures", () => { describe("addFeatures", () => {
before(() => { before(async () => {
const userFeatureQuery = `INSERT INTO "userFeatures" ("userID", "feature", "issuerUserID", "timeSubmitted") VALUES(?, ?, ?, ?)`; await insertVip(db, vipUser.pubID);
await grantFeature(db, users["remove"].pubID, testedFeature, vipUser.pubID);
return Promise.all([ await grantFeature(db, users["update"].pubID, testedFeature, vipUser.pubID);
db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES (?)`, [vipUserID]),
db.prepare("run", userFeatureQuery, [hashedUserID2, Feature.ChapterSubmitter, "some-user", 0]),
db.prepare("run", userFeatureQuery, [hashedUserID3, Feature.ChapterSubmitter, "some-user", 0])
]);
}); });
it("can add features", async () => { it("can add features", (done) => {
for (const feature of validFeatures) { for (const feature of validFeatures) {
const result = await postAddFeatures(hashedUserID1, privateVipUserID, feature, "true"); updateValidateFeature(users["grant"], feature, true, vipUser)
assert.strictEqual(result.status, 200); .catch(err => done(err));
assert.strictEqual(await hasFeature(hashedUserID1, feature), true);
} }
done();
}); });
it("can remove features", async () => { it("can remove features", () => updateValidateFeature(users["remove"], testedFeature, false, vipUser));
const feature = Feature.ChapterSubmitter;
const result = await postAddFeatures(hashedUserID2, privateVipUserID, feature, "false"); it("can update features", () => updateValidateFeature(users["update"], testedFeature, true, vipUser));
assert.strictEqual(result.status, 200);
assert.strictEqual(await hasFeature(hashedUserID2, feature), false);
});
it("can update features", async () => {
const feature = Feature.ChapterSubmitter;
const result = await postAddFeatures(hashedUserID3, privateVipUserID, feature, "true");
assert.strictEqual(result.status, 200);
assert.strictEqual(await hasFeature(hashedUserID3, feature), true);
});
}); });

View File

@@ -1,19 +1,19 @@
import { getHash } from "../../src/utils/getHash";
import { HashedUserID } from "../../src/types/user.model"; import { HashedUserID } from "../../src/types/user.model";
import { client } from "../utils/httpClient"; import { client } from "../utils/httpClient";
import { db } from "../../src/databases/databases"; import { db } from "../../src/databases/databases";
import assert from "assert"; import assert from "assert";
import { genAnonUser, genUsers } from "../utils/genUser";
// helpers // helpers
const checkUserVIP = (publicID: string) => db.prepare("get", `SELECT "userID" FROM "vipUsers" WHERE "userID" = ?`, [publicID]); const checkUserVIP = (publicID: string) => db.prepare("get", `SELECT "userID" FROM "vipUsers" WHERE "userID" = ?`, [publicID]);
const cases = [
"vip-1",
];
const users = genUsers("endpoint", cases);
// hardcoded into test code
const adminPrivateUserID = "testUserId"; const adminPrivateUserID = "testUserId";
const permVIP1 = "addVIP_permaVIPOne";
const publicPermVIP1 = getHash(permVIP1) as HashedUserID;
const permVIP2 = "addVIP_permaVIPTwo";
const publicPermVIP2 = getHash(permVIP2) as HashedUserID;
const permVIP3 = "addVIP_permaVIPThree";
const publicPermVIP3 = getHash(permVIP3) as HashedUserID;
const endpoint = "/api/addUserAsVIP"; const endpoint = "/api/addUserAsVIP";
const addUserAsVIP = (userID: string, enabled: boolean, adminUserID = adminPrivateUserID) => client({ const addUserAsVIP = (userID: string, enabled: boolean, adminUserID = adminPrivateUserID) => client({
@@ -26,116 +26,68 @@ const addUserAsVIP = (userID: string, enabled: boolean, adminUserID = adminPriva
} }
}); });
const testVIPUpdate = (target: HashedUserID, enabled: boolean, adminID: string = adminPrivateUserID) =>
addUserAsVIP(target, enabled, adminID)
.then(res => assert.strictEqual(res.status, 200))
.then(() => checkUserVIP(target))
.then(row => assert.ok(Boolean(row) == enabled));
const statusTest = (status: number, data: Record<string, any>) =>
client({
method: "POST",
url: endpoint,
params: data
}).then(res => assert.strictEqual(res.status, status));
describe("addVIP test", function() { describe("addVIP test", function() {
it("User should not already be VIP", (done) => { it("User should not already be VIP", () =>
checkUserVIP(publicPermVIP1) checkUserVIP(users["vip-1"].pubID)
.then(result => { .then(result => assert.ok(!result))
assert.ok(!result); );
done(); it("Should be able to add user as VIP", () =>
}) testVIPUpdate(users["vip-1"].pubID, true)
.catch(err => done(err)); );
}); it("Should be able to remove VIP", () =>
it("Should be able to add user as VIP", (done) => { testVIPUpdate(users["vip-1"].pubID, false)
addUserAsVIP(publicPermVIP1, true) );
.then(async res => { it("Should be able to add second user as VIP", () =>
assert.strictEqual(res.status, 200); testVIPUpdate(genAnonUser().pubID, true)
const row = await checkUserVIP(publicPermVIP1); );
assert.ok(row); it("Should return 403 with invalid adminID", () =>
done(); addUserAsVIP(genAnonUser().pubID, true, genAnonUser().privID)
}) .then(res => assert.strictEqual(res.status, 403))
.catch(err => done(err)); );
}); it("Should return 400 with missing adminID", () =>
it("Should be able to add second user as VIP", (done) => { statusTest(400, {
addUserAsVIP(publicPermVIP2, true) userID: genAnonUser().pubID,
.then(async res => { enabled: String(true)
assert.strictEqual(res.status, 200);
const row = await checkUserVIP(publicPermVIP2);
assert.ok(row);
done();
})
.catch(err => done(err));
});
it("Should return 403 with invalid adminID", (done) => {
addUserAsVIP(publicPermVIP1, true, "Invalid_Admin_User_ID")
.then(res => {
assert.strictEqual(res.status, 403);
done();
})
.catch(err => done(err));
});
it("Should return 400 with missing adminID", (done) => {
client({
method: "POST",
url: endpoint,
params: {
userID: publicPermVIP1,
enabled: String(true)
}
}) })
.then(res => { );
assert.strictEqual(res.status, 400); it("Should return 400 with missing userID", () =>
done(); statusTest(400, {
}) enabled: String(true),
.catch(err => done(err)); adminUserID: adminPrivateUserID
});
it("Should return 400 with missing userID", (done) => {
client({
method: "POST",
url: endpoint,
params: {
enabled: String(true),
adminUserID: adminPrivateUserID
}
}) })
.then(res => { );
assert.strictEqual(res.status, 400); it("Should remove VIP if enabled is not true", () => {
done(); const user = genAnonUser();
}) return testVIPUpdate(user.pubID, true)
.catch(err => done(err)); .then(() => statusTest(200, {
}); userID: user.pubID,
it("Should be able to remove VIP", (done) => {
addUserAsVIP(publicPermVIP1, false)
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await checkUserVIP(publicPermVIP1);
assert.ok(!row);
done();
})
.catch(err => done(err));
});
it("Should remove VIP if enabled is false", (done) => {
client({
method: "POST",
url: endpoint,
params: {
userID: publicPermVIP2,
adminUserID: adminPrivateUserID, adminUserID: adminPrivateUserID,
enabled: "invalid-text" enabled: "invalid-text"
} }))
}) .then(() => checkUserVIP(user.pubID))
.then(async res => { .then(row => assert.ok(!row));
assert.strictEqual(res.status, 200);
const row = await checkUserVIP(publicPermVIP2);
assert.ok(!row);
done();
})
.catch(err => done(err));
}); });
it("Should remove VIP if enabled is missing", (done) => { it("Should remove VIP if enabled is missing", () => {
client({ const user = genAnonUser();
method: "POST", return testVIPUpdate(user.pubID, true)
url: endpoint, .then(() => statusTest(200, {
params: { userID: user.pubID,
userID: publicPermVIP3, adminUserID: adminPrivateUserID,
adminUserID: adminPrivateUserID }))
} .then(() => checkUserVIP(user.pubID))
}) .then(row => assert.ok(!row));
.then(async res => {
assert.strictEqual(res.status, 200);
const row = await checkUserVIP(publicPermVIP3);
assert.ok(!row);
done();
})
.catch(err => done(err));
}); });
}); });

View File

@@ -16,14 +16,10 @@ describe("eTag", () => {
}); });
const endpoint = "/etag"; const endpoint = "/etag";
it("Should reject weak etag", (done) => { it("Should reject weak etag", () => {
const etagKey = `W/test-etag-${genRandom()}`; const etagKey = `W/test-etag-${genRandom()}`;
client.get(endpoint, { headers: { "If-None-Match": etagKey } }) return client.get(endpoint, { headers: { "If-None-Match": etagKey } })
.then(res => { .then(res => assert.strictEqual(res.status, 404));
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
}); });
}); });
@@ -34,32 +30,29 @@ describe("304 etag validation", () => {
const endpoint = "/etag"; const endpoint = "/etag";
for (const hashType of ["skipSegments", "skipSegmentsHash", "videoLabel", "videoLabelHash"]) { for (const hashType of ["skipSegments", "skipSegmentsHash", "videoLabel", "videoLabelHash"]) {
it(`${hashType} etag should return 304`, (done) => { it(`${hashType} etag should return 304`, () => {
const etagKey = `${hashType};${genRandom};YouTube;${Date.now()}`; const etagKey = `${hashType};${genRandom};YouTube;${Date.now()}`;
redis.setEx(etagKey, 8400, "test").then(() => return redis.setEx(etagKey, 8400, "test").then(() =>
client.get(endpoint, { headers: { "If-None-Match": etagKey } }).then(res => { client.get(endpoint, { headers: { "If-None-Match": etagKey } }).then(res => {
assert.strictEqual(res.status, 304); assert.strictEqual(res.status, 304);
const etag = res.headers?.etag ?? ""; const etag = res.headers?.etag ?? "";
assert.ok(validateEtag(etagKey, etag)); assert.ok(validateEtag(etagKey, etag));
done(); })
}).catch(err => done(err))
); );
}); });
} }
it(`other etag type should not return 304`, (done) => { it(`other etag type should not return 304`, () => {
const etagKey = `invalidHashType;${genRandom};YouTube;${Date.now()}`; const etagKey = `invalidHashType;${genRandom};YouTube;${Date.now()}`;
client.get(endpoint, { headers: { "If-None-Match": etagKey } }).then(res => { return client.get(endpoint, { headers: { "If-None-Match": etagKey } }).then(res => {
assert.strictEqual(res.status, 404); assert.strictEqual(res.status, 404);
done(); });
}).catch(err => done(err));
}); });
it(`outdated etag type should not return 304`, (done) => { it(`outdated etag type should not return 304`, () => {
const etagKey = `skipSegments;${genRandom};YouTube;5000`; const etagKey = `skipSegments;${genRandom};YouTube;5000`;
client.get(endpoint, { headers: { "If-None-Match": etagKey } }).then(res => { return client.get(endpoint, { headers: { "If-None-Match": etagKey } }).then(res => {
assert.strictEqual(res.status, 404); assert.strictEqual(res.status, 404);
done(); });
}).catch(err => done(err));
}); });
}); });

View File

@@ -3,59 +3,43 @@ import { db } from "../../src/databases/databases";
import { Postgres } from "../../src/databases/Postgres"; import { Postgres } from "../../src/databases/Postgres";
import { client } from "../utils/httpClient"; import { client } from "../utils/httpClient";
import { partialDeepEquals } from "../utils/partialDeepEquals"; import { partialDeepEquals } from "../utils/partialDeepEquals";
import { insertChapter } from "../utils/segmentQueryGen";
import { genRandomValue } from "../utils/getRandom";
import { insertVideoInfo } from "../utils/queryGen";
// Only works with Postgres describe("getChapterNames", function () {
if (db instanceof Postgres) { const endpoint = "/api/chapterNames";
describe("getChapterNames", function () { const chapterNamesVid1 = genRandomValue("video", "getChapterNames");
const endpoint = "/api/chapterNames"; const chapterChannelID = genRandomValue("channel", "getChapterNames");
const chapterNames = [
"Weird name",
"A different one",
"Something else",
];
const chapterNamesVid1 = "chapterNamesVid"; const nameSearch = (query: string, expected: string): Promise<void> => {
const chapterChannelID = "chapterChannelID"; const expectedData = [{
description: expected
}];
return client.get(`${endpoint}?description=${query}&channelID=${chapterChannelID}`)
.then(res => {
assert.strictEqual(res.status, 200);
assert.strictEqual(res.data.length, chapterNames.length);
assert.ok(partialDeepEquals(res.data, expectedData));
});
};
before(async () => { before(async function() {
const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "hidden", "shadowHidden", "description") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; if (!(db instanceof Postgres)) this.skip(); // only works with Postgres
await db.prepare("run", query, [chapterNamesVid1, 60, 80, 2, 0, "chapterNamesVid-1", "testman", 0, 50, "chapter", "chapter", "YouTube", 0, 0, 0, "Weird name"]); await insertChapter(db, chapterNames[0], { videoID: chapterNamesVid1, startTime: 60, endTime: 80 });
await db.prepare("run", query, [chapterNamesVid1, 70, 75, 2, 0, "chapterNamesVid-2", "testman", 0, 50, "chapter", "chapter", "YouTube", 0, 0, 0, "A different one"]); await insertChapter(db, chapterNames[1], { videoID: chapterNamesVid1, startTime: 70, endTime: 75 });
await db.prepare("run", query, [chapterNamesVid1, 71, 76, 2, 0, "chapterNamesVid-3", "testman", 0, 50, "chapter", "chapter", "YouTube", 0, 0, 0, "Something else"]); await insertChapter(db, chapterNames[2], { videoID: chapterNamesVid1, startTime: 71, endTime: 76 });
await db.prepare("run", `INSERT INTO "videoInfo" ("videoID", "channelID", "title", "published") await insertVideoInfo(db, chapterNamesVid1, chapterChannelID);
SELECT ?, ?, ?, ?`, [
chapterNamesVid1, chapterChannelID, "", 0
]);
});
it("Search for 'weird'", async () => {
const result = await client.get(`${endpoint}?description=weird&channelID=${chapterChannelID}`);
const expected = [{
description: "Weird name",
}];
assert.strictEqual(result.status, 200);
assert.strictEqual(result.data.length, 3);
assert.ok(partialDeepEquals(result.data, expected));
});
it("Search for 'different'", async () => {
const result = await client.get(`${endpoint}?description=different&channelID=${chapterChannelID}`);
const expected = [{
description: "A different one",
}];
assert.strictEqual(result.status, 200);
assert.strictEqual(result.data.length, 3);
assert.ok(partialDeepEquals(result.data, expected));
});
it("Search for 'something'", async () => {
const result = await client.get(`${endpoint}?description=something&channelID=${chapterChannelID}`);
const expected = [{
description: "Something else",
}];
assert.strictEqual(result.status, 200);
assert.strictEqual(result.data.length, 3);
assert.ok(partialDeepEquals(result.data, expected));
});
}); });
}
it("Search for 'weird'", () => nameSearch("weird", chapterNames[0]));
it("Search for 'different'", () => nameSearch("different", chapterNames[1]));
it("Search for 'something'", () => nameSearch("something", chapterNames[2]));
});

View File

@@ -50,9 +50,8 @@ describe("getIP stubs", () => {
before(() => stub = sinon.stub(config, "mode").value(mode)); before(() => stub = sinon.stub(config, "mode").value(mode));
after(() => stub.restore()); after(() => stub.restore());
it("Should return production mode if stub worked", (done) => { it("Should return production mode if stub worked", () => {
assert.strictEqual(config.mode, mode); assert.strictEqual(config.mode, mode);
done();
}); });
}); });
@@ -64,22 +63,20 @@ describe("getIP array tests", () => {
}); });
for (const [key, value] of Object.entries(expectedIP4)) { for (const [key, value] of Object.entries(expectedIP4)) {
it(`Should return correct IPv4 from ${key}`, (done) => { it(`Should return correct IPv4 from ${key}`, () => {
stub2 = sinon.stub(config, "behindProxy").value(key); stub2 = sinon.stub(config, "behindProxy").value(key);
const ip = getIP(v4MockRequest); const ip = getIP(v4MockRequest);
assert.strictEqual(config.behindProxy, key); assert.strictEqual(config.behindProxy, key);
assert.strictEqual(ip, value); assert.strictEqual(ip, value);
done();
}); });
} }
for (const [key, value] of Object.entries(expectedIP6)) { for (const [key, value] of Object.entries(expectedIP6)) {
it(`Should return correct IPv6 from ${key}`, (done) => { it(`Should return correct IPv6 from ${key}`, () => {
stub2 = sinon.stub(config, "behindProxy").value(key); stub2 = sinon.stub(config, "behindProxy").value(key);
const ip = getIP(v6MockRequest); const ip = getIP(v6MockRequest);
assert.strictEqual(config.behindProxy, key); assert.strictEqual(config.behindProxy, key);
assert.strictEqual(ip, value); assert.strictEqual(ip, value);
done();
}); });
} }
}); });
@@ -91,19 +88,17 @@ describe("getIP true tests", () => {
stub2.restore(); stub2.restore();
}); });
it(`Should return correct IPv4 from with bool true`, (done) => { it(`Should return correct IPv4 from with bool true`, () => {
stub2 = sinon.stub(config, "behindProxy").value(true); stub2 = sinon.stub(config, "behindProxy").value(true);
const ip = getIP(v4MockRequest); const ip = getIP(v4MockRequest);
assert.strictEqual(config.behindProxy, "X-Forwarded-For"); assert.strictEqual(config.behindProxy, "X-Forwarded-For");
assert.strictEqual(ip, expectedIP4["X-Forwarded-For"]); assert.strictEqual(ip, expectedIP4["X-Forwarded-For"]);
done();
}); });
it(`Should return correct IPv4 from with string true`, (done) => { it(`Should return correct IPv4 from with string true`, () => {
stub2 = sinon.stub(config, "behindProxy").value("true"); stub2 = sinon.stub(config, "behindProxy").value("true");
const ip = getIP(v4MockRequest); const ip = getIP(v4MockRequest);
assert.strictEqual(config.behindProxy, "X-Forwarded-For"); assert.strictEqual(config.behindProxy, "X-Forwarded-For");
assert.strictEqual(ip, expectedIP4["X-Forwarded-For"]); assert.strictEqual(ip, expectedIP4["X-Forwarded-For"]);
done();
}); });
}); });

View File

@@ -1,54 +1,42 @@
import { db } from "../../src/databases/databases"; import { db } from "../../src/databases/databases";
import { getHash } from "../../src/utils/getHash"; import { genUsers, User } from "../utils/genUser";
import { client } from "../utils/httpClient"; import { client } from "../utils/httpClient";
import assert from "assert"; import assert from "assert";
import { insertVip } from "../utils/queryGen";
const VIPUser = "isUserVIPVIP";
const normalUser = "isUserVIPNormal";
const endpoint = "/api/isUserVIP"; const endpoint = "/api/isUserVIP";
const vipUserRequest = (userID: string) => client.get(endpoint, { params: { userID } }); const vipUserRequest = (userID: string) => client.get(endpoint, { params: { userID } });
const checkVipStatus = (user: User, expected: boolean) =>
vipUserRequest(user.privID)
.then(res => {
assert.strictEqual(res.status, 200);
assert.strictEqual(res.data.vip, expected);
});
const cases = [
"vip",
"normal",
];
const users = genUsers("endpoint", cases);
describe("getIsUserVIP", () => { describe("getIsUserVIP", () => {
before(() => { before(async () => {
db.prepare("run", 'INSERT INTO "vipUsers" ("userID") VALUES (?)', [getHash(VIPUser)]); await insertVip(db, users["vip"].pubID);
}); });
it("Should be able to get a 200", (done) => { // status checks
vipUserRequest(VIPUser) it("Should be able to get a 200", () =>
.then(res => { vipUserRequest(users["vip"].privID)
assert.strictEqual(res.status, 200, "response should be 200"); .then(res => assert.strictEqual(res.status, 200))
done(); );
})
.catch(err => done(err));
});
it("Should get a 400 if no userID", (done) => { it("Should get a 400 if no userID", () =>
client.get(endpoint) client.get(endpoint)
.then(res => { .then(res => assert.strictEqual(res.status, 400, "response should be 400"))
assert.strictEqual(res.status, 400, "response should be 400"); );
done();
})
.catch(err => done(err));
});
it("Should say a VIP is a VIP", (done) => { // user checks
vipUserRequest(VIPUser) it("Should say a VIP is a VIP", () => checkVipStatus(users["vip"], true));
.then(res => { it("Should say a normal user is not a VIP", () => checkVipStatus(users["normal"], false));
assert.strictEqual(res.status, 200);
assert.strictEqual(res.data.vip, true);
done();
})
.catch(err => done(err));
});
it("Should say a normal user is not a VIP", (done) => {
vipUserRequest(normalUser)
.then(res => {
assert.strictEqual(res.status, 200);
assert.strictEqual(res.data.vip, false);
done();
})
.catch(err => done(err));
});
}); });

View File

@@ -1,26 +1,60 @@
import { getHash } from "../../src/utils/getHash";
import { db } from "../../src/databases/databases"; import { db } from "../../src/databases/databases";
import assert from "assert"; import assert from "assert";
import { client } from "../utils/httpClient"; import { client } from "../utils/httpClient";
import { mixedDeepEquals } from "../utils/partialDeepEquals"; import { insertLock } from "../utils/queryGen";
import { multiGenRandomValue } from "../utils/getRandom";
const endpoint = "/api/lockCategories"; const endpoint = "/api/lockCategories";
const defaultActionTypes = ["skip", "mute"]; const defaultActionTypes = ["skip", "mute"];
const getLockCategories = (videoID: string, actionType = defaultActionTypes, service = "YouTube") => client.get(endpoint, { params: { videoID, actionType, service } }); const getLockCategories = (videoID: string, actionType = defaultActionTypes, service = "YouTube") => client.get(endpoint, { params: { videoID, actionType, service } });
const queryStatusCheck = (status: number, queryString: string) =>
client.get(`${endpoint}${queryString}`)
.then(res => assert.strictEqual(res.status, status));
type lockResponse = {
categories?: string[],
reason?: string,
actionTypes?: string[]
}
type lockOverrides = {
actionTypes?: string[],
service?: string
}
const validateResponse = (videoID: string, overrides: lockOverrides = {}, expected: lockResponse): Promise<void> => {
const actionTypes = overrides.actionTypes ?? defaultActionTypes;
const service = overrides.service ?? "YouTube";
const defaultExpected = { categories: [ "sponsor" ], reason: "", actionTypes: defaultActionTypes };
const expectedResponse = { ...defaultExpected, ...expected };
return getLockCategories(videoID, actionTypes, service)
.then(res => {
assert.strictEqual(res.status, 200);
// modify both categories to sort()
res.data.categories?.sort();
expectedResponse.categories?.sort();
assert.deepStrictEqual(res.data, expectedResponse);
});
};
const validate404 = (videoID: string, overrides: lockOverrides = {}): Promise<void> => {
const actionTypes = overrides.actionTypes || defaultActionTypes;
const service = overrides.service || "YouTube";
return getLockCategories(videoID, actionTypes, service)
.then(res => assert.strictEqual(res.status, 404));
};
const videoIDs = multiGenRandomValue("video", "getLockCategories", 3);
describe("getLockCategories", () => { describe("getLockCategories", () => {
before(async () => { before(async () => {
const insertVipUserQuery = 'INSERT INTO "vipUsers" ("userID") VALUES (?)'; await insertLock(db, { videoID: videoIDs[0], reason: "1-short" });
await db.prepare("run", insertVipUserQuery, [getHash("getLockCategoriesVIP")]); await insertLock(db, { videoID: videoIDs[0], reason: "1-longer-reason", actionType: "mute", category: "interaction" });
const insertLockCategoryQuery = 'INSERT INTO "lockCategories" ("userID", "videoID", "actionType","category", "reason", "service") VALUES (?, ?, ?, ?, ?, ?)'; await insertLock(db, { videoID: videoIDs[1], reason: "2-reason", category: "preview" });
await db.prepare("run", insertLockCategoryQuery, [getHash("getLockCategoriesVIP"), "getLockCategory1", "skip", "sponsor", "1-short", "YouTube"]);
await db.prepare("run", insertLockCategoryQuery, [getHash("getLockCategoriesVIP"), "getLockCategory1", "mute", "interaction", "1-longer-reason", "YouTube"]);
await db.prepare("run", insertLockCategoryQuery, [getHash("getLockCategoriesVIP"), "getLockCategory2", "skip", "preview", "2-reason", "YouTube"]); await insertLock(db, { videoID: videoIDs[2], reason: "3-reason", category: "nonmusic", actionType: "mute", service: "PeerTube" });
await insertLock(db, { videoID: videoIDs[2], reason: "3-reason" });
await db.prepare("run", insertLockCategoryQuery, [getHash("getLockCategoriesVIP"), "getLockCategory3", "mute", "nonmusic", "3-reason", "PeerTube"]); await insertLock(db, { videoID: videoIDs[2], reason: "3-longer-reason", category: "selfpromo", actionType: "full" });
await db.prepare("run", insertLockCategoryQuery, [getHash("getLockCategoriesVIP"), "getLockCategory3", "skip", "sponsor", "3-reason", "YouTube"]);
await db.prepare("run", insertLockCategoryQuery, [getHash("getLockCategoriesVIP"), "getLockCategory3", "full", "outro", "3-longer-reason", "YouTube"]);
}); });
it("Should update the database version when starting the application", async () => { it("Should update the database version when starting the application", async () => {
@@ -28,198 +62,87 @@ describe("getLockCategories", () => {
assert.ok(version >= 29, `Version isn't greater than 29. Version is ${version}`); assert.ok(version >= 29, `Version isn't greater than 29. Version is ${version}`);
}); });
it("Should be able to get multiple locks", (done) => { // 200 tests
getLockCategories("getLockCategory1") it("should return 200 by single actionType", () => queryStatusCheck(200, `?videoID=${videoIDs[0]}&actionType=mute`));
.then(res => { it("should return 200 by single actionTypes JSON", () => queryStatusCheck(200, `?videoID=${videoIDs[0]}&actionTypes=["mute"]`));
assert.strictEqual(res.status, 200); it("should return 200 by repeating actionTypes", () => queryStatusCheck(200, `?videoID=${videoIDs[0]}&actionType=mute&actionType=skip`) );
const expected = {
categories: [
"sponsor",
"interaction"
],
reason: "1-longer-reason",
actionTypes: defaultActionTypes
};
assert.ok(mixedDeepEquals(res.data, expected));
done();
})
.catch(err => done(err));
});
it("Should be able to get single locks", (done) => { // 404 tests
getLockCategories("getLockCategory2") it("should return 404 if no lock exists", () => validate404("getLockCategoryNull"));
.then(res => { it("should return 404 if invalid actionTypes specified", () => validate404(videoIDs[0], { actionTypes: ["ban"] }));
assert.strictEqual(res.status, 200);
const expected = {
categories: [
"preview"
],
reason: "2-reason",
actionTypes: defaultActionTypes
};
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("should return 404 if no lock exists", (done) => { // 400 tests
getLockCategories("getLockCategoryNull") it("should return 400 if no videoID specified", () => queryStatusCheck(400, ""));
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
});
it("should return 400 if no videoID specified", (done) => { // complicated response tests
client.get(endpoint) it("Should be able to get multiple locks", () =>
.then(res => { validateResponse(videoIDs[0], {}, {
assert.strictEqual(res.status, 400); categories: [
done(); "sponsor",
}) "interaction"
.catch(err => done(err)); ],
}); reason: "1-longer-reason"
})
);
it("Should be able to get multiple locks with service", (done) => { it("Should be able to get single locks", () =>
getLockCategories("getLockCategory1", defaultActionTypes, "YouTube") validateResponse(videoIDs[1], {}, {
.then(res => { categories: [
assert.strictEqual(res.status, 200); "preview"
const expected = { ],
categories: [ reason: "2-reason",
"sponsor", })
"interaction" );
],
reason: "1-longer-reason",
actionTypes: defaultActionTypes
};
assert.ok(mixedDeepEquals(res.data, expected));
done();
})
.catch(err => done(err));
});
it("Should be able to get single locks with service", (done) => { it("Should be able to get multiple locks with service", () =>
getLockCategories("getLockCategory3", defaultActionTypes, "PeerTube") validateResponse(videoIDs[0], {}, {
.then(res => { categories: [
assert.strictEqual(res.status, 200); "sponsor",
const expected = { "interaction"
categories: [ ],
"nonmusic" reason: "1-longer-reason",
], })
reason: "3-reason", );
actionTypes: defaultActionTypes
};
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("Should be able to get single locks with service", (done) => { it("Should be able to get single locks with service", () =>
getLockCategories("getLockCategory3", defaultActionTypes, "Youtube") validateResponse(videoIDs[2], { service: "PeerTube" }, {
.then(res => { categories: [ "nonmusic" ],
assert.strictEqual(res.status, 200); reason: "3-reason",
const expected = { })
categories: [ );
"sponsor"
],
reason: "3-reason",
actionTypes: defaultActionTypes
};
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("should return result from Youtube service if service not match", (done) => { it("Should be able to get single locks with service", () =>
getLockCategories("getLockCategory3", defaultActionTypes, "Dailymotion") validateResponse(videoIDs[2], { service: "Youtube" }, {
.then(res => { reason: "3-reason",
assert.strictEqual(res.status, 200); })
const expected = { );
categories: [
"sponsor"
],
reason: "3-reason",
actionTypes: defaultActionTypes
};
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("should return 404 if invalid actionTypes specified", (done) => { it("should return result from Youtube service if service not match", () =>
getLockCategories("getLockCategory1", ["ban"]) validateResponse(videoIDs[2], { service: "Dailymotion" }, {
.then(res => { reason: "3-reason",
assert.strictEqual(res.status, 404); })
done(); );
})
.catch(err => done(err));
});
it("should be able to get with specific actionType", (done) => { it("should be able to get with specific actionType", () =>
getLockCategories("getLockCategory1", ["mute"]) validateResponse(videoIDs[0], { actionTypes: ["mute"] }, {
.then(res => { categories: [
assert.strictEqual(res.status, 200); "interaction"
const expected = { ],
categories: [ reason: "1-longer-reason",
"interaction" actionTypes: ["mute"]
], })
reason: "1-longer-reason", );
actionTypes: ["mute"]
};
mixedDeepEquals(res.data, expected);
done();
})
.catch(err => done(err));
});
it("Should be able to get skip, mute, full", (done) => { it("Should be able to get skip, mute, full", () => {
const actionTypes = [...defaultActionTypes, "full"]; const actionTypes = [...defaultActionTypes, "full"];
getLockCategories("getLockCategory3", actionTypes) return validateResponse(videoIDs[2], { actionTypes }, {
.then(res => { categories: [
assert.strictEqual(res.status, 200); "sponsor",
const expected = { "selfpromo",
categories: [ // "nonmusic", // no nonmusic since it's on other service
"sponsor", ],
"nonmusic", reason: "3-longer-reason",
"outro" actionTypes
], });
reason: "3-longer-reason",
actionTypes
};
mixedDeepEquals(res.data, expected);
done();
})
.catch(err => done(err));
});
it("should return 200 by single actionType", (done) => {
client.get(`${endpoint}?videoID=getLockCategory1&actionType=mute`)
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it("should return 200 by single actionTypes JSON", (done) => {
client.get(`${endpoint}?videoID=getLockCategory1&actionTypes=["mute"]`)
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it("should return 200 by repeating actionTypes", (done) => {
client.get(`${endpoint}?videoID=getLockCategory1&actionType=mute&actionType=skip`)
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
}); });
}); });

View File

@@ -11,7 +11,7 @@ describe("getStatus", () => {
dbVersion = (await db.prepare("get", "SELECT key, value FROM config where key = ?", ["version"])).value; dbVersion = (await db.prepare("get", "SELECT key, value FROM config where key = ?", ["version"])).value;
}); });
it("Should be able to get status", (done) => { it("Should be able to get status", () =>
client.get(endpoint) client.get(endpoint)
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
@@ -22,106 +22,86 @@ describe("getStatus", () => {
assert.ok(data.startTime); assert.ok(data.startTime);
assert.ok(data.processTime >= 0); assert.ok(data.processTime >= 0);
assert.ok(data.loadavg.length == 2); assert.ok(data.loadavg.length == 2);
done();
}) })
.catch(err => done(err)); );
});
it("Should be able to get uptime only", (done) => { it("Should be able to get uptime only", () =>
client.get(`${endpoint}/uptime`) client.get(`${endpoint}/uptime`)
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
assert.ok(Number(res.data) >= 1); // uptime should be greater than 1s assert.ok(Number(res.data) >= 1); // uptime should be greater than 1s
done();
}) })
.catch(err => done(err)); );
});
it("Should be able to get commit only", (done) => { it("Should be able to get commit only", () =>
client.get(`${endpoint}/commit`) client.get(`${endpoint}/commit`)
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
assert.strictEqual(res.data, "test"); // commit should be test assert.strictEqual(res.data, "test"); // commit should be test
done();
}) })
.catch(err => done(err)); );
});
it("Should be able to get db only", (done) => { it("Should be able to get db only", () =>
client.get(`${endpoint}/db`) client.get(`${endpoint}/db`)
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
assert.strictEqual(Number(res.data), Number(dbVersion)); // commit should be test assert.strictEqual(Number(res.data), Number(dbVersion)); // commit should be test
done();
}) })
.catch(err => done(err)); );
});
it("Should be able to get startTime only", (done) => { it("Should be able to get startTime only", () =>
client.get(`${endpoint}/startTime`) client.get(`${endpoint}/startTime`)
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
const now = Date.now(); const now = Date.now();
assert.ok(Number(res.data) <= now); // startTime should be more than now assert.ok(Number(res.data) <= now); // startTime should be more than now
done();
}) })
.catch(err => done(err)); );
});
it("Should be able to get processTime only", (done) => { it("Should be able to get processTime only", () =>
client.get(`${endpoint}/processTime`) client.get(`${endpoint}/processTime`)
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
assert.ok(Number(res.data) >= 0); assert.ok(Number(res.data) >= 0);
done();
}) })
.catch(err => done(err)); );
});
it("Should be able to get loadavg only", (done) => { it("Should be able to get loadavg only", () =>
client.get(`${endpoint}/loadavg`) client.get(`${endpoint}/loadavg`)
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
assert.ok(Number(res.data[0]) >= 0); assert.ok(Number(res.data[0]) >= 0);
assert.ok(Number(res.data[1]) >= 0); assert.ok(Number(res.data[1]) >= 0);
done();
}) })
.catch(err => done(err)); );
});
it("Should be able to get statusRequests only", function (done) { it("Should be able to get statusRequests only", function () {
if (!config.redis?.enabled) this.skip(); if (!config.redis?.enabled) this.skip();
client.get(`${endpoint}/statusRequests`) return client.get(`${endpoint}/statusRequests`)
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
assert.ok(Number(res.data) > 1); assert.ok(Number(res.data) > 1);
done(); });
})
.catch(err => done(err));
}); });
it("Should be able to get status with statusRequests", function (done) { it("Should be able to get status with statusRequests", function () {
if (!config.redis?.enabled) this.skip(); if (!config.redis?.enabled) this.skip();
client.get(endpoint) return client.get(endpoint)
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
const data = res.data; const data = res.data;
assert.ok(data.statusRequests > 2); assert.ok(data.statusRequests > 2);
done(); });
})
.catch(err => done(err));
}); });
it("Should be able to get redis latency", function (done) { it("Should be able to get redis latency", function () {
if (!config.redis?.enabled) this.skip(); if (!config.redis?.enabled) this.skip();
client.get(endpoint) return client.get(endpoint)
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
const data = res.data; const data = res.data;
assert.ok(data.redisProcessTime >= 0); assert.ok(data.redisProcessTime >= 0);
done(); });
})
.catch(err => done(err));
}); });
it("Should return commit unkown if not present", (done) => { it("Should return commit unkown if not present", (done) => {

View File

@@ -1,12 +1,61 @@
import { getSubmissionUUID } from "../../src/utils/getSubmissionUUID"; import { getSubmissionUUID } from "../../src/utils/getSubmissionUUID";
import assert from "assert"; import assert from "assert";
import { ActionType, VideoID, Service, Category } from "../../src/types/segments.model"; import { ActionType, VideoID, Service, Category } from "../../src/types/segments.model";
import { UserID } from "../../src/types/user.model"; import { HashedUserID } from "../../src/types/user.model";
import { getHash } from "../../src/utils/getHash";
import { HashedValue } from "../../src/types/hash.model";
import { genAnonUser } from "../utils/genUser";
import { genRandomValue } from "../utils/getRandom";
function testHash (segment: segment, version: number): HashedValue {
const manualHash = getHash(Object.values(segment).join(""), 1) as HashedValue;
const generatedHash = getSubmissionUUID(segment.videoID, segment.category, segment.actionType, segment.description, segment.userID, segment.startTime, segment.endTime, segment.service);
assert.strictEqual(version, Number(generatedHash.at(-1)), "version should match passed in version");
assert.strictEqual(`${manualHash}${version}`, generatedHash);
return generatedHash;
}
interface segment {
videoID: VideoID,
startTime: number,
endTime: number,
userID: HashedUserID,
description: string,
category: Category,
actionType: ActionType,
service: Service
}
const version = 7;
describe("getSubmissionUUID", () => { describe("getSubmissionUUID", () => {
it("Should return the hashed value", () => { it("Should return the hashed value identical to manually generated value", () => {
assert.strictEqual( const segment: segment = {
getSubmissionUUID("video001" as VideoID, "sponsor" as Category, "skip" as ActionType, "", "testuser001" as UserID, 13.33337, 42.000001, Service.YouTube), videoID: "video001" as VideoID,
"2a473bca993dd84d8c2f6a4785989b20948dfe0c12c00f6f143bbda9ed561dca7"); startTime: 13.33337,
endTime: 42.000001,
userID: "testuser001" as HashedUserID,
description: "",
category: "sponsor" as Category,
actionType: "skip" as ActionType,
service: Service.YouTube
};
const testedHash = testHash(segment, version);
// test against baked hash
assert.strictEqual(testedHash, "2a473bca993dd84d8c2f6a4785989b20948dfe0c12c00f6f143bbda9ed561dca7");
});
it ("Should return identical hash for randomly generated values", () => {
const user = genAnonUser();
const segment: segment = {
videoID: genRandomValue("video", "getUUID") as VideoID,
startTime: Math.random()*1000,
endTime: Math.random()*500,
userID: user.pubID,
description: genRandomValue("description", "getUUID"),
category: "sponsor" as Category,
actionType: "skip" as ActionType,
service: Service.YouTube
};
testHash(segment, version);
}); });
}); });

View File

@@ -1,315 +1,120 @@
import { db } from "../../src/databases/databases"; import { db } from "../../src/databases/databases";
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 { UsernameUser, genUser, genUsersUsername } from "../utils/genUser";
import { insertUsernameBulk } from "../utils/queryGen";
const endpoint = "/api/userID"; const endpoint = "/api/userID";
const getUserName = (username: string): Promise<AxiosResponse> => client.get(endpoint, { params: { username } }); const getUserName = (username: string, exact: any = false): Promise<AxiosResponse> => client.get(endpoint, { params: { username, exact } });
const validateSearch = (query: string, users: UsernameUser[], exact: number | boolean = false): Promise<void> =>
getUserName(query, exact)
.then(res => {
assert.strictEqual(res.status, 200);
const expected = users.map(user => ({
userName: user.username,
userID: user.pubID
}));
assert.deepStrictEqual(res.data, expected);
});
const validateSearchWithUser = (user: UsernameUser, exact = false): Promise<void> =>
validateSearch(user.username, [user], exact);
const cases = new Map([
["fuzzy_1", "fuzzy user 01"],
["fuzzy_2", "fuzzy user 02"],
["specific_1", "specific user 03"],
["repeating_1", "repeating"],
["repeating_2", "repeating"],
["redos_1", "0redis0"],
["redos_2", "%redos%"],
["redos_3", "_redos_"],
["redos_4", "redos\\%"],
["redos_5", "\\\\\\"],
["exact_1", "a"],
]);
const userPublicOne = genUser("getUserID", "public_1");
const users = genUsersUsername("getUserID", cases);
users["public_1"] = { ...userPublicOne, username: userPublicOne.pubID };
describe("getUserID", () => { describe("getUserID", () => {
before(async () => { before(async () => {
const insertUserNameQuery = 'INSERT INTO "userNames" ("userID", "userName") VALUES(?, ?)'; await insertUsernameBulk(db, users);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_01"), "fuzzy user 01"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_02"), "fuzzy user 02"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_03"), "specific user 03"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_04"), "repeating"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_05"), "repeating"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_06"), getHash("getuserid_user_06")]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_07"), "0redos0"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_08"), "%redos%"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_09"), "_redos_"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_10"), "redos\\%"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_11"), "\\\\\\"]);
await db.prepare("run", insertUserNameQuery, [getHash("getuserid_user_12"), "a"]);
}); });
it("Should be able to get a 200", (done) => { // status tests
it("Should be able to get a 200", () =>
getUserName("fuzzy user 01") getUserName("fuzzy user 01")
.then(res => { .then(res => assert.strictEqual(res.status, 200))
assert.strictEqual(res.status, 200); );
done();
}) it("Should be able to get a 200 (username is public id)", () =>
.catch(err => done(err)); getUserName(users["public_1"].username)
.then(res => assert.strictEqual(res.status, 200))
);
// individual user tests
it("Should be able to get single username", () => validateSearchWithUser(users["fuzzy_1"]));
it("Should be able to get with public ID", () => validateSearchWithUser(users["public_1"]));
// individual user ReDOS
it("should avoid ReDOS with _", () => validateSearchWithUser(users["redos_3"]));
it("should avoid ReDOS with %", () => validateSearchWithUser(users["redos_2"]));
it("should return user if just backslashes", () => validateSearchWithUser(users["redos_5"]));
it("should allow exact match", () => validateSearchWithUser(users["exact_1"], true));
// fuzzy tests
it("Should be able to get multiple fuzzy user info from start", () =>
validateSearch("fuzzy user",
[users["fuzzy_1"], users["fuzzy_2"]]
)
);
it("Should be able to get multiple fuzzy user info from middle", () => {
validateSearch("user",
[users["fuzzy_1"], users["fuzzy_2"], users["specific_1"]]
);
}); });
it("Should be able to get a 400 (No username parameter)", (done) => { it("Should be able to get with fuzzy public ID", () => {
client.get(endpoint) const userID = users["public_1"].pubID.substring(0,60);
.then(res => { return validateSearch(userID,
assert.strictEqual(res.status, 400); [users["public_1"]]
done(); );
})
.catch(err => done(err));
}); });
it("Should be able to get a 200 (username is public id)", (done) => { it("Should be able to get repeating username", () =>
client.get(endpoint, { params: { username: getHash("getuserid_user_06") } }) validateSearch("repeating", [users["repeating_1"], users["repeating_2"]])
.then(res => { );
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it("Should be able to get a 400 (username longer than 64 chars)", (done) => { it("Should be able to get repeating fuzzy username", () =>
client.get(endpoint, { params: { username: `${getHash("getuserid_user_06")}0` } }) validateSearch("peat", [users["repeating_1"], users["repeating_2"]])
.then(res => { );
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it("Should be able to get single username", (done) => { it("Should be able to get repeating username with exact username", () =>
client.get(endpoint, { params: { username: "fuzzy user 01" } }) validateSearch("repeating", [users["repeating_1"], users["repeating_2"]], true)
.then(res => { );
assert.strictEqual(res.status, 200);
const expected = [{
userName: "fuzzy user 01",
userID: getHash("getuserid_user_01")
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("Should be able to get multiple fuzzy user info from start", (done) => { it("Should not get exact unless explicitly set to true", () =>
getUserName("fuzzy user") validateSearch("user", [users["fuzzy_1"], users["fuzzy_2"], users["specific_1"]], 1)
.then(res => { );
assert.strictEqual(res.status, 200);
const expected = [{
userName: "fuzzy user 01",
userID: getHash("getuserid_user_01")
}, {
userName: "fuzzy user 02",
userID: getHash("getuserid_user_02")
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("Should be able to get multiple fuzzy user info from middle", (done) => {
getUserName("user")
.then(res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "fuzzy user 01",
userID: getHash("getuserid_user_01")
}, {
userName: "fuzzy user 02",
userID: getHash("getuserid_user_02")
}, {
userName: "specific user 03",
userID: getHash("getuserid_user_03")
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("Should be able to get with public ID", (done) => {
const userID = getHash("getuserid_user_06");
getUserName(userID)
.then(res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: userID,
userID
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("Should be able to get with fuzzy public ID", (done) => {
const userID = getHash("getuserid_user_06");
getUserName(userID.substr(10,60))
.then(res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: userID,
userID
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("Should be able to get repeating username", (done) => {
getUserName("repeating")
.then(res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "repeating",
userID: getHash("getuserid_user_04")
}, {
userName: "repeating",
userID: getHash("getuserid_user_05")
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("Should be able to get repeating fuzzy username", (done) => {
getUserName("peat")
.then(res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "repeating",
userID: getHash("getuserid_user_04")
}, {
userName: "repeating",
userID: getHash("getuserid_user_05")
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("should avoid ReDOS with _", (done) => {
getUserName("_redos_")
.then(res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "_redos_",
userID: getHash("getuserid_user_09")
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("should avoid ReDOS with %", (done) => {
getUserName("%redos%")
.then(res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "%redos%",
userID: getHash("getuserid_user_08")
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("should return 404 if escaped backslashes present", (done) => {
getUserName("%redos\\\\_")
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
});
it("should return 404 if backslashes present", (done) => {
getUserName(`\\%redos\\_`)
.then(res => {
assert.strictEqual(res.status, 404);
done();
})
.catch(err => done(err));
});
it("should return user if just backslashes", (done) => {
getUserName(`\\\\\\`)
.then(res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "\\\\\\",
userID: getHash("getuserid_user_11")
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("should not allow usernames more than 64 characters", (done) => {
getUserName("0".repeat(65))
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it("should not allow usernames less than 3 characters", (done) => {
getUserName("aa")
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it("should allow exact match", (done) => {
client.get(endpoint, { params: { username: "a", exact: true } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "a",
userID: getHash("getuserid_user_12")
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("Should be able to get repeating username with exact username", (done) => {
client.get(endpoint, { params: { username: "repeating", exact: true } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "repeating",
userID: getHash("getuserid_user_04")
}, {
userName: "repeating",
userID: getHash("getuserid_user_05")
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("Should not get exact unless explicitly set to true", (done) => {
client.get(endpoint, { params: { username: "user", exact: 1 } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = [{
userName: "fuzzy user 01",
userID: getHash("getuserid_user_01")
}, {
userName: "fuzzy user 02",
userID: getHash("getuserid_user_02")
}, {
userName: "specific user 03",
userID: getHash("getuserid_user_03")
}];
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("should return 400 if no username parameter specified", (done) => {
client.get(endpoint)
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(() => ("couldn't call endpoint"));
});
}); });
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 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

@@ -1,163 +1,123 @@
import { partialDeepEquals } from "../utils/partialDeepEquals"; import { partialDeepEquals } from "../utils/partialDeepEquals";
import { db } from "../../src/databases/databases"; import { db } from "../../src/databases/databases";
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 { insertSegment, insertThumbnail, insertThumbnailVote, insertTitle, insertTitleVote } from "../utils/segmentQueryGen";
import { genUsers, User } from "../utils/genUser";
import { genRandomValue } from "../utils/getRandom";
import { insertBan, insertUsername, insertWarning } from "../utils/queryGen";
describe("getUserInfo", () => { describe("getUserInfo", () => {
const endpoint = "/api/userInfo"; const endpoint = "/api/userInfo";
const cases = [
"n-0",
"n-1",
"n-2",
"n-3",
"n-4",
"n-5",
"n-6",
"null",
"vip",
"warn-0",
"warn-1",
"warn-2",
"warn-3",
"ban-1",
"ban-2",
];
const users = genUsers("endpoint", cases);
for (const [id, user] of Object.entries(users))
// generate last segment UUIDs
user.info["last"] = genRandomValue("uuid", id);
const checkValues = (user: User, expected: Record<string, string | number | boolean>) =>
client.get(endpoint, { params: { userID: user.privID, value: Object.keys(expected) } })
.then(res => {
assert.strictEqual(res.status, 200);
assert.ok(partialDeepEquals(res.data, expected));
});
before(async () => { before(async () => {
const insertUserNameQuery = 'INSERT INTO "userNames" ("userID", "userName") VALUES(?, ?)'; users["n-1"].info["username"] = genRandomValue("username", "n-1");
await db.prepare("run", insertUserNameQuery, [getHash("getuserinfo_user_01"), "Username user 01"]); await insertUsername(db, users["n-1"].pubID, users["n-1"].info["username"]);
const sponsorTimesQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "actionType", "shadowHidden") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; // insert segments
await db.prepare("run", sponsorTimesQuery, ["getUserInfo0", 1, 11, 2, "uuid000001", getHash("getuserinfo_user_01"), 1, 10, "sponsor", "skip", 0]); const defaultSegmentParams = { startTime: 0, endTime: 10, votes: 2, views: 10 };
await db.prepare("run", sponsorTimesQuery, ["getUserInfo0", 1, 11, 2, "uuid000002", getHash("getuserinfo_user_01"), 2, 10, "sponsor", "skip", 0]); // user["n-1"]
await db.prepare("run", sponsorTimesQuery, ["getUserInfo1", 1, 11, -1, "uuid000003", getHash("getuserinfo_user_01"), 3, 10, "sponsor", "skip", 0]); await insertSegment(db, { ...defaultSegmentParams, userID: users["n-1"].pubID });
await db.prepare("run", sponsorTimesQuery, ["getUserInfo1", 1, 11, -2, "uuid000004", getHash("getuserinfo_user_01"), 4, 10, "sponsor", "skip", 1]); await insertSegment(db, { ...defaultSegmentParams, userID: users["n-1"].pubID });
await db.prepare("run", sponsorTimesQuery, ["getUserInfo2", 1, 11, -5, "uuid000005", getHash("getuserinfo_user_01"), 5, 10, "sponsor", "skip", 1]); await insertSegment(db, { ...defaultSegmentParams, userID: users["n-1"].pubID, votes: -1 });
await db.prepare("run", sponsorTimesQuery, ["getUserInfo0", 1, 11, 2, "uuid000007", getHash("getuserinfo_user_02"), 7, 10, "sponsor", "skip", 1]); await insertSegment(db, { ...defaultSegmentParams, userID: users["n-1"].pubID, votes: -2 });
await db.prepare("run", sponsorTimesQuery, ["getUserInfo0", 1, 11, 2, "uuid000008", getHash("getuserinfo_user_02"), 8, 10, "sponsor", "skip", 1]); await insertSegment(db, { ...defaultSegmentParams, userID: users["n-1"].pubID, votes: -5, timeSubmitted: 5, UUID: users["n-1"].info.last });
await db.prepare("run", sponsorTimesQuery, ["getUserInfo0", 0, 36000, 2,"uuid000009", getHash("getuserinfo_user_03"), 8, 10, "sponsor", "skip", 0]); // user["n-2"]
await db.prepare("run", sponsorTimesQuery, ["getUserInfo3", 1, 11, 2, "uuid000006", getHash("getuserinfo_user_02"), 6, 10, "sponsor", "skip", 0]); await insertSegment(db, { ...defaultSegmentParams, userID: users["n-2"].pubID, shadowHidden: true });
await db.prepare("run", sponsorTimesQuery, ["getUserInfo4", 1, 11, 2, "uuid000010", getHash("getuserinfo_user_04"), 9, 10, "chapter", "chapter", 0]); await insertSegment(db, { ...defaultSegmentParams, userID: users["n-2"].pubID, shadowHidden: true });
await db.prepare("run", sponsorTimesQuery, ["getUserInfo5", 1, 11, 2, "uuid000011", getHash("getuserinfo_user_05"), 9, 10, "sponsor", "skip", 0]); await insertSegment(db, { ...defaultSegmentParams, userID: users["n-2"].pubID, timeSubmitted: 5, UUID: users["n-2"].info.last });
await db.prepare("run", sponsorTimesQuery, ["getUserInfo6", 1, 11, 2, "uuid000012", getHash("getuserinfo_user_06"), 9, 10, "sponsor", "skip", 1]); // users n-3 to n-6
await db.prepare("run", sponsorTimesQuery, ["getUserInfo7", 1, 11, 2, "uuid000013", getHash("getuserinfo_ban_02"), 9, 10, "sponsor", "skip", 1]); await insertSegment(db, { ...defaultSegmentParams, userID: users["n-3"].pubID, UUID: users["n-3"].info.last, endTime: 36000 });
await insertSegment(db, { ...defaultSegmentParams, userID: users["n-4"].pubID, UUID: users["n-4"].info.last, category: "chapter", actionType: "chapter" });
await insertSegment(db, { ...defaultSegmentParams, userID: users["n-5"].pubID, UUID: users["n-5"].info.last });
await insertSegment(db, { ...defaultSegmentParams, userID: users["n-6"].pubID, UUID: users["n-6"].info.last, shadowHidden: true });
// ban-2
await insertSegment(db, { ...defaultSegmentParams, userID: users["ban-2"].pubID, UUID: users["ban-2"].info.last, shadowHidden: true });
const titlesQuery = 'INSERT INTO "titles" ("videoID", "title", "original", "userID", "service", "hashedVideoID", "timeSubmitted", "UUID") VALUES (?, ?, ?, ?, ?, ?, ?, ?)'; // user["n-1"]
const titleVotesQuery = 'INSERT INTO "titleVotes" ("UUID", "votes", "locked", "shadowHidden") VALUES (?, ?, ?, 0);'; const userN1Video = genRandomValue("video", "getUserInfo-n1");
const thumbnailsQuery = 'INSERT INTO "thumbnails" ("videoID", "original", "userID", "service", "hashedVideoID", "timeSubmitted", "UUID") VALUES (?, ?, ?, ?, ?, ?, ?)'; // title 1
const thumbnailVotesQuery = 'INSERT INTO "thumbnailVotes" ("UUID", "votes", "locked", "shadowHidden") VALUES (?, ?, ?, 0)'; const userN1UUID1 = genRandomValue("uuid", "getUserInfo-n1-u1");
await db.prepare("run", titlesQuery, ["getUserInfo6", "title0", 1, getHash("getuserinfo_user_01"), "YouTube", getHash("getUserInfo0"), 1, "uuid000001"]); await insertTitle(db, { userID: users["n-1"].pubID, timeSubmitted: 1, videoID: userN1Video, UUID: userN1UUID1 });
await db.prepare("run", titleVotesQuery, ["uuid000001", 0, 0]); await insertTitleVote(db, userN1UUID1, 0);
await db.prepare("run", thumbnailsQuery, ["getUserInfo6", 0, getHash("getuserinfo_user_01"), "YouTube", getHash("getUserInfo0"), 1, "uuid000002"]); // title 2
await db.prepare("run", thumbnailVotesQuery, ["uuid000002", 0, 0]); const userN1UUID2 = genRandomValue("uuid", "getUserInfo-n1-u2");
await db.prepare("run", titlesQuery, ["getUserInfo6", "title1", 0, getHash("getuserinfo_user_01"), "YouTube", getHash("getUserInfo0"), 2, "uuid000003"]); await insertTitle(db, { userID: users["n-1"].pubID, timeSubmitted: 2, videoID: userN1Video, UUID: userN1UUID2 });
await db.prepare("run", titleVotesQuery, ["uuid000003", -1, 0]); await insertTitleVote(db, userN1UUID2, -1);
// thumbnail 1
const userN1UUID3 = genRandomValue("uuid", "getUserInfo-n1-u3");
await insertThumbnail(db, { userID: users["n-1"].pubID, UUID: userN1UUID3 });
await insertThumbnailVote(db, userN1UUID3, 0);
const insertWarningQuery = 'INSERT INTO warnings ("userID", "issueTime", "issuerUserID", "enabled", "reason") VALUES (?, ?, ?, ?, ?)'; // warnings & bans
await db.prepare("run", insertWarningQuery, [getHash("getuserinfo_warning_0"), 10, "getuserinfo_vip", 1, "warning0-0"]); // warn-0
await db.prepare("run", insertWarningQuery, [getHash("getuserinfo_warning_1"), 20, "getuserinfo_vip", 1, "warning1-0"]); insertWarning(db, users["warn-0"].pubID, { reason: "warning0-0", issueTime: 10 });
await db.prepare("run", insertWarningQuery, [getHash("getuserinfo_warning_1"), 30, "getuserinfo_vip", 1, "warning1-1"]); // warn-1
await db.prepare("run", insertWarningQuery, [getHash("getuserinfo_warning_2"), 40, "getuserinfo_vip", 0, "warning2-0"]); insertWarning(db, users["warn-1"].pubID, { reason: "warning1-0", issueTime: 20 });
await db.prepare("run", insertWarningQuery, [getHash("getuserinfo_warning_3"), 50, "getuserinfo_vip", 1, "warning3-0"]); insertWarning(db, users["warn-1"].pubID, { reason: "warning1-1", issueTime: 30 });
await db.prepare("run", insertWarningQuery, [getHash("getuserinfo_warning_3"), 60, "getuserinfo_vip", 0, "warning3-1"]); // warn -2
insertWarning(db, users["warn-2"].pubID, { reason: "warning2-0", issueTime: 40, enabled: false });
// warn-3
insertWarning(db, users["warn-3"].pubID, { reason: "warning3-0", issueTime: 50 });
insertWarning(db, users["warn-3"].pubID, { reason: "warning3-1", issueTime: 60, enabled: false });
const insertBanQuery = 'INSERT INTO "shadowBannedUsers" ("userID") VALUES (?)'; // ban-
await db.prepare("run", insertBanQuery, [getHash("getuserinfo_ban_01")]); insertBan(db, users["ban-1"].pubID);
await db.prepare("run", insertBanQuery, [getHash("getuserinfo_ban_02")]); insertBan(db, users["ban-2"].pubID);
}); });
it("Should be able to get a 200", (done) => { it("Should be able to get a 200", () => statusTest(200, { userID: users["n-1"].privID }));
client.get(endpoint, { params: { userID: "getuserinfo_user_01" } })
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
});
it("Should be able to get a 400 (No userID parameter)", (done) => { // value tests
client.get(endpoint, { params: { userID: "" } })
.then(res => {
assert.strictEqual(res.status, 400);
done();
})
.catch(err => done(err));
});
it("Should be able to get user info", (done) => { it("Should get title and vote submission counts", () =>
client.get(endpoint, { params: { userID: "getuserinfo_user_01" } }) checkValues(users["n-1"], {
.then(res => { titleSubmissionCount: 1,
assert.strictEqual(res.status, 200); thumbnailSubmissionCount: 1
const expected = { })
userName: "Username user 01", );
userID: "66e7c974039ffb870a500a33eca3a3989861018909b938c313cf1a8a366800b8",
minutesSaved: 5,
viewCount: 30,
ignoredViewCount: 20,
segmentCount: 3,
ignoredSegmentCount: 2,
reputation: -1.5,
lastSegmentID: "uuid000005",
vip: false,
warnings: 0,
warningReason: ""
};
assert.deepStrictEqual(res.data, expected);
done();
})
.catch(err => done(err));
});
it("Should get warning data", (done) => { // fallback/ null tests
client.get(endpoint, { params: { userID: "getuserinfo_warning_0", value: "warnings" } }) it("Should return publidID if no username set", () => {
.then(res => { const user = users["n-2"];
assert.strictEqual(res.status, 200); return checkValues(user, {
const expected = { userName: user.pubID,
warnings: 1 });
};
assert.ok(partialDeepEquals(res.data, expected));
done();
})
.catch(err => done(err));
});
it("Should get warning data with public ID", (done) => {
client.get(endpoint, { params: { publicUserID: getHash("getuserinfo_warning_0"), values: `["warnings"]` } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = {
warnings: 1
};
assert.ok(partialDeepEquals(res.data, expected));
done();
})
.catch(err => done(err));
});
it("Should get multiple warnings", (done) => {
client.get(endpoint, { params: { userID: "getuserinfo_warning_1", value: "warnings" } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = {
warnings: 2
};
assert.ok(partialDeepEquals(res.data, expected));
done();
})
.catch(err => done(err));
});
it("Should not get warnings if none", (done) => {
client.get(endpoint, { params: { userID: "getuserinfo_warning_2", value: "warnings" } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = {
warnings: 0,
};
assert.ok(partialDeepEquals(res.data, expected));
done();
})
.catch(err => done(err));
});
it("Should done(userID for userName (No userName set)", (done) => {
client.get(endpoint, { params: { userID: "getuserinfo_user_02", value: "userName" } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = {
userName: "c2a28fd225e88f74945794ae85aef96001d4a1aaa1022c656f0dd48ac0a3ea0f"
};
assert.ok(partialDeepEquals(res.data, expected));
done();
})
.catch(err => done(err));
}); });
it("Should return null segment if none", (done) => { it("Should return null segment if none", (done) => {
client.get(endpoint, { params: { userID: "getuserinfo_null", value: "lastSegmentID" } }) const user = users["null"];
client.get(endpoint, { params: { userID: user.privID, value: "lastSegmentID" } })
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
assert.strictEqual(res.data.lastSegmentID, null); assert.strictEqual(res.data.lastSegmentID, null);
@@ -167,7 +127,8 @@ describe("getUserInfo", () => {
}); });
it("Should return zeroes if userid does not exist", (done) => { it("Should return zeroes if userid does not exist", (done) => {
client.get(endpoint, { params: { userID: "getuserinfo_null", value: "lastSegmentID" } }) const user = users["null"];
client.get(endpoint, { params: { userID: user.privID, value: "lastSegmentID" } })
.then(res => { .then(res => {
const data = res.data; const data = res.data;
for (const value in data) { for (const value in data) {
@@ -180,243 +141,174 @@ describe("getUserInfo", () => {
.catch(err => done(err)); .catch(err => done(err));
}); });
it("Should get warning reason from from single enabled warning", (done) => { // warnings
client.get(endpoint, { params: { userID: "getuserinfo_warning_0", values: `["warningReason"]` } }) it("Should get warning data with public ID", (done) => {
const user = users["warn-0"];
client.get(endpoint, { params: { publicUserID: user.pubID, values: `["warnings"]` } })
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
const expected = { const expected = {
warningReason: "warning0-0", warnings: 1
}; };
assert.ok(partialDeepEquals(res.data, expected)); assert.ok(partialDeepEquals(res.data, expected));
done(); // pass
})
.catch(err => done(err));
});
it("Should get most recent warning from two enabled warnings", (done) => {
client.get(endpoint, { params: { userID: "getuserinfo_warning_1", value: "warningReason" } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = {
warningReason: "warning1-1"
};
assert.ok(partialDeepEquals(res.data, expected));
done(); // pass
})
.catch(err => done(err));
});
it("Should not get disabled warning", (done) => {
client.get(endpoint, { params: { userID: "getuserinfo_warning_2", values: `["warnings","warningReason"]` } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = {
warnings: 0,
warningReason: ""
};
assert.ok(partialDeepEquals(res.data, expected));
done(); // pass
})
.catch(err => done(err));
});
it("Should not get newer disabled warning", (done) => {
client.get(`${endpoint}?userID=getuserinfo_warning_3&value=warnings&value=warningReason`)
.then(res => {
assert.strictEqual(res.status, 200);
const expected = {
warnings: 1,
warningReason: "warning3-0"
};
assert.ok(partialDeepEquals(res.data, expected));
done(); // pass
})
.catch(err => done(err));
});
it("Should get 400 if bad values specified", (done) => {
client.get(endpoint, { params: { userID: "getuserinfo_warning_3", value: "invalid-value" } })
.then(res => {
assert.strictEqual(res.status, 400);
done(); // pass
})
.catch(err => done(err));
});
it("Should get ban data for banned user (only appears when specifically requested)", (done) => {
client.get(endpoint, { params: { userID: "getuserinfo_ban_01", value: "banned" } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = {
banned: true
};
assert.ok(partialDeepEquals(res.data, expected));
done(); // pass
})
.catch(err => done(err));
});
it("Should get ban data for unbanned user (only appears when specifically requested)", (done) => {
client.get(endpoint, { params: { userID: "getuserinfo_notban_01", value: "banned" } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = {
banned: false
};
assert.ok(partialDeepEquals(res.data, expected));
done(); // pass
})
.catch(err => done(err));
});
it("Should throw 400 on bad json in values", (done) => {
client.get(endpoint, { params: { userID: "x", values: `[userID]` } })
.then(res => {
assert.strictEqual(res.status, 400);
done(); // pass
})
.catch(err => done(err));
});
it("Should throw 400 with invalid array", (done) => {
client.get(endpoint, { params: { userID: "x", values: 123 } })
.then(res => {
assert.strictEqual(res.status, 400);
done(); // pass
})
.catch(err => done(err));
});
it("Should return 200 on userID not found", (done) => {
client.get(endpoint, { params: { userID: "notused-userid" } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = {
minutesSaved: 0,
segmentCount: 0,
ignoredSegmentCount: 0,
viewCount: 0,
ignoredViewCount: 0,
warnings: 0,
warningReason: "",
reputation: 0,
vip: false,
};
assert.ok(partialDeepEquals(res.data, expected));
done(); // pass
})
.catch(err => done(err));
});
it("Should only count long segments as 10 minutes", (done) => {
client.get(endpoint, { params: { userID: "getuserinfo_user_03" } })
.then(res => {
assert.strictEqual(res.status, 200);
const expected = {
userName: "807e0a5d0a62c9c4365fae3d403e4618a3226f231314a898fa1555a0e55eab9e",
userID: "807e0a5d0a62c9c4365fae3d403e4618a3226f231314a898fa1555a0e55eab9e",
minutesSaved: 100,
viewCount: 10,
ignoredViewCount: 0,
segmentCount: 1,
ignoredSegmentCount: 0,
reputation: 0,
lastSegmentID: "uuid000009",
vip: false,
warnings: 0,
warningReason: ""
};
assert.deepStrictEqual(res.data, expected);
done(); done();
}) })
.catch(err => done(err)); .catch(err => done(err));
}); });
it("Should be able to get permissions", (done) => { it("Should get warning reason from from single enabled warning", () =>
client.get(endpoint, { params: { userID: "getuserinfo_user_01", value: "permissions" } }) checkValues(users["warn-0"], {
warnings: 1,
warningReason: "warning0-0",
})
);
it("Should get most recent warning from two enabled warnings", () =>
checkValues(users["warn-1"], {
warnings: 2,
warningReason: "warning1-1"
})
);
it("Should not get disabled warning", () =>
checkValues(users["warn-2"], {
warnings: 0,
warningReason: ""
})
);
it("Should not get newer disabled warning", () =>
checkValues(users["warn-3"], {
warnings: 1,
warningReason: "warning3-0"
})
);
// shadowban tests
it("Should get ban data for banned user (only appears when specifically requested)", () =>
checkValues(users["ban-1"], {
banned: true
})
);
it("Should return all segments of banned user", () =>
checkValues(users["ban-2"], {
segmentCount: 1
})
);
it("Should not return shadowhidden segments of not-banned user", () =>
checkValues(users["n-6"], {
segmentCount: 0,
banned: false
})
);
// error 400 testing
const statusTest = (status: number, params: Record<string, any>) =>
client.get(endpoint, { params })
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, status);
const expected = {
permissions: {
sponsor: true,
selfpromo: true,
exclusive_access: true,
interaction: true,
intro: true,
outro: true,
preview: true,
music_offtopic: true,
filler: true,
poi_highlight: true,
chapter: false,
},
};
assert.ok(partialDeepEquals(res.data, expected));
done(); // pass
}); });
});
it("Should ignore chapters for saved time calculations", (done) => { it("Should throw 400 on bad json in values", () => statusTest(400, { userID: "x", values: `[userID]` }));
client.get(endpoint, { params: { userID: "getuserinfo_user_04" } }) it("Should throw 400 with invalid array", () => statusTest(400, { userID: "x", values: 123 }));
it("Should throw 400 with empty userID)", () => statusTest(400, { userID: "" }));
it("Should throw 400 if bad values specified", () => statusTest(400, { userID: users["warn-3"].privID, value: "invalid-value" }));
// full user stats
const fullUserStats = (params: Record<string, any>, expected: Record<string, any>) =>
client.get(endpoint, { params })
.then(res => { .then(res => {
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
const expected = {
userName: "f187933817e7b0211a3f6f7d542a63ca9cc289d6cc8a8a79669d69a313671ccf",
userID: "f187933817e7b0211a3f6f7d542a63ca9cc289d6cc8a8a79669d69a313671ccf",
minutesSaved: 0,
viewCount: 10,
ignoredViewCount: 0,
segmentCount: 1,
ignoredSegmentCount: 0,
reputation: 0,
lastSegmentID: "uuid000010",
vip: false,
warnings: 0,
warningReason: ""
};
assert.deepStrictEqual(res.data, expected); assert.deepStrictEqual(res.data, expected);
done(); });
})
.catch(err => done(err)); const defaultUserInfo = {
minutesSaved: 0,
segmentCount: 0,
ignoredSegmentCount: 0,
viewCount: 0,
ignoredViewCount: 0,
warnings: 0,
warningReason: "",
reputation: 0,
lastSegmentID: "",
vip: false,
};
it("Should be able to get user info", () => {
const user = users["n-1"];
const params = { userID: user.privID };
return fullUserStats(params, {
...defaultUserInfo,
userName: user.info.username,
userID: user.pubID,
minutesSaved: 5,
viewCount: 30,
ignoredViewCount: 20,
segmentCount: 3,
ignoredSegmentCount: 2,
reputation: -1.5,
lastSegmentID: user.info.last,
});
}); });
it("Should get title and vote submission counts", (done) => { it("Should only count long segments as 10 minutes", () => {
client.get(endpoint, { params: { userID: "getuserinfo_user_01", value: ["titleSubmissionCount", "thumbnailSubmissionCount"] } }) const user = users["n-3"];
.then(res => { const params = { userID: user.privID };
assert.strictEqual(res.status, 200); return fullUserStats(params, {
const expected = { ...defaultUserInfo,
titleSubmissionCount: 1, userName: user.pubID,
thumbnailSubmissionCount: 1 userID: user.pubID,
}; minutesSaved: 100,
assert.ok(partialDeepEquals(res.data, expected)); viewCount: 10,
done(); segmentCount: 1,
}) lastSegmentID: user.info.last,
.catch(err => done(err)); });
}); });
it("Should return all segments of banned user", (done) => { it("Should be able to get permissions", () => {
client.get(endpoint, { params: { userID: "getuserinfo_ban_02", value: ["segmentCount"] } }) const user = users["n-1"];
.then(res => { const params = { userID: user.privID, value: "permissions" };
assert.strictEqual(res.status, 200); return fullUserStats(params, {
const expected = { permissions: {
segmentCount: 1 sponsor: true,
}; selfpromo: true,
assert.ok(partialDeepEquals(res.data, expected)); exclusive_access: true,
done(); // pass interaction: true,
}) intro: true,
.catch(err => done(err)); outro: true,
preview: true,
music_offtopic: true,
filler: true,
poi_highlight: true,
chapter: false,
},
});
}); });
it("Should not return shadowhidden segments of not-banned user", (done) => { it("Should ignore chapters for saved time calculations", () => {
client.get(endpoint, { params: { userID: "getuserinfo_user_06", value: ["segmentCount"] } }) const user = users["n-4"];
.then(res => { const params = { userID: user.privID };
assert.strictEqual(res.status, 200); return fullUserStats(params, {
const expected = { ...defaultUserInfo,
segmentCount: 0 userName: user.pubID,
}; userID: user.pubID,
assert.ok(partialDeepEquals(res.data, expected)); viewCount: 10,
done(); // pass segmentCount: 1,
}) lastSegmentID: user.info.last,
.catch(err => done(err)); });
});
it("Should return 200 on userID not found", () => {
const user = users["null"];
const params = { userID: user.privID };
return fullUserStats(params, {
...defaultUserInfo,
userName: user.pubID,
userID: user.pubID,
lastSegmentID: null
});
}); });
}); });

View File

@@ -1,7 +1,8 @@
import { getHash } from "../../src/utils/getHash";
import { db } from "../../src/databases/databases"; import { db } from "../../src/databases/databases";
import { client } from "../utils/httpClient"; import { client } from "../utils/httpClient";
import assert from "assert"; import assert from "assert";
import { genUsers, User } from "../utils/genUser";
import { insertSegment } from "../utils/segmentQueryGen";
// helpers // helpers
const endpoint = "/api/getViewsForUser"; const endpoint = "/api/getViewsForUser";
@@ -10,53 +11,46 @@ const getViewsForUser = (userID: string) => client({
params: { userID } params: { userID }
}); });
const getViewUserOne = "getViewUser1"; const cases = [
const userOneViewsFirst = 30; "u-1",
const userOneViewsSecond = 0; "u-2",
"u-3"
];
const users = genUsers("getViewUser", cases);
const getViewUserTwo = "getViewUser2"; // set views for users
const userTwoViews = 0; users["u-1"].info["views1"] = 30;
users["u-1"].info["views2"] = 0;
const getViewUserThree = "getViewUser3"; users["u-1"].info["views"] = users["u-1"].info.views1 + users["u-1"].info.views2;
users["u-2"].info["views"] = 0;
users["u-3"].info["views"] = 0;
const checkUserViews = (user: User) =>
getViewsForUser(user.privID)
.then(result => {
assert.strictEqual(result.status, 200);
assert.strictEqual(result.data.viewCount, user.info.views);
});
describe("getViewsForUser", function() { describe("getViewsForUser", function() {
before(() => { before(() => {
const insertSponsorTimeQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "actionType", "videoDuration", "shadowHidden", "hashedVideoID") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; // add views for users
db.prepare("run", insertSponsorTimeQuery, ["getViewUserVideo", 0, 1, 0, "getViewUserVideo0", getHash(getViewUserOne), 0, userOneViewsFirst, "sponsor", "skip", 0, 0, "getViewUserVideo"]); insertSegment(db, { userID: users["u-1"].pubID, views: users["u-1"].info.views1 });
db.prepare("run", insertSponsorTimeQuery, ["getViewUserVideo", 0, 1, 0, "getViewUserVideo1", getHash(getViewUserOne), 0, userOneViewsSecond, "sponsor", "skip", 0, 0, "getViewUserVideo"]); insertSegment(db, { userID: users["u-1"].pubID, views: users["u-1"].info.views2 });
db.prepare("run", insertSponsorTimeQuery, ["getViewUserVideo", 0, 1, 0, "getViewUserVideo2", getHash(getViewUserTwo), 0, userTwoViews, "sponsor", "skip", 0, 0, "getViewUserVideo"]); insertSegment(db, { userID: users["u-2"].pubID, views: users["u-2"].info.views });
}); });
it("Should get back views for user one", (done) => { it("Should get back views for user one", () =>
getViewsForUser(getViewUserOne) checkUserViews(users["u-1"])
.then(result => { );
assert.strictEqual(result.data.viewCount, userOneViewsFirst + userOneViewsSecond); it("Should get back views for user two", () =>
done(); checkUserViews(users["u-2"])
}) );
.catch(err => done(err)); it("Should get 404 if no submissions", () =>
}); getViewsForUser(users["u-3"].pubID)
it("Should get back views for user two", (done) => { .then(result => assert.strictEqual(result.status, 404))
getViewsForUser(getViewUserTwo) );
.then(result => { it("Should return 400 if no userID provided", () =>
assert.strictEqual(result.data.viewCount, userTwoViews);
done();
})
.catch(err => done(err));
});
it("Should get 404 if no submissions", (done) => {
getViewsForUser(getViewUserThree)
.then(result => {
assert.strictEqual(result.status, 404);
done();
})
.catch(err => done(err));
});
it("Should return 400 if no userID provided", (done) => {
client({ url: endpoint }) client({ url: endpoint })
.then(res => { .then(res => assert.strictEqual(res.status, 400))
assert.strictEqual(res.status, 400); );
done();
})
.catch(err => done(err));
});
}); });

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,62 +1,46 @@
import { db } from "../../src/databases/databases"; import { db } from "../../src/databases/databases";
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 { genUsers, User } from "../utils/genUser";
import { insertSegment, insertVip } from "../utils/queryGen";
const VIPUser = "clearCacheVIP";
const regularUser = "regular-user";
const endpoint = "/api/clearCache"; const endpoint = "/api/clearCache";
const postClearCache = (userID: string, videoID: string) => client({ method: "post", url: endpoint, params: { userID, videoID } }); const postClearCache = (user: User, videoID: string) => client({ method: "post", url: endpoint, params: { userID: user.privID, videoID } });
const cases = [
"vip",
"normal",
];
const users = genUsers("postClearCache", cases);
describe("postClearCache", () => { describe("postClearCache", () => {
before(async () => { before(async () => {
await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES ('${getHash(VIPUser)}')`); await insertVip(db, users["vip"].pubID);
const startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", "views", "category", "shadowHidden") VALUES'; await insertSegment(db, { videoID: "clear-test" });
await db.prepare("run", `${startOfQuery}('clear-test', 0, 1, 2, 'clear-uuid', 'testman', 0, 50, 'sponsor', 0)`);
}); });
it("Should be able to clear cache for existing video", (done) => { it("Should be able to clear cache for existing video", () =>
postClearCache(VIPUser, "clear-test") postClearCache(users["vip"], "clear-test")
.then(res => { .then(res => assert.strictEqual(res.status, 200))
assert.strictEqual(res.status, 200); );
done();
})
.catch(err => done(err));
});
it("Should be able to clear cache for nonexistent video", (done) => { it("Should be able to clear cache for nonexistent video", () =>
postClearCache(VIPUser, "dne-video") postClearCache(users["vip"], "dne-video")
.then(res => { .then(res => assert.strictEqual(res.status, 200))
assert.strictEqual(res.status, 200); );
done();
})
.catch(err => done(err));
});
it("Should get 403 as non-vip", (done) => { it("Should get 403 as non-vip", () =>
postClearCache(regularUser, "clear-test") postClearCache(users["normal"], "clear-test")
.then(res => { .then(res => assert.strictEqual(res.status, 403))
assert.strictEqual(res.status, 403); );
done();
})
.catch(err => done(err));
});
it("Should give 400 with missing videoID", (done) => { it("Should give 400 with missing videoID", () =>
client.post(endpoint, { params: { userID: VIPUser } }) client.post(endpoint, { params: { userID: users["vip"].privID } })
.then(res => { .then(res => assert.strictEqual(res.status, 400))
assert.strictEqual(res.status, 400); );
done();
})
.catch(err => done(err));
});
it("Should give 400 with missing userID", (done) => { it("Should give 400 with missing userID", () =>
client.post(endpoint, { params: { videoID: "clear-test" } }) client.post(endpoint, { params: { videoID: "clear-test" } })
.then(res => { .then(res => assert.strictEqual(res.status, 400))
assert.strictEqual(res.status, 400); );
done();
})
.catch(err => done(err));
});
}); });

View File

@@ -9,17 +9,20 @@ const randKey2 = genRandom(16);
const randKey3 = genRandom(); const randKey3 = genRandom();
const randValue3 = genRandom(); const randValue3 = genRandom();
const redisGetCheck = (key: string, expected: string | null, done: Mocha.Done): Promise<void> =>
redis.get(key)
.then(res => {
assert.strictEqual(res, expected);
done();
}).catch(err => done(err));
describe("redis test", function() { describe("redis test", function() {
before(async function() { before(async function() {
if (!config.redis?.enabled) this.skip(); if (!config.redis?.enabled) this.skip();
await redis.set(randKey1, randValue1); await redis.set(randKey1, randValue1);
}); });
it("Should get stored value", (done) => { it("Should get stored value", (done) => {
redis.get(randKey1) redisGetCheck(randKey1, randValue1, done);
.then(res => {
assert.strictEqual(res, randValue1);
done();
}).catch(err => done(err));
}); });
it("Should not be able to get not stored value", (done) => { it("Should not be able to get not stored value", (done) => {
redis.get(randKey2) redis.get(randKey2)
@@ -30,23 +33,13 @@ describe("redis test", function() {
}); });
it("Should be able to delete stored value", (done) => { it("Should be able to delete stored value", (done) => {
redis.del(randKey1) redis.del(randKey1)
.then(() => { .catch(err => done(err))
redis.get(randKey1) .then(() => redisGetCheck(randKey1, null, done));
.then(res => {
assert.strictEqual(res, null);
done();
}).catch(err => done(err));
}).catch(err => done(err));
}); });
it("Should be able to set expiring value", (done) => { it("Should be able to set expiring value", (done) => {
redis.setEx(randKey3, 8400, randValue3) redis.setEx(randKey3, 8400, randValue3)
.then(() => { .catch(err => done(err))
redis.get(randKey3) .then(() => redisGetCheck(randKey3, randValue3, done));
.then(res => {
assert.strictEqual(res, randValue3);
done();
}).catch(err => done(err));
}).catch(err => done(err));
}); });
it("Should continue when undefined value is fetched", (done) => { it("Should continue when undefined value is fetched", (done) => {
const undefkey = `undefined.${genRandom()}`; const undefkey = `undefined.${genRandom()}`;

View File

@@ -1,31 +1,24 @@
import assert from "assert"; import assert from "assert";
import { db } from "../../src/databases/databases"; import { db } from "../../src/databases/databases";
import { UserID } from "../../src/types/user.model";
import { getHash } from "../../src/utils/getHash";
import { getReputation, calculateReputationFromMetrics } from "../../src/utils/reputation"; import { getReputation, calculateReputationFromMetrics } from "../../src/utils/reputation";
import { genUsers } from "../utils/genUser";
describe("reputation", () => { describe("reputation", () => {
// constants // user definitions
const userIDLowSubmissions = "reputation-lowsubmissions" as UserID; const cases = [
const userHashLowSubmissions = getHash(userIDLowSubmissions); "locking-vip",
const userIDHighDownvotes = "reputation-highdownvotes" as UserID; "low-submissions",
const userHashHighDownvotes = getHash(userIDHighDownvotes); "high-downvotes",
const userIDLowNonSelfDownvotes = "reputation-lownonselfdownvotes" as UserID; "low-non-self-downvotes",
const userHashLowNonSelfDownvotes = getHash(userIDLowNonSelfDownvotes); "high-non-self-downvotes",
const userIDHighNonSelfDownvotes = "reputation-highnonselfdownvotes" as UserID; "new-submissions",
const userHashHighNonSelfDownvotes = getHash(userIDHighNonSelfDownvotes); "low-sum",
const userIDNewSubmissions = "reputation-newsubmissions" as UserID; "high-rep-before-manual-vote",
const userHashNewSubmissions = getHash(userIDNewSubmissions); "high-rep",
const userIDLowSum = "reputation-lowsum" as UserID; "high-rep-locked",
const userHashLowSum = getHash(userIDLowSum); "have-most-upvoted-in-locked-video"
const userIDHighRepBeforeManualVote = "reputation-oldhighrep" as UserID; ];
const userHashHighRepBeforeManualVote = getHash(userIDHighRepBeforeManualVote); const users = genUsers("reputation", cases);
const userIDHighRep = "reputation-highrep" as UserID;
const userHashHighRep = getHash(userIDHighRep);
const userIDHighRepAndLocked = "reputation-highlockedrep" as UserID;
const userHashHighAndLocked = getHash(userIDHighRepAndLocked);
const userIDHaveMostUpvotedInLockedVideo = "reputation-mostupvotedaslocked" as UserID;
const userHashHaveMostUpvotedInLockedVideo = getHash(userIDHaveMostUpvotedInLockedVideo);
before(async function() { before(async function() {
this.timeout(5000); // this preparation takes longer then usual this.timeout(5000); // this preparation takes longer then usual
@@ -33,113 +26,113 @@ describe("reputation", () => {
const videoID2 = "reputation-videoID-2"; const videoID2 = "reputation-videoID-2";
const sponsorTimesInsertQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "hidden", "shadowHidden") VALUES(?,?,?,?,?,?,?,?,?,?,?,?)'; const sponsorTimesInsertQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "hidden", "shadowHidden") VALUES(?,?,?,?,?,?,?,?,?,?,?,?)';
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-0-uuid-0", userHashLowSubmissions, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-0-uuid-0", users["low-submissions"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-0-uuid-1", userHashLowSubmissions, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-0-uuid-1", users["low-submissions"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 100, 0, "reputation-0-uuid-2", userHashLowSubmissions, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 100, 0, "reputation-0-uuid-2", users["low-submissions"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-1-uuid-0", userHashHighDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-1-uuid-0", users["high-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, "reputation-1-uuid-1", userHashHighDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, "reputation-1-uuid-1", users["high-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, "reputation-1-uuid-2", userHashHighDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, "reputation-1-uuid-2", users["high-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, "reputation-1-uuid-3", userHashHighDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, "reputation-1-uuid-3", users["high-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, "reputation-1-uuid-4", userHashHighDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -2, 0, "reputation-1-uuid-4", users["high-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-1-uuid-5", userHashHighDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-1-uuid-5", users["high-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-uuid-6", userHashHighDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-uuid-6", users["high-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-uuid-7", userHashHighDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-uuid-7", users["high-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
// First video is considered a normal downvote, second is considered a self-downvote (ie. they didn't resubmit to fix their downvote) // First video is considered a normal downvote, second is considered a self-downvote (ie. they didn't resubmit to fix their downvote)
await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}A`, 1, 11, 2, 0, "reputation-1-1-uuid-0", userHashLowNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}A`, 1, 11, 2, 0, "reputation-1-1-uuid-0", users["low-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
// Different category, same video // Different category, same video
await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}A`, 1, 11, -2, 0, "reputation-1-1-uuid-1", userHashLowNonSelfDownvotes, 1606240000000, 50, "intro", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}A`, 1, 11, -2, 0, "reputation-1-1-uuid-1", users["low-non-self-downvotes"].pubID, 1606240000000, 50, "intro", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-2", userHashLowNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-2", users["low-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-3", userHashLowNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-3", users["low-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-4", userHashLowNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-4", users["low-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-1-1-uuid-5", userHashLowNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-1-1-uuid-5", users["low-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-6", userHashLowNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-6", users["low-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-7", userHashLowNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-uuid-7", users["low-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
// First videos is considered a normal downvote, last is considered a self-downvote (ie. they didn't resubmit to fix their downvote) // First videos is considered a normal downvote, last is considered a self-downvote (ie. they didn't resubmit to fix their downvote)
await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}A`, 1, 11, 2, 0, "reputation-1-1-1-uuid-0", userHashHighNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}A`, 1, 11, 2, 0, "reputation-1-1-1-uuid-0", users["high-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
// Different category, same video // Different category, same video
await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}A`, 1, 11, -2, 0, "reputation-1-1-1-uuid-1", userHashHighNonSelfDownvotes, 1606240000000, 50, "intro", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}A`, 1, 11, -2, 0, "reputation-1-1-1-uuid-1", users["high-non-self-downvotes"].pubID, 1606240000000, 50, "intro", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}B`, 1, 11, -2, 0, "reputation-1-1-1-uuid-1-b", userHashHighNonSelfDownvotes, 1606240000000, 50, "intro", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}B`, 1, 11, -2, 0, "reputation-1-1-1-uuid-1-b", users["high-non-self-downvotes"].pubID, 1606240000000, 50, "intro", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}C`, 1, 11, -2, 0, "reputation-1-1-1-uuid-1-c", userHashHighNonSelfDownvotes, 1606240000000, 50, "intro", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [`${videoID}C`, 1, 11, -2, 0, "reputation-1-1-1-uuid-1-c", users["high-non-self-downvotes"].pubID, 1606240000000, 50, "intro", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-1-uuid-2", userHashHighNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-1-uuid-2", users["high-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-1-uuid-3", userHashHighNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-1-uuid-3", users["high-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-1-uuid-4", userHashHighNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-1-uuid-4", users["high-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-1-1-1-uuid-5", userHashHighNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-1-1-1-uuid-5", users["high-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-1-uuid-6", userHashHighNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-1-uuid-6", users["high-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-1-uuid-7", userHashHighNonSelfDownvotes, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-1-1-1-uuid-7", users["high-non-self-downvotes"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-0", userHashNewSubmissions, Date.now(), 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-0", users["new-submissions"].pubID, Date.now(), 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-1", userHashNewSubmissions, Date.now(), 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-1", users["new-submissions"].pubID, Date.now(), 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-2", userHashNewSubmissions, Date.now(), 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-2", users["new-submissions"].pubID, Date.now(), 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-3", userHashNewSubmissions, Date.now(), 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-3", users["new-submissions"].pubID, Date.now(), 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-4", userHashNewSubmissions, Date.now(), 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-2-uuid-4", users["new-submissions"].pubID, Date.now(), 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-2-uuid-5", userHashNewSubmissions, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-2-uuid-5", users["new-submissions"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-2-uuid-6", userHashNewSubmissions, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-2-uuid-6", users["new-submissions"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-2-uuid-7", userHashNewSubmissions, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-2-uuid-7", users["new-submissions"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-3-uuid-0", userHashLowSum, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-3-uuid-0", users["low-sum"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 1, 0, "reputation-3-uuid-1", userHashLowSum, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 1, 0, "reputation-3-uuid-1", users["low-sum"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-3-uuid-2", userHashLowSum, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-3-uuid-2", users["low-sum"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-3-uuid-3", userHashLowSum, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-3-uuid-3", users["low-sum"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 1, 0, "reputation-3-uuid-4", userHashLowSum, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 1, 0, "reputation-3-uuid-4", users["low-sum"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-3-uuid-5", userHashLowSum, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-3-uuid-5", users["low-sum"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-3-uuid-6", userHashLowSum, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-3-uuid-6", users["low-sum"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-3-uuid-7", userHashLowSum, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-3-uuid-7", users["low-sum"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-0", userHashHighRepBeforeManualVote, 0, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-0", users["high-rep-before-manual-vote"].pubID, 0, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-1", userHashHighRepBeforeManualVote, 0, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-1", users["high-rep-before-manual-vote"].pubID, 0, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-2", userHashHighRepBeforeManualVote, 0, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-2", users["high-rep-before-manual-vote"].pubID, 0, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-3", userHashHighRepBeforeManualVote, 0, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-3", users["high-rep-before-manual-vote"].pubID, 0, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-4", userHashHighRepBeforeManualVote, 0, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-4-uuid-4", users["high-rep-before-manual-vote"].pubID, 0, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-4-uuid-5", userHashHighRepBeforeManualVote, 0, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-4-uuid-5", users["high-rep-before-manual-vote"].pubID, 0, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-4-uuid-6", userHashHighRepBeforeManualVote, 0, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-4-uuid-6", users["high-rep-before-manual-vote"].pubID, 0, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-4-uuid-7", userHashHighRepBeforeManualVote, 0, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-4-uuid-7", users["high-rep-before-manual-vote"].pubID, 0, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-0", userHashHighRep, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-0", users["high-rep"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-1", userHashHighRep, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-1", users["high-rep"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-2", userHashHighRep, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-2", users["high-rep"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-3", userHashHighRep, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-3", users["high-rep"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-4", userHashHighRep, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-5-uuid-4", users["high-rep"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-5-uuid-5", userHashHighRep, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-5-uuid-5", users["high-rep"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-5-uuid-6", userHashHighRep, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-5-uuid-6", users["high-rep"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-5-uuid-7", userHashHighRep, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-5-uuid-7", users["high-rep"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, "reputation-6-uuid-0", userHashHighAndLocked, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, "reputation-6-uuid-0", users["high-rep-locked"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, "reputation-6-uuid-1", userHashHighAndLocked, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, "reputation-6-uuid-1", users["high-rep-locked"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, "reputation-6-uuid-2", userHashHighAndLocked, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, "reputation-6-uuid-2", users["high-rep-locked"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, "reputation-6-uuid-3", userHashHighAndLocked, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 1, "reputation-6-uuid-3", users["high-rep-locked"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-6-uuid-4", userHashHighAndLocked, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-6-uuid-4", users["high-rep-locked"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-6-uuid-5", userHashHighAndLocked, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-6-uuid-5", users["high-rep-locked"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-6-uuid-6", userHashHighAndLocked, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-6-uuid-6", users["high-rep-locked"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-6-uuid-7", userHashHighAndLocked, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-6-uuid-7", users["high-rep-locked"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
//Record has most upvoted //Record has most upvoted
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 5, 0, "reputation-7-uuid-0", userHashHaveMostUpvotedInLockedVideo, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 5, 0, "reputation-7-uuid-0", users["have-most-upvoted-in-locked-video"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 101, 0, "reputation-7-uuid-1", userHashHaveMostUpvotedInLockedVideo, 1606240000000, 50, "intro", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 101, 0, "reputation-7-uuid-1", users["have-most-upvoted-in-locked-video"].pubID, 1606240000000, 50, "intro", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID2, 1, 11, 5, 0, "reputation-7-uuid-8", userHashHaveMostUpvotedInLockedVideo, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID2, 1, 11, 5, 0, "reputation-7-uuid-8", users["have-most-upvoted-in-locked-video"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID2, 1, 11, 0, 0, "reputation-7-uuid-9", userHashHaveMostUpvotedInLockedVideo, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID2, 1, 11, 0, 0, "reputation-7-uuid-9", users["have-most-upvoted-in-locked-video"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
// other segments // other segments
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-7-uuid-2", userHashHaveMostUpvotedInLockedVideo, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-7-uuid-2", users["have-most-upvoted-in-locked-video"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-7-uuid-3", userHashHaveMostUpvotedInLockedVideo, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-7-uuid-3", users["have-most-upvoted-in-locked-video"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-7-uuid-4", userHashHaveMostUpvotedInLockedVideo, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, "reputation-7-uuid-4", users["have-most-upvoted-in-locked-video"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-7-uuid-5", userHashHaveMostUpvotedInLockedVideo, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, -1, 0, "reputation-7-uuid-5", users["have-most-upvoted-in-locked-video"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-7-uuid-6", userHashHaveMostUpvotedInLockedVideo, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-7-uuid-6", users["have-most-upvoted-in-locked-video"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-7-uuid-7", userHashHaveMostUpvotedInLockedVideo, 1606240000000, 50, "sponsor", 0, 0]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 0, 0, "reputation-7-uuid-7", users["have-most-upvoted-in-locked-video"].pubID, 1606240000000, 50, "sponsor", 0, 0]);
// lock video // lock video
const insertVipUserQuery = 'INSERT INTO "vipUsers" ("userID") VALUES (?)'; const insertVipUserQuery = 'INSERT INTO "vipUsers" ("userID") VALUES (?)';
await db.prepare("run", insertVipUserQuery, [getHash("VIPUser-getLockCategories")]); await db.prepare("run", insertVipUserQuery, [users["locking-vip"].pubID]);
const insertLockCategoryQuery = 'INSERT INTO "lockCategories" ("userID", "videoID", "category") VALUES (?, ?, ?)'; const insertLockCategoryQuery = 'INSERT INTO "lockCategories" ("userID", "videoID", "category") VALUES (?, ?, ?)';
await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), videoID, "sponsor"]); await db.prepare("run", insertLockCategoryQuery, [users["locking-vip"].pubID, videoID, "sponsor"]);
await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), videoID, "intro"]); await db.prepare("run", insertLockCategoryQuery, [users["locking-vip"].pubID, videoID, "intro"]);
await db.prepare("run", insertLockCategoryQuery, [getHash("VIPUser-getLockCategories"), videoID2, "sponsor"]); await db.prepare("run", insertLockCategoryQuery, [users["locking-vip"].pubID, videoID2, "sponsor"]);
}); });
it("user in grace period", async () => { it("user in grace period", async () => {
const data = await getReputation(getHash(userIDLowSubmissions)); const data = await getReputation(users["low-submissions"].privID);
assert.strictEqual(data, 0); assert.strictEqual(data, 0);
}); });
@@ -154,7 +147,7 @@ describe("reputation", () => {
oldUpvotedSubmissions: 1, oldUpvotedSubmissions: 1,
mostUpvotedInLockedVideoSum: 0 mostUpvotedInLockedVideoSum: 0
}; };
const data = await getReputation(getHash(userIDHighDownvotes)); const data = await getReputation(users["high-downvotes"].pubID);
assert.strictEqual(data, calculateReputationFromMetrics(metrics)); assert.strictEqual(data, calculateReputationFromMetrics(metrics));
assert.strictEqual(data, -1.7500000000000002); assert.strictEqual(data, -1.7500000000000002);
}); });
@@ -170,26 +163,26 @@ describe("reputation", () => {
oldUpvotedSubmissions: 1, oldUpvotedSubmissions: 1,
mostUpvotedInLockedVideoSum: 0 mostUpvotedInLockedVideoSum: 0
}; };
const data = await getReputation(userHashLowNonSelfDownvotes); const data = await getReputation(users["low-non-self-downvotes"].pubID);
assert.strictEqual(data, calculateReputationFromMetrics(metrics)); assert.strictEqual(data, calculateReputationFromMetrics(metrics));
assert.strictEqual(data, 0); assert.strictEqual(data, 0);
}); });
it("user with high non self downvote ratio", async () => { it("user with high non self downvote ratio", async () => {
const data = await getReputation(userHashHighNonSelfDownvotes); const data = await getReputation(users["high-non-self-downvotes"].pubID);
assert.strictEqual(data, -2.5); assert.strictEqual(data, -2.5);
}); });
it("user with mostly new submissions", async () => { it("user with mostly new submissions", async () => {
assert.strictEqual(await getReputation(userHashNewSubmissions), 0); assert.strictEqual(await getReputation(users["new-submissions"].pubID), 0);
}); });
it("user with not enough vote sum", async () => { it("user with not enough vote sum", async () => {
assert.strictEqual(await getReputation(userHashLowSum), 0); assert.strictEqual(await getReputation(users["low-sum"].pubID), 0);
}); });
it("user with lots of old votes (before autovote was disabled) ", async () => { it("user with lots of old votes (before autovote was disabled) ", async () => {
assert.strictEqual(await getReputation(userHashHighRepBeforeManualVote), 0); assert.strictEqual(await getReputation(users["high-rep-before-manual-vote"].pubID), 0);
}); });
it("user with high reputation", async () => { it("user with high reputation", async () => {
@@ -203,7 +196,7 @@ describe("reputation", () => {
oldUpvotedSubmissions: 5, oldUpvotedSubmissions: 5,
mostUpvotedInLockedVideoSum: 0 mostUpvotedInLockedVideoSum: 0
}; };
const data = await getReputation(userHashHighRep); const data = await getReputation(users["high-rep"].pubID);
assert.strictEqual(data, calculateReputationFromMetrics(metrics)); assert.strictEqual(data, calculateReputationFromMetrics(metrics));
assert.strictEqual(data, 0.19310344827586207); assert.strictEqual(data, 0.19310344827586207);
}); });
@@ -219,7 +212,7 @@ describe("reputation", () => {
oldUpvotedSubmissions: 5, oldUpvotedSubmissions: 5,
mostUpvotedInLockedVideoSum: 4 mostUpvotedInLockedVideoSum: 4
}; };
const data = await getReputation(userHashHighAndLocked); const data = await getReputation(users["high-rep-locked"].pubID);
assert.strictEqual(data, calculateReputationFromMetrics(metrics)); assert.strictEqual(data, calculateReputationFromMetrics(metrics));
assert.strictEqual(data, 3.393103448275862); assert.strictEqual(data, 3.393103448275862);
}); });
@@ -235,7 +228,7 @@ describe("reputation", () => {
oldUpvotedSubmissions: 6, oldUpvotedSubmissions: 6,
mostUpvotedInLockedVideoSum: 2 mostUpvotedInLockedVideoSum: 2
}; };
const data = await getReputation(userHashHaveMostUpvotedInLockedVideo); const data = await getReputation(users["have-most-upvoted-in-locked-video"].pubID);
assert.strictEqual(data, calculateReputationFromMetrics(metrics)); assert.strictEqual(data, calculateReputationFromMetrics(metrics));
assert.strictEqual(data, 6.158620689655172); assert.strictEqual(data, 6.158620689655172);
}); });

View File

@@ -5,29 +5,23 @@ import { getHash } from "../../src/utils/getHash";
import { client } from "../utils/httpClient"; import { client } from "../utils/httpClient";
describe("userCounter", () => { describe("userCounter", () => {
it("Should return 200", function (done) { it("Should return 200", function () {
if (!config.userCounterURL) this.skip(); // skip if no userCounterURL is set if (!config.userCounterURL) this.skip(); // skip if no userCounterURL is set
axios.request({ return axios.request({
method: "POST", method: "POST",
baseURL: config.userCounterURL, baseURL: config.userCounterURL,
url: "/api/v1/addIP", url: "/api/v1/addIP",
params: { params: {
hashedIP: getHash("127.0.0.1",1) hashedIP: getHash("127.0.0.1",1)
} }
}) }).then(res => assert.strictEqual(res.status, 200));
.then(res => {
assert.strictEqual(res.status, 200);
done();
})
.catch(err => done(err));
}); });
it("Should not incremeent counter on OPTIONS", function (done) { it("Should not incremeent counter on OPTIONS", function () {
/* cannot spy test */ /* cannot spy test */
if (!config.userCounterURL) this.skip(); // skip if no userCounterURL is set if (!config.userCounterURL) this.skip(); // skip if no userCounterURL is set
//const spy = sinon.spy(UserCounter); //const spy = sinon.spy(UserCounter);
client({ method: "OPTIONS", url: "/api/status" }) return client({ method: "OPTIONS", url: "/api/status" })
.then(() => client({ method: "GET", url: "/api/status" })); .then(() => client({ method: "GET", url: "/api/status" }));
//assert.strictEqual(spy.callCount, 1); //assert.strictEqual(spy.callCount, 1);
done();
}); });
}); });

View File

@@ -106,20 +106,16 @@ describe("VideoID Validation - postSkipSegments", () => {
done(); done();
}); });
it(`Should return 400 for invalid videoID`, (done) => { it(`Should return 400 for invalid videoID`, () =>
postSkipSegments("123456").then(res => { postSkipSegments("123456").then(res => {
assert.strictEqual(res.status, 400); assert.strictEqual(res.status, 400);
assert.strictEqual(res.data, expectedError); assert.strictEqual(res.data, expectedError);
done();
}) })
.catch(err => done(err)); );
});
it(`Should return 200 for valid videoID`, (done) => { it(`Should return 200 for valid videoID`, () =>
postSkipSegments("dQw4w9WgXcQ").then(res => { postSkipSegments("dQw4w9WgXcQ").then(res =>
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200)
done(); )
}) );
.catch(err => done(err));
});
}); });

43
test/utils/genUser.ts Normal file
View File

@@ -0,0 +1,43 @@
import { genRandom } from "./getRandom";
import { UserID, HashedUserID } from "../../src/types/user.model";
import { getHash } from "../../src/utils/getHash";
type info = Record<string, any>
export interface User {
privID: UserID,
pubID: HashedUserID
info: info
}
export type userArray = Record<string, User>
export interface UsernameUser extends User {
username: string
}
export type usernameUserArray = Record<string, UsernameUser>
export const genUser = (fnname: string, testcase: string, info: info = {}): User => {
const privID = `${fnname}-${testcase}-${genRandom(2)}` as UserID;
const pubID = getHash(privID);
return { privID, pubID, info };
};
export const genAnonUser = (info: info = {}): User => {
const privID = `user-${genRandom()}` as UserID;
const pubID = getHash(privID);
return { privID, pubID, info };
};
export const genUsers = (fnname: string, testcase: string[]): userArray => {
const users: userArray = {};
for (const tc of testcase)
users[tc] = genUser(fnname, tc);
return users;
};
export const genUsersUsername = (fnname: string, case_usernames: Map<string, string>): usernameUserArray => {
const cases = Array.from(case_usernames.keys());
const users = genUsers(fnname, cases);
case_usernames.forEach((username, tc) => (users[tc] as UsernameUser).username = username);
return users as usernameUserArray;
};

View File

@@ -1,3 +1,10 @@
import crypto from "crypto"; import crypto from "crypto";
export const genRandom = (bytes=8) => crypto.pseudoRandomBytes(bytes).toString("hex"); export const genRandom = (bytes=8): string => crypto.pseudoRandomBytes(bytes).toString("hex");
export const genRandomValue = (prefix: string, identifier: string, bytes=8): string => `${prefix}-${identifier}-${genRandom(bytes)}`;
export const multiGenRandomValue = (prefix: string, identifier: string, count: number, bytes=8): string[] => {
const arr: string[] = [];
for (let i = 0; i < count; i++) arr.push(genRandomValue(prefix, identifier, bytes));
return arr;
};

94
test/utils/queryGen.ts Normal file
View File

@@ -0,0 +1,94 @@
import { IDatabase } from "../../src/databases/IDatabase";
import { HashedUserID } from "../../src/types/user.model";
import { User, userArray, usernameUserArray } from "./genUser";
import { Feature } from "../../src/types/user.model";
import { ActionType, Category, Service, VideoIDHash } from "../../src/types/segments.model";
import { genRandomValue } from "./getRandom";
import { getHash } from "../../src/utils/getHash";
// segments
export { insertSegment } from "./segmentQueryGen";
// vip
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);
};
// userFeatures
export const grantFeature = async (db: IDatabase, target: HashedUserID, feature: Feature, issuer = "default-issuer", time = 0) => {
const query = 'INSERT INTO "userFeatures" ("userID", "feature", "issuerUserID", "timeSubmitted") VALUES(?, ?, ?, ?)';
await db.prepare("run", query, [target, feature, issuer, time]);
};
export const bulkGrantFeature = async (db: IDatabase, users: userArray, feature: Feature, issuer: User, time = 0) => {
for (const user of Object.values(users))
await grantFeature(db, user.pubID, feature, issuer.pubID, time);
};
// usernames
export const insertUsername = async (db: IDatabase, userID: HashedUserID, userName: string, locked = false) => {
const query = 'INSERT INTO "userNames" ("userID", "userName", "locked") VALUES(?, ?, ?)';
const lockedValue = Number(locked);
await db.prepare("run", query, [userID, userName, lockedValue]);
};
export const insertUsernameBulk = async (db: IDatabase, users: usernameUserArray) => {
for (const user of Object.values(users))
await insertUsername(db, user.pubID, user.username, false);
};
// videoInfo
export const insertVideoInfo = async (db: IDatabase, videoID: string, channelID: string, title = "", published = 0) => {
const query = 'INSERT INTO "videoInfo" ("videoID", "channelID", "title", "published") VALUES(?, ?, ?, ?)';
await db.prepare("run", query, [videoID, channelID, title, published]);
};
interface lockParams {
videoID?: string,
userID?: HashedUserID | "",
actionType?: ActionType | string,
category?: Category | string,
hashedVideoID?: VideoIDHash | "",
reason?: string,
service?: Service | string
}
export const insertLock = async(db: IDatabase, overrides: lockParams = {}) => {
const query = 'INSERT INTO "lockCategories" ("videoID", "userID", "actionType", "category", "hashedVideoID", "reason", "service") VALUES (?, ?, ?, ?, ?, ?, ?)';
const identifier = "lock";
const defaults = {
videoID: genRandomValue("video", identifier), userID: genRandomValue("user", identifier),
actionType: "skip", category: "sponsor", hashedVideoID: "", reason: "", service: Service.YouTube
};
const params = { ...defaults, ...overrides };
params.hashedVideoID = getHash(params.videoID);
await db.prepare("run", query, Object.values(params));
};
// warning
type warningParams = {
userID?: HashedUserID,
issueTime?: number,
issuerUserID?: HashedUserID,
enabled?: boolean | number,
reason?: string,
type?: number
}
export const insertWarning = async (db: IDatabase, userID: HashedUserID, overrides: warningParams = {}) => {
const defaults = { userID, issueTime: 0, issuerUserID: "vip-user", enabled: true, reason: "default-warn-reason", type: 0 };
const params = { ...defaults, ...overrides };
params.enabled = Number(params.enabled);
const query = 'INSERT INTO "warnings" ("userID", "issueTime", "issuerUserID", "enabled", "reason", "type") VALUES(?, ?, ?, ?, ?, ?)';
await db.prepare("run", query, Object.values(params));
};
// ban
export const insertBan = async (db: IDatabase, userID: HashedUserID) => {
const query = 'INSERT INTO "shadowBannedUsers" ("userID") VALUES (?)';
await db.prepare("run", query, [userID]);
};

View File

@@ -0,0 +1,132 @@
import { IDatabase } from "../../src/databases/IDatabase";
import { Service, VideoIDHash } from "../../src/types/segments.model";
import { HashedUserID } from "../../src/types/user.model";
import { genRandom, genRandomValue } from "./getRandom";
import { getHash } from "../../src/utils/getHash";
interface baseParams {
videoID?: string
hashedVideoID?: VideoIDHash | ""
userID?: HashedUserID | ""
service?: Service
timeSubmitted?: number
UUID?: string
}
// sponsorTimes
interface insertSegmentParams extends baseParams {
startTime?: number,
endTime?: number,
votes?: number,
locked?: boolean | number,
views?: number,
category?: string,
actionType?: string,
videoDuration?: number,
hidden?: boolean | number,
shadowHidden?: boolean | number,
description?: string
}
const defaultSegmentParams: insertSegmentParams = {
videoID: "",
startTime: 0,
endTime: 0,
votes: 0,
locked: false,
UUID: "",
userID: "",
timeSubmitted: 0,
views: 0,
category: "sponsor",
actionType: "skip",
service: Service.YouTube,
videoDuration: 0,
hidden: false,
shadowHidden: false,
hashedVideoID: "",
description: ""
};
const generateDefaults = (identifier: string) => ({
videoID: `vid-${identifier}`,
hashedVideoID: getHash(`vid-${identifier}`),
userID: `user-${identifier}`,
UUID: genRandomValue("uuid", identifier, 2),
});
export const insertSegment = async(db: IDatabase, overrides: insertSegmentParams = {}, identifier?: string) => {
const query = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "actionType", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID", "description") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
// generate defaults
identifier = identifier ?? genRandom();
const defaults = generateDefaults(identifier);
const params = { ...defaultSegmentParams, ...defaults, ...overrides };
// convert bool to 0 | 1
params.locked = Number(params.locked);
params.hidden = Number(params.hidden);
params.shadowHidden = Number(params.shadowHidden);
await db.prepare("run", query, Object.values(params));
};
export const insertChapter = async(db: IDatabase, description: string, params: insertSegmentParams = {}) => {
const overrides = { category: "chapter", actionType: "chapter", description, ...params };
await insertSegment(db, overrides);
};
// titles
interface insertTitleParams extends baseParams {
title?: string,
original?: boolean | number,
}
const defaultTitleParams: insertTitleParams = {
videoID: "",
title: "",
original: false,
userID: "",
service: Service.YouTube,
hashedVideoID: "",
timeSubmitted: 0,
UUID: "",
};
export const insertTitle = async (db: IDatabase, overrides: insertTitleParams = {}, identifier?: string) => {
const query = 'INSERT INTO "titles" ("videoID", "title", "original", "userID", "service", "hashedVideoID", "timeSubmitted", "UUID") VALUES (?, ?, ?, ?, ?, ?, ?, ?)';
// generate defaults
identifier = identifier ?? genRandom();
const defaults = generateDefaults(identifier);
const params = { ...defaultTitleParams, ...defaults, ...overrides };
params.title = genRandomValue("title", identifier);
// convert bool to 0 | 1
params.original = Number(params.original);
await db.prepare("run", query, Object.values(params));
};
export const insertTitleVote = async (db: IDatabase, UUID: string, votes: number, locked = false, shadowHidden = false, verification = false) => {
const query = 'INSERT INTO "titleVotes" ("UUID", "votes", "locked", "shadowHidden", "verification") VALUES (?, ?, ?, ?, ?)';
const params = [UUID, votes, Number(locked), Number(shadowHidden), Number(verification)];
await db.prepare("run", query, params);
};
interface insertThumbnailParams extends baseParams {
original?: number,
}
const defaultThumbParams = {
videoID: "",
original: 0,
userID: "",
service: Service.YouTube,
hashedVideoID: "",
timeSubmitted: 0,
UUID: "",
};
export const insertThumbnail = async (db: IDatabase, overrides: insertThumbnailParams = {}, identifier?: string) => {
const query = 'INSERT INTO "thumbnails" ("videoID", "original", "userID", "service", "hashedVideoID", "timeSubmitted", "UUID") VALUES (?, ?, ?, ?, ?, ?, ?)';
// generate defaults
identifier = identifier ?? genRandom();
const defaults = generateDefaults(identifier);
const params = { ...defaultThumbParams, ...defaults, ...overrides };
// convert bool to 0 | 1
await db.prepare("run", query, Object.values(params));
};
export const insertThumbnailVote = async (db: IDatabase, UUID: string, votes: number, locked = false, shadowHidden = false) => {
const query = 'INSERT INTO "thumbnailVotes" ("UUID", "votes", "locked", "shadowHidden") VALUES (?, ?, ?, ?)';
const params = [UUID, votes, Number(locked), Number(shadowHidden)];
await db.prepare("run", query, params);
};