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

326 lines
No EOL
15 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour //
////////////////////////////////////////////////////////////////////////////////
#include "tests/config.h"
#include "tests/common/helpers.h"
#include "tests/fixture/memoryCheckFixture.h"
#include "testsUnit/http/ps4/mockHttpPs4Impl.h"
#include "testsUnit/mock/mockHttpRequest.h"
#include <ubiservices/core/configs/configpriv.h>
#include <ubiservices/core/http/httpEngineConfig.h>
#include <ubiservices/core/http/httpEntityReader.h>
#include <ubiservices/core/http/ps4/httpEnginePs4.h>
#include <ubiservices/core/http/ps4/httpRequestPs4.h>
#include <ubiservices/services/http/httpConfig.h>
#include <libhttp.h>
namespace US_NS {;
US_DEFINE_TEST(TestHttpEnginePS4);
};
#if !defined(US_DLL)
namespace US_NS {;
typedef LeakChecker HTTP_ENGINE_PS4_MOCK;
namespace TestHttpEnginePs4_BF
{
void checkKeepAlive(const String serializedHeaders, bool isKeepAliveExpected)
{
using namespace testing;
MockHttpPs4Impl* ps4Impl = US_NEW(MockHttpPs4Impl);
const SceInt32 sceHttpId = 3u;
MockHttpPs4Impl_BF::setEngineExpectations(*ps4Impl, sceHttpId);
{
HttpEnginePs4 enginePs4(ps4Impl);
EXPECT_TRUE(enginePs4.initialize(HttpEngineConfig()));
const SceInt32 sceConnectionId = 5u;
EXPECT_CALL(*ps4Impl, sceHttpCreateConnectionWithURL(_,_,_)).WillOnce(Return(sceConnectionId));
HttpRequestContext requestContext = MockHttpRequest_BF::createDummyContext();
const SceInt32 sceRequestId = 6u;
MockHttpPs4Impl_BF::setRequestInitExpectations(*ps4Impl, sceConnectionId, sceRequestId);
HttpRequestInternal* internalRequest = enginePs4.createRequest(requestContext);
HttpRequestPs4* request = reinterpret_cast<HttpRequestPs4*>(internalRequest);
EXPECT_CALL(*ps4Impl, sceHttpSendRequest(sceRequestId,_,_)).WillRepeatedly(Return(SCE_OK));
request->executeStep(); // stepSendRequest
EXPECT_CALL(*ps4Impl, sceHttpGetResponseContentLength(sceRequestId,_,_)).WillOnce(DoAll(
SetArgPointee<1>(SCE_HTTP_CONTENTLEN_EXIST), SetArgPointee<2>(0), Return(SCE_OK)));
request->executeStep(); // stepResponseContentLength
EXPECT_CALL(*ps4Impl, sceHttpGetAllResponseHeaders(sceRequestId,_,_)).WillOnce(DoAll(
SetArgPointee<1>(const_cast<char*>(serializedHeaders.getUtf8())), SetArgPointee<2>(serializedHeaders.getLength() + 1), Return(SCE_OK)));
EXPECT_CALL(*ps4Impl, sceHttpGetStatusCode(_,_)).WillOnce(Return(SCE_OK));
// The request should have been deleted in the previous step (all data have been downloaded)
// Ensure here that the request is not deleted after the last call to stepDownloadData
MockHttpPs4Impl_BF::setRequestReleaseExpectations(*ps4Impl, sceRequestId);
request->executeStep(); // stepGetAllResponseHeaders
request->executeStep(); // stepParseResponseHeaders
// Check that the connection is not using keep alive
EXPECT_EQ(isKeepAliveExpected, request->isConnectionAlive()) << "keepAlive status is wrong for headers : \"" << serializedHeaders << "\"";
// If keep alive is disabled, the connection shall be closed as soon as the request is released
// Otherwise, in this test, the connection is closed only when the engine is shut down (close all connections)
// So the call to sceHttpDeleteConnection is checked before and after the release of the request
if (isKeepAliveExpected)
{
EXPECT_CALL(*ps4Impl, sceHttpDeleteConnection(sceConnectionId)).Times(0);
}
else
{
EXPECT_CALL(*ps4Impl, sceHttpDeleteConnection(sceConnectionId)).WillOnce(Return(SCE_OK));
}
// Request is not delete automatically by the engine implementation but by HttpEngine components
enginePs4.releaseRequest(internalRequest);
if (isKeepAliveExpected)
{
EXPECT_CALL(*ps4Impl, sceHttpDeleteConnection(sceConnectionId)).WillOnce(Return(SCE_OK));
}
else
{
EXPECT_CALL(*ps4Impl, sceHttpDeleteConnection(sceConnectionId)).Times(0);
}
enginePs4.shutdown();
}
}
}
// Validate request creation when sceHttpCreateConnectionWithURL succeeds
TEST_F(HTTP_ENGINE_PS4_MOCK, LOCAL_CreateRequestSuccess)
{
using namespace testing;
MockHttpPs4Impl* ps4Impl = US_NEW(MockHttpPs4Impl);
MockHttpPs4Impl_BF::setEngineExpectations(*ps4Impl);
{
HttpEnginePs4 enginePs4(ps4Impl);
EXPECT_TRUE(enginePs4.initialize(HttpEngineConfig()));
const SceInt32 connectionId = 1;
EXPECT_CALL(*ps4Impl, sceHttpCreateConnectionWithURL(_,_,_)).WillOnce(Return(connectionId));
MockHttpPs4Impl_BF::setRequestExpectations(*ps4Impl, connectionId);
HttpRequestContext requestContext = MockHttpRequest_BF::createDummyContext();
HttpRequestInternal* internalRequest = enginePs4.createRequest(requestContext);
// Request is not delete automatically by the engine implementation but by HttpEngine components
enginePs4.releaseRequest(internalRequest);
EXPECT_CALL(*ps4Impl, sceHttpDeleteConnection(connectionId)).WillOnce(Return(SCE_OK));
enginePs4.shutdown();
}
}
// Validate request creation when connection creation fails
TEST_F(HTTP_ENGINE_PS4_MOCK, LOCAL_CreateConnectionError)
{
using namespace testing;
MockHttpPs4Impl* ps4Impl = US_NEW(MockHttpPs4Impl);
MockHttpPs4Impl_BF::setEngineExpectations(*ps4Impl);
{
HttpEnginePs4 enginePs4(ps4Impl);
EXPECT_TRUE(enginePs4.initialize(HttpEngineConfig()));
EXPECT_CALL(*ps4Impl, sceHttpCreateConnectionWithURL(_,_,_)).WillOnce(Return(SCE_HTTP_ERROR_INSUFFICIENT_STACKSIZE));
HttpRequestContext requestContext = MockHttpRequest_BF::createDummyContext();
HttpRequestInternal* internalRequest = enginePs4.createRequest(requestContext);
// Make sure that the request is not created
EXPECT_EQ(nullptr, internalRequest);
enginePs4.shutdown();
}
}
// Validate request creation when the SCE Http API is initialized by the user
TEST_F(HTTP_ENGINE_PS4_MOCK, LOCAL_CreateRequestApiInitByUser)
{
using namespace testing;
const SceInt32 userHttpId = 8; // Arbitrary value (> 0)
HttpEngineConfigPs4 engineConfig;
engineConfig.setLibHttpContextId(userHttpId);
MockHttpPs4Impl* ps4Impl = US_NEW(MockHttpPs4Impl);
MockHttpPs4Impl_BF::setEngineExpectationsUserHttpId(*ps4Impl, userHttpId);
{
HttpEnginePs4 enginePs4(ps4Impl);
EXPECT_TRUE(enginePs4.initialize(engineConfig));
const SceInt32 connectionId = 1; // Arbitrary value (> 0)
EXPECT_CALL(*ps4Impl, sceHttpCreateConnectionWithURL(_,_,_)).WillOnce(Return(connectionId));
MockHttpPs4Impl_BF::setRequestExpectations(*ps4Impl, connectionId);
HttpRequestContext requestContext = MockHttpRequest_BF::createDummyContext();
HttpRequestInternal* internalRequest = enginePs4.createRequest(requestContext);
// Request is not delete automatically by the engine implementation but by HttpEngine components
enginePs4.releaseRequest(internalRequest);
EXPECT_CALL(*ps4Impl, sceHttpDeleteConnection(connectionId)).WillOnce(Return(SCE_OK));
enginePs4.shutdown();
}
}
// Validate parameters sent to the initialize of a request
TEST_F(HTTP_ENGINE_PS4_MOCK, LOCAL_CreateRequestInitializeParameters)
{
using namespace testing;
// Parameters that should be sent by the engine in the initialize method
const SceInt32 sceHttpId = 8; // Arbitrary value (> 0)
const SceInt32 sceConnectionId = 5; // Arbitrary value (> 0)
const uint32 maxBufferSize = 10u;
const bool validateCerts = false;
HttpEngineConfigPs4 engineConfig;
engineConfig.setTransferBufferSize(maxBufferSize);
engineConfig.setValidateCerts(validateCerts);
MockHttpPs4Impl* ps4Impl = US_NEW(MockHttpPs4Impl);
MockHttpPs4Impl_BF::setEngineExpectations(*ps4Impl, sceHttpId);
{
HttpEnginePs4 enginePs4(ps4Impl);
EXPECT_TRUE(enginePs4.initialize(engineConfig));
EXPECT_CALL(*ps4Impl, sceHttpCreateConnectionWithURL(_,_,_)).WillOnce(Return(sceConnectionId));
// Force an url that should be validated
const String requestBody = "You wouldn't have won if we'd beaten you";
HttpStringEntity* requestEntity = US_NEW(HttpStringEntity, requestBody);
HttpBinaryEntity* responseEntity = US_NEW(HttpBinaryEntity);
HttpRequestContext requestContext = MockHttpRequest_BF::createDummyContext(HttpMethod::HTTP_POST, requestEntity, responseEntity);
const String url = "https://ubiservices.ubi.com/";
requestContext.getRequestData().m_url = url;
// Request expectations
const SceInt32 sceRequestId = 6;
{
// Check the validateCerts parameter (url should be validated, but the validateCerts tells to avoid checking)
Expectation httpsDisable = EXPECT_CALL(*ps4Impl, sceHttpsEnableOption(sceConnectionId,SCE_HTTPS_FLAG_SERVER_VERIFY)).WillOnce(Return(SCE_OK));
// Check the connectionId parameter
Expectation createRequest = EXPECT_CALL(*ps4Impl, sceHttpCreateRequestWithURL2(sceConnectionId, _, StrEq(url.getUtf8()), _)).After(httpsDisable).WillOnce(Return(sceRequestId));
Expectation setNonBlock = EXPECT_CALL(*ps4Impl, sceHttpSetNonblock(sceRequestId,SCE_TRUE)).After(createRequest).WillOnce(Return(SCE_OK));
SceHttpEpollHandle eh = reinterpret_cast<SceHttpEpollHandle>(1); // arbitrary value to ensure eh will not be null
// Check the httpId parameter
Expectation createEpoll = EXPECT_CALL(*ps4Impl, sceHttpCreateEpoll(sceHttpId,_)).After(setNonBlock).WillOnce(DoAll(SetArgPointee<1>(eh), Return(SCE_OK)));
EXPECT_CALL(*ps4Impl, sceHttpSetEpoll(sceRequestId,_,nullptr)).After(createEpoll).WillOnce(Return(SCE_OK));
}
HttpRequestInternal* internalRequest = enginePs4.createRequest(requestContext);
HttpRequestPs4* request = reinterpret_cast<HttpRequestPs4*>(internalRequest);
// Check maxBufferSize on upload
{
const uint32 requestContentLength = requestBody.getLength(); // Shall be above the maximum buffer size
uint32 bytesLeft = requestContentLength;
EXPECT_CALL(*ps4Impl, sceHttpSendRequest(sceRequestId,_,Le(maxBufferSize))).WillRepeatedly(Return(SCE_OK));
while (bytesLeft > 0)
{
request->executeStep(); // stepSendRequest
bytesLeft -= maxBufferSize;
}
}
// Get response headers
const uint32 responseContentLength = 30u; // Arbitrary value, but shall be above the maximum buffer size
{
EXPECT_CALL(*ps4Impl, sceHttpGetResponseContentLength(sceRequestId,_,_)).WillOnce(DoAll(
SetArgPointee<1>(SCE_HTTP_CONTENTLEN_EXIST), SetArgPointee<2>(responseContentLength), Return(SCE_OK)));
request->executeStep(); // stepResponseContentLength
StringStream responseHeadersStream;
responseHeadersStream << "HTTP/1.1 200 OK\r\nContent-Length: " << responseContentLength << "\r\n\r\n";
const String responseHeaders = responseHeadersStream.getContent();
EXPECT_CALL(*ps4Impl, sceHttpGetAllResponseHeaders(sceRequestId,_,_)).WillOnce(DoAll(
SetArgPointee<1>(const_cast<char*>(responseHeaders.getUtf8())), SetArgPointee<2>(responseHeaders.getLength() + 1), Return(SCE_OK)));
EXPECT_CALL(*ps4Impl, sceHttpGetStatusCode(sceRequestId,_)).WillOnce(Return(SCE_OK));
request->executeStep(); // stepResponseHeaders
request->executeStep(); // stepParseHeaders
}
// Check maxBufferSize on download
{
uint32 bytesLeft = responseContentLength;
MockHttpPs4Impl_BF::setRequestReleaseExpectations(*ps4Impl, sceRequestId);
while (bytesLeft > 0)
{
EXPECT_CALL(*ps4Impl, sceHttpReadData(sceRequestId,_,Le(maxBufferSize))).WillOnce(
Return(bytesLeft > maxBufferSize?maxBufferSize:bytesLeft));
request->executeStep(); // stepDownloadData
bytesLeft -= maxBufferSize;
}
}
// Request is not delete automatically by the engine implementation but by HttpEngine components
enginePs4.releaseRequest(internalRequest);
EXPECT_CALL(*ps4Impl, sceHttpDeleteConnection(sceConnectionId)).WillOnce(Return(SCE_OK));
enginePs4.shutdown();
}
}
/// @test Checks that the connection is closed when the server does not support keep-alive and kept open otherwise
TEST_F(HTTP_ENGINE_PS4_MOCK, LOCAL_KeepAlive)
{
{
// Http 1.0 without the keep-alive header
// => Connection should not use keep alive since Http 1.0 is not using keep-alive by default
const String serializedHeaders = "HTTP/1.0 200 OK\r\n\r\n";
TestHttpEnginePs4_BF::checkKeepAlive(serializedHeaders, false);
}
{
// Http 1.1 with the header connection close => Connection should not use keep-alive
const String serializedHeaders = "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n";
TestHttpEnginePs4_BF::checkKeepAlive(serializedHeaders, false);
}
{
// Http 1.0 with keep alive header => Connection should use keep alive
const String serializedHeaders = "HTTP/1.0 200 OK\r\nConnection: keep-alive\r\n\r\n";
TestHttpEnginePs4_BF::checkKeepAlive(serializedHeaders, true);
}
{
// Http 1.1 => Connection uses keep alive by default
const String serializedHeaders = "HTTP/1.1 200 OK\r\n\r\n";
TestHttpEnginePs4_BF::checkKeepAlive(serializedHeaders, true);
}
{
// Http 1.1 with redundant keep-alive header => Connection should use keep alive
const String serializedHeaders = "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\n\r\n";
TestHttpEnginePs4_BF::checkKeepAlive(serializedHeaders, true);
}
{
// Http 1.0 with the header connection close
// => Connection should not use keep-alive since "close" header is ignored (not defined in Http 1.0)
// and default behavior in Http 1.0 is to disable the keep-alive
const String serializedHeaders = "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n";
TestHttpEnginePs4_BF::checkKeepAlive(serializedHeaders, false);
}
}
};
#endif //#if !defined(US_DLL)