cse47122
4 years ago
5 changed files with 2624 additions and 186 deletions
@ -1,96 +1,73 @@ |
|||||
const sizeof = require('object-sizeof') |
/* globals describe it */ |
||||
const FakeDevice = require('./fake-device') |
|
||||
|
|
||||
module.exports = function FakeDeviceManager ({ |
const expect = require('chai').expect |
||||
connection, |
|
||||
deviceCount = 10, |
|
||||
spawnInterval = 200, |
|
||||
metricsInterval = 200, |
|
||||
sendInterval = 15000, |
|
||||
measurements, |
|
||||
onUpdateStats |
|
||||
}) { |
|
||||
if (!connection) { |
|
||||
throw new Error('Missing connection param') |
|
||||
} |
|
||||
if (!measurements) { |
|
||||
throw new Error('Missing measurements param') |
|
||||
} |
|
||||
let devices = [] |
|
||||
|
|
||||
let stats = { |
const FakeDeviceManager = require('../src/fake-device-manager') |
||||
devices: 0, |
const measurements = { |
||||
measurements: 0, |
usage: {type: 'integer', min: 0, max: 100}, |
||||
writes: 0, |
voltage: {type: 'integer', min: 0, max: 15}, |
||||
size: 0, |
temperature: {type: 'integer', min: -20, max: 60} |
||||
errors: 0 |
|
||||
} |
} |
||||
|
|
||||
/** |
// create fake influx connection
|
||||
* Return device list |
// let connectionWriteData = false
|
||||
*/ |
const connection = { |
||||
const getDevices = () => { |
send: (deviceId, data) => { |
||||
return devices |
return new Promise((resolve, reject) => { |
||||
|
// connectionWriteData = {deviceId, data}
|
||||
|
resolve() |
||||
|
}) |
||||
} |
} |
||||
|
|
||||
/** |
|
||||
* Return stats data |
|
||||
*/ |
|
||||
const getStats = () => { |
|
||||
return stats |
|
||||
} |
} |
||||
|
|
||||
/** |
describe('FakeDeviceManager', function () { |
||||
* Update stats on device data send event |
let fakeDeviceManager = null |
||||
*/ |
|
||||
const onDeviceSendData = (err, data) => { |
it('should throw error if no params are passed', function () { |
||||
if (err) { |
expect(FakeDeviceManager).to.throw(Error) |
||||
console.log(err) |
|
||||
stats.errors++ |
|
||||
return |
|
||||
} |
|
||||
stats.measurements += data.length |
|
||||
data.forEach(chunk => { |
|
||||
stats.size += sizeof(chunk) |
|
||||
}) |
}) |
||||
stats.writes++ |
|
||||
} |
|
||||
|
|
||||
/** |
it('shold throw missing connection param', function () { |
||||
* Start device spawn process |
expect(() => FakeDeviceManager({})).to.throw('Missing connection param') |
||||
*/ |
}) |
||||
const start = () => { |
|
||||
let __spawnInterval = setInterval(() => { |
it('shold throw missing measurements param', function () { |
||||
stats.devices++ |
expect(() => FakeDeviceManager({ |
||||
devices.push(FakeDevice({ |
connection |
||||
deviceId: stats.devices, |
})).to.throw('Missing measurements param') |
||||
|
}) |
||||
|
|
||||
|
it('should create instance', function () { |
||||
|
fakeDeviceManager = FakeDeviceManager({ |
||||
connection, |
connection, |
||||
measurements, |
measurements, |
||||
onSendData: onDeviceSendData, |
sendInterval: 500 |
||||
autoStart: true, |
}) |
||||
metricsInterval, |
expect(fakeDeviceManager).to.have.property('start') |
||||
sendInterval |
}) |
||||
})) |
|
||||
// when device limit is reached stop spawn inteval
|
|
||||
if (stats.devices === deviceCount) { |
|
||||
clearTimeout(__spawnInterval) |
|
||||
} |
|
||||
}, spawnInterval) |
|
||||
} |
|
||||
|
|
||||
/** |
it('should spawn device instances', function (done) { |
||||
* Stop all spawned devices |
fakeDeviceManager.start() |
||||
*/ |
setTimeout(() => { |
||||
const stop = () => { |
let devices = fakeDeviceManager.getDevices() |
||||
for (let i = 0; i < stats.devices; i++) { |
done(!devices.length) |
||||
devices[i].stop() |
}, 500) |
||||
} |
}) |
||||
} |
|
||||
|
|
||||
return { |
it('should collect device stats', function (done) { |
||||
start, |
setTimeout(() => { |
||||
stop, |
let stats = fakeDeviceManager.getStats() |
||||
getDevices, |
if (!stats) return done('No data') |
||||
getStats |
if ( |
||||
} |
stats.devices && |
||||
|
stats.measurements && |
||||
|
stats.writes && |
||||
|
stats.size |
||||
|
) { |
||||
|
done() |
||||
|
} else { |
||||
|
done('Invalid write data format') |
||||
} |
} |
||||
|
}, 1000) |
||||
|
}) |
||||
|
}) |
||||
|
@ -1,111 +1,81 @@ |
|||||
/** |
/* globals describe it */ |
||||
* Create FakeDevice |
|
||||
* |
|
||||
* @param {any} { |
|
||||
* deviceId, |
|
||||
* metricsInterval = 100, |
|
||||
* sendInterval = 15000 |
|
||||
* } |
|
||||
* @returns FakeDevice |
|
||||
*/ |
|
||||
module.exports = function FakeDevice ({ |
|
||||
deviceId, |
|
||||
connection, |
|
||||
metricsInterval = 100, |
|
||||
sendInterval = 30000, |
|
||||
onSendData, |
|
||||
autoStart = false, |
|
||||
measurements |
|
||||
}) { |
|
||||
if (!deviceId) { |
|
||||
throw new Error('Missing deviceId param') |
|
||||
} |
|
||||
if (!connection) { |
|
||||
throw new Error('Missing connection param') |
|
||||
} |
|
||||
if (!measurements) { |
|
||||
throw new Error('Missing measurements param') |
|
||||
} |
|
||||
|
|
||||
let data = [] |
|
||||
|
|
||||
let __metricsInterval = null |
const expect = require('chai').expect |
||||
let __sendInterval = null |
|
||||
|
|
||||
/** |
const FakeDevice = require('../src/fake-device') |
||||
* Return data buffer |
const measurements = { |
||||
*/ |
usage: {type: 'integer', min: 0, max: 100}, |
||||
const getData = () => { |
voltage: {type: 'integer', min: 0, max: 15}, |
||||
return data |
temperature: {type: 'integer', min: -20, max: 60} |
||||
} |
} |
||||
|
|
||||
/** |
// create fake influx connection
|
||||
* Read data from sensors |
let connectionWriteData = false |
||||
* Will generate fake random data |
const connection = { |
||||
*/ |
send: (deviceId, data) => { |
||||
const readData = () => { |
return new Promise((resolve, reject) => { |
||||
function getRandomArbitrary (min, max) { |
connectionWriteData = {deviceId, data} |
||||
return Math.random() * (max - min) + min |
resolve() |
||||
|
}) |
||||
} |
} |
||||
|
|
||||
let chunk = {} |
|
||||
Object.keys(measurements).forEach(measurement => { |
|
||||
switch (measurements[measurement].type) { |
|
||||
case 'integer': |
|
||||
chunk[measurement] = getRandomArbitrary(measurements[measurement].min, measurements[measurement].max) |
|
||||
break |
|
||||
default: |
|
||||
throw new Error('Invalid measurement type') |
|
||||
} |
} |
||||
}) |
|
||||
chunk['timestamp'] = new Date() |
|
||||
|
|
||||
data.push(chunk) |
describe('FakeDevice', function () { |
||||
} |
let fakeDevice = null |
||||
|
|
||||
/** |
it('should throw error if no params are passed', function () { |
||||
* Send data to db and clear data buffer |
expect(FakeDevice).to.throw(Error) |
||||
* Calls onSendData function if set |
|
||||
*/ |
|
||||
const send = () => { |
|
||||
// send data buffer to connection
|
|
||||
connection.send(deviceId, data) |
|
||||
.then(() => { |
|
||||
if (!onSendData) return |
|
||||
onSendData(null, data) |
|
||||
// clear internal data buffer on successfull send
|
|
||||
data = [] |
|
||||
}) |
}) |
||||
.catch(err => { |
|
||||
if (!onSendData) return |
it('shold throw missing deviceId param', function () { |
||||
onSendData(err) |
expect(() => FakeDevice({})).to.throw('Missing deviceId param') |
||||
}) |
}) |
||||
} |
|
||||
|
|
||||
/** |
it('shold throw missing connection param', function () { |
||||
* Stop collecting data |
expect(() => FakeDevice({ |
||||
*/ |
deviceId: 1 |
||||
const stop = () => { |
})).to.throw('Missing connection param') |
||||
clearInterval(__metricsInterval) |
}) |
||||
clearInterval(__sendInterval) |
|
||||
} |
|
||||
|
|
||||
/** |
it('shold throw missing measurements param', function () { |
||||
* Start collecting data |
expect(() => FakeDevice({ |
||||
*/ |
deviceId: 1, |
||||
const start = () => { |
connection |
||||
__metricsInterval = setInterval(readData, metricsInterval) |
})).to.throw('Missing measurements param') |
||||
__sendInterval = setInterval(send, sendInterval) |
}) |
||||
} |
|
||||
|
|
||||
if (autoStart) { |
it('should create instance', function () { |
||||
start() |
fakeDevice = FakeDevice({ |
||||
} |
deviceId: 1, |
||||
|
connection, |
||||
|
sendInterval: 1000, |
||||
|
measurements |
||||
|
}) |
||||
|
expect(fakeDevice).to.have.property('start') |
||||
|
}) |
||||
|
|
||||
return { |
it('should generate data', function (done) { |
||||
stop, |
fakeDevice.start() |
||||
start, |
setTimeout(() => { |
||||
send, |
let data = fakeDevice.getData() |
||||
getData |
done(!data.length) |
||||
} |
}, 500) |
||||
|
}) |
||||
|
|
||||
|
it('should send data to influx', function (done) { |
||||
|
setTimeout(() => { |
||||
|
if (!connectionWriteData) return done('No data') |
||||
|
if (!connectionWriteData.deviceId) return done('Invalid write data - missing deviceId') |
||||
|
if ( |
||||
|
connectionWriteData.data[0].usage && |
||||
|
connectionWriteData.data[0].voltage && |
||||
|
connectionWriteData.data[0].temperature && |
||||
|
connectionWriteData.data[0].timestamp |
||||
|
) { |
||||
|
done() |
||||
|
} else { |
||||
|
done('Invalid write data format') |
||||
} |
} |
||||
|
}, 1000) |
||||
|
}) |
||||
|
}) |
||||
|
@ -0,0 +1,23 @@ |
|||||
|
const DeviceManager = require('./src/fake-device-manager') |
||||
|
const FakeDeviceConnection = require('./src/fake-device-connection')() |
||||
|
|
||||
|
const updateStats = require('./src/stats') |
||||
|
|
||||
|
console.log('Generating data - send interval: 30s') |
||||
|
|
||||
|
let deviceManager = DeviceManager({ |
||||
|
deviceCount: 10, |
||||
|
metricsInterval: 30, |
||||
|
connection: FakeDeviceConnection, |
||||
|
onUpdateStats: updateStats, |
||||
|
measurements: { |
||||
|
temperature: {type: 'integer', min: -10, max: 50}, |
||||
|
air_humidity: {type: 'integer', min: 30, max: 100}, |
||||
|
ground_humidity: {type: 'integer', min: 30, max: 100}, |
||||
|
airforce: {type: 'integer', min: 30, max: 100} |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
updateStats(deviceManager) |
||||
|
|
||||
|
deviceManager.start() |
File diff suppressed because it is too large
@ -0,0 +1,30 @@ |
|||||
|
{ |
||||
|
"name": "iot-dummy-data-generator", |
||||
|
"version": "0.1.0", |
||||
|
"description": "Spawn dummy IoT devices and generate custom data that can be send to some data store.", |
||||
|
"main": "index.js", |
||||
|
"scripts": { |
||||
|
"test": "mocha --watch --reporter spec" |
||||
|
}, |
||||
|
"author": "Vedran Jukic", |
||||
|
"license": "MIT", |
||||
|
"dependencies": { |
||||
|
"influx": "^5.0.3", |
||||
|
"object-sizeof": "^1.1.1", |
||||
|
"progress": "^1.1.8" |
||||
|
}, |
||||
|
"devDependencies": { |
||||
|
"eslint": "^3.11.1", |
||||
|
"eslint-config-standard": "^6.2.1", |
||||
|
"eslint-plugin-promise": "^3.4.0", |
||||
|
"eslint-plugin-standard": "^2.0.1", |
||||
|
"chai": "^3.5.0", |
||||
|
"deepstream.io": "^2.0.0", |
||||
|
"deepstream.io-client-js": "^2.0.0", |
||||
|
"diff": "^3.0.1", |
||||
|
"jsdoc": "^3.4.3", |
||||
|
"mocha": "^3.1.2", |
||||
|
"sinon": "^1.17.6", |
||||
|
"winston": "^2.3.0" |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue