Cassandra plugin

Overview

The Cassandra plugin connects QALIPSIS to Apache Cassandra.

It enables interaction with Apache Cassandra clusters for testing distributed data storage and retrieval, as well as accessing data generated by the system under test. It provides three key steps: poll, save, and search.

This page explains configuration, important concepts, and provides examples of usage (poll, save, search).

Technologies addressed
Dependency

io.qalipsis.plugin:qalipsis-plugin-cassandra

Namespace in scenario

cassandra()

Client library

DataStax: a modern, feature-rich and highly tunable Java client library for Apache Cassandra using Cassandra’s binary protocol and Cassandra Query Language.

Supported steps

Poll step

The poll step within the Cassandra plugin polls the newest records from the database table.

Ancestor

Scenario or Step

Functionality

The poll step is created only once in a scenario; it is then used throughout the scenario. The poll step within the Cassandra plugin uses a strategy of “delivered at least once." That means the same logical record might be delivered more than once (for example, on retries or restarts).
To correctly and efficiently poll only new data, the plugin uses:

  • An ORDER BY clause in the query (for example ORDER BY timestamp).

  • A tieBreaker configuration that identifies the column used to compare the "last seen" value (example a timestamp or an increasing id).

Example

This example demonstrates how to configure a poll step using the timestamp as a tiebreaker.

