From 181472a1ffaec787cdc457aeec7bbd4906fa6e9d Mon Sep 17 00:00:00 2001 From: mikefero Date: Wed, 10 Jun 2015 12:33:56 -0400 Subject: [PATCH 1/4] fix: Allow cass_statement_bind_bytes_by_name to accept varint --- src/statement.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/statement.cpp b/src/statement.cpp index b9969a034..1447e5eda 100644 --- a/src/statement.cpp +++ b/src/statement.cpp @@ -87,7 +87,8 @@ namespace cass { template<> struct IsValidValueType { bool operator()(uint16_t type) const { - return type == CASS_VALUE_TYPE_BLOB; + return type == CASS_VALUE_TYPE_BLOB || + type == CASS_VALUE_TYPE_VARINT; } }; From ffb7c65b1a8a3db68c451d6e9cd4ede11f24fe45 Mon Sep 17 00:00:00 2001 From: mikefero Date: Wed, 10 Jun 2015 12:34:18 -0400 Subject: [PATCH 2/4] test: CPP-272 Ensure cass_statement_bind_bytes_by_name accepts varint --- test/integration_tests/src/test_by_name.cpp | 61 +++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/test/integration_tests/src/test_by_name.cpp b/test/integration_tests/src/test_by_name.cpp index 07539d5f5..dcf89b3e4 100644 --- a/test/integration_tests/src/test_by_name.cpp +++ b/test/integration_tests/src/test_by_name.cpp @@ -35,6 +35,8 @@ struct ByNameTests : public test_utils::SingleSessionTest { test_utils::execute_query(session, str(boost::format("USE %s") % test_utils::SIMPLE_KEYSPACE)); test_utils::execute_query(session, "CREATE TABLE by_name (key uuid PRIMARY KEY, a int, b boolean, c text, abc float, \"ABC\" float, \"aBc\" float)"); + + test_utils::execute_query(session, "CREATE TABLE bytes_by_name (key uuid PRIMARY KEY, blobs blob, varints varint)"); } test_utils::CassPreparedPtr prepare(const std::string& query) { @@ -51,6 +53,14 @@ struct ByNameTests : public test_utils::SingleSessionTest { BOOST_REQUIRE(cass_result_row_count(result.get()) > 0); return result; } + + test_utils::CassResultPtr select_all_from_bytes_by_name() { + test_utils::CassResultPtr result; + test_utils::execute_query(session, "SELECT * FROM bytes_by_name", &result); + BOOST_REQUIRE(cass_result_column_count(result.get()) == 3); + BOOST_REQUIRE(cass_result_row_count(result.get()) > 0); + return result; + } }; BOOST_FIXTURE_TEST_SUITE(by_name, ByNameTests) @@ -272,4 +282,55 @@ BOOST_AUTO_TEST_CASE(null) BOOST_CHECK(cass_value_is_null(cass_row_get_column_by_name(row, "\"aBc\""))); } +/** + * Bind bytes by name + * + * This test handles the binding of a prepared statement with a + * CASS_VALUE_TYPE_BLOB and CASS_VALUE_TYPE_VARINT datatype. + * + * @since 2.0.2 + * @test_category prepared_statements:binding + * @jira_ticket CPP-272 [https://datastax-oss.atlassian.net/browse/CPP-272] + */ +BOOST_AUTO_TEST_CASE(bind_bytes_by_name) +{ + test_utils::CassPreparedPtr prepared = prepare("INSERT INTO bytes_by_name (key, blobs, varints) VALUES (?, ?, ?)"); + test_utils::CassStatementPtr statement(cass_prepared_bind(prepared.get())); + + CassUuid key = test_utils::generate_time_uuid(uuid_gen); + CassBytes blob; + blob.data = reinterpret_cast("68971169783116971203269110116101114112114105115101329911211245100114105118101114"); + blob.size = strlen(reinterpret_cast(blob.data)); + CassBytes varint; + varint.data = reinterpret_cast("1234567890123456789012345678901234567890"); + varint.size = strlen(reinterpret_cast(varint.data)); + + BOOST_REQUIRE_EQUAL(cass_statement_bind_uuid_by_name(statement.get(), "key", key), CASS_OK); + BOOST_REQUIRE_EQUAL(cass_statement_bind_bytes_by_name(statement.get(), "blobs", const_cast(blob.data), blob.size), CASS_OK); + BOOST_REQUIRE_EQUAL(cass_statement_bind_bytes_by_name(statement.get(), "varints", const_cast(varint.data), varint.size), CASS_OK); + + test_utils::CassFuturePtr future(cass_session_execute(session, statement.get())); + test_utils::wait_and_check_error(future.get()); + test_utils::CassResultPtr result = select_all_from_bytes_by_name(); + const CassRow* row = cass_result_first_row(result.get()); + + const CassValue* value = cass_row_get_column_by_name(row, "key"); + CassUuid result_key; + BOOST_REQUIRE(value != NULL); + BOOST_REQUIRE_EQUAL(cass_value_get_uuid(value, &result_key), CASS_OK); + BOOST_CHECK(test_utils::Value::equal(result_key, key)); + + value = cass_row_get_column_by_name(row, "blobs"); + CassBytes result_blob; + BOOST_REQUIRE(value != NULL); + BOOST_REQUIRE_EQUAL(cass_value_get_bytes(value, &result_blob.data, &result_blob.size), CASS_OK); + BOOST_REQUIRE(test_utils::Value::equal(blob, result_blob)); + + value = cass_row_get_column_by_name(row, "varints"); + CassBytes result_varint; + BOOST_REQUIRE(value != NULL); + BOOST_REQUIRE_EQUAL(cass_value_get_bytes(value, &result_varint.data, &result_varint.size), CASS_OK); + BOOST_REQUIRE(test_utils::Value::equal(varint, result_varint)); +} + BOOST_AUTO_TEST_SUITE_END() From 011910e320afc476606f93e608f4b60a686765e1 Mon Sep 17 00:00:00 2001 From: mikefero Date: Fri, 12 Jun 2015 21:35:44 -0400 Subject: [PATCH 3/4] test: CPP-187 - Increase test coverage for Cassandra 1.2.x This commit will allow for the following tests to run against C* 1.2.x: async, basics, by_name, collections, outage, paging, stress, and version1. The basics test suite was also enhanced to perform simple statement queries for all data types. Tests that also are not applicable to a particular C* instance can now be skipped without starting up a cluster (e.g. basics and serial consistency tests are skipped on C* 1.2.x). Minor cleanup along with a memory leak was also addressed. --- test/ccm_bridge/include/cql_ccm_bridge.hpp | 56 +++- test/ccm_bridge/src/cql_ccm_bridge.cpp | 19 +- test/integration_tests/src/test_async.cpp | 18 +- test/integration_tests/src/test_basics.cpp | 297 ++++++++++++------ test/integration_tests/src/test_batch.cpp | 279 +++++++++------- test/integration_tests/src/test_by_name.cpp | 29 +- .../src/test_collections.cpp | 18 +- test/integration_tests/src/test_outage.cpp | 16 +- test/integration_tests/src/test_paging.cpp | 20 +- .../src/test_prepared_outage.cpp | 7 +- .../src/test_schema_agreement.cpp | 1 - .../src/test_serial_consistency.cpp | 72 +++-- test/integration_tests/src/test_stress.cpp | 34 +- test/integration_tests/src/test_utils.cpp | 76 ++++- test/integration_tests/src/test_utils.hpp | 180 ++++++++++- test/integration_tests/src/test_version1.cpp | 6 +- 16 files changed, 803 insertions(+), 325 deletions(-) diff --git a/test/ccm_bridge/include/cql_ccm_bridge.hpp b/test/ccm_bridge/include/cql_ccm_bridge.hpp index 4f12e7b08..bbcd25f27 100644 --- a/test/ccm_bridge/include/cql_ccm_bridge.hpp +++ b/test/ccm_bridge/include/cql_ccm_bridge.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -46,7 +47,7 @@ struct CassVersion { /** * Extra portion of version number */ - char extra[64]; + std::string extra; /** * Initializing constructor for structure @@ -55,8 +56,58 @@ struct CassVersion { major = 0; minor = 0; patch = 0; - memset(extra, '\0', sizeof(extra)); + extra = ""; }; + + /** + * Create the CassVersion from a human readable string + * + * @param version_string String representation to convert + */ + CassVersion(std::string version_string) { + major = 0; + minor = 0; + patch = 0; + extra = ""; + from_string(version_string); + }; + + /** + * Convert the version into a human readable string + */ + std::string to_string() { + std::stringstream version_string; + version_string << major << "." << minor << "." << patch; + if (!extra.empty()) { + version_string << "-" << patch; + } + return version_string.str(); + } + + /** + * Convert the version from human readable string to structure + * + * @param version_string String representation to convert + */ + void from_string(const std::string &version_string) { + // Clean up the string for tokens + std::string version(version_string); + std::replace(version.begin(), version.end(), '.', ' '); + std::size_t found = version.find("-"); + if (found != std::string::npos) { + version.replace(found, 1, " "); + } + + // Convert to tokens and assign version parameters + std::istringstream tokens(version); + if (tokens >> major) { + if (tokens >> minor) { + if (tokens >> patch) { + tokens >> extra; + } + } + } + } }; namespace cql { @@ -81,7 +132,6 @@ class cql_ccm_bridge_t : public boost::noncopyable { void resume(int node); void kill(); void kill(int node); - void binary(int node, bool enable); void gossip(int node, bool enable); void remove(); diff --git a/test/ccm_bridge/src/cql_ccm_bridge.cpp b/test/ccm_bridge/src/cql_ccm_bridge.cpp index 5afd523e2..40252c45d 100644 --- a/test/ccm_bridge/src/cql_ccm_bridge.cpp +++ b/test/ccm_bridge/src/cql_ccm_bridge.cpp @@ -310,24 +310,21 @@ void cql_ccm_bridge_t::execute_ccm_and_print(const string& ccm_args) { } CassVersion cql_ccm_bridge_t::get_cassandra_version() { - //Convert the cassandra_version value into the CassVersion structure - CassVersion version; - sscanf(_cassandra_version.c_str(), "%hu.%hu.%hu-%s", &version.major, &version.minor, &version.patch, version.extra); + CassVersion version(_cassandra_version); return version; } CassVersion cql_ccm_bridge_t::get_cassandra_version(int node) { - //Get the version string from CCM + // Get the version string from CCM std::string version_string = execute_command(boost::str(boost::format("%1% node%2% version") % CCM_COMMAND % node)); size_t prefix_index = version_string.find("ReleaseVersion: "); if (prefix_index != std::string::npos) { version_string.replace(0, 16, ""); } - //Convert the version string into the CassVersion structure - CassVersion version; - sscanf(version_string.c_str(), "%hu.%hu.%hu-%s", &version.major, &version.minor, &version.patch, version.extra); + // Return the version of the node + CassVersion version(_cassandra_version); return version; } @@ -371,14 +368,6 @@ void cql_ccm_bridge_t::kill(int node) { execute_ccm_command(boost::str(boost::format("node%1% stop --not-gently") % node)); } -void cql_ccm_bridge_t::binary(int node, bool enable) { - if (enable) { - execute_ccm_command(boost::str(boost::format("node%1% nodetool enablebinary") % node)); - } else { - execute_ccm_command(boost::str(boost::format("node%1% nodetool disablebinary") % node)); - } -} - void cql_ccm_bridge_t::gossip(int node, bool enable) { if (enable) { execute_ccm_command(boost::str(boost::format("node%1% nodetool enablegossip") % node)); diff --git a/test/integration_tests/src/test_async.cpp b/test/integration_tests/src/test_async.cpp index 092625ead..90ac5c777 100644 --- a/test/integration_tests/src/test_async.cpp +++ b/test/integration_tests/src/test_async.cpp @@ -49,12 +49,20 @@ struct AsyncTests : public test_utils::SingleSessionTest { std::vector ids; for (size_t i = 0; i < num_concurrent_requests; ++i) { CassUuid id = test_utils::generate_time_uuid(uuid_gen); - test_utils::CassStatementPtr statement(cass_statement_new_n(insert_query.data(), insert_query.size(), 3)); + test_utils::CassStatementPtr statement(cass_statement_new(insert_query.c_str(), 3)); + + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + insert_query = str(boost::format("INSERT INTO %s (id, num, str) VALUES(%s, %s, 'row%s')") % table_name % test_utils::Value::to_string(id) % i % i); + statement = test_utils::CassStatementPtr(cass_statement_new(insert_query.c_str(), 0)); + } else { + BOOST_REQUIRE(cass_statement_bind_uuid(statement.get(), 0, id) == CASS_OK); + BOOST_REQUIRE(cass_statement_bind_int32(statement.get(), 1, i) == CASS_OK); + std::string str_value = str(boost::format("row%d") % i); + BOOST_REQUIRE(cass_statement_bind_string(statement.get(), 2, str_value.c_str()) == CASS_OK); + } + cass_statement_set_consistency(statement.get(), CASS_CONSISTENCY_QUORUM); - BOOST_REQUIRE(cass_statement_bind_uuid(statement.get(), 0, id) == CASS_OK); - BOOST_REQUIRE(cass_statement_bind_int32(statement.get(), 1, i) == CASS_OK); - std::string str_value = str(boost::format("row%d") % i); - BOOST_REQUIRE(cass_statement_bind_string_n(statement.get(), 2, str_value.data(), str_value.size()) == CASS_OK); futures->push_back(test_utils::CassFuturePtr(cass_session_execute(session, statement.get()))); ids.push_back(id); } diff --git a/test/integration_tests/src/test_basics.cpp b/test/integration_tests/src/test_basics.cpp index a7d1969f1..706841c84 100644 --- a/test/integration_tests/src/test_basics.cpp +++ b/test/integration_tests/src/test_basics.cpp @@ -45,20 +45,39 @@ struct BasicTests : public test_utils::SingleSessionTest { std::string table_name = str(boost::format("table_%s") % test_utils::generate_unique_str(uuid_gen)); std::string type_name = test_utils::get_value_type(type); - test_utils::execute_query(session, str(boost::format("CREATE TABLE %s (tweet_id uuid PRIMARY KEY, test_val %s);") + test_utils::execute_query(session, str(boost::format("CREATE TABLE %s (tweet_id uuid PRIMARY KEY, test_val %s)") % table_name % type_name)); - CassUuid tweet_id = test_utils::generate_random_uuid(uuid_gen); + /* + * Bound parameters or prepared statement validation + */ - std::string insert_query = str(boost::format("INSERT INTO %s (tweet_id, test_val) VALUES(?, ?);") % table_name); + // Create insert statement for bound parameters + CassUuid tweet_id = test_utils::generate_random_uuid(uuid_gen); + std::string insert_query = str(boost::format("INSERT INTO %s (tweet_id, test_val) VALUES(?, ?)") % table_name); test_utils::CassStatementPtr insert_statement(cass_statement_new(insert_query.c_str(), 2)); + + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, insert_query); + insert_statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } + BOOST_REQUIRE(cass_statement_bind_uuid(insert_statement.get(), 0, tweet_id) == CASS_OK); BOOST_REQUIRE(test_utils::Value::bind(insert_statement.get(), 1, value) == CASS_OK); test_utils::CassFuturePtr insert_future(cass_session_execute(session, insert_statement.get())); test_utils::wait_and_check_error(insert_future.get()); + // Create select statement for bound parameters std::string select_query = str(boost::format("SELECT * FROM %s WHERE tweet_id = ?;") % table_name); test_utils::CassStatementPtr select_statement(cass_statement_new(select_query.c_str(), 1)); + + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, select_query); + select_statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } + BOOST_REQUIRE(cass_statement_bind_uuid(select_statement.get(), 0, tweet_id) == CASS_OK); test_utils::CassFuturePtr select_future(cass_session_execute(session, select_statement.get())); test_utils::wait_and_check_error(select_future.get()); @@ -72,6 +91,41 @@ struct BasicTests : public test_utils::SingleSessionTest { BOOST_REQUIRE(cass_value_type(column) == type); BOOST_REQUIRE(test_utils::Value::get(column, &result_value) == CASS_OK); BOOST_REQUIRE(test_utils::Value::equal(result_value, value)); + + /* + * Simple statement validation + */ + + // Generate the appropriate formatted string for the simple statement + std::string tweet_id_string = test_utils::generate_random_uuid_str(uuid_gen); + std::string value_string = test_utils::Value::to_string(value); + if (type == CASS_VALUE_TYPE_BLOB) { + value_string = "0x" + test_utils::to_hex(value_string.c_str()); + } else if (type == CASS_VALUE_TYPE_VARINT) { + value_string = test_utils::BigNumber::to_string(value_string.c_str()); + } else if (type == CASS_VALUE_TYPE_ASCII || type == CASS_VALUE_TYPE_TEXT || + type == CASS_VALUE_TYPE_VARCHAR || type == CASS_VALUE_TYPE_INET) { + value_string = "'" + value_string + "'"; + } + + insert_query = str(boost::format(test_utils::replaceAll(insert_query, "?", "%s")) % tweet_id_string % value_string); + insert_statement = test_utils::CassStatementPtr(cass_statement_new(insert_query.c_str(), 0)); + insert_future = test_utils::CassFuturePtr(cass_session_execute(session, insert_statement.get())); + test_utils::wait_and_check_error(insert_future.get()); + + select_query = str(boost::format(test_utils::replaceAll(select_query, "?", "%s")) % tweet_id_string); + select_statement = test_utils::CassStatementPtr(cass_statement_new(select_query.c_str(), 0)); + select_future = test_utils::CassFuturePtr(cass_session_execute(session, select_statement.get())); + test_utils::wait_and_check_error(select_future.get()); + + result = test_utils::CassResultPtr(cass_future_get_result(select_future.get())); + BOOST_REQUIRE(cass_result_row_count(result.get()) == 1); + BOOST_REQUIRE(cass_result_column_count(result.get()) == 2); + + column = cass_row_get_column(cass_result_first_row(result.get()), 1); + BOOST_REQUIRE(cass_value_type(column) == type); + BOOST_REQUIRE(test_utils::Value::get(column, &result_value) == CASS_OK); + BOOST_REQUIRE(test_utils::Value::equal(result_value, value)); } template @@ -79,21 +133,40 @@ struct BasicTests : public test_utils::SingleSessionTest { std::string table_name = str(boost::format("table_%s") % test_utils::generate_unique_str(uuid_gen)); std::string type_name = test_utils::get_value_type(type); - test_utils::execute_query(session, str(boost::format("CREATE TABLE %s (tweet_id uuid PRIMARY KEY, min_val %s, max_val %s);") + test_utils::execute_query(session, str(boost::format("CREATE TABLE %s (tweet_id uuid PRIMARY KEY, min_val %s, max_val %s)") % table_name % type_name % type_name)); - CassUuid tweet_id = test_utils::generate_random_uuid(uuid_gen); + /* + * Bound parameters or prepared statement validation + */ + // Create insert statement for bound parameters + CassUuid tweet_id = test_utils::generate_random_uuid(uuid_gen); std::string insert_query = str(boost::format("INSERT INTO %s (tweet_id, min_val, max_val) VALUES(?, ?, ?);") % table_name); test_utils::CassStatementPtr insert_statement(cass_statement_new(insert_query.c_str(), 3)); + + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, insert_query); + insert_statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } + BOOST_REQUIRE(cass_statement_bind_uuid(insert_statement.get(), 0, tweet_id) == CASS_OK); BOOST_REQUIRE(test_utils::Value::bind(insert_statement.get(), 1, test_utils::Value::min_value()) == CASS_OK); BOOST_REQUIRE(test_utils::Value::bind(insert_statement.get(), 2, test_utils::Value::max_value()) == CASS_OK); test_utils::CassFuturePtr result_future(cass_session_execute(session, insert_statement.get())); test_utils::wait_and_check_error(result_future.get()); + // Create select statement for bound parameters std::string select_query = str(boost::format("SELECT * FROM %s WHERE tweet_id = ?;") % table_name); test_utils::CassStatementPtr select_statement(cass_statement_new(select_query.c_str(), 1)); + + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, select_query.c_str()); + select_statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } + BOOST_REQUIRE(cass_statement_bind_uuid(select_statement.get(), 0, tweet_id) == CASS_OK); test_utils::CassFuturePtr select_future(cass_session_execute(session, select_statement.get())); test_utils::wait_and_check_error(select_future.get()); @@ -109,8 +182,43 @@ struct BasicTests : public test_utils::SingleSessionTest { T max_value; BOOST_REQUIRE(test_utils::Value::get(cass_row_get_column(cass_result_first_row(result.get()), 1), &max_value) == CASS_OK); BOOST_REQUIRE(test_utils::Value::equal(max_value, test_utils::Value::max_value())); + + /* + * Simple statement validation + */ + + // Generate the appropriate formatted strings for the simple statement + std::string tweet_id_string = test_utils::generate_random_uuid_str(uuid_gen); + std::string min_value_string = test_utils::Value::to_string(test_utils::Value::min_value()); + std::string max_value_string = test_utils::Value::to_string(test_utils::Value::max_value()); + if (type == CASS_VALUE_TYPE_INET) { + min_value_string = "'" + min_value_string + "'"; + max_value_string = "'" + max_value_string + "'"; + } + + insert_query = str(boost::format(test_utils::replaceAll(insert_query, "?", "%s")) + % tweet_id_string % min_value_string % max_value_string); + insert_statement = test_utils::CassStatementPtr(cass_statement_new(insert_query.c_str(), 0)); + result_future = test_utils::CassFuturePtr(cass_session_execute(session, insert_statement.get())); + test_utils::wait_and_check_error(result_future.get()); + + select_query = str(boost::format(test_utils::replaceAll(select_query, "?", "%s")) % tweet_id_string); + select_statement = test_utils::CassStatementPtr(cass_statement_new(select_query.c_str(), 0)); + select_future = test_utils::CassFuturePtr(cass_session_execute(session, select_statement.get())); + test_utils::wait_and_check_error(select_future.get()); + + result = test_utils::CassResultPtr(cass_future_get_result(select_future.get())); + BOOST_REQUIRE(cass_result_row_count(result.get()) == 1); + BOOST_REQUIRE(cass_result_column_count(result.get()) == 3); + + BOOST_REQUIRE(test_utils::Value::get(cass_row_get_column(cass_result_first_row(result.get()), 2), &min_value) == CASS_OK); + BOOST_REQUIRE(test_utils::Value::equal(min_value, test_utils::Value::min_value())); + + BOOST_REQUIRE(test_utils::Value::get(cass_row_get_column(cass_result_first_row(result.get()), 1), &max_value) == CASS_OK); + BOOST_REQUIRE(test_utils::Value::equal(max_value, test_utils::Value::max_value())); } + template void insert_null_value(CassValueType type) { std::string table_name = str(boost::format("table_%s") % test_utils::generate_unique_str(uuid_gen)); std::string type_name = test_utils::get_value_type(type); @@ -121,20 +229,39 @@ struct BasicTests : public test_utils::SingleSessionTest { type_name.append(""); } - test_utils::execute_query(session, str(boost::format("CREATE TABLE %s (tweet_id uuid PRIMARY KEY, test_val %s);") + test_utils::execute_query(session, str(boost::format("CREATE TABLE %s (tweet_id uuid PRIMARY KEY, test_val %s)") % table_name % type_name)); - CassUuid tweet_id = test_utils::generate_random_uuid(uuid_gen); + /* + * Bound parameters or prepared statement validation + */ + // Create insert statement for bound parameters + CassUuid tweet_id = test_utils::generate_random_uuid(uuid_gen); std::string insert_query = str(boost::format("INSERT INTO %s (tweet_id, test_val) VALUES(?, ?);") % table_name); test_utils::CassStatementPtr insert_statement(cass_statement_new(insert_query.c_str(), 2)); + + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, insert_query); + insert_statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } + BOOST_REQUIRE(cass_statement_bind_uuid(insert_statement.get(), 0, tweet_id) == CASS_OK); BOOST_REQUIRE(cass_statement_bind_null(insert_statement.get(), 1) == CASS_OK); test_utils::CassFuturePtr insert_future(cass_session_execute(session, insert_statement.get())); test_utils::wait_and_check_error(insert_future.get()); + // Create select statement for bound parameters std::string select_query = str(boost::format("SELECT * FROM %s WHERE tweet_id = ?;") % table_name); test_utils::CassStatementPtr select_statement(cass_statement_new(select_query.c_str(), 1)); + + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, select_query); + select_statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } + BOOST_REQUIRE(cass_statement_bind_uuid(select_statement.get(), 0, tweet_id) == CASS_OK); test_utils::CassFuturePtr select_future(cass_session_execute(session, select_statement.get())); test_utils::wait_and_check_error(select_future.get()); @@ -143,50 +270,43 @@ struct BasicTests : public test_utils::SingleSessionTest { BOOST_REQUIRE(cass_result_row_count(result.get()) == 1); BOOST_REQUIRE(cass_result_column_count(result.get()) == 2); - // Get the test value column from the first row of the result - const CassValue *testValue = cass_row_get_column(cass_result_first_row(result.get()), 1); + // Ensure the test value is NULL + const CassValue* column_value = cass_row_get_column(cass_result_first_row(result.get()), 1); + BOOST_REQUIRE(cass_value_is_null(column_value)); + T value; + BOOST_REQUIRE(test_utils::Value::get(column_value, &value) == CASS_ERROR_LIB_NULL_VALUE); + + /* + * Simple statement validation + */ + + // Generate the appropriate formatted strings for the simple statement + std::string tweet_id_string = test_utils::generate_random_uuid_str(uuid_gen); + + insert_query = str(boost::format(test_utils::replaceAll(insert_query, "?", "%s")) % tweet_id_string % "NULL"); + insert_statement = test_utils::CassStatementPtr(cass_statement_new(insert_query.c_str(), 0)); + insert_future = test_utils::CassFuturePtr(cass_session_execute(session, insert_statement.get())); + test_utils::wait_and_check_error(insert_future.get()); + + select_query = str(boost::format(test_utils::replaceAll(select_query, "?", "%s")) % tweet_id_string); + select_statement = test_utils::CassStatementPtr(cass_statement_new(select_query.c_str(), 0)); + select_future = test_utils::CassFuturePtr(cass_session_execute(session, select_statement.get())); + test_utils::wait_and_check_error(select_future.get()); + + result = test_utils::CassResultPtr(cass_future_get_result(select_future.get())); + BOOST_REQUIRE(cass_result_row_count(result.get()) == 1); + BOOST_REQUIRE(cass_result_column_count(result.get()) == 2); // Ensure the test value is NULL - BOOST_REQUIRE(cass_value_is_null(testValue)); - - // Verify cass_value_get function returns CASS_ERROR_LIB_NULL_VALUE - if (type == CASS_VALUE_TYPE_INT) { - cass_int32_t value = 0; - BOOST_REQUIRE_EQUAL(cass_value_get_int32(testValue, &value), CASS_ERROR_LIB_NULL_VALUE); - } else if (type == CASS_VALUE_TYPE_BIGINT || type == CASS_VALUE_TYPE_TIMESTAMP) { - cass_int64_t value = 0; - BOOST_REQUIRE_EQUAL(cass_value_get_int64(testValue, &value), CASS_ERROR_LIB_NULL_VALUE); - } else if (type == CASS_VALUE_TYPE_FLOAT) { - cass_float_t value = 0; - BOOST_REQUIRE_EQUAL(cass_value_get_float(testValue, &value), CASS_ERROR_LIB_NULL_VALUE); - } else if (type == CASS_VALUE_TYPE_DOUBLE) { - cass_double_t value = 0; - BOOST_REQUIRE_EQUAL(cass_value_get_double(testValue, &value), CASS_ERROR_LIB_NULL_VALUE); - } else if (type == CASS_VALUE_TYPE_BOOLEAN) { - cass_bool_t value = cass_false; - BOOST_REQUIRE_EQUAL(cass_value_get_bool(testValue, &value), CASS_ERROR_LIB_NULL_VALUE); - } else if (type == CASS_VALUE_TYPE_UUID || type == CASS_VALUE_TYPE_TIMEUUID) { - CassUuid value; - BOOST_REQUIRE_EQUAL(cass_value_get_uuid(testValue, &value), CASS_ERROR_LIB_NULL_VALUE); - } else if (type == CASS_VALUE_TYPE_INET) { - CassInet value; - BOOST_REQUIRE_EQUAL(cass_value_get_inet(testValue, &value), CASS_ERROR_LIB_NULL_VALUE); - } else if (type == CASS_VALUE_TYPE_ASCII || type == CASS_VALUE_TYPE_TEXT || type == CASS_VALUE_TYPE_VARCHAR) { - CassString value; - BOOST_REQUIRE_EQUAL(cass_value_get_string(testValue, &value.data, &value.length), CASS_ERROR_LIB_NULL_VALUE); - } else if (type == CASS_VALUE_TYPE_BLOB || type == CASS_VALUE_TYPE_VARINT || type == CASS_VALUE_TYPE_LIST || type == CASS_VALUE_TYPE_MAP || type == CASS_VALUE_TYPE_SET) { - CassBytes value; - BOOST_REQUIRE_EQUAL(cass_value_get_bytes(testValue, &value.data, &value.size), CASS_ERROR_LIB_NULL_VALUE); - } else if (type == CASS_VALUE_TYPE_DECIMAL) { - CassDecimal value; - BOOST_REQUIRE_EQUAL(cass_value_get_decimal(testValue, &value.varint, &value.varint_size, &value.scale), CASS_ERROR_LIB_NULL_VALUE); - } + column_value = cass_row_get_column(cass_result_first_row(result.get()), 1); + BOOST_REQUIRE(cass_value_is_null(column_value)); + BOOST_REQUIRE(test_utils::Value::get(column_value, &value) == CASS_ERROR_LIB_NULL_VALUE); } bool is_result_empty(const CassResult* result) { bool is_empty = true; - //Go through each row in the result and ensure it is empty + // Go through each row in the result and ensure it is empty if (result) { CassIterator* rows = cass_iterator_from_result(result); while (cass_iterator_next(rows)) { @@ -286,45 +406,28 @@ BOOST_AUTO_TEST_CASE(min_max) cass_uuid_max_from_time(std::numeric_limits::max(), &value); insert_single_value(CASS_VALUE_TYPE_TIMEUUID, value); } - - { - CassDecimal value; - insert_single_value(CASS_VALUE_TYPE_DECIMAL, value); - } - - { - CassString value; - insert_single_value(CASS_VALUE_TYPE_ASCII, value); - insert_single_value(CASS_VALUE_TYPE_VARCHAR, value); - } - - { - CassBytes value; - insert_single_value(CASS_VALUE_TYPE_BLOB, value); - insert_single_value(CASS_VALUE_TYPE_VARINT, value); - } } BOOST_AUTO_TEST_CASE(null) { - insert_null_value(CASS_VALUE_TYPE_ASCII); - insert_null_value(CASS_VALUE_TYPE_BIGINT); - insert_null_value(CASS_VALUE_TYPE_BLOB); - insert_null_value(CASS_VALUE_TYPE_BOOLEAN); - insert_null_value(CASS_VALUE_TYPE_DECIMAL); - insert_null_value(CASS_VALUE_TYPE_DOUBLE); - insert_null_value(CASS_VALUE_TYPE_FLOAT); - insert_null_value(CASS_VALUE_TYPE_INT); - insert_null_value(CASS_VALUE_TYPE_TEXT); - insert_null_value(CASS_VALUE_TYPE_TIMESTAMP); - insert_null_value(CASS_VALUE_TYPE_UUID); - insert_null_value(CASS_VALUE_TYPE_VARCHAR); - insert_null_value(CASS_VALUE_TYPE_VARINT); - insert_null_value(CASS_VALUE_TYPE_TIMEUUID); - insert_null_value(CASS_VALUE_TYPE_INET); - insert_null_value(CASS_VALUE_TYPE_LIST); - insert_null_value(CASS_VALUE_TYPE_MAP); - insert_null_value(CASS_VALUE_TYPE_SET); + insert_null_value(CASS_VALUE_TYPE_ASCII); + insert_null_value(CASS_VALUE_TYPE_BIGINT); + insert_null_value(CASS_VALUE_TYPE_BLOB); + insert_null_value(CASS_VALUE_TYPE_BOOLEAN); + insert_null_value(CASS_VALUE_TYPE_DECIMAL); + insert_null_value(CASS_VALUE_TYPE_DOUBLE); + insert_null_value(CASS_VALUE_TYPE_FLOAT); + insert_null_value(CASS_VALUE_TYPE_INT); + insert_null_value(CASS_VALUE_TYPE_TEXT); + insert_null_value(CASS_VALUE_TYPE_TIMESTAMP); + insert_null_value(CASS_VALUE_TYPE_UUID); + insert_null_value(CASS_VALUE_TYPE_VARCHAR); + insert_null_value(CASS_VALUE_TYPE_VARINT); + insert_null_value(CASS_VALUE_TYPE_TIMEUUID); + insert_null_value(CASS_VALUE_TYPE_INET); + insert_null_value(CASS_VALUE_TYPE_LIST); + insert_null_value(CASS_VALUE_TYPE_MAP); + insert_null_value(CASS_VALUE_TYPE_SET); } BOOST_AUTO_TEST_CASE(timestamp) @@ -361,14 +464,20 @@ BOOST_AUTO_TEST_CASE(counters) test_utils::execute_query(session, "CREATE TABLE test(tweet_id int PRIMARY KEY, incdec counter);"); int tweet_id = 0; - for (int i = 0; i < 100; ++i) { + // Create update statement for bound parameters std::string update_query = str(boost::format("UPDATE %s SET incdec = incdec %s ? WHERE tweet_id = %d;") - % test_utils::SIMPLE_TABLE % ((i % 2) == 0 ? "-" : "+") % tweet_id); - + % test_utils::SIMPLE_TABLE % ((i % 2) == 0 ? "-" : "+") % tweet_id); test_utils::CassStatementPtr statement(cass_statement_new(update_query.c_str(), 1)); - BOOST_REQUIRE(cass_statement_bind_int64(statement.get(), 0, i) == CASS_OK); + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + update_query = str(boost::format("UPDATE %s SET incdec = incdec %s %d WHERE tweet_id = %d;") + % test_utils::SIMPLE_TABLE % ((i % 2) == 0 ? "-" : "+") % i % tweet_id); + statement = test_utils::CassStatementPtr(cass_statement_new(update_query.c_str(), 0)); + } else { + BOOST_REQUIRE(cass_statement_bind_int64(statement.get(), 0, i) == CASS_OK); + } test_utils::CassFuturePtr result_future(cass_session_execute(session, statement.get())); test_utils::wait_and_check_error(result_future.get()); @@ -396,16 +505,26 @@ BOOST_AUTO_TEST_CASE(rows_in_rows_out) str(boost::format("CREATE TABLE %s (tweet_id bigint PRIMARY KEY, t1 bigint, t2 bigint, t3 bigint);") % test_utils::SIMPLE_TABLE), NULL, consistency); - const size_t num_rows = 100000; - + // Create insert statement for bound parameters std::string insert_query(boost::str(boost::format("INSERT INTO %s (tweet_id, t1, t2, t3) VALUES (?, ?, ?, ?);") % test_utils::SIMPLE_TABLE)); + + const size_t num_rows = 100000; for (size_t i = 0; i < num_rows; ++i) { test_utils::CassStatementPtr statement(cass_statement_new(insert_query.c_str(), 4)); + + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + std::string insert_query(boost::str(boost::format("INSERT INTO %s (tweet_id, t1, t2, t3) VALUES (%s, %s, %s, %s);") % test_utils::SIMPLE_TABLE + % i % (i + 1) % (i + 2) % (i + 3))); + statement = test_utils::CassStatementPtr(cass_statement_new(insert_query.c_str(), 0)); + } else { + BOOST_REQUIRE(test_utils::Value::bind(statement.get(), 0, i) == CASS_OK); + BOOST_REQUIRE(test_utils::Value::bind(statement.get(), 1, i + 1) == CASS_OK); + BOOST_REQUIRE(test_utils::Value::bind(statement.get(), 2, i + 2) == CASS_OK); + BOOST_REQUIRE(test_utils::Value::bind(statement.get(), 3, i + 3) == CASS_OK); + } + cass_statement_set_consistency(statement.get(), consistency); - BOOST_REQUIRE(test_utils::Value::bind(statement.get(), 0, i) == CASS_OK); - BOOST_REQUIRE(test_utils::Value::bind(statement.get(), 1, i + 1) == CASS_OK); - BOOST_REQUIRE(test_utils::Value::bind(statement.get(), 2, i + 2) == CASS_OK); - BOOST_REQUIRE(test_utils::Value::bind(statement.get(), 3, i + 3) == CASS_OK); test_utils::CassFuturePtr result_future(cass_session_execute(session, statement.get())); test_utils::wait_and_check_error(result_future.get(), 30 * test_utils::ONE_SECOND_IN_MICROS); } diff --git a/test/integration_tests/src/test_batch.cpp b/test/integration_tests/src/test_batch.cpp index bd54ef515..b8bd2e76b 100644 --- a/test/integration_tests/src/test_batch.cpp +++ b/test/integration_tests/src/test_batch.cpp @@ -21,6 +21,7 @@ #include "cassandra.h" #include "test_utils.hpp" +#include #include #include #include @@ -39,171 +40,207 @@ struct BatchTests : public test_utils::SingleSessionTest { test_utils::execute_query(session, str(boost::format("CREATE TABLE %s (tweet_id int PRIMARY KEY, test_val text);") % SIMPLE_TABLE_NAME)); test_utils::execute_query(session, str(boost::format("CREATE TABLE %s (tweet_id int PRIMARY KEY, test_val counter);") % COUNTER_TABLE_NAME)); } + + void validate_results(int num_rows) { + std::string select_query = str(boost::format("SELECT * FROM %s WHERE tweet_id = ?;") % BatchTests::SIMPLE_TABLE_NAME); + + for (int y = 0; y < num_rows; y++) + { + test_utils::CassStatementPtr select_statement(cass_statement_new(select_query.c_str(), 1)); + BOOST_REQUIRE(cass_statement_bind_int32(select_statement.get(), 0, y) == CASS_OK); + test_utils::CassFuturePtr select_future(cass_session_execute(session, select_statement.get())); + test_utils::wait_and_check_error(select_future.get()); + test_utils::CassResultPtr result(cass_future_get_result(select_future.get())); + const CassValue* column = cass_row_get_column(cass_result_first_row(result.get()), 1); + + CassString result_value; + BOOST_REQUIRE(cass_value_type(column) == CASS_VALUE_TYPE_VARCHAR); + BOOST_REQUIRE(test_utils::Value::get(column, &result_value) == CASS_OK); + BOOST_REQUIRE(test_utils::Value::equal(result_value, str(boost::format("test data %s") % y).c_str())); + } + } }; const char* BatchTests::SIMPLE_TABLE_NAME = "simple_batch_testing_table"; const char* BatchTests::COUNTER_TABLE_NAME = "counter_batch_testing_table"; -BOOST_FIXTURE_TEST_SUITE(batch, BatchTests) - - -void validate_results(CassSession* session, int num_rows) { - std::string select_query = str(boost::format("SELECT * FROM %s WHERE tweet_id = ?;") % BatchTests::SIMPLE_TABLE_NAME); - - for (int y = 0; y < num_rows; y++) - { - test_utils::CassStatementPtr select_statement(cass_statement_new(select_query.c_str(), 1)); - BOOST_REQUIRE(cass_statement_bind_int32(select_statement.get(), 0, y) == CASS_OK); - test_utils::CassFuturePtr select_future(cass_session_execute(session, select_statement.get())); - test_utils::wait_and_check_error(select_future.get()); - test_utils::CassResultPtr result(cass_future_get_result(select_future.get())); - const CassValue* column = cass_row_get_column(cass_result_first_row(result.get()), 1); - - CassString result_value; - BOOST_REQUIRE(cass_value_type(column) == CASS_VALUE_TYPE_VARCHAR); - BOOST_REQUIRE(test_utils::Value::get(column, &result_value) == CASS_OK); - BOOST_REQUIRE(test_utils::Value::equal(result_value, CassString(str(boost::format("test data %s") % y).c_str()))); - } -} +BOOST_AUTO_TEST_SUITE(batch) BOOST_AUTO_TEST_CASE(prepared) { - test_utils::CassBatchPtr batch(cass_batch_new(CASS_BATCH_TYPE_LOGGED)); - std::string insert_query = str(boost::format("INSERT INTO %s (tweet_id, test_val) VALUES(?, ?);") % BatchTests::SIMPLE_TABLE_NAME); - - test_utils::CassFuturePtr prepared_future(cass_session_prepare_n(session, - insert_query.data(), insert_query.size())); - test_utils::wait_and_check_error(prepared_future.get()); - test_utils::CassPreparedPtr prepared(cass_future_get_prepared(prepared_future.get())); - - for (int x = 0; x < 4; x++) - { - test_utils::CassStatementPtr insert_statement(cass_prepared_bind(prepared.get())); - BOOST_REQUIRE(cass_statement_bind_int32(insert_statement.get(), 0, x) == CASS_OK); - BOOST_REQUIRE(cass_statement_bind_string(insert_statement.get(), 1, str(boost::format("test data %s") % x).c_str()) == CASS_OK); - cass_batch_add_statement(batch.get(), insert_statement.get()); - } + CassVersion version = test_utils::get_version(); + if (version.major != 1) { + BatchTests tester; + test_utils::CassBatchPtr batch(cass_batch_new(CASS_BATCH_TYPE_LOGGED)); + std::string insert_query = str(boost::format("INSERT INTO %s (tweet_id, test_val) VALUES(?, ?);") % BatchTests::SIMPLE_TABLE_NAME); + + test_utils::CassFuturePtr prepared_future(cass_session_prepare(tester.session, insert_query.c_str())); + test_utils::wait_and_check_error(prepared_future.get()); + test_utils::CassPreparedPtr prepared(cass_future_get_prepared(prepared_future.get())); + + for (int x = 0; x < 4; x++) + { + test_utils::CassStatementPtr insert_statement(cass_prepared_bind(prepared.get())); + BOOST_REQUIRE(cass_statement_bind_int32(insert_statement.get(), 0, x) == CASS_OK); + BOOST_REQUIRE(cass_statement_bind_string(insert_statement.get(), 1, str(boost::format("test data %s") % x).c_str()) == CASS_OK); + cass_batch_add_statement(batch.get(), insert_statement.get()); + } - test_utils::CassFuturePtr insert_future(cass_session_execute_batch(session, batch.get())); - test_utils::wait_and_check_error(insert_future.get()); + test_utils::CassFuturePtr insert_future(cass_session_execute_batch(tester.session, batch.get())); + test_utils::wait_and_check_error(insert_future.get()); - validate_results(session, 4); + tester.validate_results(4); + } else { + boost::unit_test::unit_test_log_t::instance().set_threshold_level(boost::unit_test::log_messages); + BOOST_TEST_MESSAGE("Unsupported Test for Cassandra v" << version.to_string() << ": Skipping batch/prepared"); + BOOST_REQUIRE(true); + } } BOOST_AUTO_TEST_CASE(simple) { - test_utils::CassBatchPtr batch(cass_batch_new(CASS_BATCH_TYPE_LOGGED)); - std::string insert_query = str(boost::format("INSERT INTO %s (tweet_id, test_val) VALUES(?, ?);") % BatchTests::SIMPLE_TABLE_NAME); - - for (int x = 0; x < 4; x++) - { - test_utils::CassStatementPtr insert_statement(cass_statement_new(insert_query.c_str(), 2)); - BOOST_REQUIRE(cass_statement_bind_int32(insert_statement.get(), 0, x) == CASS_OK); - BOOST_REQUIRE(cass_statement_bind_string(insert_statement.get(), 1, str(boost::format("test data %s") % x).c_str()) == CASS_OK); - cass_batch_add_statement(batch.get(), insert_statement.get()); - } + CassVersion version = test_utils::get_version(); + if (version.major != 1) { + BatchTests tester; + test_utils::CassBatchPtr batch(cass_batch_new(CASS_BATCH_TYPE_LOGGED)); + std::string insert_query = str(boost::format("INSERT INTO %s (tweet_id, test_val) VALUES(?, ?);") % BatchTests::SIMPLE_TABLE_NAME); + + for (int x = 0; x < 4; x++) + { + test_utils::CassStatementPtr insert_statement(cass_statement_new(insert_query.c_str(), 2)); + BOOST_REQUIRE(cass_statement_bind_int32(insert_statement.get(), 0, x) == CASS_OK); + BOOST_REQUIRE(cass_statement_bind_string(insert_statement.get(), 1, str(boost::format("test data %s") % x).c_str()) == CASS_OK); + cass_batch_add_statement(batch.get(), insert_statement.get()); + } - test_utils::CassFuturePtr insert_future(cass_session_execute_batch(session, batch.get())); - test_utils::wait_and_check_error(insert_future.get()); + test_utils::CassFuturePtr insert_future(cass_session_execute_batch(tester.session, batch.get())); + test_utils::wait_and_check_error(insert_future.get()); - validate_results(session, 4); + tester.validate_results(4); + } else { + boost::unit_test::unit_test_log_t::instance().set_threshold_level(boost::unit_test::log_messages); + BOOST_TEST_MESSAGE("Unsupported Test for Cassandra v" << version.to_string() << ": Skipping batch/simple"); + BOOST_REQUIRE(true); + } } BOOST_AUTO_TEST_CASE(mixed) { - test_utils::CassBatchPtr batch(cass_batch_new(CASS_BATCH_TYPE_LOGGED)); - std::string insert_query = str(boost::format("INSERT INTO %s (tweet_id, test_val) VALUES(?, ?);") % BatchTests::SIMPLE_TABLE_NAME); - - test_utils::CassFuturePtr prepared_future(cass_session_prepare_n(session, - insert_query.data(), insert_query.size())); - test_utils::wait_and_check_error(prepared_future.get()); - test_utils::CassPreparedPtr prepared(cass_future_get_prepared(prepared_future.get())); - - for (int x = 0; x < 1000; x++) - { - test_utils::CassStatementPtr insert_statement; - if (x % 2 == 0) { - insert_statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); - } else { - insert_statement = test_utils::CassStatementPtr(cass_statement_new(insert_query.c_str(), 2)); + CassVersion version = test_utils::get_version(); + if (version.major != 1) { + BatchTests tester; + test_utils::CassBatchPtr batch(cass_batch_new(CASS_BATCH_TYPE_LOGGED)); + std::string insert_query = str(boost::format("INSERT INTO %s (tweet_id, test_val) VALUES(?, ?);") % BatchTests::SIMPLE_TABLE_NAME); + + test_utils::CassFuturePtr prepared_future(cass_session_prepare(tester.session, insert_query.c_str())); + test_utils::wait_and_check_error(prepared_future.get()); + test_utils::CassPreparedPtr prepared(cass_future_get_prepared(prepared_future.get())); + + for (int x = 0; x < 1000; x++) + { + test_utils::CassStatementPtr insert_statement; + if (x % 2 == 0) { + insert_statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } else { + insert_statement = test_utils::CassStatementPtr(cass_statement_new(insert_query.c_str(), 2)); + } + BOOST_REQUIRE(cass_statement_bind_int32(insert_statement.get(), 0, x) == CASS_OK); + BOOST_REQUIRE(cass_statement_bind_string(insert_statement.get(), 1, str(boost::format("test data %s") % x).c_str()) == CASS_OK); + cass_batch_add_statement(batch.get(), insert_statement.get()); } - BOOST_REQUIRE(cass_statement_bind_int32(insert_statement.get(), 0, x) == CASS_OK); - BOOST_REQUIRE(cass_statement_bind_string(insert_statement.get(), 1, str(boost::format("test data %s") % x).c_str()) == CASS_OK); - cass_batch_add_statement(batch.get(), insert_statement.get()); - } - test_utils::CassFuturePtr insert_future(cass_session_execute_batch(session, batch.get())); - test_utils::wait_and_check_error(insert_future.get()); + test_utils::CassFuturePtr insert_future(cass_session_execute_batch(tester.session, batch.get())); + test_utils::wait_and_check_error(insert_future.get()); - validate_results(session, 1000); + tester.validate_results(1000); + } else { + boost::unit_test::unit_test_log_t::instance().set_threshold_level(boost::unit_test::log_messages); + BOOST_TEST_MESSAGE("Unsupported Test for Cassandra v" << version.to_string() << ": Skipping batch/mixed"); + BOOST_REQUIRE(true); + } } BOOST_AUTO_TEST_CASE(invalid_batch_type) { - test_utils::CassBatchPtr batch(cass_batch_new(CASS_BATCH_TYPE_LOGGED)); - std::string update_query = str(boost::format("UPDATE %s SET test_val = test_val + ? WHERE tweet_id = ?;") % BatchTests::COUNTER_TABLE_NAME); + CassVersion version = test_utils::get_version(); + if (version.major != 1) { + BatchTests tester; + test_utils::CassBatchPtr batch(cass_batch_new(CASS_BATCH_TYPE_LOGGED)); + std::string update_query = str(boost::format("UPDATE %s SET test_val = test_val + ? WHERE tweet_id = ?;") % BatchTests::COUNTER_TABLE_NAME); - test_utils::CassStatementPtr update_statement(cass_statement_new(update_query.c_str(), 2)); + test_utils::CassStatementPtr update_statement(cass_statement_new(update_query.c_str(), 2)); - const int some_value = 99; - BOOST_REQUIRE(cass_statement_bind_int64(update_statement.get(), 0, some_value) == CASS_OK); - BOOST_REQUIRE(cass_statement_bind_int32(update_statement.get(), 1, some_value) == CASS_OK); - cass_batch_add_statement(batch.get(), update_statement.get()); + const int some_value = 99; + BOOST_REQUIRE(cass_statement_bind_int64(update_statement.get(), 0, some_value) == CASS_OK); + BOOST_REQUIRE(cass_statement_bind_int32(update_statement.get(), 1, some_value) == CASS_OK); + cass_batch_add_statement(batch.get(), update_statement.get()); - test_utils::CassFuturePtr update_future(cass_session_execute_batch(session, batch.get())); - BOOST_REQUIRE(cass_future_error_code(update_future.get()) == CASS_ERROR_SERVER_INVALID_QUERY); + test_utils::CassFuturePtr update_future(cass_session_execute_batch(tester.session, batch.get())); + BOOST_REQUIRE(cass_future_error_code(update_future.get()) == CASS_ERROR_SERVER_INVALID_QUERY); + } else { + boost::unit_test::unit_test_log_t::instance().set_threshold_level(boost::unit_test::log_messages); + BOOST_TEST_MESSAGE("Unsupported Test for Cassandra v" << version.to_string() << ": Skipping batch/invalid_batch_type"); + BOOST_REQUIRE(true); + } } BOOST_AUTO_TEST_CASE(counter_mixed) { - test_utils::CassBatchPtr batch(cass_batch_new(CASS_BATCH_TYPE_COUNTER)); - std::string update_query = str(boost::format("UPDATE %s SET test_val = test_val + ? WHERE tweet_id = ?;") % BatchTests::COUNTER_TABLE_NAME); - - test_utils::CassFuturePtr prepared_future(cass_session_prepare_n(session, - update_query.data(), update_query.size())); - test_utils::wait_and_check_error(prepared_future.get()); - test_utils::CassPreparedPtr prepared(cass_future_get_prepared(prepared_future.get())); - - for (int x = 0; x < 1000; x++) - { - test_utils::CassStatementPtr update_statement; - if (x % 2 == 0) { - update_statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); - } else { - update_statement = test_utils::CassStatementPtr(cass_statement_new(update_query.c_str(), 2)); + CassVersion version = test_utils::get_version(); + if (version.major != 1) { + BatchTests tester; + test_utils::CassBatchPtr batch(cass_batch_new(CASS_BATCH_TYPE_COUNTER)); + std::string update_query = str(boost::format("UPDATE %s SET test_val = test_val + ? WHERE tweet_id = ?;") % BatchTests::COUNTER_TABLE_NAME); + + test_utils::CassFuturePtr prepared_future(cass_session_prepare(tester.session, update_query.c_str())); + test_utils::wait_and_check_error(prepared_future.get()); + test_utils::CassPreparedPtr prepared(cass_future_get_prepared(prepared_future.get())); + + for (int x = 0; x < 1000; x++) + { + test_utils::CassStatementPtr update_statement; + if (x % 2 == 0) { + update_statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } else { + update_statement = test_utils::CassStatementPtr(cass_statement_new(update_query.c_str(), 2)); + } + cass_statement_set_consistency(update_statement.get(), CASS_CONSISTENCY_QUORUM); + BOOST_REQUIRE(cass_statement_bind_int64(update_statement.get(), 0, x) == CASS_OK); + BOOST_REQUIRE(cass_statement_bind_int32(update_statement.get(), 1, x) == CASS_OK); + cass_batch_add_statement(batch.get(), update_statement.get()); } - cass_statement_set_consistency(update_statement.get(), CASS_CONSISTENCY_QUORUM); - BOOST_REQUIRE(cass_statement_bind_int64(update_statement.get(), 0, x) == CASS_OK); - BOOST_REQUIRE(cass_statement_bind_int32(update_statement.get(), 1, x) == CASS_OK); - cass_batch_add_statement(batch.get(), update_statement.get()); - } - test_utils::CassFuturePtr update_future(cass_session_execute_batch(session, batch.get())); - test_utils::wait_and_check_error(update_future.get()); + test_utils::CassFuturePtr update_future(cass_session_execute_batch(tester.session, batch.get())); + test_utils::wait_and_check_error(update_future.get()); - std::string select_query = str(boost::format("SELECT * FROM %s;") % BatchTests::COUNTER_TABLE_NAME); + std::string select_query = str(boost::format("SELECT * FROM %s;") % BatchTests::COUNTER_TABLE_NAME); - test_utils::CassResultPtr result; + test_utils::CassResultPtr result; - test_utils::execute_query(session, select_query, &result, CASS_CONSISTENCY_QUORUM); + test_utils::execute_query(tester.session, select_query, &result, CASS_CONSISTENCY_QUORUM); - BOOST_REQUIRE(cass_result_row_count(result.get()) == 1000); - BOOST_REQUIRE(cass_result_column_count(result.get()) == 2); + BOOST_REQUIRE(cass_result_row_count(result.get()) == 1000); + BOOST_REQUIRE(cass_result_column_count(result.get()) == 2); - test_utils::CassIteratorPtr iterator(cass_iterator_from_result(result.get())); + test_utils::CassIteratorPtr iterator(cass_iterator_from_result(result.get())); - while (cass_iterator_next(iterator.get())) { - const CassValue* column1 = cass_row_get_column(cass_iterator_get_row(iterator.get()), 0); - BOOST_REQUIRE(cass_value_type(column1) == CASS_VALUE_TYPE_INT); - cass_int32_t tweet_id; - BOOST_REQUIRE(cass_value_get_int32(column1, &tweet_id) == CASS_OK); + while (cass_iterator_next(iterator.get())) { + const CassValue* column1 = cass_row_get_column(cass_iterator_get_row(iterator.get()), 0); + BOOST_REQUIRE(cass_value_type(column1) == CASS_VALUE_TYPE_INT); + cass_int32_t tweet_id; + BOOST_REQUIRE(cass_value_get_int32(column1, &tweet_id) == CASS_OK); - const CassValue* column2 = cass_row_get_column(cass_iterator_get_row(iterator.get()), 1); - BOOST_REQUIRE(cass_value_type(column2) == CASS_VALUE_TYPE_COUNTER); - cass_int64_t test_val; - BOOST_REQUIRE(cass_value_get_int64(column2, &test_val) == CASS_OK); + const CassValue* column2 = cass_row_get_column(cass_iterator_get_row(iterator.get()), 1); + BOOST_REQUIRE(cass_value_type(column2) == CASS_VALUE_TYPE_COUNTER); + cass_int64_t test_val; + BOOST_REQUIRE(cass_value_get_int64(column2, &test_val) == CASS_OK); - BOOST_REQUIRE(tweet_id == test_val); + BOOST_REQUIRE(tweet_id == test_val); + } + } else { + boost::unit_test::unit_test_log_t::instance().set_threshold_level(boost::unit_test::log_messages); + BOOST_TEST_MESSAGE("Unsupported Test for Cassandra v" << version.to_string() << ": Skipping batch/counter_mixed"); + BOOST_REQUIRE(true); } } diff --git a/test/integration_tests/src/test_by_name.cpp b/test/integration_tests/src/test_by_name.cpp index dcf89b3e4..24cc95440 100644 --- a/test/integration_tests/src/test_by_name.cpp +++ b/test/integration_tests/src/test_by_name.cpp @@ -39,13 +39,6 @@ struct ByNameTests : public test_utils::SingleSessionTest { test_utils::execute_query(session, "CREATE TABLE bytes_by_name (key uuid PRIMARY KEY, blobs blob, varints varint)"); } - test_utils::CassPreparedPtr prepare(const std::string& query) { - test_utils::CassFuturePtr prepared_future(cass_session_prepare_n(session, - query.data(), query.size())); - test_utils::wait_and_check_error(prepared_future.get()); - return test_utils::CassPreparedPtr(cass_future_get_prepared(prepared_future.get())); - } - test_utils::CassResultPtr select_all_from_by_name() { test_utils::CassResultPtr result; test_utils::execute_query(session, "SELECT * FROM by_name", &result); @@ -67,7 +60,7 @@ BOOST_FIXTURE_TEST_SUITE(by_name, ByNameTests) BOOST_AUTO_TEST_CASE(bind_and_get) { - test_utils::CassPreparedPtr prepared = prepare("INSERT INTO by_name (key, a, b, c) VALUES (?, ?, ?, ?)"); + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, "INSERT INTO by_name (key, a, b, c) VALUES (?, ?, ?, ?)"); test_utils::CassStatementPtr statement(cass_prepared_bind(prepared.get())); @@ -118,7 +111,7 @@ BOOST_AUTO_TEST_CASE(bind_and_get) BOOST_AUTO_TEST_CASE(bind_and_get_case_sensitive) { - test_utils::CassPreparedPtr prepared = prepare("INSERT INTO by_name (key, abc, \"ABC\", \"aBc\") VALUES (?, ?, ?, ?)"); + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, "INSERT INTO by_name (key, abc, \"ABC\", \"aBc\") VALUES (?, ?, ?, ?)"); test_utils::CassStatementPtr statement(cass_prepared_bind(prepared.get())); @@ -167,7 +160,7 @@ BOOST_AUTO_TEST_CASE(bind_and_get_case_sensitive) BOOST_AUTO_TEST_CASE(bind_multiple_columns) { - test_utils::CassPreparedPtr prepared = prepare("INSERT INTO by_name (key, abc, \"ABC\", \"aBc\") VALUES (?, ?, ?, ?)"); + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, "INSERT INTO by_name (key, abc, \"ABC\", \"aBc\") VALUES (?, ?, ?, ?)"); test_utils::CassStatementPtr statement(cass_prepared_bind(prepared.get())); @@ -224,7 +217,7 @@ BOOST_AUTO_TEST_CASE(bind_not_prepared) BOOST_AUTO_TEST_CASE(bind_invalid_name) { - test_utils::CassPreparedPtr prepared = prepare("INSERT INTO by_name (key, a, b, c, abc, \"ABC\", \"aBc\") VALUES (?, ?, ?, ?, ?, ?, ?)"); + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, "INSERT INTO by_name (key, a, b, c, abc, \"ABC\", \"aBc\") VALUES (?, ?, ?, ?, ?, ?, ?)"); test_utils::CassStatementPtr statement(cass_prepared_bind(prepared.get())); @@ -235,7 +228,15 @@ BOOST_AUTO_TEST_CASE(bind_invalid_name) BOOST_AUTO_TEST_CASE(get_invalid_name) { - test_utils::CassStatementPtr statement(cass_statement_new("INSERT INTO by_name (key, a) VALUES (?, ?)", 2)); + // Create insert statement for bound parameters + std::string insert_query = "INSERT INTO by_name (key, a) VALUES (?, ?)"; + test_utils::CassStatementPtr statement(cass_statement_new(insert_query.c_str(), 2)); + + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, insert_query.c_str()); + statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } CassUuid key = test_utils::generate_time_uuid(uuid_gen); @@ -256,7 +257,7 @@ BOOST_AUTO_TEST_CASE(get_invalid_name) BOOST_AUTO_TEST_CASE(null) { - test_utils::CassPreparedPtr prepared = prepare("INSERT INTO by_name (key, a, b, c, abc, \"ABC\", \"aBc\") VALUES (?, ?, ?, ?, ?, ?, ?)"); + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, "INSERT INTO by_name (key, a, b, c, abc, \"ABC\", \"aBc\") VALUES (?, ?, ?, ?, ?, ?, ?)"); test_utils::CassStatementPtr statement(cass_prepared_bind(prepared.get())); CassUuid key = test_utils::generate_time_uuid(uuid_gen); @@ -294,7 +295,7 @@ BOOST_AUTO_TEST_CASE(null) */ BOOST_AUTO_TEST_CASE(bind_bytes_by_name) { - test_utils::CassPreparedPtr prepared = prepare("INSERT INTO bytes_by_name (key, blobs, varints) VALUES (?, ?, ?)"); + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, "INSERT INTO bytes_by_name (key, blobs, varints) VALUES (?, ?, ?)"); test_utils::CassStatementPtr statement(cass_prepared_bind(prepared.get())); CassUuid key = test_utils::generate_time_uuid(uuid_gen); diff --git a/test/integration_tests/src/test_collections.cpp b/test/integration_tests/src/test_collections.cpp index cb36f59f5..101d78af7 100644 --- a/test/integration_tests/src/test_collections.cpp +++ b/test/integration_tests/src/test_collections.cpp @@ -39,19 +39,24 @@ struct CollectionsTests : public test_utils::MultipleNodesTest { std::string type_name = str(boost::format("%s<%s>") % test_utils::get_value_type(type) % test_utils::get_value_type(primary_type)); test_utils::execute_query(session, str(boost::format("CREATE TABLE %s (tweet_id int PRIMARY KEY, test_val %s);") - % table_name % type_name)); + % table_name % type_name)); test_utils::CassCollectionPtr input(cass_collection_new(static_cast(type), values.size())); for (typename std::vector::const_iterator it = values.begin(), - end = values.end(); it != end; ++it) { + end = values.end(); it != end; ++it) { test_utils::Value::append(input.get(), *it); } std::string query = str(boost::format("INSERT INTO %s (tweet_id, test_val) VALUES(0, ?);") % table_name); - test_utils::CassStatementPtr statement(cass_statement_new(query.c_str(), 1)); + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, query.c_str()); + statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } + BOOST_REQUIRE(cass_statement_bind_collection(statement.get(), 0, input.get()) == CASS_OK); test_utils::CassFuturePtr result_future(cass_session_execute(session, statement.get())); @@ -188,9 +193,14 @@ struct CollectionsTests : public test_utils::MultipleNodesTest { } std::string query = str(boost::format("INSERT INTO %s (tweet_id, test_val) VALUES(0, ?);") % table_name); - test_utils::CassStatementPtr statement(cass_statement_new(query.c_str(), 1)); + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, query.c_str()); + statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } + BOOST_REQUIRE(cass_statement_bind_collection(statement.get(), 0, input.get()) == CASS_OK); test_utils::CassFuturePtr result_future(cass_session_execute(session, statement.get())); diff --git a/test/integration_tests/src/test_outage.cpp b/test/integration_tests/src/test_outage.cpp index 55912cca5..067a64449 100644 --- a/test/integration_tests/src/test_outage.cpp +++ b/test/integration_tests/src/test_outage.cpp @@ -40,7 +40,6 @@ #include "cassandra.h" #include "test_utils.hpp" -#include "cql_ccm_bridge.hpp" #define TEST_DURATION_SECS 300 // 5 minutes #define NUM_NODES 3 @@ -60,7 +59,7 @@ struct OutageTests : public test_utils::MultipleNodesTest { : test_utils::MultipleNodesTest(NUM_NODES, 0) , is_done(false) , timer(io_service) { - test_utils::CassLog::set_output_log_level(CASS_LOG_DEBUG); + test_utils::CassLog::set_output_log_level(CASS_LOG_DISABLED); printf("Warning! This test is going to take %d minutes\n", TEST_DURATION_SECS / 60); std::fill(nodes_states, nodes_states + NUM_NODES, UP); // TODO(mpenick): This is a stopgap. To be fixed in CPP-140 @@ -133,7 +132,7 @@ struct OutageTests : public test_utils::MultipleNodesTest { if (--n == 0) { if (disableBinaryGossip) { if (random_int(1, 100) <= 50) { - ccm->binary(i, false); + ccm->gossip(i, false); nodes_states[i] = BINARY_DISABLED; } else { ccm->gossip(i, false); @@ -166,7 +165,7 @@ struct OutageTests : public test_utils::MultipleNodesTest { break; } else if (nodes_states[i] == BINARY_DISABLED) { nodes_states[i] = UP; - ccm->binary(i, true); + ccm->gossip(i, true); break; } } @@ -178,8 +177,13 @@ struct OutageTests : public test_utils::MultipleNodesTest { bool execute_insert(CassSession* session, const std::string& table_name) { std::string query = str(boost::format("INSERT INTO %s (id, event_time, text_sample) VALUES (?, ?, ?)") % table_name); + test_utils::CassStatementPtr statement(cass_statement_new(query.c_str(), 3)); - test_utils::CassStatementPtr statement(cass_statement_new_n(query.data(), query.size(), 3)); + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, query.c_str()); + statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } boost::chrono::system_clock::time_point now(boost::chrono::system_clock::now()); boost::chrono::milliseconds event_time(boost::chrono::duration_cast(now.time_since_epoch())); @@ -187,7 +191,7 @@ struct OutageTests : public test_utils::MultipleNodesTest { cass_statement_bind_uuid(statement.get(), 0, test_utils::generate_time_uuid(uuid_gen)); cass_statement_bind_int64(statement.get(), 1, event_time.count()); - cass_statement_bind_string_n(statement.get(), 2, text_sample.data(), text_sample.size()); + cass_statement_bind_string(statement.get(), 2, text_sample.c_str()); test_utils::CassFuturePtr future(cass_session_execute(session, statement.get())); cass_future_wait(future.get()); diff --git a/test/integration_tests/src/test_paging.cpp b/test/integration_tests/src/test_paging.cpp index f2850a9a7..51ee4cdf9 100644 --- a/test/integration_tests/src/test_paging.cpp +++ b/test/integration_tests/src/test_paging.cpp @@ -47,29 +47,35 @@ BOOST_AUTO_TEST_CASE(paging_simple) const int num_rows = 100; const int page_size = 5; - const char* insert_query = "INSERT INTO test (part, key, value) VALUES (?, ?, ?);"; + std::string insert_query = "INSERT INTO test (part, key, value) VALUES (?, ?, ?);"; + test_utils::CassStatementPtr statement(cass_statement_new(insert_query.c_str(), 3)); + + // Determine if bound parameters can be used based on C* version + if (version.major == 1) { + test_utils::CassPreparedPtr prepared = test_utils::prepare(session, insert_query.c_str()); + statement = test_utils::CassStatementPtr(cass_prepared_bind(prepared.get())); + } const cass_int32_t part_key = 0; for (int i = 0; i < num_rows; ++i) { - test_utils::CassStatementPtr statement(cass_statement_new(insert_query, 3)); cass_statement_bind_int32(statement.get(), 0, part_key); cass_statement_bind_uuid(statement.get(), 1, test_utils::generate_time_uuid(uuid_gen)); cass_statement_bind_int32(statement.get(), 2, i); test_utils::CassFuturePtr future(cass_session_execute(session, statement.get())); - BOOST_REQUIRE(cass_future_error_code(future.get()) == CASS_OK); + test_utils::wait_and_check_error(future.get()); } - const char* select_query = "SELECT value FROM test"; + std::string select_query = "SELECT value FROM test"; test_utils::CassResultPtr result; - test_utils::CassStatementPtr statement(cass_statement_new(select_query, 0)); + statement = test_utils::CassStatementPtr(cass_statement_new(select_query.c_str(), 0)); cass_statement_set_paging_size(statement.get(), page_size); cass_int32_t count = 0; do { test_utils::CassFuturePtr future(cass_session_execute(session, statement.get())); - BOOST_REQUIRE(cass_future_error_code(future.get()) == CASS_OK); + test_utils::wait_and_check_error(future.get()); result = test_utils::CassResultPtr(cass_future_get_result(future.get())); test_utils::CassIteratorPtr iterator(cass_iterator_from_result(result.get())); @@ -97,7 +103,7 @@ BOOST_AUTO_TEST_CASE(paging_empty) cass_statement_set_paging_size(statement.get(), page_size); test_utils::CassFuturePtr future(cass_session_execute(session, statement.get())); - BOOST_REQUIRE(cass_future_error_code(future.get()) == CASS_OK); + test_utils::wait_and_check_error(future.get()); test_utils::CassResultPtr result(cass_future_get_result(future.get())); BOOST_REQUIRE(cass_result_has_more_pages(result.get()) == cass_false); } diff --git a/test/integration_tests/src/test_prepared_outage.cpp b/test/integration_tests/src/test_prepared_outage.cpp index 87cfc0f95..a21416b2c 100644 --- a/test/integration_tests/src/test_prepared_outage.cpp +++ b/test/integration_tests/src/test_prepared_outage.cpp @@ -28,7 +28,6 @@ #include #include -#include "cql_ccm_bridge.hpp" #include "cassandra.h" #include "test_utils.hpp" @@ -113,13 +112,13 @@ BOOST_AUTO_TEST_CASE(reprepared_on_new_node) } ccm->gossip(1, true); - ccm->binary(2, false); - ccm->binary(1, false); + ccm->gossip(2, false); + ccm->gossip(1, false); //Ensure the binary protocol is disabled before executing the inserts boost::this_thread::sleep_for(boost::chrono::seconds(5)); test_utils::execute_query(session, str(boost::format(insert_query) % table_name % "123456789" % 20)); - ccm->binary(2, true); + ccm->gossip(2, true); for (int i = 0; i < 10; ++i) { diff --git a/test/integration_tests/src/test_schema_agreement.cpp b/test/integration_tests/src/test_schema_agreement.cpp index 2cb48ce39..39cabe147 100644 --- a/test/integration_tests/src/test_schema_agreement.cpp +++ b/test/integration_tests/src/test_schema_agreement.cpp @@ -20,7 +20,6 @@ #include "cassandra.h" #include "test_utils.hpp" -#include "cql_ccm_bridge.hpp" #include #include diff --git a/test/integration_tests/src/test_serial_consistency.cpp b/test/integration_tests/src/test_serial_consistency.cpp index 62b33cddc..2f98d455c 100644 --- a/test/integration_tests/src/test_serial_consistency.cpp +++ b/test/integration_tests/src/test_serial_consistency.cpp @@ -18,12 +18,12 @@ # define BOOST_TEST_MODULE cassandra #endif -#include "cql_ccm_bridge.hpp" #include "test_utils.hpp" #include "policy_tools.hpp" #include "cassandra.h" +#include #include #include #include @@ -36,45 +36,61 @@ struct SerialConsistencyTests : public test_utils::SingleSessionTest { test_utils::execute_query(session, str(boost::format("USE %s") % test_utils::SIMPLE_KEYSPACE)); test_utils::execute_query(session, "CREATE TABLE test (key text PRIMARY KEY, value int);"); } -}; -BOOST_FIXTURE_TEST_SUITE(serial_consistency, SerialConsistencyTests) + test_utils::CassFuturePtr insert_row(const std::string& key, int value, CassConsistency serial_consistency) { + std::string insert_query = "INSERT INTO test (key, value) VALUES (?, ?) IF NOT EXISTS"; -test_utils::CassFuturePtr insert_row(CassSession* session, const std::string& key, int value, CassConsistency serial_consistency) { - const char* insert_query = "INSERT INTO test (key, value) VALUES (?, ?) IF NOT EXISTS;"; + test_utils::CassStatementPtr statement(cass_statement_new(insert_query.c_str(), 2)); + cass_statement_bind_string(statement.get(), 0, key.c_str()); + cass_statement_bind_int32(statement.get(), 1, value); - test_utils::CassStatementPtr statement(cass_statement_new(insert_query, 2)); - cass_statement_bind_string_n(statement.get(), 0, key.data(), key.size()); - cass_statement_bind_int32(statement.get(), 1, value); + cass_statement_set_serial_consistency(statement.get(), serial_consistency); + return test_utils::CassFuturePtr(cass_session_execute(session, statement.get())); + } +}; - cass_statement_set_serial_consistency(statement.get(), serial_consistency); - return test_utils::CassFuturePtr(cass_session_execute(session, statement.get())); -} +BOOST_AUTO_TEST_SUITE(serial_consistency) BOOST_AUTO_TEST_CASE(simple) { - for (int i = 0; i < 2; ++i) { - test_utils::CassFuturePtr future = insert_row(session, "abc", 99, CASS_CONSISTENCY_SERIAL); - BOOST_REQUIRE(cass_future_error_code(future.get()) == CASS_OK); - test_utils::CassResultPtr result(cass_future_get_result(future.get())); - BOOST_REQUIRE(cass_result_row_count(result.get()) > 0); - const CassValue* value = cass_row_get_column(cass_result_first_row(result.get()), 0); - cass_bool_t applied; - cass_value_get_bool(value, &applied); - BOOST_REQUIRE_EQUAL(applied, i == 0 ? cass_true : cass_false); + CassVersion version = test_utils::get_version(); + if (version.major != 1) { + SerialConsistencyTests tester; + for (int i = 0; i < 2; ++i) { + test_utils::CassFuturePtr future = tester.insert_row("abc", 99, CASS_CONSISTENCY_SERIAL); + test_utils::wait_and_check_error(future.get()); + test_utils::CassResultPtr result(cass_future_get_result(future.get())); + BOOST_REQUIRE(cass_result_row_count(result.get()) > 0); + const CassValue* value = cass_row_get_column(cass_result_first_row(result.get()), 0); + cass_bool_t applied; + cass_value_get_bool(value, &applied); + BOOST_REQUIRE_EQUAL(applied, i == 0 ? cass_true : cass_false); + } + } else { + boost::unit_test::unit_test_log_t::instance().set_threshold_level(boost::unit_test::log_messages); + BOOST_TEST_MESSAGE("Unsupported Test for Cassandra v" << version.to_string() << ": Skipping serial_consistency/simple"); + BOOST_REQUIRE(true); } } BOOST_AUTO_TEST_CASE(invalid) { - test_utils::CassFuturePtr future = insert_row(session, "abc", 99, CASS_CONSISTENCY_ONE); // Invalid - - CassError code = cass_future_error_code(future.get()); - BOOST_REQUIRE_EQUAL(code, CASS_ERROR_SERVER_INVALID_QUERY); - - CassString message; - cass_future_error_message(future.get(), &message.data, &message.length); - BOOST_REQUIRE(strncmp(message.data, "Invalid consistency for conditional update. Must be one of SERIAL or LOCAL_SERIAL", message.length) == 0); + CassVersion version = test_utils::get_version(); + if (version.major != 1) { + SerialConsistencyTests tester; + test_utils::CassFuturePtr future = tester.insert_row("abc", 99, CASS_CONSISTENCY_ONE); // Invalid + + CassError code = cass_future_error_code(future.get()); + BOOST_REQUIRE_EQUAL(code, CASS_ERROR_SERVER_INVALID_QUERY); + + CassString message; + cass_future_error_message(future.get(), &message.data, &message.length); + BOOST_REQUIRE(strncmp(message.data, "Invalid consistency for conditional update. Must be one of SERIAL or LOCAL_SERIAL", message.length) == 0); + } else { + boost::unit_test::unit_test_log_t::instance().set_threshold_level(boost::unit_test::log_messages); + BOOST_TEST_MESSAGE("Unsupported Test for Cassandra v" << version.to_string() << ": Skipping serial_consistency/invalid"); + BOOST_REQUIRE(true); + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/integration_tests/src/test_stress.cpp b/test/integration_tests/src/test_stress.cpp index 5ec77ff4c..8d04049e2 100644 --- a/test/integration_tests/src/test_stress.cpp +++ b/test/integration_tests/src/test_stress.cpp @@ -36,7 +36,6 @@ #include "cassandra.h" #include "test_utils.hpp" -#include "cql_ccm_bridge.hpp" struct StressTests : public test_utils::MultipleNodesTest { CassSession* session; @@ -51,6 +50,21 @@ struct StressTests : public test_utils::MultipleNodesTest { cass_session_free(session); } + bool create_and_execute_insert(const std::string &query, CassConsistency consistency) { + CassUuid time_uuid = test_utils::generate_random_uuid(uuid_gen); + std::string time_uuid_string = test_utils::Value::to_string(time_uuid); + boost::chrono::system_clock::time_point now(boost::chrono::system_clock::now()); + boost::chrono::milliseconds event_time(boost::chrono::duration_cast(now.time_since_epoch())); + std::string text_sample("'" + test_utils::string_from_time_point(now) + "'"); + + std::string simple_query = test_utils::replaceAll(query, "?", "%s"); + simple_query = str(boost::format(simple_query) % time_uuid_string % event_time.count() % text_sample); + test_utils::CassStatementPtr statement(cass_statement_new(simple_query.c_str(), 0)); + cass_statement_set_consistency(statement.get(), consistency); + + return execute_insert(statement.get()); + } + bool bind_and_execute_insert(CassStatement* statement) { boost::chrono::system_clock::time_point now(boost::chrono::system_clock::now()); boost::chrono::milliseconds event_time(boost::chrono::duration_cast(now.time_since_epoch())); @@ -60,6 +74,10 @@ struct StressTests : public test_utils::MultipleNodesTest { cass_statement_bind_int64(statement, 1, event_time.count()); cass_statement_bind_string_n(statement, 2, text_sample.data(), text_sample.size()); + return execute_insert(statement); + } + + bool execute_insert(CassStatement* statement) { test_utils::CassFuturePtr future(cass_session_execute(session, statement)); cass_future_wait(future.get()); CassError code = cass_future_error_code(future.get()); @@ -76,10 +94,16 @@ struct StressTests : public test_utils::MultipleNodesTest { bool insert_task(const std::string& query, CassConsistency consistency, int rows_per_id) { bool is_successful = true; for (int i = 0; i < rows_per_id; ++i) { - test_utils::CassStatementPtr statement(cass_statement_new(query.c_str(), 3)); - cass_statement_set_consistency(statement.get(), consistency); - if (!bind_and_execute_insert(statement.get())) { - is_successful = false; + if (version.major == 1) { + if (!create_and_execute_insert(query, consistency)) { + is_successful = false; + } + } else { + test_utils::CassStatementPtr statement(cass_statement_new(query.c_str(), 3)); + cass_statement_set_consistency(statement.get(), consistency); + if (!bind_and_execute_insert(statement.get())) { + is_successful = false; + } } } return is_successful; diff --git a/test/integration_tests/src/test_utils.cpp b/test/integration_tests/src/test_utils.cpp index 3731e23bc..d5106a035 100644 --- a/test/integration_tests/src/test_utils.cpp +++ b/test/integration_tests/src/test_utils.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -123,6 +124,31 @@ const char* get_value_type(CassValueType type) { } } +std::string to_hex(const char *byte_array) { + std::stringstream value; + value << std::hex << std::setfill('0'); + for (unsigned int n = 0; n < strlen(byte_array); ++n) { + value << std::setw(2) << static_cast(byte_array[n]); + } + + if (value.str().size() == 0) { + value << "00"; + } + return value.str(); +} + +std::string replaceAll(const std::string& current, const std::string& search, const std::string& replace) { + // Go through each found occurrence and replace the value (in place) + std::string updated = current; + size_t found_position = 0; + while ((found_position = updated.find(search, found_position)) != std::string::npos) { + updated.replace(found_position, search.length(), replace); + found_position += replace.length(); + } + + return updated; +} + //----------------------------------------------------------------------------------- const std::string CREATE_KEYSPACE_SIMPLE_FORMAT = "CREATE KEYSPACE %s WITH replication = { 'class' : 'SimpleStrategy', 'replication_factor' : %s }"; const std::string CREATE_KEYSPACE_NETWORK_FORMAT = "CREATE KEYSPACE %s WITH replication = { 'class' : 'NetworkTopologyStrategy', 'dc1' : %d, 'dc2' : %d }"; @@ -148,11 +174,13 @@ const char ALPHA_NUMERIC[] = { "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJK //----------------------------------------------------------------------------------- +CassVersion MultipleNodesTest::version; + MultipleNodesTest::MultipleNodesTest(unsigned int num_nodes_dc1, unsigned int num_nodes_dc2, unsigned int protocol_version, bool isSSL /* = false */) : conf(cql::get_ccm_bridge_configuration()) { boost::debug::detect_memory_leaks(false); ccm = cql::cql_ccm_bridge_t::create_and_start(conf, "test", num_nodes_dc1, num_nodes_dc2, isSSL); - version = ccm->version(); + version.from_string(ccm->version().to_string()); uuid_gen = cass_uuid_gen_new(); cluster = cass_cluster_new(); @@ -192,6 +220,7 @@ SingleSessionTest::~SingleSessionTest() { if (session) { CassFuturePtr close_future(cass_session_close(session)); cass_future_wait(close_future.get()); + cass_session_free(session); } if (ssl) { cass_ssl_free(ssl); @@ -266,6 +295,12 @@ void wait_and_check_error(CassFuture* future, cass_duration_t timeout) { } } +test_utils::CassPreparedPtr prepare(CassSession* session, const std::string& query) { + test_utils::CassFuturePtr prepared_future(cass_session_prepare(session, query.c_str())); + test_utils::wait_and_check_error(prepared_future.get()); + return test_utils::CassPreparedPtr(cass_future_get_prepared(prepared_future.get())); +} + std::string string_from_time_point(boost::chrono::system_clock::time_point time) { std::time_t t = boost::chrono::system_clock::to_time_t(time); char buffer[26]; @@ -283,23 +318,30 @@ std::string string_from_uuid(CassUuid uuid) { return std::string(buffer); } -CassVersion get_version(CassSession* session) { - // Execute the version query - CassResultPtr result; - execute_query(session, SELECT_VERSION, &result); - - // Only one row should be returned; get the first row - const CassRow *row = cass_result_first_row(result.get()); - - // Convert the release_version value to a string - const CassValue* value = cass_row_get_column_by_name(row, "release_version"); - CassString version_string; - cass_value_get_string(value, &version_string.data, &version_string.length); +CassVersion get_version(CassSession* session /* = NULL */) { + // Determine if we should get the version from C* or the configuration file + std::string version_string; + if (session) { + // Execute the version query + CassResultPtr result; + execute_query(session, SELECT_VERSION, &result); + + // Only one row should be returned; get the first row + const CassRow *row = cass_result_first_row(result.get()); + + // Convert the release_version value to a string + CassString version_cass_string; + const CassValue* value = cass_row_get_column_by_name(row, "release_version"); + cass_value_get_string(value, &version_cass_string.data, &version_cass_string.length); + version_string = std::string(version_cass_string.data, version_cass_string.length); // Needed for null termination + } else { + // Get the version string from the configuration + const cql::cql_ccm_bridge_configuration_t& conf(cql::get_ccm_bridge_configuration()); + version_string = std::string(conf.cassandara_version()); + } - // Parse the version string and return the Cassandra version - CassVersion version; - std::string str(version_string.data, version_string.length); // Needed for null termination - sscanf(str.c_str(), "%hu.%hu.%hu-%s", &version.major, &version.minor, &version.patch, version.extra); + // Return the version information + CassVersion version(version_string); return version; } diff --git a/test/integration_tests/src/test_utils.hpp b/test/integration_tests/src/test_utils.hpp index 094eb8099..2716709ac 100644 --- a/test/integration_tests/src/test_utils.hpp +++ b/test/integration_tests/src/test_utils.hpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include @@ -29,6 +29,10 @@ #include #include +#include + +#include + #include "cassandra.h" #include "cql_ccm_bridge.hpp" @@ -150,6 +154,84 @@ class CassLog{ static LogData log_data_; }; +/** + * Simplified "Big Number" implementation for converting binary values + */ +class BigNumber { +private: + /** + * Decode a two's complement varint (e.g. Java BigInteger) byte array into its + * numerical value + * + * @param byte_array Two's complement varint byte array + * @return Numerical value of the varint + */ + static std::string decode_varint(const char *byte_array) { + std::string result; + // Assuming positive numbers only + //TODO: Add check for bit to return negative values + BIGNUM *value = BN_bin2bn(reinterpret_cast(byte_array), static_cast(strlen(byte_array)), NULL); + if (value) { + char * decimal = BN_bn2dec(value); + result = std::string(decimal); + delete decimal; + decimal = NULL; + + //Normalize - strip leading zeros + for (unsigned int n = 0; n < result.size(); ++n) { + if (result.at(n) == '0') { + result.replace(n, 1, ""); + } else { + break; + } + } + if (result.size() == 0) { + result = "0"; + } + } + + BN_free(value); + return result; + } + +public: + /** + * Convert a two's compliment byte array into a numerical string value + * + * @param byte_array Byte array to convert + * @return String representation of numerical value + */ + static std::string to_string(const char *byte_array) { + return decode_varint(byte_array); + } + /** + * Convert a CassBytes object into a numerical string value + * + * @param byte_array Byte array to convert + * @return String representation of numerical value + */ + static std::string to_string(CassBytes bytes) { + return to_string(std::string(reinterpret_cast(bytes.data), bytes.size).c_str()); + } + /** + * Convert a CassDecimal object into a numerical string value + * + * @param byte_array Byte array to convert + * @return String representation of numerical value + */ + static std::string to_string(CassDecimal decimal) { + std::string byte_array = std::string(reinterpret_cast(decimal.varint), decimal.varint_size); + std::string integer_value = decode_varint(byte_array.c_str()); + + //Ensure the decimal has scale + if (decimal.scale > 0) { + unsigned int period_position = integer_value.size() - decimal.scale; + return integer_value.substr(0, period_position) + "." + integer_value.substr(period_position); + } + return integer_value; + } +}; + template struct Deleter; @@ -289,6 +371,12 @@ struct Value { static cass_int32_t max_value() { return std::numeric_limits::max(); } + + static std::string to_string(cass_int32_t value) { + std::stringstream value_stream; + value_stream << value; + return value_stream.str(); + } }; template<> @@ -316,6 +404,12 @@ struct Value { static cass_int64_t max_value() { return std::numeric_limits::max(); } + + static std::string to_string(cass_int64_t value) { + std::stringstream value_stream; + value_stream << value; + return value_stream.str(); + } }; template<> @@ -343,6 +437,12 @@ struct Value { static cass_float_t max_value() { return std::numeric_limits::max(); } + + static std::string to_string(cass_float_t value) { + std::stringstream value_stream; + value_stream << std::setprecision(32) << value; + return value_stream.str(); + } }; template<> @@ -370,6 +470,12 @@ struct Value { static cass_double_t max_value() { return std::numeric_limits::max(); } + + static std::string to_string(cass_double_t value) { + std::stringstream value_stream; + value_stream << std::setprecision(32) << value; + return value_stream.str(); + } }; template<> @@ -389,6 +495,10 @@ struct Value { static bool equal(cass_bool_t a, cass_bool_t b) { return a == b; } + + static std::string to_string(cass_bool_t value) { + return value == cass_true ? "TRUE" : "FALSE"; + } }; template<> @@ -411,6 +521,10 @@ struct Value { } return strncmp(a.data, b.data, a.length) == 0; } + + static std::string to_string(CassString value) { + return std::string(value.data, value.length); + } }; template<> @@ -433,6 +547,10 @@ struct Value { } return memcmp(a.data, b.data, a.size) == 0; } + + static std::string to_string(CassBytes value) { + return std::string(reinterpret_cast(value.data), value.size); + } }; template<> @@ -469,6 +587,17 @@ struct Value { memset(value.address, 0xF, sizeof(value.address)); return value; } + + static std::string to_string(CassInet value) { + char buffer[INET6_ADDRSTRLEN]; + if (value.address_length == 4) { + uv_inet_ntop(AF_INET, value.address, buffer, sizeof(buffer)); + } else { + uv_inet_ntop(AF_INET6, value.address, buffer, sizeof(buffer)); + } + + return std::string(buffer); + } }; template<> @@ -503,6 +632,12 @@ struct Value { value.time_and_version = std::numeric_limits::max(); return value; } + + static std::string to_string(CassUuid value) { + char c_string[CASS_UUID_STRING_LENGTH]; + cass_uuid_string(value, c_string); + return std::string(c_string); + } }; template<> @@ -528,8 +663,16 @@ struct Value { } return memcmp(a.varint, b.varint, a.varint_size) == 0; } + + static std::string to_string(CassDecimal value) { + return test_utils::BigNumber::to_string(value); + } }; +/* + * TODO: Implement https://datastax-oss.atlassian.net/browse/CPP-244 to avoid + * current test skip implementation in batch and serial_consistency. + */ /** The following class cannot be used as a kernel of test fixture because of parametrized ctor. Derive from it to use it in your tests. */ @@ -538,7 +681,7 @@ struct MultipleNodesTest { virtual ~MultipleNodesTest(); boost::shared_ptr ccm; - CassVersion version; + static CassVersion version; const cql::cql_ccm_bridge_configuration_t& conf; CassUuidGen* uuid_gen; CassCluster* cluster; @@ -557,6 +700,24 @@ void initialize_contact_points(CassCluster* cluster, std::string prefix, unsigne const char* get_value_type(CassValueType type); +/** + * Convert a byte array to hex + * + * @param byte_array Byte array to convert + * @return Hex representation of the byte array + */ +std::string to_hex(const char *byte_array); + +/** + * Find and replace all occurrences of a string and replace with a new value + * + * @param current The string to replace all occurrences + * @param search The string to find + * @param replace The string to replace with + * @return Updated string + */ +std::string replaceAll(const std::string& current, const std::string& search, const std::string& replace); + CassSessionPtr create_session(CassCluster* cluster, cass_duration_t timeout = 60 * ONE_SECOND_IN_MICROS); CassSessionPtr create_session(CassCluster* cluster, CassError* code, cass_duration_t timeout = 60 * ONE_SECOND_IN_MICROS); @@ -575,6 +736,8 @@ void execute_query(CassSession* session, CassError wait_and_return_error(CassFuture* future, cass_duration_t timeout = 60 * ONE_SECOND_IN_MICROS); void wait_and_check_error(CassFuture* future, cass_duration_t timeout = 60 * ONE_SECOND_IN_MICROS); +test_utils::CassPreparedPtr prepare(CassSession* session, const std::string& query); + inline CassBytes bytes_from_string(const char* str) { return CassBytes(reinterpret_cast(str), strlen(str)); } @@ -609,12 +772,19 @@ inline std::string generate_unique_str(CassUuidGen* uuid_gen) { std::string string_from_time_point(boost::chrono::system_clock::time_point time); std::string string_from_uuid(CassUuid uuid); +inline std::string generate_random_uuid_str(CassUuidGen* uuid_gen) { + return string_from_uuid(generate_random_uuid(uuid_gen)); +} + /** - * Get the Cassandra version number from current session + * Get the Cassandra version number from current session or from the + * configuration file. * - * @param session Current connected session + * @param session Current connected session (default: NULL; get version from + * configuration file) + * @return Cassandra version from session or configuration file */ -CassVersion get_version(CassSession* session); +CassVersion get_version(CassSession* session = NULL); /* * Generate a random string of a certain size using alpha numeric characters diff --git a/test/integration_tests/src/test_version1.cpp b/test/integration_tests/src/test_version1.cpp index cfa012bdf..16350be97 100644 --- a/test/integration_tests/src/test_version1.cpp +++ b/test/integration_tests/src/test_version1.cpp @@ -170,7 +170,11 @@ BOOST_AUTO_TEST_CASE(query_param_error) CassString message; cass_future_error_message(future.get(), &message.data, &message.length); BOOST_REQUIRE(code == CASS_ERROR_SERVER_INVALID_QUERY); - BOOST_REQUIRE(std::string(message.data, message.length).find("Invalid amount of bind variables") != std::string::npos); + if (version.major == 1) { + BOOST_REQUIRE(std::string(message.data, message.length).find("Cannot execute query with bind variables") != std::string::npos); + } else { + BOOST_REQUIRE(std::string(message.data, message.length).find("Invalid amount of bind variables") != std::string::npos); + } } BOOST_AUTO_TEST_SUITE_END() From fc9c25a3db879894d40306642864413ef8f7d979 Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Mon, 27 Jul 2015 14:27:57 -0700 Subject: [PATCH 4/4] Updated links to API docs --- topics/README.md | 14 +++++++------- topics/basics/binding_parameters/README.md | 2 +- topics/basics/consistency/README.md | 2 +- topics/basics/handling_results/README.md | 8 ++++---- topics/basics/uuids/README.md | 6 +++--- topics/configuration/README.md | 2 +- topics/metrics/README.md | 4 ++-- topics/security/ssl/README.md | 6 +++--- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/topics/README.md b/topics/README.md index 31b465cf1..9ccaa3e53 100644 --- a/topics/README.md +++ b/topics/README.md @@ -36,19 +36,19 @@ int main() { } ``` -To connect a session, a [`CassCluster`](http://datastax.github.io/cpp-driver/api/struct_cass_cluster/) object will need to be created and configured. The minimal configuration needed to connect is a list of contact points. The contact points are used to initialize the driver and it will automatically discover the rest of the nodes in your cluster. +To connect a session, a [`CassCluster`](http://datastax.github.io/cpp-driver/api/CassCluster/) object will need to be created and configured. The minimal configuration needed to connect is a list of contact points. The contact points are used to initialize the driver and it will automatically discover the rest of the nodes in your cluster. **Perfomance Tip:** Include more than one contact point to be robust against node failures. ## Futures -The driver is designed so that no operation will force an application to block. Operations that would normally cause the application to block, such as connecting to a cluster or running a query, instead return a [`CassFuture`](http://datastax.github.io/cpp-driver/api/struct_cass_future/) object that can be waited on, polled, or used to register a callback. +The driver is designed so that no operation will force an application to block. Operations that would normally cause the application to block, such as connecting to a cluster or running a query, instead return a [`CassFuture`](http://datastax.github.io/cpp-driver/api/CassFuture/) object that can be waited on, polled, or used to register a callback. **NOTE:** The API can also be used synchronously by waiting on or immediately attempting to get the result from a future. ## Executing Queries -Queries are executed using [`CassStatement`](http://datastax.github.io/cpp-driver/api/struct_cass_statement/) objects. Statements encapsulate the query string and the query parameters. Query parameters are not supported by ealier versions of Cassandra (1.2 and below) and values need to be inlined in the query string itself. +Queries are executed using [`CassStatement`](http://datastax.github.io/cpp-driver/api/CassStatement/) objects. Statements encapsulate the query string and the query parameters. Query parameters are not supported by ealier versions of Cassandra (1.2 and below) and values need to be inlined in the query string itself. ```c /* Create a statement with zero parameters */ @@ -98,7 +98,7 @@ cass_future_free(query_future); ## Handling Query Results -A single row can be retrieved using the convenience function [`cass_result_first_row()`](TODO) to get the first row. A [`CassIterator`](http://datastax.github.io/cpp-driver/api/struct_cass_iterator/) object may also be used to iterate over the returned row(s). +A single row can be retrieved using the convenience function [`cass_result_first_row()`](TODO) to get the first row. A [`CassIterator`](http://datastax.github.io/cpp-driver/api/CassIterator/) object may also be used to iterate over the returned row(s). ```c /* Execute "SELECT * FROM example (key, value) WHERE key = 'abc'" */ @@ -138,11 +138,11 @@ cass_result_free(result); ## Cluster -The [`CassCluster`](http://datastax.github.io/cpp-driver/api/struct_cass_cluster/) object describes a Cassandra cluster’s configuration. The default cluster object is good for most clusters and only requires a single or multiple list of contact points in order to establish a session connection. Once a session is connected using a cluster object its configuration is constant. Modifying the cluster object configuration once a session is established does not alter the session's configuration. +The [`CassCluster`](http://datastax.github.io/cpp-driver/api/CassCluster/) object describes a Cassandra cluster’s configuration. The default cluster object is good for most clusters and only requires a single or multiple list of contact points in order to establish a session connection. Once a session is connected using a cluster object its configuration is constant. Modifying the cluster object configuration once a session is established does not alter the session's configuration. ## Session -The [`CassSession`](http://datastax.github.io/cpp-driver/api/struct_cass_session/) object is used for query execution. Internally, a session object also manages a pool of client connections to Cassandra and uses a load balancing policy to distribute requests across those connections. An application should create a single session object per keyspace as a session object is designed to be created once, reused, and shared by multiple threads within the application. The throughput of a session can be scaled by increasing the number of I/O threads. An I/O thread is used to handle reading and writing query request data to and from Cassandra. The number of I/O threads defaults to one per CPU core, but it can be configured using [`cass_cluster_set_num_threads_io()`](). It’s generally better to create a single session with more I/O threads than multiple sessions with a smaller number of I/O threads. More DataStax driver best practices can be found in this [post](http://www.datastax.com/dev/blog/4-simple-rules-when-using-the-datastax-drivers-for-cassandra). +The [`CassSession`](http://datastax.github.io/cpp-driver/api/CassSession/) object is used for query execution. Internally, a session object also manages a pool of client connections to Cassandra and uses a load balancing policy to distribute requests across those connections. An application should create a single session object per keyspace as a session object is designed to be created once, reused, and shared by multiple threads within the application. The throughput of a session can be scaled by increasing the number of I/O threads. An I/O thread is used to handle reading and writing query request data to and from Cassandra. The number of I/O threads defaults to one per CPU core, but it can be configured using [`cass_cluster_set_num_threads_io()`](). It’s generally better to create a single session with more I/O threads than multiple sessions with a smaller number of I/O threads. More DataStax driver best practices can be found in this [post](http://www.datastax.com/dev/blog/4-simple-rules-when-using-the-datastax-drivers-for-cassandra). ## Asynchronous I/O @@ -156,7 +156,7 @@ allows the driver to batch requests destined for the same node. ## Thread safety -A [`CassSession`](http://datastax.github.io/cpp-driver/api/struct_cass_session/) is designed to be used concurrently from multiple threads. [`CassFuture`](http://datastax.github.io/cpp-driver/api/struct_cass_future/) is also thread safe. Other than these exclusions, in general, functions that might modify an object's state are **NOT** thread safe. Object's that are immutable (marked 'const') can be read safely by multiple threads. +A [`CassSession`](http://datastax.github.io/cpp-driver/api/CassSession/) is designed to be used concurrently from multiple threads. [`CassFuture`](http://datastax.github.io/cpp-driver/api/CassFuture/) is also thread safe. Other than these exclusions, in general, functions that might modify an object's state are **NOT** thread safe. Object's that are immutable (marked 'const') can be read safely by multiple threads. **NOTE:** The object/resource free-ing functions (e.g. cass_cluster_free, cass_session_free, ... cass_*_free) cannot be called conncurently on the same instance of an object. diff --git a/topics/basics/binding_parameters/README.md b/topics/basics/binding_parameters/README.md index e7fee803f..6343ee721 100644 --- a/topics/basics/binding_parameters/README.md +++ b/topics/basics/binding_parameters/README.md @@ -51,7 +51,7 @@ cass_statement_bind_custom(statement, 1, 8 * 1024 * 1024, &bytes); ## Constructing Collections -Collections are supported using [`CassCollection`](http://datastax.github.io/cpp-driver/api/struct_cass_collection/) objects; supporting `list`, `map` and `set` Cassandra types. The code below shows how to construct a `list` collection; however, a set can be constructed in a very similiar way. The only difference is the type `CASS_COLLECTION_TYPE_SET` is used to create the collection instead of `CASS_COLLECTION_TYPE_LIST`. +Collections are supported using [`CassCollection`](http://datastax.github.io/cpp-driver/api/CassCollection/) objects; supporting `list`, `map` and `set` Cassandra types. The code below shows how to construct a `list` collection; however, a set can be constructed in a very similiar way. The only difference is the type `CASS_COLLECTION_TYPE_SET` is used to create the collection instead of `CASS_COLLECTION_TYPE_LIST`. **Important**: Values appended to the colleciton can be freed immediately afterward because the values are copied. diff --git a/topics/basics/consistency/README.md b/topics/basics/consistency/README.md index bb9a04179..38b7258d6 100644 --- a/topics/basics/consistency/README.md +++ b/topics/basics/consistency/README.md @@ -77,7 +77,7 @@ The consistency level determines the number of replicas on which the read/write ## Setting Consistency Level -A ['CassStatement'](http://datastax.github.io/cpp-driver/api/struct_cass_future/) object can have its consistency level altered at anytime before the statement is executed by the session. +A ['CassStatement'](http://datastax.github.io/cpp-driver/api/CassFuture/) object can have its consistency level altered at anytime before the statement is executed by the session. ```c /* Create a simple or prepared statment */ diff --git a/topics/basics/handling_results/README.md b/topics/basics/handling_results/README.md index fc9deadab..c3442b9fa 100644 --- a/topics/basics/handling_results/README.md +++ b/topics/basics/handling_results/README.md @@ -1,6 +1,6 @@ # Handling Results -The [`CassResult`](http://datastax.github.io/cpp-driver/api/struct_cass_result/) object is typically returned for `SELECT` statments. For mutations (`INSERT`, `UPDATE`, and `DELETE`) only a status code will be present and can be accessed using `cass_future_error_code()`. However, when using lightweight transactions a result object will be available to check the status of the transaction. The result object is obtained from executed statements' future object. +The [`CassResult`](http://datastax.github.io/cpp-driver/api/CassResult/) object is typically returned for `SELECT` statments. For mutations (`INSERT`, `UPDATE`, and `DELETE`) only a status code will be present and can be accessed using `cass_future_error_code()`. However, when using lightweight transactions a result object will be available to check the status of the transaction. The result object is obtained from executed statements' future object. **Important**: Rows, column values, collections, decimals, strings, and bytes objects are all invalidated when the result object is freed. All of these objects point to memory held by the result. This allows the driver to avoid unneccessarily copying data. @@ -16,7 +16,7 @@ cass_result_free(result); ## Rows and Column Values -The result object represents a collection of rows. The first row, if present, can be obtained using `cass_result_first_row()`. Multiple rows are accessed using a [`CassIterator`](http://datastax.github.io/cpp-driver/api/struct_cass_iterator/) object. After a row has been retrieved, the column value(s) can be accessed from a row by either index or by name. The iterator object can also be used with enumerated column values. +The result object represents a collection of rows. The first row, if present, can be obtained using `cass_result_first_row()`. Multiple rows are accessed using a [`CassIterator`](http://datastax.github.io/cpp-driver/api/CassResult/) object. After a row has been retrieved, the column value(s) can be accessed from a row by either index or by name. The iterator object can also be used with enumerated column values. ```c const CassRow* row = cass_result_first_row(result); @@ -32,7 +32,7 @@ const CassRow* row = cass_result_first_row(result); const CassValue* column1 = cass_row_get_column_by_name(row, "column1"); ``` -Once the [`CassValue`]((http://datastax.github.io/cpp-driver/api/struct_cass_value/)) has been obtained from the column, the actual value can be retrieved and assigned into the proper datatype. +Once the [`CassValue`]((http://datastax.github.io/cpp-driver/api/CassValue/)) has been obtained from the column, the actual value can be retrieved and assigned into the proper datatype. ```c cass_int32_t int_value; @@ -92,7 +92,7 @@ cass_iterator_free(iterator); ## Paging -When communicating with Cassandra 2.0 or later, large result sets can be divided into multiple pages automatically. The [`CassResult`](http://datastax.github.io/cpp-driver/api/struct_cass_result/) object keeps track of the pagination state for the sequence of paging queries. When paging through the result set, the result object is checked to see if more pages exist where it is then attached to the statement before re-executing the query to get the next page. +When communicating with Cassandra 2.0 or later, large result sets can be divided into multiple pages automatically. The [`CassResult`](http://datastax.github.io/cpp-driver/api/CassResult/) object keeps track of the pagination state for the sequence of paging queries. When paging through the result set, the result object is checked to see if more pages exist where it is then attached to the statement before re-executing the query to get the next page. ```c CassStatement* statement = cass_statement_new("SELECT * FROM table1", 0); diff --git a/topics/basics/uuids/README.md b/topics/basics/uuids/README.md index 7bbed6acc..4fbd52b06 100644 --- a/topics/basics/uuids/README.md +++ b/topics/basics/uuids/README.md @@ -1,7 +1,7 @@ # UUIDs UUIDs are 128-bit identifiers that can be used to uniquely identify information -without requiring central coordination. These are often used in Cassandra +without requiring central coordination. These are often used in Cassandra for primary and clustering keys. There are two types of UUIDs supported by the driver (and Cassandra), version 1 which is time-based and version 4 which is randomly generated. Version 1 can be used with Cassandra'a `timeuuid` type @@ -63,5 +63,5 @@ cass_uint8_t version = cass_uuid_version(uuid); char uuid_str[CASS_UUID_STRING_LENGTH]; cass_uuid_string(uuid, uuid_str); ``` -[`cass_uuid_timestamp()`]: http://datastax.github.io/cpp-driver/api/struct_cass_uuid/#1a3980467a0bb6642054ecf37d49aebf1a -[`CassUuidGen`]: http://datastax.github.io/cpp-driver/api/struct_cass_uuid_gen/ +[`cass_uuid_timestamp()`]: http://datastax.github.io/cpp-driver/api/CassUuid/#1a3980467a0bb6642054ecf37d49aebf1a +[`CassUuidGen`]: http://datastax.github.io/cpp-driver/api/CassUuidGen/ diff --git a/topics/configuration/README.md b/topics/configuration/README.md index 8b92d3126..89e39a86c 100644 --- a/topics/configuration/README.md +++ b/topics/configuration/README.md @@ -96,4 +96,4 @@ cass_cluster_set_latency_aware_routing_settings(cluster, min_measured); ``` -[`allow_remote_dcs_for_local_cl`]: http://datastax.github.io/cpp-driver/api/struct_cass_cluster/#1a46b9816129aaa5ab61a1363489dccfd0 +[`allow_remote_dcs_for_local_cl`]: http://datastax.github.io/cpp-driver/api/CassCluster/#1a46b9816129aaa5ab61a1363489dccfd0 diff --git a/topics/metrics/README.md b/topics/metrics/README.md index a89de2979..c854188cd 100644 --- a/topics/metrics/README.md +++ b/topics/metrics/README.md @@ -39,5 +39,5 @@ host. This can occur when too many requests are in-flight for a single host. Connection timeouts occur when the process of establishing new connections is unresponsive (default: 5 seconds). -[`cass_session_get_metrics()`]: http://datastax.github.io/cpp-driver/api/struct_cass_session/#1ab3773670c98c00290bad48a6df0f9eae -[`CassMetrics`]: http://datastax.github.io/cpp-driver/api/struct_cass_metrics/ +[`cass_session_get_metrics()`]: http://datastax.github.io/cpp-driver/api/CassSession/#1ab3773670c98c00290bad48a6df0f9eae +[`CassMetrics`]: http://datastax.github.io/cpp-driver/api/CassMetrics/ diff --git a/topics/security/ssl/README.md b/topics/security/ssl/README.md index abfca166f..2100325b1 100644 --- a/topics/security/ssl/README.md +++ b/topics/security/ssl/README.md @@ -58,7 +58,7 @@ The following [guide](http://www.datastax.com/documentation/cassandra/2.1/cassan ## Setting up the C/C++ Driver to Use SSL -A [`CassSsl`](http://datastax.github.io/cpp-driver/api/struct_cass_ssl/) object is required and must be configured: +A [`CassSsl`](http://datastax.github.io/cpp-driver/api/CassSsl/) object is required and must be configured: ```c #include @@ -67,7 +67,7 @@ void setup_ssl(CassCluster* cluster) { CassSsl* ssl = cass_ssl_new(); // Configure SSL object... - + // To enable SSL attach it to the cluster object cass_cluster_set_ssl(cluster, ssl); @@ -79,7 +79,7 @@ void setup_ssl(CassCluster* cluster) { #### Exporting and Loading the Cassandra Public Key -The default setting of the driver is to verify the certifcate sent during the SSL handshake. For the driver to properly verify the Cassandra certifcate the driver needs either the public key from the self-signed public key or the CA certificate chain used to sign the public key. To have this work, extract the public key from the Cassandra keystore generated in the previous steps. This exports a [PEM formatted](https://www.openssl.org/docs/crypto/pem.html#PEM_ENCRYPTION_FORMAT) certficate which is required by the C/C++ driver. +The default setting of the driver is to verify the certifcate sent during the SSL handshake. For the driver to properly verify the Cassandra certifcate the driver needs either the public key from the self-signed public key or the CA certificate chain used to sign the public key. To have this work, extract the public key from the Cassandra keystore generated in the previous steps. This exports a [PEM formatted](https://www.openssl.org/docs/crypto/pem.html#PEM_ENCRYPTION_FORMAT) certficate which is required by the C/C++ driver. ```bash keytool -exportcert -rfc -noprompt \