365 lines
16 KiB
C++
365 lines
16 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
// (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour //
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
#include "tests/config.h"
|
|
#if defined(US_SDK_FULL) || defined(US_SDK_S2S)
|
|
#include <gmock/gmock-spec-builders.h>
|
|
#include "tests/fixture/authenticationFixture.h"
|
|
#include "tests/fixture/loginMockFixture.h"
|
|
#include "tests/mock/mockLogDevice.h"
|
|
#include "tests/mock/mockResultHelper.h"
|
|
#include <ubiservices/core/errors/errorDetails.h>
|
|
#include <../private/ubiservices/core/log/remoteLoggerLevel.h>
|
|
#include <ubiservices/services/remoteLog/remoteLog.h>
|
|
#include <ubiservices/services/remoteLog/remoteLogClient.h>
|
|
#include <../private/ubiservices/services/remoteLog/remoteLoggerCustom.h>
|
|
#include <../private/ubiservices/services/parameters/parametersClientProxy.h>
|
|
#include <../private/ubiservices/services/parameters/parametersInfo.h>
|
|
|
|
// it will be removed from ealmem.h in version 7.00.
|
|
// set as extern because we will want to continue using it in our tests even after the function will be removed from the eal API.
|
|
extern eal_u32 EalMemGetAllocated();
|
|
|
|
namespace US_NS {;
|
|
US_DEFINE_TEST(TestRemoteLogClient);
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Only manual tests here since the client method return void.
|
|
// Having this testIntegration file ensures that a compilation error will raise if a private file is included by remoteLogClient
|
|
|
|
typedef AuthenticationFixture<> REMOTELOG;
|
|
typedef LeakChecker REMOTELOG_NOLOGIN;
|
|
|
|
#if !defined (US_DLL)
|
|
class TestRemoteLogClientHelper
|
|
{
|
|
public:
|
|
static RemoteLoggerCustom& getRemoteLoggerCustom(FacadeInternal& facade);
|
|
};
|
|
|
|
// Check that many remoteLogs can be sent simultaneously
|
|
// @disabled This test sends 10000 remote logs and lasts ~1min
|
|
TEST_F(REMOTELOG, DISABLED_MANUAL_US_RemoteLogClientLogLimitLoadTest)
|
|
{
|
|
const String category("TestCategory");
|
|
std::unordered_map<std::string, RemoteLogLevel::Enum> map;
|
|
map[category.getUtf8()] = RemoteLogLevel::Warning;
|
|
TestRemoteLogClientHelper::getRemoteLoggerCustom(getFacadeInternal()).setLogLevelByCategory(map);
|
|
RemoteLogClient& remoteLogClient = getFacade().getRemoteLogClient();
|
|
|
|
uint32 memEnd = 0;
|
|
uint32 memEndAfterFirstLoop = 0;
|
|
const RemoteLog logMessage("My load message");
|
|
|
|
const uint32 LOG_LIMIT = 1000;
|
|
|
|
for (int j = 0; j < 10; j++)
|
|
{
|
|
for (uint32 i = 0; i < LOG_LIMIT; ++i)
|
|
{
|
|
remoteLogClient.sendRemoteLog(RemoteLogClient::Error, category, logMessage);
|
|
|
|
// Sleep 10ms every 100 log to make sure logs are not sent
|
|
// in a unique and huge message
|
|
if (i % 100 == 0)
|
|
{
|
|
Helper::sleep(10);
|
|
}
|
|
}
|
|
US_TEST_NS::Helper::sleep(5000); // Should be sufficient for the last send to be finished
|
|
|
|
memEnd = EalMemGetAllocated();
|
|
if (memEndAfterFirstLoop == 0)
|
|
{
|
|
// Get allocated memory after sending the first 10,000 logs
|
|
// All pools should be allocated and memory size should be stable
|
|
memEndAfterFirstLoop = memEnd;
|
|
}
|
|
}
|
|
|
|
// Allow memory to grow no more than 50% from first memEnd
|
|
// If more, could be memory buildup/leak !
|
|
// 50% margin is really large, but tests on build farm show that it is sometimes above 30%
|
|
// The test wants to ensure that the memory used on each loop will be reused,
|
|
// i.e. the maximum memory used is not 10 times the quantity for one loop
|
|
double maxMemAccepted = memEndAfterFirstLoop + memEndAfterFirstLoop * 0.50;
|
|
EXPECT_LT(memEnd, maxMemAccepted);
|
|
}
|
|
|
|
// Try doing a lot of calls per second during a long period of time
|
|
// Check manually the number of logs received by the server
|
|
TEST_F(REMOTELOG, DISABLED_MANUAL_US_RemoteLogClientLogLimitStressTest)
|
|
{
|
|
const String category("TestCategory");
|
|
std::unordered_map<std::string, RemoteLogLevel::Enum> map;
|
|
map[category.getUtf8()] = RemoteLogLevel::Warning;
|
|
TestRemoteLogClientHelper::getRemoteLoggerCustom(getFacadeInternal()).setLogLevelByCategory(map);
|
|
RemoteLogClient& remoteLogClient = getFacade().getRemoteLogClient();
|
|
|
|
const uint32 STRESS_TIME = 1200000;
|
|
const uint32 DELAY_TIME = 20;
|
|
const uint32 CALL_NUMBER = STRESS_TIME / DELAY_TIME;
|
|
const RemoteLog logMessage("My stress message");
|
|
for (uint32 i = 0; i < CALL_NUMBER; ++i)
|
|
{
|
|
// Save the http request
|
|
remoteLogClient.sendRemoteLog(RemoteLogClient::Warning, category, logMessage);
|
|
Helper::sleep(DELAY_TIME);
|
|
}
|
|
|
|
Helper::sleep(5000); // Should be sufficient for the last send to be finished
|
|
}
|
|
|
|
TEST_F(REMOTELOG_NOLOGIN, US_RemoteLogClientSessionInvalid)
|
|
{
|
|
#if defined(US_LOG_ENABLED)
|
|
LoggingHelper::enableVerbose();
|
|
LoggingHelper::enableMultiLines();
|
|
enableLogCategories({ LogCategory::RemoteLog, LogCategory::Core });
|
|
|
|
LoggingHelper::setCategoryLevel(LogCategory::Core, LogLevel::Error);
|
|
|
|
PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device)
|
|
{
|
|
US_EXPECT_LOG("RemoteLogClient failed sending log: Create session is not completed!", LogLevel::Error, Times(1));
|
|
|
|
// SDK Remote Logs: None
|
|
US_EXPECT_LOG("profiles/me/remotelog HTTP/1.1", LogLevel::Debug, Times(0));
|
|
|
|
// PROD Remote Logs: None
|
|
US_EXPECT_LOG("profiles/me/remotelog?dummyparam=1 HTTP/1.1", LogLevel::Debug, Times(0));
|
|
});
|
|
|
|
{
|
|
PRINT_LINE("Creating Facade");
|
|
Facade facade;
|
|
uint32 logId = 1;
|
|
|
|
const String category("TestCategory");
|
|
std::unordered_map<std::string, RemoteLogLevel::Enum> map;
|
|
map[category.getUtf8()] = RemoteLogLevel::Warning;
|
|
TestRemoteLogClientHelper::getRemoteLoggerCustom(getFacadeInternal(facade)).setLogLevelByCategory(map);
|
|
|
|
// A log with valid facade but no valid session
|
|
// Log is ignored
|
|
RemoteLogClient& remoteLogClient = facade.getRemoteLogClient();
|
|
|
|
{
|
|
RemoteLog remoteLog("Session[Invalid]");
|
|
remoteLog.addField("logId", logId++);
|
|
remoteLogClient.sendRemoteLog(RemoteLogClient::Warning, "TestCategory", remoteLog);
|
|
Helper::sleep(1000); // Should be sufficient for the last send to be finished
|
|
}
|
|
}
|
|
|
|
PRINT_LINE("Facade deleted");
|
|
#endif
|
|
}
|
|
|
|
TEST_F(REMOTELOG_NOLOGIN, US_MINRUN_RemoteLogClientSessionValidSingleLog)
|
|
{
|
|
#if defined(US_LOG_ENABLED)
|
|
LoggingHelper::enableVerbose();
|
|
LoggingHelper::enableMultiLines();
|
|
enableLogCategories({ LogCategory::RemoteLog });
|
|
|
|
PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device)
|
|
{
|
|
#if !defined(US_SDK_S2S)
|
|
// PROD Remote Logs: 1 log, 1 call
|
|
US_EXPECT_LOG("profiles/me/remotelog?dummyparam=1 HTTP/1.1", LogLevel::Debug, Times(1));
|
|
#else
|
|
US_UNUSED(device);
|
|
#endif
|
|
});
|
|
|
|
{
|
|
PRINT_LINE("Creating Facade");
|
|
Facade facade;
|
|
uint32 logId = 1;
|
|
|
|
RemoteLogClient& remoteLogClient = facade.getRemoteLogClient();
|
|
|
|
const AuthenticationClient& client = facade.getAuthenticationClient();
|
|
EXPECT_FALSE(client.getSessionInfo().hasValidSession());
|
|
|
|
const AsyncResult<Empty> resultLogin = facade.createSession(GET_CREDENTIALS(), {}, {});
|
|
ASSERT_TRUE(resultLogin.isProcessing());
|
|
ASSERT_TRUE(AsyncHelper::waitSuccess(resultLogin));
|
|
US_ASSERT_SUCCESS(resultLogin);
|
|
EXPECT_TRUE(client.getSessionInfo().hasValidSession());
|
|
#if !defined(US_SDK_S2S)
|
|
PRINT_LINE("Player's Profile ID: %s", static_cast<const String&>(facade.getAuthenticationClient().getSessionInfo().getProfileId()).getUtf8());
|
|
#endif
|
|
PRINT_LINE("Player's Session ID: %s", static_cast<const String&>(facade.getAuthenticationClient().getSessionInfo().getSessionId()).getUtf8());
|
|
|
|
const String category("TestCategory");
|
|
std::unordered_map<std::string, RemoteLogLevel::Enum> map;
|
|
map[category.getUtf8()] = RemoteLogLevel::Warning;
|
|
TestRemoteLogClientHelper::getRemoteLoggerCustom(getFacadeInternal(facade)).setLogLevelByCategory(map);
|
|
|
|
{
|
|
RemoteLog remoteLog("Session[valid]");
|
|
remoteLog.addField("logId", logId++);
|
|
remoteLogClient.sendRemoteLog(RemoteLogClient::Warning, category, remoteLog);
|
|
}
|
|
US_TEST_NS::Helper::sleep(5000); // Should be sufficient for the last send to be finished
|
|
|
|
const AsyncResult<Empty> resultDeleteSession = facade.deleteSession();
|
|
ASSERT_TRUE(resultDeleteSession.wait(NS_COMMON::DEFAULT_WAIT_TIME));
|
|
US_EXPECT_SUCCESS(resultDeleteSession);
|
|
|
|
EXPECT_FALSE(client.getSessionInfo().hasValidSession());
|
|
}
|
|
|
|
PRINT_LINE("Facade deleted");
|
|
#endif
|
|
}
|
|
|
|
TEST_F(REMOTELOG_NOLOGIN, DISABLED_MANUAL_US_RemoteLogClientSessionValidBurstLogs)
|
|
{
|
|
#if defined(US_LOG_ENABLED)
|
|
LoggingHelper::enableVerbose();
|
|
LoggingHelper::enableMultiLines();
|
|
enableLogCategories({ LogCategory::RemoteLog });
|
|
|
|
PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device)
|
|
{
|
|
// SDK Remote Logs: Expect at least 1 call
|
|
US_EXPECT_LOG("profiles/me/remotelog HTTP/1.1", LogLevel::Debug, Times(::testing::AtLeast(1)));
|
|
|
|
// PROD Remote Logs: 50 logs, 2 calls and maybe more
|
|
US_EXPECT_LOG("profiles/me/remotelog?dummyparam=1 HTTP/1.1", LogLevel::Debug, Times(::testing::AtLeast(2)));
|
|
});
|
|
|
|
{
|
|
PRINT_LINE("Creating Facade");
|
|
Facade facade;
|
|
uint32 logId = 1;
|
|
|
|
RemoteLogClient& remoteLogClient = facade.getRemoteLogClient();
|
|
|
|
const AuthenticationClient& client = facade.getAuthenticationClient();
|
|
EXPECT_FALSE(client.getSessionInfo().hasValidSession());
|
|
|
|
const AsyncResult<Empty> resultLogin = facade.createSession(GET_CREDENTIALS(), {}, {});
|
|
ASSERT_TRUE(resultLogin.isProcessing());
|
|
ASSERT_TRUE(AsyncHelper::waitSuccess(resultLogin));
|
|
US_ASSERT_SUCCESS(resultLogin);
|
|
EXPECT_TRUE(client.getSessionInfo().hasValidSession());
|
|
#if !defined(US_SDK_S2S)
|
|
PRINT_LINE("Player's Profile ID: %s", static_cast<const String&>(facade.getAuthenticationClient().getSessionInfo().getProfileId()).getUtf8());
|
|
#endif
|
|
PRINT_LINE("Player's Session ID: %s", static_cast<const String&>(facade.getAuthenticationClient().getSessionInfo().getSessionId()).getUtf8());
|
|
|
|
const String category("TestCategory");
|
|
std::unordered_map<std::string, RemoteLogLevel::Enum> map;
|
|
map[category.getUtf8()] = RemoteLogLevel::Warning;
|
|
TestRemoteLogClientHelper::getRemoteLoggerCustom(getFacadeInternal(facade)).setLogLevelByCategory(map);
|
|
|
|
// Burst of N remote logs
|
|
{
|
|
for (uint32 i = 0; i < 100; i++)
|
|
{
|
|
RemoteLog remoteLog("Session[valid] Burst");
|
|
remoteLog.addField("logId", logId++);
|
|
remoteLogClient.sendRemoteLog(RemoteLogClient::Warning, category, remoteLog);
|
|
}
|
|
}
|
|
Helper::sleep(5000); // Should be sufficient for the last send to be finished
|
|
|
|
const AsyncResult<Empty> resultDeleteSession = facade.deleteSession();
|
|
ASSERT_TRUE(resultDeleteSession.wait(NS_COMMON::DEFAULT_WAIT_TIME));
|
|
US_EXPECT_SUCCESS(resultDeleteSession);
|
|
|
|
EXPECT_FALSE(client.getSessionInfo().hasValidSession());
|
|
}
|
|
|
|
PRINT_LINE("Facade deleted");
|
|
#endif
|
|
}
|
|
|
|
// The WaitRemoteLogCompletionOnDeleteSession parameter allows the RemoteLogger to accept and send log while the
|
|
// DeleteSession is occurring, at the cost of a longer DeleteSession (100 to 250 additional ms). This parameter is
|
|
// tested by doing a delete session right after adding 1000logs. When the parameter is activated, the delete session
|
|
// wait for the 1000logs to send. If not, it shouldn't have time.
|
|
// Use https://ec2-logging-us-client.ubisoft.onbe/kibana3/#/dashboard/elasticsearch/UbiServices%20SDK to view logs received.
|
|
// To enable every log family for this test, copy the following Json in "parametersInfo.cpp", in the Parse remote logs internal section (line 433).
|
|
// Use that Json variable in m_remoteLogParametersInternal's parseData ( ex: m_remoteLogParametersInternal.parseData(test); )
|
|
// Json test("{ \"maxTextLength\":32768,\"applicationUsed\" : \"Debug\",\"applicationInformation\" : \"Debug\",\"async\" : \"None\","
|
|
// "\"authentication\" : \"Debug\",\"club\" : \"Debug\",\"configuration\" : \"Debug\",\"connection\" : \"Debug\",\"core\" : \"None\","
|
|
// "\"coreNotification\" : \"None\",\"entity\" : \"Debug\",\"event\" : \"Debug\",\"friend\" : \"Debug\",\"http\" : \"Debug\","
|
|
// "\"httpEngine\" : \"None\",\"job\" : \"None\",\"leaderboard\" : \"Debug\",\"localization\" : \"Debug\",\"user\""
|
|
// ": \"Debug\",\"news\" : \"Debug\",\"notification\" : \"Debug\",\"population\" : \"Debug\",\"primaryStore\" : \"Debug\","
|
|
// "\"profile\" : \"Debug\",\"remoteLog\" : \"None\",\"scheduler\" : \"None\",\"secondaryStore\" : \"Debug\",\"stats\" :"
|
|
// "\"Debug\",\"task\" : \"None\",\"test\" : \"None\",\"user\" : \"Debug\",\"userContent\" : \"Debug\",\"websocket\" : \"Debug\" }");
|
|
TEST_F(REMOTELOG_NOLOGIN, DISABLED_MANUAL_US_WaitRemoteLogCompletionOnDeleteSessionTest)
|
|
{
|
|
setupDebugLogging();
|
|
Facade facade;
|
|
HighResolutionChrono chrono;
|
|
|
|
const AuthenticationClient& client = facade.getAuthenticationClient();
|
|
EXPECT_FALSE(client.getSessionInfo().hasValidSession());
|
|
ClockSteady::TDuration::TRep deleteSessionTimerWaitRemoteLog = 0, deleteSessionTimer = 0;
|
|
|
|
// Doing the createSess/deleteSess sequence 2 times; 1 with the parameter activated, 1 without
|
|
for (int j = 0; j < 2; j++)
|
|
{
|
|
// Create session
|
|
const AsyncResult<Empty> resultLogin = facade.createSession(GET_CREDENTIALS(), {}, {});
|
|
ASSERT_TRUE(resultLogin.isProcessing());
|
|
ASSERT_TRUE(AsyncHelper::waitSuccess(resultLogin));
|
|
US_ASSERT_SUCCESS(resultLogin);
|
|
EXPECT_TRUE(client.getSessionInfo().hasValidSession());
|
|
|
|
// Activate or not the parameter that tells the logger to keep working while delete session is occurring
|
|
if (j == 0)
|
|
{
|
|
ParametersClientProxy::setWaitRemoteLogCompletionOnDeleteSessionParameter(getFacadeInternal(facade), true);
|
|
ASSERT_TRUE(ParametersClientProxy::getParametersInfo(getFacadeInternal(facade)).m_paramsSettings.m_waitRemoteLogCompletionOnDeleteSession);
|
|
}
|
|
else
|
|
{
|
|
ParametersClientProxy::setWaitRemoteLogCompletionOnDeleteSessionParameter(getFacadeInternal(facade), false);
|
|
ASSERT_FALSE(ParametersClientProxy::getParametersInfo(getFacadeInternal(facade)).m_paramsSettings.m_waitRemoteLogCompletionOnDeleteSession);
|
|
}
|
|
|
|
// Send 1000 logs to fill the buffer
|
|
RemoteLogClient& remoteLogClient = facade.getRemoteLogClient();
|
|
{
|
|
for (uint32 i = 0; i < 1000; i++)
|
|
{
|
|
RemoteLog remoteLog("WaitRemoteLogCompletionOnDeleteSessionTest");
|
|
remoteLog.addField("logId", i);
|
|
remoteLogClient.sendRemoteLog(RemoteLogClient::Warning, "TestCategory", remoteLog);
|
|
}
|
|
}
|
|
|
|
// Delete the session and time it
|
|
chrono.resetState();
|
|
const AsyncResult<Empty> resultDeleteSession = facade.deleteSession();
|
|
ASSERT_TRUE(resultDeleteSession.wait(NS_COMMON::DEFAULT_WAIT_TIME));
|
|
if (j == 0)
|
|
{
|
|
deleteSessionTimerWaitRemoteLog = static_cast<int>((chrono.getElapsed() / 1000u) / 1000.0f);
|
|
PRINT_LINE("Delta Time for delete session: %d ms", deleteSessionTimerWaitRemoteLog);
|
|
}
|
|
else
|
|
{
|
|
deleteSessionTimer = static_cast<int>((chrono.getElapsed() / 1000u) / 1000.0f);
|
|
PRINT_LINE("Delta Time for delete session: %d ms", deleteSessionTimer);
|
|
}
|
|
|
|
US_EXPECT_SUCCESS(resultDeleteSession);
|
|
EXPECT_FALSE(client.getSessionInfo().hasValidSession());
|
|
}
|
|
PRINT_LINE("Time for delete session with WaitRemoteLogCompletionOnDeleteSession parameter activated: %d ms", deleteSessionTimerWaitRemoteLog);
|
|
PRINT_LINE("Time for delete session without WaitRemoteLogCompletionOnDeleteSession parameter : %d ms", deleteSessionTimer);
|
|
ASSERT_GT(deleteSessionTimerWaitRemoteLog, deleteSessionTimer);
|
|
}
|
|
|
|
#endif // !defined (US_DLL)
|
|
|
|
};
|
|
#endif // defined(US_SDK_FULL)
|