Added testing

This commit is contained in:
Joe-Dowd
2020-04-01 21:04:04 +01:00
parent 1bff019a64
commit 5369d48eae
23 changed files with 1388 additions and 517 deletions

View File

@@ -1,84 +1,5 @@
var express = require('express');
var fs = require('fs');
var http = require('http');
// Create a service (the app object is just a callback).
var app = express();
let config = JSON.parse(fs.readFileSync('config.json'));
// Routes
var corsMiddleware = require('./src/middleware/cors.js');
var loggerMiddleware = require('./src/middleware/logger.js');
// Routes
var getVideoSponsorTimes = require('./src/routes/getVideoSponsorTimes.js');
var submitSponsorTimes = require('./src/routes/submitSponsorTimes.js');
var voteOnSponsorTime = require('./src/routes/voteOnSponsorTime.js');
var viewedVideoSponsorTime = require('./src/routes/viewedVideoSponsorTime.js');
var setUsername = require('./src/routes/setUsername.js');
var getUsername = require('./src/routes/getUsername.js');
var shadowBanUser = require('./src/routes/shadowBanUser.js');
var addUserAsVIP = require('./src/routes/addUserAsVIP.js');
var getSavedTimeForUser = require('./src/routes/getSavedTimeForUser.js');
var getViewsForUser = require('./src/routes/getViewsForUser.js');
var getTopUsers = require('./src/routes/getTopUsers.js');
var getTotalStats = require('./src/routes/getTotalStats.js');
var getDaysSavedFormatted = require('./src/routes/getDaysSavedFormatted.js');
// Create an HTTP service.
http.createServer(app).listen(config.port);
//setup CORS correctly
app.use(corsMiddleware);
app.use(loggerMiddleware);
//add the get function
app.get('/api/getVideoSponsorTimes', getVideoSponsorTimes);
//add the post function
app.get('/api/postVideoSponsorTimes', submitSponsorTimes);
app.post('/api/postVideoSponsorTimes', submitSponsorTimes);
//voting endpoint
app.get('/api/voteOnSponsorTime', voteOnSponsorTime);
app.post('/api/voteOnSponsorTime', voteOnSponsorTime);
//Endpoint when a sponsorTime is used up
app.get('/api/viewedVideoSponsorTime', viewedVideoSponsorTime);
app.post('/api/viewedVideoSponsorTime', viewedVideoSponsorTime);
//To set your username for the stats view
app.post('/api/setUsername', setUsername);
//get what username this user has
app.get('/api/getUsername', getUsername);
//Endpoint used to hide a certain user's data
app.post('/api/shadowBanUser', shadowBanUser);
//Endpoint used to make a user a VIP user with special privileges
app.post('/api/addUserAsVIP', addUserAsVIP);
//Gets all the views added up for one userID
//Useful to see how much one user has contributed
app.get('/api/getViewsForUser', getViewsForUser);
//Gets all the saved time added up (views * sponsor length) for one userID
//Useful to see how much one user has contributed
//In minutes
app.get('/api/getSavedTimeForUser', getSavedTimeForUser);
app.get('/api/getTopUsers', getTopUsers);
//send out totals
//send the total submissions, total views and total minutes saved
app.get('/api/getTotalStats', getTotalStats);
//send out a formatted time saved total
app.get('/api/getdayssavedformatted', getDaysSavedFormatted);
app.get('/database.db', function (req, res) {
res.sendfile("./databases/sponsortimes.db", { root: __dirname });
var config = require('./src/config.js');
var createServer = require('./src/app.js');
var server = createServer(() => {
console.log("Server started.");
});

1540
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"description": "Server that holds the SponsorBlock database",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"test": "node test.js",
"start": "node index.js"
},
"author": "Ajay Ramachandran",
@@ -15,5 +15,8 @@
"http": "0.0.0",
"uuid": "^3.3.2",
"youtube-api": "^2.0.10"
},
"devDependencies": {
"mocha": "^7.1.1"
}
}

82
src/app.js Normal file
View File

