//////////////////////////////////////////////////////////////////////////////// // (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/memoryCheckFixture.h" #include "tests/fixture/paramFixture.h" #include "tests/mock/mockLogDevice.h" #include "tests/mock/mockProfileHelper.h" #include "tests/mock/mockResultHelper.h" #include "tests/mock/parametersMockHelper.h" #include "tests/common/cancelTest.h" #include "tests/fixture/loginMockFixture.h" #include #include #include #include #include #include #include #include <../private/ubiservices/core/helpers/instancesManager.h> #include <../private/ubiservices/services/friend/friendClientProxy.h> #include #include #include #include #include #include <../private/ubiservices/services/profile/profileTypeHelper.h> #include #include // Please do not delete yet ! DomD //#if defined(US_TARGET_PS4) //#include "usCommon/ps4/firstPartyInit.h" //#endif namespace US_NS {; US_DEFINE_TEST(TestFriendsCommon); const char* const HTTP_EMPTY_BODY = ""; const char* const UPLAY_PROFILE_ID = "9070605b-ecc4-4153-86bc-2eacc1c5faaa"; const char* const TEST_PROFILE_ID = "68e7e6f5-cf7e-4650-ba1a-f8ac546c9d71"; const char* const TEST_PROFILE_ID_2 = "11111111-2222-3333-4444-555566667777"; const char* const TEST_PROFILE_ID_CERT2 = "68e7e6f5-cf7e-4650-ba1a-f8ac546c9d71"; const char* const TEST_PROFILE_ID_INVALID = "11111111-2222-3333-4444-555566667777"; typedef AuthenticationFixture<1, true> FRIENDS; typedef AuthenticationFixture<1, false> FRIENDS_NO_LOGIN; typedef LoginMockFixture FRIENDS_MOCK; typedef LoginMockFixture FRIENDS_MOCK_CANCEL; typedef LoginMockFixture FRIENDS_MOCK_NOLOGIN; typedef LeakChecker FRIENDS_NO_FACADE; typedef LeakCheckerNoInit FRIENDS_NO_INIT; // Cancel test settings typedef AuthenticationFixtureWithParam::type FRIENDS_CANCEL; US_DEFINE_LONG_TEST_P(FRIENDS_CANCEL, TestConfigCancel(20), TestConfigCancel(10)); /// @cond PRIVATE_API namespace TestFriends_BF { const static char* s_TEXT_REPLACEMENT = "(Forbidden Terms)"; /// Validates that the result contains the players "ussdk002" and "ussdk003". void validateClubFriends( const AsyncResult >& resultFriends, bool usingForbiddenTerms = false) { const String USSDK_2_NAME = "ussdk002"; const String USSDK_3_NAME = "ussdk003"; ASSERT_LE(2u, resultFriends.getResult().size()); ASSERT_TRUE(resultFriends.getResult().front().getInfoClub() != NULL); const uint32 EXPECTED_USERNAME_COUNT = 2u; uint32 usernameCount = 0; for(const auto& itRelation : resultFriends.getResult()) { const FriendInfoClub* info = itRelation.getInfoClub(); ASSERT_TRUE(info != NULL); if (usingForbiddenTerms && ((info->m_profileInfo.m_nameOnPlatform == s_TEXT_REPLACEMENT) || (info->m_profileInfo.m_nameOnPlatform == USSDK_3_NAME))) { usernameCount++; } else if ( (info->m_profileInfo.m_nameOnPlatform == USSDK_2_NAME) || (info->m_profileInfo.m_nameOnPlatform == USSDK_3_NAME)) { usernameCount++; } ASSERT_TRUE(info->m_profileInfo.m_userId.isSpecified()); ASSERT_TRUE(info->m_profileInfo.m_userId.value().isValid()); if (info->m_relation != FriendInfoClub::Friends && info->m_relation != FriendInfoClub::PendingSentInvite && info->m_relation != FriendInfoClub::PendingReceivedInvite) { EXPECT_TRUE(false); // Received an unknown value } // Ignoring info->m_date for now } EXPECT_EQ(EXPECTED_USERNAME_COUNT, usernameCount); // Only 1 friend when requesting with Club as entry point #if defined(US_LOG_ENABLED) // Temp debug code if (EXPECTED_USERNAME_COUNT != usernameCount) { ::std::cout << "Invalid number of friends. Dumping friends:"; for(const auto& itRelation : resultFriends.getResult()) { StringStream msg; msg << itRelation << US_NS::endl; ::std::cout << msg.getContent().getAnsi(); } } #endif } /// Requests Club friends and validates that the result contains the expected players void requestClubFriends(Facade& facade, bool usingForbiddenTerms = false) { const AsyncResult > resultFriends = facade.getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); ASSERT_TRUE(AsyncHelper::waitSuccess(resultFriends)); validateClubFriends(resultFriends, usingForbiddenTerms); for (const auto& it : resultFriends.getResult()) { EXPECT_TRUE(it.getInfoClub()->m_profileInfo.m_profileId.isValid()); EXPECT_FALSE(it.getInfoClub()->m_profileInfo.m_nameOnPlatform.isEmpty()); } } #if defined(US_TARGET_XONE) AsyncResult> checkRelationShipChange(Facade& facade, bool& eventReceived, FriendClient::Mode friendRequestMode) { Windows::Xbox::System::User^ user = Helper::getUser(facade.getAuthenticationClient().getSessionInfo().getPlayerCredentials()); AsyncResult> resultChange; #if defined(US_XONE_USE_XSAPI_CPP) std::shared_ptr xboxLiveContext(new xbox::services::xbox_live_context(user)); xboxLiveContext->real_time_activity_service()->activate(); xboxLiveContext->social_service().add_social_relationship_changed_handler( [&facade, &eventReceived, friendRequestMode, &resultChange](xbox::services::social::social_relationship_change_event_args args) { PRINT_LINE("Friend change event detected."); // Invalidate cache PlatformHelper::forwardSocialRelationShipChange(args); // 3rd friend request, after invalidating cache resultChange = facade.getFriendClient().requestFriends(friendRequestMode); ASSERT_TRUE(AsyncHelper::waitSuccess(resultChange)); ASSERT_EQ(3, resultChange.getResult().size()); // This value might change depending on the friends setup for current user. eventReceived = true; }); xboxLiveContext->social_service().subscribe_to_social_relationship_change(user->XboxUserId->Data()); #else Microsoft::Xbox::Services::XboxLiveContext^ xboxLiveContext = ref new Microsoft::Xbox::Services::XboxLiveContext(user); xboxLiveContext->RealTimeActivityService->Activate(); Windows::Foundation::EventRegistrationToken onSocialRelationshipChangedRegistration = xboxLiveContext->SocialService->SocialRelationshipChanged += ref new Windows::Foundation::EventHandler( [&facade, &eventReceived, friendRequestMode, &resultChange] (::Platform::Object^, Microsoft::Xbox::Services::Social::SocialRelationshipChangeEventArgs^ args) { PRINT_LINE("Friend change event detected."); // Invalidate cache PlatformHelper::forwardSocialRelationShipChange(XoneSocialRelationshipChangeEventArgs(args)); // 3rd friend request, after invalidating cache resultChange = facade.getFriendClient().requestFriends(friendRequestMode); ASSERT_TRUE(AsyncHelper::waitSuccess(resultChange)); ASSERT_EQ(3, resultChange.getResult().size()); // This value might change depending on the friends setup for current user. eventReceived = true; }); US_UNUSED(onSocialRelationshipChangedRegistration); xboxLiveContext->SocialService->SubscribeToSocialRelationshipChange(user->XboxUserId); #endif return resultChange; } #endif } /// @endcond // China infrastructure is not ready yet, currently only supports Windows #if defined(US_TARGET_WINDOWS) && defined(US_SDK_TEST_CHINA) /// @test Request club friends while simulating China context /// @disabled uplaycn platformtype is currently not supported by the service. JIRA US-16595 to reenable it. #if defined(US_CHINA_ACCOUNTS_SETUP_NOT_DONE) // 0 friends in china TEST_F(FRIENDS_NO_INIT, DISABLED_US_RequestClubFriendsChina) #else TEST_F(FRIENDS_NO_INIT, US_RequestClubFriendsChina) #endif { const US_TEST_NS::ScopedInit autoInit; { ApplicationId chinaPcAppId("586cc2e2-29c0-4522-8626-a1159939abe4"); String chinaPcBuildId("CHINA_IS_PROD"); configureSdk(GameConfig( chinaPcAppId, chinaPcBuildId, #if defined(US_SDK_S2S) NS_COMMON::Options::environment(), #endif OnlineAccessContext::China, GameConfigEvent(String(), US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()), GameConfigConsole()), SystemConfig(US_NS::ThreadingConfig())); // Perform the login Facade facade; const String sessionRailId(US_TEST_NS::WEGAME_SESSION_ID); const US_NS::String playerRailId(US_TEST_NS::WEGAME_PROFILE_RAIL_ID); const String gameRailId(US_TEST_NS::WEGAME_GAME_RAIL_ID); const US_NS::String weGameToken(US_NS::CredentialsTypeHelper::getWeGameToken(sessionRailId, playerRailId, gameRailId)); const PlayerCredentials credentials(weGameToken, US_NS::CredentialsType::WeGame, playerRailId); ASSERT_TRUE(AsyncHelper::waitSuccess(facade.createSession(credentials, {}, {}))); const AsyncResult > resultFriends = facade.getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); ASSERT_TRUE(AsyncHelper::waitSuccess(resultFriends)); const Vector friends = resultFriends.getResult(); EXPECT_EQ(friends.size(), 3); for (const auto& it : friends) { EXPECT_TRUE(it.getInfoClub()->m_profileInfo.m_profileId.isValid()); EXPECT_FALSE(it.getInfoClub()->m_profileInfo.m_nameOnPlatform.isEmpty()); } EXPECT_TRUE(AsyncHelper::waitSuccess(facade.deleteSession())); } } #endif // Disabled on Xbox One because of friend community segregation between X360 and XONE players. #if !defined(US_TARGET_XONE) /// @test Requests Club friends... #if defined(US_CHINA_ACCOUNTS_SETUP_NOT_DONE) // 0 friends in china TEST_F(FRIENDS, DISABLED_US_RequestClubFriendsCheckingProfileIds) #elif defined(US_TARGET_GGP) // To run this test your ggp account needs to be linked to a ubisoft profile // And your ubisoft profile needs to be friends with another ubisoft profile that has a ggp linked to that account. TEST_F(FRIENDS, DISABLED_MANUAL_US_RequestClubFriendsCheckingProfileIds) #else TEST_F(FRIENDS, US_MINRUN_RequestClubFriendsCheckingProfileIds) #endif { const AsyncResult > resultFriends = getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); ASSERT_TRUE(AsyncHelper::waitSuccess(resultFriends)); const Vector friends = resultFriends.getResult(); EXPECT_GE(friends.size(), 1ul); for(const auto& it : friends) { EXPECT_TRUE(it.getInfoClub()->m_profileInfo.m_profileId.isValid()); EXPECT_FALSE(it.getInfoClub()->m_profileInfo.m_nameOnPlatform.isEmpty()); } } #if defined(US_TARGET_WINDOWS) /// @test Request Club friends with modified response having useless data TEST_F(FRIENDS_MOCK, USNOT_RequestClubFriendsCheckingProfileIdsConsolidatedWithModifiedResponseForForwardCompatibility) { Vector friendsMock; { JsonWriter friend1; friend1["pid"] = "68e7e6f5-cf7e-4650-ba1a-f8ac546c9d71"; friend1["lastModified"] = "2017-11-09T04:22:53.6570000"; friend1["state"] = "PendingSentInvite"; friendsMock.push_back(friend1.getJson()); JsonWriter friend2; friend2["pid"] = "fa6fd9aa-7726-4e83-a08f-ee61523c6cfa"; friend2["lastModified"] = "2017-08-07T20:03:54.9470000"; friend2["state"] = "PendingReceivedInvite"; friendsMock.push_back(friend2.getJson()); Vector uselessArray; uselessArray.push_back("1"); uselessArray.push_back("2"); uselessArray.push_back("3"); JsonWriter friend3; friend3["pid"] = "b2cfc7a1-a08e-4bd8-adf3-73cb1c19faf1"; friend3["lastModified"] = "2014-08-06T00:00:00.0000000"; friend3["state"] = "Friends"; friend3["uselessData"] = true; friend3["uselessArray"] = uselessArray; friendsMock.push_back(friend3.getJson()); JsonWriter friend4; friend4["pid"] = "a701a60d-1fd9-4c4f-98a2-b33fa8beb00f"; friend4["lastModified"] = "2014-06-30T00:00:00.0000000"; friend4["state"] = "Friends"; friendsMock.push_back(friend4.getJson()); } JsonWriter writerFriends; writerFriends["before"] = true; writerFriends["friends"] = friendsMock; writerFriends["other"] = 5; Vector profilesMock; { JsonWriter profile1; profile1["profileId"] = "b2cfc7a1-a08e-4bd8-adf3-73cb1c19faf1"; profile1["userId"] = "b2cfc7a1-a08e-4bd8-adf3-73cb1c19faf1"; profile1["platformType"] = "uplay"; profile1["idOnPlatform"] = "B2CFC7A1-A08E-4BD8-ADF3-73CB1C19FAF1"; profile1["nameOnPlatform"] = "ussdk002"; profilesMock.push_back(profile1.getJson()); JsonWriter profile2; profile2["profileId"] = "a701a60d-1fd9-4c4f-98a2-b33fa8beb00f"; profile2["userId"] = "a701a60d-1fd9-4c4f-98a2-b33fa8beb00f"; profile2["platformType"] = "uplay"; profile2["idOnPlatform"] = "A701A60D-1FD9-4C4F-98A2-B33FA8BEB00F"; profile2["nameOnPlatform"] = "ussdk003"; profilesMock.push_back(profile2.getJson()); } JsonWriter writerProfiles; writerProfiles["profiles"] = profilesMock; ::testing::Sequence s; { const MockAsyncResult friendsMockResult = MockResultHelper::createSuccessResult(writerFriends.renderContent()); StringStream friendsExpectedUrl; friendsExpectedUrl << "/mock-friendsClub"; US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, friendsExpectedUrl.getContent(), friendsMockResult); } { const MockAsyncResult profilesMockResult = MockResultHelper::createSuccessResult(writerProfiles.renderContent()); StringStream profilesExpectedUrl; profilesExpectedUrl << "/mock-profiles?userId"; US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, profilesExpectedUrl.getContent(), profilesMockResult); } const AsyncResult > resultFriends = getFacade().getFriendClient().requestFriends(FriendClient::Consolidated); ASSERT_TRUE(AsyncHelper::waitSuccess(resultFriends)); const Vector friends = resultFriends.getResult(); ASSERT_GE(friends.size(), 1ul); for (const auto& it : friends) { EXPECT_TRUE(it.getInfoClub()->m_profileInfo.m_profileId.isValid()); EXPECT_FALSE(it.getInfoClub()->m_profileInfo.m_nameOnPlatform.isEmpty()); } } #endif /// @test Requests Club friends from the first Test environment player. /// @note The test currently only targets Win32 because it requires the /// player profile to have a Ubi Account with two friends to succeed. #if defined(US_CHINA_ACCOUNTS_SETUP_NOT_DONE) // 0 friends in china TEST_F(FRIENDS, DISABLED_US_Win32RequestClubFriends) #else TEST_F(FRIENDS, US_Win32RequestClubFriends) #endif { TestFriends_BF::requestClubFriends(getFacade()); } TEST_F(FRIENDS, US_RequestFriendsListShareCount) { AsyncResult > h1; { const AsyncResult > h = getFacade().getFriendClient().requestFriends(FriendClient::ConsoleWithClubInfo); h1 = h; EXPECT_TRUE(h1.isProcessing()); } // Friend service is still in scope ASSERT_TRUE(AsyncHelper::waitSuccess(h1)); } #if !defined(US_DLL) #if defined(US_CHINA_ACCOUNTS_SETUP_NOT_DONE) // 0 friends in china TEST_F(FRIENDS, DISABLED_US_RequestProfileId) #else TEST_F(FRIENDS, US_MINRUN_RequestProfileId) #endif { const SessionInfo sessionInfo = (getFacade().getAuthenticationClient().getSessionInfo()); ProfileInfo profileInfo; { #if (defined(US_ENABLE_UPLAY_LOGIN) && !defined(US_TARGET_IOS)) || defined(US_UPLAY_LOGIN_FOR_IOS) || defined(US_TARGET_MANJARO) //manjaro tempo const String onlineId = sessionInfo.getUserId(); #elif defined(US_TARGET_XONE) const String onlineId = sessionInfo.getPlayerCredentials().getXuid(); #elif defined(US_TARGET_PS4) || defined(US_TARGET_KILI) SceNpAccountId accountId; sceNpGetAccountIdA(sessionInfo.getPlayerCredentials().getUserId(), &accountId); const String onlineId = String::formatText("%lld", accountId); #elif defined(US_TARGET_SWITCH) const uint64 id = sessionInfo.getPlayerCredentials().getNsaId().id; const String onlineId = String::formatText("%08X%08X", static_cast((id >> 32) & 0xFFFFFFFF), static_cast(id & 0xFFFFFFFF)); #elif defined(US_TARGET_IOS) const String onlineId = sessionInfo.getPlayerCredentials().getPlayerID(); #elif defined(US_TARGET_GGP) const String onlineId = String::formatText("%llu", sessionInfo.getPlayerCredentials().getPlayerId()); #else #error Oups, not yet supported!!! #endif #if defined(US_ENABLE_UPLAY_LOGIN) const AsyncResult > result = getFacade().getProfileClient().requestProfiles({ onlineId }, ProfileTypeHelper::getProfileTypeDefault()); #else const AsyncResult > result = getFacade().getProfileClient().requestProfiles({ onlineId }); #endif ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_GT(result.getResult().size(), 0ull); EXPECT_TRUE(result.getResult().find(onlineId)->second.m_profileId.isValid()); EXPECT_EQ(getFacade().getAuthenticationClient().getSessionInfo().getProfileId(), result.getResult().find(onlineId)->second.m_profileId); profileInfo = result.getResult().find(onlineId)->second; } { const AsyncResult > result = getFacade().getProfileClient().requestProfiles(Vector({ profileInfo.m_profileId })); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_GT(result.getResult().size(), 0ull); Map::const_iterator profileIt = result.getResult().find(profileInfo.m_profileId); EXPECT_TRUE(profileIt != result.getResult().end()); if (profileIt != result.getResult().end()) { ProfileInfo resultProfileInfo = profileIt->second; EXPECT_TRUE(resultProfileInfo.m_profileId.isValid()); EXPECT_EQ(getFacade().getAuthenticationClient().getSessionInfo().getProfileId(), resultProfileInfo.m_profileId); EXPECT_EQ(profileInfo.m_profileId, resultProfileInfo.m_profileId); EXPECT_TRUE(resultProfileInfo.m_userId.isSpecified()); if (profileInfo.m_userId.isSpecified() && resultProfileInfo.m_userId.isSpecified()) { EXPECT_EQ(profileInfo.m_userId.value(), resultProfileInfo.m_userId.value()); } EXPECT_EQ(profileInfo.m_profileType, resultProfileInfo.m_profileType); EXPECT_EQ(profileInfo.m_idOnPlatform, resultProfileInfo.m_idOnPlatform); EXPECT_EQ(profileInfo.m_nameOnPlatform, resultProfileInfo.m_nameOnPlatform); } } { const UserId uplayId = sessionInfo.getUserId(); const AsyncResult > result = getFacade().getProfileClient().requestUplayProfiles(Vector{ uplayId }); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_GT(result.getResult().size(), 0ull); Map::const_iterator itUserId = result.getResult().find(uplayId); ASSERT_TRUE(itUserId != result.getResult().end()); EXPECT_TRUE(itUserId->second.m_profileId.isValid()); // The profile id from the sessionInfo is specific for the console platform, // whereas the profile from the lookup belongs to Club. ASSERT_TRUE(itUserId->second.m_userId.isSpecified()); EXPECT_EQ(sessionInfo.getUserId(), itUserId->second.m_userId.value()); } } #endif /// @test Validates that \c FriendClient::requestFriends may be fire and forgotten // TODO: This test shall be performed using mock. There is no way to confirm // that the call completed successfully in the current implementation. TEST_F(FRIENDS, US_RequestClubFriendsFireAndForget) { { const AsyncResult > resultFriends = getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); EXPECT_FALSE(resultFriends.wait(100)); // Just make sure the job is started, not just scheduled. EXPECT_TRUE(resultFriends.isProcessing()); } // The test must not end before the job complete (otherwise, it will be canceled). // Wait for the requestFriends to complete using an arbitrary time interval. // The test assumes fire & forget succeed if no crash occurs... US_TEST_NS::Helper::sleep(2000); } #endif // US_TARGET_XONE TEST_F(FRIENDS, US_InviteFriendClub) { const Environment currentEnvironment = getFacade().getAuthenticationClient().getSessionInfo().getEnvironmentCode(); const ProfileId profileId(currentEnvironment == Environment::Cert2 ? TEST_PROFILE_ID_CERT2 : TEST_PROFILE_ID); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().getFriendClient().sendFriendsClubInvite({ profileId }))); } #if defined(US_CHINA_ACCOUNTS_SETUP_NOT_DONE) // 0 friends in china TEST_F(FRIENDS, DISABLED_US_RequestPendingFriendsClub) #else TEST_F(FRIENDS, US_RequestPendingFriendsClub) #endif { const AsyncResult > result = getFacade().getFriendClient().requestFriendsClubInvites(); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); const Vector& friends = result.getResult(); //all test accounts should have a pending friend invitation from ussdk010 EXPECT_GE(friends.size(), 1ul) << "Configuration requires a pending friend for this test to be valid."; for(const auto& it : friends) { const FriendInfoClub* info = it.getInfoClub(); EXPECT_TRUE(info != NULL && info->m_relation == FriendInfoClub::PendingReceivedInvite); } } #if defined(US_CHINA_ACCOUNTS_SETUP_NOT_DONE) // return HTTP_404_NOT_FOUND instead of HTTP_403_FORBIDDEN TEST_F(FRIENDS, DISABLED_US_AcceptInviteClub) #else TEST_F(FRIENDS, US_AcceptInviteClub) #endif { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Status code: 403", LogLevel::Error, Times(1)); US_EXPECT_LOG("Friends accept/invite for the following error:", LogLevel::Error, Times(1)); }); ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getFriendClient().acceptFriendClubInvite(ProfileId(UPLAY_PROFILE_ID)), Errors::HTTP_403_FORBIDDEN)); } /// @tests that declining a non existant invitation returns a 200 /// @note service is returning 200 because it does not validate if the profileId passed is actually a friend/inviting TEST_F(FRIENDS, US_DeclineInviteClub) { ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().getFriendClient().declineFriendClubInvite(ProfileId(UPLAY_PROFILE_ID)))); } /// @tests that removing a friend that does not exist in a friend list returns 200. /// @note service is returning 200 because it does not validate if the profileId passed is actually a friend/inviting TEST_F(FRIENDS, US_RemoveFriendClub) { ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().getFriendClient().removeFriendClub(ProfileId(TEST_PROFILE_ID_INVALID)))); } /// @test Requests console friends twice in parallel. /// @note service is returning 200 because it does not validate if the profileId passed is actually a friend/inviting TEST_F(FRIENDS, US_RequestConsoleFriendsTwiceInParallel) { const AsyncResult< US_NS::Vector > result1 = getFacade().getFriendClient().requestFriends(FriendClient::ConsoleWithClubInfo); const AsyncResult< US_NS::Vector > result2 = getFacade().getFriendClient().requestFriends(FriendClient::ConsoleWithClubInfo); EXPECT_TRUE(result1.isProcessing()); EXPECT_TRUE(result2.isProcessing()); EXPECT_TRUE(result1.wait(NS_COMMON::DEFAULT_WAIT_TIME)); EXPECT_TRUE(result1.hasSucceeded()); EXPECT_TRUE(result2.wait(NS_COMMON::DEFAULT_WAIT_TIME)); EXPECT_TRUE(result2.hasSucceeded()); } // Disabled on XOne due to community segregation between X360 and XOne #if !defined(US_TARGET_XONE) /// @test Validates that \c FriendClient::requestFriends can be cancelled at anytime /// This tests passes 75% of the time. When it fails, server seems to bump out the token and reject all user request. /// TODO: FIXME Is this iteration legit for online test? Should it be mocked instead? TEST_P(FRIENDS_CANCEL, US_RequestClubFriendsCancelled) { TestCanceler<> canceler(this->getParam()); while (!canceler.isComplete()) { EXPECT_TRUE(canceler.cancel(getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo))); } } #endif TEST_P(FRIENDS_CANCEL, US_RequestFriendsCancel) { TestCanceler<> canceler(this->getParam()); while (!canceler.isComplete()) { EXPECT_TRUE(canceler.cancel(getFacade().getFriendClient().requestFriends(FriendClient::ConsoleOnly))); } } // Disabled on XOne due to community segregation between X360 and XOne #if !defined(US_TARGET_XONE) /// @test Requests Club friends with an account with no Club friends TEST_F(FRIENDS_NO_LOGIN, US_Win32RequestClubFriendsNoClubFriends) { Facade facade; { #if defined(US_CHINA_ACCOUNTS_SETUP_NOT_DONE) // Work right now but when friends get added it will break. We need to make a specific user for this test. const std::unique_ptr credentials(NS_COMMON::AuthenticationHelper::createPlayerCredentials()); #elif defined(US_TARGET_WINDOWS) const std::unique_ptr credentials(NS_COMMON::AuthenticationHelper::createPlayerCredentialsWithNoFriends()); #else const std::unique_ptr credentials(NS_COMMON::AuthenticationHelper::createPlayerCredentials(8)); #endif ASSERT_TRUE(AsyncHelper::waitSuccess(facade.createSession(*credentials, {}, {}))); } { const AsyncResult > resultFriends = facade.getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); ASSERT_TRUE(AsyncHelper::waitSuccess(resultFriends)); EXPECT_EQ(0u, resultFriends.getResult().size()); } { ASSERT_TRUE(AsyncHelper::waitSuccess(facade.deleteSession())); } } #if defined(US_TARGET_PS4) || defined(US_TARGET_XONE) || defined(US_TARGET_SWITCH) || defined(US_TARGET_KILI) /// @test Validates the maximum concurrent calls allowed for requesting ConsoleWithClubInfo friends using a range. TEST_F(FRIENDS_MOCK, USNOT_RequestFriendsConsoleWithClubInfoTooManyTimes) { const uint32 COUNT = 6; { // In order to reduce test timing sensitivity, the HTTP GET asynchronous // result is returned in the pending state, so the request friends jobs // remain processing until the sixth call to request friends. // (Returning success, especially using a mock, may end up having the // first request call completing before the sixth request (especially // in DEBUG configuration, where logging and memory validations may slow // down the process considerably. const MockAsyncResult pending = MockResultHelper::createPendingResult(); //::testing::Sequence s; US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub") .Times(::testing::AtMost(COUNT)) .WillRepeatedly(testing::Return(pending)); } AsyncResult > results[COUNT]; const ClockSteady::TTimeMilli t1 = ClockSteady::getTimeMilli(); US_UNUSED(t1); for(uint32 i = 0; i < COUNT; ++i) { results[i] = getFacade().getFriendClient().requestFriendsConsoleWithClubInfo(ResultRange(0, 2)); } const ClockSteady::TTimeMilli t2 = ClockSteady::getTimeMilli(); US_UNUSED(t2); PRINT_LINE("Requesting Friends Time: %d ms", (t2 - t1)); Helper::sleep(25); for(uint32 i = 0; i < COUNT - 1; ++i) { EXPECT_FALSE(results[i].hasFailed()); EXPECT_FALSE(results[i].hasSucceeded()); EXPECT_TRUE(results[i].isProcessing()); } EXPECT_FALSE(results[COUNT - 1].isProcessing()); // No more than 1 call at a time US_EXPECT_FAILURE(results[COUNT - 1], Errors::CORE_TOO_MANY_JOBS_IN_PROGRESS); } /// @test Validates the maximum concurrent calls allowed for requesting ConsoleOnly friends using a range. TEST_F(FRIENDS_MOCK, USNOT_RequestFriendsConsoleOnlyTooManyTimes) { const uint32 COUNT = 6; { // In order to reduce test timing sensitivity, the HTTP GET asynchronous // result is returned in the pending state, so the request friends jobs // remain processing until the sixth call to request friends. // (Returning success, especially using a mock, may end up having the // first request call completing before the sixth request (especially // in DEBUG configuration, where logging and memory validations may slow // down the process considerably. const MockAsyncResult pending = MockResultHelper::createPendingResult(); //::testing::Sequence s; US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub") .Times(::testing::AtMost(COUNT)) .WillRepeatedly(testing::Return(pending)); } AsyncResult > results[COUNT]; const ClockSteady::TTimeMilli t1 = ClockSteady::getTimeMilli(); US_UNUSED(t1); for (uint32 i = 0; i < COUNT; ++i) { results[i] = getFacade().getFriendClient().requestFriendsConsoleOnly(ResultRange(0, 2)); } const ClockSteady::TTimeMilli t2 = ClockSteady::getTimeMilli(); US_UNUSED(t2); PRINT_LINE("Requesting Friends Time: %d ms", (t2 - t1)); Helper::sleep(25); for (uint32 i = 0; i < COUNT - 1; ++i) { EXPECT_FALSE(results[i].hasFailed()); EXPECT_FALSE(results[i].hasSucceeded()); EXPECT_TRUE(results[i].isProcessing()); } EXPECT_FALSE(results[COUNT - 1].isProcessing()); // No more than 1 call at a time US_EXPECT_FAILURE(results[COUNT - 1], Errors::CORE_TOO_MANY_JOBS_IN_PROGRESS); } #endif //defined(US_TARGET_PS4) || defined(US_TARGET_XONE) || defined(US_TARGET_SWITCH) || defined(US_TARGET_KILI) /// @test Requests Club friends from the first Test environment player. #if defined(US_TARGET_GGP) // Unfortunately this tests even though is mocked needs an specific setup for ussdk002 and ussdk003. // The tests uses first party api to recover first party information for the user above. // Those users, however do not have ggp valid accounts. TEST_F(FRIENDS_MOCK, DISABLED_USNOT_RequestClubFriends) #else TEST_F(FRIENDS_MOCK, USNOT_RequestClubFriends) #endif { const Vector indices = { 2u, 3u }; ::testing::Sequence s; { const String json = MockProfileHelper::buildRequestFriendsResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub", mockResult); } { const String json = MockProfileHelper::buildRequestProfilesResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles?userId", mockResult); } TestFriends_BF::requestClubFriends(getFacade()); } /// @test Requests Club friends parsing an empty list from JSON body. TEST_F(FRIENDS_MOCK, USNOT_RequestClubFriendsEmptyJSON) { { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult("{\"friends\":[]}"); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub", mockResult); } const AsyncResult > resultFriends = getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); ASSERT_TRUE(AsyncHelper::waitSuccess(resultFriends)); EXPECT_EQ(0u, resultFriends.getResult().size()); } /// @test Requests Club friends parsing an invalid JSON body. TEST_F(FRIENDS_MOCK, USNOT_RequestClubFriendsInvalidJSON) { { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult("{\"Friends\":[],}"); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub", mockResult); } const AsyncResult > resultFriends = getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); ASSERT_TRUE(AsyncHelper::waitFailure(resultFriends, Errors::CORE_INVALID_JSON_FORMAT)); EXPECT_EQ(0u, resultFriends.getResult().size()); } /// @test Requests Club friends parsing a JSON structure containing extra fields. #if defined(US_TARGET_GGP) // Unfortunately this tests even though is mocked needs an specific setup for ussdk002 and ussdk003. // The tests uses first party api to recover first party information for the user above. // Those users, however do not have ggp valid accounts. TEST_F(FRIENDS_MOCK, DISABLED_USNOT_RequestClubFriendsFieldsVariations) #else TEST_F(FRIENDS_MOCK, USNOT_RequestClubFriendsFieldsVariations) #endif { const Vector indices = { 2u, 3u }; ::testing::Sequence s; { const String json = MockProfileHelper::buildRequestFriendsResponse(indices).renderContent(); const String field = "\"pid"; const String addfield = "\t\t\"EXTRA FIELD\":\"TEST CONTENT\",\n" + field; const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json.replace(field, addfield)); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub", mockResult); } { const String json = MockProfileHelper::buildRequestProfilesResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles?userId", mockResult); } const AsyncResult< Vector > resultFriends = getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); ASSERT_TRUE(AsyncHelper::waitSuccess(resultFriends)); EXPECT_EQ(2u, resultFriends.getResult().size()); } /// @test Requests Club friends parsing a JSON structure containing extra Root node. #if defined(US_TARGET_GGP) // Unfortunately this tests even though is mocked needs an specific setup for ussdk002 and ussdk003. // The tests uses first party api to recover first party information for the user above. // Those users, however do not have ggp valid accounts. TEST_F(FRIENDS_MOCK, DISABLED_USNOT_RequestClubFriendsWithExtraRootNode) #else TEST_F(FRIENDS_MOCK, USNOT_RequestClubFriendsWithExtraRootNode) #endif { const Vector indices = { 2u, 3u }; ::testing::Sequence s; { const String jsonBody = MockProfileHelper::buildRequestFriendsResponse(indices).renderContent(); // Add extra root node String jsonBodyExtraNode = "{\"extraRootNode\":[{\"name\":\"extraItem\",\"quantity\":2}],"; // Remove first '{' because its now part of a json array jsonBodyExtraNode += jsonBody.substr(jsonBody.findSubstringNoCase("{") + 1, jsonBody.getLength()); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(jsonBodyExtraNode); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub", mockResult); } { const String json = MockProfileHelper::buildRequestProfilesResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles?userId", mockResult); } const AsyncResult< Vector > resultFriends = getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); ASSERT_TRUE(AsyncHelper::waitSuccess(resultFriends)); EXPECT_EQ(2, resultFriends.getResult().size()); } /// @test Requests Club friends expecting an HTTP error. TEST_F(FRIENDS_MOCK, USNOT_RequestClubFriendsHttp404) { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Status code: 404", LogLevel::Error, Times(1)); }); { const MockAsyncResult mockResult = MockResultHelper::createHttpErrorResult( RestStatusCode::Error404, "{\"ErrorNumber\":7,\"Description\":\"One or more parameters are missing}"); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub", mockResult); } ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo), Errors::HTTP_404_NOT_FOUND)); } /// @test Cancels request friends after 1st HTTP call /// @note The first HTTP call happens in JobRequestFriendsConsole::syncFriends. /// The job will not reach the JobRequestFriendsConsole::lookupClubInfo step. TEST_F(FRIENDS_MOCK_CANCEL, USNOT_RequestFriendsFirst) { { const MockAsyncResult mockResult = MockResultHelper::createPendingResult(); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub", mockResult); } AsyncResult > resultFriends = getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); EXPECT_FALSE(resultFriends.wait(100)); // Wait so jobs are in progress resultFriends.cancel(); #if defined(US_LOG_ENABLED) EXPECT_TRUE(resultFriends.isCanceled()) << "Call state is not canceled? " << US_STREAM_CSTR(static_cast(resultFriends)); #else EXPECT_TRUE(resultFriends.isCanceled()) << "Call state is not canceled?"; #endif US_EXPECT_FAILURE(resultFriends, Errors::CANCELED); } /// @test Cancels request friends after call is terminated TEST_F(FRIENDS_MOCK_CANCEL, USNOT_RequestFriendsDoneBeforeCancel) { { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult("{\"friends\":[]}"); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub", mockResult); } AsyncResult > resultFriends = getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); EXPECT_TRUE(resultFriends.wait(NS_COMMON::DEFAULT_WAIT_TIME)); // Canceling a call after call is terminated is a no-op resultFriends.cancel(); EXPECT_FALSE(resultFriends.isCanceled()); US_EXPECT_SUCCESS(resultFriends); EXPECT_EQ(0u, resultFriends.getResult().size()); } /// @test Ensures the same call can be issued after canceling it first. /// This test makes sure that up on cancel, number of active calls is decreased.USNOT_InviteFriendClubInvalidProfileId TEST_F(FRIENDS_MOCK_CANCEL, USNOT_RequestFriendsAfterCancel) { { const MockAsyncResult mockPending = MockResultHelper::createPendingResult(); const MockAsyncResult mockSuccess = MockResultHelper::createSuccessResult("{\"friends\":[]}"); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub") .WillOnce(testing::Return(mockPending)) .WillOnce(testing::Return(mockSuccess)); } { AsyncResult > resultFriends = getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); EXPECT_FALSE(resultFriends.wait(100)); resultFriends.cancel(); #if defined(US_LOG_ENABLED) EXPECT_TRUE(resultFriends.isCanceled()) << "Call state is not canceled? " << US_STREAM_CSTR(static_cast(resultFriends)); #else EXPECT_TRUE(resultFriends.isCanceled()) << "Call state is not canceled?"; #endif EXPECT_TRUE(resultFriends.hasFailed()); } // Ensure calling requestFriends succeeds after a cancel. { const AsyncResult > resultFriends = getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); ASSERT_TRUE(AsyncHelper::waitSuccess(resultFriends)); EXPECT_EQ(0u, resultFriends.getResult().size()); } } #endif // US_TARGET_XONE TEST_F(FRIENDS_MOCK, USNOT_InviteFriendClub) { { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(""); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_POST, "friendsClub", mockResult); } EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getFriendClient().sendFriendsClubInvite({ ProfileId(TEST_PROFILE_ID) }))); } TEST_F(FRIENDS_MOCK, USNOT_InviteFriendClubSeveralProfiles) { HttpPost request(StringUrl(""), String()); { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(""); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_POST, "friendsClub") .WillOnce(testing::DoAll(testing::SaveArg<0>(static_cast(&request)), testing::Return(mockResult))); } EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getFriendClient().sendFriendsClubInvite({ ProfileId(TEST_PROFILE_ID), ProfileId(TEST_PROFILE_ID_2) }))); EXPECT_NE(String::npos, request.getBodyAsString().findSubstringCase(TEST_PROFILE_ID)); EXPECT_NE(String::npos, request.getBodyAsString().findSubstringCase(TEST_PROFILE_ID_2)); } TEST_F(FRIENDS_MOCK, USNOT_InviteFriendClubFailed) { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Status code: 400", LogLevel::Error, Times(1)); US_EXPECT_LOG("Friends invitation failed for the following error:", LogLevel::Error, Times(1)); }); { const MockAsyncResult mockResult = MockResultHelper::createHttpErrorResult( RestStatusCode::Error400, "{\"FaultNum\":12345, \"FaultDesc\":\"My Mocked Error\"}"); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_POST, "friendsClub", mockResult); } ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getFriendClient().sendFriendsClubInvite({ ProfileId(TEST_PROFILE_ID) }), Errors::FRIEND_GENERIC_FAILURE)); } TEST_F(FRIENDS_MOCK, USNOT_AcceptInviteClubSuccess) { { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(HTTP_EMPTY_BODY); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_PUT, "friendsClub", mockResult); } ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().getFriendClient().acceptFriendClubInvite(ProfileId(UPLAY_PROFILE_ID)))); } TEST_F(FRIENDS_MOCK, USNOT_DeclineInviteClubSuccess) { { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(HTTP_EMPTY_BODY); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_DELETE, "friendsClub", mockResult); } ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().getFriendClient().declineFriendClubInvite(ProfileId(UPLAY_PROFILE_ID)))); } TEST_F(FRIENDS_MOCK, USNOT_RemoveFriendClubSuccess) { { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(HTTP_EMPTY_BODY); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_DELETE, "friendsClub", mockResult); } ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().getFriendClient().removeFriendClub(ProfileId(TEST_PROFILE_ID_INVALID)))); } #if !defined(US_TARGET_WINDOWS) && !defined(US_TARGET_OSX) || defined(US_TARGET_LINUX) || defined(US_TARGET_GGP) typedef LoginMockFixture FRIENDS_MOCK_NOLOGIN; /// @test Validates that requesting console friends fails if not logged in to Uplay. /// @note This test does not apply for Win32 and OSX as there are no platform-specific friends. TEST_F(FRIENDS_MOCK_NOLOGIN, USNOT_RequestFriendsNotLoggedIn) { ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getFriendClient().requestFriends(FriendClient::ConsoleOnly), Errors::AUTH_SESSION_NOT_CREATED)); } #endif // Disabled on XONE due to community segregation between X360 and XONE // This test does not make sense on ClubLogin targets #if !defined(US_ENABLE_UPLAY_LOGIN) && !defined(US_TARGET_XONE) TEST_F(FRIENDS, US_RequestFriendsClubCheckConsoleInfo) { const AsyncResult > result = getFacade().getFriendClient().requestFriends(FriendClient::ClubWithConsoleInfo); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); for(const auto& it : result.getResult()) { const FriendInfoClub* club = it.getInfoClub(); if(club != NULL && club->m_profileInfo.m_nameOnPlatform == "ussdk002") { const FriendInfoConsole* info = it.getInfoConsole(); ASSERT_TRUE(info != NULL); EXPECT_TRUE(info->hasAlreadyPlayedUbisoftGame()); EXPECT_TRUE(info->m_profileInfo.m_profileId.isValid()); EXPECT_NE(0u, info->m_profileInfo.m_nameOnPlatform.getLength()); break; } } } #endif /// @test Checks that an error is raised and no request is sent when an invalid profile is given TEST_F(FRIENDS_MOCK, USNOT_InviteFriendClubInvalidProfileId) { US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_POST, "friendsClub").Times(0); ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getFriendClient().sendFriendsClubInvite({ ProfileId("Invalid") }), Errors::FRIEND_INVALID_PARAM)); } /// @test Checks that an error is raised and no request is sent when an invalid profile is given TEST_F(FRIENDS_MOCK, USNOT_RemoveFriendClubInvalidProfileId) { US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_POST, "friendsClub").Times(0); ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getFriendClient().removeFriendClub(ProfileId("Invalid")), Errors::FRIEND_INVALID_PARAM)); } /// @test Checks that an error is raised and no request is sent when an invalid profile is given TEST_F(FRIENDS_MOCK, USNOT_AcceptFriendClubInviteInvalidProfileId) { US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_POST, "friendsClub").Times(0); ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getFriendClient().acceptFriendClubInvite(ProfileId("Invalid")), Errors::FRIEND_INVALID_PARAM)); } /// @test Checks that an error is raised and no request is sent when an invalid profile is given TEST_F(FRIENDS_MOCK, USNOT_DeclineFriendClubInviteInvalidProfileId) { US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_POST, "friendsClub").Times(0); ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getFriendClient().declineFriendClubInvite(ProfileId("Invalid")), Errors::FRIEND_INVALID_PARAM)); } #if !defined(US_DLL) /// @test Validates Caching on requestClubFriends. #if defined(US_TARGET_GGP) // Unfortunately this tests even though is mocked needs an specific setup for ussdk002 and ussdk003. // The tests uses first party api to recover first party information for the user above. // Those users, however do not have ggp valid accounts. TEST_F(FRIENDS_MOCK_NOLOGIN, DISABLED_USNOT_FriendCaching) #else TEST_F(FRIENDS_MOCK_NOLOGIN, USNOT_FriendCaching) #endif { { // Note : It seems that first-party calls to friends can take more than 3 seconds // The cache ttl (default 3s in mock tests) is therefore increased in this test class LongTTLParametersSpaceMockHelper : public ParametersSpaceMockHelper { private: Json buildParameterGroupSettingsCacheTTL() const override { const uint32 ttl = 3*60; // 3 minutes instead of 3 seconds JsonWriter fields; fields["defaultSec"] = ttl; fields["profilesNewsSec"] = ttl; fields["spacesNewsSec"] = ttl; fields["profilesActionsSec"] = ttl; fields["profilesChallengesSec"] = ttl; fields["profilesRewardsSec"] = ttl; fields["friendsListSec"] = ttl; return renderParameterGroup(fields.getJson()); } }; const MockAsyncResult parametersSpaceResult = MockResultHelper::createSuccessResult( LongTTLParametersSpaceMockHelper().getParameters().renderContent()); mockFullLogin(nullptr, nullptr, ¶metersSpaceResult); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().createSession(GET_CREDENTIALS(), {}, {}))); } { const Vector indices = { 2u, 3u }; ::testing::Sequence s; { const String json = MockProfileHelper::buildRequestFriendsResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub", mockResult); } { const String json = MockProfileHelper::buildRequestProfilesResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles?userId", mockResult); } } // First call sends requests TestFriends_BF::requestClubFriends(getFacade()); // Second call must return with the cache (no HTTP call) TestFriends_BF::requestClubFriends(getFacade()); // Invalidate the cache so the third call triggers HTTP requests FriendClientProxy::invalidateCache(getFacade().getFriendClient()); { const Vector indices = { 2u, 3u }; ::testing::Sequence s; { const String json = MockProfileHelper::buildRequestFriendsResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "friendsClub", mockResult); } { const String json = MockProfileHelper::buildRequestProfilesResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP_SIMPLE(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "profiles?userId", mockResult); } } TestFriends_BF::requestClubFriends(getFacade()); } #endif // !defined(US_DLL) #if defined(US_TARGET_PS4) // TODO transform this test in Mock and check that calls are made the second time. // we want to verify that the InstancesManager::unregisterUser method has been called and that it resets the friend cache // US-12808 TEST_F(FRIENDS_NO_FACADE, US_PS4FriendCacheInvalidatesWhenFacadeIsDeleted) { { Facade facade; EXPECT_TRUE(AsyncHelper::waitSuccess(facade.createSession(*NS_COMMON::AuthenticationHelper::createCredentials(), {}, {}))); const AsyncResult > result = facade.getFriendClient().requestFriends(FriendClient::ConsoleOnly); EXPECT_TRUE(AsyncHelper::waitSuccess(result)); EXPECT_LE(0u, result.getResult().size()); } { Facade facade; EXPECT_TRUE(AsyncHelper::waitSuccess(facade.createSession(*NS_COMMON::AuthenticationHelper::createCredentials(), {}, {}))); const AsyncResult > result = facade.getFriendClient().requestFriends(FriendClient::ConsoleOnly); EXPECT_TRUE(AsyncHelper::waitSuccess(result)); EXPECT_LE(0u, result.getResult().size()); } } /// @test Validates the account has 100 friends and 55 of them as their new name and not the one stored in our services /// @note This test requires a specific account: Manual Hundredfriends /// This is how the test work: /// The account has 100 friends, where 55 of them were connected once to our services with an old name. /// Afterward, these accounts name were all changed to specific pattern: manualXXfriends (where XX is a number from 1 to 55). /// Theses 55 accounts are to never be connected again to our services, so our services still has the old name registered. /// The test verifies that we're batching to group of 50(being the limit per batch), and that the names in both batch that /// were changed are the ones from the primary network and not from our services(e.g. manualXXfriends). TEST_F(FRIENDS_NO_FACADE, DISABLED_MANUAL_US_PS4FriendRequest) { std::unique_ptr creds(NS_COMMON::AuthenticationHelper::createPlayerCredentials()); Facade facade; EXPECT_TRUE(AsyncHelper::waitSuccess(facade.createSession(*creds, {}, {}))); FriendClient& client = facade.getFriendClient(); AsyncResult > result = client.requestFriends(FriendClient::ConsoleOnly); EXPECT_TRUE(AsyncHelper::waitSuccess(result)); Vector friendsInfo = result.getResult(); ASSERT_EQ(friendsInfo.size(), 100); unsigned int newNamesCount = 0; for (Vector::const_iterator it = friendsInfo.begin(); it != friendsInfo.end(); ++it) { const FriendInfoConsole* friendInfoConsole = it->getInfoConsole(); if (friendInfoConsole) { const String id = friendInfoConsole->m_profileInfo.m_idOnPlatform; const String name = friendInfoConsole->m_profileInfo.m_nameOnPlatform; if (name.findSubstringNoCase("manual") != String::npos) { ++newNamesCount; } PRINT_LINE("Requesting Friends = %30s - %30s", id.getUtf8(), name.getUtf8()); } } ASSERT_EQ(newNamesCount, 55); } // Please do not delete yet ! DomD //TEST_F(FRIENDS, DISABLED_MANUAL_TestAddFriendsAndRequestFriendsList) //{ // LoggingHelper::enableVerbose(); // LoggingHelper::enableMultiLines(); // for (;;) // { // if (NS_COMMON::isFriendCallBackReceived) //when we receive the notification from PS4 that the friends were changed // { // NS_COMMON::isFriendCallBackReceived = false; // FriendClient& client = getFacade().getFriendClient(); // const AsyncResult > resultAll = client.requestFriends(FriendClient::ConsoleWithClubInfo); // ASSERT_TRUE(AsyncHelper::waitSuccess(resultAll)); // } // else // { // Helper::sleep(100); // } // } //} #endif #if defined(US_TARGET_XONE) #if !defined(US_DLL) /// @test Validates that after receiving a callback event from the Xbox social service, /// the cache for ConsoleWithClubInfo is invalidated. /// Three Http friends requests are made. /// 1st request: to get get friend request, we check for size to validate content (expects call) /// 2nd request: to verify that cache is being used. (no call expected) /// 3rd request: to verify that the cache was invalidated after receiving callback and that an actual Http request is sent. (expects call) /// To run this test you must add/remove friend from user while the test is running TEST_F(FRIENDS_MOCK_NOLOGIN, DISABLED_MANUAL_TestFriendClientConsoleWithClubInfoCacheInvalidationOnCallback) { // Set expect Http request for event. // Events might be sent while waiting for tester to add/remove a friend { mockFullLogin(); US_EXPECT_CALL(US_TEST_NS::Action::SendEvents) .Times(testing::AnyNumber()) .WillRepeatedly(testing::Return(MockResultHelper::createSuccessResult())); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().createSession(*NS_COMMON::AuthenticationHelper::createCredentials(), {}, {}))); waitForPostLoginCompletion(); } // Expected calls for friend requests const Vector indices = { 2u, 3u }; { const String json = MockProfileHelper::buildRequestProfilesResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "mock-profiles?idOnPlatform") .Times(2).WillRepeatedly(testing::Return(mockResult)); } { const String json = MockProfileHelper::buildRequestProfilesResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "mock-profiles?userId") .Times(2).WillRepeatedly(testing::Return(mockResult)); } static bool eventReceived = false; // Initial friend request const AsyncResult > result = getFacade().getFriendClient().requestFriends(FriendClient::ConsoleWithClubInfo); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(4, result.getResult().size()); // This value might change depending on the friends setup for current user. // 2nd friend request (should use cache) const AsyncResult > resultCache = getFacade().getFriendClient().requestFriends(FriendClient::ConsoleWithClubInfo); ASSERT_TRUE(AsyncHelper::waitSuccess(resultCache)); ASSERT_EQ(4, resultCache.getResult().size()); // This value might change depending on the friends setup for current user. // Setup friend callback TestFriends_BF::checkRelationShipChange(getFacade(), eventReceived, FriendClient::ConsoleWithClubInfo); // Loop waits for friend change while (!eventReceived) { Helper::sleep(1000); PRINT_LINE("Waiting for friend change event..."); } } // @test Validates that after receiving a callback event from the Xbox social service, /// the cache for Consolidated is invalidated. /// Three Http friends requests are made. /// 1st request: to get get friend request, we check for size to validate content (expects call) /// 2nd request: to verify that cache is being used. (no call expected) /// 3rd request: to verify that the cache was invalidated after receiving callback and that an actual Http request is sent. (expects call) /// To run this test you must add/remove friend from user while the test is running TEST_F(FRIENDS_MOCK_NOLOGIN, DISABLED_MANUAL_TestFriendClientConsolidatedCacheInvalidationOnCallback) { // Set expect Http request for event. // Events might be sent while waiting for tester to add/remove a friend { mockFullLogin(); US_EXPECT_CALL(US_TEST_NS::Action::SendEvents) .Times(testing::AnyNumber()) .WillRepeatedly(testing::Return(MockResultHelper::createSuccessResult())); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().createSession(*NS_COMMON::AuthenticationHelper::createCredentials(), {}, {}))); waitForPostLoginCompletion(); } // Expected calls for friend requests const Vector indices = { 2u, 3u }; { const String json = MockProfileHelper::buildRequestProfilesResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "mock-profiles?idOnPlatform") .Times(2).WillRepeatedly(testing::Return(mockResult)); } { const String json = MockProfileHelper::buildRequestFriendsResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "mock-friendsClub") .Times(2).WillRepeatedly(testing::Return(mockResult)); } { const String json = MockProfileHelper::buildRequestProfilesResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "mock-profiles?userId") .Times(4).WillRepeatedly(testing::Return(mockResult)); } static bool eventReceived = false; // Initial friend request const AsyncResult > result = getFacade().getFriendClient().requestFriends(FriendClient::Consolidated); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(4, result.getResult().size()); // This value might change depending on the friends setup for current user. // 2nd friend request (should use cache) const AsyncResult > resultCache = getFacade().getFriendClient().requestFriends(FriendClient::Consolidated); ASSERT_TRUE(AsyncHelper::waitSuccess(resultCache)); ASSERT_EQ(4, resultCache.getResult().size()); // This value might change depending on the friends setup for current user. // Setup friend callback TestFriends_BF::checkRelationShipChange(getFacade(), eventReceived, FriendClient::Consolidated); // Loop waits for friend change while (!eventReceived) { Helper::sleep(1000); PRINT_LINE("Waiting for friend change event..."); } } /// @test validates that after receiving a callback event from the Xbox social service, /// the cache for ConsoleOnly is invalidated. /// Three Http friends requests are made. /// 1st request: to get get friend request, we check for size to validate content (expects call) /// 2nd request: to verify that cache is being used. (no call expected) /// 3rd request: to verify that the cache was invalidated after receiving callback and that an actual Http request is sent. (expects call) /// To run this test you must add/remove friend from user while the test is running TEST_F(FRIENDS_MOCK_NOLOGIN, DISABLED_MANUAL_TestFriendClientConsoleOnlyCacheInvalidationOnCallback) { // Set expect Http request for event. // Events might be sent while waiting for tester to add/remove a friend { mockFullLogin(); US_EXPECT_CALL(US_TEST_NS::Action::SendEvents) .Times(testing::AnyNumber()) .WillRepeatedly(testing::Return(MockResultHelper::createSuccessResult())); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().createSession(*NS_COMMON::AuthenticationHelper::createCredentials(), {}, {}))); waitForPostLoginCompletion(); } // Expected calls for friend requests const Vector indices = { 2u, 3u }; { const String json = MockProfileHelper::buildRequestProfilesResponse(indices).renderContent(); const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(json); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "mock-profiles?idOnPlatform") .Times(2).WillRepeatedly(testing::Return(mockResult)); } static bool eventReceived = false; // Initial friend request const AsyncResult > result = getFacade().getFriendClient().requestFriends(FriendClient::ConsoleOnly); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); ASSERT_EQ(4, result.getResult().size()); // This value might change depending on the friends setup for current user. // 2nd friend request (should use cache) const AsyncResult > resultCache = getFacade().getFriendClient().requestFriends(FriendClient::ConsoleOnly); ASSERT_TRUE(AsyncHelper::waitSuccess(resultCache)); ASSERT_EQ(4, resultCache.getResult().size()); // This value might change depending on the friends setup for current user. // Setup friend callback TestFriends_BF::checkRelationShipChange(getFacade(), eventReceived, FriendClient::ConsoleOnly); // Loop waits for friend change while (!eventReceived) { Helper::sleep(1000); PRINT_LINE("Waiting for friend change event..."); } } #endif //US_DLL /// @test validates that after receiving a callback event from the Xbox social service, /// the cache for ConsoleOnly is invalidated /// and that the new friend list contains the right friends. /// @note To run this test you must add/remove friend from user while the test is running and observe the resulting friend list changes TEST_F(FRIENDS, DISABLED_MANUAL_TestFriendClientConsoleOnlyCacheAfterRemoveFriend) { // Initial friend request const AsyncResult > result = getFacade().getFriendClient().requestFriends(FriendClient::ConsoleOnly); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); const AsyncResult > resultCache = getFacade().getFriendClient().requestFriends(FriendClient::ConsoleOnly); EXPECT_EQ(result, resultCache); bool eventReceived = false; // Setup friend callback AsyncResult> updatedResult = TestFriends_BF::checkRelationShipChange(getFacade(), eventReceived, FriendClient::ConsoleOnly); // Loop waits for friend change while (!eventReceived) { Helper::sleep(1000); PRINT_LINE("Waiting for a friend change event..."); } auto printFriendList = [] (const char* title, const Vector& friendList) { PRINT_LINE(title); for (const FriendInfo& friendInfo : friendList) { PRINT_LINE("Player display name: %s", friendInfo.getInfoConsole()->m_profileInfo.m_nameOnPlatform.getUtf8()); } }; printFriendList("Initial friend list:", result.getResult()); printFriendList("Cached Friend list:", resultCache.getResult()); printFriendList("Friend list after change:", updatedResult.getResult()); } #endif };