diff --git a/integration/CMakeLists.txt b/integration/CMakeLists.txt index 04e7a6f18..83e0d4b68 100644 --- a/integration/CMakeLists.txt +++ b/integration/CMakeLists.txt @@ -92,7 +92,10 @@ endif() enable_testing() set(TEST_SOURCES - connection_string_builder.cc + connection_string_builder.h + integration_test_utils.cc + integration_test_utils.h + base_failover_integration_test.cc connection_string_builder_test.cc) set(INTEGRATION_TESTS diff --git a/integration/base_failover_integration_test.cc b/integration/base_failover_integration_test.cc index e3a3eb345..e1b1bf25e 100644 --- a/integration/base_failover_integration_test.cc +++ b/integration/base_failover_integration_test.cc @@ -58,19 +58,8 @@ #include #include -#include "connection_string_builder.cc" - -#define MAX_NAME_LEN 4096 -#define SQL_MAX_MESSAGE_LENGTH 512 - -#define AS_SQLCHAR(str) const_cast(reinterpret_cast(str)) - -static int str_to_int(const char* str) { - const long int x = strtol(str, nullptr, 10); - assert(x <= INT_MAX); - assert(x >= INT_MIN); - return static_cast(x); -} +#include "connection_string_builder.h" +#include "integration_test_utils.h" static std::string DOWN_STREAM_STR = "DOWNSTREAM"; static std::string UP_STREAM_STR = "UPSTREAM"; @@ -97,8 +86,8 @@ class BaseFailoverIntegrationTest : public testing::Test { std::string PROXIED_CLUSTER_TEMPLATE = std::getenv("PROXIED_CLUSTER_TEMPLATE"); std::string DB_CONN_STR_SUFFIX = std::getenv("DB_CONN_STR_SUFFIX"); - int MYSQL_PORT = str_to_int(std::getenv("MYSQL_PORT")); - int MYSQL_PROXY_PORT = str_to_int(std::getenv("MYSQL_PROXY_PORT")); + int MYSQL_PORT = INTEGRATION_TEST_UTILS::str_to_int(std::getenv("MYSQL_PORT")); + int MYSQL_PROXY_PORT = INTEGRATION_TEST_UTILS::str_to_int(std::getenv("MYSQL_PROXY_PORT")); Aws::String cluster_id = MYSQL_CLUSTER_URL.substr(0, MYSQL_CLUSTER_URL.find('.')); static const int GLOBAL_FAILOVER_TIMEOUT = 120000; @@ -321,35 +310,6 @@ class BaseFailoverIntegrationTest : public testing::Test { return readers.at(distribution(generator)); } - static std::string host_to_IP(Aws::String hostname) { - int status; - struct addrinfo hints; - struct addrinfo *servinfo; - struct addrinfo *p; - char ipstr[INET_ADDRSTRLEN]; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; //IPv4 - hints.ai_socktype = SOCK_STREAM; - - if ((status = getaddrinfo(hostname.c_str(), NULL, &hints, &servinfo)) != 0) { - ADD_FAILURE() << "The IP address of host " << hostname << " could not be determined." - << "getaddrinfo error:" << gai_strerror(status); - return {}; - } - - for (p = servinfo; p != NULL; p = p->ai_next) { - void* addr; - - struct sockaddr_in* ipv4 = (struct sockaddr_in*)p->ai_addr; - addr = &(ipv4->sin_addr); - inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr)); - } - - freeaddrinfo(servinfo); - return std::string(ipstr); - } - static bool has_writer_changed(const Aws::RDS::RDSClient& client, const Aws::String& cluster_id, std::string initial_writer_id, std::chrono::nanoseconds timeout) { auto start = std::chrono::high_resolution_clock::now(); @@ -370,7 +330,7 @@ class BaseFailoverIntegrationTest : public testing::Test { const Aws::String& target_writer_id = "") { auto cluster_endpoint = get_DB_cluster(client, cluster_id).GetEndpoint(); - std::string initial_writer_ip = host_to_IP(cluster_endpoint); + std::string initial_writer_ip = INTEGRATION_TEST_UTILS::host_to_IP(cluster_endpoint); failover_cluster(client, cluster_id, target_writer_id); @@ -385,10 +345,10 @@ class BaseFailoverIntegrationTest : public testing::Test { } // Failover has finished, wait for DNS to be updated so cluster endpoint resolves to the correct writer instance. - std::string current_writer_ip = host_to_IP(cluster_endpoint); + std::string current_writer_ip = INTEGRATION_TEST_UTILS::host_to_IP(cluster_endpoint); while (initial_writer_ip == current_writer_ip) { std::this_thread::sleep_for(std::chrono::seconds(1)); - current_writer_ip = host_to_IP(cluster_endpoint); + current_writer_ip = INTEGRATION_TEST_UTILS::host_to_IP(cluster_endpoint); } // Wait for target instance to be verified as a writer diff --git a/integration/connection_string_builder.cc b/integration/connection_string_builder.h similarity index 99% rename from integration/connection_string_builder.cc rename to integration/connection_string_builder.h index 119209ea0..f1531a99f 100644 --- a/integration/connection_string_builder.cc +++ b/integration/connection_string_builder.h @@ -27,6 +27,9 @@ // along with this program. If not, see // http://www.gnu.org/licenses/gpl-2.0.html. +#ifndef __CONNECTIONSTRINGBUILDER_H__ +#define __CONNECTIONSTRINGBUILDER_H__ + #include #include #include @@ -467,3 +470,5 @@ class ConnectionStringBuilder { private: std::unique_ptr connection_string; }; + +#endif /* __CONNECTIONSTRINGBUILDER_H__ */ diff --git a/integration/connection_string_builder_test.cc b/integration/connection_string_builder_test.cc index 2470e6d32..ae8e3b125 100644 --- a/integration/connection_string_builder_test.cc +++ b/integration/connection_string_builder_test.cc @@ -29,7 +29,7 @@ #include -#include "connection_string_builder.cc" +#include "connection_string_builder.h" class ConnectionStringBuilderTest : public testing::Test { }; diff --git a/integration/iam_authentication_integration_test.cc b/integration/iam_authentication_integration_test.cc index 7a81a8f14..40f57d38b 100644 --- a/integration/iam_authentication_integration_test.cc +++ b/integration/iam_authentication_integration_test.cc @@ -28,53 +28,22 @@ // http://www.gnu.org/licenses/gpl-2.0.html. #include -#include #include #include -#include "connection_string_builder.cc" - -#define MAX_NAME_LEN 255 -#define AS_SQLCHAR(str) const_cast(reinterpret_cast(str)) +#include "connection_string_builder.h" +#include "integration_test_utils.h" // Connection string parameters static char* test_dsn; static char* test_db; static char* test_user; static char* test_pwd; +static unsigned int test_port; static char* iam_user; static std::string test_endpoint; -static std::string host_to_IP(std::string hostname) { - int status; - struct addrinfo hints; - struct addrinfo* servinfo; - struct addrinfo* p; - char ipstr[INET_ADDRSTRLEN]; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; //IPv4 - hints.ai_socktype = SOCK_STREAM; - - if ((status = getaddrinfo(hostname.c_str(), NULL, &hints, &servinfo)) != 0) { - ADD_FAILURE() << "The IP address of host " << hostname << " could not be determined." - << "getaddrinfo error:" << gai_strerror(status); - return {}; - } - - for (p = servinfo; p != NULL; p = p->ai_next) { - void* addr; - - struct sockaddr_in* ipv4 = (struct sockaddr_in*)p->ai_addr; - addr = &(ipv4->sin_addr); - inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr)); - } - - freeaddrinfo(servinfo); - return std::string(ipstr); -} - class IamAuthenticationIntegrationTest : public testing::Test { protected: ConnectionStringBuilder builder; @@ -88,7 +57,9 @@ class IamAuthenticationIntegrationTest : public testing::Test { test_db = std::getenv("TEST_DATABASE"); test_user = std::getenv("TEST_UID"); test_pwd = std::getenv("TEST_PASSWORD"); - iam_user = "john_doe"; + test_port = INTEGRATION_TEST_UTILS::str_to_int( + INTEGRATION_TEST_UTILS::get_env_var("MYSQL_PORT", "3306")); + iam_user = INTEGRATION_TEST_UTILS::get_env_var("IAM_USER", "john_doe"); auto conn_str_builder = ConnectionStringBuilder(); auto conn_str = conn_str_builder @@ -96,7 +67,7 @@ class IamAuthenticationIntegrationTest : public testing::Test { .withServer(test_endpoint) .withUID(test_user) .withPWD(test_pwd) - .withPort(3306) + .withPort(test_port) .withDatabase(test_db).build(); SQLHENV env1 = nullptr; @@ -117,12 +88,12 @@ class IamAuthenticationIntegrationTest : public testing::Test { char query_buffer[200]; sprintf(query_buffer, "DROP USER IF EXISTS %s;", iam_user); SQLExecDirect(stmt, AS_SQLCHAR(query_buffer), SQL_NTS); - memset(query_buffer, 0, sizeof(query_buffer)); + memset(query_buffer, 0, sizeof(query_buffer)); sprintf(query_buffer, "CREATE USER %s IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS';", iam_user); EXPECT_EQ(SQL_SUCCESS, SQLExecDirect(stmt, AS_SQLCHAR(query_buffer), SQL_NTS)); - memset(query_buffer, 0, sizeof(query_buffer)); + memset(query_buffer, 0, sizeof(query_buffer)); sprintf(query_buffer, "GRANT ALL ON `%`.* TO %s@`%`;", iam_user); EXPECT_EQ(SQL_SUCCESS, SQLExecDirect(stmt, AS_SQLCHAR(query_buffer), SQL_NTS)); @@ -175,8 +146,8 @@ TEST_F(IamAuthenticationIntegrationTest, SimpleIamConnection) { .withServer(test_endpoint) .withAuthHost(test_endpoint) .withUID(iam_user) - .withPort(3306) - .withAuthPort(3306).build(); + .withPort(test_port) + .withAuthPort(test_port).build(); SQLCHAR conn_out[4096] = "\0"; SQLSMALLINT len; @@ -194,8 +165,8 @@ TEST_F(IamAuthenticationIntegrationTest, ServerWithNoAuthHost) { auto connection_string = builder .withServer(test_endpoint) .withUID(iam_user) - .withPort(3306) - .withAuthPort(3306).build(); + .withPort(test_port) + .withAuthPort(test_port).build(); SQLCHAR conn_out[4096] = "\0"; SQLSMALLINT len; @@ -214,7 +185,7 @@ TEST_F(IamAuthenticationIntegrationTest, PortWithNoAuthPort) { .withServer(test_endpoint) .withAuthHost(test_endpoint) .withUID(iam_user) - .withPort(3306).build(); + .withPort(test_port).build(); SQLCHAR conn_out[4096] = "\0"; SQLSMALLINT len; @@ -229,13 +200,13 @@ TEST_F(IamAuthenticationIntegrationTest, PortWithNoAuthPort) { // Tests that IAM connection will still connect // when given an IP address instead of a cluster name. TEST_F(IamAuthenticationIntegrationTest, ConnectToIpAddress) { - auto ip_address = host_to_IP(test_endpoint); + auto ip_address = INTEGRATION_TEST_UTILS::host_to_IP(test_endpoint); auto connection_string = builder .withServer(ip_address) .withAuthHost(test_endpoint) .withUID(iam_user) - .withPort(3306).build(); + .withPort(test_port).build(); SQLCHAR conn_out[4096] = "\0"; SQLSMALLINT len; @@ -255,7 +226,7 @@ TEST_F(IamAuthenticationIntegrationTest, WrongPassword) { .withAuthHost(test_endpoint) .withUID(iam_user) .withPWD("WRONG_PASSWORD") - .withPort(3306).build(); + .withPort(test_port).build(); SQLCHAR conn_out[4096] = "\0"; SQLSMALLINT len; @@ -273,7 +244,7 @@ TEST_F(IamAuthenticationIntegrationTest, WrongUser) { .withServer(test_endpoint) .withAuthHost(test_endpoint) .withUID("WRONG_USER") - .withPort(3306).build(); + .withPort(test_port).build(); SQLCHAR conn_out[4096] = "\0"; SQLSMALLINT len; @@ -298,7 +269,7 @@ TEST_F(IamAuthenticationIntegrationTest, EmptyUser) { .withServer(test_endpoint) .withAuthHost(test_endpoint) .withUID("") - .withPort(3306).build(); + .withPort(test_port).build(); SQLCHAR conn_out[4096] = "\0"; SQLSMALLINT len; diff --git a/integration/integration_test_utils.cc b/integration/integration_test_utils.cc new file mode 100644 index 000000000..97ba895a7 --- /dev/null +++ b/integration/integration_test_utils.cc @@ -0,0 +1,77 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0 +// (GPLv2), as published by the Free Software Foundation, with the +// following additional permissions: +// +// This program is distributed with certain software that is licensed +// under separate terms, as designated in a particular file or component +// or in the license documentation. Without limiting your rights under +// the GPLv2, the authors of this program hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have included with the program. +// +// Without limiting the foregoing grant of rights under the GPLv2 and +// additional permission as to separately licensed software, this +// program is also subject to the Universal FOSS Exception, version 1.0, +// a copy of which can be found along with its FAQ at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see +// http://www.gnu.org/licenses/gpl-2.0.html. + +#include + +#include "integration_test_utils.h" + +char* INTEGRATION_TEST_UTILS::get_env_var(const char* key, char* default_value) { + char* value = std::getenv(key); + if (value == nullptr || value == "") { + return default_value; + } + + return value; +} + +int INTEGRATION_TEST_UTILS::str_to_int(const char* str) { + const long int x = strtol(str, nullptr, 10); + assert(x <= INT_MAX); + assert(x >= INT_MIN); + return static_cast(x); +} + +std::string INTEGRATION_TEST_UTILS::host_to_IP(std::string hostname) { + int status; + struct addrinfo hints; + struct addrinfo* servinfo; + struct addrinfo* p; + char ipstr[INET_ADDRSTRLEN]; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; //IPv4 + hints.ai_socktype = SOCK_STREAM; + + if ((status = getaddrinfo(hostname.c_str(), NULL, &hints, &servinfo)) != 0) { + ADD_FAILURE() << "The IP address of host " << hostname << " could not be determined." + << "getaddrinfo error:" << gai_strerror(status); + return {}; + } + + for (p = servinfo; p != NULL; p = p->ai_next) { + void* addr; + + struct sockaddr_in* ipv4 = (struct sockaddr_in*)p->ai_addr; + addr = &(ipv4->sin_addr); + inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr)); + } + + freeaddrinfo(servinfo); + return std::string(ipstr); +} diff --git a/integration/integration_test_utils.h b/integration/integration_test_utils.h new file mode 100644 index 000000000..7baddcf08 --- /dev/null +++ b/integration/integration_test_utils.h @@ -0,0 +1,47 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2.0 +// (GPLv2), as published by the Free Software Foundation, with the +// following additional permissions: +// +// This program is distributed with certain software that is licensed +// under separate terms, as designated in a particular file or component +// or in the license documentation. Without limiting your rights under +// the GPLv2, the authors of this program hereby grant you an additional +// permission to link the program and your derivative works with the +// separately licensed software that they have included with the program. +// +// Without limiting the foregoing grant of rights under the GPLv2 and +// additional permission as to separately licensed software, this +// program is also subject to the Universal FOSS Exception, version 1.0, +// a copy of which can be found along with its FAQ at +// http://oss.oracle.com/licenses/universal-foss-exception. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License, version 2.0, for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see +// http://www.gnu.org/licenses/gpl-2.0.html. + +#ifndef __INTEGRATIONTESTUTILS_H__ +#define __INTEGRATIONTESTUTILS_H__ + +#include + +#define MAX_NAME_LEN 4096 +#define SQL_MAX_MESSAGE_LENGTH 512 + +#define AS_SQLCHAR(str) const_cast(reinterpret_cast(str)) + +class INTEGRATION_TEST_UTILS { +public: + static char* get_env_var(const char* key, char* default_value); + static int str_to_int(const char* str); + static std::string host_to_IP(std::string hostname); +}; + +#endif /* __INTEGRATIONTESTUTILS_H__ */ diff --git a/integration/secrets_manager_integration_test.cc b/integration/secrets_manager_integration_test.cc index 3e60a847e..905480277 100644 --- a/integration/secrets_manager_integration_test.cc +++ b/integration/secrets_manager_integration_test.cc @@ -39,25 +39,16 @@ #include #include -#include "connection_string_builder.cc" - -#define MAX_NAME_LEN 255 - -#define AS_SQLCHAR(str) const_cast(reinterpret_cast(str)) - -static int str_to_int(const char* str) { - const long int x = strtol(str, nullptr, 10); - assert(x <= INT_MAX); - assert(x >= INT_MIN); - return static_cast(x); -} +#include "connection_string_builder.h" +#include "integration_test_utils.h" class SecretsManagerIntegrationTest : public testing::Test { protected: std::string SECRETS_ARN = std::getenv("SECRETS_ARN"); char* dsn = std::getenv("TEST_DSN"); - int MYSQL_PORT = str_to_int(std::getenv("MYSQL_PORT")); + int MYSQL_PORT = INTEGRATION_TEST_UTILS::str_to_int( + INTEGRATION_TEST_UTILS::get_env_var("MYSQL_PORT", "3306")); std::string MYSQL_CLUSTER_URL = std::getenv("TEST_SERVER");