use github repo as central

This commit is contained in:
Jackson Tian
2019-01-09 14:07:33 +08:00
parent 9664fb1b00
commit bc0df2dcec
46 changed files with 1864 additions and 29 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.vscode/

View File

@@ -1,12 +1,12 @@
#
# Copyright 2009-2017 Alibaba Cloud All rights reserved.
#
#
# Licensed 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.
@@ -14,6 +14,15 @@
# limitations under the License.
#
# coverage option
OPTION (ENABLE_COVERAGE "Use gcov" ON)
MESSAGE(STATUS ENABLE_COVERAGE=${ENABLE_COVERAGE})
IF(ENABLE_COVERAGE)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
# SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
ENDIF()
configure_file(src/Config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/include/alibabacloud/core/Config.h @ONLY)
set(core_public_header
@@ -120,7 +129,7 @@ set(core_src
src/sts/StsClient.cc
src/sts/StsRequest.cc
src/sts/model/AssumeRoleRequest.cc
src/sts/model/AssumeRoleResult.cc
src/sts/model/AssumeRoleResult.cc
src/sts/model/GetCallerIdentityRequest.cc
src/sts/model/GetCallerIdentityResult.cc
)

View File

@@ -1,12 +1,12 @@
/*
* Copyright 2009-2017 Alibaba Cloud All rights reserved.
*
*
* Licensed 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.

View File

@@ -1,12 +1,12 @@
/*
* Copyright 2009-2017 Alibaba Cloud All rights reserved.
*
*
* Licensed 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.
@@ -18,7 +18,7 @@
#include "Executor.h"
static AlibabaCloud::Executor * executor = nullptr;
void AlibabaCloud::InitializeSdk()
{
if (IsSdkInitialized())
@@ -37,7 +37,7 @@ void AlibabaCloud::ShutdownSdk()
{
if (!IsSdkInitialized())
return;
executor->shutdown();
delete executor;
executor = nullptr;

View File

@@ -106,7 +106,7 @@ void Executor::shutdown()
{
if (isShutdown())
return;
{
std::lock_guard<std::mutex> locker(tasksQueueMutex_);
while (tasksQueue_.size() > 0) {

View File

@@ -1,12 +1,12 @@
/*
* Copyright 2009-2017 Alibaba Cloud All rights reserved.
*
*
* Licensed 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.
@@ -99,7 +99,7 @@ HttpMessage::HeaderValueType HttpMessage::header(const HeaderNameType & name) co
auto it = headers_.find(name);
if (it != headers_.end())
return it->second;
else
else
return std::string();
}
@@ -161,8 +161,9 @@ void HttpMessage::setBody(const char *data, size_t size)
bodySize_ = 0;
if (size) {
bodySize_ = size;
body_ = new char[size];
body_ = new char[size + 1];
std::copy(data, data + size, body_);
body_[size] = '\0';
}
}

View File

@@ -77,7 +77,7 @@ void StsAssumeRoleCredentialsProvider::loadCredentials()
std::tm tm = {};
#if defined(__GNUG__) && __GNUC__ < 5
strptime(stsCredentials.expiration.c_str(), "%Y-%m-%dT%H:%M:%SZ", &tm);
#else
#else
std::stringstream ss(stsCredentials.expiration);
ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%SZ");
#endif

View File

@@ -1,12 +1,12 @@
/*
* Copyright 2009-2017 Alibaba Cloud All rights reserved.
*
*
* Licensed 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.
@@ -45,7 +45,7 @@ std::string AlibabaCloud::GenerateUuid()
std::string AlibabaCloud::UrlEncode(const std::string & src)
{
CURL *curl = curl_easy_init();
CURL *curl = curl_easy_init();
char *output = curl_easy_escape(curl, src.c_str(), src.size());
std::string result(output);
curl_free(output);
@@ -89,7 +89,7 @@ std::string AlibabaCloud::ComputeContentMD5(const char * data, size_t size)
#else
unsigned char md[MD5_DIGEST_LENGTH];
MD5(reinterpret_cast<const unsigned char*>(data), size, (unsigned char*)&md);
char encodedData[100];
EVP_EncodeBlock(reinterpret_cast<unsigned char*>(encodedData), md, MD5_DIGEST_LENGTH);
return encodedData;
@@ -99,10 +99,10 @@ std::string AlibabaCloud::ComputeContentMD5(const char * data, size_t size)
void AlibabaCloud::StringReplace(std::string & src, const std::string & s1, const std::string & s2)
{
std::string::size_type pos =0;
while ((pos = src.find(s1, pos)) != std::string::npos)
while ((pos = src.find(s1, pos)) != std::string::npos)
{
src.replace(pos, s1.length(), s2);
pos += s2.length();
pos += s2.length();
}
}

View File

@@ -1,12 +1,12 @@
/*
* Copyright 2009-2017 Alibaba Cloud All rights reserved.
*
*
* Licensed 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.

24
test-coverage.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
action=$1
if [ $action == "init" ]; then
echo 'init coverage'
lcov -d sdk_build -z
lcov -d sdk_build -b . --no-external --initial -c -o initCoverage.info
fi
echo 'run test'
cd sdk_build
ctest
cd ..
echo 'create info after test'
lcov -d sdk_build -b . --no-external -c -o testCoverage.info
echo 'generate html'
genhtml -o coverageReport --prefix=`pwd` initCoverage.info testCoverage.info
echo 'check report ' `pwd`/coverageReport/index.html

69
test/core/CMakeLists.txt Normal file
View File

@@ -0,0 +1,69 @@
cmake_minimum_required(VERSION 2.8.2)
set(CMAKE_CXX_STANDARD 11)
include(CTest)
if (CMAKE_VERSION VERSION_LESS 3.2)
set(UPDATE_DISCONNECTED_IF_AVAILABLE "")
else()
set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1")
endif()
include(DownloadProject.cmake)
download_project(PROJ googletest
PREFIX CMAKE_SOURCE_DIR/test/googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
${UPDATE_DISCONNECTED_IF_AVAILABLE}
)
# Prevent GoogleTest from overriding our compiler/linker options
# when building with Visual Studio
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
# When using CMake 2.8.11 or later, header path dependencies
# are automatically added to the gtest and gmock targets.
# For earlier CMake versions, we have to explicitly add the
# required directories to the header search path ourselves.
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include"
"${gmock_SOURCE_DIR}/include")
endif()
include_directories("../../core/include/")
add_executable(core_ut
alibabacloud_ut.cc
asynccallercontext_ut.cc
clientconfiguration_ut.cc
commonrequest_ut.cc
commonresponse_ut.cc
credentials_ut.cc
curlhttpclient_ut.cc
endpointprovider_ut.cc
error_ut.cc
executor_ut.cc
httprequest_ut.cc
httpresponse_ut.cc
httpmessage_ut.cc
hmacsha1signer_ut.cc
networkproxy_ut.cc
roaservicerequest_ut.cc
rpcservicerequest_ut.cc
runnable_ut.cc
serviceresult_ut.cc
servicerequest_ut.cc
simplecredentialsprovider_ut.cc
url_ut.cc
utils_ut.cc)
set_target_properties(core_ut
PROPERTIES
OUTPUT_NAME ${TARGET_OUTPUT_NAME_PREFIX}core_ut
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
target_link_libraries(core_ut core gtest gmock_main)
add_test(NAME core_ut COMMAND core_ut)

View File

@@ -0,0 +1,17 @@
# Distributed under the OSI-approved MIT License. See accompanying
# file LICENSE or https://github.com/Crascit/DownloadProject for details.
cmake_minimum_required(VERSION 2.8.2)
project(${DL_ARGS_PROJ}-download NONE)
include(ExternalProject)
ExternalProject_Add(${DL_ARGS_PROJ}-download
${DL_ARGS_UNPARSED_ARGUMENTS}
SOURCE_DIR "${DL_ARGS_SOURCE_DIR}"
BINARY_DIR "${DL_ARGS_BINARY_DIR}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

View File

@@ -0,0 +1,182 @@
# Distributed under the OSI-approved MIT License. See accompanying
# file LICENSE or https://github.com/Crascit/DownloadProject for details.
#
# MODULE: DownloadProject
#
# PROVIDES:
# download_project( PROJ projectName
# [PREFIX prefixDir]
# [DOWNLOAD_DIR downloadDir]
# [SOURCE_DIR srcDir]
# [BINARY_DIR binDir]
# [QUIET]
# ...
# )
#
# Provides the ability to download and unpack a tarball, zip file, git repository,
# etc. at configure time (i.e. when the cmake command is run). How the downloaded
# and unpacked contents are used is up to the caller, but the motivating case is
# to download source code which can then be included directly in the build with
# add_subdirectory() after the call to download_project(). Source and build
# directories are set up with this in mind.
#
# The PROJ argument is required. The projectName value will be used to construct
# the following variables upon exit (obviously replace projectName with its actual
# value):
#
# projectName_SOURCE_DIR
# projectName_BINARY_DIR
#
# The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically
# need to be provided. They can be specified if you want the downloaded source
# and build directories to be located in a specific place. The contents of
# projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the
# locations used whether you provide SOURCE_DIR/BINARY_DIR or not.
#
# The DOWNLOAD_DIR argument does not normally need to be set. It controls the
# location of the temporary CMake build used to perform the download.
#
# The PREFIX argument can be provided to change the base location of the default
# values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments
# are provided, then PREFIX will have no effect. The default value for PREFIX is
# CMAKE_BINARY_DIR.
#
# The QUIET option can be given if you do not want to show the output associated
# with downloading the specified project.
#
# In addition to the above, any other options are passed through unmodified to
# ExternalProject_Add() to perform the actual download, patch and update steps.
# The following ExternalProject_Add() options are explicitly prohibited (they
# are reserved for use by the download_project() command):
#
# CONFIGURE_COMMAND
# BUILD_COMMAND
# INSTALL_COMMAND
# TEST_COMMAND
#
# Only those ExternalProject_Add() arguments which relate to downloading, patching
# and updating of the project sources are intended to be used. Also note that at
# least one set of download-related arguments are required.
#
# If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to
# prevent a check at the remote end for changes every time CMake is run
# after the first successful download. See the documentation of the ExternalProject
# module for more information. It is likely you will want to use this option if it
# is available to you. Note, however, that the ExternalProject implementation contains
# bugs which result in incorrect handling of the UPDATE_DISCONNECTED option when
# using the URL download method or when specifying a SOURCE_DIR with no download
# method. Fixes for these have been created, the last of which is scheduled for
# inclusion in CMake 3.8.0. Details can be found here:
#
# https://gitlab.kitware.com/cmake/cmake/commit/bdca68388bd57f8302d3c1d83d691034b7ffa70c
# https://gitlab.kitware.com/cmake/cmake/issues/16428
#
# If you experience build errors related to the update step, consider avoiding
# the use of UPDATE_DISCONNECTED.
#
# EXAMPLE USAGE:
#
# include(DownloadProject)
# download_project(PROJ googletest
# GIT_REPOSITORY https://github.com/google/googletest.git
# GIT_TAG master
# UPDATE_DISCONNECTED 1
# QUIET
# )
#
# add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
#
#========================================================================================
set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}")
include(CMakeParseArguments)
function(download_project)
set(options QUIET)
set(oneValueArgs
PROJ
PREFIX
DOWNLOAD_DIR
SOURCE_DIR
BINARY_DIR
# Prevent the following from being passed through
CONFIGURE_COMMAND
BUILD_COMMAND
INSTALL_COMMAND
TEST_COMMAND
)
set(multiValueArgs "")
cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# Hide output if requested
if (DL_ARGS_QUIET)
set(OUTPUT_QUIET "OUTPUT_QUIET")
else()
unset(OUTPUT_QUIET)
message(STATUS "Downloading/updating ${DL_ARGS_PROJ}")
endif()
# Set up where we will put our temporary CMakeLists.txt file and also
# the base point below which the default source and binary dirs will be.
# The prefix must always be an absolute path.
if (NOT DL_ARGS_PREFIX)
set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}")
else()
get_filename_component(DL_ARGS_PREFIX "${DL_ARGS_PREFIX}" ABSOLUTE
BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if (NOT DL_ARGS_DOWNLOAD_DIR)
set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download")
endif()
# Ensure the caller can know where to find the source and build directories
if (NOT DL_ARGS_SOURCE_DIR)
set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src")
endif()
if (NOT DL_ARGS_BINARY_DIR)
set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build")
endif()
set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE)
set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE)
# The way that CLion manages multiple configurations, it causes a copy of
# the CMakeCache.txt to be copied across due to it not expecting there to
# be a project within a project. This causes the hard-coded paths in the
# cache to be copied and builds to fail. To mitigate this, we simply
# remove the cache if it exists before we configure the new project. It
# is safe to do so because it will be re-generated. Since this is only
# executed at the configure step, it should not cause additional builds or
# downloads.
file(REMOVE "${DL_ARGS_DOWNLOAD_DIR}/CMakeCache.txt")
# Create and build a separate CMake project to carry out the download.
# If we've already previously done these steps, they will not cause
# anything to be updated, so extra rebuilds of the project won't occur.
# Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project
# has this set to something not findable on the PATH.
configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in"
"${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt")
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}"
-D "CMAKE_MAKE_PROGRAM:FILE=${CMAKE_MAKE_PROGRAM}"
.
RESULT_VARIABLE result
${OUTPUT_QUIET}
WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}"
)
if(result)
message(FATAL_ERROR "CMake step for ${DL_ARGS_PROJ} failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
${OUTPUT_QUIET}
WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}"
)
if(result)
message(FATAL_ERROR "Build step for ${DL_ARGS_PROJ} failed: ${result}")
endif()
endfunction()

View File

@@ -0,0 +1,18 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/AlibabaCloud.h"
using namespace std;
using namespace AlibabaCloud;
TEST(AlibabaCloudTest, basic) {
InitializeSdk();
EXPECT_TRUE(IsSdkInitialized() == true);
InitializeSdk();
EXPECT_TRUE(IsSdkInitialized() == true);
ShutdownSdk();
EXPECT_TRUE(IsSdkInitialized() == false);
ShutdownSdk();
EXPECT_TRUE(IsSdkInitialized() == false);
}

View File

@@ -0,0 +1,18 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/AsyncCallerContext.h"
using namespace std;
using namespace AlibabaCloud;
TEST(AsyncCallerContext, basic) {
const std::string sys_generated_uuid = "643ce9ff-32b5-444c-814a-153b87a6aca8";
const std::string init_uuid = "init_uuid_for_test";
const std::string new_uuid = "new_uuid_for_test";
AsyncCallerContext context(init_uuid);
EXPECT_TRUE(context.uuid() == init_uuid);
context.setUuid(new_uuid);
EXPECT_TRUE(context.uuid() == new_uuid);
AsyncCallerContext context_from_GenerateUuid = AsyncCallerContext();
EXPECT_TRUE(context_from_GenerateUuid.uuid().length() == sys_generated_uuid.length());
}

View File

@@ -0,0 +1,31 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/ClientConfiguration.h"
using namespace std;
using namespace AlibabaCloud;
TEST(ClientConfiguration, basic) {
const std::string regionId = "cn-shanghai";
const std::string regionId_new = "cn-beijing";
const std::string endpoint = "ep-cn-shanghai";
const std::string hostname = "hostname";
const std::string user = "user";
const std::string password = "password";
uint16_t port = 12345;
const NetworkProxy proxy(NetworkProxy::Http, hostname, port, user, password);
ClientConfiguration config(regionId);
EXPECT_TRUE(config.regionId() == regionId);
config.setEndpoint(endpoint);
config.setProxy(proxy);
config.setRegionId(regionId_new);
EXPECT_TRUE(config.endpoint() == endpoint);
EXPECT_TRUE(config.regionId() == regionId_new);
EXPECT_TRUE(config.proxy().hostName() == hostname);
EXPECT_TRUE(config.proxy().port() == port);
EXPECT_TRUE(config.proxy().user() == user);
EXPECT_TRUE(config.proxy().password() == password);
}

View File

@@ -0,0 +1,22 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/CommonRequest.h"
using namespace std;
using namespace AlibabaCloud;
TEST(CommonRequest, basic) {
CommonRequest cr;
cr.setDomain("testDomain");
cr.setHeaderParameter("name1", "value1");
cr.setHttpMethod(HttpRequest::Method::Get);
cr.setQueryParameter("name2", "value2");
cr.setRequestPattern(CommonRequest::RequestPattern::RpcPattern);
EXPECT_TRUE(cr.domain() == "testDomain");
EXPECT_TRUE(cr.httpMethod() == HttpRequest::Method::Get);
EXPECT_TRUE(cr.requestPattern() == CommonRequest::RequestPattern::RpcPattern);
EXPECT_TRUE(cr.headerParameter("name1") == "value1");
EXPECT_TRUE(cr.queryParameter("name2") == "value2");
EXPECT_TRUE(cr.queryParameters()["name2"] == "value2");
EXPECT_TRUE(cr.headerParameters()["name1"] == "value1");
}

View File

@@ -0,0 +1,14 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/CommonResponse.h"
using namespace std;
using namespace AlibabaCloud;
TEST(CommonResponse, basic) {
CommonResponse cres("test_payload_");
EXPECT_TRUE(cres.payload() == "test_payload_");
CommonResponse cres1;
EXPECT_TRUE(cres1.payload() == "");
}

View File

@@ -0,0 +1,28 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/Credentials.h"
using namespace std;
using namespace AlibabaCloud;
TEST(CredentialsTest, basic) {
const string access_key = "accessKeyId";
const string access_secret = "accessKeySecret";
const string session_token = "sessionToken";
const string new_access_key = "new_accessKeyId";
const string new_access_secret = "new_accessKeySecret";
const string new_session_token = "new_sessionToken";
Credentials credentials(access_key, access_secret, session_token);
EXPECT_TRUE(credentials.accessKeyId() == access_key);
EXPECT_TRUE(credentials.accessKeySecret() == access_secret);
EXPECT_TRUE(credentials.sessionToken() == session_token);
credentials.setAccessKeyId(new_access_key);
credentials.setAccessKeySecret(new_access_secret);
credentials.setSessionToken(new_session_token);
EXPECT_TRUE(credentials.accessKeyId() == new_access_key);
EXPECT_TRUE(credentials.accessKeySecret() == new_access_secret);
EXPECT_TRUE(credentials.sessionToken() == new_session_token);
}

View File

@@ -0,0 +1,145 @@
#include <iostream>
#include <stdio.h>
#include "utils.h"
#include "../include/gtest/gtest.h"
#include "../include/gmock/gmock.h"
#include "../../core/include/alibabacloud/core/Url.h"
#include "../../core/include/alibabacloud/core/HttpRequest.h"
#include "../../core/include/alibabacloud/core/HttpClient.h"
#include "../../core/src/CurlHttpClient.h"
using namespace std;
using ::testing::Return;
using ::testing::DoAll;
using ::testing::SetArgReferee;
using ::testing::ReturnPointee;
using ::testing::_;
using ::testing::NiceMock;
using ::testing::DefaultValue;
using namespace AlibabaCloud;
using namespace std;
class mockCurlHttpClient : public CurlHttpClient {
public:
MOCK_METHOD1(makeRequest, HttpResponseOutcome (const HttpRequest &request));
};
// httpserver_for_ut port "echo text"
// default port 8021
// default text test/httpserver/index.html
TEST(CurlHttpClient, basic) {
CurlHttpClient client;
HttpRequest request;
utUtils utils;
char dir[1024];
utils.get_dir_exec(dir, nullptr);
char httpserver_ut_with_args[10 * 1024];
const string testBody = "CurlHttpClient test boday";
snprintf(httpserver_ut_with_args, 10 * 1024, "%s/httpserver_for_ut 8021 \"%s\"", dir, testBody.c_str());
FILE* http = popen(httpserver_ut_with_args, "r");
EXPECT_TRUE(http != nullptr);
// wait util httpserver started
char buffer[100];
usleep(10 * 1000);
fgets(buffer, 100, http);
Url url;
url.setHost("127.0.0.1");
url.setPort(8021);
request.setMethod(HttpRequest::Method::Get);
request.setUrl(url);
request.setHeader("head1", "value1");
request.setHeader("head2", "value2");
HttpClient::HttpResponseOutcome out = client.makeRequest(request);
EXPECT_TRUE(out.result().body() == testBody);
request.setMethod(HttpRequest::Method::Put);
request.setUrl(url);
HttpClient::HttpResponseOutcome out1 = client.makeRequest(request);
EXPECT_TRUE(out1.result().body() == testBody);
request.setMethod(HttpRequest::Method::Post);
request.setUrl(url);
HttpClient::HttpResponseOutcome out2 = client.makeRequest(request);
EXPECT_TRUE(out2.result().body() == testBody);
pclose(http);
}
TEST(CurlHttpClient, netWorkError) {
CurlHttpClient client;
HttpRequest request;
HttpClient::HttpResponseOutcome out = client.makeRequest(request);
EXPECT_TRUE(out.error().errorCode() == "NetworkError");
EXPECT_TRUE(out.error().errorMessage() == "Failed to connect to host or proxy.");
}
TEST(CurlHttpClient, netWorkErrorWithHttpProxy) {
const std::string hostname = "hostname";
const std::string user = "user";
const std::string password = "password";
uint16_t port = 12345;
const NetworkProxy proxy(NetworkProxy::Http, hostname, port, user, password);
CurlHttpClient client;
client.setProxy(proxy);
HttpRequest request;
HttpClient::HttpResponseOutcome out = client.makeRequest(request);
EXPECT_TRUE(out.error().errorCode() == "NetworkError");
EXPECT_TRUE(out.error().errorMessage() == "Failed to connect to host or proxy.");
}
TEST(CurlHttpClient, netWorkErrorWithSocks5Proxy) {
const std::string hostname = "hostname";
const std::string user = "user";
const std::string password = "password";
uint16_t port = 12345;
const NetworkProxy proxy(NetworkProxy::Socks5, hostname, port, user, password);
CurlHttpClient client;
client.setProxy(proxy);
HttpRequest request;
HttpClient::HttpResponseOutcome out = client.makeRequest(request);
EXPECT_TRUE(out.error().errorCode() == "NetworkError");
EXPECT_TRUE(out.error().errorMessage() == "Failed to connect to host or proxy.");
}
TEST(CurlHttpClient, mock) {
CurlHttpClient client;
HttpRequest request;
string body = "1234567";
HttpResponse response(request);
response.setStatusCode(200);
response.setBody(body.c_str(), body.size());
NiceMock<mockCurlHttpClient> mclient;
HttpClient::HttpResponseOutcome res = HttpClient::HttpResponseOutcome(response);
HttpClient::HttpResponseOutcome out1;
out1.error().setErrorCode("111");
out1.error().setErrorMessage("this is a mock test");
DefaultValue<HttpClient::HttpResponseOutcome>::Set(res);
HttpRequest req;
EXPECT_CALL(mclient, makeRequest(_));
HttpClient::HttpResponseOutcome o = mclient.makeRequest(request);
EXPECT_TRUE(res.result().body() == body);
}

View File

@@ -0,0 +1,69 @@
#include <iostream>
#include <stdio.h>
#include "gtest/gtest.h"
#include "alibabacloud/core/EndpointProvider.h"
using namespace std;
using namespace AlibabaCloud;
using namespace AlibabaCloud::Location;
TEST(EndpointProvider, basic) {
ClientConfiguration configuration("cn-hangzhou");
char* key = getenv("ENV_AccessKeyId");
char* secret = getenv("ENV_AccessKeySecret");
bool no_key_provided = false;
string accessKeyId, accessKeySecret;
if (key == nullptr) {
accessKeyId = "no-AccessKeyId";
no_key_provided = true;
} else {
accessKeyId = string(key);
}
if (secret == nullptr) {
accessKeySecret = "no-AccessKeySecret";
no_key_provided = true;
} else {
accessKeySecret = string(secret);
}
auto locationClient = std::make_shared<LocationClient>(accessKeyId, accessKeySecret, configuration);
EndpointProvider ep(locationClient, configuration.regionId(), "Ecs", "ecs");
EndpointProvider::EndpointOutcome out = ep.getEndpoint();
if (no_key_provided) {
EXPECT_TRUE(out.error().errorCode() == "InvalidAccessKeyId.NotFound");
} else {
EXPECT_TRUE(out.result() == "ecs-cn-hangzhou.aliyuncs.com");
}
}
TEST(EndpointProvider, basic1) {
ClientConfiguration configuration("cn-hangzhou");
const string accessKeyId = "no-AccessKeyId";
const string accessKeySecret = "no-AccessKeySecret";
auto locationClient = std::make_shared<LocationClient>(accessKeyId, accessKeySecret, configuration);
EndpointProvider ep(locationClient, configuration.regionId(), "Ecs");
EndpointProvider::EndpointOutcome out = ep.getEndpoint();
EXPECT_TRUE(out.error().errorCode() == "InvalidRegionId");
}
TEST(EndpointProvider, basic2) {
ClientConfiguration configuration("xxxcn-hangzhou");
const string accessKeyId = "no-AccessKeyId";
const string accessKeySecret = "no-AccessKeySecret";
auto locationClient = std::make_shared<LocationClient>(accessKeyId, accessKeySecret, configuration);
EndpointProvider ep(locationClient, configuration.regionId(), "Ecs", "ecs");
EndpointProvider::EndpointOutcome out = ep.getEndpoint();
EXPECT_TRUE(out.error().errorCode() == "InvalidAccessKeyId.NotFound");
}

33
test/core/error_ut.cc Normal file
View File

@@ -0,0 +1,33 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/Error.h"
using namespace std;
using namespace AlibabaCloud;
TEST(Error, basic) {
const std::string error_code = "errorCode";
const std::string error_message = "errorMessage";
const std::string host = "Host";
const std::string request_id = "requestId";
Error error(error_code, error_message);
EXPECT_TRUE(error.errorCode() == error_code);
EXPECT_TRUE(error.errorMessage() == error_message);
EXPECT_TRUE(error.host() == "");
EXPECT_TRUE(error.requestId() == "");
error.setHost(host);
error.setRequestId(request_id);
EXPECT_TRUE(error.errorCode() == error_code);
EXPECT_TRUE(error.errorMessage() == error_message);
EXPECT_TRUE(error.host() == host);
EXPECT_TRUE(error.requestId() == request_id);
const string code1 = "invalid regionId";
const string message1 = "invalid regionId cn-xxxx";
error.setErrorCode(code1);
error.setErrorMessage(message1);
EXPECT_TRUE(error.errorCode() == code1);
EXPECT_TRUE(error.errorMessage() == message1);
}

78
test/core/executor_ut.cc Normal file
View File

@@ -0,0 +1,78 @@
#include <iostream>
#include <stdio.h>
#include "gtest/gtest.h"
#include "alibabacloud/core/Runnable.h"
#include "../src/Executor.h"
using namespace std;
using namespace AlibabaCloud;
namespace {
static unsigned int nbr = 0;
static void f0() {
usleep(3000);
nbr |= 0x01;
}
static void f1() {
usleep(3000);
nbr |= 0x02;
}
static void f2() {
usleep(3000);
nbr |= 0x04;
}
// there should be no exception
TEST(Executor, basic) {
std::function<void()> func0(f0);
std::function<void()> func1(f1);
std::function<void()> func2(f2);
Runnable* rf0 = new Runnable(func0);
Runnable* rf1 = new Runnable(func1);
Runnable* rf2 = new Runnable(func2);
Executor* e = new Executor;
EXPECT_TRUE(e->isShutdown() == true);
// thread created to execute tasks
e->start();
// before
EXPECT_TRUE(nbr == 0);
// push tasks to queue
e->instance()->execute(rf0);
e->instance()->execute(rf1);
e->instance()->execute(rf2);
// shutdown removes tasks in queue
e->shutdown();
// there is no time for task executing
// maybe some tasks executed as the async reason
EXPECT_TRUE(nbr != 0x07);
rf0 = new Runnable(func0);
rf1 = new Runnable(func1);
rf2 = new Runnable(func2);
nbr = 0;
e->execute(rf0);
usleep(5000);
// executor not started, nbr no changed
EXPECT_TRUE(nbr == 0);
e->start();
// there should be no more thread created
e->start();
e->instance()->execute(rf0);
e->execute(rf1);
e->execute(rf2);
usleep(20000);
EXPECT_TRUE(nbr == 0x07);
e->shutdown();
}
}

View File

@@ -0,0 +1,25 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/HmacSha1Signer.h"
#include <openssl/hmac.h>
using namespace std;
using namespace AlibabaCloud;
TEST(HmacSha1Signer, assign) {
HmacSha1Signer sig;
string sign = sig.generate("GET&%2F&AccessKeyId%3Dtestid%26Action%3DDescribeRegions"
"%26Format%3DXML%26RegionId%3Dregion1%26SignatureMethod%3DHMAC-SHA1"
"%26SignatureNonce%3DNwDAxvLU6tFE0DVb%26SignatureVersion%3D1.0"
"%26TimeStamp%3D2012-12-26T10%253A33%253A56Z%26Version%3D2013-01-10",
"testsecret&");
EXPECT_TRUE("axE3FUHgDyfm9/+Iep0HpZXrRwE=" == sign);
EXPECT_TRUE(sig.type() == HmacSha1Signer::HmacSha1);
EXPECT_TRUE(sig.name() == "HMAC-SHA1");
EXPECT_TRUE(sig.version() == "1.0");
}
TEST(HmacSha1Signer, edge_from_empty_string) {
HmacSha1Signer sign;
EXPECT_TRUE(sign.generate("", "") == "");
}

View File

@@ -0,0 +1,56 @@
#include <iostream>
#include <stdio.h>
#include "gtest/gtest.h"
#include "alibabacloud/core/HttpRequest.h"
using namespace std;
using namespace AlibabaCloud;
TEST(HttpMessage, perRequest) {
const std::string data = "Thu, 19 Oct 2017 04:38:27 GMT";
HttpRequest req;
req.setHeader("accept", "application/xml");
EXPECT_TRUE(req.header("accept") == "application/xml");
req.setHeader("Accept", "application/json");
EXPECT_TRUE(req.header("accept") == "application/json");
EXPECT_TRUE(req.headers().size() == 1);
req.setHeader("Date", data);
EXPECT_TRUE(req.headers().size() == 2);
EXPECT_TRUE(req.header(HttpMessage::KnownHeader::Date) == data);
req.addHeader("header1", "value1");
EXPECT_TRUE(req.header("header1") == "value1");
EXPECT_TRUE(req.headers().size() == 3);
req.addHeader(HttpMessage::KnownHeader::ContentMD5, "testmd5sume");
EXPECT_TRUE(req.header(HttpMessage::KnownHeader::ContentMD5) == "testmd5sume");
EXPECT_TRUE(req.headers().size() == 4);
req.removeHeader("header1");
EXPECT_TRUE(req.header("header1") == "");
EXPECT_TRUE(req.headers().size() == 3);
req.removeHeader(HttpMessage::KnownHeader::ContentMD5);
EXPECT_TRUE(req.header(HttpMessage::KnownHeader::ContentMD5) == "");
EXPECT_TRUE(req.headers().size() == 2);
string body = "this is a test body";
req.setBody(body.c_str(), body.size());
EXPECT_TRUE(req.bodySize() == body.size());
EXPECT_TRUE(req.hasBody());
EXPECT_TRUE(req.body() != nullptr);
}
class TestHttpMessage: public HttpMessage {
public:
TestHttpMessage(): HttpMessage(){}
};
TEST(HttpMessage, A) {
TestHttpMessage tm;
TestHttpMessage ttm(tm);
}

View File

@@ -0,0 +1,30 @@
#include <iostream>
#include <stdio.h>
#include "gtest/gtest.h"
#include "alibabacloud/core/HttpRequest.h"
using namespace std;
using namespace AlibabaCloud;
TEST(HttpRequest, basic) {
const string src = "abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1";
Url url;
url.setScheme("abc");
url.setUserName("username");
url.setPassword("password");
url.setHost("example.com");
url.setPath("/path/data");
url.setPort(123);
url.setQuery("key=value&key2=value2");
url.setFragment("fragid1");
HttpRequest http_request(url, HttpRequest::Method::Post);
EXPECT_TRUE(http_request.method() == HttpRequest::Method::Post);
http_request.setMethod(HttpRequest::Method::Get);
EXPECT_TRUE(http_request.method() == HttpRequest::Method::Get);
http_request.setUrl(url);
Url rUrl = http_request.url();
EXPECT_TRUE(rUrl.toString() == src);
}

View File

@@ -0,0 +1,18 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/HttpResponse.h"
using namespace std;
using namespace AlibabaCloud;
TEST(HttpResponse, basic) {
HttpResponse r;
r.setStatusCode(202);
EXPECT_TRUE(r.statusCode() == 202);
Url url;
url.setHost("example.com");
HttpRequest req(url, HttpRequest::Method::Post);
HttpResponse res(req);
EXPECT_TRUE(res.request().url().host() == "example.com");
}

View File

@@ -0,0 +1,21 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/NetworkProxy.h"
using namespace std;
using namespace AlibabaCloud;
TEST(NetworProxyTest, basic) {
NetworkProxy proxy(NetworkProxy::Http);
proxy.setHostName("abc.com");
proxy.setPassword("myPassword");
proxy.setPort(123);
proxy.setUser("tester");
EXPECT_TRUE(proxy.type() == NetworkProxy::Http);
proxy.setType(NetworkProxy::Socks5);
EXPECT_TRUE(proxy.type() == NetworkProxy::Socks5);
EXPECT_TRUE(proxy.hostName() == "abc.com");
EXPECT_TRUE(proxy.password() == "myPassword");
EXPECT_TRUE(proxy.user() == "tester");
EXPECT_TRUE(proxy.port() == 123);
}

View File

@@ -0,0 +1,16 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/RoaServiceRequest.h"
using namespace std;
using namespace AlibabaCloud;
TEST(test_RoaServiceRequest, basic) {
const string product = "ECS";
const string version = "1.0";
RoaServiceRequest roa(product, version);
EXPECT_TRUE(roa.version() == version);
EXPECT_TRUE(roa.product() == product);
}

View File

@@ -0,0 +1,18 @@
#include <iostream>
#include <stdio.h>
#include "gtest/gtest.h"
#include "alibabacloud/core/RpcServiceRequest.h"
using namespace std;
using namespace AlibabaCloud;
TEST(test_RpcServiceRequest, basic) {
const string product = "ECS";
const string version = "1.0";
const string action = "testAction";
RpcServiceRequest rpc(product, version, action);
EXPECT_TRUE(rpc.actionName() == action);
EXPECT_TRUE(rpc.product() == product);
EXPECT_TRUE(rpc.version() == version);
}

22
test/core/runnable_ut.cc Normal file
View File

@@ -0,0 +1,22 @@
#include <iostream>
#include <stdio.h>
#include "gtest/gtest.h"
#include "alibabacloud/core/Runnable.h"
using namespace std;
using namespace AlibabaCloud;
static int nbr = 0;
void foo() {
nbr = 1;
}
// there should be no exception
TEST(Runnable, basic) {
std::function<void()> func(foo);
Runnable f(func);
EXPECT_TRUE(nbr == 0);
f.run();
EXPECT_TRUE(nbr == 1);
}

View File

@@ -0,0 +1,110 @@
#include <iostream>
#include <stdio.h>
#include <string.h>
#include "gtest/gtest.h"
#include "alibabacloud/core/ServiceRequest.h"
using namespace std;
using namespace AlibabaCloud;
namespace AlibabaCloud{
class TestServiceRequest: public ServiceRequest {
public:
explicit TestServiceRequest(const std::string &product, const std::string &version):
ServiceRequest(product, version)
{}
explicit TestServiceRequest(const ServiceRequest &other):
ServiceRequest(other)
{}
explicit TestServiceRequest(ServiceRequest &&other):
ServiceRequest(other)
{}
void addParameter(const ParameterNameType &k, const ParameterValueType &v) {
ServiceRequest::addParameter(k, v);
}
void removeParameter(const ParameterNameType &k) {
ServiceRequest::removeParameter(k);
}
ServiceRequest::ParameterValueType parameter (const ParameterNameType &name) {
return ServiceRequest::parameter(name);
}
void setContent(const char* data, size_t size) {
ServiceRequest::setContent(data, size);
}
void setParameter(const ParameterNameType &k, const ParameterValueType &v) {
ServiceRequest::setParameter(k, v);
}
void setParameters(const ParameterCollection &params) {
ServiceRequest::setParameters(params);
}
void setResourcePath (const std::string &p) {
ServiceRequest::setResourcePath(p);
}
void setProduct (const std::string &product) {
ServiceRequest::setProduct(product);
}
void setVersion(const std::string &version) {
ServiceRequest::setVersion(version);
}
};
}
TEST(ServiceRequestTest, basic) {
TestServiceRequest sr1("ECS", "1.0");
TestServiceRequest sr2(sr1);
sr1.addParameter("k1", "v1");
sr2.addParameter("k2", "v2");
ServiceRequest::ParameterCollection p1 = sr1.parameters();
ServiceRequest::ParameterCollection p2 = sr2.parameters();
EXPECT_TRUE(sr1.parameter("k1") == "v1");
sr1.addParameter("kx", "vx");
EXPECT_TRUE(sr1.parameter("kx") == "vx");
EXPECT_TRUE(sr1.parameters().size() == 2);
sr1.removeParameter("k1");
EXPECT_TRUE(sr1.parameters().size() == 1);
sr1.setParameter("ka", "va");
EXPECT_TRUE(sr1.parameter("ka") == "va");
sr1.setContent("123456", 6);
EXPECT_TRUE(sr1.contentSize() == 6);
EXPECT_TRUE(sr1.hasContent() == true);
EXPECT_TRUE(strncmp(sr1.content(), "123456", 6) == 0);
sr1.setContent("aliyunsdk", 9);
EXPECT_TRUE(sr1.contentSize() == 9);
EXPECT_TRUE(sr1.hasContent() == true);
EXPECT_TRUE(strncmp(sr1.content(), "aliyunsdk", 9) == 0);
sr1.setProduct("OSS");
EXPECT_TRUE(sr1.product() == "OSS");
sr1.setVersion("3.0");
EXPECT_TRUE(sr1.version() == "3.0");
sr1.setResourcePath("http://abc.com/a/b/c");
EXPECT_TRUE(sr1.resourcePath() == "http://abc.com/a/b/c");
ServiceRequest::ParameterCollection ps;
ps["km"] = "vm";
ps["kn"] = "vn";
sr1.setParameters(ps);
ServiceRequest::ParameterCollection pc = sr1.parameters();
EXPECT_TRUE(pc.at("km") == "vm");
EXPECT_TRUE(pc.at("kn") == "vn");
}

View File

@@ -0,0 +1,29 @@
#include <iostream>
#include <stdio.h>
#include "gtest/gtest.h"
#include "alibabacloud/core/ServiceResult.h"
using namespace std;
using namespace AlibabaCloud;
namespace AlibabaCloud{
class myServiceResult: public ServiceResult {
public:
myServiceResult(){}
void setRequestId(const string request_id) {
ServiceResult::setRequestId(request_id);
}
};
}
TEST(ServiceResult, basic) {
ServiceResult* service_result = new ServiceResult();
EXPECT_TRUE(service_result->requestId() == "");
myServiceResult* sr = new myServiceResult();
sr->setRequestId("testRequestId");
EXPECT_TRUE(sr->requestId() == "testRequestId");
delete(service_result);
delete(sr);
}

20
test/core/signer_ut.cc Normal file
View File

@@ -0,0 +1,20 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/Signer.h"
using namespace std;
using namespace AlibabaCloud;
namespace {
TEST(Signer, basic) {
HmacSha1Signer sig;
string sign = sig.generate("GET&%2F&AccessKeyId%3Dtestid%26Action%3DDescribeRegions"
"%26Format%3DXML%26RegionId%3Dregion1%26SignatureMethod%3DHMAC-SHA1"
"%26SignatureNonce%3DNwDAxvLU6tFE0DVb%26SignatureVersion%3D1.0"
"%26TimeStamp%3D2012-12-26T10%253A33%253A56Z%26Version%3D2013-01-10",
"testsecret&");
EXPECT_TRUE("axE3FUHgDyfm9/+Iep0HpZXrRwE=" == sign);
}
}

View File

@@ -0,0 +1,23 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/Credentials.h"
#include "alibabacloud/core/sts/StsClient.h"
#include "alibabacloud/core/SimpleCredentialsProvider.h"
using namespace std;
using namespace AlibabaCloud;
TEST(SimpleCredentialsProvider, basic) {
const string access_key = "accessKeyId";
const string access_secret = "accessKeySecret";
Credentials credentials(access_key, access_secret);
SimpleCredentialsProvider p1(credentials);
SimpleCredentialsProvider p2(access_key, access_secret);
EXPECT_TRUE(p1.getCredentials().accessKeyId() == access_key);
EXPECT_TRUE(p1.getCredentials().accessKeySecret() == access_secret);
EXPECT_TRUE(p2.getCredentials().accessKeyId() == access_key);
EXPECT_TRUE(p2.getCredentials().accessKeySecret() == access_secret);
}

118
test/core/url_ut.cc Normal file
View File

@@ -0,0 +1,118 @@
#include "gtest/gtest.h"
#include "alibabacloud/core/Url.h"
using namespace std;
using namespace AlibabaCloud;
namespace {
TEST(UrlTest, assign) {
const string src = "abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1";
Url url;
url.setScheme("abc");
url.setUserName("username");
url.setPassword("password");
url.setHost("example.com");
url.setPath("/path/data");
url.setPort(123);
url.setQuery("key=value&key2=value2");
url.setFragment("fragid1");
EXPECT_TRUE(url.toString() == src);
EXPECT_TRUE(url.scheme() == "abc");
EXPECT_TRUE(url.userName() == "username");
EXPECT_TRUE(url.password() == "password");
EXPECT_TRUE(url.host() == "example.com");
EXPECT_TRUE(url.path() == "/path/data");
EXPECT_TRUE(url.port() == 123);
EXPECT_TRUE(url.query() == "key=value&key2=value2");
EXPECT_TRUE(url.fragment() == "fragid1");
url.clear();
EXPECT_TRUE(url.toString() == "");
EXPECT_TRUE(url.scheme() == "");
EXPECT_TRUE(url.userName() == "");
EXPECT_TRUE(url.password() == "");
EXPECT_TRUE(url.host() == "");
EXPECT_TRUE(url.path() == "");
EXPECT_TRUE(url.port() == -1);
EXPECT_TRUE(url.query() == "");
EXPECT_TRUE(url.fragment() == "");
url.fromString(src);
EXPECT_TRUE(url.scheme() == "abc");
EXPECT_TRUE(url.userName() == "username");
EXPECT_TRUE(url.password() == "password");
EXPECT_TRUE(url.host() == "example.com");
EXPECT_TRUE(url.path() == "/path/data");
EXPECT_TRUE(url.port() == 123);
EXPECT_TRUE(url.query() == "key=value&key2=value2");
EXPECT_TRUE(url.fragment() == "fragid1");
Url newurl = url;
EXPECT_TRUE(newurl.scheme() == "abc");
EXPECT_TRUE(newurl.userName() == "username");
EXPECT_TRUE(newurl.password() == "password");
EXPECT_TRUE(newurl.host() == "example.com");
EXPECT_TRUE(newurl.path() == "/path/data");
EXPECT_TRUE(newurl.port() == 123);
EXPECT_TRUE(newurl.query() == "key=value&key2=value2");
EXPECT_TRUE(newurl.fragment() == "fragid1");
}
TEST(UrlTest, from_string) {
const string src = "http://oss.example.com";
Url url(src);
EXPECT_TRUE(url.scheme() == "http");
EXPECT_TRUE(url.userName() == "");
EXPECT_TRUE(url.password() == "");
EXPECT_TRUE(url.host() == "oss.example.com");
EXPECT_TRUE(url.path() == "/");
EXPECT_TRUE(url.port() == -1);
EXPECT_TRUE(url.query() == "");
EXPECT_TRUE(url.fragment() == "");
}
TEST(UrlTest, abnormal) {
const string src = "http://oss.example.com";
Url url(src);
Url newurl = url;
newurl.setPort(12345);
EXPECT_TRUE(url.isEmpty() == false);
EXPECT_TRUE(url.isValid());
EXPECT_TRUE(newurl != url);
EXPECT_TRUE(newurl.port() == 12345);
}
TEST(UrlTest, abnormal_2) {
const string src = "";
Url empty_url;
empty_url.fromString(src);
EXPECT_TRUE(empty_url.isEmpty());
Url url(src);
Url newurl = url;
EXPECT_TRUE(url == newurl);
newurl.setPort(12345);
EXPECT_TRUE(url.isEmpty() == true);
EXPECT_TRUE(url.isValid() == false);
EXPECT_TRUE(url.authority() == "");
EXPECT_TRUE(newurl != url);
EXPECT_TRUE(newurl.port() == 12345);
newurl.setAuthority("");
EXPECT_TRUE(newurl.host() == "");
EXPECT_TRUE(newurl.port() == -1);
EXPECT_TRUE(newurl.userInfo() == "");
newurl.setScheme("");
EXPECT_TRUE(newurl.scheme() == "");
newurl.setUserInfo("userinfo");
EXPECT_TRUE(newurl.userName() == "userinfo");
newurl.setUserInfo("user:password");
EXPECT_TRUE(newurl.userName() == "user");
EXPECT_TRUE(newurl.password() == "password");
}
}

30
test/core/utils.h Normal file
View File

@@ -0,0 +1,30 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
class utUtils {
public:
void get_dir_exec(char* dir, char* exec) {
char* filename = nullptr;
if (readlink("/proc/self/exe", dir, 1024) < 0) {
dir[0] = '\0';
return;
}
filename = strrchr(dir, '/');
if (filename == nullptr) {
dir[0] = '\0';
return;
}
++filename;
if (exec) {
sprintf(exec, "%s", filename);
}
*filename = '\0';
return;
}
};

63
test/core/utils_ut.cc Normal file
View File

@@ -0,0 +1,63 @@
#include "gtest/gtest.h"
#include "../../core/src/Utils.h"
using namespace std;
using namespace AlibabaCloud;
namespace {
TEST(UtilsTest, ComputeContentMD5) {
const std::string src = "abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1";
const std::string md5 = ComputeContentMD5(src.c_str(), src.size());
EXPECT_TRUE(md5 == "WL7+fwrxHSlBTsfU9WCSbA==");
}
TEST(UtilsTest, GenerateUuid) {
const std::string uuid1 = GenerateUuid();
const std::string uuid2 = GenerateUuid();
EXPECT_TRUE(uuid1 != uuid2);
}
TEST(UtilsTest, HttpMethodToString){
std::string method = HttpMethodToString(HttpRequest::Method::Head);
EXPECT_TRUE(method == "HEAD");
method = HttpMethodToString(HttpRequest::Method::Post);
EXPECT_TRUE(method == "POST");
method = HttpMethodToString(HttpRequest::Method::Put);
EXPECT_TRUE(method == "PUT");
method = HttpMethodToString(HttpRequest::Method::Delete);
EXPECT_TRUE(method == "DELETE");
method = HttpMethodToString(HttpRequest::Method::Connect);
EXPECT_TRUE(method == "CONNECT");
method = HttpMethodToString(HttpRequest::Method::Options);
EXPECT_TRUE(method == "OPTIONS");
method = HttpMethodToString(HttpRequest::Method::Patch);
EXPECT_TRUE(method == "PATCH");
method = HttpMethodToString(HttpRequest::Method::Trace);
EXPECT_TRUE(method == "TRACE");
method = HttpMethodToString(HttpRequest::Method::Get);
EXPECT_TRUE(method == "GET");
}
TEST(UtilsTest, StringReplace) {
std::string src = "abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1";
StringReplace(src, "abc", "http");
EXPECT_TRUE(src == "http://username:password@example.com:123/path/data?key=value&key2=value2#fragid1");
StringReplace(src, "value", "VALUE");
EXPECT_TRUE(src == "http://username:password@example.com:123/path/data?key=VALUE&key2=VALUE2#fragid1");
}
TEST(UtilsTest, Encode) {
const std::string url = "http://username:password@example.com:123/path/data?key=value&key2=value2#fragid1";
const std::string encoded = "http%3A%2F%2Fusername%3Apassword%40example.com%3A123%2Fpath%2Fdata%3Fkey%3Dvalue%26key2%3Dvalue2%23fragid1";
const std::string enc = UrlEncode(url);
EXPECT_TRUE(enc == encoded);
}
TEST(UtilsTest, Decode) {
const std::string url = "http://username:password@example.com:123/path/data?key=value&key2=value2#fragid1";
const std::string encoded = "http%3A%2F%2Fusername%3Apassword%40example.com%3A123%2Fpath%2Fdata%3Fkey%3Dvalue%26key2%3Dvalue2%23fragid1";
const std::string decoded = UrlDecode(encoded);
EXPECT_TRUE(decoded == url);
}
}

View File

@@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.0)
set(CMAKE_CXX_STANDARD 11)
add_executable(httpserver_for_ut
HTTPServer.cpp
ServerThread.cpp
main.cpp
)
# httpserver_for_ut use pthread
find_package(Threads)
target_link_libraries(httpserver_for_ut ${CMAKE_THREAD_LIBS_INIT})
# copy httpserver_for_ut to the same directory as the core_ut binary
set_target_properties(httpserver_for_ut
PROPERTIES
OUTPUT_NAME httpserver_for_ut
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# httpserver_for_ut echo this message to client
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/index.html ${CMAKE_BINARY_DIR}/bin/index.html COPYONLY)

View File

@@ -0,0 +1,118 @@
#include "HTTPServer.h"
using namespace std;
// the terminator logic, run in a separate thread
void *tfunc(void* obj) {
((HTTPServer*) obj)->RunTerminator();
}
void* sfunc(void* obj) {
((HTTPServer*) obj)->RunServer();
}
void error(string msg) {
cerr << msg << endl;
exit(1);
}
void msg(string msg) {
cout << msg << endl;
}
HTTPServer::HTTPServer(int port) {
this->portno = port;
}
HTTPServer::~HTTPServer() {
}
void HTTPServer::StartServer() {
// socket(int domain, int type, int protocol)
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("Opening socket");
// clear the struct's memory
bzero((char *) &serv_addr, sizeof (serv_addr));
// setup the host_addr structure
serv_addr.sin_family = AF_INET;
// automatically be filled with current host's IP address which is localhost
serv_addr.sin_addr.s_addr = INADDR_ANY;
// convert short to network port order
serv_addr.sin_port = htons(portno);
// to avoid waiting for limbo connection when debugging
int en = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &en, sizeof (int));
// bind(int fd, struct sockaddr *local_addr, socklen_t addr_length)
// This bind() call will bind the socket to the current IP address on our port
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
error("On binding");
// This listen() function will start filling the backlog queue with clients
// The maximum size for the backlog queue to 1
listen(sockfd, 1);
clilen = sizeof (cli_addr);
// create the server thread
pthread_create(&server, NULL, sfunc, this);
}
void HTTPServer::StartTerminator() {
// create the terminator thread
pthread_create(&terminator, NULL, tfunc, this);
}
void HTTPServer::RunServer() {
msg("Server is online!");
while (true) {
// The accept() function blocks untill the backlog has elements
// It then stores the info of the client socket in newsockfd
int csockn = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (csockn < 0)
msg("Failed on accept.");
printf("Incoming connection from %s port %ho\n",
inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
ServerThread* clt = new ServerThread(csockn);
clt->Serve();
aclients.push_front(clt);
}
}
void HTTPServer::RunTerminator() {
while (true) {
sleep(0.01);
time_t now = time(NULL);
int nc = aclients.size();
int ttl = 1 / (double) (nc > 0 ? nc : 1); //in seconds
for (list<ServerThread*>::iterator list_iter = aclients.begin(); list_iter != aclients.end();) {
ServerThread* st = *list_iter;
int runningtime = difftime(now, st->GetStartTime());
if (st->IsMarked() || (runningtime >= ttl && st->Terminate(false))) {
if (st->IsMarked())
cout << "Client on socket " << st->GetSocket() << " self terminated" << endl;
else
cout << "Terminated client on socket " << st->GetSocket() << endl;
delete st;
list_iter = aclients.erase(list_iter);
} else {
list_iter++;
}
}
}
}
void HTTPServer::Stop() {
close(sockfd);
if (server)
pthread_cancel(server);
if (terminator)
pthread_cancel(terminator);
}

View File

@@ -0,0 +1,52 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/*
* File: HTTPServer.h
* Author: root
*
* Created on November 5, 2016, 5:46 PM
*/
#ifndef HTTPSERVER_H
#define HTTPSERVER_H
#include <list>
#include "ServerThread.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <iostream>
using namespace std;
class HTTPServer {
public:
HTTPServer(int port);
HTTPServer(const HTTPServer& orig);
virtual ~HTTPServer();
void RunServer();
void RunTerminator();
void StartServer();
void StartTerminator();
void Stop();
private:
pthread_t server, terminator;
// a list of active clients
list<ServerThread*> aclients;
// socket fields
int sockfd, portno;
sockaddr_in serv_addr, cli_addr;
socklen_t clilen;
};
#endif /* HTTPSERVER_H */

View File

@@ -0,0 +1,163 @@
#include "ServerThread.h"
using namespace std;
// entry point for all threads
char echo_buffer[100 *1024];
void getExecDir(char*dir) {
char* filename = nullptr;
if (readlink("/proc/self/exe", dir, 1024) < 0) {
dir[0] = '\0';
return;
}
filename = strrchr(dir, '/');
if (filename == nullptr) {
dir[0] = '\0';
return;
}
++filename;
*filename = '\0';
sprintf(dir + strlen(dir), "%s", "index.html");
return;
}
void* run(void* obj) {
((ServerThread*) obj)->Run();
// when Run() finishes, mark for termination
((ServerThread*) obj)->MarkFT();
}
bool getExt(const char* path, char* ext) {
int l = strlen(path), i = l;
while (i > 0 && path[--i] != '.' && path[i] != '/');
if (i == 0 || path[i] == '/') return false;
for (int j = 0; i < l; ext[j++] = path[++i]);
return true;
}
int getHeader(char *header, const char *buffer, int rd) {
int hl = 0;
int i = 0;
for (; hl < rd && strcmp(term, buffer + hl); hl++) {
for (i = 0; i < 4; i++)
if (term[i] != buffer[hl + i]) break;
if (i == 4) break;
header[hl] = buffer[hl];
}
header[hl] = '\0';
return hl;
}
///////////////////////////////////////////////////////////
ServerThread::ServerThread(int socket) {
this->socket = socket;
marked = serving = false;
}
ServerThread::~ServerThread() {
}
// start serving in a separate thread
void ServerThread::Serve() {
pthread_create(&tid, NULL, run, this);
start = time(NULL);
}
// terminate the thread and close the socket
bool ServerThread::Terminate(bool force) {
if (serving&&!force)return false;
pthread_cancel(tid);
close(socket);
return true;
}
// run in current thread
void ServerThread::Run() {
int rd, hl;
while (1) {
serving = false;
rd = read(socket, buffer, BUFFERLENGTH - 1);
if (rd <= 0) {
// client disconnected mysteriously
Terminate(true);
break; // precautionary
}
// parse the header
serving = true;
char method[8], path[261], version[8], ext[5];
strcpy(path, WORKDIR);
// getExecDir(path);
hl = getHeader(header, buffer, rd);
sscanf(header, "%s %s %s", method, path + WDLEN, version);
// handle default file name
// if (!getExt(path, ext))strcat(path, "/index.html");
getExecDir(path);
// handle the request
if (!strcmp("GET", method) || !strcmp("PUT", method)) {
if (strlen(echo_buffer) > 0) {
int size = strlen(echo_buffer);
sprintf(buffer, "%s%d\r\n\r\n", "HTTP/1.1 200 OK\r\nContent-Length: ", size);
send(socket, buffer, strlen(buffer), 0);
send(socket, echo_buffer, size, 0);
} else {
// try to open the requested file
FILE * file = fopen(path, "r");
if (file) {
fseek(file, 0, SEEK_END);
int size = ftell(file);
fseek(file, 0, 0);
// send 200
sprintf(buffer, "%s%d\r\n\r\n", "HTTP/1.1 200 OK\r\nContent-Length: ", size);
send(socket, buffer, strlen(buffer), 0);
cout << "200 " << path << endl;
do {
rd = fread(buffer, sizeof (char), BUFFERLENGTH, file);
send(socket, buffer, rd, 0);
} while (rd > 0);
fclose(file);
} else {
// send 404
sprintf(buffer, "%s\r\n\r\n", "HTTP/1.1 404 Not Found");
send(socket, buffer, strlen(buffer), 0);
cout << "404 " << path << endl;
}
}
serving = false;
Terminate(true);
} else if (!strcmp("POST", method)) {
if (fopen(path, "r") > 0) {
sprintf(buffer, "%s\r\n\r\n", "HTTP/1.1 403 Forbidden");
send(socket, buffer, strlen(buffer), 0);
cout << "402 " << path << endl;
continue;
}
FILE *file = fopen(path, "w+");
if (file) {
// send 200
sprintf(buffer, "%s\r\n\r\n", "HTTP/1.1 200 OK");
send(socket, buffer, strlen(buffer), 0);
cout << "200 " << path << endl;
// if client sent data after the header
if (rd - hl > 4)
fwrite(buffer + hl + 4, sizeof (char), rd - hl - 4, file);
rd = read(socket, buffer, BUFFERLENGTH - 1);
while (rd > 0) {
fwrite(buffer, sizeof (char), rd, file);
rd = read(socket, buffer, BUFFERLENGTH - 1);
// TODO: implement blocks or read content length
if (rd < BUFFERLENGTH - 1 || !strcmp(buffer - 4, term))
break;
}
fclose(file);
} else {
sprintf(buffer, "%s\r\n\r\n", "HTTP/1.1 500 Internal Server Error");
send(socket, buffer, strlen(buffer), 0);
cout << "500 " << path << endl;
}
}
}
}

View File

@@ -0,0 +1,55 @@
#ifndef SERVERTHREAD_H
#define SERVERTHREAD_H
#include <ctime>
#include <pthread.h>
#include <iostream>
#include <ctime>
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#define BUFFERLENGTH 8192
#define WORKDIR "/tmp"
#define WDLEN 11
#define term "\r\n\r\n"
class ServerThread {
private:
int socket;
pthread_t tid;
std::time_t start;
char buffer[BUFFERLENGTH];
char header[BUFFERLENGTH];
bool marked;
bool serving;
public:
ServerThread(int socket);
virtual ~ServerThread();
void Serve();
void Run();
bool Terminate(bool force);
int GetSocket() {
return this->socket;
}
time_t GetStartTime() {
return this->start;
}
pthread_t GetThreadID() {
return this->tid;
}
void MarkFT() {
marked = true;
}
bool IsMarked() {
return marked;
}
};
#endif // SERVERTHREAD_H

View File

@@ -0,0 +1 @@
{"Endpoints":{"Endpoint":[{"Protocols":{"Protocols":["HTTP","HTTPS"]},"Type":"openAPI","Namespace":"26842","Id":"cn-hangzhou","SerivceCode":"ecs","Endpoint":"ecs-cn-hangzhou.aliyuncs.com"}]},"RequestId":"9AF4C364-08A0-4C00-A002-9E4DF57E3389","Success":true}

67
test/httpserver/main.cpp Normal file
View File

@@ -0,0 +1,67 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include "ServerThread.h"
#include "HTTPServer.h"
#include <pthread.h>
using namespace std;
extern char echo_buffer[100 *1024];
// command symbol table
enum _cmd {
cunknown,
cexit
};
_cmd str2cmd(string cmdstr) {
if (cmdstr == "x" || cmdstr == "exit" || cmdstr == "quit")
return cexit;
return cunknown;
}
int main(int argc, char *argv[]) {
string cmd;
bool running = true;
int portno = 8021;
// the first argument is always the work directory.
if (argc == 2) {
// get port number from arguments
portno = atoi(argv[1]);
echo_buffer[0] = '\0';
}
if (argc >= 3) {
// get port number from arguments
portno = atoi(argv[1]);
snprintf(echo_buffer, sizeof(echo_buffer), "%s", argv[2]);
}
HTTPServer* server = new HTTPServer(portno);
server->StartServer();
// without the terminator, only the client can close the connection
server->StartTerminator();
while (running) {
cin >> cmd;
if (cmd != "")
switch (str2cmd(cmd)) {
case cexit:
running = false;
break;
default:
cout << "Unrecognized command." << endl;
break;
}
}
server->Stop();
return 0;
}