Skip to content

v4.0 Scenarios

Verobika Kochugova edited this page Jun 5, 2018 · 39 revisions

Contents

  1. Introduction
    1.1. JSR-223 Compliance
    1.2. New Version Changes
  2. DSL
    2.1. Step
    2.1.1. Methods
    2.1.2. Types
    2.1.2.1. Basic
    2.1.2.2. Additional Shortcuts
    2.1.2.2.1. Built-In
    2.1.2.2.2. Custom
    2.2. Values Substitution
    2.3. Non-Blocking Execution
    2.4. Resume Support
  3. Examples
    3.1. Javascript
    3.1.1. External Command
    3.1.2. Load
    3.1.3. Weighted Load
    3.1.4. Chain Load
    3.2. Other Scripting Languages

1. Introduction

The user scenarios are executed by the [Java's scripting engine|https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/]. Mongoose exposes the specific DSL to the user scenarios to run the performance tests.

1.1. JSR-223 Compliance

The JSR-223 compliant scenario engines support has the following benefits in comparison to the old approach:

  • The full power of scripting language including conditions, arithmetic, variables, etc
  • Ability to customize and reuse the load steps
  • Less complicated support (most of the logic and complexity goes to the 3rd party scripting engine which is much more stable and established)

1.2. New Version Changes

2. DSL

Generally, to define a scenario an user should:

  1. Define at least one load step in the script
  2. Invoke the defined steps using method run either start

Note: Javascript scenarios are supported out-of-the-box (the corresponding engine is included in the JVM by default). So the examples below are in Javascript. It's necessary to put the custom JSR-223 implementation jar to the <USER_HOME_DIR>/.mongoose/<VERSION>/ext directory to use other scripting languages for scenarios.

2.1. Load Step

The load step is the basic entity which should be used to make a scenario. Mongoose's DSL defines few basic steps and a lot of additional shortcut steps.

Note: All scenario statements are executed locally except the load steps. In the distributed mode the steps are sliced and executed on the specified Mongoose nodes.

2.1.1. Methods

  1. config(config)

    Appends the configuration structure element to the step. An argument should be a dictionary/map with a structure equivalent to the configuration structure (see <USER_HOME_DIR>/.mongoose/<VERSION>/config/defaults.json file for the reference). Returns the copied instance with the configuration instance. Please refer to the step type table for the implementation details.

  2. start()

    Start/resume the step execution. Returns the same instance with state changed to STARTED if call was successful.

  3. stop()

    Stop (with further resumption capability) the step. Returns the same instance with state changed to STOPPED if call was successful.

  4. await()

    Wait while the step state is STARTED. Returns the same instance.

  5. close()

    Free the resources allocated by the step instance. Stops the step execution if was started. Returns nothing. Should be invoked after all other step's methods (also terminate the call chain on the step if any).

  6. run()

    The convenience method for blocking execution flow. Includes start(), await() and close() calls sequence.

2.1.2. Types

2.1.2.1. Basic

Step Type Name Description Example config method behavior
Load Execute a linear load link Apply the configuration (json/map)
ChainLoad Execute a chain load link Append the configuration element (json/map)
WeightedLoad Execute a weighted load link Append the configuration element (json/map)

2.1.2.2. Additional Shortcuts

2.1.2.2.1. Built-In
  1. PreconditionLoad

    The same as load but with disabled metrics output.

  2. NoopLoad

    A load with noop operations type.

  3. CreateLoad

    A load with create operations type.

  4. ReadLoad

    A load with read operations type.

  5. UpdateLoad

    A load with update operations type.

  6. DeleteLoad

    A load with delete operations type.

  7. ReadVerifyLoad

    A load with read operations type and enabled content verification.

  8. ReadRandomRangeLoad

    A load with read operations type. Performs the reading of a single random byte range per operation.

  9. ReadVerifyRandomRangeLoad

    A load with read operations type. Performs the reading of a single random byte range per operation. The data being read is verified also.

  10. UpdateRandomRangeLoad

    A load with read operations type. Performs the single byte range update operations.

2.1.2.2.2. Custom

It's possible to define a custom shortcut step types what is especially useful for the load step type and its derivatives. This is because the load step supports only single configuration element so configuring multiple configuration elements lead to merging them into the single. The additivity rule works for the new configuration parameters (not set before). If the same configuration parameter is set again in the subsequent config call its value will be overridden.

Javascript example:

var copyLoadUsingEnvVars = CreateLoad
    .config(
        {
            "item": {
                "input": {
                    "file": ITEM_INPUT_FILE,
                    "path": ITEM_INPUT_PATH
                },
                "output": {
                    "path": ITEM_OUTPUT_PATH
                }
            }
        }
    );

copyLoadUsingEnvVars.run();

The example applies the additional configuration to the create_load step (which is derivative of the load step) making the new copy_load step. The scenario uses the following environment variables: ITEM_INPUT_FILE, ITEM_INPUT_PATH, ITEM_OUTPUT_PATH. To perform a copy load step its necessary to supply only one valid items input, e.g. specify ITEM_INPUT_FILE value either ITEM_INPUT_PATH. The ITEM_OUTPUT_PATH value specifies the destination path for the items being copied.

To use the scenario above to copy the items using the items input file the following command may be issued:

export ITEM_INPUT_FILE=items2copy.csv
export ITEM_OUTPUT_PATH=/destination_path_bucket_container_etc
java -jar <MONGOOSE_DIR>/mongoose.jar \
    --run-scenario=copy.js

Otherwise, to use the scenario above to copy the items using the items input path (copy from the source path/bucket/container/etc to the target one):

export ITEM_INPUT_PATH=/source_path_bucket_container_etc
export ITEM_OUTPUT_PATH=/target_path_bucket_container_etc
java -jar <MONGOOSE_DIR>/mongoose.jar \
    --run-scenario=copy.js

2.2. Values Substitution

The environment variables are accessible from a scenario with the same name:

export ZONE1_ADDRS=127.0.0.1
export ZONE2_ADDRS=192.168.1.136
java -jar mongoose-next/mongoose.jar \
    --run-scenario=scenario/jsr223/js/chain_with_delay.js

The Javascript example scenario which uses these environment variables:

var config1 = {
    "item" : {
        "output" : {
            "delay" : "1m",
            "path" : "/default"
        }
    },
    "storage" : {
        "net" : {
            "node" : {
                "addrs" : ZONE1_ADDRS
            }
        }
    }
};

var config2 = {
    "load" : {
        "type" : "read"
    },
    "storage" : {
        "net" : {
            "node" : {
                "addrs" : ZONE2_ADDRS
            }
        }
    }
};

ChainLoad
    .config(config1)
    .config(config2)
    .run();

2.3. Non-Blocking Execution

In the new version it's possible to execute the steps asynchronously. This allows to deprecate the special parallel step wrapper.

Previous version (not supported anymore):

Parallel
    .step(step1)
    .step(step2)
    .run();

New version:

// start both steps
step1.start();
step2.start();

// wait for the 1st step to finish and stop the 2nd step immediately
step1.await();
step2.stop();

// free the resources
step1.close();
step2.close();

Note: It's necessary to invoke close() method if asynchronous execution mode is used.

2.4. Resume Support

start and stop methods may be used as resume and pause accordingly (if the particular step implementation supports the pausing/resuming).

var startedLoadStep = Load
    .config(...)
    .start()
    
// do something, wait some time, parse the logs, whatever
...

var pausedLoadStep = startedLoadStep.stop();

// do something more
...

var resumedLoadStep = pausedLoadStep.start();
...

3. Examples

The complete set of the example scenarios is available in the <MONGOOSE_DIR>/example/scenario directory. The scenarios are sorted by the language.

3.1. Javascript

Javascript is the default scripting language which should be used for the custom user scenarios. Other scripting languages are not supported. An user may use deprecated JSON scenarios either JSR-223 compliant scripting language at his/her own risk.

3.1.1. External Command

Example:

// start the process
var cmd = new java.lang.ProcessBuilder()
    .command("sh", "-c", "echo Hello world!")
    .start();

// obtain the process stdin/stderr for further reading
var cmdStdOut = new java.io.BufferedReader(
    new java.io.InputStreamReader(cmd.getInputStream())
);
var cmdStdErr = new java.io.BufferedReader(
    new java.io.InputStreamReader(cmd.getErrorStream())
);

// wait until the command finishes 
cmd.waitFor();

// output the buffered stdin/stderr contents 
while(null != (nextLine = cmdStdOut.readLine())) {
    print(nextLine);
}
while(null != (nextLine = cmdStdErr.readLine())) {
    print(nextLine);
}

cmdStdOut.close();
cmdStdErr.close();

Notes:

  1. The command is invoked using /bin/sh -c <CMD> command in order to support additional Unix shell capabilities like the pipeline. This allows to run the complex commands like ps alx | grep java but is not portable.

  2. The config method accepts single string value as argument. Subsequent calls on the same step discards previous value setting. Returns the new step instance of the same type so the call may be included into the call chain.

3.1.2. Linear Load

Example:

Load.run();

The config method appends the configuration structure element to the step. An argument should be a dictionary/map with a structure equivalent to the configuration structure (see <MONGOOSE_DIR>/config/defaults.json file for the reference). Subsequent calls merge the configurations (see the details). Returns the new step instance of the same type so the call may be included into the call chain.

3.1.3. Weighted Load

See also the Weighted Load specification.

Example:

WeightedLoad
    .config(
        {
            "load" : {
                "generator" : {
                    "weight" : 20
                },
                "step" : {
                    "limit" : {
                        "time" : "5m"
                    }
                }
                "type" : "create"
            }
        }
    )
    .config(
        {
            "load" : {
                "generator" : {
                    "recycle" : {
                        "enabled" : true
                    },
                    "weight" : 80
                },
                "type" : "read"
            }
        }
    )
    .run();

The config method appends the configuration structure element to the step. An argument should be a dictionary/map with a structure equivalent to the configuration structure (see <MONGOOSE_DIR>/config/defaults.json file for the reference). Subsequent calls on the same step appends the configuration structure to the list. Returns the new step instance of the same type so the call may be included into the call chain.

3.1.4. Chain Load

See also the Chain Load specification.

Example:

var createConfig = {
    "load" : {
        "step" : {
            "limit" : {
                "time" : "1h"
            }
        }
    }
};

var readConfig = {
    "load" : {
        "type" : "read"
    }
};

var deleteConfig = {
    "item" : {
        "output" : {
            "file" : "items_passed_through_create_read_delete_chain.csv"
        }
    },
    "load" : {
        "type" : "delete"
    }
};

ChainLoad
    .config(createConfig)
    .config(readConfig)
    .config(deleteConfig)
    .run();

The example using the delay between the operations capability:

var config1 = {
    "item" : {
        "output" : {
            "delay" : "1m",
            "path" : "/default"
        }
    },
    "storage" : {
        "net" : {
            "node" : {
                "addrs" : ZONE1_ADDRS
            }
        }
    }
};

var config2 = {
    "load" : {
        "type" : "read"
    },
    "storage" : {
        "net" : {
            "node" : {
                "addrs" : ZONE2_ADDRS
            }
        }
    }
};

ChainLoad
    .config(config1)
    .config(config2)
    .run();

Note the environment variables ZONE1_ADDRS and ZONE2_ADDRS which should be set externally.

The config method appends the configuration structure element to the step. An argument should be a dictionary/map with a structure equivalent to the configuration structure (see <USER_HOME_DIR>/.mongoose/<VERSION>/config/defaults.json file for the reference). Subsequent calls on the same step appends the configuration structure to the list. Returns the new step instance of the same type so the call may be included into the call chain.

3.2. Other Scripting Languages

It's possible to use other JSR-223 compliant scripting language to write down custom scripts. However there's no official support for other scripting languages. The are example dockerfiles for the Groovy support and for the Jython support are available for the reference.

Clone this wiki locally