Skip to content

Commit 744310e

Browse files
author
Michael Fero
committed
CPP-813 - Detect CaaS and change consistency defaults
1 parent 951a3b2 commit 744310e

23 files changed

Lines changed: 448 additions & 73 deletions

cpp-driver/gtests/src/integration/integration.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ void Integration::connect(Cluster cluster) {
325325
std::stringstream use_keyspace_query;
326326
use_keyspace_query << "USE " << keyspace_name_;
327327
session_.execute(use_keyspace_query.str());
328+
CHECK_FAILURE;
328329
}
329330

330331
void Integration::connect() {

cpp-driver/gtests/src/integration/integration.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@
107107

108108
#define CHECK_CONTINUE(flag, message) ASSERT_TRUE(flag) << message;
109109

110-
#define CASSANDRA_KEY_VALUE_TABLE_FORMAT "CREATE TABLE %s (key %s PRIMARY KEY, value %s)"
110+
#define CASSANDRA_KEY_VALUE_TABLE_FORMAT \
111+
"CREATE TABLE IF NOT EXISTS %s (key %s PRIMARY KEY, value %s)"
111112
#define CASSANDRA_KEY_VALUE_INSERT_FORMAT "INSERT INTO %s (key, value) VALUES(%s, %s)"
112113
#define CASSANDRA_SELECT_VALUE_FORMAT "SELECT value FROM %s WHERE key=%s"
113114
#define CASSANDRA_DELETE_ROW_FORMAT "DELETE FROM %s WHERE key=%s"

cpp-driver/gtests/src/integration/tests/test_dbaas.cpp

Lines changed: 94 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class DbaasTests : public Integration {
8787
// Ensure CCM and session are not created for these tests
8888
is_ccm_requested_ = false;
8989
is_session_requested_ = false;
90+
is_schema_metadata_ = true; // Needed for prepared statements
9091
Integration::SetUp();
9192
}
9293

@@ -150,6 +151,7 @@ class DbaasTests : public Integration {
150151
args.push_back("start");
151152
args.push_back("--root");
152153
args.push_back("--wait-for-binary-proto");
154+
args.push_back("--jvm_arg=-Ddse.product_type=DATASTAX_APOLLO");
153155
return ccm_execute(args);
154156
}
155157

@@ -165,6 +167,7 @@ class DbaasTests : public Integration {
165167
args.push_back("start");
166168
args.push_back("--root");
167169
args.push_back("--wait-for-binary-proto");
170+
args.push_back("--jvm_arg=-Ddse.product_type=DATASTAX_APOLLO");
168171
return ccm_execute(args);
169172
}
170173

@@ -259,16 +262,15 @@ CASSANDRA_INTEGRATION_TEST_F(DbaasTests, ResolveAndConnect) {
259262
Cluster cluster = default_cluster(false);
260263
cass_cluster_set_cloud_secure_connection_bundle_no_ssl_lib_init(cluster.get(),
261264
creds_v1().c_str());
262-
cluster.connect();
265+
connect(cluster);
263266
}
264267

265268
/**
266269
* Perform query using a simple statement against the DBaaS SNI single endpoint docker image.
267270
*
268271
* This test will perform a connection and execute a simple statement query against the
269272
* system.local table to ensure query execution to a DBaaS SNI single endpoint while validating the
270-
* results. This test will also ensure that the configured keyspace is assigned as the DBaaS
271-
* configuration assigns `system` as the default keyspace.
273+
* results.
272274
*
273275
* @jira_ticket CPP-787
274276
* @test_category dbaas
@@ -282,11 +284,11 @@ CASSANDRA_INTEGRATION_TEST_F(DbaasTests, QueryEachNode) {
282284
Cluster cluster = default_cluster(false).with_load_balance_round_robin();
283285
cass_cluster_set_cloud_secure_connection_bundle_no_ssl_lib_init(cluster.get(),
284286
creds_v1().c_str());
285-
Session session = cluster.connect();
287+
connect(cluster);
286288

287289
ServerNames server_names;
288290
for (int i = 0; i < 3; ++i) {
289-
Result result = session.execute(SELECT_ALL_SYSTEM_LOCAL_CQL);
291+
Result result = session_.execute(SELECT_ALL_SYSTEM_LOCAL_CQL);
290292
Uuid expected_host_id = Uuid(result.server_name());
291293
Row row = result.first_row();
292294

@@ -300,6 +302,78 @@ CASSANDRA_INTEGRATION_TEST_F(DbaasTests, QueryEachNode) {
300302
EXPECT_EQ(3u, server_names.size()); // Ensure all three nodes were queried
301303
}
302304

305+
/**
306+
* Ensure guardrails are enabled when performing a query against the DBaaS SNI single endpoint
307+
* docker image.
308+
*
309+
* This test will perform a connection and execute a simple insert statement query against the
310+
* server using a valid consistency level.DBaaS SNI single endpoint while validating the
311+
* insert occured.
312+
*
313+
* @jira_ticket CPP-813
314+
* @test_category dbaas
315+
* @test_category queries:guard_rails
316+
* @since 2.14.0
317+
* @expected_result Simple statement is executed and is validated.
318+
*/
319+
CASSANDRA_INTEGRATION_TEST_F(DbaasTests, ConsistencyGuardrails) {
320+
CHECK_FAILURE;
321+
322+
Cluster cluster = default_cluster(false);
323+
cass_cluster_set_cloud_secure_connection_bundle_no_ssl_lib_init(cluster.get(),
324+
creds_v1().c_str());
325+
connect(cluster);
326+
327+
session_.execute(
328+
format_string(CASSANDRA_KEY_VALUE_TABLE_FORMAT, default_table().c_str(), "int", "int"));
329+
CHECK_FAILURE;
330+
331+
session_.execute(Statement(
332+
format_string(CASSANDRA_KEY_VALUE_INSERT_FORMAT, default_table().c_str(), "0", "1")));
333+
Result result = session_.execute(
334+
Statement(format_string(CASSANDRA_SELECT_VALUE_FORMAT, default_table().c_str(), "0")));
335+
EXPECT_EQ(1u, result.row_count());
336+
ASSERT_EQ(1u, result.column_count());
337+
ASSERT_EQ(Integer(1), result.first_row().next().as<Integer>());
338+
}
339+
340+
/**
341+
* Ensure guardrails are enabled when performing a query against the DBaaS SNI single endpoint
342+
* docker image.
343+
*
344+
* This test will perform a connection and execute a simple statement query against the
345+
* server using an invalid consistency level.DBaaS SNI single endpoint while validating the
346+
* error.
347+
*
348+
* @jira_ticket CPP-813
349+
* @test_category dbaas
350+
* @test_category queries:guard_rails
351+
* @since 2.14.0
352+
* @expected_result Simple statement is executed and guard rail error is validated.
353+
*/
354+
CASSANDRA_INTEGRATION_TEST_F(DbaasTests, ConsistencyGuardrailsInvalid) {
355+
CHECK_FAILURE;
356+
357+
Cluster cluster = default_cluster(false);
358+
cass_cluster_set_cloud_secure_connection_bundle_no_ssl_lib_init(cluster.get(),
359+
creds_v1().c_str());
360+
connect(cluster);
361+
362+
session_.execute(
363+
format_string(CASSANDRA_KEY_VALUE_TABLE_FORMAT, default_table().c_str(), "int", "int"));
364+
CHECK_FAILURE
365+
366+
Statement statement(
367+
format_string(CASSANDRA_KEY_VALUE_INSERT_FORMAT, default_table().c_str(), "0", "1"));
368+
statement.set_consistency(
369+
CASS_CONSISTENCY_LOCAL_ONE); // Override default DBaaS configured consistency
370+
Result result = session_.execute(statement, false);
371+
EXPECT_TRUE(result.error_code() != CASS_OK)
372+
<< "Statement execution succeeded; guardrails may not be enabled";
373+
EXPECT_TRUE(contains(result.error_message(),
374+
"Provided value LOCAL_ONE is not allowed for Write Consistency Level"));
375+
}
376+
303377
/**
304378
* Perform query ensuring token aware is enabled by default.
305379
*
@@ -329,7 +403,8 @@ CASSANDRA_INTEGRATION_TEST_F(DbaasTests, DcAwareTokenAwareRoutingDefault) {
329403
Cluster cluster = default_cluster(false);
330404
cass_cluster_set_cloud_secure_connection_bundle_no_ssl_lib_init(cluster.get(),
331405
creds_v1().c_str());
332-
Session session = cluster.connect();
406+
connect(cluster);
407+
333408
for (std::vector<std::pair<int, int> >::iterator it = replicas.begin(), end = replicas.end();
334409
it != end; ++it) {
335410
Statement statement(SELECT_ALL_SYSTEM_LOCAL_CQL, 1);
@@ -338,8 +413,8 @@ CASSANDRA_INTEGRATION_TEST_F(DbaasTests, DcAwareTokenAwareRoutingDefault) {
338413
statement.set_keyspace("system");
339414
statement.bind<Integer>(0, Integer(it->first));
340415

341-
Result result =
342-
session.execute(statement, false); // No bind variables exist so statement will return error
416+
Result result = session_.execute(
417+
statement, false); // No bind variables exist so statement will return error
343418
EXPECT_EQ(server_names[it->second], result.server_name());
344419
}
345420
}
@@ -362,7 +437,7 @@ CASSANDRA_INTEGRATION_TEST_F(DbaasTests, ResolveAndConnectWithoutCredsInBundle)
362437
cass_cluster_set_cloud_secure_connection_bundle_no_ssl_lib_init(cluster.get(),
363438
creds_v1_no_creds().c_str());
364439
cluster.with_credentials("cassandra", "cassandra");
365-
cluster.connect();
440+
connect(cluster);
366441
}
367442

368443
/**
@@ -383,7 +458,7 @@ CASSANDRA_INTEGRATION_TEST_F(DbaasTests, InvalidWithoutCreds) {
383458
cass_cluster_set_cloud_secure_connection_bundle_no_ssl_lib_init(cluster.get(),
384459
creds_v1_no_creds().c_str());
385460
try {
386-
cluster.connect();
461+
connect(cluster);
387462
EXPECT_TRUE(false) << "Connection established";
388463
} catch (Session::Exception& se) {
389464
EXPECT_EQ(CASS_ERROR_SERVER_BAD_CREDENTIALS, se.error_code());
@@ -408,7 +483,7 @@ CASSANDRA_INTEGRATION_TEST_F(DbaasTests, InvalidMetadataServer) {
408483
cass_cluster_set_cloud_secure_connection_bundle_no_ssl_lib_init(cluster.get(),
409484
creds_v1_unreachable().c_str());
410485
try {
411-
cluster.connect();
486+
connect(cluster);
412487
EXPECT_TRUE(false) << "Connection established";
413488
} catch (Session::Exception& se) {
414489
EXPECT_EQ(CASS_ERROR_LIB_NO_HOSTS_AVAILABLE, se.error_code());
@@ -433,7 +508,7 @@ CASSANDRA_INTEGRATION_TEST_F(DbaasTests, InvalidCertificate) {
433508
cass_cluster_set_cloud_secure_connection_bundle_no_ssl_lib_init(cluster.get(),
434509
creds_v1_no_cert().c_str());
435510
try {
436-
cluster.connect();
511+
connect(cluster);
437512
EXPECT_TRUE(false) << "Connection established";
438513
} catch (Session::Exception& se) {
439514
EXPECT_EQ(CASS_ERROR_LIB_NO_HOSTS_AVAILABLE, se.error_code());
@@ -458,7 +533,7 @@ CASSANDRA_INTEGRATION_TEST_F(DbaasTests, InvalidCertificateAuthority) {
458533
cass_cluster_set_cloud_secure_connection_bundle_no_ssl_lib_init(cluster.get(),
459534
creds_v1_invalid_ca().c_str());
460535
try {
461-
cluster.connect();
536+
connect(cluster);
462537
EXPECT_TRUE(false) << "Connection established";
463538
} catch (Session::Exception& se) {
464539
EXPECT_EQ(CASS_ERROR_LIB_NO_HOSTS_AVAILABLE, se.error_code());
@@ -486,16 +561,16 @@ CASSANDRA_INTEGRATION_TEST_F(DbaasTests, QueryWithNodesDown) {
486561
Cluster cluster = default_cluster(false);
487562
cass_cluster_set_cloud_secure_connection_bundle_no_ssl_lib_init(cluster.get(),
488563
creds_v1().c_str());
489-
Session session = cluster.connect();
564+
connect(cluster);
490565

491566
EXPECT_TRUE(stop_node(1));
492567
for (int i = 0; i < 8; ++i) {
493-
EXPECT_NE(server_names[1], session.execute(SELECT_ALL_SYSTEM_LOCAL_CQL).server_name());
568+
EXPECT_NE(server_names[1], session_.execute(SELECT_ALL_SYSTEM_LOCAL_CQL).server_name());
494569
}
495570

496571
EXPECT_TRUE(stop_node(3));
497572
for (int i = 0; i < 8; ++i) {
498-
EXPECT_EQ(server_names[2], session.execute(SELECT_ALL_SYSTEM_LOCAL_CQL).server_name());
573+
EXPECT_EQ(server_names[2], session_.execute(SELECT_ALL_SYSTEM_LOCAL_CQL).server_name());
499574
}
500575

501576
EXPECT_TRUE(start_cluster());
@@ -522,13 +597,13 @@ CASSANDRA_INTEGRATION_TEST_F(DbaasTests, FullOutage) {
522597
Cluster cluster = default_cluster(false).with_constant_reconnect(10); // Quick reconnect
523598
cass_cluster_set_cloud_secure_connection_bundle_no_ssl_lib_init(cluster.get(),
524599
creds_v1().c_str());
525-
Session session = cluster.connect();
600+
connect(cluster);
526601

527602
EXPECT_TRUE(stop_cluster());
528603

529604
Statement statement(SELECT_ALL_SYSTEM_LOCAL_CQL);
530-
EXPECT_EQ(CASS_ERROR_LIB_NO_HOSTS_AVAILABLE, session.execute(statement, false).error_code());
605+
EXPECT_EQ(CASS_ERROR_LIB_NO_HOSTS_AVAILABLE, session_.execute(statement, false).error_code());
531606

532607
EXPECT_TRUE(start_cluster());
533-
EXPECT_EQ(CASS_OK, session.execute(statement).error_code());
608+
EXPECT_EQ(CASS_OK, session_.execute(statement).error_code());
534609
}

cpp-driver/gtests/src/unit/mockssandra.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#endif
3434

3535
using datastax::internal::bind_callback;
36+
using datastax::internal::Map;
3637
using datastax::internal::Memory;
3738
using datastax::internal::OStringStream;
3839
using datastax::internal::ScopedMutex;
@@ -1088,6 +1089,15 @@ inline int32_t encode_uuid(CassUuid uuid, String* output) {
10881089
return 16;
10891090
}
10901091

1092+
int32_t encode_string_map(const Map<String, Vector<String> >& value, String* output) {
1093+
int32_t size = encode_uint16(value.size(), output);
1094+
for (Map<String, Vector<String> >::const_iterator it = value.begin(); it != value.end(); ++it) {
1095+
size += encode_string(it->first, output);
1096+
size += encode_string_list(it->second, output);
1097+
}
1098+
return size;
1099+
}
1100+
10911101
static String encode_header(int8_t version, int8_t flags, int16_t stream, int8_t opcode,
10921102
int32_t len) {
10931103
String header;
@@ -1993,7 +2003,17 @@ int32_t ProtocolHandler::decode_frame(ClientConnection* client, const char* fram
19932003
} else {
19942004
return len - remaining;
19952005
}
1996-
state_ = BODY;
2006+
2007+
if (length_ == 0) {
2008+
decode_body(client, pos, 0);
2009+
version_ = 0;
2010+
flags_ = 0;
2011+
opcode_ = 0;
2012+
length_ = 0;
2013+
state_ = PROTOCOL_VERSION;
2014+
} else {
2015+
state_ = BODY;
2016+
}
19972017
break;
19982018
case BODY:
19992019
if (remaining >= length_) {

cpp-driver/gtests/src/unit/mockssandra.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "address.hpp"
2929
#include "event_loop.hpp"
3030
#include "list.hpp"
31+
#include "map.hpp"
3132
#include "ref_counted.hpp"
3233
#include "scoped_ptr.hpp"
3334
#include "string.hpp"
@@ -46,6 +47,7 @@
4647
using datastax::String;
4748
using datastax::internal::Atomic;
4849
using datastax::internal::List;
50+
using datastax::internal::Map;
4951
using datastax::internal::RefCounted;
5052
using datastax::internal::ScopedPtr;
5153
using datastax::internal::SharedRefPtr;
@@ -360,6 +362,8 @@ struct QueryParameters {
360362
String keyspace;
361363
};
362364

365+
int32_t encode_string_map(const Map<String, Vector<String> >& value, String* output);
366+
363367
class Type {
364368
public:
365369
static Type text();

cpp-driver/gtests/src/unit/tests/test_connection.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ TEST_F(ConnectionUnitTest, SslCancel) {
303303
}
304304

305305
TEST_F(ConnectionUnitTest, Timeout) {
306-
mockssandra::RequestHandler::Builder builder;
306+
mockssandra::SimpleRequestHandlerBuilder builder;
307307
builder.on(mockssandra::OPCODE_STARTUP).no_result(); // Don't return a response
308308
mockssandra::SimpleCluster cluster(builder.build());
309309
ASSERT_EQ(cluster.start_all(), 0);

cpp-driver/gtests/src/unit/tests/test_decoder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ TEST_F(DecoderUnitTest, DecodeStringMultiMap) {
740740
0, 6, 80, 121, 116, 104, 111, 110, // Python
741741
0, 4, 82, 117, 98, 121 }; // Ruby
742742
TestDecoder decoder(input, 58);
743-
Map<String, Vector<String> > value;
743+
StringMultimap value;
744744

745745
// SUCCESS
746746
ASSERT_TRUE(decoder.decode_string_multimap(value));

cpp-driver/gtests/src/unit/tests/test_exec_profile.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ TEST(ExecutionProfileUnitTest, Consistency) {
4141
Config copy_config = config.new_instance();
4242
ExecutionProfile profile_lookup;
4343
ASSERT_TRUE(execution_profile(copy_config, "profile", profile_lookup));
44-
ASSERT_EQ(CASS_DEFAULT_CONSISTENCY, profile_lookup.consistency());
45-
ASSERT_EQ(CASS_DEFAULT_CONSISTENCY, copy_config.default_profile().consistency());
44+
ASSERT_EQ(CASS_CONSISTENCY_UNKNOWN, profile_lookup.consistency());
45+
ASSERT_EQ(CASS_CONSISTENCY_UNKNOWN, copy_config.default_profile().consistency());
4646
}
4747

4848
TEST(ExecutionProfileUnitTest, SerialConsistency) {

0 commit comments

Comments
 (0)