@@ -0,0 +1,82 @@
var express = require('express');
// Create a service (the app object is just a callback).
var app = express();
var config = require('./config.js');
// Middleware
var corsMiddleware = require('./middleware/cors.js');
var loggerMiddleware = require('./middleware/logger.js');
// Routes
var getVideoSponsorTimes = require('./routes/getVideoSponsorTimes.js');
var submitSponsorTimes = require('./routes/submitSponsorTimes.js');
var voteOnSponsorTime = require('./routes/voteOnSponsorTime.js');
var viewedVideoSponsorTime = require('./routes/viewedVideoSponsorTime.js');
var setUsername = require('./routes/setUsername.js');
var getUsername = require('./routes/getUsername.js');
var shadowBanUser = require('./routes/shadowBanUser.js');
var addUserAsVIP = require('./routes/addUserAsVIP.js');
var getSavedTimeForUser = require('./routes/getSavedTimeForUser.js');
var getViewsForUser = require('./routes/getViewsForUser.js');
var getTopUsers = require('./routes/getTopUsers.js');
var getTotalStats = require('./routes/getTotalStats.js');
var getDaysSavedFormatted = require('./routes/getDaysSavedFormatted.js');
//setup CORS correctly
app.use(corsMiddleware);
app.use(loggerMiddleware);
//add the get function
app.get('/api/getVideoSponsorTimes', getVideoSponsorTimes);
//add the post function
app.get('/api/postVideoSponsorTimes', submitSponsorTimes);
app.post('/api/postVideoSponsorTimes', submitSponsorTimes);
//voting endpoint
app.get('/api/voteOnSponsorTime', voteOnSponsorTime);
app.post('/api/voteOnSponsorTime', voteOnSponsorTime);
//Endpoint when a sponsorTime is used up
app.get('/api/viewedVideoSponsorTime', viewedVideoSponsorTime);
app.post('/api/viewedVideoSponsorTime', viewedVideoSponsorTime);
//To set your username for the stats view
app.post('/api/setUsername', setUsername);
//get what username this user has
app.get('/api/getUsername', getUsername);
//Endpoint used to hide a certain user's data
app.post('/api/shadowBanUser', shadowBanUser);
//Endpoint used to make a user a VIP user with special privileges
app.post('/api/addUserAsVIP', addUserAsVIP);
//Gets all the views added up for one userID
//Useful to see how much one user has contributed
app.get('/api/getViewsForUser', getViewsForUser);
//Gets all the saved time added up (views * sponsor length) for one userID
//Useful to see how much one user has contributed
//In minutes
app.get('/api/getSavedTimeForUser', getSavedTimeForUser);
app.get('/api/getTopUsers', getTopUsers);
//send out totals
//send the total submissions, total views and total minutes saved
app.get('/api/getTotalStats', getTotalStats);
//send out a formatted time saved total
app.get('/api/getdayssavedformatted', getDaysSavedFormatted);
app.get('/database.db', function (req, res) {
res.sendfile("./databases/sponsortimes.db", { root: __dirname });
});
// Create an HTTP service.
module.exports = function createServer (callback) {
return app.listen(config.port, callback);
}

12
src/config.js Normal file
View File

@@ -0,0 +1,12 @@
var fs = require('fs');
var config = undefined;
// Check to see if launched in test mode
if (process.env.npm_lifecycle_script === 'node test.js') {
config = JSON.parse(fs.readFileSync('test.json'));
} else {
config = JSON.parse(fs.readFileSync('config.json'));
}
module.exports = config;

View File

