//////////////////////////////////////////////////////////////////////////////// // (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour // //////////////////////////////////////////////////////////////////////////////// #include "tests/config.h" #if defined(US_SDK_LIGHT_MOBILE) #error This file shall not be part of the solution #endif #include "tests/fixture/authenticationFixture.h" #include "tests/fixture/loginMockFixture.h" #include "tests/mock/mockLogDevice.h" #include "tests/mock/mockResultHelper.h" #include <../private/ubiservices/core/configs/environmentHelper.h> #include <../private/ubiservices/core/helpers/instancesHelper.h> #include <../private/ubiservices/services/parameters/parametersClientProxy.h> #include #include #include #include #include #if defined(US_SDK_TEST_CHINA) #define APP_ID_US_SDK_SPECIAL_TESTS_PC "586cc2e2-29c0-4522-8626-a1159939abe4" #else #define APP_ID_US_SDK_SPECIAL_TESTS_PC "bb875ed4-07a0-461e-bb33-882b4964dda1" #endif namespace US_NS {; US_DEFINE_TEST(TestApplicationHistoryClient); typedef AuthenticationFixture<1> APPLICATIONS_USED; typedef LoginMockFixture APPLICATIONS_USED_MOCK; typedef LeakCheckerNoInit APPLICATIONS_USED_NOINIT; #if !defined(US_DLL) namespace ApplicationUsedInfoPrivate { bool extractData(const Json& source, ApplicationUsedInfo& target); } #if defined(US_TARGET_WINDOWS) /// @test In UAT, data expires automatically after 3 months /// Therefore we need to login (actually send a player start) from each profile, /// on each applications used in the RequestApplicationsUsed test to avoid expiration. #if defined(US_CHINA_ACCOUNTS_SETUP_NOT_DONE) TEST_F(APPLICATIONS_USED_NOINIT, DISABLED_US_RequestApplicationsUsedSetup) #else TEST_F(APPLICATIONS_USED_NOINIT, US_RequestApplicationsUsedSetup) #endif // defined(US_CHINA_ACCOUNTS_SETUP_NOT_DONE) { struct Local { static void sendEventOnCurrentApp(const String& email, const String& password) { Facade facade; // The createSession should trigger a player.start ASSERT_TRUE(AsyncHelper::waitSuccess(facade.createSession(PlayerCredentials(email, password), {}, {}))); // Need to wait until the event config has been retrieved in order to sendEvents. ASSERT_TRUE(US_TEST_NS::Helper::waitForPostLogin(facade)); // The deleteSession should force sending the player.start ASSERT_TRUE(AsyncHelper::waitSuccess(facade.deleteSession())); } }; //expectProcessingJobsAtJobManagerDestruction(); // ussdk017 and ussdk018 connect to UbiServices SDK PC initializeSdk(); { const GameConfig gameConfig( ApplicationId(US_TEST_NS::APP_ID_US_SDK_PC), 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(), "{}", NS_COMMON::Options::getApplicationSecretKey().c_str()) #endif ); configureSdk(gameConfig); Local::sendEventOnCurrentApp("ussdk017@ubisoft.com", "a1234567"); Local::sendEventOnCurrentApp("ussdk018@ubisoft.com", "a1234567"); } US_TEST_NS::Helper::uninitializeSdk(); // ussdk018 and ussdk019 connect to UbiServices SDK Special Tests PC initializeSdk(); { const GameConfig gameConfig2( ApplicationId(APP_ID_US_SDK_SPECIAL_TESTS_PC), 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(), "{}", NS_COMMON::Options::getApplicationSecretKey().c_str()) #endif ); configureSdk(gameConfig2); //PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Status code: 403", LogLevel::Error).Times(2); }); Local::sendEventOnCurrentApp("ussdk018@ubisoft.com", "a1234567"); Local::sendEventOnCurrentApp("ussdk019@ubisoft.com", "a1234567"); } US_TEST_NS::Helper::uninitializeSdk(); } #endif #endif // !defined(US_DLL) /// This test uses data that can expire after 3 months, in UAT, if the tested profiles are not "playing" the tested applications, /// i.e. if the tested profile is not sending any player.start event from the the tested application. /// @warning Only a few applications are monitored in UAT. You can get the list here /// (and eventually request to activate other applications): /// https://dna-center/Dashboard/Monitoring/TitleStateForApplicationUsedHistory /// @warning This test should be working only in UAT. The applications tested are not monitored in other environments /// @note For punctual tests, it is possible to configure application usage manually for a given profile. /// https://dna-center/DnaServices/ApplicationUsedHistory/ViewPlayerApplications /// However, these data will expire after three months. Do not use these data for automatic tests. // TODO: Rework test after the friend's cache has been corrected. // [US-12465] As Preparing2017, I want caches to follow the same pattern TEST_F(APPLICATIONS_USED, DISABLED_US_RequestApplicationsUsed) { if (isEnvironmentNot(Environment::Uat)) { return; // Configuration required in the environment. } // The following test requires proper server configuration. { const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsedForAllApplications(); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); // Note : Despite the tests are not run automatically on mobile platforms (and data could expire), // the following line is still valid since the profile used on these platforms is the same as on PC and OSX // The number of application used is always above 1. EXPECT_LE(1u, result.getResult().size()); } //getFacade().getProfileClient().invalidateCacheApplicationUsed(); { const Vector applications { ApplicationId("9edaaf7f-2cbf-42bc-8037-067e5bfed518"), // This is not a valid appId ApplicationId("9edaaf7f-2cbf-42bc-8037-067e5bfed518") }; const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed(applications); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); EXPECT_EQ(0u, result.getResult().size()); } //getFacade().getProfileClient().invalidateCacheApplicationUsed(); { const Vector profiles = { ProfileId("d2fb4dfa-653e-4937-84e9-20b0d0622e41"), // ussdk017 ProfileId("4277e08e-ac55-4453-aafd-4bc7dc72afa8"), // ussdk018 ProfileId("c819ca41-6064-4f43-b9a1-2eb9c91a3c04") // ussdk019 }; const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed({ ApplicationId(APP_ID_US_SDK_SPECIAL_TESTS_PC) }, profiles); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); EXPECT_EQ(2u, result.getResult().size()); } //getFacade().getProfileClient().invalidateCacheApplicationUsed(); { const Vector profiles = { ProfileId("d2fb4dfa-653e-4937-84e9-20b0d0622e41"), // ussdk017 ProfileId("4277e08e-ac55-4453-aafd-4bc7dc72afa8"), // ussdk018 ProfileId("c819ca41-6064-4f43-b9a1-2eb9c91a3c04") // ussdk019 }; const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsedForAllApplications(profiles); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); EXPECT_EQ(4u, result.getResult().size()); } } TEST_F(APPLICATIONS_USED_MOCK, USNOT_RequestApplicationsUsedForAllApplicationsWithModifiedResponseForForwardCompatibility) { const StringJson json = "{" " \"before\" : true," " \"applications\": [" " {" " \"profileId\": \"4d9061de-7c20-4cc9-9f55-b8d6228da6ae\"," " \"firstSessionDate\" : \"2017-10-18T18:19:35.659Z\"," " \"lastSessionDate\" : \"2017-10-18T18:19:39.778Z\"," " \"applicationId\" : \"043a4bd9-9336-4cc3-b51c-1da703f89f87\"," " \"sessionsCount\" : 4" " }," " {" " \"profileId\": \"4d9061de-7c20-4cc9-9f55-b8d6228da6ae\"," " \"applicationId\" : \"085021fb-32ea-4b1c-b5c6-1dd39dc27d5f\"," " \"firstSessionDate\" : \"2016-08-01T14:56:02.255Z\"," " \"lastSessionDate\" : \"2016-08-01T15:34:07.064Z\"," " \"uselessArray\" : [" " 1," " 2," " 3," " 4," " 5" " ]," " \"sessionsCount\" : 4" " }" " ]," " \"other\" : 5" "}"; HttpGet request(StringUrl("")); { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); StringStream expectedUrl; expectedUrl << "/profiles/mock-applications"; US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, expectedUrl.getContent()) .WillOnce(testing::DoAll(testing::SaveArg<0>(static_cast(&request)), testing::Return(mockResult))); } const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsedForAllApplications(); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(2u, result.getResult().size()); } TEST_F(APPLICATIONS_USED_MOCK, USNOT_RequestApplicationsUsedWithModifiedResponseForForwardCompatibility) { const StringJson json = "{" " \"before\": true," " \"applications\": [" " {" " \"profileId\": \"4d9061de-7c20-4cc9-9f55-b8d6228da6ae\"," " \"firstSessionDate\" : \"2015-09-17T15:35:29.768Z\"," " \"lastSessionDate\" : \"2017-11-17T19:13:11.803Z\"," " \"applicationId\" : \"1521fc83-86e3-4d7b-bc64-f0b2dc2f6e89\"," " \"uselessArray\" : [" " 1," " 2," " 3," " 4," " 5" " ]," " \"sessionsCount\" : 10540337" " }" " ]," " \"other\" : 5" "}"; HttpGet request(StringUrl("")); { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); StringStream expectedUrl; expectedUrl << "/profiles/mock-allProfiles-applications"; US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, expectedUrl.getContent()) .WillOnce(testing::DoAll(testing::SaveArg<0>(static_cast(&request)), testing::Return(mockResult))); } const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed( Vector(), { ProfileId("4d9061de-7c20-4cc9-9f55-b8d6228da6ae") }); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); const Vector& applicationUsedInfo = result.getResult(); ASSERT_EQ(1u, applicationUsedInfo.size()); ASSERT_EQ(ProfileId("4d9061de-7c20-4cc9-9f55-b8d6228da6ae"), applicationUsedInfo[0].m_profileId); } #if !defined(US_DLL) TEST_F(APPLICATIONS_USED_MOCK, USNOT_RequestApplicationsUsedFeatureSwitchOff) { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("ApplicationUsed feature/service shut down by feature switch. Skipping the request.", LogLevel::Warning, Times(1)); }); ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::ApplicationUsed, false); ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getProfileClient().requestApplicationsUsed(), Errors::SKIPPED_FEATURESWITCH)); } #endif TEST_F(APPLICATIONS_USED_MOCK, USNOT_RequestApplicationsUsed) { { const StringJson jsonBody = "{" "\"applications\": [" "{" "\"profileId\": \"9edaaf7f-2cbf-42bc-8037-067e5bfed518\"," "\"applicationId\": \"9edaaf7f-2cbf-42bc-8037-067e5bfed518\"," "\"firstSessionDate\": \"2010-11-23T03:02:01.0000000\"," "\"lastSessionDate\": \"2011-01-03T04:05:06.0000000\"," "\"sessionsCount\": 440" "}" "]" "}"; const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(jsonBody); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles/mock-applications", mockResult); } const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed(); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(1u, result.getResult().size()); const ApplicationUsedInfo& info = result.getResult().front(); EXPECT_STREQ("9edaaf7f-2cbf-42bc-8037-067e5bfed518", static_cast(info.m_applicationId).getUtf8()); EXPECT_EQ(DateTime(2010, 11, 23, 3, 2, 1), info.m_firstDatePlayed); EXPECT_EQ(DateTime(2011, 1, 3, 4, 5, 6), info.m_lastDatePlayed); EXPECT_EQ(440, info.m_sessionPlayedCount); } /// @test Requests Application Used parsing a JSON structure containing extra Root node. // TODO: Rework test after the friend's cache has been corrected. // [US-12465] As Preparing2017, I want caches to follow the same pattern TEST_F(APPLICATIONS_USED_MOCK, DISABLED_USNOT_RequestApplicationsUsedWithExtraRootNode) { const StringJson jsonBody = "{" // Extra root node "\"extraRootNode\":" "[" "{" "\"name\":\"extraItem\"," "\"quantity\" : 2" "}" "]," "\"applications\": [" "{" "\"profileId\": \"9edaaf7f-2cbf-42bc-8037-067e5bfed518\"," "\"applicationId\": \"9edaaf7f-2cbf-42bc-8037-067e5bfed518\"," "\"firstSessionDate\": \"2010-11-23T03:02:01.0000000\"," "\"lastSessionDate\": \"2011-01-03T04:05:06.0000000\"," "\"sessionsCount\": 440" "}" "]" "}"; { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(jsonBody); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles/mock-applications", mockResult); } const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed(); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); EXPECT_EQ(1, result.getResult().size()); } // TODO: Rework test after the application used cache has been corrected. // [US-12465] As Preparing2017, I want caches to follow the same pattern TEST_F(APPLICATIONS_USED_MOCK, DISABLED_USNOT_RequestApplicationsUsedWithFiltering) { const StringJson jsonBody = "{" "\"applications\": [" "{" "\"profileId\": \"9edaaf7f-2cbf-42bc-8037-067e5bfed518\"," "\"applicationId\": \"9edaaf7f-2cbf-42bc-8037-067e5bfed518\"," "\"firstSessionDate\": \"2010-11-23T03:02:01.0000000\"," "\"lastSessionDate\": \"2011-01-03T04:05:06.0000000\"," "\"sessionsCount\": 440" "}" "]" "}"; { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(jsonBody); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles/mock-applications?applicationIds=9edaaf7f-2cbf-42bc-8037-067e5bfed518", mockResult); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles/mock-allProfiles-applications?profileIds=9edaaf7f-2cbf-42bc-8037-067e5bfed518", mockResult); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles/mock-allProfiles-applications?profileIds=9edaaf7f-2cbf-42bc-8037-067e5bfed518&applicationIds=9edaaf7f-2cbf-42bc-8037-067e5bfed518", mockResult); } const Vector applications = { ApplicationId("9edaaf7f-2cbf-42bc-8037-067e5bfed518") }; { const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed(applications); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(1u, result.getResult().size()); const ApplicationUsedInfo& info = result.getResult().front(); EXPECT_STREQ("9edaaf7f-2cbf-42bc-8037-067e5bfed518", static_cast(info.m_applicationId).getUtf8()); EXPECT_EQ(DateTime(2010, 11, 23, 3, 2, 1), info.m_firstDatePlayed); EXPECT_EQ(DateTime(2011, 1, 3, 4, 5, 6), info.m_lastDatePlayed); EXPECT_EQ(440, info.m_sessionPlayedCount); } const Vector profiles{ ProfileId("9edaaf7f-2cbf-42bc-8037-067e5bfed518") }; //getFacade().getProfileClient().invalidateCacheApplicationUsed(); { const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed(Vector(), profiles); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(1u, result.getResult().size()); } //getFacade().getProfileClient().invalidateCacheApplicationUsed(); { const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed(applications, profiles); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(1u, result.getResult().size()); } } TEST_F(APPLICATIONS_USED_MOCK, USNOT_RequestApplicationsUsedErrorJsonSyntax) { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Request Application History failed. Invalid JSON in response's body:", LogLevel::Error, Times(1)); }); const StringJson jsonBody = //"{" // Intentionally missing "\"applications\": [" "{" "\"profileId\": \"9edaaf7f-2cbf-42bc-8037-067e5bfed518\"," "\"applicationId\": \"9edaaf7f-2cbf-42bc-8037-067e5bfed518\"," "\"firstSessionDate\": \"2010-11-23T00:00:00.0000000\"," "\"lastSessionDate\": \"2011-01-03T00:00:00.0000000\"," "\"sessionsCount\": 440" "}" "]" "}"; { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(jsonBody); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles/mock-applications", mockResult); } ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getProfileClient().requestApplicationsUsed(), Errors::CORE_INVALID_JSON_FORMAT)); } TEST_F(APPLICATIONS_USED_MOCK, USNOT_RequestApplicationsUsedErrorMissingFields) { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("issing mandatory field: firstSessionDate", LogLevel::Error, Times(1)); US_EXPECT_LOG("issing mandatory field: sessionsCount", LogLevel::Error, Times(1)); US_EXPECT_LOG("Unexpected JSON format. Ignoring ApplicationHistory:", LogLevel::Warning, Times(1)); }); const StringJson jsonBody = "{" "\"applications\": [" "{" "\"profileId\": \"9edaaf7f-2cbf-42bc-8037-067e5bfed518\"," "\"applicationId\": \"9edaaf7f-2cbf-42bc-8037-067e5bfed518\"," //"\"firstSessionDate\": \"2010-11-23T00:00:00.0000000\"," // Intentionally missing "\"lastSessionDate\": \"2011-01-03T00:00:00.0000000\"" //"\"sessionsCount\": 440" // Intentionally missing "}" "]" "}"; { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(jsonBody); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles/mock-applications", mockResult); } const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed(); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(0u, result.getResult().size()) << "Invalid record shall be ignored."; } TEST_F(APPLICATIONS_USED_MOCK, USNOT_RequestApplicationsUsedExtraFields) { const StringJson jsonBody = "{" "\"applications\": [" "{" "\"profileId\": \"9edaaf7f-2cbf-42bc-8037-067e5bfed518\"," "\"applicationId\": \"9edaaf7f-2cbf-42bc-8037-067e5bfed518\"," "\"firstSessionDate\": \"2010-11-23T00:00:00.0000000\"," "\"lastSessionDate\": \"2011-01-03T00:00:00.0000000\"," "\"sessionsCount\": 440," "\"daysPlayedExtra1\": 346,"// Extra field #1 "\"daysPlayedExtra2\": 346" // Extra field #2 "}" "]" "}"; { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(jsonBody); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles/mock-applications", mockResult); } const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed(); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(1u, result.getResult().size()); } /// @test Checks that an error is raised and no request is sent when only invalid applicationIds are given as parameter TEST_F(APPLICATIONS_USED_MOCK, USNOT_RequestApplicationsUsedForAllApplicationsDefaultValues) { HttpGet request(StringUrl("")); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "/mock-applications") .WillOnce(testing::DoAll( testing::SaveArg<0>(static_cast(&request)), testing::Return(MockResultHelper::createSuccessResult()))); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().getProfileClient().requestApplicationsUsedForAllApplications())); const String query = URLInfo(request.getUrl()).getQuery(); EXPECT_EQ(String::npos, query.findSubstringCase("applicationIds=")); EXPECT_EQ(String::npos, query.findSubstringCase("profileIds=")); } /// @test Checks that an error is raised and no request is sent when only invalid applicationIds are given as parameter TEST_F(APPLICATIONS_USED_MOCK, USNOT_RequestApplicationsUsedDefaultValues) { HttpGet request(StringUrl("")); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "/mock-applications") .WillOnce(testing::DoAll( testing::SaveArg<0>(static_cast(&request)), testing::Return(MockResultHelper::createSuccessResult()))); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().getProfileClient().requestApplicationsUsed())); StringStream expectedAppIds; expectedAppIds << "applicationIds=" << InstancesHelper::getApplicationId(); const String query = URLInfo(request.getUrl()).getQuery(); EXPECT_NE(String::npos, query.findSubstringCase(expectedAppIds.getContent())); EXPECT_EQ(String::npos, query.findSubstringCase("profileIds=")); } /// @test Checks that an error is raised and no request is sent when only invalid applicationIds are given as parameter TEST_F(APPLICATIONS_USED_MOCK, USNOT_RequestApplicationsUsedOnlyInvalidApplicationIds) { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("ApplicationId 'Invalid Id #1' is invalid. It is not used to request application used", LogLevel::Warning, Times(1)); US_EXPECT_LOG("ApplicationId 'Invalid Id #2' is invalid. It is not used to request application used", LogLevel::Warning, Times(1)); US_EXPECT_LOG("No valid applicationId given to request applications used", LogLevel::Error, Times(1)); }); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "/mock-applications").Times(0); const Vector applicationIds{ ApplicationId("Invalid Id #1"), ApplicationId("Invalid Id #2") }; ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getProfileClient().requestApplicationsUsed(applicationIds), Errors::PROFILES_INVALID_PARAM)); } /// @test Checks that an error is raised and no request is sent when only invalid profileIds are given as parameter TEST_F(APPLICATIONS_USED_MOCK, USNOT_RequestApplicationsUsedOnlyInvalidProfileIds) { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("ProfileId 'Invalid Id #1' is invalid. It is not used to request application used", LogLevel::Warning, Times(1)); US_EXPECT_LOG("ProfileId 'Invalid Id #2' is invalid. It is not used to request application used", LogLevel::Warning, Times(1)); US_EXPECT_LOG("No valid profileId given to request applications used", LogLevel::Error, Times(1)); }); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "/mock-applications").Times(0); const Vector profiles = { ProfileId("Invalid Id #1"), ProfileId("Invalid Id #2") }; ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getProfileClient().requestApplicationsUsed(Vector(), profiles), Errors::PROFILES_INVALID_PARAM)); } /// @test Checks that an error is raised and no request is sent when only invalid profileIds are given as parameter TEST_F(APPLICATIONS_USED_MOCK, USNOT_RequestApplicationsUsedForAllApplicationsOnlyInvalidProfileIds) { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("ProfileId 'Invalid Id #1' is invalid. It is not used to request application used", LogLevel::Warning, Times(1)); US_EXPECT_LOG("ProfileId 'Invalid Id #2' is invalid. It is not used to request application used", LogLevel::Warning, Times(1)); US_EXPECT_LOG("No valid profileId given to request applications used", LogLevel::Error, Times(1)); }); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "/mock-allProfiles-applications").Times(0); const Vector profileIds = { ProfileId("Invalid Id #1"), ProfileId("Invalid Id #2") }; ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getProfileClient().requestApplicationsUsedForAllApplications(profileIds), Errors::PROFILES_INVALID_PARAM)); } #if !defined(US_DLL) #define UST_STREAM_TITLE_VALUE(_stream, _title) _stream << _title << ": " << std::endl #define UST_STREAM_FIELD_VALUE(_stream, _label, _value) _stream << _label << ": " << _value << std::endl ::std::ostream& operator<<(::std::ostream& stream, const DateTime& source) { StringStream ss; ss << source; stream << ss.getContent().getUtf8(); return stream; } ::std::ostream& operator<<(::std::ostream& stream, const ApplicationUsedInfo& source) { UST_STREAM_TITLE_VALUE(stream, "ApplicationUsedInfo"); UST_STREAM_FIELD_VALUE(stream, "Profile Id", source.m_profileId); UST_STREAM_FIELD_VALUE(stream, "Application Id", source.m_applicationId); UST_STREAM_FIELD_VALUE(stream, "First Session Date", source.m_firstDatePlayed); UST_STREAM_FIELD_VALUE(stream, "Last Session Date", source.m_lastDatePlayed); UST_STREAM_FIELD_VALUE(stream, "Sessions Count", source.m_sessionPlayedCount); return stream; } // TODO: Rework test after the friend's cache has been corrected. // [US-12465] As Preparing2017, I want caches to follow the same pattern TEST_F(APPLICATIONS_USED_MOCK, DISABLED_USNOT_RequestApplicationsUsedCache) { SAVE_ALLOC_COUNT(count); JsonWriter writer; ApplicationUsedInfo appUsedInfo; EXPECT_ALLOC_COUNT_PC_EQ(5, count); { JsonWriter appUsed; EXPECT_ALLOC_COUNT_PC_EQ(3, count); appUsed["profileId"] = "9edaaf7f-2cbf-42bc-8037-067e5bfed518"; appUsed["applicationId"] = "9edaaf7f-2cbf-42bc-8037-067e5bfed518"; appUsed["firstSessionDate"] = "2010-11-23T03:02:01.0000000"; appUsed["lastSessionDate"] = "2011-01-03T04:05:06.0000000"; appUsed["sessionsCount"] = 440; ASSERT_TRUE(ApplicationUsedInfoPrivate::extractData(appUsed.getJson(), appUsedInfo)); EXPECT_ALLOC_COUNT_PC_EQ(78, count); writer["applications"] = Vector({ appUsed.getJson() }); } { const String jsonBody = writer.renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(jsonBody); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles/mock-applications", mockResult); } { const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed(); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(1u, result.getResult().size()); } // Second call should not send request { const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed(); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(1u, result.getResult().size()); } // Invalidating the cache should trigger request send //getFacade().getProfileClient().invalidateCacheApplicationUsed(); SAVE_ALLOC_COUNT(count2); JsonWriter writer2; ApplicationUsedInfo appUsedInfo2; EXPECT_ALLOC_COUNT_PC_EQ(5, count2); { JsonWriter appUsed; EXPECT_ALLOC_COUNT_PC_EQ(3, count2); appUsed["profileId"] = "1111aaaa-1111-1111-1111-aaaabbbbcccc"; appUsed["applicationId"] = "9edaaf7f-2cbf-42bc-8037-067e5bfed518"; appUsed["firstSessionDate"] = "2010-11-23T03:02:01.0000000"; appUsed["lastSessionDate"] = "2011-01-03T04:05:06.0000000"; appUsed["sessionsCount"] = 23; ASSERT_TRUE(ApplicationUsedInfoPrivate::extractData(appUsed.getJson(), appUsedInfo2)); EXPECT_ALLOC_COUNT_PC_EQ(78, count2); writer2["applications"] = Vector({ appUsed.getJson() }); } const String jsonBody2 = writer2.renderContent(); { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(jsonBody2); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles/mock-applications", mockResult); } { const AsyncResult > result = getFacade().getProfileClient().requestApplicationsUsed(); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(1u, result.getResult().size()); } } #endif }; #undef APP_ID_US_SDK_SPECIAL_TESTS_PC