JD2022-TU1/main/extern/UbiServices/custom/testsUnit/http/testHttp.cpp

1232 lines
49 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour //
////////////////////////////////////////////////////////////////////////////////
#include "tests/config.h"
#include "tests/common/cancelTest.h"
#include "tests/common/helpers.h"
#include "tests/common/restStatusCode.h"
#include "tests/fixture/authenticationFixture.h" // AsyncHelper
#include "tests/fixture/loginMockFixture.h"
#include "tests/fixture/memoryCheckFixture.h"
#include "tests/fixture/paramFixture.h"
#include "tests/mock/mockLogDevice.h"
#include "tests/mock/mockResultHelper.h"
#include "testsUnit/helpers/asyncResultBaseProxy.h"
#include "testsUnit/mock/mockHttpRequest.h"
#include <ubiservices/facadeInternal.h>
#include <ubiservices/version.h>
#include <ubiservices/localizationHelper.h>
#include <ubiservices/core/chrono/clockSystem.h>
#include <ubiservices/core/chrono/chronometer.h>
#include <ubiservices/core/configs/environmentHelper.h>
#include <ubiservices/core/configs/platformName.h>
#include <ubiservices/core/helpers/instancesManager.h>
#include <ubiservices/core/http/httpHeadersHelper.h>
#include <ubiservices/core/http/httpEngine.h>
#include <ubiservices/core/http/httpRequestContext.h>
#include <ubiservices/core/http/httpStringEntity.h>
#include <ubiservices/core/JSON/jsonWriter.h>
#include <ubiservices/core/network/URLInfo.h>
#include <ubiservices/core/types/string.h>
#include <ubiservices/services/parameters/parametersClientProxy.h>
#include <ubiservices/services/parameters/parametersInfo.h>
#include <ubiservices/services/parameters/parametersSettingsHttpGame.h>
#include <ubiservices/services/http/httpClient.h>
#include <ubiservices/services/http/httpProxyConfig.h>
#include <ubiservices/services/http/request/httpRequestIncludes.h>
#include <ubiservices/services/parameters/gatewayResources.h>
// #if !defined(US_RETAIL)
// extern bool US_DLL_API s_forceNonSecure;
// #endif
namespace US_NS {;
US_DEFINE_TEST(TestHttp);
template<uint32 facadesCount = 1, bool executeLogin = true, bool skipEalMemForLibcurl = false>
class AuthenticationFixtureHttp : public AuthenticationFixture<facadesCount, executeLogin>
{
public:
AuthenticationFixtureHttp<facadesCount, executeLogin, skipEalMemForLibcurl>() : AuthenticationFixture<facadesCount, executeLogin>()
{
}
protected:
void SetUp() override
{
LeakChecker::m_skipEalMemForLibcurl = skipEalMemForLibcurl;
AuthenticationFixture<facadesCount, executeLogin>::SetUp();
}
};
typedef LeakChecker CORE_HTTP;
typedef LeakCheckerHttpClient CORE_HTTP_CLIENT;
typedef LeakCheckerHttpClientSkipLibCurlEalMem CORE_HTTP_CLIENT_NOEALMEM;
typedef LeakCheckerNoInit CORE_HTTP_NO_INIT;
typedef AuthenticationFixtureHttp<1, true, true> CORE_HTTP_CANCEL_LOGIN;
typedef AuthenticationFixtureHttp<2, false> CORE_HTTP_PROXY_X2;
typedef ParamFixture<LeakCheckerHttpClientSkipLibCurlEalMem, TestConfigCancel> CORE_HTTP_CANCEL;
US_DEFINE_LONG_TEST_P(CORE_HTTP_CANCEL, TestConfigCancel(100u), TestConfigCancel(20u));
typedef LeakCheckerNoInitWithParam<TestConfigCancel>::type CORE_HTTP_CANCEL_NO_INIT;
US_DEFINE_LONG_TEST_P(CORE_HTTP_CANCEL_NO_INIT, TestConfigCancel(200u), TestConfigCancel(20u));
TEST_F(CORE_HTTP, LOCAL_CheckProxyConfig)
{
const HttpProxyConfig defaultProxy;
EXPECT_STREQ("", defaultProxy.m_host.getUtf8());
EXPECT_EQ(0u, defaultProxy.m_port);
EXPECT_STREQ("", defaultProxy.m_username.getUtf8());
EXPECT_STREQ("", defaultProxy.m_password.getUtf8());
const String host("proxy.ubi.com");
const uint32 PORT = 9090;
const String username("player2");
const String password("Im 3l33t!");
const HttpProxyConfig proxyNoAuth(host, PORT);
EXPECT_EQ(host, proxyNoAuth.m_host);
EXPECT_EQ(PORT, proxyNoAuth.m_port);
EXPECT_STREQ("", proxyNoAuth.m_username.getUtf8());
EXPECT_STREQ("", proxyNoAuth.m_password.getUtf8());
const HttpProxyConfig proxyAuth(host, PORT, username, password);
EXPECT_EQ(host, proxyAuth.m_host);
EXPECT_EQ(PORT, proxyAuth.m_port);
EXPECT_EQ(username, proxyAuth.m_username);
EXPECT_EQ(password, proxyAuth.m_password);
const HttpProxyConfig copy(proxyAuth);
EXPECT_EQ(proxyAuth.m_host, copy.m_host);
EXPECT_EQ(proxyAuth.m_port, copy.m_port);
EXPECT_EQ(proxyAuth.m_username, copy.m_username);
EXPECT_EQ(proxyAuth.m_password, copy.m_password);
HttpProxyConfig copy2;
copy2 = copy;
EXPECT_EQ(copy.m_host, copy2.m_host);
EXPECT_EQ(copy.m_port, copy2.m_port);
EXPECT_EQ(copy.m_username, copy2.m_username);
EXPECT_EQ(copy.m_password, copy2.m_password);
}
TEST_F(CORE_HTTP, LOCAL_HttpHeader)
{
SAVE_ALLOC_COUNT(testCount);
{
HttpHeader headersSource;
headersSource["field1"] = "value1";
headersSource["field2"] = "value2";
EXPECT_TRUE(headersSource.hasHeader("field1"));
EXPECT_TRUE(headersSource.hasHeader("field2"));
EXPECT_EQ(2u, headersSource.getHeaderCount());
const String lines1 = "field1: value1";
const String lines2 = "field2: value2";
HttpHeader headersTarget;
EXPECT_STREQ("field1", headersTarget.addHeaderLine(lines1).getUtf8());
EXPECT_STREQ("field2", headersTarget.addHeaderLine(lines2).getUtf8());
EXPECT_EQ(lines1.getLength() + lines2.getLength(), headersTarget.getSize());
EXPECT_TRUE(headersTarget.hasHeader("field1"));
EXPECT_TRUE(headersTarget.hasHeader("field2"));
EXPECT_EQ(lines1, headersTarget.getLine("field1"));
EXPECT_EQ(headersSource.getLine("field1"), headersTarget.getLine("field1"));
EXPECT_EQ(lines2, headersTarget.getLine("field2"));
EXPECT_EQ(headersSource.getLine("field2"), headersTarget.getLine("field2"));
EXPECT_EQ(headersSource, headersTarget);
}
{
HttpHeader header;
EXPECT_EQ(-1, header.getContentLength());
header["Content-Length"] = "5";
EXPECT_EQ(5u, header.getContentLength());
}
{
HttpHeader header;
EXPECT_EQ(-1, header.getContentLength());
header["content-Length"] = "5";
EXPECT_EQ(5u, header.getContentLength());
}
{
HttpHeader caseInsentiveHeader;
const String value1 = "value1";
caseInsentiveHeader["field1"] = value1;
EXPECT_EQ(value1, caseInsentiveHeader.getValue("FIELD1"));
EXPECT_EQ(1u, caseInsentiveHeader.getHeaderCount());
caseInsentiveHeader["fiElD1"] = "value1";
EXPECT_EQ(value1, caseInsentiveHeader.getValue("field1"));
EXPECT_EQ(1u, caseInsentiveHeader.getHeaderCount());
EXPECT_TRUE(caseInsentiveHeader.hasHeader("field1"));
EXPECT_TRUE(caseInsentiveHeader.hasHeader("fiElD1"));
caseInsentiveHeader.addHeader("field2", "value2");
EXPECT_EQ(2u, caseInsentiveHeader.getHeaderCount());
caseInsentiveHeader.addHeader("FiELd2", "value2");
EXPECT_EQ(2u, caseInsentiveHeader.getHeaderCount());
EXPECT_TRUE(caseInsentiveHeader.hasHeader("field2"));
EXPECT_TRUE(caseInsentiveHeader.hasHeader("FiELd2"));
caseInsentiveHeader.removeHeader("fiElD1");
EXPECT_EQ(1u, caseInsentiveHeader.getHeaderCount());
caseInsentiveHeader.removeHeader("FiELd2");
EXPECT_EQ(0u, caseInsentiveHeader.getHeaderCount());
EXPECT_FALSE(caseInsentiveHeader.hasHeader("field2"));
EXPECT_FALSE(caseInsentiveHeader.hasHeader("FiELd2"));
}
{
HttpHeader headersSource;
EXPECT_EQ(0u, headersSource.getHeaderCount());
headersSource["field1"] = "value1";
EXPECT_EQ(1u, headersSource.getHeaderCount());
headersSource.addHeader("field1", "value1"); // redundant adding
EXPECT_EQ(1u, headersSource.getHeaderCount());
headersSource.addHeader("field2", "value2");
EXPECT_EQ(2u, headersSource.getHeaderCount());
headersSource.removeHeader("NotFound");
EXPECT_EQ(2u, headersSource.getHeaderCount());
headersSource.removeHeader("field1");
headersSource.removeHeader("field2");
EXPECT_EQ(0, headersSource.getHeaderCount());
}
EXPECT_ALLOC_COUNT_PC_X1_EQ(114u, 114, testCount);
}
#if defined(US_TARGET_WINDOWS)
#pragma warning(disable:4068) // unknown pragma
#pragma BullseyeCoverage save off
#pragma warning(default:4068)
#endif
/// @test Retrieves the user-agent sent from UbiServices and checks it is present and correct
TEST_F(CORE_HTTP_CLIENT, HTTPBOX_CheckUserAgent)
{
Facade facade;
const HttpGet request(TestHelpers_BF::getHttpTestUrl("get"), TestHelpers_BF::getHttpBoxHeader());
const AsyncResult<HttpResponse> result = facade.getHttpClient().sendRequest(request);
ASSERT_TRUE(AsyncHelper::waitSuccess(result));
EXPECT_EQ(RestStatusCode::OK, result.getResult().getStatusCode());
const Json bodyReader(result.getResult().getBodyAsString());
ASSERT_TRUE(bodyReader.isValid());
const Json headersReader = bodyReader["headers"];
ASSERT_TRUE(headersReader.isValid());
const Json userAgentReader = headersReader["User-Agent"];
ASSERT_TRUE(userAgentReader.isValid());
ASSERT_TRUE(userAgentReader.isTypeString());
const String userAgent = userAgentReader.getValueString();
#if defined(US_SDK_S2S)
#if defined(US_UNITY3D)
const StringUrl expectedUserAgent = String::formatText("UbiServices_SDK_Unity_Server_" US_SDK_VERSION_CONST_CHAR "_%s", US_PLATFORM_NAME);
#else
const StringUrl expectedUserAgent = String::formatText("UbiServices_SDK_Server_" US_SDK_VERSION_CONST_CHAR "_%s", US_PLATFORM_NAME);
#endif
#elif defined(US_SDK_LIGHT_MOBILE)
#if defined(US_UNITY3D)
const StringUrl expectedUserAgent = String::formatText("UbiServices_SDK_Unity_Light_Mobile_" US_SDK_VERSION_CONST_CHAR "_%s", US_PLATFORM_NAME);
#else
const StringUrl expectedUserAgent = String::formatText("UbiServices_SDK_Light_Mobile_" US_SDK_VERSION_CONST_CHAR "_%s", US_PLATFORM_NAME);
#endif
#else //Full SDK
#if defined(US_UNITY3D)
const StringUrl expectedUserAgent = String::formatText("UbiServices_SDK_Unity_" US_SDK_VERSION_CONST_CHAR "_%s", US_PLATFORM_NAME);
#else
const StringUrl expectedUserAgent = String::formatText("UbiServices_SDK_" US_SDK_VERSION_CONST_CHAR "_%s", US_PLATFORM_NAME);
#endif
#endif
// Check if the string is found in the retrieved user-agent
// Avoid checking that the full string are equal as libraries may add some prefix or suffix (e.g. PS4)
EXPECT_NE(String::npos, userAgent.findSubstringCase(expectedUserAgent));
PRINT_LINE("User Agent: %s", userAgent.getAnsi().c_str());
}
/// Executes multiple (PARALLEL_COUNT) HTTP requests in parallel
/// (repeating the exercise EXECUTION_COUNT times)
TEST_F(CORE_HTTP_CLIENT, HTTPBOX_ParalleleRequests)
{
const uint32 EXECUTION_COUNT = 10;
const uint32 PARALLEL_COUNT = 6;
Facade facade;
String data;
for(uint32 i = 0; i < 1000; i++)
{
data += "Test";
}
// Force UAT environment. Since there is no login, prod would be used every time
const StringUrl url = TestHelpers_BF::getHttpTestUrl("get");
HttpHeader headers = TestHelpers_BF::getHttpBoxHeader();
headers["DummyData"] = data.getAnsi(); // Sending a large request
for (uint32 count = 0; count < EXECUTION_COUNT; count++)
{
Vector<AsyncResult<HttpResponse> > responses(PARALLEL_COUNT);
for(Vector<AsyncResult<HttpResponse> >::iterator it = responses.begin(); it != responses.end(); ++it)
{
*it = facade.getHttpClient().sendRequest(HttpGet(url, headers));
// FIXME, this does not validate the test. The requests are not truly made in parallel.
#if defined(US_TARGET_XONE)
Helper::sleep(250); // Arbitrary delay attempting to improve success (some requests time out...)
#endif
}
for(Vector<AsyncResult<HttpResponse> >::iterator it = responses.begin(); it != responses.end(); ++it)
{
EXPECT_TRUE((*it).wait());
US_EXPECT_SUCCESS((*it));
EXPECT_TRUE(!(*it).getResult().getBodyAsString().isEmpty());
}
}
}
/// Same test as above, but for SSL requests
TEST_F(CORE_HTTP_CLIENT, HTTPBOX_ParalleleRequestsSecure)
{
const uint32 EXECUTION_COUNT = 10;
const uint32 PARALLEL_COUNT = 6;
Facade facade;
String data;
for(uint32 i = 0; i < 1000; i++)
{
data += "Test";
}
HttpHeader headers = TestHelpers_BF::getHttpBoxHeader();
headers["DummyData"] = data.getAnsi(); //Sending a large request
const HttpGet request(TestHelpers_BF::getHttpTestUrl("get", String(), false, false), headers);
for (uint32 count = 0; count < EXECUTION_COUNT; count++)
{
{
Vector<AsyncResult<HttpResponse> > responses(PARALLEL_COUNT);
for(Vector<AsyncResult<HttpResponse> >::iterator it = responses.begin(); it != responses.end(); ++it)
{
*it = facade.getHttpClient().sendRequest(request);
}
for(Vector<AsyncResult<HttpResponse> >::iterator it = responses.begin(); it != responses.end(); ++it)
{
EXPECT_TRUE((*it).wait());
US_EXPECT_SUCCESS((*it));
EXPECT_TRUE(it->getResult().isSuccessStatusCode());
}
}
}
}
#if !defined(US_DLL)
/* Test the prefix of the the user agent */
TEST_F(CORE_HTTP_CLIENT, HTTP_GetUserAgentPrefix)
{
const String agent = HttpHelper::getUserAgent();
#if defined(US_SDK_S2S)
#if defined(US_UNITY3D)
EXPECT_TRUE(agent.findSubstringCase("UbiServices_SDK_Unity_Server_") == 0);
#else
EXPECT_TRUE(agent.findSubstringCase("UbiServices_SDK_Server_") == 0);
#endif //defined(US_UNITY3D)
#elif defined(US_SDK_LIGHT_MOBILE)
#if defined(US_UNITY3D)
EXPECT_TRUE(agent.findSubstringCase("UbiServices_SDK_Unity_Light_Mobile_") == 0);
#else
EXPECT_TRUE(agent.findSubstringCase("UbiServices_SDK_Light_Mobile_") == 0);
#endif
#else //Full Client SDK
#if defined(US_UNITY3D)
EXPECT_TRUE(agent.findSubstringCase("UbiServices_SDK_Unity_") == 0);
#else
EXPECT_TRUE(agent.findSubstringCase("UbiServices_SDK_") == 0);
#endif //defined(US_UNITY3D)
#endif //defined(US_SDK_S2S)
}
#endif
TEST_F(CORE_HTTP_CLIENT, HTTPBOX_TrafficStatsBasicUpload)
{
Facade facade;
HttpClient& client = facade.getHttpClient();
{
client.resetTrafficStats();
const HttpStatistics stats = client.getTrafficStats();
EXPECT_EQ(0u, stats.getTotalStatistics(HttpTrafficWay::Upload, HttpTrafficType::Http));
EXPECT_EQ(0u, stats.getTotalStatistics(HttpTrafficWay::Download, HttpTrafficType::Http));
EXPECT_EQ(0u, stats.getNbRequest(HttpTrafficType::Http));
}
const StringUrl testUrl = TestHelpers_BF::getHttpTestUrl("put");
const String testBody = "Look at me sexy body! - Fat Bastard";
HttpHeader testHeader = TestHelpers_BF::getHttpContentHeader();
testHeader["dummyKey"] = "dummyValue";
ASSERT_TRUE(AsyncHelper::waitSuccess(facade.getHttpClient().sendRequest(HttpPut(testUrl, testHeader, testBody))));
{
const HttpStatistics stats = client.getTrafficStats();
EXPECT_EQ(1u, stats.getNbRequest(HttpTrafficType::Http));
const uint32 testUploadUrl = stats.getStatistic(HttpTrafficWay::Upload, HttpTrafficType::Http, HttpTrafficStatistic::UrlSize);
const uint32 testUploadHeader = stats.getStatistic(HttpTrafficWay::Upload, HttpTrafficType::Http, HttpTrafficStatistic::HeaderSize);
const uint32 testUploadBody = stats.getStatistic(HttpTrafficWay::Upload, HttpTrafficType::Http, HttpTrafficStatistic::BodySize);
EXPECT_EQ(testUrl.getLength(), testUploadUrl);
EXPECT_EQ(testHeader.getSize(), testUploadHeader);
EXPECT_EQ(testBody.getLength(), testUploadBody);
EXPECT_EQ(testUploadUrl + testUploadHeader + testUploadBody, stats.getTotalStatistics(HttpTrafficWay::Upload, HttpTrafficType::Http));
}
{
client.resetTrafficStats();
const HttpStatistics stats = client.getTrafficStats();
EXPECT_EQ(0u, stats.getTotalStatistics(HttpTrafficWay::Upload, HttpTrafficType::Http));
EXPECT_EQ(0u, stats.getTotalStatistics(HttpTrafficWay::Download, HttpTrafficType::Http));
EXPECT_EQ(0u, stats.getNbRequest(HttpTrafficType::Http));
}
}
#if !defined(US_DLL)
TEST_F(CORE_HTTP_CLIENT, HTTPBOX_TrafficStatsBasicDownload)
{
Facade facade;
HttpClient& client = facade.getHttpClient();
client.resetTrafficStats();
const String receivedData("DUMMY_DATA.");
const size_t uReceivedDataSize = receivedData.getLength();
const String sReceivedDataSize = String::formatText("%d", uReceivedDataSize).getUtf8();
// by using the httpbox "bytes/11" url, the httpbox will send back 11 random bytes
const StringUrl testUrl = TestHelpers_BF::getHttpTestUrl(String(("bytes/") + sReceivedDataSize));
const AsyncResult<HttpResponse> requestAsync = facade.getHttpClient().sendRequest(HttpGet(testUrl, TestHelpers_BF::getHttpBoxHeader()));
EXPECT_TRUE(requestAsync.wait());
US_EXPECT_SUCCESS(requestAsync);
JsonWriter expectedResponseBody;
{
//innacurate but only the body size is important
expectedResponseBody["data"] = receivedData;
}
HttpHeader expectedResponseHeader;
{
//some of the headers values might be innacurate but only the header content size bothers.
expectedResponseHeader["Cache-Control"] = "no-cache";
expectedResponseHeader["Connection"] = "keep-alive";
expectedResponseHeader["Pragma"] = "no-cache";
expectedResponseHeader["Content-Type"] = "application/octet-stream";
expectedResponseHeader["Expires"] = "-1";
expectedResponseHeader["Server"] = "UbiServices Gateway /1.5.0";
expectedResponseHeader["Strict-Transport-Security"] = "max-age=63072000";
expectedResponseHeader["Ubi-Forwarded-By"] = "ue1-d-us-public-nginx-0cc428d17f577b72d msr-dev-us nginx02";
expectedResponseHeader["Ubi-transactionId"] = "e6a31c3e-ab29-4049-aa17-747e80c8d327";
expectedResponseHeader["X-AspNet-Version"] = "4.0.30319";
expectedResponseHeader["X-Powered-By"] = "ASP.NET";
expectedResponseHeader["X-Content-Type-Options"] = "nosniff";
expectedResponseHeader["X-Frame-Options"] = "DENY";
expectedResponseHeader["Date"] = "Fri, 31 Oct 2014 13:07:57 GMT";
expectedResponseHeader["Content-Length"] = sReceivedDataSize;
expectedResponseHeader["ETag"] = "\"786ce1d467b1f7d99e942ad95787b1082c990fc0\"";
EXPECT_EQ(expectedResponseHeader.getSize(), requestAsync.getResult().getAllHeader().getSize());
}
{
const HttpStatistics stats = client.getTrafficStats();
EXPECT_EQ(1u, stats.getNbRequest(HttpTrafficType::Http));
const uint32 testDownloadHeader = stats.getStatistic(HttpTrafficWay::Download, HttpTrafficType::Http, HttpTrafficStatistic::HeaderSize);
const uint32 testDownloadBody = stats.getStatistic(HttpTrafficWay::Download, HttpTrafficType::Http, HttpTrafficStatistic::BodySize);
const uint32 testDownloadedBytes = stats.getTotalStatistics(HttpTrafficWay::Download, HttpTrafficType::Http);
EXPECT_EQ(testDownloadHeader, expectedResponseHeader.getSize());
EXPECT_EQ(testDownloadBody, uReceivedDataSize);
EXPECT_EQ(testDownloadBody + testDownloadHeader, testDownloadedBytes);
}
client.resetTrafficStats();
}
#endif
/// @test Verifies that HTTP requests have all the same behavior when a HTTP timeout occurs
#if !defined(US_DLL)
TEST_F(CORE_HTTP_CLIENT, HTTPBOX_HttpErrorCode)
{
using namespace testing;
struct Helper
{
static AssertionResult sendRequest(HttpClient& client, const HttpRequest& request, uint32 statusCode)
{
HttpRetryConfig retryConfig = HttpRetryConfig(0); /* Disable retry feature */
const AsyncResult<HttpResponse> result = client.sendRequest(request, retryConfig);
if (!result.wait())
{
return ::testing::AssertionFailure() << "Wait failed";
}
if (result.hasFailed())
{
return ::testing::AssertionFailure() << "Async result failed";
}
if (statusCode != result.getResult().getStatusCode())
{
return ::testing::AssertionFailure() << "Response status code is " << result.getResult().getStatusCode() << " , expected " << statusCode;
}
return AssertionSuccess();
}
static AssertionResult performHttpRequests(HttpClient& client, const HttpHeader& header, RestStatusCode::Enum statusCode)
{
{ // GET
const StringUrl url = TestHelpers_BF::getHttpStatusCodeTestUrl(statusCode);
const AssertionResult result = sendRequest(client, HttpGet(url, header), statusCode);
if (!result)
{
return result;
}
}
{ // HEAD
const StringUrl url = TestHelpers_BF::getHttpStatusCodeTestUrl(statusCode);
const AssertionResult result = sendRequest(client, HttpHead(url, header), statusCode);
if (!result)
{
return result;
}
}
{ // POST
const StringUrl url = TestHelpers_BF::getHttpStatusCodeTestUrl(statusCode);
const AssertionResult result = sendRequest(client, HttpPost(url, header, "body"), statusCode);
if (!result)
{
return result;
}
}
{ // PUT
const StringUrl url = TestHelpers_BF::getHttpStatusCodeTestUrl(statusCode);
const AssertionResult result = sendRequest(client, HttpPut(url, header, "body"), statusCode);
if (!result)
{
return result;
}
}
{ // DELETE
const StringUrl url = TestHelpers_BF::getHttpStatusCodeTestUrl(statusCode);
const AssertionResult result = sendRequest(client, HttpDelete(url, header, "body"), statusCode);
if (!result)
{
return result;
}
}
return AssertionSuccess();
}
};
Facade facade;
// JsonWriter writer;
// writer["delete some thing"] = 0;
// // On Xbox One, when we send data with a POST, PUT or DELETE and we receive an error from the server
// // like a 404. The HttpCallback::OnError method get called and in that case we do not have access
// // to the header and status code. It seems that since the data was not sent, the OnError method get called.
// // But if we have nothing to send, it works as expected.
// #if defined(US_TARGET_XONE)
// const String body;
// #else
// const String body = writer.renderContent();
// #endif
HttpClient& client = facade.getHttpClient();
const HttpHeader header = TestHelpers_BF::getHttpContentHeader();
EXPECT_TRUE(Helper::performHttpRequests(client, header, RestStatusCode::OK_202));
EXPECT_TRUE(Helper::performHttpRequests(client, header, RestStatusCode::Error400));
EXPECT_TRUE(Helper::performHttpRequests(client, header, RestStatusCode::Error403));
EXPECT_TRUE(Helper::performHttpRequests(client, header, RestStatusCode::Error500));
EXPECT_TRUE(Helper::performHttpRequests(client, header, RestStatusCode::Error503));
}
TEST_F(CORE_HTTP_CLIENT, HTTPBOX_PerformHttpTimeOut)
{
const ClockSteady::TTimeNano TIMEOUT = 1000; // 1s
HttpRetryConfig retryConfig = HttpRetryConfig(0, HttpRetryConfig::RetryParam(), HttpRetryConfig::TimeoutParam(TIMEOUT));
Facade facade;
const StringUrl url = TestHelpers_BF::getHttpTestUrl("get", String::formatText("delay=%i", 3000));
const AsyncResult<HttpResponse> result = facade.getHttpClient().sendRequest(HttpGet(url, TestHelpers_BF::getHttpBoxHeader()), retryConfig);
EXPECT_TRUE(result.wait());
EXPECT_TRUE(result.hasFailed());
US_EXPECT_FAILURE(result, Errors::HTTP_TIMEOUT);
}
/// @test The download streaming should timeout properly when waiting for client to download next chunk
TEST_F(CORE_HTTP_CLIENT, HTTPBOX_PerformHttpGETStreamTimeoutBeforeNextQuery)
{
// Reducing the timeout threshold since the default 60 sec is a bit long for the test.
const ClockSteady::TTimeNano TIMEOUT = 5000; // 5s
HttpRetryConfig retryConfig = HttpRetryConfig(0, HttpRetryConfig::RetryParam(), HttpRetryConfig::TimeoutParam(TIMEOUT));
Facade facade;
const StringUrl url = TestHelpers_BF::getHttpTestUrl("get");
const uint32 DUMMY_SIZE = 1000u;
HttpStreamContext context;
const HttpStreamPost request(url, DUMMY_SIZE, TestHelpers_BF::getHttpBoxHeader(), context);
AsyncResult<HttpResponse> result = facade.getHttpClient().sendRequest(request, retryConfig);
// Do the streaming
while (result.isProcessing())
{
// Check notifications
HttpStreamNotification::Code notification = context.popNotification();
while (notification != HttpStreamNotification::None)
{
switch (notification)
{
case HttpStreamNotification::BufferToPush: //Do nothing!
case HttpStreamNotification::BufferToPop: //Do nothing!
case HttpStreamNotification::ContentLengthReady:
case HttpStreamNotification::None:
default:
break;
}
notification = context.popNotification();
}
Helper::sleep(50);
}
US_EXPECT_FAILURE(result, Errors::HTTP_TIMEOUT);
}
// NEED CHECK AS THE STATUS CODE CONF DISAPEARED
//// Test that the requests are automatically retried on configured codes : 500, 502, 503 and 504.
//typedef ParamFixture<CORE_HTTP_CLIENT, uint32> CORE_HTTP_RETRY_STATUS_CODE;
//INSTANTIATE_TEST_CASE_P(StatusCode, CORE_HTTP_RETRY_STATUS_CODE, ::testing::Values(500, 502, 503, 504));
//TEST_P(CORE_HTTP_RETRY_STATUS_CODE, HTTPBOX_PerformHttpRetryStatusCodes)
//{
// //HttpEngineConfig& httpEngineConfig = InstancesManager::getInstance()->getHttpEngine().getConfiguration();
// //httpEngineConfig.setMaxRequestRetry(1);
// //httpEngineConfig.setRetryInterval(1000);
// HttpRetryConfig retryConfig = HttpRetryConfig(1, HttpRetryConfig::RetryParam(1000));
//
// Facade facade;
//
// const StringUrl url = TestHelpers_BF::getHttpStatusCodeTestUrl(this->getParam());
//
// Set<uint32> httpCode;
// httpCode.insert(this->getParam());
//
// const AsyncResultBase result = facade.getHttpClient().sendRequest(HttpGet(url, TestHelpers_BF::getHttpBoxHeader(), HttpRetryConfig(httpCode)));
// US_EXPECT_PROPERTY_WAIT(result, AsyncResultBase::isDelayed, true, 1500);
// US_EXPECT_PROPERTY_WAIT(result, AsyncResultBase::getRetryCount, static_cast<uint32>(1), 5000);
//
// EXPECT_TRUE(result.wait());
// EXPECT_TRUE(result.hasSucceeded()) << "The request should be considered successful even if the http code returned is not a 200.";
//
// // Retry count is reset to 0 once the async is complete
// EXPECT_EQ(0u, result.getRetryCount());
//}
/// @test Tests that retry count is 0 on some status codes
typedef ParamFixture<CORE_HTTP_CLIENT, RestStatusCode::Enum> CORE_HTTP_NO_RETRY_STATUS_CODE;
INSTANTIATE_TEST_CASE_P(StatusCode, CORE_HTTP_NO_RETRY_STATUS_CODE, ::testing::Values(RestStatusCode::OK, RestStatusCode::Error403, RestStatusCode::Error501, RestStatusCode::Error508));
TEST_P(CORE_HTTP_NO_RETRY_STATUS_CODE, HTTPBOX_PerformHttpNoRetryStatusCodes)
{
HttpRetryConfig retryConfig = HttpRetryConfig(1);
Facade facade;
const StringUrl url = TestHelpers_BF::getHttpStatusCodeTestUrl(this->getParam());
const AsyncResult<HttpResponse> result = facade.getHttpClient().sendRequest(HttpGet(url, TestHelpers_BF::getHttpBoxHeader()), retryConfig);
EXPECT_TRUE(result.wait());
EXPECT_TRUE(result.hasSucceeded());
EXPECT_EQ(0u, AsyncResultBaseProxy::getRetryCount(result));
}
#endif // DLL
////////////////////////////////////////////////////////////////////////////////
// Cancel tests
/// @test Cancels HTTP requests with various delays.
TEST_P(CORE_HTTP_CANCEL, HTTPBOX_CancelGet)
{
{
TestCanceler<> canceler(this->getParam());
while (!canceler.isComplete())
{
Facade facade;
HttpClient& client = facade.getHttpClient();
// getCount vs. getCompleteCountMax could bring issue since count may be > completeCountMax.
// getCompleteCount vs. getCompleteCountMax should not have any issue, but the progression bar may not progress during several steps
//PRINT_PROGRESS((canceler.m_testConfig.getCompleteCount() + 1), (canceler.m_testConfig.getCompleteCountMax() + 1), "Processing Time Interval: %d ms", canceler.m_testConfig.getTimeInterval());
const StringUrl url(TestHelpers_BF::getHttpTestUrl("get"));
EXPECT_TRUE(canceler.cancel(client.sendRequest(HttpGet(url, TestHelpers_BF::getHttpBoxHeader()))));
}
}
}
/// @test Cancels HTTP requests with various delays.
/// (Normal cancel flow over secure since SSL does some more process)
TEST_P(CORE_HTTP_CANCEL, US_CancelGetSecure)
{
TestCanceler<> canceler(this->getParam());
while (!canceler.isComplete())
{
Facade facade;
HttpClient& client = facade.getHttpClient();
const String urlPath("https://uat-public-ubiservices.ubi.com/v1/applications/{applicationId}/configuration");
const StringUrl url(urlPath.replace("{applicationId}", NS_COMMON::Options::getApplicationId().c_str()));
EXPECT_TRUE(canceler.cancel(client.sendRequest(HttpGet(url, TestHelpers_BF::getHttpBoxHeader()))));
}
}
/// @test Cancels HTTP requests with various delays.
TEST_P(CORE_HTTP_CANCEL, HTTPBOX_CancelHead)
{
TestCanceler<> canceler(this->getParam());
while (!canceler.isComplete())
{
Facade facade;
HttpClient& client = facade.getHttpClient();
EXPECT_TRUE(canceler.cancel(client.sendRequest(HttpHead(TestHelpers_BF::getHttpTestUrl("head"), TestHelpers_BF::getHttpBoxHeader()))));
}
}
/// @test Cancels HTTP requests with various delays.
TEST_P(CORE_HTTP_CANCEL, HTTPBOX_CancelPost)
{
const StringUrl url(TestHelpers_BF::getHttpTestUrl("post"));
TestCanceler<> canceler(this->getParam());
while (!canceler.isComplete())
{
Facade facade;
HttpClient& client = facade.getHttpClient();
EXPECT_TRUE(canceler.cancel(client.sendRequest(HttpPost(url, TestHelpers_BF::getHttpContentHeader(), "In Soviet Russia, queries post you."))));
}
}
/// @test Cancels HTTP requests with various delays.
/// @note Disabled on XB1/2013-08 QFE2 until further investigation
/// (XHTTPRequest::Open failed: -2146697208 [0x800C0008])
/// (HttpCallback::OnError failed: 0x800C000E [INET_E_SECURITY_PROBLEM])
#if defined(US_TARGET_XONE) && (_XDK_VER >= 9837) // Fails on SDK August QFE2
TEST_P(CORE_HTTP_CANCEL, DISABLED_HTTPBOX_CancelPut) // TODO: REVIEW: Disabled for XONE
#else
TEST_P(CORE_HTTP_CANCEL, HTTPBOX_CancelPut)
#endif
{
const StringUrl url(TestHelpers_BF::getHttpTestUrl("put"));
TestCanceler<> canceler(this->getParam());
while (!canceler.isComplete())
{
Facade facade;
HttpClient& client = facade.getHttpClient();
EXPECT_TRUE(canceler.cancel(client.sendRequest(HttpPut(url, TestHelpers_BF::getHttpContentHeader(), "In Soviet Russia, queries delete you."))));
}
}
/// @test Cancels HTTP requests with various delays.
TEST_P(CORE_HTTP_CANCEL, HTTPBOX_CancelDelete)
{
const StringUrl url(TestHelpers_BF::getHttpTestUrl("delete"));
TestCanceler<> canceler(this->getParam());
while (!canceler.isComplete())
{
Facade facade;
HttpClient& client = facade.getHttpClient();
EXPECT_TRUE(canceler.cancel(client.sendRequest(HttpDelete(url, TestHelpers_BF::getHttpBoxHeader(), "In Soviet Russia, queries delete you."))));
}
}
/// @test Cancels HTTP requests with uninit
TEST_P(CORE_HTTP_CANCEL_NO_INIT, HTTPBOX_RequestInProgressUninit)
{
initializeSdk();
class UninitRequestGet : public CancelRequest
{
public:
UninitRequestGet() {}
virtual ~UninitRequestGet() {}
virtual AsyncResultBase launchRequest(Facade& facade)
{
const StringUrl url(TestHelpers_BF::getHttpTestUrl("get"));
return facade.getHttpClient().sendRequest(HttpGet(url, TestHelpers_BF::getHttpBoxHeader()));
}
};
{
TestCanceler<UninitNoLoginHttp> canceler(this->getParam());
UninitRequestGet getRequest;
while (!canceler.isComplete())
{
EXPECT_TRUE(canceler.cancel(getRequest));
}
}
uninitDefaultSDK();
}
/// This case targets a problematic URL. The server is reachable but the URL
/// cannot be resolved and hangs (invalid port).
TEST_P(CORE_HTTP_CANCEL, HTTPBOX_RequestTimeoutHostResolvedUrlHangs)
{
TestConfigCancel& config = this->getParam();
config.setMaxCount(5);
TestCanceler<> canceler(config);
while (!canceler.isComplete())
{
Facade facade;
HttpClient& client = facade.getHttpClient();
EXPECT_TRUE(canceler.cancel(client.sendRequest(HttpGet("http://msr-d-us-iis01.ubisoft.onbe:8001", TestHelpers_BF::getHttpBoxHeader()))));
}
}
/// @test Cancels HTTP requests with various delays.
/// This case targets a slow server. The server is reachable but URL takes time to answer.
TEST_P(CORE_HTTP_CANCEL, HTTPBOX_RequestTimeoutHostResolvedUrlDelayAnswer)
{
const StringUrl url(TestHelpers_BF::getHttpTestUrl("get", "delay=5"));
TestConfigCancel& config = this->getParam();
config.setMaxCount(5);
TestCanceler<> canceler(config);
while (!canceler.isComplete())
{
Facade facade;
HttpClient& client = facade.getHttpClient();
EXPECT_TRUE(canceler.cancel(client.sendRequest(HttpGet(url, TestHelpers_BF::getHttpBoxHeader()))));
}
}
/// @test Sends a long(delayed) request and then, send an immediate request
/// The first request shall still be in progress when the second is finished
TEST_F(CORE_HTTP_CLIENT, HTTPBOX_NonBlockingRequests)
{
Facade facade;
HttpClient& client = facade.getHttpClient();
const StringUrl urlDelayed(TestHelpers_BF::getHttpTestUrl("get", "delay=10"));
const StringUrl urlImmediate(TestHelpers_BF::getHttpTestUrl("get"));
AsyncResult<HttpResponse> resultDelayed = client.sendRequest(HttpGet(urlDelayed, TestHelpers_BF::getHttpBoxHeader()));
EXPECT_TRUE(resultDelayed.isProcessing());
US_TEST_NS::Helper::sleep(500); // Ensure the second request starts after the first one
AsyncResult<HttpResponse> resultImmediate = client.sendRequest(HttpGet(urlImmediate, TestHelpers_BF::getHttpBoxHeader()));
EXPECT_TRUE(resultDelayed.isProcessing());
EXPECT_TRUE(resultImmediate.wait());
EXPECT_TRUE(resultDelayed.isProcessing());
US_EXPECT_SUCCESS(resultImmediate);
EXPECT_TRUE(!resultImmediate.getResult().getBodyAsString().isEmpty());
EXPECT_TRUE(resultDelayed.isProcessing());
resultDelayed.cancel();
EXPECT_TRUE(resultDelayed.wait());
EXPECT_FALSE(resultDelayed.hasSucceeded());
}
/// @test Ensures that cancels are not blocking each other when several requests are pending
TEST_F(CORE_HTTP_CLIENT, HTTPBOX_NonBlockingCancels)
{
Facade facade;
HttpClient& client = facade.getHttpClient();
const StringUrl url1(TestHelpers_BF::getHttpTestUrl("get", "delay=3"));
const StringUrl url2(TestHelpers_BF::getHttpTestUrl("get", "delay=5"));
HighResolutionChrono chrono;
chrono.resetState();
AsyncResult<HttpResponse> result1 = client.sendRequest(HttpGet(url1, TestHelpers_BF::getHttpBoxHeader()));
EXPECT_TRUE(result1.isProcessing());
US_TEST_NS::Helper::sleep(500); // Ensure the second request starts after the first one
AsyncResult<HttpResponse> result2 = client.sendRequest(HttpGet(url2, TestHelpers_BF::getHttpBoxHeader()));
EXPECT_TRUE(result1.isProcessing());
US_TEST_NS::Helper::sleep(500); // Ensure the second request has started
result1.cancel();
// The cancel shall not wait for the first request to finish
EXPECT_LT(chrono.getElapsed(), ClockSteady::getNanoFromMilli(3000));
// The cancel shall not wait for the second request to finish
EXPECT_TRUE(result1.wait());
EXPECT_FALSE(result1.hasSucceeded());
EXPECT_LT(chrono.getElapsed(), ClockSteady::getNanoFromMilli(5000));
// Cancel the next requests to clean the test
result2.cancel();
EXPECT_TRUE(result2.wait());
}
#if !defined(US_DLL)
/// @test Validates that sending a request creation should not block the main thread.
TEST_F(CORE_HTTP_CLIENT, HTTPBOX_NonBlockingMainThreadRequests)
{
Facade facade;
HttpClient& client = facade.getHttpClient();
const StringUrl url(TestHelpers_BF::getHttpTestUrl("get"));
const HttpGet request(url, TestHelpers_BF::getHttpBoxHeader());
const uint32 MAX_ACTIVE_CALL = InstancesManager::getInstance()->getHttpEngine().getConfiguration().getMaxActiveRequest();
Vector<AsyncResult<HttpResponse> > responses(MAX_ACTIVE_CALL);
const uint32 LOOP_COUNT = 10;
for (uint32 i = 0; i < LOOP_COUNT; i++)
{
for(Vector<AsyncResult<HttpResponse> >::iterator it = responses.begin(); it != responses.end(); ++it)
{
HighResolutionChrono chrono;
*it = client.sendRequest(request);
#if defined(US_RETAIL)
EXPECT_LT(chrono.getElapsed(), DurationNano(DurationMilli(2))); // Tolerance delay
#else
EXPECT_LT(chrono.getElapsed(), DurationNano(DurationMilli(15))); // Sanity check since debug/release are very inaccurate
#endif
// Needed to ensure the current request will have been processed before the next request starts
while (!it->isProcessing())
{
Helper::sleep(1);
}
}
for(Vector<AsyncResult<HttpResponse> >::iterator it = responses.begin(); it != responses.end(); ++it)
{
EXPECT_TRUE(it->wait());
}
}
}
#if !defined(US_DLL)
namespace HttpClientImpl_BF
{
extern uint32 s_MAX_CONCURRENT_US_CALLS;
}
#if !defined(US_SDK_S2S)
#if defined(US_TARGET_SWITCH)
// The SWITCH console requires to limit the number of concurrent HTTPS requests (custom or not).
TEST_F(CORE_HTTP_PROXY_X2, HTTPBOX_MaximumRequestsPerFacade)
#else
TEST_F(CORE_HTTP_PROXY_X2, HTTPBOX_Win32MaximumRequestsPerFacade)
#endif
{
const uint32 DELAY = 1;
// Ensure the requests will be launched in parallel by setting a two seconds delay
const StringUrl url(TestHelpers_BF::getHttpTestUrl("get", String::formatText("delay=%d", DELAY)));
Vector<AsyncResult<HttpResponse> > results;
for (uint32 i = 0; i < HttpClientImpl_BF::s_MAX_CONCURRENT_US_CALLS; i++)
{
for (uint32 f = 0; f < getInstancesCount(); f++)
{
results.push_back(getFacade(f).getHttpClient().sendRequest(HttpGet(url, TestHelpers_BF::getHttpBoxHeader())));
}
}
const uint32 CHECKS_PER_SECOND = 10;
uint32 done = 0;
#if defined(US_TARGET_SWITCH)
bool maxReached = false;
#endif
for (int x = 0; x < ((DELAY*10)*CHECKS_PER_SECOND) && done < HttpClientImpl_BF::s_MAX_CONCURRENT_US_CALLS * getInstancesCount(); x++)
{
US_TEST_NS::Helper::sleep(1000/CHECKS_PER_SECOND);
int delayed = 0;
done = 0;
for (Vector<AsyncResult<HttpResponse> >::iterator it = results.begin(); it != results.end(); ++it)
{
if (AsyncResultBaseProxy::isCurrentlyDelayed(*it))
delayed++;
if (it->hasSucceeded() || it->hasFailed())
done++;
}
#if defined(US_TARGET_SWITCH)
maxReached = maxReached || (delayed == HttpClientImpl_BF::s_MAX_CONCURRENT_US_CALLS);
#else
// Not useful, the final ASSERT should detect when MAX_CONCURRENT not reached
// ASSERT_EQ(0u, delayed);
#endif
}
ASSERT_EQ(HttpClientImpl_BF::s_MAX_CONCURRENT_US_CALLS * getInstancesCount(), done);
#if defined(US_TARGET_SWITCH)
ASSERT_TRUE(maxReached);
#endif
}
#endif
#endif
namespace testHttp_BF
{
void validateTimeOutTest(const AsyncResult<HttpResponse>& result, uint32 RETRY_COUNT,
DurationMilli TIMEOUT_INTERVAL_MILLI, DurationMilli TIMEOUT_INCREMENT_MILLI)
{
HighResolutionChrono chrono;
Vector<DurationMilli> deltas;
uint32 previousCount = 0;
DurationMilli startTime = ClockSteady::getTimeMilli();
while (result.isProcessing())
{
const uint32 count = AsyncResultBaseProxy::getRetryCount(result);
if (previousCount != count)
{
deltas.push_back(ClockSteady::getTimeMilli() - startTime);
previousCount = count;
startTime = ClockSteady::getTimeMilli();
}
US_TEST_NS::Helper::sleep(100u);
}
result.wait();
EXPECT_FALSE(result.hasSucceeded());
EXPECT_EQ(RETRY_COUNT, static_cast<uint32>(deltas.size())) << "Must match the max retry count in the parameters.";
EXPECT_EQ(result.getError().m_code, Errors::HTTP_TIMEOUT) << "The final error code should be a timeout.";
ASSERT_EQ(RETRY_COUNT, deltas.size());
for (uint32 i = 1; i < (RETRY_COUNT + 1); i++)
{
#if defined(US_TARGET_IOS)
const uint32 TOLERANCE = 150u;
#else
const uint32 TOLERANCE = 100u;
#endif
EXPECT_GE(deltas.at(i - 1), TIMEOUT_INTERVAL_MILLI + (i*(i - 1)*TIMEOUT_INCREMENT_MILLI) - TOLERANCE);
EXPECT_LT(deltas.at(i - 1), TIMEOUT_INTERVAL_MILLI + (i*(i - 0)*TIMEOUT_INCREMENT_MILLI) + TOLERANCE);
}
}
}
/// @test Checks that HTTP timeout is actually increased by the right value at each retry.
/// In this test, the timeout parameters should be taken from the local HTTP timeout config
TEST_F(CORE_HTTP_CLIENT, HTTPBOX_TestIncrementalTimeoutPerRequestConfig)
{
PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device)
{
US_EXPECT_LOG("HttpTimeoutComponent request timeout after 0 sec", LogLevel::Error, Times(1));
US_EXPECT_LOG("HttpTimeoutComponent request timeout after 1 sec", LogLevel::Error, Times(1));
US_EXPECT_LOG("HttpTimeoutComponent request timeout after 2 sec", LogLevel::Error, Times(1));
US_EXPECT_LOG("HttpTimeoutComponent request timeout after 3 sec", LogLevel::Error, Times(1));
});
Facade facade;
const uint32 RETRY_COUNT = 3;
const DurationMilli TIMEOUT_INTERVAL = 500u;
const DurationMilli TIMEOUT_INCREMENT = 250u;
HttpRetryConfig retryConfig(RETRY_COUNT,
HttpRetryConfig::RetryParam(0, 0, 0),
HttpRetryConfig::TimeoutParam(TIMEOUT_INTERVAL, TIMEOUT_INCREMENT));
const StringUrl url = TestHelpers_BF::getHttpTestUrl("get", "delay=1000"); //delay so high we don't care about it.
testHttp_BF::validateTimeOutTest(facade.getHttpClient().sendRequest(
HttpGet(url), retryConfig), RETRY_COUNT, TIMEOUT_INTERVAL, TIMEOUT_INCREMENT);
}
#if defined(US_TARGET_WINDOWS)
/// @test Checks that HTTP timeout is actually increased by the right value at each retry
/// In this test, the timeout parameters should be taken from the custom HTTP timeout config
#if defined(US_SDK_S2S) || defined(US_CHINA_ACCOUNTS_SETUP_NOT_DONE)
/// @disabled Test disabled on S2S because the us-sdkServerSettingsHttpGame (or any server group) is not set up on the portal
TEST_F(CORE_HTTP_NO_INIT, DISABLED_US_TestIncrementalTimeoutFromConfigCustom)
#else
TEST_F(CORE_HTTP_NO_INIT, US_TestIncrementalTimeoutFromConfigCustom)
#endif
{
initializeSdk();
// This applicationId has the following HTTP custom config
// httpParam : {
// maxCount : 2,
// RetryParam : {
// initialDelayMsec : 0,
// incrementFactorMsec : 0,
// randomDelayMsec : 0
// },
// TimeoutParam : {
// initialDelayMsec : 1000,
// incrementFactorMsec : 1000
// }
// }
{
const GameConfig gameConfig(
ApplicationId(US_TEST_NS::APP_ID_US_SDK_SPECIAL_TESTS_PC),
NS_COMMON::Options::getApplicationBuildId().c_str()
#if defined(US_SDK_S2S)
, NS_COMMON::Options::environment()
#endif
, OnlineAccessContext::Standard
#if !defined(US_SDK_S2S)
, GameConfigEvent(String(), US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector<EventTypeInfo>())
#endif
);
configureSdk(gameConfig);
{
SmartPtr<FacadeInternal> facade(US_NEW(FacadeInternal));
#if defined(US_SDK_S2S)
AsyncResult<Empty> resultLogin = facade->createSession(S2S_SECRET, {}, {});
#else
AsyncResult<Empty> resultLogin = facade->createSession(GET_CREDENTIALS(), {}, {});
#endif
EXPECT_TRUE(AsyncHelper::waitSuccess(resultLogin));
const ParametersSettingsHttpGame& httpCustomParam = ParametersClientProxy::getParametersInfo(*facade).m_paramsSettingsHttpGame;
const StringUrl url = TestHelpers_BF::getHttpTestUrl("get", "delay=1000"); //delay so high we don't shouldn't care about it.
testHttp_BF::validateTimeOutTest(facade->getHttpClient().sendRequest(HttpGet(url)),
httpCustomParam.m_maxCount, httpCustomParam.m_timeoutInitialDelayMsec.getCount(),
httpCustomParam.m_timeoutIncrementFactorMsec.getCount());
}
}
US_TEST_NS::Helper::uninitializeSdk();
}
#endif
typedef ParamFixture<CORE_HTTP, RestStatusCode::Enum> CORE_HTTP_CLIENT_SERVICES_RETRY_CODE;
INSTANTIATE_TEST_CASE_P(StatusCode, CORE_HTTP_CLIENT_SERVICES_RETRY_CODE, ::testing::Values(
RestStatusCode::Error500, RestStatusCode::Error502, RestStatusCode::Error503, RestStatusCode::Error504));
/// @test Validates that request are retried when the service returns specific HTTP status codes.
TEST_P(CORE_HTTP_CLIENT_SERVICES_RETRY_CODE, LOCAL_UbiServicesRetryHandler)
{
const uint32 MAX_RETRY_COUNT = 3;
HttpRequestContext context = MockHttpRequest_BF::createDummyContext(HttpMethod::HTTP_POST, US_NEW(HttpStringEntity), US_NEW(HttpStringEntity));
context.setStatusCode(this->getParam());
const_cast<HttpRetryConfig&>(const_cast<HttpRetryHandler&>(context.getRetryHandler()).getRetryConfig()).m_retryCount = MAX_RETRY_COUNT;
const HttpRetryHandler handler(context.getRetryHandler().getRetryConfig(), true);
ASSERT_TRUE(handler.isValid(context));
uint32 retryCount = 0;
while (handler.processRequestRetry(context))
{
retryCount++;
}
EXPECT_EQ(retryCount, MAX_RETRY_COUNT);
}
/// @test No retry should be performed if the server returns a status code 503
TEST_F(CORE_HTTP, LOCAL_UbiServicesRetryHandlerRest503status5003)
{
const uint32 MAX_RETRY_COUNT = 3;
const String restErrorBody = MockResultHelper::createRestErrorResult(RestStatusCode::Error503, 5003u).getResult().getBodyAsString();
HttpStringEntity* responseData = US_NEW(HttpStringEntity);
responseData->setBody(restErrorBody);
HttpRequestContext context = MockHttpRequest_BF::createDummyContext(HttpMethod::HTTP_POST, US_NEW(HttpStringEntity), responseData);
const_cast<HttpRetryConfig&>(const_cast<HttpRetryHandler&>(context.getRetryHandler()).getRetryConfig()).m_retryCount = MAX_RETRY_COUNT;
context.setStatusCode(RestStatusCode::Error503);
const HttpRetryHandler handler(context.getRetryHandler().getRetryConfig(), true);
ASSERT_TRUE(handler.isValid(context));
uint32 retryCount = 0;
while (handler.processRequestRetry(context))
{
retryCount++;
}
EXPECT_EQ(0u, retryCount) << "We shouldn't retry on a services with HTTP 503 code with a rest code 5003.";
}
typedef ParamFixture<CORE_HTTP, RestStatusCode::Enum> CORE_HTTP_CLIENT_SERVICES_NO_RETRY_CODE;
INSTANTIATE_TEST_CASE_P(StatusCode, CORE_HTTP_CLIENT_SERVICES_NO_RETRY_CODE, ::testing::Values(
RestStatusCode::Error400,RestStatusCode::Error401, RestStatusCode::Error402, RestStatusCode::Error403,
RestStatusCode::Error404, RestStatusCode::Error405, RestStatusCode::Error407, RestStatusCode::Error409,
RestStatusCode::Error413, RestStatusCode::Error414, RestStatusCode::Error418, RestStatusCode::Error429));
/// @test Validates that request are not retried when the service returns specific HTTP status codes.
TEST_P(CORE_HTTP_CLIENT_SERVICES_NO_RETRY_CODE, LOCAL_UbiServicesRetryHandler)
{
const uint32 MAX_RETRY_COUNT = 3;
HttpRequestContext context = MockHttpRequest_BF::createDummyContext(HttpMethod::HTTP_POST, US_NEW(HttpStringEntity), US_NEW(HttpStringEntity));
const_cast<HttpRetryConfig&>(const_cast<HttpRetryHandler&>(context.getRetryHandler()).getRetryConfig()).m_retryCount = MAX_RETRY_COUNT;
context.setStatusCode(this->getParam());
const HttpRetryHandler handler(context.getRetryHandler().getRetryConfig(), true);
ASSERT_TRUE(handler.isValid(context));
uint32 retryCount = 0;
while (handler.processRequestRetry(context))
{
retryCount++;
}
EXPECT_EQ(0u, retryCount) << "No retry is expected on the http code : " << this->getParam();
}
#endif // US_DLL
#if defined(US_TARGET_WINDOWS)
#pragma warning(disable:4068) // unknown pragma
#pragma BullseyeCoverage restore
#pragma warning(default:4068)
#endif
};