SlideShare a Scribd company logo
©2013 DataStax Confidential. Do not distribute without consent.
@chbatey
Christopher Batey

Technical Evangelist for Apache Cassandra
LA 2015: Testing Cassandra applications
@chbatey
Who am I?
• Based in London
• Technical Evangelist for Apache Cassandra
•Work on Stubbed Cassandra
•Help out Apache Cassandra users
• Previous: Cassandra backed apps at BSkyB
@chbatey
Agenda
• Cassandra failure scenarios
• Developer tools
• Stubbed Cassandra
@chbatey
Production?
Application
@chbatey
Production?
ApplicationApplicationApplicationApplicationApplication
replication factor: 3
consistency: ONE
@chbatey
Production?
ApplicationApplicationApplicationApplicationApplication
ApplicationApplicationApplicationApplicationApplication
DC1
DC2
@chbatey
Read timeout
Application C
R1
R2
R3
C=QUROUM
Replication factor: 3
timeout
timeout
Read timeout
@chbatey
Read timeout
• Received acknowledgements
• Required acknowledgements
• Consistency level
• wasDataReceived
@chbatey
Write timeout
Application C
R1
R2
R3
C=QUROUM
Replication factor: 3
timeout
timeout
Write timeout
@chbatey
Retrying writes
• Cassandra does not roll back!
@chbatey
Write timeout
• Received acknowledgements
• Required acknowledgements
• Consistency level
• CAS and Batches are more complicated:
- WriteType: SIMPLE, BATCH, UNLOGGED_BATCH,
BATCH_LOG, CAS
@chbatey
Batches
• BATCH_LOG
- Timed out waiting for batch log replicas
- Retry if you like
• BATCH
- Written to batch log but timed out waiting for actual replica
- Will eventually be committed (serial read)
• UNLOGGED_BATCH
- Unknown - retry if you like
@chbatey
Idempotent writes
• All writes are idempotent with the following exceptions:
- Counters
- lists
@chbatey
Unavailable
Application C
R1
R2
R3
C=QUROUM
Replication factor: 3
Unavailable
@chbatey
Unavailable
• Alive Replicas
• Required Replicas
• Consistency
@chbatey
Coordinator issue
Application C
R1
R2
R3
C=QUROUM
Replication factor: 3
???
Set a socket read timeout!
@chbatey
Unit & Integration testing
• Requirements: Quick to run, deterministic, not brittle!!
• Integration tests against an embedded Cassandra?
• cassandra-unit
• Integration tests against an external Cassandra running on developer / CI
machines
• CCM
• Regular install
• Docker
• Vagrant
• Mocking the driver
@chbatey
Acceptance testing
Application
Acceptance
test
prepare data
verification
@chbatey
How do this if it was a HTTP service?
• Release it - great book
• Wiremock - mocking HTTP
services
• Saboteur - adding network
latency
If you want to build a fault tolerant application
you better test faults!
@chbatey
Stubbed Cassandra
Application
Acceptance
test
prime on admin port (REST)
verification on admin port
Admin endpoints
Native protocol
@chbatey
Two sides of Scassandra
• Java
-Acts as a unit/integration testing library
-90% of effort on this side
• Standalone
-Runs as a separate process
@chbatey
Java Client
• Embeds Stubbed Cassandra in a Java library
- Start / stop the server
- Prime the server to return rows and/or errors
- Verify exactly the queries your application has executed
@chbatey
Starting / Stopping
@ClassRule

public static final ScassandraServerRule SCASSANDRA = new
ScassandraServerRule();


Scassandra scassandra = ScassandraFactory.createServer();
scassandra.start();
PrimingClient primingClient = scassandra.primingClient();
ActivityClient activityClient = scassandra.activityClient();
@chbatey
Activity Client
• Query
‣ Query text
‣ Consistency
• PrepreparedStatementExecution
‣ Prepared statement text
‣ Bound variables


public List<Query> retrieveQueries();
public List<PreparedStatementExecution> retrievePreparedStatementExecutions()


public List<Connection> retrieveConnections();
public void clearAllRecordedActivity()


public void clearConnections();

public void clearQueries();

public void clearPreparedStatementExecutions();

@chbatey
Priming Client
• PrimingRequest
‣ Either a Query or PreparedStatement
‣ Query text or QueryPattern (regex)
‣ Consistency (default all)
‣ Result (success, read timeout, unavailable etc)
‣ Rows for successful response
‣ Column types for rows
‣ Variable types for prepared statements
public void prime(PrimingRequest prime)


