Skip to content


Erhan Bağdemir edited this page Nov 2, 2019 · 35 revisions

Sessions are contextual objects to keep state during scenario and simulation executions. Sessions are used to share data between scenarios/or DSLs if ReactiveSimulationRunner is used. There are two implementations of sessions:

User Sessions

Rhino creates UserSession instances as tokens to loop through the load generation pipeline to generate load. The framework creates a new UserSession for each user. It lets UserSession instances stream through the load generation loop. Load generation loop consists of user created scenario methods which are executed for the active UserSession. Once all scenarios are executed, the framework starts from the beginning with a new token, so the UserSession instance will be discarded.

User sessions are contextual object which can be used to store data to share among scenario methods. In non-reactive mode (scenario mode), a simulation might contain multiple scenario methods in its scope. The scenario methods will then be executed sequentially by the framework while passing the user session instances as method arguments. This will give test developers the opportunity to add some object into the sessions context where the next scenarios are able to pick up from:

  @Scenario(name = "Scenario 1")
  public void performScenario1(Measurement measurement, UserSession session) {
      session.add("variable", 1);

  @Scenario(name = "Scenario 2")
  public void performScenario2(Measurement measurement, UserSession session) {
      session.get("variable").ifPresent(var -> out.println(var));

A new session instance will be created every time a testing cycle is started. Once all scenarios executed, the session and its state will be discarded. For the next turn, a newly created sessions instances will be instantiated. If you want to keep a state during the whole simulation execution, simulation session is the right place to retain the data.

Sessions contain also information about the user:


Simulation Sessions

Simulation session is a contextual object to store information during the simulation's lifetime. In contrast to the user sessions, the data stored in the simulation session is available during the testing session. It is accessible through user session instances which are injected into the scenario methods:


Simulation session is handy if you want to prepare the simulation with @Prepare methods. The prepare steps are executed exactly once for each user. It gives developers the opportunity to prepare user's test workflow, e.g upload a file into user's storage:

  public static LoadDsl prepare() {
    return Start.dsl()
            .header(c -> from(X_REQUEST_ID, "Rhino-" + UUID.randomUUID().toString()))
            .header(X_API_KEY, SimulationConfig.getApiKey())
            .upload(() -> file("classpath:///image.png"))
            .saveTo("result", Scope.SIMULATION));

The prepare will be called for every user requested from the user repository. Once user workflows are initialized after prepare execution, the information which you might require in your tests, e.g the URI of the uploaded file, can be stored into the Simulation context, by telling the spec in saveTo("result", Scope.SIMULATION) explicitly.

In Load DSL you can access the Simulation session over user sessions:

  @Dsl(name = "Shop Benchmarks")
  public LoadDsl singleTestDsl() {
    return Start.dsl()
        .run(http("Files Request")
            .header(X_API_KEY, SimulationConfig.getApiKey())
            .header(session -> from(X_REQUEST_ID, "Rhino-" + UUID.randomUUID().toString()))
            .endpoint(session -> session.getSimulationSession().<HttpResponse> get("result")
                .map(r -> r.getResponse().getUri())

The endpoint will take the value from the simulation session.

WARNING While calling saveTo() if there is no scope is defined the default one is the user scope.

Sessions in Load DSL

If the Load DSL does encompass multiple runners, you can use session objects to exchange information between specs. To store information use session(key, object supplier) runner. Take a look at the following example:

  @Dsl(name = "Upload and Get")
  public LoadDsl loadTestPutAndGetFile() {
    return Start.dsl()
        .session("userB", () -> userProvider.take()) ❶
        .run(http("PUT text.txt")  ❷ 
            .header(session -> from(X_REQUEST_ID, "Rhino-" + userProvider.take())) ❸
            .header(X_API_KEY, SimulationConfig.getApiKey())
            .endpoint(session -> FILES_ENDPOINT)
            .upload(() -> file("classpath:///test.txt"))
        .run(http("GET text.txt")
            .header(c -> from(X_REQUEST_ID, "Rhino-" + userProvider.take()))
            .header(X_API_KEY, SimulationConfig.getApiKey())
            .auth(session("userB")) ❹
            .endpoint(session("PUT text.txt", "endpoint")) ❺

With line ❶ we are storing a new user instance provided by userProvider in the current user session with the key "userB". In the second HTTP spec in line ❹, we can then use the userB in auth() which makes the framework use the second user in HTTP request. header() methods in HttpSpec take functions as parameter which takes session instances ❸, so you can access user session to pick up information.

You can’t perform that action at this time.