blob: 28e83470b2772e9d517959bb1c042755bc960ff9 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "test_utils.hpp"
#include "exception.hpp"
#include "tsocket.hpp"
#include <uv.h>
#include <algorithm>
#include <fcntl.h>
#include <iomanip>
#include <sstream>
#ifndef _WIN32
#include <time.h>
#endif
#ifdef _WIN32
#define FILE_MODE 0
#else
#define FILE_MODE S_IRWXU | S_IRWXG | S_IROTH
#endif
#define FILE_PATH_SIZE 1024
#define TRIM_DELIMETERS " \f\n\r\t\v"
// Constant and static initialization
#ifdef _WIN32
const char test::Utils::PATH_SEPARATOR = '\\';
#else
const char test::Utils::PATH_SEPARATOR = '/';
#endif
template <typename T>
T* test::Utils::addressof(T& value) {
return reinterpret_cast<T*>(&const_cast<char&>(reinterpret_cast<const volatile char&>(value)));
}
bool test::Utils::contains(const std::string& input, const std::string& search) {
return input.find(search) != std::string::npos ? true : false;
}
std::string test::Utils::cwd() {
char cwd[FILE_PATH_SIZE] = { 0 };
size_t cwd_length = sizeof(cwd);
uv_cwd(cwd, &cwd_length);
return std::string(cwd, cwd_length);
}
std::string test::Utils::scalar_cql_type(CassValueType value_type) {
switch (value_type) {
case CASS_VALUE_TYPE_ASCII:
return "ascii";
break;
case CASS_VALUE_TYPE_BIGINT:
return "bigint";
break;
case CASS_VALUE_TYPE_BLOB:
return "blob";
break;
case CASS_VALUE_TYPE_BOOLEAN:
return "boolean";
break;
case CASS_VALUE_TYPE_COUNTER:
return "counter";
break;
case CASS_VALUE_TYPE_DECIMAL:
return "decimal";
break;
case CASS_VALUE_TYPE_DOUBLE:
return "double";
break;
case CASS_VALUE_TYPE_FLOAT:
return "float";
break;
case CASS_VALUE_TYPE_INT:
return "int";
break;
case CASS_VALUE_TYPE_TEXT:
return "text";
break;
case CASS_VALUE_TYPE_TIMESTAMP:
return "timestamp";
break;
case CASS_VALUE_TYPE_UUID:
return "uuid";
break;
case CASS_VALUE_TYPE_VARCHAR:
return "varchar";
break;
case CASS_VALUE_TYPE_VARINT:
return "varint";
break;
case CASS_VALUE_TYPE_TIMEUUID:
return "timeuuid";
break;
case CASS_VALUE_TYPE_INET:
return "inet";
break;
case CASS_VALUE_TYPE_DATE:
return "date";
break;
case CASS_VALUE_TYPE_TIME:
return "time";
break;
case CASS_VALUE_TYPE_SMALL_INT:
return "smallint";
break;
case CASS_VALUE_TYPE_TINY_INT:
return "tinyint";
break;
case CASS_VALUE_TYPE_DURATION:
return "duration";
break;
default:
std::stringstream message;
message << "Unable to Retrieve CQL Type: CassValueType [" << value_type << "] is not valid";
throw test::Exception(message.str());
}
}
std::vector<std::string> test::Utils::explode(const std::string& input,
const char delimiter /*= ' '*/) {
// Iterate over the input line and parse the tokens
std::vector<std::string> result;
std::istringstream parser(input);
for (std::string token; std::getline(parser, token, delimiter);) {
if (!token.empty()) {
result.push_back(trim(token));
}
}
return result;
}
bool test::Utils::file_exists(const std::string& filename) {
uv_fs_t request;
int error_code = uv_fs_stat(NULL, &request, filename.c_str(), NULL);
uv_fs_req_cleanup(&request);
return error_code == 0;
}
std::string test::Utils::indent(const std::string& input, unsigned int indent) {
std::stringstream output;
// Iterate over each line in the input string and indent
std::vector<std::string> lines = explode(input, '\n');
for (std::vector<std::string>::iterator iterator = lines.begin(); iterator < lines.end();
++iterator) {
output << std::setw(indent) << "" << *iterator;
if ((iterator + 1) != lines.end()) {
output << std::endl;
}
}
return output.str();
}
void test::Utils::mkdir(const std::string& path) {
// Create a synchronous libuv file system call to create the path
uv_loop_t loop;
uv_loop_init(&loop);
uv_fs_t request;
int error_code;
std::string error_message;
error_code = uv_fs_mkdir(&loop, &request, path.c_str(), FILE_MODE, NULL);
if (error_code != 0 && error_code != UV_EEXIST) {
error_message = uv_strerror(error_code);
}
uv_run(&loop, UV_RUN_DEFAULT);
uv_loop_close(&loop);
uv_fs_req_cleanup(&request);
// Determine if there was an issue creating the directory
if (!error_message.empty()) {
throw test::Exception("Unable to Create Directory: " + error_message);
}
}
void test::Utils::msleep(unsigned int milliseconds) {
#ifdef _WIN32
Sleep(milliseconds);
#else
// Convert the milliseconds into a proper timespec structure
struct timespec requested;
time_t seconds = static_cast<int>(milliseconds / 1000);
long int nanoseconds = static_cast<long int>((milliseconds - (seconds * 1000)) * 1000000);
// Assign the requested time and perform sleep
requested.tv_sec = seconds;
requested.tv_nsec = nanoseconds;
while (nanosleep(&requested, &requested) == -1) {
continue;
}
#endif
}
std::string test::Utils::replace_all(const std::string& input, const std::string& from,
const std::string& to) {
size_t position = 0;
std::string result = input;
while ((position = result.find(from, position)) != std::string::npos) {
result.replace(position, from.length(), to);
// Handle the case where 'to' is a substring of 'from'
position += to.length();
}
return result;
}
std::string test::Utils::shorten(const std::string& input,
bool add_space_after_newline /*= true*/) {
std::string result = input;
// Iterate over each trim delimiter
std::string delimiters = TRIM_DELIMETERS;
for (std::string::iterator iterator = delimiters.begin(); iterator < delimiters.end();
++iterator) {
// Replace the trim delimiter with empty string (space if EOL)
std::string delimiter(1, *iterator);
std::string newline_replacement = add_space_after_newline ? " " : "";
std::string replacement = delimiter.compare("\n") == 0 ? newline_replacement : "";
result = replace_all(result, delimiter, replacement);
}
// Return the single line string
return result;
}
std::string test::Utils::to_lower(const std::string& input) {
std::string lowercase = input;
std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(), ::tolower);
return lowercase;
}
std::string test::Utils::trim(const std::string& input) {
std::string result;
if (!input.empty()) {
// Trim right
result = input.substr(0, input.find_last_not_of(TRIM_DELIMETERS) + 1);
if (!result.empty()) {
// Trim left
result = result.substr(result.find_first_not_of(TRIM_DELIMETERS));
}
}
return result;
}
bool test::Utils::wait_for_port(const std::string& ip_address, unsigned short port,
unsigned int number_of_retries /*= 100*/,
unsigned int retry_delay_ms /*= 100*/) {
// Attempt establish a connection to the IP address and port of the node
for (unsigned int n = 0; n < number_of_retries; ++n) {
Socket socket;
try {
socket.establish_connection(ip_address, port);
return true;
} catch (...) {
msleep(retry_delay_ms);
}
}
// Unable to establish connection to node on port
return false;
}
std::string test::Utils::home_directory() {
char home[FILE_PATH_SIZE] = { 0 };
size_t home_length = sizeof(home);
uv_os_homedir(home, &home_length);
return std::string(home, home_length);
}
std::string test::Utils::temp_directory() {
char tmp[260] = { 0 }; // Note: 260 is the maximum path on Windows
size_t tmp_length = 260;
uv_os_tmpdir(tmp, &tmp_length);
return std::string(tmp, tmp_length);
}