cassandra().poll {
    connect { (1)
        name = "my-poll-step"
        servers = listOf("localhost:9042")
        keyspace = "iot"
        datacenterName = "datacenter1"
    }
    query("SELECT deviceid, timestamp, batterylevel FROM batteryState
       WHERE company = ? ORDER BY timestamp") (2)
    parameters("ACME Inc.") (3)
    tieBreaker {           (4)
        name = "timestamp"
        type = GenericType.INSTANT
    }
    pollDelay(Duration.ofSeconds(1)) (5)
}
1 Define the connection parameters to the cassandra cluster.
2 Define the prepared statement to execute when polling.
3 Bind values to the clauses of the prepared query.
4 Repeat the first column used for sorting and comparison
( or >=, depending on the ascending or descending order).
5 Specify the delay between query executions.
Tips
  • Use the poll step with a left join operator to verify the values saved by your tested system in the database.

  • query requires at least one sorting field (tiebreaker in the example) to filter the newest results and not fetch the same records repeatedly.

  • The latest known value for tiebreaker is used to filter out values already received from the database.

  • Call flatten() after the poll step to transform the list of records into a map of column identifier [CQLIdentifier] to values.

Reference documentation

Refer to the Apache Cassandra documentation for further parameter and configuration information.

Save step

The save step within the Cassandra plugin persists records into a cassandra database using the save query with The Cassandra Query Language (CQL).

Ancestor

Step

Functionality

The save step’s input and step context are used to generate documents to save into a database.

Example
previousStep.cassandra().save { (1)
    name = "my-save-step"
    connect {   (2)
        servers = listOf("localhost:9042")
        keyspace = "iot"
        datacenterName = "datacenter1"
    }

    table { stepContext, input ->   (3)
        "batteryState"
    }

    columns { stepContext, input ->  (4)
        listOf(
            "company",
            "deviceid",
            "timestamp",
            "batterylevel"
        )
    }

    rows { stepContext, input ->   (5)
        listOf(
            CassandraSaveRow(
                "'ACME Inc.'",
                "'${input.deviceId}'",
                "'${input.timestamp}'",
                input.batteryLevel
            )
        )
    }
}
1 Set a placeholder for any preceding step (e.g. execute(), verify(), map(), etc.).
2 Define the connection parameters to the cassandra cluster.
3 Name the output table, that can be resolved from the context and input.
4 Define column names for the output table, that can be resolved from the context and input.
5 Define how input fields are extracted and formatted to the output tables, using the step context and input.
Tips
  • Use the save step after a collect step to reduce the number of queries executed onto the database and reduce the load your scenario generates on it.

  • The save step is extremely flexible; table, rows, and columns depend on the context and input value received from the previous step.

Reference documentation

Refer to the Apache Cassandra documentation for further parameter and configuration information.

Search step

The search step within the Cassandra plugin searches records in the database using a search query.

Ancestor

Step

Functionality

The search step’s input and step context are used to complete the search; the list of results is then forwarded to the next step(s).

Example
previousStep.cassandra().search {
    name = "my-search-step"

    connect {          (1)
        servers = listOf("localhost:9042")
        keyspace = "iot"
        datacenterName = "datacenter1"
    }
    query { stepContext, input ->   (2)
        "SELECT * FROM batteryState WHERE company= ?
           AND deviceid = ? AND timestamp = ?"
    }
    parameters { stepContext, input ->            (3)
        listOf("ACME Inc.", input.input.deviceId, input.input.timestamp)
    }
}
1 Define the connection parameters to the cassandra cluster.
2 Define the query statement, that can be resolved from the context and input.
3 Define the query parameters, using the step context and input.
Tips
  • Use the search step after a collect() step to reduce the number of queries executed onto the database and to reduce the load the scenario generates on the test system.

  • The query parameter may contain ordering clauses.

Reference documentation
  • Refer to the Apache Cassandra documentation for further parameter and configuration information.

Configuration

DSL parameters

Available parameters are described in the table below.

Refer to the Apache Cassandra documentation for further parameter and configuration information.

Parameter Description

connect

Defines the connection parameters to Apache Cassandra.
Applicable Steps: Poll, Search, Save
Optional/Required: Required
Data Type: Lambda within which connection parameters are defined.
Default Value: N/A

Example
connect {
    servers = listOf("localhost:9042")
    keySpace = "iot"
    datacenterProfile = DriverProfile.DEFAULT
    datacenterName = "datacenter1"
}

connect.servers

List of servers available for the connection.
Applicable Steps: Poll, Search, Save
Optional/Required: Required
Data Type: List<String>
Default Value: localhost:9042

Example
connect {
    servers = listOf("localhost:9042")
}

connect.keyspace

Name of the keyspace to use. A keyspace defines how data is replicated across the cluster (replication strategy and replication factor).
Applicable Steps: Poll, Search, Save
Optional/Required: Required
Data Type: String
Default Value: ""

Example
connect {
    keySpace = "iot"
}

connect.datacenterName

Name of the datacenter where data is stored.
Applicable Steps: Poll, Search, Save
Optional/Required: Required
Data Type: String
Default Value: ""

Example
connect {
    datacenterName = "datacenter1"
}

connect.datacenterProfile

Determines how the DataStax driver selects the Cassandra datacenter to be used for routing requests.
Available settings:
* LOCAL: Use the value of connect.datacenterName as the local datacenter.
* PEER: Application must set datacenter to the peer datacenter you want to target.
* DEFAULT: Use the driver’s default selection policy (i.e don’t override the profile’s local datacenter selection).

Applicable Steps: Poll, Search
Optional/Required: Optional
Data Type: DriverProfile (enum: LOCAL, PEER, DEFAULT)
Default Value: DriverProfile.DEFAULT

Example
connect {
    datacenterProfile = DriverProfile.LOCAL
}

query

Defines the prepared statement to query or execute.
Applicable Steps: Poll, Search
Optional/Required: Required
Data Type:
* Poll: String that defines the prepared statement or query to execute.
* Search: Lambda that takes step context and input to return a string.
Default Value: N/A

Example (Poll)
query ("SELECT deviceid, timestamp, batterylevel FROM battery_state WHERE company = ? ORDER BY timestamp")
Example (Search)
query { stepContext, input -> 'SELECT * FROM battery_state WHERE company = ? AND deviceid = ? AND timestamp = ?'}

parameters

Poll: Binds values to the clauses of the prepared query.
Search: Computes the list of values bound to the prepared query using the step context and input.
Applicable Steps: Poll, Search
Optional/Required: Optional
Data Type:
* Poll: List<Any> / vararg Any
* Search: Lambda that takes step context and input and returns List<Any>.
Default Value: emptyList()

Example (Poll)
parameters(listOf(1, "abc")) or parameters(1, "abc")
Example (Search)
parameters {
    stepContext, input -> listOf("ACME Inc.")
}

tieBreaker

Configures the tiebreaker column used to track the "last seen" value for polling.
Applicable Step: Poll
Optional/Required: Required
Data Type: Lambda within which tiebreaker parameters are defined.
Default Value: N/A

Example
tieBreaker {
    name = "timestamp"
    type = GenericType.INSTANT
}

tieBreaker.type

Data type to help the datastax driver interpret a value.
Applicable Step: Poll
Optional/Required: Required
Data Type: GenericType (enum)
Default Value: null

Example
tieBreaker {
    type = GenericType.INSTANT
}

tieBreaker.name

Name of the column used as a tiebreaker.
Applicable Step: Poll
Optional/Required: Required
Data Type: String
Default Value: ""

Example
tieBreaker {
    name = "timestamp"
}

pollDelay

Delay between two polling executions.
Applicable Step: Poll
Optional/Required: Optional
Data Type: java.time.Duration Default Value: Duration.ofSeconds(10)

Example
pollDelay(Duration.ofSeconds(1))

table

Computes the output table name using the step context and input.
Applicable Step: Save
Optional/Required: Required
Data Type: Lambda that takes step context and input and returns String.
Default Value: N/A

Example
table { stepContext, input -> "batteryState" }

columns

Computes the list of column names for the output table using the step context and input.
Applicable Step: Save
Optional/Required: Required
Data Type: Lambda that takes step context and input and returns List<String>.
Default Value: N/A

Example
columns { stepContext, input -> listOf("company", "deviceid", "timestamp", "batterylevel") }

rows

Computes the list of CassandraSaveRow to save into the output table using the step context and input.
Applicable Step: Save
Optional/Required: Required
Data Type: Lambda that takes step context and input and returns List<CassandraSaveRow>.
Default Value: N/A

Example (Single row table)
CassandraSaveRow (vararg args: Any?)
Example (Multi-row table)
rows {
    stepContext, input -> listOf( CassandraSaveRow( "'ACME Inc.'", "'${input.deviceId}'", "'${input.timestamp}'", "'${input.batteryLevel}'" ) )
}

singletonConfiguration

Configures how polled results are delivered to scenario minions.
Refer to SingletonConfiguration parameters for details on strategies and examples of usage.

monitoring

Configures QALIPSIS monitoring (meters/events) for the step.
Refer to Monitoring parameters for configuration details and examples of usage.

Shared defaults for Cassandra steps

You can define defaults once in the scenario section or just after, and let all following Cassandra steps inherit them.

scenario {
  cassandra().defaults { (1)
    connect {
      servers = listOf("localhost:9042")
      keyspace = "iot"
      datacenterName = "datacenter1"
    }
    monitoring {
      events = true
      meters = true
    }
  }
}
1 Defaults are applied to subsequent Cassandra steps in the same scenario. Individual steps can still override values.