DEV Community

Cover image for A simple AI to simulate multiple methods call
Nicola
Nicola

Posted on

A simple AI to simulate multiple methods call

An introduction to the use case

WHY

I've maded a simple js script to handle multiple method call with different params. The reasons why I needed this script are really simple:

  1. Simulate multiple server-side methods with different params
  2. Stress the server (or the client) with a lot of method calls
  3. Test the strengthness of my server-side methods
  4. Automate the server behaviours, because I don't want to trigger manually a lot of methods while develop.

HOW

This script works in a simple way, it accepts an array of defined methods with an array of different params. So the script will call these methods with random params, simulating the execution of these methods.

AI.js

The following is the implementation of the "AI":

/**
 _______  ___             ___  _______ 
|   _   ||   |           |   ||       |
|  |_|  ||   |           |   ||  _____|
|       ||   |           |   || |_____ 
|       ||   |  ___   ___|   ||_____  |
|   _   ||   | |   | |       | _____| |
|__| |__||___| |___| |_______||_______|

@desc   a script to automate js method run
@author nicolacastellanidev@gmail.com
*/
function AI(...bindings) {
  if (!bindings) {
    throw new Error('AI cannot run without bindings');
  }
  this.bindings = bindings;
}

AI.prototype = {
  running: false,
  /** @desc run a random binding with random parameters*/
  run() {
    this.running = true;
    /** get a random method to call with random params */
    const randomBindingIndex = Math.floor(Math.random() * this.bindings[0].length);
    const binding = this.bindings[0][randomBindingIndex];
    const randomParamIndex = Math.floor(Math.random() * binding.withParams.length);

    /** call random binding */
    try {
      this.log(`>>> SIMULATING *** ${binding.method.name} *** WITH PARAMS *** ${Object.values(binding.withParams[randomParamIndex])} ***`);
      binding.method.call(this, ...Object.values(binding.withParams[randomParamIndex]));
    } catch (ex) {
      this.log(`>>> SIMULATING *** ${binding.method.name} *** WITH PARAMS *** ${binding.withParams[randomParamIndex]} ***`);
      this.log(`>>> ERROR: ${ex.message}`);
    }
    /** then set a random timeout for the next call */
    this.runTimeout = setTimeout(() => {
      this.run();
    }, (Math.floor(Math.random() * 5) + 2) * 1000);
  },
  /** @desc stop the AI execution */
  stop() {
    this.running = false;
    this.log(`>>> SIMULATION STOPPED`);
    clearTimeout(this.runTimeout);
  },

  /** @desc log method - appen a string to the console html element */
  log(what) {
    console.log(`${what}</br>`)
  }
};

Fake methods implementation

/**
* FAKE METHODS IMPLEMENTATION
*/
const fakeMethod = (url) => {
  console.log(`A fakeMethod has been called with url: ${url}`);
}

const sum = (a, b) => {
  console.log(`The sum is: ${a + b}`);
}

const diff = (a, b) => {
  console.log(`The diff is: ${a - b}`);
}

AI initialization with fake methods

/**
* AI INITIALIZATION
*/
const r2d2 = new AI(
  [
    {
      method: fakeMethod,
      withParams: [
        {url: '/simulate?action=1'},
        {url: '/simulate?action=2'},
      ]
    },
    {
      method: sum,
      withParams: [
        {a: 1, b: 1},
        {a: 1, b: 3}
      ]
    },
    {
      method: diff,
      withParams: [
        {a: 1, b: 1},
        {a: 3, b: 5}
      ]
    }
  ]
);

Run the AI

With the method run you can start the simulations:

r2d2.run();

Stop the AI

With the method stop you can stop the simulations:

r2d2.stop();

Live example

Conclusions

This is just an example, you can extend as you prefer with more complex simulations, or AI behaviours.

Latest comments (3)

Collapse
 
codelitically_incorrect profile image
codelitically_incorrect • Edited

pretty cool

Collapse
 
mastrobardo profile image
davide

I don't really understand how this could be useful at all. Methods calls, stress test, ...etc should be covered by test, and randomness !== good testing.

Collapse
 
nicolalc profile image
Nicola

You're right, the idea is to trigger 'automatically' some methods.

In my case I have multiples server-side rest API methods to test, so I use this script to make multiple rest calls to my server without any manual rest call.

So I can check if there are some chaining or performance issues with a lot of consecutive or parallel rest api calls.

For example, I can create 1000 AI instances, and each instance will make a rest call to the server, so I can check if the server is working good and if the data generated is correct, also I can check if the server is working good with a lot of input requests.

Another useful use case is on websocket, if you want to test websocket interactions with broadcast/unicast messages without calling manually a server-side method you can use this script, take this example:

loom.com/share/8cffce9f751241f997b...

In this example I'm simulating a server-side methods (environment update / node insert, etc..) to test my websocket connections.