Skip to content

Commit

Permalink
Refactor Integration Tests (#128)
Browse files Browse the repository at this point in the history
  • Loading branch information
justing-bq authored and yanw-bq committed May 17, 2023
1 parent 62a7c12 commit b89f642
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 110 deletions.
5 changes: 4 additions & 1 deletion integration/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
54 changes: 7 additions & 47 deletions integration/base_failover_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,8 @@
#include <arpa/inet.h>
#include <netinet/in.h>

#include "connection_string_builder.cc"

#define MAX_NAME_LEN 4096
#define SQL_MAX_MESSAGE_LENGTH 512

#define AS_SQLCHAR(str) const_cast<SQLCHAR*>(reinterpret_cast<const SQLCHAR*>(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<int>(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";
Expand All @@ -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;
Expand Down Expand Up @@ -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();

Expand All @@ -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);

Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <stdexcept>
#include <string>
#include <memory>
Expand Down Expand Up @@ -467,3 +470,5 @@ class ConnectionStringBuilder {
private:
std::unique_ptr<ConnectionString> connection_string;
};

#endif /* __CONNECTIONSTRINGBUILDER_H__ */
2 changes: 1 addition & 1 deletion integration/connection_string_builder_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

#include <gtest/gtest.h>

#include "connection_string_builder.cc"
#include "connection_string_builder.h"

class ConnectionStringBuilderTest : public testing::Test {
};
Expand Down
67 changes: 19 additions & 48 deletions integration/iam_authentication_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,53 +28,22 @@
// http://www.gnu.org/licenses/gpl-2.0.html.

#include <gtest/gtest.h>
#include <httplib.h>
#include <sql.h>
#include <sqlext.h>

#include "connection_string_builder.cc"

#define MAX_NAME_LEN 255
#define AS_SQLCHAR(str) const_cast<SQLCHAR*>(reinterpret_cast<const SQLCHAR*>(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;
Expand All @@ -88,15 +57,17 @@ 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
.withDSN(test_dsn)
.withServer(test_endpoint)
.withUID(test_user)
.withPWD(test_pwd)
.withPort(3306)
.withPort(test_port)
.withDatabase(test_db).build();

SQLHENV env1 = nullptr;
Expand All @@ -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));

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down
77 changes: 77 additions & 0 deletions integration/integration_test_utils.cc
Original file line number Diff line number Diff line change
@@ -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 <gtest/gtest.h>

#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<int>(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);
}
Loading

0 comments on commit b89f642

Please sign in to comment.