//////////////////////////////////////////////////////////////////////////////// // (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour // //////////////////////////////////////////////////////////////////////////////// #include "tests/config.h" #include "tests/fixture/memoryCheckFixture.h" #include #include #include #include #include #include <../private/ubiservices/localizationHelperPriv.h> #include <../private/ubiservices/core/debug/systemChecker.h> #include <../private/ubiservices/core/configs/environmentHelper.h> #include <../private/ubiservices/core/helpers/facadesManager.h> #include <../private/ubiservices/core/helpers/helpers.h> #include <../private/ubiservices/core/helpers/instancesManager.h> #include #include #include #include #include // 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(TestInstancesManager); }; #if !defined US_DLL && (!defined(US_UNITY3D) && !defined(RETAIL)) namespace US_NS {; typedef LeakCheckerNoInit INSTANCE_MANAGER; /// @cond PRIVATE_API namespace TestInstancesManager_BF { class SystemCheckerMock { public: SystemCheckerMock() { m_hasAsserted = false; SystemChecker::RegisterSystemCheckCallBack(&SystemCheckerMock::systemCheck); } ~SystemCheckerMock() { SystemChecker::UnregisterSystemCheckCallBack(); } bool hasAsserted() const { return m_hasAsserted; } void reset() { m_hasAsserted = false; } private: static void systemCheck(const char* strExpression, const char* szFile, uint32 uiLine) { US_UNUSED(strExpression); US_UNUSED(szFile); US_UNUSED(uiLine); m_hasAsserted = true; } static bool m_hasAsserted; }; bool SystemCheckerMock::m_hasAsserted = false; #if defined(US_TARGET_XONE) const uint32 MAX_UNINIT_TIME_IN_MICRO = 85 * 1000; // Empiric value (found values between 42000 and 83000 in debug) #else const uint32 MAX_UNINIT_TIME_IN_MICRO = 35 * 1000; // Empiric value (32000 happened on the build farm) #endif } /// @endcond /// @test Validates that ASSERT occurs if the InstanceManager is accessed before calling configure. #if !defined(US_SYSTEM_CHECK_ENABLED) TEST_F(INSTANCE_MANAGER, DISABLED_LOCAL_GetInstanceManagerAsserts) #else TEST_F(INSTANCE_MANAGER, LOCAL_GetInstanceManagerAsserts) #endif // US_RETAIL { TestInstancesManager_BF::SystemCheckerMock sysCheckMock; initializeSdk(); EXPECT_TRUE(InstancesManager::getInstance() == NULL); EXPECT_TRUE(sysCheckMock.hasAsserted()); sysCheckMock.reset(); configureSdk(GameConfig( ApplicationId(NS_COMMON::Options::getApplicationId().c_str()), NS_COMMON::Options::getApplicationBuildId().c_str() #if defined(US_SDK_S2S) , NS_COMMON::Options::environment() #endif , OnlineAccessContext::Standard #if !defined(US_SDK_S2S) , GameConfigEvent(US_SDK_VERSION_CONST_CHAR, US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()) #endif #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 )); EXPECT_FALSE(InstancesManager::getInstance() == NULL); EXPECT_FALSE(sysCheckMock.hasAsserted()); US_TEST_NS::Helper::uninitializeSdk(); EXPECT_FALSE(sysCheckMock.hasAsserted()); EalLogLibInit(); EXPECT_TRUE(InstancesManager::getInstance() == NULL); EXPECT_TRUE(sysCheckMock.hasAsserted()); EalLogLibShutdown(); } /// @test Validates normal creation/destruction sequence. #if !defined(US_SYSTEM_CHECK_ENABLED) TEST_F(INSTANCE_MANAGER, DISABLED_LOCAL_NormalUsage) // TODO: Disabled in retail #else TEST_F(INSTANCE_MANAGER, LOCAL_NormalUsage) #endif // US_RETAIL { initializeSdk(); TestInstancesManager_BF::SystemCheckerMock sysCheckMock; { configureSdk(GameConfig( ApplicationId(NS_COMMON::Options::getApplicationId().c_str()), NS_COMMON::Options::getApplicationBuildId().c_str() #if defined(US_SDK_S2S) , NS_COMMON::Options::environment() #endif , OnlineAccessContext::Standard #if !defined(US_SDK_S2S) , GameConfigEvent(US_SDK_VERSION_CONST_CHAR, US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()) #endif #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 )); { Facade facade; } } US_TEST_NS::Helper::uninitializeSdk(); EXPECT_FALSE(sysCheckMock.hasAsserted()); initializeSdk(); { configureSdk(GameConfig( ApplicationId(NS_COMMON::Options::getApplicationId().c_str()), NS_COMMON::Options::getApplicationBuildId().c_str() #if defined(US_SDK_S2S) , NS_COMMON::Options::environment() #endif , OnlineAccessContext::Standard #if !defined(US_SDK_S2S) , GameConfigEvent(US_SDK_VERSION_CONST_CHAR, US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()) #endif #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 )); { Facade facade1; Facade facade2; } EXPECT_FALSE(sysCheckMock.hasAsserted()); { Facade facade; } } US_TEST_NS::Helper::uninitializeSdk(); EXPECT_FALSE(sysCheckMock.hasAsserted()); } /// @test Validates that ASSERT occurs if the facade is created before /// the InstanceManager. Validation for facade destruction is done /// in an other test case. #if !defined(US_SYSTEM_CHECK_ENABLED) TEST_F(INSTANCE_MANAGER, DISABLED_LOCAL_FacadeBeforeInit) // TODO: Disabled in retail #else TEST_F(INSTANCE_MANAGER, LOCAL_FacadeBeforeInit) #endif // US_RETAIL { TestInstancesManager_BF::SystemCheckerMock sysCheckMock; Facade facade; EXPECT_TRUE(sysCheckMock.hasAsserted()); sysCheckMock.reset(); } /// @test Validates that memory is actually released when uninitialize is called #if !defined(US_SYSTEM_CHECK_ENABLED) TEST_F(INSTANCE_MANAGER, DISABLED_LOCAL_Init) // TODO: Disabled in retail #else TEST_F(INSTANCE_MANAGER, LOCAL_Init) #endif //US_RETAIL { initializeSdk(); TestInstancesManager_BF::SystemCheckerMock sysCheckMock; configureSdk(GameConfig( ApplicationId(NS_COMMON::Options::getApplicationId().c_str()), NS_COMMON::Options::getApplicationBuildId().c_str() #if defined(US_SDK_S2S) , NS_COMMON::Options::environment() #endif , OnlineAccessContext::Standard #if !defined(US_SDK_S2S) , GameConfigEvent(US_SDK_VERSION_CONST_CHAR, US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()) #endif #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 )); { Facade facade; } const uint32 memStart = EalMemGetAllocated(); // should delete hosted object (log, httpManager...) US_TEST_NS::Helper::uninitializeSdk(); EXPECT_FALSE(sysCheckMock.hasAsserted()); const uint32 memEnd = EalMemGetAllocated(); EXPECT_GE(memStart, memEnd); } /// @test Validates normal destruction sequence happens after a login. #if !defined(US_SYSTEM_CHECK_ENABLED) TEST_F(INSTANCE_MANAGER, DISABLED_US_NormalUsageAndLogin) // TODO: Disabled in retail #else TEST_F(INSTANCE_MANAGER, US_NormalUsageAndLogin) #endif // RETAIL_VERSION { initializeSdk(); TestInstancesManager_BF::SystemCheckerMock sysCheckMock; configureSdk(GameConfig( ApplicationId(NS_COMMON::Options::getApplicationId().c_str()), NS_COMMON::Options::getApplicationBuildId().c_str() #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, Vector()) #endif #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 )); { Facade facade; const AsyncResult loginAsync = facade.createSession(GET_CREDENTIALS(), {}, {}); EXPECT_TRUE(loginAsync.wait(NS_COMMON::DEFAULT_WAIT_TIME)); US_EXPECT_SUCCESS(loginAsync); } US_TEST_NS::Helper::uninitializeSdk(); EXPECT_FALSE(sysCheckMock.hasAsserted()); } /// @test Validates that \c uninitializeSDK can be called when a facade /// still exists. A system check is expected during facade destruction because /// a message is attempted to be written to the EventLog. /// @disabled Is this feature still supported? See US-4197 #if !defined(US_SYSTEM_CHECK_ENABLED) TEST_F(INSTANCE_MANAGER, DISABLED_LOCAL_UninitThenDeleteFacade) // TODO: Disabled in retail #else TEST_F(INSTANCE_MANAGER, DISABLED_LOCAL_UninitThenDeleteFacade) // TODO: Is this feature still supported? See US-4197 #endif // US_RETAIL { initializeSdk(); TestInstancesManager_BF::SystemCheckerMock sysCheckMock; { configureSdk(GameConfig( ApplicationId(NS_COMMON::Options::getApplicationId().c_str()), NS_COMMON::Options::getApplicationBuildId().c_str() #if defined(US_SDK_S2S) , NS_COMMON::Options::environment() #endif , OnlineAccessContext::Standard #if !defined(US_SDK_S2S) , GameConfigEvent(US_SDK_VERSION_CONST_CHAR, US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()) #endif #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 )); Facade facade; US_TEST_NS::Helper::uninitializeSdk(); EXPECT_FALSE(sysCheckMock.hasAsserted()); } EXPECT_TRUE(sysCheckMock.hasAsserted()); } /// @test Validates that \c uninitializeSdk may be called when a facade is connected. /// A system check is expected during facade destruction because a message is /// attempted to be written to the \c EventLog. /// @disabled Is this feature still supported? See US-4197 #if !defined(US_SYSTEM_CHECK_ENABLED) TEST_F(INSTANCE_MANAGER, DISABLED_US_UninitThenDeleteFacadeAfterLogin) // TODO: Disabled in retail #else // TODO review: adding the new event config request causes deadlock warnings. // We must play with the locks level to make sure everything is fine TEST_F(INSTANCE_MANAGER, DISABLED_US_UninitThenDeleteFacadeAfterLogin) // TODO: Is this feature still supported? See US-4197 #endif // US_RETAIL { initializeSdk(); TestInstancesManager_BF::SystemCheckerMock sysCheckMock; { configureSdk(GameConfig( ApplicationId(NS_COMMON::Options::getApplicationId().c_str()), NS_COMMON::Options::getApplicationBuildId().c_str() #if defined(US_SDK_S2S) , NS_COMMON::Options::environment() #endif , OnlineAccessContext::Standard #if !defined(US_SDK_S2S) , GameConfigEvent(US_SDK_VERSION_CONST_CHAR, US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()) #endif #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 )); Facade facade; const AsyncResult loginAsync = facade.createSession(GET_CREDENTIALS(), {}, {}); EXPECT_TRUE(loginAsync.wait(NS_COMMON::DEFAULT_WAIT_TIME)); US_EXPECT_SUCCESS(loginAsync); US_TEST_NS::Helper::uninitializeSdk(); EXPECT_FALSE(sysCheckMock.hasAsserted()); } EXPECT_TRUE(sysCheckMock.hasAsserted()); } /// @test Validates that \c uninitializeSDK can be called when jobs are pending. /// A system check is expected during facade destruction because a message is attempted /// to be written to the EventLog. #if !defined(US_SYSTEM_CHECK_ENABLED) TEST_F(INSTANCE_MANAGER, DISABLED_US_UninitDuringLogin) // TODO: Disabled in retail #else /// @note Failed on Xbox One (flaky). Dead locking on tear down... TEST_F(INSTANCE_MANAGER, DISABLED_US_UninitDuringLogin) // TODO: Disabled... why? #endif // US_RETAIL { initializeSdk(); // Checking asserts does not work in retail TestInstancesManager_BF::SystemCheckerMock sysCheckMock; { configureSdk(GameConfig( ApplicationId(NS_COMMON::Options::getApplicationId().c_str()), NS_COMMON::Options::getApplicationBuildId().c_str() #if defined(US_SDK_S2S) , NS_COMMON::Options::environment() #endif , OnlineAccessContext::Standard #if !defined(US_SDK_S2S) , GameConfigEvent(US_SDK_VERSION_CONST_CHAR, US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()) #endif #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 )); Facade facade; const AsyncResult loginAsync = facade.createSession(GET_CREDENTIALS(), {}, {}); ASSERT_TRUE(loginAsync.isProcessing()); Helper::sleep(500); // to make sure job is started US_TEST_NS::Helper::uninitializeSdk(); EXPECT_FALSE(sysCheckMock.hasAsserted()); } EXPECT_TRUE(sysCheckMock.hasAsserted()); } namespace HelperUninit { struct Stats { ClockSteady::TDuration first = 0; ClockSteady::TDuration min = static_cast(-1); ClockSteady::TDuration max = 0; ClockSteady::TDuration sum = 0; uint32 count = 0; }; Stats UninitializeSdk() { Stats stats; EXPECT_EQ(0, stats.count); EXPECT_EQ(0, stats.sum); UninitializeResult result; do { const ClockSteady::TTimePoint start = ClockSteady::getTime(); result = uninitializeSdk(); const ClockSteady::TTimePoint end = ClockSteady::getTime(); const ClockSteady::TDuration duration = (end - start).getEpoch(); if (stats.first == 0) { stats.first = duration; } if (duration < stats.min) { stats.min = duration; } if (duration > stats.max) { stats.max = duration; } stats.sum += duration; stats.count++; } while (result != UninitializeResult::Complete); PRINT_LINE("Time consumed executing uninitializeSdk (first call): %d", static_cast(stats.first.getCount())); if (stats.count > 1) { PRINT_LINE("Time consumed executing uninitializeSdk (min/max): %d/%d", static_cast(stats.min.getCount()), static_cast(stats.max.getCount())); } else { PRINT_LINE("Time consumed executing uninitializeSdk (min/max): -/-"); } PRINT_LINE("Total time consumed executing uninitializeSdk: %d", static_cast(stats.sum.getCount())); PRINT_LINE("Total calls to uninitializeSdk: %d", static_cast(stats.count)); PRINT_LINE("Avegage time processing uninitializeSdk: %d", static_cast((stats.sum.getCount()) / stats.count)); return stats; } } TEST_F(INSTANCE_MANAGER, LOCAL_NonBlockingUninitWitness) { initializeSdk(); configureSdk(GameConfig( ApplicationId(NS_COMMON::Options::getApplicationId().c_str()), NS_COMMON::Options::getApplicationBuildId().c_str() #if defined(US_SDK_S2S) , NS_COMMON::Options::environment() #endif , OnlineAccessContext::Standard #if !defined(US_SDK_S2S) , GameConfigEvent(US_SDK_VERSION_CONST_CHAR, US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()) #endif #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 )); //US_TEST_NS::Helper::uninitializeSdk(); // Not applicable for this test. const auto stats = HelperUninit::UninitializeSdk(); EXPECT_LE(stats.max.getCount(), TestInstancesManager_BF::MAX_UNINIT_TIME_IN_MICRO * 1000); } TEST_F(INSTANCE_MANAGER, US_NonBlockingUninitDuringLogin) // TODO: Rework required { initializeSdk(); configureSdk(GameConfig( ApplicationId(NS_COMMON::Options::getApplicationId().c_str()), NS_COMMON::Options::getApplicationBuildId().c_str() #if defined(US_SDK_S2S) , NS_COMMON::Options::environment() #endif , OnlineAccessContext::Standard #if !defined(US_SDK_S2S) , GameConfigEvent(US_SDK_VERSION_CONST_CHAR, US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()) #endif #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 )); Helper::sleep(500); // to make sure job is started // Perform login { Facade facade; const AsyncResult loginAsync = facade.createSession(GET_CREDENTIALS(), {}, {}); ASSERT_TRUE(loginAsync.isProcessing()); Helper::sleep(500); // to make sure job is started } //US_TEST_NS::Helper::uninitializeSdk(); // Not applicable for this test. const auto stats = HelperUninit::UninitializeSdk(); EXPECT_LE(stats.max.getCount(), TestInstancesManager_BF::MAX_UNINIT_TIME_IN_MICRO * 1000); } #if !defined(US_SDK_S2S) TEST_F(INSTANCE_MANAGER, LOCAL_LocalizationLocaleCode) { initializeSdk(); { configureSdk(GameConfig( ApplicationId(NS_COMMON::Options::getApplicationId().c_str()), NS_COMMON::Options::getApplicationBuildId().c_str() #if defined(US_SDK_S2S) , NS_COMMON::Options::environment() #endif , OnlineAccessContext::Standard #if !defined(US_SDK_S2S) , GameConfigEvent(US_SDK_VERSION_CONST_CHAR, US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()) #endif #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 )); // See LocalizationHelper documentation for information on why PS4 is disabled here. #if !defined(US_TARGET_PS4) && !defined(US_TARGET_KILI) EXPECT_NE(String(), LocalizationHelper::getLocaleCode()); EXPECT_EQ(LocalizationHelperPrivate::getPlatformLocaleCode(), LocalizationHelper::getLocaleCode()); #endif const String localCode = "us-EN"; LocalizationHelper::setLocaleCode(localCode); EXPECT_EQ(localCode, LocalizationHelper::getLocaleCode()); } US_TEST_NS::Helper::uninitializeSdk(); } #endif }; #endif // !defined US_DLL && (!defined(US_UNITY3D) && !defined(RETAIL))