public List<PrimingRequest> retrievePreparedPrimes()

public List<PrimingRequest> retrieveQueryPrimes()

public void clearAllPrimes()

public void clearQueryPrimes()

public void clearPreparedPrimes()





@chbatey
Example time
public interface PersonDao {

void connect();



void disconnect();



List<Person> retrievePeople();



List<Person> retrievePeopleByName(String firstName);



void storePerson(Person person);

}

@chbatey
Testing the connect method
@Test

public void shouldConnectToCassandraWhenConnectCalled() {

//given

activityClient.clearConnections();

//when

underTest.connect();

//then

assertTrue("Expected at least one connection",

activityClient.retrieveConnections().size() > 0);

}
@chbatey
Testing retrieve
public List<Person> retrieveNames() {

ResultSet result;

try {

Statement statement = new SimpleStatement("select * from person");

statement.setConsistencyLevel(ConsistencyLevel.QUORUM);

result = session.execute(statement);

} catch (ReadTimeoutException e) {

throw new UnableToRetrievePeopleException();

}



List<Person> people = new ArrayList<>();

for (Row row : result) {

people.add(new Person(row.getString("first_name"), row.getInt("age")));

}

return people;

}
@chbatey
Test the query + consistency
@Test

public void testQueryIssuedWithCorrectConsistencyUsingMatcher() {

//given

Query expectedQuery = Query.builder()

.withQuery("select * from person")

.withConsistency("QUORUM").build();



//when

underTest.retrievePeople();



//then

assertThat(activityClient.retrieveQueries(), containsQuery(expectedQuery));

}
Hamcrest matcher
@chbatey
Testing behaviour
@Test

