JD2022-TU1/main/extern/UbiServices/custom/testsUnit/services/testConnection.cpp

359 lines
14 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour //
////////////////////////////////////////////////////////////////////////////////
#include "tests/config.h"
#include "tests/common/restStatusCode.h"
#include "tests/mock/mockLogDevice.h"
#include "tests/fixture/authenticationFixture.h"
#include "tests/fixture/loginMockFixture.h" // for BuildList
#include "tests/fixture/memoryCheckFixture.h"
#include "testsUnit/mock/mockWebsocketStreamImpl.h"
#include "testsUnit/mock/mockSocket.h"
#include "testsUnit/mock/mockWebsocketClient.h"
#include <ubiservices/core/http/httpObfuscatorHelper.h>
#include <ubiservices/core/JSON/jsonWriter.h>
#include <ubiservices/core/JSON/json.h>
#include <ubiservices/core/types/dateTimeHelper.h>
#include <ubiservices/services/notification/notificationClient.h>
#include <ubiservices/services/notification/connectionInfo.h>
#include <ubiservices/services/notification/connectionInfoOwn.h>
namespace US_NS {;
US_DEFINE_TEST(TestConnection);
#if !defined(US_DLL)
typedef LeakChecker UNIT_CONNECTION;
typedef LeakCheckerNoInit UNIT_CONNECTION_NOINIT;
typedef LeakCheckerNoScheduler UNIT_CONNECTION_NOENGINES;
typedef LoginMockFixture<false> UNIT_CONNECTION_MOCK_NOLOGIN;
namespace ConnectionInfoPrivate
{
bool extractData(const Json& source, ConnectionInfo& target);
bool extractData(const Json& source)
{
ConnectionInfo dummy;
return extractData(source, dummy);
}
}
namespace OwnConnectionInfoPrivate
{
bool extractData(const Json& source, ConnectionInfoOwn& target);
bool extractData(const Json& source)
{
ConnectionInfoOwn dummy;
return extractData(source, dummy);
}
}
namespace FieldNames
{
const char* const CONNECTION_TYPE = "notificationType";
const char* const CONNECTION_ID = "connectionId";
const char* const CONTACT_URL = "contactUrl";
const char* const CONTENT = "content";
const char* const DATE_POSTED = "datePosted";
}
namespace FieldValues
{
const char* const CONNECTION_TYPE = "US_CONNECTION_ESTABLISHED";
const char* const CONNECTION_ID = "3a685713-e022-4e03-bcf7-9d7ba70e2066";
const char* const CONTACT_URL = "http://uat-im-ubiservices.ubi.com/not01/8180/channels/39389/message";
const char* const DATE_POSTED = "2014-07-22T17:17:18.725Z";
}
namespace TestConnectionStructures_BF
{
Json getConnectionInfoMissingInfo()
{
JsonWriter writer;
//writer[CONNECTION_ID] = "11112222-3333-4444-5555-666677778888";
writer["profileId"] = "aaaabbbb-cccc-dddd-eeee-ffffaaaabbbb";
writer["applicationId"] = "1111aaaa-2222-bbbb-3333-cccc4444dddd";
writer[FieldNames::CONTACT_URL] = "https://contact.url.com";
writer["contactProtocol"] = "https";
writer["createdDate"] = "2014-08-01T00:00:00Z";
writer["lastModifiedDate"] = "2014-08-01T00:00:00Z";
writer["messageTypes"] = Vector<String>({"type1", "type2"});
{
JsonWriter obj;
obj["field"] = "value";
writer["obj"] = obj.getJson();
}
return writer.getJson();
}
Json getValidConnectionInfo()
{
const Json json = getConnectionInfoMissingInfo();
JsonWriter writer(json);
writer[FieldNames::CONNECTION_ID] = "11112222-3333-4444-5555-666677778888";
return writer.getJson();
}
Json getValidConnectionInfoExtraField()
{
const Json json = getValidConnectionInfo();
JsonWriter writer(json);
writer["field"] = "value";
return writer.getJson();
}
int32 createMockUbiServicesErrorResponse(char* data, uint32 maxSize)
{
const String response =
"HTTP/1.1 404 Not Found\r\n"
"Connection: close\r\n"
"X-WebSocket-Reject-Reason: Error message: The resource was not found\r\n"
"Content-Type: application/json\r\n"
"Content-Length: 297\r\n"
"\r\n"
"{\"errorCode\":1003,\"errorContext\":\"Events\",\"httpCode\":404,\"message\":\"Error message : The resource was not found\","
"\"moreInfo\":\"A link to more information will be coming soon.Please contact UbiServices for more support.\",\"stackTrace\":\"\","
"\"transactionId\":\"\",\"transactionTime\":\"2015-03-05T21:39:44.248Z\"}";
EXPECT_LE(response.getLength(), maxSize);
memcpy(data, response.getUtf8(), response.getLength());
return static_cast<int32>(response.getLength());
}
}
TEST_F(UNIT_CONNECTION_NOENGINES, LOCAL_ConnectionInfoValid)
{
SAVE_ALLOC_COUNT(count1);
const Json info = TestConnectionStructures_BF::getValidConnectionInfo();
EXPECT_ALLOC_COUNT_PC_EQ(62u, count1);
EXPECT_TRUE(ConnectionInfoPrivate::extractData(info));
EXPECT_ALLOC_COUNT_PC_EQ(43u, count1);
}
TEST_F(UNIT_CONNECTION, LOCAL_ConnectionInfoValidExtraField)
{
const Json info = TestConnectionStructures_BF::getValidConnectionInfo();
JsonWriter writer(info);
writer["field"] = "value";
const Json reader = writer.getJson();
EXPECT_TRUE(ConnectionInfoPrivate::extractData(reader));
}
TEST_F(UNIT_CONNECTION, LOCAL_ConnectionInfoMissingInfo)
{
const Json info = TestConnectionStructures_BF::getConnectionInfoMissingInfo();
EXPECT_FALSE(ConnectionInfoPrivate::extractData(info));
}
TEST_F(UNIT_CONNECTION, LOCAL_OwnConnectionInfoJson)
{
const ConnectionId connectionId(FieldValues::CONNECTION_ID);
const StringUrl url = FieldValues::CONTACT_URL;
const String stringDateTime = FieldValues::DATE_POSTED;
const DateTime dateTime = DateTimeHelper::parseDateISO8601(stringDateTime);
JsonWriter writer;
{
JsonWriter child;
child[FieldNames::CONNECTION_ID] = connectionId;
child[FieldNames::CONTACT_URL] = url;
writer[FieldNames::CONTENT] = child.getJson();
}
writer[FieldNames::CONNECTION_TYPE] = FieldValues::CONNECTION_TYPE;
writer[FieldNames::DATE_POSTED] = stringDateTime;
ConnectionInfoOwn connectionInfo;
EXPECT_TRUE(OwnConnectionInfoPrivate::extractData(writer.getJson(), connectionInfo));
EXPECT_EQ(connectionId, connectionInfo.m_connectionId);
EXPECT_EQ(url, connectionInfo.m_contactUrl);
EXPECT_EQ(dateTime, connectionInfo.m_createdTime);
}
TEST_F(UNIT_CONNECTION_NOINIT, LOCAL_OwnConnectionInfoJson)
{
SAVE_ALLOC_COUNT(count1);
initializeSdk();
{
const ConnectionId connectionId(FieldValues::CONNECTION_ID);
const StringUrl url = FieldValues::CONTACT_URL;
const String dateTime = FieldValues::DATE_POSTED;
JsonWriter writer;
{
JsonWriter child;
child[FieldNames::CONNECTION_ID] = connectionId;
child[FieldNames::CONTACT_URL] = url;
writer[FieldNames::CONTENT] = child.getJson();
}
writer[FieldNames::CONNECTION_TYPE] = FieldValues::CONNECTION_TYPE;
writer[FieldNames::DATE_POSTED] = dateTime;
EXPECT_ALLOC_COUNT_PC_X1_EQ(46u, 46u, count1);
{
US_PERF_TASK_FORMAT("Instanciating ConnectionInfoOwn", NULL);
ConnectionInfoOwn connectionInfo;
EXPECT_ALLOC_COUNT_PC_X1_EQ(35u, 38u, count1);
{
US_PERF_TASK_FORMAT("Populating ConnectionInfo from JSON", NULL);
EXPECT_TRUE(OwnConnectionInfoPrivate::extractData(writer.getJson(), connectionInfo));
}
EXPECT_ALLOC_COUNT_PC_X1_EQ(53u, 65u, count1);
EXPECT_EQ(connectionId, connectionInfo.m_connectionId);
EXPECT_EQ(url, connectionInfo.m_contactUrl);
EXPECT_EQ(DateTimeHelper::parseDateISO8601(dateTime), connectionInfo.m_createdTime);
}
EXPECT_ALLOC_COUNT_PC_X1_EQ(7u, 7u, count1);
}
EXPECT_EQ(UninitializeResult::Complete, uninitializeSdk());
}
TEST_F(UNIT_CONNECTION, LOCAL_OwnConnectionInfoJsonExtraParam)
{
JsonWriter writer;
{
JsonWriter child;
child[FieldNames::CONNECTION_ID] = FieldValues::CONNECTION_ID;
child[FieldNames::CONTACT_URL] = FieldValues::CONTACT_URL;
writer[FieldNames::CONTENT] = child.getJson();
}
writer[FieldNames::CONNECTION_TYPE] = FieldValues::CONNECTION_TYPE;
writer[FieldNames::DATE_POSTED] = FieldValues::DATE_POSTED;
writer["ExtraParam"] = "ExtraValue";
EXPECT_TRUE(OwnConnectionInfoPrivate::extractData(writer.getJson()));
}
TEST_F(UNIT_CONNECTION, LOCAL_OwnConnectionInfoJsonMissingParam)
{
{
JsonWriter writer;
writer[FieldNames::CONTACT_URL] = FieldValues::CONTACT_URL;
writer[FieldNames::CONNECTION_TYPE] = FieldValues::CONNECTION_TYPE;
writer[FieldNames::DATE_POSTED] = FieldValues::DATE_POSTED;
EXPECT_FALSE(OwnConnectionInfoPrivate::extractData(writer.getJson()));
}
{
JsonWriter writer;
writer[FieldNames::CONNECTION_ID] = FieldValues::CONNECTION_ID;
writer[FieldNames::CONNECTION_TYPE] = FieldValues::CONNECTION_TYPE;
writer[FieldNames::DATE_POSTED] = FieldValues::DATE_POSTED;
EXPECT_FALSE(OwnConnectionInfoPrivate::extractData(writer.getJson()));
}
{
JsonWriter writer;
writer[FieldNames::CONNECTION_ID] = FieldValues::CONNECTION_ID;
writer[FieldNames::CONTACT_URL] = FieldValues::CONTACT_URL;
writer[FieldNames::CONNECTION_TYPE] = FieldValues::CONNECTION_TYPE;
EXPECT_FALSE(OwnConnectionInfoPrivate::extractData(writer.getJson()));
}
}
#if !defined(US_TARGET_XONE) && !defined(US_TARGET_UWP) && !defined(US_TARGET_MANJARO)
///@test Verifies that the client manages the REST response from the service.
/// It also validates that we don't retry the connection on a service unavailable error.
TEST_F(UNIT_CONNECTION_MOCK_NOLOGIN, USNOT_ServicesUnavailable)
{
PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device)
{
US_EXPECT_LOG("Not Found", LogLevel::Error, Times(3));
});
MockWebSocketEngine* engine = US_NEW(MockWebSocketEngine);
InstancesManager::getInstance()->replaceWebSocketEngine(engine);
MockWebSocketStreamImpl* mockStream = US_NEW(MockWebSocketStreamImpl,
StringUrl(),
InstancesManager::getInstance()->getSSLPinningKeys(),
HttpObfuscatorHelper::getObfuscator());
{
//m_url = {Text="https://api-ubiservices.ubi.com/v2/profiles/sessions"}
US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_POST, "/profiles/sessions", getMockedLoginResponseNoUbiAccount());
US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "/parameters")
.Times(2)
.WillOnce(testing::Return(getMockedParametersApplication()))
.WillOnce(testing::Return(getMockedParametersSpace()));
{
US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "/mock-config-events")
.Times(testing::AnyNumber())
.WillOnce(testing::Return(getMockedLoginResponseEventConfig()));
}
{
US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, String::formatText("/%s/mock-spaces-primarystoremapping", "12121212-3434-5656-7878-909090909090"))
.Times(testing::AnyNumber())
.WillOnce(testing::Return(getMockedSecondaryPrimaryStoreMapping()));
}
{
US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_POST, "/mock-profiles-inventory-primarystore")
.Times(testing::AnyNumber())
.WillRepeatedly(testing::Return(getMockedNotifyPrimaryStoreUpdate()));
}
{
const String jsonBody = "{" "\"populations\": [" "]" "}";
MockAsyncResult resultPopulations("MockPopulations");
resultPopulations.setResult(HttpResponse(RestStatusCode::OK, HttpHeader(), jsonBody));
resultPopulations.setToComplete(US_NS::ErrorDetails(Errors::SUCCESS, "MockPopulationsSuccess"));
US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles/me/mock-populations")
.Times(testing::AnyNumber())
.WillRepeatedly(testing::Return(resultPopulations));
US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_PUT, "profiles/me/mock-populations/data")
.Times(testing::AnyNumber())
.WillRepeatedly(testing::Return(resultPopulations));
}
MockSocket* socket = reinterpret_cast<MockSocket*>(mockStream->getSocket());
using namespace testing;
EXPECT_CALL(*engine, createStream(_,_,_)).WillOnce(Return(mockStream));
EXPECT_CALL(*engine, openConnectionImpl(_, _, _, _, _, _, _))
.WillOnce(Invoke(engine, &MockWebSocketEngine::invokeOpenConnectionImpl));
EXPECT_CALL(*socket, Connect(_, _));
EXPECT_CALL(*socket, SetSendBufSize(_)).Times(1);
EXPECT_CALL(*socket, Select(_, _, _)).Times(1);
EXPECT_CALL(*socket, GetPendingDataCount()).Times(1);
EXPECT_CALL(*mockStream, writeStream(_)).WillOnce(Return(Errors::SUCCESS));
EXPECT_CALL(*mockStream, readStream(_)).WillOnce(Invoke(mockStream, &MockWebSocketStreamImpl::DelegateReadStream));
EXPECT_CALL(*socket, Receive(_, _)).WillOnce(Invoke(TestConnectionStructures_BF::createMockUbiServicesErrorResponse));
EXPECT_CALL(*socket, Close());
}
{
ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().createSession(getPlayerCredentials(), {}, {})));
ASSERT_FALSE(TestHelpers_BF::waitForPropertyValue(getFacade().getNotificationClient(),
&NotificationClient::isConnectionActive, true, "NotificationClient::isConnectionActive", 1000));
}
}
#endif //!defined(US_TARGET_XONE) && !defined(US_TARGET_UWP) && !defined(US_TARGET_MANJARO)
#endif //!defined(US_DLL)
};