JD2022-TU1/main/extern/UbiServices/custom/testsIntegration/testRemoteLogClient.cpp

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)