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

267 lines
No EOL
12 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour //
////////////////////////////////////////////////////////////////////////////////
// TrafficStatistics cannot be accessed in DLL.
#include "tests/config.h"
#include "tests/fixture/memoryCheckFixture.h"
#include "testsUnit/mock/mockHttpEngine.h"
#include <ubiservices/core/chrono/chronometer.h>
#include <ubiservices/core/helpers/instancesManager.h>
#include <ubiservices/core/helpers/trafficStatistics.h>
#include <ubiservices/core/http/httpEngine.h>
#include <ubiservices/core/http/jobs/jobHttpRequest.h> // WARNING: This includes "configpriv.h"
#include <ubiservices/core/tasks/asyncResultInternal.h>
#include <ubiservices/facadeInternal.h>
#include <ubiservices/services/http/httpResponse.h>
#include <ubiservices/services/http/request/httpGet.h>
#include <ubiservices/services/http/request/httpPost.h>
#include <ubiservices/services/http/httpStatistics.h>
namespace US_NS {;
US_DEFINE_TEST(TestJobHttpRequest);
};
#define DUMMY_URL "dummy"
#if !defined(US_DLL)
namespace US_NS {;
typedef LeakChecker CORE_JOB_HTTP_REQUEST_MOCK;
namespace TestJobHttpRequest_BF
{
void waitForRequestCreation(HttpRequestInternal* request)
{
const uint32 MAX_SLEEP_ITERATIONS = 50;
uint32 currentSleepIteration = 0;
while (request == NULL && currentSleepIteration < MAX_SLEEP_ITERATIONS)
{
Helper::sleep(100);
currentSleepIteration++;
}
EXPECT_LT(currentSleepIteration, MAX_SLEEP_ITERATIONS) << "The request was not created";
}
}
TEST_F(CORE_JOB_HTTP_REQUEST_MOCK, LOCAL_RequestSuccess)
{
using namespace testing;
MockHttpEngineImpl* engineImpl = MockHttpEngine_BF::getMockHttpEngineInit(1);
HttpEngine* engine = US_NEW(HttpEngine, engineImpl);
InstancesManager::getInstance()->replaceHttpEngine(engine);
HttpConfig httpConfig;
engine->initialize(httpConfig);
DummyRequest* dummyRequest = nullptr;
EXPECT_CALL(*engineImpl, createRequest(_)).WillOnce(MockActionHttpEngine_BF::CreateRequestSetPtr<DummyRequest>(&dummyRequest));
AsyncResultInternal<HttpResponse> response(US_WHERE());
SmartPtr<TrafficStatistics> stats = US_NEW(TrafficStatistics);
SmartPtr<FacadeInternal> facade = US_NEW(FacadeInternal); // No need to retrieve a "real" facadeInternal here
response.startTask(US_NEW(JobHttpRequest, response, *facade, HttpGet(DUMMY_URL), HttpRetryHandler(HttpRetryConfig(0u)), stats));
response.wait(250); // Ensure the waiting step has been reached
TestJobHttpRequest_BF::waitForRequestCreation(dummyRequest);
if (dummyRequest != NULL)
{
dummyRequest->setToSuccess();
response.wait();
US_EXPECT_SUCCESS(response);
US_EXPECT_PROPERTY_WAIT(engine, HttpEngine::getNumberOfRequests, static_cast<size_t>(0u), US_WAIT_MOCK_PROPERTY_DEFAULT_TIME);
}
}
TEST_F(CORE_JOB_HTTP_REQUEST_MOCK, LOCAL_RequestFailure)
{
using namespace testing;
MockHttpEngineImpl* engineImpl = MockHttpEngine_BF::getMockHttpEngineInit(1);
HttpEngine* engine = US_NEW(HttpEngine, engineImpl);
InstancesManager::getInstance()->replaceHttpEngine(engine);
// Disable retry feature
HttpConfig httpConfig;
//httpConfig.setMaxRequestRetry(0);
engine->initialize(httpConfig);
HttpRetryConfig retryConfig(0);
DummyRequest* dummyRequest = NULL;
EXPECT_CALL(*engineImpl, createRequest(_)).WillOnce(MockActionHttpEngine_BF::CreateRequestSetPtr<DummyRequest>(&dummyRequest));
AsyncResultInternal<HttpResponse> response(US_WHERE());
SmartPtr<TrafficStatistics> stats = US_NEW(TrafficStatistics);
SmartPtr<FacadeInternal> facade = US_NEW(FacadeInternal); // No need to retrieve a "real" facadeInternal here
response.startTask(US_NEW(JobHttpRequest, response, *facade, HttpGet(DUMMY_URL), HttpRetryHandler(retryConfig), stats));
response.wait(250); // Ensure the waiting step has been reached
TestJobHttpRequest_BF::waitForRequestCreation(dummyRequest);
if (dummyRequest != NULL)
{
HttpRequestError error(Errors::HTTP_REQUEST_TRANSFER_FAILURE, "generic failure");
dummyRequest->setToError(error);
response.wait();
US_EXPECT_FAILURE(response, Errors::HTTP_REQUEST_TRANSFER_FAILURE);
US_EXPECT_PROPERTY_WAIT(engine, HttpEngine::getNumberOfRequests, static_cast<size_t>(0u), US_WAIT_MOCK_PROPERTY_DEFAULT_TIME);
}
}
TEST_F(CORE_JOB_HTTP_REQUEST_MOCK, LOCAL_RequestCancel)
{
using namespace testing;
MockHttpEngineImpl* engineImpl = MockHttpEngine_BF::getMockHttpEngineInit(1);
HttpEngine* engine = US_NEW(HttpEngine, engineImpl);
InstancesManager::getInstance()->replaceHttpEngine(engine);
HttpConfig httpConfig;
engine->initialize(httpConfig);
DummyRequest* dummyRequest = NULL;
EXPECT_CALL(*engineImpl, createRequest(_)).WillOnce(MockActionHttpEngine_BF::CreateRequestSetPtr<DummyRequest>(&dummyRequest));
AsyncResultInternal<HttpResponse> response(US_WHERE());
SmartPtr<TrafficStatistics> stats = US_NEW(TrafficStatistics);
SmartPtr<FacadeInternal> facade = US_NEW(FacadeInternal); // No need to retrieve a "real" facadeInternal here
response.startTask(US_NEW(JobHttpRequest, response, *facade, HttpGet(DUMMY_URL), HttpRetryHandler(HttpRetryConfig(0u)), stats));
response.wait(250); // Ensure the waiting step has been reached
TestJobHttpRequest_BF::waitForRequestCreation(dummyRequest);
if (dummyRequest != NULL)
{
// The context shall be retrieved before the call to cancel
// in order to increase its number of reference on the context and avoid its deletion during the cancel.
HttpRequestContext requestContext = dummyRequest->getRequestContext();
response.cancel();
US_EXPECT_PROPERTY_WAIT(requestContext, HttpRequestContext::isCanceled, true, US_WAIT_MOCK_PROPERTY_DEFAULT_TIME);
US_EXPECT_FAILURE(response, Errors::CANCELED);
US_EXPECT_PROPERTY_WAIT(engine, HttpEngine::getNumberOfRequests, static_cast<size_t>(0u), US_WAIT_MOCK_PROPERTY_DEFAULT_TIME);
}
}
#if !defined(US_TARGET_ANDROID)
///@test Validate that cancelling a request isn't locking the thread if the httpEngine lags somewhere it it's processing.
TEST_F(CORE_JOB_HTTP_REQUEST_MOCK, LOCAL_RequestCancelNonBlockingCallingThread)
{
using namespace testing;
class Local
{
public:
Local()
: m_invokeCalled(false)
{}
HttpEngineComponent::State invokeProcessRequestImpl(uint32 contextHandle, HttpRequestContext& request)
{
US_UNUSED(contextHandle);
US_UNUSED(request);
m_invokeCalled = true;
Helper::sleep(200);
return HttpEngineComponent::Finish;
}
bool isInvokedCalled() const
{
return m_invokeCalled;
}
private:
volatile bool m_invokeCalled;
};
Local testInvoker;
MockHttpEngineImpl* engineImpl = MockHttpEngine_BF::getMockHttpEngineInitComponentTest();
HttpEngine* engine = US_NEW(HttpEngine, engineImpl);
MockHttpEngineComponent* mockComponent = US_NEW(MockHttpEngineComponent, HttpEngineComponent::Controller);
EXPECT_CALL(*engineImpl, configureEngineComponents(_)).WillOnce(MockActionHttpEngine_BF::SetHttpComponent(mockComponent));
// This validate the state of the request, when the components are notified
Expectation expectCreate = EXPECT_CALL(*mockComponent,
onCreateImpl(Property(&HttpRequestContext::getRequestState, HttpRequestState::Init))).Times(1);
// When the mock component return HttpEngineComponent::Finish the request should be completed since this is the only component
Expectation expectProcess = EXPECT_CALL(*mockComponent,
processRequestImpl(_, Property(&HttpRequestContext::getRequestState, HttpRequestState::Processing))).WillOnce(Invoke(&testInvoker, &Local::invokeProcessRequestImpl));
HttpConfig httpConfig;
engine->initialize(httpConfig);
InstancesManager::getInstance()->replaceHttpEngine(engine);
{
const StringUrl dummyUrl = "http://dummy.dummy.dm";
const String dummyBody = "DummyBody DummyBody DummyBody";
SmartPtr<TrafficStatistics> stats = US_NEW(TrafficStatistics);
AsyncResultInternal<HttpResponse> response(US_WHERE());
SmartPtr<FacadeInternal> facade = US_NEW(FacadeInternal); // No need to retrieve a "real" facadeInternal here
response.startTask(US_NEW(JobHttpRequest, response, *facade, HttpPost(dummyUrl, dummyBody), HttpRetryHandler(HttpRetryConfig(0u)), stats));
US_EXPECT_PROPERTY_WAIT(static_cast<const AsyncResultBase&>(response), AsyncResultBase::isProcessing, true, US_WAIT_MOCK_PROPERTY_DEFAULT_TIME);
US_EXPECT_PROPERTY_WAIT(testInvoker, Local::isInvokedCalled, true, US_WAIT_MOCK_PROPERTY_DEFAULT_TIME);
HighResolutionChrono chrono;
response.cancel();
const ClockSteady::TTimeNano elapsed = chrono.getElapsed();
EXPECT_LT(elapsed, ClockSteady::getNanoFromMilli(1)) << "The cancel of the request should not block the main thread.";
}
}
#endif
TEST_F(CORE_JOB_HTTP_REQUEST_MOCK, LOCAL_RequestStatUpdates)
{
using namespace testing;
MockHttpEngineImpl* engineImpl = MockHttpEngine_BF::getMockHttpEngineInit(1);
HttpEngine* engine = US_NEW(HttpEngine, engineImpl);
InstancesManager::getInstance()->replaceHttpEngine(engine);
HttpConfig httpConfig;
engine->initialize(httpConfig);
DummyRequest* dummyRequest = NULL;
EXPECT_CALL(*engineImpl, createRequest(_)).WillOnce(MockActionHttpEngine_BF::CreateRequestSetPtr<DummyRequest>(&dummyRequest));
AsyncResultInternal<HttpResponse> response(US_WHERE());
SmartPtr<TrafficStatistics> stats = US_NEW(TrafficStatistics);
SmartPtr<FacadeInternal> facade = US_NEW(FacadeInternal); // No need to retrieve a "real" facadeInternal here
const StringUrl dummyUrl = "http://dummy.dummy.dm";
const String dummyBody = "DummyBody DummyBody DummyBody";
response.startTask(US_NEW(JobHttpRequest, response, *facade, HttpPost(dummyUrl, dummyBody), HttpRetryHandler(HttpRetryConfig(0u)), stats));
response.wait(250); // Ensure the waiting step has been reached
TestJobHttpRequest_BF::waitForRequestCreation(dummyRequest);
if (dummyRequest != NULL)
{
HttpRequestContext requestContext = dummyRequest->getRequestContext();
requestContext.getStats().incrementByteSent(dummyBody.getLength());
const uint32 RECEIVED_BODY_LENGTH = 5u;
requestContext.getStats().incrementByteReceived(RECEIVED_BODY_LENGTH);
dummyRequest->setToSuccess();
response.wait();
US_EXPECT_SUCCESS(response);
US_EXPECT_PROPERTY_WAIT(engine, HttpEngine::getNumberOfRequests, static_cast<size_t>(0u), US_WAIT_MOCK_PROPERTY_DEFAULT_TIME);
EXPECT_EQ(1u, stats->getNbRequests(static_cast<int32>(HttpTrafficWay::Upload), static_cast<int32>(HttpTrafficType::Http)));
EXPECT_EQ(dummyUrl.getLength(), stats->getStatistic(static_cast<int32>(HttpTrafficWay::Upload), static_cast<int32>(HttpTrafficType::Http), static_cast<int32>(HttpTrafficStatistic::UrlSize)));
EXPECT_EQ(dummyBody.getLength(), stats->getStatistic(static_cast<int32>(HttpTrafficWay::Upload), static_cast<int32>(HttpTrafficType::Http), static_cast<int32>(HttpTrafficStatistic::BodySize)));
EXPECT_EQ(RECEIVED_BODY_LENGTH, stats->getStatistic(static_cast<int32>(HttpTrafficWay::Download), static_cast<int32>(HttpTrafficType::Http), static_cast<int32>(HttpTrafficStatistic::BodySize)));
}
}
};
#endif