267 lines
No EOL
12 KiB
C++
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 |