JD2022-TU1/main/extern/UbiServices/custom/tests/fixture/memoryCheckFixture.cpp

504 lines
18 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour //
////////////////////////////////////////////////////////////////////////////////
#include "tests/common/helpers.h"
#include "tests/common/badEvents.h"
#include "tests/config.h"
#include "tests/fixture/memoryCheckFixture.h"
#include <../private/ubiservices/core/chrono/chronometer.h>
#include <../private/ubiservices/core/helpers/instancesManager.h>
#include <ubiservices/core/log/outputFormat.h>
#include <ubiservices/core/log/eventLog.h>
#include <ubiservices/loggingHelper.h>
#include <ubiservices/ubiservices.h>
#include <ubiservices/services/authentication/authenticationClient.h>
#include <ubiservices/services/authentication/authenticationNotification.h>
#if defined(US_SDK_S2S)
#include "ubiservices/services/event/types/eventTypeInfo.h"
#endif
#include <ubiservices/services/notification/connectionInfoOwn.h>
#include <ubiservices/services/notification/notificationClient.h>
#include <../private/ubiservices/services/preflightEndpoint.h>
#include <external/harbourcommon/libraries/harboureal/implementation/simplemem.h>
#include <usCommon/options.h>
#include <usCommon/settings.h>
#if defined(US_SDK_S2S)
#include <usCommon/authenticationHelper.h>
#endif
#if defined(US_PROFILE)
#include <ealfile.h>
#include <ealnet.h>
#include <faprofiler.h>
#include <faprofiler_disk.h>
#include <faprofiler_network.h>
#include <ubiservices/core/profiler/profilerMacros.h>
#define FAPROFILER_ALLOCATED_MEMORY 16*1024*1024
#define FAPROFILER_FILE_NAME "UbiservicesProfile"
#endif
#if defined(US_TARGET_XONE)
#include <ubiservices/core/log/logDevice.h>
#include <usCommon/win32/firstPartyInit.h>
namespace harbour_printf //ubiservices_hack
{
int internalVPrintf(const char* format, va_list& argList);
int internalPrintf(const char* format, ...);
};
#elif defined(US_TARGET_SWITCH)
#include "usCommon/nnx/firstPartyInit.h"
#elif defined(US_TARGET_PS4)
#include "usCommon/ps4/firstPartyInit.h"
#elif defined(US_TARGET_KILI)
#include "usCommon/kili/firstPartyInit.h"
#elif defined(US_TARGET_GGP)
#include "usCommon/ggp/firstPartyInit.h"
#elif defined(US_TARGET_SWITCH)
#define NintendoApplicationIdForUbiservices "01009d800a1d0000"
#endif
namespace US_NS {;
#if defined(US_USE_LIBCURL) && !defined(US_DLL)
extern bool g_skipEalMemForLibcurl;
#endif
extern US_DLL_API EventLog* g_testEventLog; // Only needed for test purposes
#if !defined(US_SDK_S2S)
namespace LeakChecker_BF
{
Vector<EventTypeInfo> getDefaultEventTypesForSaveGame()
{
US_TEST_STATIC_ASSERT(static_cast<uint32>(EventType::ENUM_END) == 18u, "getDefaultEventTypesForSaveGame() needs to be updated");
// Default config accepts all event types (Note : This would be a wrong integration in games)
return Vector<EventTypeInfo>
{
EventTypeInfo(EventType::PlayerAchievement),
EventTypeInfo(EventType::GameStart),
EventTypeInfo(EventType::GameSuspendedStart),
EventTypeInfo(EventType::GameSuspendedStop),
EventTypeInfo(EventType::PlayerStart),
EventTypeInfo(EventType::ContextStart, "myContextType0"),
EventTypeInfo(EventType::ContextStart, "myContextType1"),
EventTypeInfo(EventType::ContextStart, "myContextType2"),
EventTypeInfo(EventType::ContextStart, "myContextType3"),
EventTypeInfo(EventType::ContextStop, "myContextType0"),
EventTypeInfo(EventType::ContextStop, "myContextType1"),
EventTypeInfo(EventType::ContextStop, "myContextType2"),
EventTypeInfo(EventType::ContextStop, "myContextType3"),
EventTypeInfo(EventType::GameLocalization),
EventTypeInfo(EventType::HardwareSpecs),
EventTypeInfo(EventType::PlayerProgression, "Mission"),
EventTypeInfo(EventType::PlayerProgression, "myProgression"),
EventTypeInfo(EventType::PlayerPosition),
EventTypeInfo(EventType::PlayerPrimaryStore),
EventTypeInfo(EventType::PlayerNewsAction),
EventTypeInfo(EventType::PlayerNewsImpression),
EventTypeInfo(EventType::PlayerStatsPlayTime),
EventTypeInfo(EventType::Custom, CUSTOM_EVENT_NAME),
EventTypeInfo(EventType::Service, TestHelpers_BF::SERVICE_EVENT_NAME),
EventTypeInfo(EventType::Service, "TestingService"),
};
}
}
#endif
#if !defined(US_SDK_S2S)
::testing::AssertionResult WebsocketHelper::waitForWebsocketInit(Facade& facade)
{
class Condition : public US_TEST_NS::Helper::ConditionTemplate
{
public:
Condition(Facade& facade)
: m_facade(facade)
, m_listener(facade.getAuthenticationClient().createNotificationListener())
{
}
bool operator()() const
{
return (m_facade.getNotificationClient().isConnectionActive() && !m_facade.getNotificationClient().getOwnConnectionInfo().m_contactUrl.isEmpty());
}
private:
//US_CLASS_COPY_NOT_ALLOWED(Condition)
Condition(const Condition& dummy) : m_facade(dummy.m_facade) {}
Condition& operator=(Condition&) { return *this; }
Facade& m_facade;
mutable ListenerHandler<AuthenticationNotification> m_listener;
} condition(facade);
return US_TEST_NS::Helper::WaitFor(condition, 1ull, 10*1000ull, "websocket init")
? ::testing::AssertionSuccess()
: ::testing::AssertionFailure() << "Timed out waiting for connection to be active";
}
#endif
#if !defined(US_RETAIL)
extern bool US_DLL_API s_forceNonSecure;
extern bool US_DLL_API g_forcePreflightURL[7];
#endif
LeakChecker::LeakChecker(FixtureType type)
: m_mightLeak(false)
, m_willLeak(false)
, m_type(type)
, m_skipEalMemForLibcurl(false)
#if defined(US_ENABLE_ALLOC_STATS)
, m_currentTestAllocStatistics(g_stats)
#endif
{
#if !defined(US_RETAIL)
s_forceNonSecure = NS_COMMON::Options::forceUnsecure();
g_forcePreflightURL[PreflightEndpoint::Applications] = NS_COMMON::Options::preflightURL(PreflightEndpoint::Applications);
g_forcePreflightURL[PreflightEndpoint::Users] = NS_COMMON::Options::preflightURL(PreflightEndpoint::Users);
g_forcePreflightURL[PreflightEndpoint::Policies] = NS_COMMON::Options::preflightURL(PreflightEndpoint::Policies);
g_forcePreflightURL[PreflightEndpoint::ProfilesExternal] = NS_COMMON::Options::preflightURL(PreflightEndpoint::ProfilesExternal);
g_forcePreflightURL[PreflightEndpoint::Sessions] = NS_COMMON::Options::preflightURL(PreflightEndpoint::Sessions);
#endif
}
LeakChecker::~LeakChecker()
{
#if !defined(US_RETAIL)
s_forceNonSecure = false;
#endif
}
void LeakChecker::SetUp()
{
#if defined(US_USE_LIBCURL) && !defined(US_DLL) && !defined(US_TARGET_SWITCH)
g_skipEalMemForLibcurl = m_skipEalMemForLibcurl;
#endif
BadEvents::createInstance();
// Wait at least 1 ms to make sure that all subsequent memory allocations
// will not have the same timer value than m_testStartTime. Otherwise
// getAllocatedMemoryInfo would not display those allocations.
Helper::sleep(1);
#if defined(US_PROFILE)
FAProfiler::Init(FAPROFILER_ALLOCATED_MEMORY);
FAProfilerDisk::Init();
FAProfiler::Enable();
EalPerfLibInit();
// This fake a frame for the whole test
// Not required but it can be helpful
FAProfiler::BeginNewFrame();
#endif
US_PERF_SET_CURRENT_THREADNAME("Main");
if (m_type == AutoExecuteInit || m_type == InitNoScheduler)
{
initDefaultSDK();
}
if (m_type == AutoExecuteInit)
{
resetLogLevel();
#if defined(US_TARGET_XONE)
// The following internal device allows to redirect UbiServices internal
// logging into the Google test logging framework. This may be useful
// to redirect all the logging sequence into a single output file.
// This solution however does not work for unit tests explicitly
// initializing the SDK.
class LogDeviceGtest : public LogDevice
{
public:
void output(const String& logString, LogLevel logLevel, const String& file, uint32 line) override
{
US_UNUSED(logLevel);
US_UNUSED(file);
US_UNUSED(line);
harbour_printf::internalPrintf("%s", logString.getUtf8());
}
};
InstancesManager::getInstance()->getEventLog().setLogDevice(US_NEW(LogDeviceGtest));
#endif
}
}
void LeakChecker::TearDown()
{
if (m_type == AutoExecuteInit || m_type == InitNoScheduler)
{
uninitDefaultSDK();
}
EXPECT_TRUE(!m_willLeak || SIMPL_NS::g_memoryLeakAtShutdown) <<
"[ US_TEST_ERROR_FAILED ] Expected memory leaks did not occurred in this test.";
EXPECT_TRUE(m_willLeak || m_mightLeak || !SIMPL_NS::g_memoryLeakAtShutdown) <<
"[ US_TEST_ERROR_FAILED ] Memory leaks occurred during this test.";
EXPECT_FALSE(SIMPL_NS::g_memoryCorruption) <<
"[ US_TEST_ERROR_FAILED ] Memory Corruption occurred during this test.";
#if defined(US_PROFILE)
// Profiler needs to be terminated after Ubiservices or it might crash during unitiliazeSDK()
EalPerfLibShutdown();
FAProfiler::Disable();
FAProfilerDisk::Serialize(getTestName());
FAProfilerDisk::Shutdown();
FAProfiler::Shutdown();
#endif
#if defined(US_ENABLE_ALLOC_STATS)
{
m_currentTestAllocStatistics.m_allocCountCurrent = g_stats.m_allocCountCurrent - m_currentTestAllocStatistics.m_allocCountCurrent;
m_currentTestAllocStatistics.m_allocCountTotal = g_stats.m_allocCountTotal - m_currentTestAllocStatistics.m_allocCountTotal;
m_currentTestAllocStatistics.m_allocSizeTotal = g_stats.m_allocSizeTotal - m_currentTestAllocStatistics.m_allocSizeTotal;
m_currentTestAllocStatistics.m_allocArrayCountCurrent = g_stats.m_allocArrayCountCurrent - m_currentTestAllocStatistics.m_allocArrayCountCurrent;
m_currentTestAllocStatistics.m_allocArrayCountTotal = g_stats.m_allocArrayCountTotal - m_currentTestAllocStatistics.m_allocArrayCountTotal;
m_currentTestAllocStatistics.m_allocArraySizeTotal = g_stats.m_allocArraySizeTotal - m_currentTestAllocStatistics.m_allocArraySizeTotal;
m_currentTestAllocStatistics.m_newArrayWithZero = g_stats.m_newArrayWithZero - m_currentTestAllocStatistics.m_newArrayWithZero;
m_currentTestAllocStatistics.m_deleteWithNull = g_stats.m_deleteWithNull - m_currentTestAllocStatistics.m_deleteWithNull;
m_currentTestAllocStatistics.m_deleteArrayWithNull = g_stats.m_deleteArrayWithNull - m_currentTestAllocStatistics.m_deleteArrayWithNull;
}
// Printing with tabs for easier adaptation to excel sheet
US_NS::Log::print("\n");
US_NS::Log::print("--- Memory allocation statistics ---\n");
US_NS::Log::print("Stats: Test_name\tallocCountCurrent\tallocCountTotal\tallocSizeTotal\tallocArrayCountCurrent\t");
US_NS::Log::print("allocArrayCountTotal\tallocArraySizeTotal\tnewArrayWithZero\tdeleteWithNull\tdeleteArrayWithNull\n");
US_NS::Log::print("Stats: %s.%s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", getTestCaseName(), getTestName(), m_currentTestAllocStatistics.m_allocCountCurrent
, m_currentTestAllocStatistics.m_allocCountTotal, m_currentTestAllocStatistics.m_allocSizeTotal, m_currentTestAllocStatistics.m_allocArrayCountCurrent
, m_currentTestAllocStatistics.m_allocArrayCountTotal, m_currentTestAllocStatistics.m_allocArraySizeTotal, m_currentTestAllocStatistics.m_newArrayWithZero
, m_currentTestAllocStatistics.m_deleteWithNull, m_currentTestAllocStatistics.m_deleteArrayWithNull);
US_NS::Log::print("-----------------------------------\n");
#endif
// NB : This line needs to be placed AFTER the EalPerfLisShutdown in the US_PROFILE part.
EXPECT_TRUE(g_AllocCounter == NULL) <<
"[ US_TEST_ERROR_FAILED ] Memory manager shouldn't be initialized anymore at the end of the test. "
"Please check in this test that the number of SDK initialize matches the number of SDK uninitialize";
BadEvents::deleteInstance();
#if defined(US_USE_LIBCURL) && !defined(US_DLL) && !defined(US_TARGET_SWITCH)
g_skipEalMemForLibcurl = false;
#endif
}
FacadeInternal& LeakChecker::getFacadeInternal(Facade& facade)
{
return *facade.m_facadeInternal;
}
const FacadeInternal& LeakChecker::getFacadeInternal(const Facade& facade)
{
return *facade.m_facadeInternal;
}
EventLog* LeakChecker::getEventLog()
{
if (g_testEventLog == NULL)
{
g_testEventLog = US_NEW(EventLog);
}
return g_testEventLog;
}
void LeakChecker::outputLog(LogLevel level, LogCategory category, const char* string, const char* file, uint32 line)
{
if (g_testEventLog == NULL)
{
g_testEventLog = US_NEW(EventLog);
}
if (g_testEventLog->isLogEnabled(level, category))
{
g_testEventLog->outputLog(level, category, string, file, line);
}
}
void LeakChecker::setLogLevel(LogLevel logLevel)
{
if (g_testEventLog == NULL)
{
g_testEventLog = US_NEW(EventLog);
}
g_testEventLog->setLogLevel(logLevel);
g_testEventLog->getOutputFormat().setShowTag(OutputFormat::Time, true);
// Forces level to warning in case the previously executed test set it to an other value.
if(InstancesManager::getInstance() != NULL)
{
EventLog& eventLog = InstancesManager::getInstance()->getEventLog();
eventLog.setLogLevel(logLevel);
}
}
void LeakChecker::resetLogLevel()
{
setLogLevel(LogLevel::Warning);
}
void LeakChecker::setMultiLinesLog(bool state)
{
if (g_testEventLog == NULL)
{
g_testEventLog = US_NEW(EventLog);
}
g_testEventLog->enableMultiLines(state); // Setup for US_TEST_LOG EventLog
#if defined(US_LOG_ENABLED)
LoggingHelper::enableMultiLines(state); // Setup for US_LOG EventLog
#endif
}
void LeakChecker::setupDebugLogging()
{
#if defined(US_LOG_ENABLED)
LoggingHelper::enableMultiLines(true);
LoggingHelper::enableVerbose(true);
#endif
setLogLevel(LogLevel::Debug);
}
void LeakChecker::disableLogCategories()
{
#if defined(US_LOG_ENABLED)
for (uint32 i = static_cast<uint32>(LogCategory::ENUM_BEGIN); i != static_cast<uint32>(LogCategory::ENUM_END); ++i)
{
LoggingHelper::disableCategory(static_cast<LogCategory>(i));
}
#endif
}
void LeakChecker::enableLogCategories(const Vector<LogCategory>& categories)
{
#if defined(US_LOG_ENABLED)
disableLogCategories();
for (LogCategory category : categories)
{
LoggingHelper::enableCategory(category);
}
#else
US_UNUSED(categories);
#endif
}
HttpConfig LeakChecker::getHttpConfig() const
{
return HttpConfig();
}
const char* LeakChecker::getTestName() const
{
const ::testing::TestInfo* testInfo = ::testing::UnitTest::GetInstance()->current_test_info();
return testInfo->name();
}
const char* US_NS::LeakChecker::getTestCaseName() const
{
const ::testing::TestInfo* testInfo = ::testing::UnitTest::GetInstance()->current_test_info();
return testInfo->test_case_name();
}
void LeakChecker::initDefaultSDK()
{
initializeSdk();
if (m_type != InitNoScheduler)
{
#if defined(ENABLE_PROXY_SETTINGS_TEST)
US_NS::HttpConfig httpConfig;
httpConfig.m_proxy.m_host = "127.0.0.1"; // Fiddler proxy port
httpConfig.m_proxy.m_port = 8888; // Fiddler proxy port
httpConfig.m_proxy.m_username = "username";
httpConfig.m_proxy.m_username = "password";
httpConfig.m_proxy.m_proxyType = HttpProxyConfig::Type::Enabled;
#elif defined(US_TARGET_SWITCH)
US_NS::HttpConfig httpConfig;
//httpConfig.m_proxy.m_host = "127.0.0.1"; // Fiddler proxy port
//httpConfig.m_proxy.m_port = 8888; // Fiddler proxy port
//httpConfig.m_proxy.m_username = "username";
//httpConfig.m_proxy.m_username = "password";
httpConfig.m_proxy.m_proxyType = HttpProxyConfig::Type::AutoProxy;
#else
const US_NS::HttpConfig httpConfig = getHttpConfig();
#endif
const GameConfig gameConfig(ApplicationId(NS_COMMON::Options::getApplicationId().c_str())
#if defined(US_SDK_TEST_CHINA)
, String("CHINA_IS_PROD")
#else
, NS_COMMON::Options::getApplicationBuildId().c_str()
#endif
#if defined(US_SDK_S2S)
, NS_COMMON::Options::environment()
#endif
#if defined(US_SDK_TEST_CHINA)
, OnlineAccessContext::China
#else
, OnlineAccessContext::Standard
#endif
#if !defined(US_SDK_S2S)
, GameConfigEvent(US_SDK_VERSION_CONST_CHAR
, US_TEST_NS::US_SDK_DUMMY_GAME_SKU
, LeakChecker_BF::getDefaultEventTypesForSaveGame()
, StringJson("{}")
, NS_COMMON::Options::getApplicationSecretKey().c_str())
#endif //!defined(US_SDK_S2S)
#if defined(US_TARGET_PS4) || defined(US_TARGET_SWITCH) || defined(US_TARGET_XONE) || defined(US_TARGET_GGP) || defined(US_TARGET_KILI)
, GameConfigConsole(NS_COMMON::FIRSTPARTY_APP_ID)
#endif
);
const SystemConfig systemConfig(US_NS::ThreadingConfig(), httpConfig);
const US_NS::ConfigureResult result = configureSdk(gameConfig, systemConfig);
if (result != ConfigureResult::Success)
{
PRINT_DEBUG("configureSdk FAILED with error : %d", result);
}
EXPECT_EQ(result, ConfigureResult::Success);
#if !defined(US_SDK_S2S)
EXPECT_TRUE(InstancesHelper::SetBackdoorEnvironment(NS_COMMON::Options::environment()));
#endif
}
}
void LeakChecker::uninitDefaultSDK()
{
US_TEST_NS::Helper::uninitializeSdk();
}
#if defined(US_USE_LIBCURL) && !defined(US_DLL) && !defined(US_TARGET_SWITCH)
void LeakCheckerNoLibcurlEalMem::SetUp()
{
g_skipEalMemForLibcurl = true;
LeakChecker::SetUp();
}
#endif
LeakCheckerScopedInit::LeakCheckerScopedInit(LeakChecker& testInstance)
: m_testInstance(testInstance)
{
m_testInstance.LeakChecker::initDefaultSDK();
}
LeakCheckerScopedInit::~LeakCheckerScopedInit()
{
m_testInstance.LeakChecker::uninitDefaultSDK();
}
};