Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Obivus Modes Testing, logfile uploads #1391

Open
wants to merge 9 commits into
base: development
Choose a base branch
from
19 changes: 15 additions & 4 deletions src/server/routes/obvius.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ function handleStatus(req, res) {
/**
* Logs the Obvius request and sets the req.IP field to be the ip address.
*/
function obviusLog(req, res, next){
function obviusLog(req, res, next) {
// Log the IP of the requester
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
req.IP = ip;
Expand All @@ -111,7 +111,7 @@ function obviusLog(req, res, next){
/**
* Verifies an Obvius request via username and password.
*/
function verifyObviusUser(req, res, next){
function verifyObviusUser(req, res, next) {
// First we ensure that the password and username parameters are provided.
const password = req.param('password');
// TODO This is allowing for backwards compatibility if previous obvius meters are using the'email' parameter
Expand Down Expand Up @@ -157,6 +157,7 @@ router.all('/', obviusLog, verifyObviusUser, async (req, res) => {
return;
}
const conn = getConnection();
const loadLogfilePromises = [];
for (const fx of req.files) {
log.info(`Received ${fx.fieldname}: ${fx.originalname}`);
// Logfiles are always gzipped.
Expand All @@ -168,9 +169,19 @@ router.all('/', obviusLog, verifyObviusUser, async (req, res) => {
failure(req, res, `Unable to gunzip incoming buffer: ${err}`);
return;
}
loadLogfileToReadings(req.param('serialnumber'), ip, data, conn);
// The original code did not await for the Promise to finish. The new version
// allows the files to run in parallel (as before) but then wait for them all
// to finish before returning.
loadLogfilePromises.push(loadLogfileToReadings(req.param('serialnumber'), ip, data, conn));
}
success(req, res, 'Logfile Upload IS PROVISIONAL');
// TODO This version returns an error. Should check all usage to be sure it is properly handled.
Promise.all(loadLogfilePromises).then(() => {
success(req, res, 'Logfile Upload IS PROVISIONAL');
}).catch((err) => {
log.warn(`Logfile Upload had issues from ip: ${ip}`, err)
failure(req, res, 'Logfile Upload had issues');
});
// This return may not be needed.
return;
}

Expand Down
211 changes: 210 additions & 1 deletion src/server/test/web/obviusTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@

const { chai, mocha, expect, app, testDB, testUser } = require('../common');
const User = require('../../models/User');
const Configfile = require('../../models/obvius/Configfile');
const bcrypt = require('bcryptjs');
const { insertUnits } = require('../../util/insertData');
const Unit = require('../../models/Unit');
const Meter = require('../../models/Meter.js');

mocha.describe('Obvius API', () => {
mocha.describe('upload: ', () => {
Expand Down Expand Up @@ -58,5 +62,210 @@ mocha.describe('Obvius API', () => {
}
}
});
mocha.describe('obvius request modes', async () => {
mocha.beforeEach(async () => {
const conn = testDB.getConnection();
// The kWh unit is not used in all tests but easier to just put in.
const unitData = [
{
name: 'kWh',
identifier: '',
unitRepresent: Unit.unitRepresentType.QUANTITY,
secInRate: 3600,
typeOfUnit: Unit.unitType.UNIT,
suffix: '',
displayable: Unit.displayableType.ALL,
preferredDisplay: true,
note: 'OED created standard unit'
}
];
await insertUnits(unitData, false, conn);
});
mocha.it('should reject requests without a mode', async () => {
const password = 'password';
const hashedPassword = await bcrypt.hash(password, 10);
const obviusUser = new User(undefined, '[email protected]', hashedPassword, User.role.OBVIUS);
await obviusUser.insert(conn);
obviusUser.password = password;
const res = await chai.request(app).post('/api/obvius').send({ username: obviusUser.username, password: obviusUser.password });
//should respond with 406, not acceptable
expect(res).to.have.status(406);
//should also return expected message
expect(res.text).equals(`<pre>\nRequest must include mode parameter.\n</pre>\n`);
});
mocha.it('should accept status requests', async () => {
const password = 'password';
const hashedPassword = await bcrypt.hash(password, 10);
const obviusUser = new User(undefined, '[email protected]', hashedPassword, User.role.OBVIUS);
await obviusUser.insert(conn);
obviusUser.password = password;
const requestMode = 'STATUS';
const res = await chai.request(app).post('/api/obvius').send({ username: obviusUser.username, password: obviusUser.password, mode: requestMode });
//should respond with 200, success
expect(res).to.have.status(200);
//should also return expected message
expect(res.text).equals("<pre>\nSUCCESS\n</pre>\n");
});
mocha.it('should accept valid logfile uploads', async () => {
const password = 'password';
const hashedPassword = await bcrypt.hash(password, 10);
const obviusUser = new User(undefined, '[email protected]', hashedPassword, User.role.OBVIUS);
await obviusUser.insert(conn);
obviusUser.password = password;
const logfileRequestMode = 'LOGFILEUPLOAD';

// Adapted from ../obvius/README.md
const logfilePath = 'src/server/test/web/obvius/mb-001.log.gz';

//the upload of a logfile is the subject of the test
const res = await chai.request(app)
.post('/api/obvius')
.field('username', obviusUser.username)
.field('password', obviusUser.password)
.field('mode', logfileRequestMode)
.field('serialnumber', 'mb-001')
.attach('files', logfilePath);
//should respond with 200, success
expect(res).to.have.status(200);
//should also return expected message
expect(res.text).equals("<pre>\nSUCCESS\nLogfile Upload IS PROVISIONAL</pre>\n");

});
mocha.it('should accept valid config file uploads', async () => {
const password = 'password';
const hashedPassword = await bcrypt.hash(password, 10);
const obviusUser = new User(undefined, '[email protected]', hashedPassword, User.role.OBVIUS);
await obviusUser.insert(conn);
obviusUser.password = password;
const requestMode = 'CONFIGFILEUPLOAD';

// Adapted from ../obvius/README.md
const configFilePath = 'src/server/test/web/obvius/mb-001.ini.gz';

const res = await chai.request(app)
.post('/api/obvius')
.field('username', obviusUser.username)
.field('password', obviusUser.password)
.field('mode', requestMode)
.field('serialnumber', 'mb-001')
.field('modbusdevice', '1234')
.attach('files', configFilePath);

//should respond with 200, success
expect(res).to.have.status(200);
//should also return expected message
expect(res.text).equals("<pre>\nSUCCESS\nAcquired config log with (pseudo)filename mb-001-mb-1234.ini.</pre>\n");
});
mocha.it('should return accurate config file manifests', async () => {
const password = 'password';
const hashedPassword = await bcrypt.hash(password, 10);
const obviusUser = new User(undefined, '[email protected]', hashedPassword, User.role.OBVIUS);
await obviusUser.insert(conn);
obviusUser.password = password;
const uploadRequestMode = 'CONFIGFILEUPLOAD';
const manifestRequestMode = 'CONFIGFILEMANIFEST';

// Adapted from ../obvius/README.md
const configFilePath = 'src/server/test/web/obvius/mb-001.ini.gz';
const upload = await chai.request(app)
.post('/api/obvius')
.field('username', obviusUser.username)
.field('password', obviusUser.password)
.field('mode', uploadRequestMode)
.field('serialnumber', 'mb-001')
.field('modbusdevice', '1234')
.attach('files', configFilePath);

const res = await chai.request(app)
.post('/api/obvius')
.field('username', obviusUser.username)
.field('password', obviusUser.password)
.field('mode', manifestRequestMode);

//logfile upload should respond with 200, success
expect(upload).to.have.status(200);

//logfile request should respond with 200, success
expect(res).to.have.status(200);

//get "all" config files to compare to response
const allConfigfiles = await Configfile.getAll(conn);
let response = '';
for (f of allConfigfiles) {
response += `CONFIGFILE,${f.makeFilename()},${f.hash},${f.created.format('YYYY-MM-DD hh:mm:ss')}`;
}

//the third line of the response should be the config file
expect(res.text.split("\n")[2]).equals(response);

//config file uploads should create accurate meter objects
const allMeters = await Meter.getAll(conn);

//mb-001.ini should make 28 meters
expect(allMeters.length).to.equal(28);

//these arrays should vary for different submeters
const meterNames = [];
const meterIDs = [];

//flags for meter fields (.type, .displayable, .enabled)
const allMetersAreObvius = true;
const allMetersAreNotDisplayable = true;
const allMetersAreNotEnabled = true;

//expected names and ids
const expMeterNames = [
'mb-001.0', 'mb-001.1', 'mb-001.2', 'mb-001.3', 'mb-001.4', 'mb-001.5', 'mb-001.6', 'mb-001.7',
'mb-001.8', 'mb-001.9', 'mb-001.10', 'mb-001.11', 'mb-001.12', 'mb-001.13', 'mb-001.14', 'mb-001.15',
'mb-001.16', 'mb-001.17', 'mb-001.18', 'mb-001.19', 'mb-001.20', 'mb-001.21', 'mb-001.22', 'mb-001.23',
'mb-001.24', 'mb-001.25', 'mb-001.26', 'mb-001.27'
];

const expMeterIDs = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28
];
for (const meter of allMeters) {
//populate arrays with varying values in ascending order
let currentName = meter.name + "";
let idx = currentName.split('.')[1];
meterNames[parseInt(idx)] = meter.name;
meterIDs[meter.id - 1] = meter.id;
//ensure each meter is obvius, not displayable, and not enabled
if (meter.type != 'obvius') {
allMetersAreObvius = false;
}
if (meter.displayable != false) {
allMetersAreNotDisplayable = false;
}
if (meter.enabled != false) {
allMetersAreNotEnabled = false;
}
}

//flags for comparison between expected arrays and actual arrays
const expectedNamesAreEqual = true;
const expectedIDsAreEqual = true;

//both arrays should be contain the same sequence of values
for (let i = 0; i < 28; i++) {
if (expMeterNames[i] != meterNames[i]) {
expectedNamesAreEqual = false;
}

if (expMeterIDs[i] != meterIDs[i]) {
expectedIDsAreEqual = false;
}
}

//assertion for type, displayable, and enabled
expect(allMetersAreObvius).to.equal(true);
expect(allMetersAreNotDisplayable).to.equal(true);
expect(allMetersAreNotEnabled).to.equal(true);

//expected arrays should equal actual arrays
expect(expectedNamesAreEqual).to.equal(true);
expect(expectedIDsAreEqual).to.equal(true);
});
});
});
});
});
Loading