Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@asyncapi/fluffy-robot

Package Overview
Dependencies
Maintainers
3
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@asyncapi/fluffy-robot - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

example-projects/game-processor/asyncapi.yaml

7

package.json
{
"name": "@asyncapi/fluffy-robot",
"version": "0.2.0",
"version": "0.3.0",
"type": "commonjs",

@@ -36,2 +36,3 @@ "description": "The asyncapi command line library to test your app at scale.",

"ajv": "^8.6.0",
"async-mqtt": "^2.6.1",
"chalk": "^4.1.0",

@@ -46,6 +47,6 @@ "commander": "^7.2.0",

"@semantic-release/release-notes-generator": "^9.0.1",
"@types/node": "^14.17.3",
"@types/node": "^14.17.5",
"all-contributors-cli": "^6.14.2",
"conventional-changelog-conventionalcommits": "^4.4.0",
"eslint": "^7.29.0",
"eslint": "^7.31.0",
"eslint-plugin-mocha": "^9.0.0",

@@ -52,0 +53,0 @@ "eslint-plugin-security": "^1.4.0",

@@ -1,4 +0,8 @@

# AsyncApi Performance Tester
# AsyncApi Simulator
___
In development
---
Ever wondered what it would feel like your application to

@@ -10,5 +14,6 @@ be the center of interest?

#### Define and simulate high traffic
#### scenarios for your app and create statistics.
#### Define and simulate scenarios for your applications and create statistics.
Usage

@@ -21,4 +26,43 @@

Run sample application by specifying the corresponding
AsyncApi and scenario files.
```
simulator -f ./example-projects/game-processor/asyncapi.yaml -s ./example-projects/game-processor/scenario.yaml
or
simulator -b ../ -f ./simulatorFolder/example-projects/game-processor/asyncapi.yaml -s ./simulatorFolder/example-projects/game-processor/scenario.yaml
```
### Cli
```
Options:
-v AsyncApi simulator cli version.
-f, --filepath <type> The filepath of a AsyncAPI document, as either yaml or json file.
-s, --scenario <type> The filepath of a json or yaml file which defines a scenario based on the spec.
-b, --basedir <type> The basePath from which relative paths are computed.
Defaults to the directory where simulator.sh resides. (default: "./").
-h, --help Display help for flags and commands.
```
### Supported Protocols
- mqtt
### AsyncApi File
The file where the api you want to test is defined. By specifying the x-plot: {id} field
under a channel will automatically make the channel available for sending requests.
### Scenario File
Here with the plot-{id} (where id is the same as the x-plot: {id} in the field you specified in the AsyncAPI channel) field you:
- Connect your AsyncApi and scenario File.
- Specify the parameters for each channel and have the options for them to be randomly generated.
- Specify the payload you want to send.

@@ -9,24 +9,51 @@ #!/usr/bin/env node

const {scenarioParserAndConnector} = require('../parser/index');
const {RequestManager} = require('../RequestHandler/RequestManager');
const rdInterface = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function parseAsyncApi(handlingContext) {
if (handlingContext.ready && handlingContext.scenarioReady) {
handlingContext.ParsedAndFormated = scenarioParserAndConnector(handlingContext.file,handlingContext.scenarioFile);
} else {
console.log('\nUnable to complete AsyncApi File parsing. The file is either non-Existent or there was an unknown Error.\nPress Ctrl + c to terminate');
const enumerateOptions = (serverNames) => {
let result = '';
serverNames.forEach((value,i) => {
result += `\n${i}: ${value}`;
});
return result;
};
const checkFilepath = (asyncFile,regex,basedir) => {
if (!String(asyncFile).match(regex)) {
console.log('\nError: Filepath provide does not point to a yaml or json file. You must provided either a yaml or json.');
return false;
}
}
try {
if (!basedir) {
filesystem.accessSync(asyncFile , filesystem.constants.R_OK);
} else {
filesystem.accessSync(path.resolve(basedir, asyncFile) , filesystem.constants.R_OK);
}
} catch (err) {
console.log('Error: Accessing the provided file. Make sure it exists and the user in the terminal session has read access rights.');
return false;
}
return true;
};
const inputLoopScenario = (handlingContext) => {
handlingContext.rd.question(`\nEnter a proper ${chalk.blueBright('scenario')} document filepath:`, (scenarioFile) => {
filesystem.access(scenarioFile, 1, (err) => {
if (err) {
console.log(`\nError in accessing provided ${chalk.blueBright('scenario')} file \nDetails:${err}\n\n`);
inputLoopScenario(handlingContext);
} else if (!String(scenarioFile).match(handlingContext.yamlJsonRegex)) {
console.log(`\nPlease provide a proper ${chalk.blueBright('scenario')} filepath ex: ./myAsyncApi.json ./myAsyncApi.yaml:`);
inputLoopScenario(handlingContext);
const inputLoopServer = (availableServers) => {
return new Promise((resolve) => {
rdInterface.question('\nSelect the server you want to target\n' + 'Options' + `\n${enumerateOptions(availableServers)}\nSelect:` , (selectedServer) => {
const questionLoop = (availableServers) => {
rdInterface.question('\nPlease select one server id number from the list\n' + 'Options:' + `\n${enumerateOptions(availableServers)}\nSelect:` , (selectedServer) => {
if (selectedServer < 0 || selectedServer > availableServers.length -1) {
questionLoop(availableServers);
} else {
resolve(availableServers[parseInt(selectedServer, 10)]);
}
});
};
if (selectedServer < 0 || selectedServer > availableServers.length -1) {
questionLoop(availableServers);
} else {
handlingContext.scenarioFile = scenarioFile;
handlingContext.scenarioReady = true;
parseAsyncApi(handlingContext);
resolve(availableServers[parseInt(selectedServer, 10)]);
}

@@ -37,52 +64,51 @@ });

const inputLoopAsyncApi = (handlingContext) => {
handlingContext.rd.question(`\nEnter a proper ${chalk.green('asyncApi')} document filepath:`, (filepath) => {
filesystem.access(filepath, 1, (err) => {
if (err) {
console.log(`\nError in accessing provided file \nDetails:${err}\n\n`);
inputLoopAsyncApi(handlingContext);
} else if (!String(filepath).match(handlingContext.yamlJsonRegex)) {
console.log('\nPlease provide a proper filepath ex: ./myAsyncApi.json ./myAsyncApi.yaml:');
inputLoopAsyncApi(handlingContext);
} else {
handlingContext.ready = true;
handlingContext.file = filepath;
if (!handlingContext.scenarioFile) {
inputLoopScenario(handlingContext);
}
// eslint-disable-next-line sonarjs/no-identical-functions
filesystem.access(handlingContext.scenarioFile, 1, (err) => {
if (err) {
console.log(`\nError in accessing provided ${chalk.blueBright('scenario')} file \nDetails:${err}\n\n`);
inputLoopScenario(handlingContext);
} else if (!String(handlingContext.scenarioFile).match(handlingContext.yamlJsonRegex)) {
console.log(`\nPlease provide a proper ${chalk.blueBright('scenario')} filepath ex: ./myAsyncApi.json ./myAsyncApi.yaml:`);
inputLoopScenario(handlingContext);
const inputLoopScenario = (rd,scenario,regex,basedir) => {
const isFileValid = checkFilepath(scenario,regex,basedir);
if (!isFileValid) {
return new Promise((resolve) => {
rd.question('\nPlease provide an existent yaml or json file .It should abide by the scenario json schema.\nScenario filepath:',(answer) => {
const inputLoop = (filepath) => {
const isFileValid = checkFilepath(filepath,regex,basedir);
if (!isFileValid) {
rd.question('Please fix errors and provide a correctly formatted and' +
' accessible file in filepath.\nScenario filepath:',inputLoop);
} else {
//handlingContext.scenarioFile = handlingContext.scenarioFile;
handlingContext.scenarioReady = true;
parseAsyncApi(handlingContext);
resolve(path.resolve(basedir,filepath));
}
}
);
}
};
inputLoop(answer);
});
});
});
}
return Promise.resolve(path.resolve(basedir,scenario));
};
const inputLoopAsyncApi = (rd,asyncFile,regex,basedir) => {
const isFileValid = checkFilepath(asyncFile,regex,basedir);
if (!isFileValid) {
return new Promise((resolve) => {
rd.question('\nPlease provide an existent yaml or json file.It should abide by the asyncApi Spec.\nAsyncApi filepath:',(answer) => {
const inputLoop = (filepath) => {
const isFileValid = checkFilepath(filepath,regex,basedir);
if (!isFileValid) {
rd.question('Please fix errors and provide a correctly formatted and accessible file in filepath.\nAsyncApi Filepath:',inputLoop);
} else resolve(path.resolve(basedir,filepath));
};
inputLoop(answer);
});
});
}
return Promise.resolve(path.resolve(basedir,asyncFile));
};
/**
* Verifies the command line arguments, re-prompts in case of error. Parses file and returns the object representation.
* Verifies the command line arguments, re-prompts in case of error. Parses AsyncApi File and returns the object representation.
* @returns {Promise<*|null>}
* @param rd
* @param file
* @param asyncApiFilepath
* @param scenarioFile
* @param basedir
*/
const verifyInput_ParseAndLinkFiles = async (rd, file,scenarioFile) => {
const handlingContext = this;
handlingContext.ready = false;
handlingContext.rd = rd;
handlingContext.file = file;
handlingContext.scenarioFile= scenarioFile;
const yamlJsonRegex = RegExp(/^.*\.(json|yaml)$/, 'gm');
handlingContext.yamlJsonRegex = yamlJsonRegex;
const verifyInputGetData = async (rd, asyncApiFilepath,scenarioFile,basedir) => {
const yamlJsonRegex = new RegExp(/^.*\.(json|yaml)$/, 'gm');

@@ -94,51 +120,34 @@ console.log(chalk.blueBright(`

if (!!file) {
if (!String(file).match(yamlJsonRegex)) {
console.log('\nPlease provide a correctly formatted filepath ex: ./myAsyncApi.json ./myAsyncApi.yaml:');
inputLoopAsyncApi(handlingContext);
} else {
handlingContext.file = file;
handlingContext.ready = true;
if (!scenarioFile) {
inputLoopScenario(handlingContext);
} else if (!String(scenarioFile).match(yamlJsonRegex)) {
inputLoopScenario(handlingContext);
} else {
handlingContext.scenarioFile = scenarioFile;
handlingContext.scenarioReady = true;
parseAsyncApi(handlingContext);
}
}
} else {
console.log('\nFilepath not provided');
inputLoopAsyncApi(handlingContext);
}
asyncApiFilepath = await inputLoopAsyncApi(rd,asyncApiFilepath,yamlJsonRegex,basedir);
return handlingContext.ready ? await handlingContext.ParsedAndFormated : null;
scenarioFile = await inputLoopScenario(rd,scenarioFile,yamlJsonRegex,basedir);
const structuredData = await scenarioParserAndConnector(asyncApiFilepath,scenarioFile);
const availableServers = Object.keys(structuredData.servers);
structuredData.targetedServer = await inputLoopServer(availableServers);
return structuredData;
};
(async function Main () {
program.version('0.0.1', 'v', 'async-api performance tester cli version');
program.version('0.0.1', '-v', 'AsyncApi simulator cli version.');
program
.requiredOption('-f, --filepath <type>', 'The filepath of a async-api specification yaml or json file')
.requiredOption('-s, --scenario <type>', 'The filepath of a file defining a scenario based on the spec.')
.option('-b, --basedir <type>', 'The basepath from which relative paths are computed.\nDefaults to the directory where simulator.sh resides.');
.requiredOption('-f, --filepath <type>', 'The filepath of a AsyncAPI document, as either yaml or json file.')
.requiredOption('-s, --scenario <type>', 'The filepath of a json or yaml file which defines a scenario based on the spec.')
.option('-b, --basedir <type>', 'The basePath from which relative paths are computed.\nDefaults to the directory where simulator.sh resides.','./');
program.parse(process.argv);
///Interface , SignalsHandling
const cliInterface = readline.createInterface({
input: process.stdin,
output: process.stdout
});
cliInterface.on('SIGINT', () => {
rdInterface.on('SIGINT', () => {
console.log('\nShutting down');
process.exit();
});
cliInterface.on('close', () => {
rdInterface.on('close', () => {
console.log('\nAsync-api performance tester instance closed');
process.exit();
});
cliInterface.on('uncaughtException', (err) => {
rdInterface.on('uncaughtException', (err) => {
console.log(err);

@@ -159,6 +168,17 @@ process.exit();

});
let asyncApiPath;
let scenarioPath;
const options = program.opts();
if (options.basedir) {
asyncApiPath = path.resolve(options.basedir,options.filepath);
scenarioPath = path.resolve(options.basedir,options.scenario);
} else {
asyncApiPath = path.resolve(options.filepath);
scenarioPath = path.resolve(options.scenario);
}
const structuredData = await verifyInputGetData(rdInterface, path.resolve(asyncApiPath),path.resolve(scenarioPath),options.basedir);
const manager = RequestManager();
await manager.createReqHandler(structuredData);
await manager.startOperations();
}());
await verifyInput_ParseAndLinkFiles(cliInterface, path.resolve(options.filepath),path.resolve(options.scenario));
}());

@@ -72,4 +72,6 @@ const parser = require('@asyncapi/parser');

const eps = value.eps;
const parameters = value.parameters;
const payload = value.payload;
if (parserContext.PublishOperations.soloOps.hasOwnProperty(plotId[0])) {
Object.assign(parserContext.PublishOperations.soloOps[plotId[0]],{eventsPsec: eps});
Object.assign(parserContext.PublishOperations.soloOps[plotId[0]],{eventsPsec: eps,parameters,payload});
}

@@ -76,0 +78,0 @@ }

@@ -21,3 +21,3 @@ {

},
"^plot-[\\w\\d]+$": {
"^plot-[\\w\\d]+$" : {
"type": "object",

@@ -33,2 +33,18 @@ "additionalProperties": false,

"description": "This determines whether it should be prioritized in case the resources to emit events is insufficient "
},
"payload": {
"type": "object",
"additionalProperties": true,
"description": "The payload that is going to be sent is currently specifically defined."
},
"parameters": {
"type": "object",
"description": "Specify the parameter instance variables of the channel, if any are present.",
"additionalProperties": false,
"patternProperties": {
"^[\\w\\d]{1,28}$" : {
"type": "string",
"description": "A parameter instance variable with the corresponding assigned value as string."
}
}
}

@@ -35,0 +51,0 @@ }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc