From 8a6de3c8317d8a69379dbfdc50fc4282a7b3d99f Mon Sep 17 00:00:00 2001 From: Camina Drummer Date: Tue, 29 Aug 2023 18:36:14 -0400 Subject: [PATCH 1/3] Create LoadTestEnglish class with basic methods --- load-test-engine/load-test-engine.ts | 77 ++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 load-test-engine/load-test-engine.ts diff --git a/load-test-engine/load-test-engine.ts b/load-test-engine/load-test-engine.ts new file mode 100644 index 0000000..3775ffc --- /dev/null +++ b/load-test-engine/load-test-engine.ts @@ -0,0 +1,77 @@ +const hash = require('crypto'); + +// To generate a label if one is not provided by user +function hashCall(stub, message, interval) { + return hash.createHash('sha256') + .update(stub.toString() + JSON.stringify(message) + interval.toString()) + .digest('hex'); +} + +type stub = { + stub: (arg: any) => any, + message: Record, + interval: number, + timeout: NodeJS.Timeout | undefined, +} + +class LoadTestEngine { + private calls: Record + private active: Record + + constructor() { + this.calls = {}; + this.active = {}; + } + + addCall(stub: (arg: any) => any, message: Record, interval: number, label: string = hashCall(stub, message, interval), timeout: NodeJS.Timeout | undefined): LoadTestEngine { + if (this.calls[label]) { + throw new Error('Label already exists.'); + } + + this.calls[label] = { + stub, + message, + interval, + timeout + } + + return this; + } + + start(labels: Array): void { + labels.forEach((label) => { + // Check that call is not already active + if (!this.active[label]) { + // The associated this.calls object for the current label + const call = this.calls[label]; + + // Set a recursive timeout + function repeatCall() { + call.stub(call.message); + call.timeout = setTimeout(repeatCall, call.interval); + } + repeatCall(); + + // Add to active calls tracker + this.active[label] = call; + } + }) + } + + stop(labels: Array): void { + labels.forEach((label) => { + clearTimeout(this.active[label].timeout); + delete this.active[label]; + }) + } + + stopAll() { + for (const label in this.active) { + clearTimeout(this.active[label].timeout); + delete this.active[label]; + } + } + +} + +module.exports = LoadTestEngine; \ No newline at end of file From 587c718cbb123f935f9435dfc1d337f27cef1309 Mon Sep 17 00:00:00 2001 From: Camina Drummer Date: Tue, 29 Aug 2023 21:38:16 -0400 Subject: [PATCH 2/3] Complete working prototype and demo for LoadTestEngine --- load-test-engine/load-test-engine.js | 94 ++++++++++++++++++++++++++++ load-test-engine/load-test-engine.ts | 54 ++++++++++++---- load-test-engine/lte-demo.js | 17 +++++ 3 files changed, 154 insertions(+), 11 deletions(-) create mode 100644 load-test-engine/load-test-engine.js create mode 100644 load-test-engine/lte-demo.js diff --git a/load-test-engine/load-test-engine.js b/load-test-engine/load-test-engine.js new file mode 100644 index 0000000..a13a389 --- /dev/null +++ b/load-test-engine/load-test-engine.js @@ -0,0 +1,94 @@ +// Only used for hashCall() +var hash = require('crypto'); +// Generates a label if one is not provided by user +function hashCall(stub, message, interval) { + return hash.createHash('sha256') + .update(stub.toString() + JSON.stringify(message) + interval.toString()) + .digest('hex'); +} +// Recursively calls setTimeout for repeating calls +function repeatCall(call) { + call.stub(call.message); + call.timeout = setTimeout(function () { repeatCall(call); }, call.interval); +} +// Load test engine to be instantiated +var LoadTestEngine = /** @class */ (function () { + function LoadTestEngine() { + this.calls = {}; + this.active = {}; + } + LoadTestEngine.prototype.addCall = function (stub, message, interval, label, timeout) { + if (label === void 0) { label = hashCall(stub, message, interval); } + if (this.calls[label]) { + throw new Error('Label already exists.'); + } + this.calls[label] = { + stub: stub, + message: message, + interval: interval, + timeout: timeout + }; + console.log("Call ".concat(label, " added.")); + return this; + }; + LoadTestEngine.prototype.removeCall = function (label) { + if (this.calls[label]) { + delete this.calls[label]; + console.log("Call ".concat(label, " removed")); + } + else { + throw new Error('Label does not exist.'); + } + }; + LoadTestEngine.prototype.getLabels = function () { + return Object.keys(this.calls); + }; + LoadTestEngine.prototype.start = function (labels) { + var _this = this; + labels.forEach(function (label) { + // Check that call is not already active + if (!_this.active[label]) { + // The associated this.calls object for the current label + var call = _this.calls[label]; + // Set a recursive timeout + repeatCall(call); + console.log("Call ".concat(label, " started.")); + // Add to active calls tracker + _this.active[label] = call; + } + }); + }; + LoadTestEngine.prototype.startAll = function () { + console.log("Starting all calls."); + for (var label in this.calls) { + if (!this.active[label]) { + var call = this.calls[label]; + repeatCall(call); + console.log("Call ".concat(label, " started.")); + this.active[label] = call; + } + } + }; + LoadTestEngine.prototype.stop = function (labels) { + var _this = this; + labels.forEach(function (label) { + clearTimeout(_this.active[label].timeout); + delete _this.active[label]; + console.log("Call ".concat(label, " stopped.")); + }); + }; + LoadTestEngine.prototype.stopAll = function () { + if (!Object.keys(this.active).length) { + throw new Error('No active calls.'); + } + for (var label in this.active) { + clearTimeout(this.active[label].timeout); + delete this.active[label]; + console.log("Call ".concat(label, " stopped.")); + } + console.log('All active calls stopped.'); + }; + return LoadTestEngine; +}()); + +module.exports = new LoadTestEngine; diff --git a/load-test-engine/load-test-engine.ts b/load-test-engine/load-test-engine.ts index 3775ffc..1130d35 100644 --- a/load-test-engine/load-test-engine.ts +++ b/load-test-engine/load-test-engine.ts @@ -1,12 +1,18 @@ const hash = require('crypto'); -// To generate a label if one is not provided by user +// Generates a label if one is not provided by user function hashCall(stub, message, interval) { return hash.createHash('sha256') .update(stub.toString() + JSON.stringify(message) + interval.toString()) .digest('hex'); } +// Recursive setTimeout for repeating calls +function repeatCall(call) { + call.stub(call.message); + call.timeout = setTimeout(() => {repeatCall(call)}, call.interval); +} + type stub = { stub: (arg: any) => any, message: Record, @@ -27,49 +33,75 @@ class LoadTestEngine { if (this.calls[label]) { throw new Error('Label already exists.'); } - this.calls[label] = { stub, message, interval, timeout } - + console.log(`Call ${label} added.`); return this; } + removeCall(label): void { + if (this.calls[label]) { + delete this.calls[label]; + console.log(`Call ${label} removed`); + } else { + throw new Error('Label does not exist.') + } + } + + getLabels(): Array { + return Object.keys(this.calls); + } + start(labels: Array): void { labels.forEach((label) => { // Check that call is not already active if (!this.active[label]) { // The associated this.calls object for the current label const call = this.calls[label]; - // Set a recursive timeout - function repeatCall() { - call.stub(call.message); - call.timeout = setTimeout(repeatCall, call.interval); - } - repeatCall(); - + repeatCall(call); + console.log(`Call ${label} started.`); // Add to active calls tracker this.active[label] = call; } }) } + startAll(): void { + console.log(`Starting all calls.`); + for (const label in this.calls) { + if (!this.active[label]) { + const call = this.calls[label]; + repeatCall(call); + console.log(`Call ${label} started.`); + this.active[label] = call; + } + } + } + stop(labels: Array): void { labels.forEach((label) => { clearTimeout(this.active[label].timeout); delete this.active[label]; + console.log(`Call ${label} stopped.`); }) } - stopAll() { + stopAll(): void { + if (!Object.keys(this.active).length) { + throw new Error('No active calls.') + } + for (const label in this.active) { clearTimeout(this.active[label].timeout); delete this.active[label]; + console.log(`Call ${label} stopped.`); } + console.log('All active calls stopped.'); } } diff --git a/load-test-engine/lte-demo.js b/load-test-engine/lte-demo.js new file mode 100644 index 0000000..e2e88aa --- /dev/null +++ b/load-test-engine/lte-demo.js @@ -0,0 +1,17 @@ +const engine = require('./load-test-engine.js'); + +const dummyFn1 = (message) => { + console.log(message) +} +const dummyFn2 = (message) => { + console.log(message) +} + +engine + .addCall(dummyFn1, {dF1Message: 'Hi!'}, 1000, 'dummy1') + .addCall(dummyFn2, {dF2Message: 'Hello!'}, 2000, 'dummy2') + .startAll(); + +setTimeout(() => { + engine.stopAll(); +}, 10000) \ No newline at end of file From a4ebdca6dc589ecfeff8f68fdaae8e00ab51982c Mon Sep 17 00:00:00 2001 From: Camina Drummer Date: Tue, 29 Aug 2023 21:57:26 -0400 Subject: [PATCH 3/3] Add removeCall() testing to demo and export instance instead of class --- load-test-engine/load-test-engine.js | 12 +++++------- load-test-engine/load-test-engine.ts | 9 +++++---- load-test-engine/lte-demo.js | 8 ++++++++ 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/load-test-engine/load-test-engine.js b/load-test-engine/load-test-engine.js index a13a389..7be015c 100644 --- a/load-test-engine/load-test-engine.js +++ b/load-test-engine/load-test-engine.js @@ -1,4 +1,3 @@ -// Only used for hashCall() var hash = require('crypto'); // Generates a label if one is not provided by user function hashCall(stub, message, interval) { @@ -6,12 +5,11 @@ function hashCall(stub, message, interval) { .update(stub.toString() + JSON.stringify(message) + interval.toString()) .digest('hex'); } -// Recursively calls setTimeout for repeating calls +// Recursive setTimeout for repeating calls function repeatCall(call) { call.stub(call.message); call.timeout = setTimeout(function () { repeatCall(call); }, call.interval); } -// Load test engine to be instantiated var LoadTestEngine = /** @class */ (function () { function LoadTestEngine() { this.calls = {}; @@ -35,6 +33,7 @@ var LoadTestEngine = /** @class */ (function () { if (this.calls[label]) { delete this.calls[label]; console.log("Call ".concat(label, " removed")); + return this; } else { throw new Error('Label does not exist.'); @@ -51,8 +50,8 @@ var LoadTestEngine = /** @class */ (function () { // The associated this.calls object for the current label var call = _this.calls[label]; // Set a recursive timeout - repeatCall(call); console.log("Call ".concat(label, " started.")); + repeatCall(call); // Add to active calls tracker _this.active[label] = call; } @@ -63,8 +62,8 @@ var LoadTestEngine = /** @class */ (function () { for (var label in this.calls) { if (!this.active[label]) { var call = this.calls[label]; - repeatCall(call); console.log("Call ".concat(label, " started.")); + repeatCall(call); this.active[label] = call; } } @@ -90,5 +89,4 @@ var LoadTestEngine = /** @class */ (function () { }; return LoadTestEngine; }()); - -module.exports = new LoadTestEngine; +module.exports = new LoadTestEngine(); diff --git a/load-test-engine/load-test-engine.ts b/load-test-engine/load-test-engine.ts index 1130d35..92c3802 100644 --- a/load-test-engine/load-test-engine.ts +++ b/load-test-engine/load-test-engine.ts @@ -43,10 +43,11 @@ class LoadTestEngine { return this; } - removeCall(label): void { + removeCall(label): LoadTestEngine { if (this.calls[label]) { delete this.calls[label]; console.log(`Call ${label} removed`); + return this; } else { throw new Error('Label does not exist.') } @@ -63,8 +64,8 @@ class LoadTestEngine { // The associated this.calls object for the current label const call = this.calls[label]; // Set a recursive timeout - repeatCall(call); console.log(`Call ${label} started.`); + repeatCall(call); // Add to active calls tracker this.active[label] = call; } @@ -76,8 +77,8 @@ class LoadTestEngine { for (const label in this.calls) { if (!this.active[label]) { const call = this.calls[label]; - repeatCall(call); console.log(`Call ${label} started.`); + repeatCall(call); this.active[label] = call; } } @@ -106,4 +107,4 @@ class LoadTestEngine { } -module.exports = LoadTestEngine; \ No newline at end of file +module.exports = new LoadTestEngine(); \ No newline at end of file diff --git a/load-test-engine/lte-demo.js b/load-test-engine/lte-demo.js index e2e88aa..b9b4396 100644 --- a/load-test-engine/lte-demo.js +++ b/load-test-engine/lte-demo.js @@ -14,4 +14,12 @@ engine setTimeout(() => { engine.stopAll(); + + console.log('Calls currently stored on engine: ', engine.getLabels()); + + engine + .removeCall('dummy1') + .removeCall('dummy2'); + + console.log('Calls currently stored on engine: ', engine.getLabels()); }, 10000) \ No newline at end of file