@@ -1,6 +1,6 @@
var fs = require('fs');
var config = JSON.parse(fs.readFileSync('config.json'));
var config = require('../config.js');
var Sqlite3 = require('better-sqlite3');
var fs = require('fs');
let options = {
readonly: config.readOnly
@@ -9,6 +9,11 @@ let options = {
var db = new Sqlite3(config.db, options);
var privateDB = new Sqlite3(config.privateDB, options);
if (config.createDatabaseIfNotExist && !config.readOnly) {
if (fs.existsSync(config.dbSchema)) db.exec(fs.readFileSync(config.dbSchema).toString());
if (fs.existsSync(config.privateDBSchema)) privateDB.exec(fs.readFileSync(config.privateDBSchema).toString());
}
// Enable WAL mode checkpoint number
if (!config.readOnly && config.mode === "production") {
db.exec("PRAGMA journal_mode=WAL;");

View File

@@ -1,5 +1,5 @@
var fs = require('fs');
var config = JSON.parse(fs.readFileSync('config.json'));
var config = require('../config.js');
module.exports = function logger (req, res, next) {
(config.mode === "development") && console.log('Request recieved: ' + req.url);

View File

@@ -1,5 +1,5 @@
var fs = require('fs');
var config = JSON.parse(fs.readFileSync('config.json'));
var config = require('../config.js');
var db = require('../databases/databases.js').db;
var getHash = require('../utils/getHash.js');

View File

@@ -1,5 +1,5 @@
var fs = require('fs');
var config = JSON.parse(fs.readFileSync('config.json'));
var config = require('../config.js');
var databases = require('../databases/databases.js');
var db = databases.db;

View File

@@ -1,6 +1,5 @@
var fs = require('fs');
var config = JSON.parse(fs.readFileSync('config.json'));
var config = require('../config.js');
var db = require('../databases/databases.js').db;
var getHash = require('../utils/getHash.js');

View File

@@ -1,5 +1,4 @@
var fs = require('fs');
var config = JSON.parse(fs.readFileSync('config.json'));
var config = require('../config.js');
var databases = require('../databases/databases.js');
var db = databases.db;

View File

@@ -1,5 +1,4 @@
var fs = require('fs');
var config = JSON.parse(fs.readFileSync('config.json'));
var config = require('../config.js');
var databases = require('../databases/databases.js');
var db = databases.db;

View File

@@ -1,5 +1,5 @@
var fs = require('fs');
var config = JSON.parse(fs.readFileSync('config.json'));
var config = require('../config.js');
var getHash = require('../utils/getHash.js');
var getIP = require('../utils/getIP.js');
@@ -99,6 +99,7 @@ module.exports = async function voteOnSponsorTime(req, res) {
err && console.log(err);
return;
}
console.log(config.test);
request.post(config.discordReportChannelWebhookURL, {
json: {

View File

@@ -1,6 +1,8 @@
var crypto = require('crypto');
module.exports = function (value, times=5000) {
if (times <= 0) return "";
for (let i = 0; i < times; i++) {
let hashCreator = crypto.createHash('sha256');
value = hashCreator.update(value).digest('hex');

View File

@@ -1,5 +1,4 @@
var fs = require('fs');
var config = JSON.parse(fs.readFileSync('config.json'));
var config = require('../config.js');
// YouTube API
const YouTubeAPI = require("youtube-api");

35
test.js Normal file
View File

@@ -0,0 +1,35 @@
var Mocha = require('mocha'),
fs = require('fs'),
path = require('path');
var createServer = require('./src/app.js');
var createMockServer = require('./test/mocks.js');
// Instantiate a Mocha instance.
var mocha = new Mocha();
var testDir = './test/cases'
// Add each .js file to the mocha instance
fs.readdirSync(testDir).filter(function(file) {
// Only keep the .js files
return file.substr(-3) === '.js';
}).forEach(function(file) {
mocha.addFile(
path.join(testDir, file)
);
});
var mockServer = createMockServer(() => {
console.log("Started mock HTTP Server");
var server = createServer(() => {
console.log("Started main HTTP server");
// Run the tests.
mocha.run(function(failures) {
mockServer.close();
server.close();
process.exitCode = failures ? 1 : 0; // exit with non-zero status if there were failures
});
});
});

17
test.json Normal file
View File

@@ -0,0 +1,17 @@
{
"port": 8080,
"mockPort": 8081,
"globalSalt": "testSalt",
"adminUserID": "testUserId",
"youtubeAPIKey": "",
"discordReportChannelWebhookURL": "http://127.0.0.1:8081/ReportChannelWebhook",
"discordFirstTimeSubmissionsWebhookURL": "http://127.0.0.1:8081/FirstTimeSubmissionsWebhook",
"behindProxy": true,
"db": "./test/databases/sponsorTimes.db",
"privateDB": "./test/databases/private.db",
"createDatabaseIfNotExist": true,
"dbSchema": "./test/databases/_sponsorTimes.db.sql",
"privateDBSchema": "./test/databases/_private.db.sql",
"mode": "development",
"readOnly": false
}

29
test/cases/getHash.js Normal file
View File

@@ -0,0 +1,29 @@
var getHash = require('../../src/utils/getHash.js');
var assert = require('assert');
describe('getHash', () => {
it('Should not output the input string', () => {
assert(getHash("test") !== "test");
assert(getHash("test", -1) !== "test");
assert(getHash("test", 0) !== "test");
assert(getHash("test", null) !== "test");
});
it('Should return a hashed value', () => {
assert.equal(getHash("test"), "2f327ef967ade1ebf4319163f7debbda9cc17bb0c8c834b00b30ca1cf1c256ee");
});
it ('Should take a variable number of passes', () => {
assert.equal(getHash("test", 1), "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08");
assert.equal(getHash("test", 2), "7b3d979ca8330a94fa7e9e1b466d8b99e0bcdea1ec90596c0dcc8d7ef6b4300c");
assert.equal(getHash("test", 3), "5b24f7aa99f1e1da5698a4f91ae0f4b45651a1b625c61ed669dd25ff5b937972");
});
it ('Should default to 5000 passes', () => {
assert.equal(getHash("test"), getHash("test", 5000));
});
it ('Should not take a negative number of passes', () => {
assert.equal(getHash("test", -1), "");
});
});

View File

@@ -0,0 +1,22 @@
BEGIN TRANSACTION;
DROP TABLE "shadowBannedUsers";
DROP TABLE "votes";
DROP TABLE "sponsorTimes";
CREATE TABLE IF NOT EXISTS "shadowBannedUsers" (
"userID" TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS "votes" (
"UUID" TEXT NOT NULL,
"userID" INTEGER NOT NULL,
"hashedIP" INTEGER NOT NULL,
"type" INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS "sponsorTimes" (
"videoID" TEXT NOT NULL,
"hashedIP" TEXT NOT NULL,
"timeSubmitted" INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS sponsorTimes_hashedIP on sponsorTimes(hashedIP);
CREATE INDEX IF NOT EXISTS votes_userID on votes(UUID);
COMMIT;

View File

@@ -0,0 +1,26 @@
BEGIN TRANSACTION;
DROP TABLE "vipUsers";
DROP TABLE "sponsorTimes";
DROP TABLE "userNames";
CREATE TABLE IF NOT EXISTS "vipUsers" (
"userID" TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS "sponsorTimes" (
"videoID" TEXT NOT NULL,
"startTime" REAL NOT NULL,
"endTime" REAL NOT NULL,
"votes" INTEGER NOT NULL,
"UUID" TEXT NOT NULL UNIQUE,
"userID" TEXT NOT NULL,
"timeSubmitted" INTEGER NOT NULL,
"views" INTEGER NOT NULL,
"shadowHidden" INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS "userNames" (
"userID" TEXT NOT NULL,
"userName" TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS sponsorTimes_videoID on sponsorTimes(videoID);
CREATE INDEX IF NOT EXISTS sponsorTimes_UUID on sponsorTimes(UUID);
COMMIT;

BIN
test/databases/private.db Normal file

Binary file not shown.

Binary file not shown.

16
test/mocks.js Normal file
View File

@@ -0,0 +1,16 @@
var express = require('express');
var app = express();
var config = require('../src/config.js');
app.post('/ReportChannelWebhook', (req, res) => {
res.status(200);
});
app.post('/FirstTimeSubmissionsWebhook', (req, res) => {
res.status(200);
});
module.exports = function createMockServer(callback) {
return app.listen(config.mockPort, callback);
}