Scripting architecture
StormWeaver relies on scripts written in Lua for test scenarios and utility code for the scenarios.
The C++ code is just a framework, it provides a helper architecture and executes a main lua script. If that script does nothing, the program just exits after startup.
There are also helper functions/classes written in lua, using the C++ code. The goal of these is to simplify the development of test scenarios, while also allowing easy modification without rebuilding the main executable.
Folder structure
Lua scripts are stored in two directories:
scenarios
is intended for specific test scenariosscripts
is intended for helper functions/classes usable by multiple scenarios
These directories are added to the search path at two locations:
- Relative to the executable (which is
bin/stormweaver
, the directories have to be in the same folder asbin
) - Relative to the current working directory
3rd party libraries
Additional, several 3rd party lua libraries are also included and are usable by scripts/scenarios. These are the following:
- argparse for command line arguments
- inspect.lua for dumping lua objects
- toml.lua for dealing with config file
C++ binding
Stormweaver includes several classes/functions implemented in C++, which are usable in lua scripts. The complete list of these functions is available in the Lua C++ reference.
Scenario configuration
The argparse
library is included, and the C++ runner forwards all arguments to the script, including the scenario filename.
The lua helpers already create a default parser using the global variable argparser
, which includes handling the common arguments, so scenarios only have to set up additional scenario specific arguments.
Multi-threaded structure
StormWeaver is a multithreaded, concurrent test framework, while lua is a single threaded scripting language. To make the two work together, it uses multiple lua instances:
- There's one "main" instance used for the scenario startup and setup
- There's one instance per worker thread when running workloads
- And any of the above threads also might start background workers, resulting in additional lua threads
The main thread and background workers are lua-first:
there's a lua function (main
in case of the main thread, user specified for the other) that gets executed, and when this function ends, the thread also exists.
The worker threads are hovever C++-first: the random workload is generated by a C++ runner, and it only executes lua functions when it is neccessary.
Limitations
To ensure that all threads have access to the same functions, the scenario file is loaded for all lua states.
This results in the following limitations:
- the scenario script, and included other scripts get processed multiple times
- anything that is executed directly by the script will be executed by all threads
- while global variables will be available in all threads, their values will be different and won't be synced
In line with this, it is recommended that script/scenario files:
- shouldn't rely on mutable global variables
- shouldn't execute code directly in the source file, instead everything should go into the
main
functions