From 181472a1ffaec787cdc457aeec7bbd4906fa6e9d Mon Sep 17 00:00:00 2001 From: mikefero Date: Wed, 10 Jun 2015 12:33:56 -0400 Subject: [PATCH 1/3] 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/3] 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/3] 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()