public void testRetrievingOfNames() throws Exception {

// given

Map<String, ?> row = ImmutableMap.of(

"first_name", "Chris",

"last_name", "Batey",

"age", 29);

primingClient.prime(PrimingRequest.queryBuilder()

.withQuery("select * from person")

.withColumnTypes(column("age", PrimitiveType.INT))

.withRows(row)

.build());



//when

List<Person> names = underTest.retrievePeople();



//then

assertEquals(1, names.size());

assertEquals(“Chris Batey", names.get(0).getName());

}
Each Cassandra Row == Java map
Tell Scassandra about your schem
@chbatey
Testing errors
@Test(expected = UnableToRetrievePeopleException.class)

public void testHandlingOfReadRequestTimeout() throws Exception {

// given

PrimingRequest primeReadRequestTimeout = PrimingRequest.queryBuilder()

.withQuery("select * from person")

.withResult(Result.read_request_timeout)

.build();

primingClient.prime(primeReadRequestTimeout);



//when

underTest.retrievePeople();



//then

} Expecting custom exception
@chbatey
Testing retries


@Override

public RetryDecision onReadTimeout(Statement statement, ConsistencyLevel cl, int requiredResponses,
int receivedResponses, boolean dataRetrieved, int nbRetry) {

if (nbRetry < configuredRetries) {

return RetryDecision.retry(cl);

} else {

return RetryDecision.rethrow();

}

}



@Override

public RetryDecision onWriteTimeout(Statement s, ConsistencyLevel cl, WriteType wt, int requiredAcks,
int receivedAcks, int nbRetry) {

return DefaultRetryPolicy.INSTANCE.onWriteTimeout(s, cl, wt, receivedAcks, receivedAcks, nbRetry);

}



@Override

public RetryDecision onUnavailable(Statement statement, ConsistencyLevel cl, int requiredReplica,
int aliveReplica, int nbRetry) {

return DefaultRetryPolicy.INSTANCE.onUnavailable(statement, cl, requiredReplica, aliveReplica, nbRetry);

}

@chbatey
Testing retries
@Test

public void testRetriesConfiguredNumberOfTimes() throws Exception {

PrimingRequest readTimeoutPrime = PrimingRequest.queryBuilder()

.withQuery("select * from person")

.withResult(Result.read_request_timeout)

.build();

primingClient.prime(readTimeoutPrime);



try {

underTest.retrievePeople();

} catch (UnableToRetrievePeopleException e) {

}



assertEquals(CONFIGURED_RETRIES + 1, activityClient.retrieveQueries().size());

}
@chbatey
Coordinator issue
Application C
R1
R2
R3
C=QUROUM
Replication factor: 3
???
@chbatey
Testing slow connection
@Test(expected = UnableToSavePersonException.class)

public void testThatSlowQueriesTimeout() throws Exception {

// given

PrimingRequest preparedStatementPrime = PrimingRequest.preparedStatementBuilder()

.withQueryPattern("insert into person.*")

.withVariableTypes(VARCHAR, INT, list(TIMESTAMP))

.withFixedDelay(1000)

.build();

primingClient.prime(preparedStatementPrime);

underTest.connect();



underTest.storePerson(new Person("Christopher", 29, Collections.emptyList()));

}
Delays the response by 1000ms
Expect a custom exception
@chbatey
Testing slow connection
SocketOptions socketOptions = new SocketOptions();

socketOptions.setReadTimeoutMillis(500);

cluster = Cluster.builder()

.addContactPoint("localhost")

.withPort(port)

.withRetryPolicy(new RetryReads())

.withSocketOptions(socketOptions)

.build();
Set a read timeout
@Override

public void storePerson(Person person) {

try {

BoundStatement bind = storeStatement.bind(person.getName(), person.getAge());

session.execute(bind);

} catch (NoHostAvailableException e) {

throw new UnableToSavePersonException();

}

}
@chbatey
Summary of features
• Start as many instances as you like in the same JVM
• Prime all primitive types + collections
• Prime prepared statements
• Verify number of connections your application makes
• Test slow queries
@chbatey
Future features
• Loading of schema for priming prepared statements
• Pretending to be multiple nodes
@chbatey
How do I get it?
•It is on maven central
•Or go to www.scassandra.org
•Executable jar + REST API
<dependency>

<groupId>org.scassandra</groupId>

<artifactId>java-client</artifactId>

<version>0.6.0</version>

<scope>test</scope>

</dependency>
@chbatey
I want to help
• Server: https://github.com/scassandra/scassandra-
server
• Client: https://github.com/scassandra/scassandra-java-
client
• Tests: https://github.com/scassandra/scassandra-it-java-
driver-2
@chbatey
Summary
• Testing is good - I want more tools to help me
• Existing tools for Cassandra are great at happy path
scenarios
• Stubbed Cassandra allows testing of edge cases
@chbatey
The end - Questions?
www.scassandra.org
http://christopher-batey.blogspot.co.uk/
Ping me on twitter @chbatey
@chbatey
How does this work?
• Server implemented in Scala
• Binary port for your Cassandra application to connect to
• Admin port for the REST API
• Thin Java wrapper to make it easy to be used in JUnit
tests

More Related Content

What's hot (20)

PDF
Reactive Fault Tolerant Programming with Hystrix and RxJava
Matt Stine
 
PDF
Reactive Streams: Handling Data-Flow the Reactive Way
Roland Kuhn
 
PPTX
Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemot...
Codemotion
 
PDF
Resilience with Hystrix
Uwe Friedrichsen
 
PPTX
REEF: Towards a Big Data Stdlib
DataWorks Summit
 
ZIP
Barcamp Auckland Rails3 presentation
Sociable
 
PDF
NYC Cassandra Day - Java Intro
Christopher Batey
 
PDF
ScalaSwarm 2017 Keynote: Tough this be madness yet theres method in't
Konrad Malawski
 
PDF
Akka persistence == event sourcing in 30 minutes
Konrad Malawski
 
PDF
Voxxed Vienna 2015 Fault tolerant microservices
Christopher Batey
 
PDF
HBase RowKey design for Akka Persistence
Konrad Malawski
 
PDF
Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams
Konrad Malawski
 
PDF
Reactive Streams / Akka Streams - GeeCON Prague 2014
Konrad Malawski
 
PDF
Need for Async: Hot pursuit for scalable applications
Konrad Malawski
 
PDF
The Need for Async @ ScalaWorld
Konrad Malawski
 
PDF
The things we don't see – stories of Software, Scala and Akka
Konrad Malawski
 
KEY
Curator intro
Jordan Zimmerman
 
PDF
Manchester Hadoop Meetup: Cassandra Spark internals
Christopher Batey
 
PPTX
Lambdas puzzler - Peter Lawrey
JAXLondon_Conference
 
PDF
[Tokyo Scala User Group] Akka Streams & Reactive Streams (0.7)
Konrad Malawski
 
Reactive Fault Tolerant Programming with Hystrix and RxJava
Matt Stine
 
Reactive Streams: Handling Data-Flow the Reactive Way
Roland Kuhn
 
Samuele Resca - REACTIVE PROGRAMMING, DAMN. IT IS NOT ABOUT REACTJS - Codemot...
Codemotion
 
Resilience with Hystrix
Uwe Friedrichsen
 
REEF: Towards a Big Data Stdlib
DataWorks Summit
 
Barcamp Auckland Rails3 presentation
Sociable
 
NYC Cassandra Day - Java Intro
Christopher Batey
 
ScalaSwarm 2017 Keynote: Tough this be madness yet theres method in't
Konrad Malawski
 
Akka persistence == event sourcing in 30 minutes
Konrad Malawski
 
Voxxed Vienna 2015 Fault tolerant microservices
Christopher Batey
 
HBase RowKey design for Akka Persistence
Konrad Malawski
 
Fresh from the Oven (04.2015): Experimental Akka Typed and Akka Streams
Konrad Malawski
 
Reactive Streams / Akka Streams - GeeCON Prague 2014
Konrad Malawski
 
Need for Async: Hot pursuit for scalable applications
Konrad Malawski
 
The Need for Async @ ScalaWorld
Konrad Malawski
 
The things we don't see – stories of Software, Scala and Akka
Konrad Malawski
 
Curator intro
Jordan Zimmerman
 
Manchester Hadoop Meetup: Cassandra Spark internals
Christopher Batey
 
Lambdas puzzler - Peter Lawrey
JAXLondon_Conference
 
[Tokyo Scala User Group] Akka Streams & Reactive Streams (0.7)
Konrad Malawski
 

Similar to LA Cassandra Day 2015 - Testing Cassandra (20)

PDF
Cassandra Summit EU 2014 - Testing Cassandra Applications
Christopher Batey
 
PDF
DataStax: Making Cassandra Fail (for effective testing)
DataStax Academy
 
PDF
Cassandra is great but how do I test my application?
Christopher Batey
 
PDF
Cassandra Community Webinar - August 22 2013 - Cassandra Internals
aaronmorton
 
KEY
Building Distributed Systems in Scala
Alex Payne
 
PPT
Apache cassandra
Muralidharan Deenathayalan
 
PDF
An introduction to_rac_system_test_planning_methods
Ajith Narayanan
 
PPTX
Oracle real application clusters system tests with demo
Ajith Narayanan
 
PDF
Shooting the Rapids
Maurice Naftalin
 
PDF
C* Summit EU 2013: Cassandra Internals
DataStax Academy
 
PDF
Introduction to .Net Driver
DataStax Academy
 
PDF
Enhanced Web Service Testing: A Better Mock Structure
Salesforce Developers
 
PDF
3 Dundee-Spark Overview for C* developers
Christopher Batey
 
PDF
Performance Test Driven Development with Oracle Coherence
aragozin
 
PDF
Building Scalable Stateless Applications with RxJava
Rick Warren
 
PPTX
Serverless archtiectures
Iegor Fadieiev
 
PPTX
Developing a Real-time Engine with Akka, Cassandra, and Spray
Jacob Park
 
PPTX
Using the Tooling API to Generate Apex SOAP Web Service Clients
Daniel Ballinger
 
PDF
Quarkus - a shrink ray to your Java Application
CodeOps Technologies LLP
 
PPTX
Testing basics for developers
Anton Udovychenko
 
Cassandra Summit EU 2014 - Testing Cassandra Applications
Christopher Batey
 
DataStax: Making Cassandra Fail (for effective testing)
DataStax Academy
 
Cassandra is great but how do I test my application?
Christopher Batey
 
Cassandra Community Webinar - August 22 2013 - Cassandra Internals
aaronmorton
 
Building Distributed Systems in Scala
Alex Payne
 
Apache cassandra
Muralidharan Deenathayalan
 
An introduction to_rac_system_test_planning_methods
Ajith Narayanan
 
Oracle real application clusters system tests with demo
Ajith Narayanan
 
Shooting the Rapids
Maurice Naftalin
 
C* Summit EU 2013: Cassandra Internals
DataStax Academy
 
Introduction to .Net Driver
DataStax Academy
 
Enhanced Web Service Testing: A Better Mock Structure
Salesforce Developers
 
3 Dundee-Spark Overview for C* developers
Christopher Batey
 
Performance Test Driven Development with Oracle Coherence
aragozin
 
Building Scalable Stateless Applications with RxJava
Rick Warren
 
Serverless archtiectures
Iegor Fadieiev
 
Developing a Real-time Engine with Akka, Cassandra, and Spray
Jacob Park
 
Using the Tooling API to Generate Apex SOAP Web Service Clients
Daniel Ballinger
 
Quarkus - a shrink ray to your Java Application
CodeOps Technologies LLP
 
Testing basics for developers
Anton Udovychenko
 
Ad

More from Christopher Batey (20)

PDF
Cassandra summit LWTs
Christopher Batey
 
PDF
Docker and jvm. A good idea?
Christopher Batey
 
PDF
LJC: Microservices in the real world
Christopher Batey
 
PDF
Cassandra Day NYC - Cassandra anti patterns
Christopher Batey
 
PDF
Think your software is fault-tolerant? Prove it!
Christopher Batey
 
PDF
Cassandra London - 2.2 and 3.0
Christopher Batey
 
PDF
Cassandra London - C* Spark Connector
Christopher Batey
 
PDF
IoT London July 2015
Christopher Batey
 
PDF
1 Dundee - Cassandra 101
Christopher Batey
 
PDF
2 Dundee - Cassandra-3
Christopher Batey
 
PDF
Paris Day Cassandra: Use case
Christopher Batey
 
PDF
Dublin Meetup: Cassandra anti patterns
Christopher Batey
 
PDF
Cassandra Day London: Building Java Applications
Christopher Batey
 
PDF
Data Science Lab Meetup: Cassandra and Spark
Christopher Batey
 
PDF
Manchester Hadoop Meetup: Spark Cassandra Integration
Christopher Batey
 
PDF
Manchester Hadoop User Group: Cassandra Intro
Christopher Batey
 
PDF
Webinar Cassandra Anti-Patterns
Christopher Batey
 
PDF
Munich March 2015 - Cassandra + Spark Overview
Christopher Batey
 
PDF
Reading Cassandra Meetup Feb 2015: Apache Spark
Christopher Batey
 
PDF
LA Cassandra Day 2015 - Cassandra for developers
Christopher Batey
 
Cassandra summit LWTs
Christopher Batey
 
Docker and jvm. A good idea?
Christopher Batey
 
LJC: Microservices in the real world
Christopher Batey
 
Cassandra Day NYC - Cassandra anti patterns
Christopher Batey
 
Think your software is fault-tolerant? Prove it!
Christopher Batey
 
Cassandra London - 2.2 and 3.0
Christopher Batey
 
Cassandra London - C* Spark Connector
Christopher Batey
 
IoT London July 2015
Christopher Batey
 
1 Dundee - Cassandra 101
Christopher Batey
 
2 Dundee - Cassandra-3
Christopher Batey
 
Paris Day Cassandra: Use case
Christopher Batey
 
Dublin Meetup: Cassandra anti patterns
Christopher Batey
 
Cassandra Day London: Building Java Applications
Christopher Batey
 
Data Science Lab Meetup: Cassandra and Spark
Christopher Batey
 
Manchester Hadoop Meetup: Spark Cassandra Integration
Christopher Batey
 
Manchester Hadoop User Group: Cassandra Intro
Christopher Batey
 
Webinar Cassandra Anti-Patterns
Christopher Batey
 
Munich March 2015 - Cassandra + Spark Overview
Christopher Batey
 
Reading Cassandra Meetup Feb 2015: Apache Spark
Christopher Batey
 
LA Cassandra Day 2015 - Cassandra for developers
Christopher Batey
 
Ad

Recently uploaded (20)

PDF
Salesforce Implementation Services Provider.pdf
VALiNTRY360
 
PPTX
Contractor Management Platform and Software Solution for Compliance
SHEQ Network Limited
 
PDF
Adobe Illustrator Crack Full Download (Latest Version 2025) Pre-Activated
imang66g
 
PDF
SAP GUI Installation Guide for macOS (iOS) | Connect to SAP Systems on Mac
SAP Vista, an A L T Z E N Company
 
PDF
New Download MiniTool Partition Wizard Crack Latest Version 2025
imang66g
 
PPTX
slidesgo-unlocking-the-code-the-dynamic-dance-of-variables-and-constants-2024...
kr2589474
 
PDF
Applitools Platform Pulse: What's New and What's Coming - July 2025
Applitools
 
PDF
Salesforce Pricing Update 2025: Impact, Strategy & Smart Cost Optimization wi...
GetOnCRM Solutions
 
PDF
Summary Of Odoo 18.1 to 18.4 : The Way For Odoo 19
CandidRoot Solutions Private Limited
 
PPT
Brief History of Python by Learning Python in three hours
adanechb21
 
PDF
advancepresentationskillshdhdhhdhdhdhhfhf
jasmenrojas249
 
PPTX
classification of computer and basic part of digital computer
ravisinghrajpurohit3
 
PPTX
TRAVEL APIs | WHITE LABEL TRAVEL API | TOP TRAVEL APIs
philipnathen82
 
PDF
Using licensed Data Loss Prevention (DLP) as a strategic proactive data secur...
Q-Advise
 
PDF
New Download FL Studio Crack Full Version [Latest 2025]
imang66g
 
PDF
SAP GUI Installation Guide for Windows | Step-by-Step Setup for SAP Access
SAP Vista, an A L T Z E N Company
 
PDF
Supabase Meetup: Build in a weekend, scale to millions
Carlo Gilmar Padilla Santana
 
PDF
AI Image Enhancer: Revolutionizing Visual Quality”
docmasoom
 
PDF
Virtual Threads in Java: A New Dimension of Scalability and Performance
Tier1 app
 
PDF
Infrastructure planning and resilience - Keith Hastings.pptx.pdf
Safe Software
 
Salesforce Implementation Services Provider.pdf
VALiNTRY360
 
Contractor Management Platform and Software Solution for Compliance
SHEQ Network Limited
 
Adobe Illustrator Crack Full Download (Latest Version 2025) Pre-Activated
imang66g
 
SAP GUI Installation Guide for macOS (iOS) | Connect to SAP Systems on Mac
SAP Vista, an A L T Z E N Company
 
New Download MiniTool Partition Wizard Crack Latest Version 2025
imang66g
 
slidesgo-unlocking-the-code-the-dynamic-dance-of-variables-and-constants-2024...
kr2589474
 
Applitools Platform Pulse: What's New and What's Coming - July 2025
Applitools
 
Salesforce Pricing Update 2025: Impact, Strategy & Smart Cost Optimization wi...
GetOnCRM Solutions
 
Summary Of Odoo 18.1 to 18.4 : The Way For Odoo 19
CandidRoot Solutions Private Limited
 
Brief History of Python by Learning Python in three hours
adanechb21
 
advancepresentationskillshdhdhhdhdhdhhfhf
jasmenrojas249
 
classification of computer and basic part of digital computer
ravisinghrajpurohit3
 
TRAVEL APIs | WHITE LABEL TRAVEL API | TOP TRAVEL APIs
philipnathen82
 
Using licensed Data Loss Prevention (DLP) as a strategic proactive data secur...
Q-Advise
 
New Download FL Studio Crack Full Version [Latest 2025]
imang66g
 
SAP GUI Installation Guide for Windows | Step-by-Step Setup for SAP Access
SAP Vista, an A L T Z E N Company
 
Supabase Meetup: Build in a weekend, scale to millions
Carlo Gilmar Padilla Santana
 
AI Image Enhancer: Revolutionizing Visual Quality”
docmasoom
 
Virtual Threads in Java: A New Dimension of Scalability and Performance
Tier1 app
 
Infrastructure planning and resilience - Keith Hastings.pptx.pdf
Safe Software
 

LA Cassandra Day 2015 - Testing Cassandra

  • 1. ©2013 DataStax Confidential. Do not distribute without consent. @chbatey Christopher Batey
 Technical Evangelist for Apache Cassandra LA 2015: Testing Cassandra applications
  • 2. @chbatey Who am I? • Based in London • Technical Evangelist for Apache Cassandra •Work on Stubbed Cassandra •Help out Apache Cassandra users • Previous: Cassandra backed apps at BSkyB
  • 3. @chbatey Agenda • Cassandra failure scenarios • Developer tools • Stubbed Cassandra
  • 8. @chbatey Read timeout • Received acknowledgements • Required acknowledgements • Consistency level • wasDataReceived
  • 11. @chbatey Write timeout • Received acknowledgements • Required acknowledgements • Consistency level • CAS and Batches are more complicated: - WriteType: SIMPLE, BATCH, UNLOGGED_BATCH, BATCH_LOG, CAS
  • 12. @chbatey Batches • BATCH_LOG - Timed out waiting for batch log replicas - Retry if you like • BATCH - Written to batch log but timed out waiting for actual replica - Will eventually be committed (serial read) • UNLOGGED_BATCH - Unknown - retry if you like
  • 13. @chbatey Idempotent writes • All writes are idempotent with the following exceptions: - Counters - lists
  • 15. @chbatey Unavailable • Alive Replicas • Required Replicas • Consistency
  • 17. @chbatey Unit & Integration testing • Requirements: Quick to run, deterministic, not brittle!! • Integration tests against an embedded Cassandra? • cassandra-unit • Integration tests against an external Cassandra running on developer / CI machines • CCM • Regular install • Docker • Vagrant • Mocking the driver
  • 19. @chbatey How do this if it was a HTTP service? • Release it - great book • Wiremock - mocking HTTP services • Saboteur - adding network latency If you want to build a fault tolerant application you better test faults!
  • 20. @chbatey Stubbed Cassandra Application Acceptance test prime on admin port (REST) verification on admin port Admin endpoints Native protocol
  • 21. @chbatey Two sides of Scassandra • Java -Acts as a unit/integration testing library -90% of effort on this side • Standalone -Runs as a separate process
  • 22. @chbatey Java Client • Embeds Stubbed Cassandra in a Java library - Start / stop the server - Prime the server to return rows and/or errors - Verify exactly the queries your application has executed
  • 23. @chbatey Starting / Stopping @ClassRule
 public static final ScassandraServerRule SCASSANDRA = new ScassandraServerRule(); 
 Scassandra scassandra = ScassandraFactory.createServer(); scassandra.start(); PrimingClient primingClient = scassandra.primingClient(); ActivityClient activityClient = scassandra.activityClient();
  • 24. @chbatey Activity Client • Query ‣ Query text ‣ Consistency • PrepreparedStatementExecution ‣ Prepared statement text ‣ Bound variables 
 public List<Query> retrieveQueries(); public List<PreparedStatementExecution> retrievePreparedStatementExecutions() 
 public List<Connection> retrieveConnections(); public void clearAllRecordedActivity() 
 public void clearConnections();
 public void clearQueries();
 public void clearPreparedStatementExecutions();

  • 25. @chbatey Priming Client • PrimingRequest ‣ Either a Query or PreparedStatement ‣ Query text or QueryPattern (regex) ‣ Consistency (default all) ‣ Result (success, read timeout, unavailable etc) ‣ Rows for successful response ‣ Column types for rows ‣ Variable types for prepared statements public void prime(PrimingRequest prime) 
 public List<PrimingRequest> retrievePreparedPrimes()
 public List<PrimingRequest> retrieveQueryPrimes()
 public void clearAllPrimes()
 public void clearQueryPrimes()
 public void clearPreparedPrimes()
 
 

  • 26. @chbatey Example time public interface PersonDao {
 void connect();
 
 void disconnect();
 
 List<Person> retrievePeople();
 
 List<Person> retrievePeopleByName(String firstName);
 
 void storePerson(Person person);
 }

  • 27. @chbatey Testing the connect method @Test
 public void shouldConnectToCassandraWhenConnectCalled() {
 //given
 activityClient.clearConnections();
 //when
 underTest.connect();
 //then
 assertTrue("Expected at least one connection",
 activityClient.retrieveConnections().size() > 0);
 }
  • 28. @chbatey Testing retrieve public List<Person> retrieveNames() {
 ResultSet result;
 try {
 Statement statement = new SimpleStatement("select * from person");
 statement.setConsistencyLevel(ConsistencyLevel.QUORUM);
 result = session.execute(statement);
 } catch (ReadTimeoutException e) {
 throw new UnableToRetrievePeopleException();
 }
 
 List<Person> people = new ArrayList<>();
 for (Row row : result) {
 people.add(new Person(row.getString("first_name"), row.getInt("age")));
 }
 return people;
 }
  • 29. @chbatey Test the query + consistency @Test
 public void testQueryIssuedWithCorrectConsistencyUsingMatcher() {
 //given
 Query expectedQuery = Query.builder()
 .withQuery("select * from person")
 .withConsistency("QUORUM").build();
 
 //when
 underTest.retrievePeople();
 
 //then
 assertThat(activityClient.retrieveQueries(), containsQuery(expectedQuery));
 } Hamcrest matcher
  • 30. @chbatey Testing behaviour @Test
 public void testRetrievingOfNames() throws Exception {
 // given
 Map<String, ?> row = ImmutableMap.of(
 "first_name", "Chris",
 "last_name", "Batey",
 "age", 29);
 primingClient.prime(PrimingRequest.queryBuilder()
 .withQuery("select * from person")
 .withColumnTypes(column("age", PrimitiveType.INT))
 .withRows(row)
 .build());
 
 //when
 List<Person> names = underTest.retrievePeople();
 
 //then
 assertEquals(1, names.size());
 assertEquals(“Chris Batey", names.get(0).getName());
 } Each Cassandra Row == Java map Tell Scassandra about your schem
  • 31. @chbatey Testing errors @Test(expected = UnableToRetrievePeopleException.class)
 public void testHandlingOfReadRequestTimeout() throws Exception {
 // given
 PrimingRequest primeReadRequestTimeout = PrimingRequest.queryBuilder()
 .withQuery("select * from person")
 .withResult(Result.read_request_timeout)
 .build();
 primingClient.prime(primeReadRequestTimeout);
 
 //when
 underTest.retrievePeople();
 
 //then
 } Expecting custom exception
  • 32. @chbatey Testing retries 
 @Override
 public RetryDecision onReadTimeout(Statement statement, ConsistencyLevel cl, int requiredResponses, int receivedResponses, boolean dataRetrieved, int nbRetry) {
 if (nbRetry < configuredRetries) {
 return RetryDecision.retry(cl);
 } else {
 return RetryDecision.rethrow();
 }
 }
 
 @Override
 public RetryDecision onWriteTimeout(Statement s, ConsistencyLevel cl, WriteType wt, int requiredAcks, int receivedAcks, int nbRetry) {
 return DefaultRetryPolicy.INSTANCE.onWriteTimeout(s, cl, wt, receivedAcks, receivedAcks, nbRetry);
 }
 
 @Override
 public RetryDecision onUnavailable(Statement statement, ConsistencyLevel cl, int requiredReplica, int aliveReplica, int nbRetry) {
 return DefaultRetryPolicy.INSTANCE.onUnavailable(statement, cl, requiredReplica, aliveReplica, nbRetry);
 }

  • 33. @chbatey Testing retries @Test
 public void testRetriesConfiguredNumberOfTimes() throws Exception {
 PrimingRequest readTimeoutPrime = PrimingRequest.queryBuilder()
 .withQuery("select * from person")
 .withResult(Result.read_request_timeout)
 .build();
 primingClient.prime(readTimeoutPrime);
 
 try {
 underTest.retrievePeople();
 } catch (UnableToRetrievePeopleException e) {
 }
 
 assertEquals(CONFIGURED_RETRIES + 1, activityClient.retrieveQueries().size());
 }
  • 35. @chbatey Testing slow connection @Test(expected = UnableToSavePersonException.class)
 public void testThatSlowQueriesTimeout() throws Exception {
 // given
 PrimingRequest preparedStatementPrime = PrimingRequest.preparedStatementBuilder()
 .withQueryPattern("insert into person.*")
 .withVariableTypes(VARCHAR, INT, list(TIMESTAMP))
 .withFixedDelay(1000)
 .build();
 primingClient.prime(preparedStatementPrime);
 underTest.connect();
 
 underTest.storePerson(new Person("Christopher", 29, Collections.emptyList()));
 } Delays the response by 1000ms Expect a custom exception
  • 36. @chbatey Testing slow connection SocketOptions socketOptions = new SocketOptions();
 socketOptions.setReadTimeoutMillis(500);
 cluster = Cluster.builder()
 .addContactPoint("localhost")
 .withPort(port)
 .withRetryPolicy(new RetryReads())
 .withSocketOptions(socketOptions)
 .build(); Set a read timeout @Override
 public void storePerson(Person person) {
 try {
 BoundStatement bind = storeStatement.bind(person.getName(), person.getAge());
 session.execute(bind);
 } catch (NoHostAvailableException e) {
 throw new UnableToSavePersonException();
 }
 }
  • 37. @chbatey Summary of features • Start as many instances as you like in the same JVM • Prime all primitive types + collections • Prime prepared statements • Verify number of connections your application makes • Test slow queries
  • 38. @chbatey Future features • Loading of schema for priming prepared statements • Pretending to be multiple nodes
  • 39. @chbatey How do I get it? •It is on maven central •Or go to www.scassandra.org •Executable jar + REST API <dependency>
 <groupId>org.scassandra</groupId>
 <artifactId>java-client</artifactId>
 <version>0.6.0</version>
 <scope>test</scope>
 </dependency>
  • 40. @chbatey I want to help • Server: https://github.com/scassandra/scassandra- server • Client: https://github.com/scassandra/scassandra-java- client • Tests: https://github.com/scassandra/scassandra-it-java- driver-2
  • 41. @chbatey Summary • Testing is good - I want more tools to help me • Existing tools for Cassandra are great at happy path scenarios • Stubbed Cassandra allows testing of edge cases
  • 42. @chbatey The end - Questions? www.scassandra.org http://christopher-batey.blogspot.co.uk/ Ping me on twitter @chbatey
  • 43. @chbatey How does this work? • Server implemented in Scala • Binary port for your Cassandra application to connect to • Admin port for the REST API • Thin Java wrapper to make it easy to be used in JUnit tests