//////////////////////////////////////////////////////////////////////////////// // (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour // //////////////////////////////////////////////////////////////////////////////// #include "tests/config.h" #include "tests/fixture/authenticationFixture.h" #include "tests/fixture/loginMockFixture.h" #include "tests/mock/mockLogDevice.h" #include "tests/mock/mockResultHelper.h" #include "tests/mock/parametersMockHelper.h" #include #include <../private/ubiservices/core/http/httpEntity.h> #include <../private/ubiservices/services/cacheManager.h> #include <../private/ubiservices/services/parameters/parametersClientProxy.h> #include <../private/ubiservices/services/news/newsProxy.h> #include #include #include #include #include #include #include #define DUMMY_PROFILE_ID DUMMY_GUID_ID1 namespace US_NS {; US_DEFINE_TEST(TestNews); typedef AuthenticationFixture<1> NEWS; typedef LoginMockFixture NEWS_MOCK; typedef LoginMockFixtureNoInit NEWS_MOCK_NOINIT; namespace TestNews_BF { #if !defined(US_DLL) static ::testing::AssertionResult checkResultingNews(const Vector& news) { if (news.size() != 6) { return ::testing::AssertionFailure() << "There shall be 6 news in the result list"; } else if ((news.front().m_links.size() != 2) || (news.back().m_links.size() != 2)) { return ::testing::AssertionFailure() << "There shall be 2 links for each news"; } return ::testing::AssertionSuccess(); } #endif String createMockResult() { return "{" "\"news\":" "[" "{" "\"profileId\":\"" DUMMY_PROFILE_ID "\"," "\"spaceId\":\"3a441107-673a-40b7-a304-0cd5fcb7ee9b\"," "\"newsId\":\"neolane.AC4_DLC_01\"," "\"type\":\"DLCOffer\"," "\"placement\":\"mainMenu1\"," "\"priority\":1," "\"displayTime\":20," "\"publicationDate\":\"2014-11-11 12:00:00Z\"," "\"locale\":\"en-US\"," "\"title\":\"New DLC Released\"," "\"body\":\"Get the Season Pass DLC from the Marketplace\"," "\"mediaURL\":\"http://static8.ubisoft.com/234224/asset34.png\"," "\"mediaType\":\"image/png\"," "\"links\":" "[" "{" "\"type\":\"pstore\"," "\"param\":\"0x555308796ea1e800\"," "\"actionName\":\"OpenedTheStoreForSeasonPass\"," "\"actionDescription\":\"Buy the Season Pass\"" "}," "{" "\"type\":\"web\"," "\"param\":\"http://acu.ubisoft.com/dlc1/description.html\"," "\"actionName\":\"MoreInfoOnSeasonPass\"," "\"actionDescription\":\"More info...\"" "}" "]," "\"obj\":{\"assetId\":13}" "}," "{" "\"profileId\":\"" DUMMY_PROFILE_ID "\"," "\"spaceId\":\"3a441107-673a-40b7-a304-0cd5fcb7ee9b\"," "\"newsId\":\"neolane.AC4_DLC_02\"," "\"type\":\"DLCOffer\"," "\"placement\":\"mainMenu1\"," "\"priority\":2," "\"displayTime\":10," "\"publicationDate\":\"2014-11-11 13:00:00Z\"," "\"locale\":\"en-US\"," "\"title\":\"New DLC Released\"," "\"body\":\"Get the Season Pass DLC from the Marketplace\"," "\"mediaURL\":\"http://static8.ubisoft.com/234224/asset34.png\"," "\"mediaType\":\"image/png\"," "\"links\":" "[" "{" "\"type\":\"pstore\"," "\"param\":\"0x555308796ea1e800\"," "\"actionName\":\"OpenedTheStoreForSeasonPass\"," "\"actionDescription\":\"Buy the Season Pass\"" "}," "{" "\"type\":\"web\"," "\"param\":\"http://acu.ubisoft.com/dlc1/description.html\"," "\"actionName\":\"MoreInfoOnSeasonPass\"," "\"actionDescription\":\"More info...\"" "}" "]," "\"obj\":{\"assetId\":13}" "}," "{" "\"profileId\":\"" DUMMY_PROFILE_ID "\"," "\"spaceId\":\"3a441107-673a-40b7-a304-0cd5fcb7ee9b\"," "\"newsId\":\"neolane.AC4_DLC_03\"," "\"type\":\"DLCOffer\"," "\"placement\":\"mainMenu2\"," "\"priority\":1," "\"displayTime\":15," "\"publicationDate\":\"2014-11-11 14:00:00Z\"," "\"locale\":\"en-US\"," "\"title\":\"New DLC Released\"," "\"body\":\"Get the Season Pass DLC from the Marketplace\"," "\"mediaURL\":\"http://static8.ubisoft.com/234224/asset34.png\"," "\"mediaType\":\"image/png\"," "\"links\":" "[" "{" "\"type\":\"pstore\"," "\"param\":\"0x555308796ea1e800\"," "\"actionName\":\"OpenedTheStoreForSeasonPass\"," "\"actionDescription\":\"Buy the Season Pass\"" "}," "{" "\"type\":\"web\"," "\"param\":\"http://acu.ubisoft.com/dlc1/description.html\"," "\"actionName\":\"MoreInfoOnSeasonPass\"," "\"actionDescription\":\"More info...\"" "}" "]," "\"obj\":{\"assetId\":13}" "}," "{" "\"profileId\":\"" DUMMY_PROFILE_ID "\"," "\"spaceId\":\"3a441107-673a-40b7-a304-0cd5fcb7ee9b\"," "\"newsId\":\"neolane.AC4_DLC_04\"," "\"type\":\"DLCOffer\"," "\"placement\":\"mainMenu2\"," "\"priority\":2," "\"displayTime\":5," "\"publicationDate\":\"2014-11-11 15:00:00Z\"," "\"locale\":\"en-US\"," "\"title\":\"New DLC Released\"," "\"body\":\"Get the Season Pass DLC from the Marketplace\"," "\"mediaURL\":\"http://static8.ubisoft.com/234224/asset34.png\"," "\"mediaType\":\"image/png\"," "\"links\":" "[" "{" "\"type\":\"pstore\"," "\"param\":\"0x555308796ea1e800\"," "\"actionName\":\"OpenedTheStoreForSeasonPass\"," "\"actionDescription\":\"Buy the Season Pass\"" "}," "{" "\"type\":\"web\"," "\"param\":\"http://acu.ubisoft.com/dlc1/description.html\"," "\"actionName\":\"MoreInfoOnSeasonPass\"," "\"actionDescription\":\"More info...\"" "}" "]," "\"obj\":{\"assetId\":13}" "}," "{" "\"profileId\":\"" DUMMY_PROFILE_ID "\"," "\"spaceId\":\"3a441107-673a-40b7-a304-0cd5fcb7ee9b\"," "\"newsId\":\"neolane2.AC4_DLC_05\"," "\"type\":\"DLCOffer\"," "\"placement\":\"mainMenu3\"," "\"priority\":1," "\"displayTime\":30," "\"publicationDate\":\"2014-11-22 16:00:00Z\"," "\"locale\":\"en-US\"," "\"title\":\"New DLC Released\"," "\"body\":\"Get the Season Pass DLC from the Marketplace\"," "\"mediaURL\":\"http://static8.ubisoft.com/234224/asset34.png\"," "\"mediaType\":\"image/png\"," "\"links\":" "[" "{" "\"type\":\"pstore\"," "\"param\":\"0x555308796ea1e800\"," "\"actionName\":\"OpenedTheStoreForSeasonPass\"," "\"actionDescription\":\"Buy the Season Pass\"" "}," "{" "\"type\":\"web\"," "\"param\":\"http://acu.ubisoft.com/dlc1/description.html\"," "\"actionName\":\"MoreInfoOnSeasonPass\"," "\"actionDescription\":\"More info...\"" "}" "]," "\"obj\":{\"assetId\":13}" "}," "{" "\"profileId\":\"" DUMMY_PROFILE_ID "\"," "\"spaceId\":\"3a441107-673a-40b7-a304-0cd5fcb7ee9b\"," "\"newsId\":\"neolane2.AC4_DLC_06\"," "\"type\":\"DLCOffer\"," "\"placement\":\"mainMenu3\"," "\"priority\":2," "\"displayTime\":35," "\"publicationDate\":\"2014-11-22 17:00:00Z\"," "\"locale\":\"en-US\"," "\"title\":\"New DLC Released\"," "\"body\":\"Get the Season Pass DLC from the Marketplace\"," "\"mediaURL\":\"http://static8.ubisoft.com/234224/asset34.png\"," "\"mediaType\":\"image/png\"," "\"links\":" "[" "{" "\"type\":\"pstore\"," "\"param\":\"0x555308796ea1e800\"," "\"actionName\":\"OpenedTheStoreForSeasonPass\"," "\"actionDescription\":\"Buy the Season Pass\"" "}," "{" "\"type\":\"sstore\"," "\"param\":\"0x555308796ea1e801\"," "\"actionName\":\"MoreInfoOnSeasonPass\"," "\"actionDescription\":\"More info...\"" "}" "]," "\"obj\":{\"assetId\":13}" "}" "]" "}"; } Map extractEventsFromRequest(const HttpPost& eventRequest) { const Json requestBodyJson(eventRequest.getBodyAsString()); const Vector eventsArray = requestBodyJson["events"].getValueArray(); Map events; for (const auto& it : eventsArray) { events[it["seqId"].getValueInteger()] = it["type"].getValueString(); } return events; } } /// @test Requests news to the server, validating that the received content /// matches with records provisioned (external requirement). /// The following URL allows to configure news in UAT: /// http://ingame-news-preview-backoffice.ubisoft.org/ #if (defined(US_TARGET_IOS) && !defined(US_UPLAY_LOGIN_FOR_IOS)) || defined(US_CHINA_SERVICE_UNAVAILABLE) // need the good url with rail id placeholder TEST_F(NEWS, DISABLED_US_RequestNews) // News Services does not support Game Center tickets #else TEST_F(NEWS, US_MINRUN_RequestNews) #endif { #if defined(ENABLING_VERBOSE_LOGGING) LoggingHelper::enableVerbose(); LoggingHelper::enableMultiLines(); #endif struct Local { static void validateInstance(const NewsInfo& info, const SpaceId& spaceId, bool checkProfile) { PRINT_STREAM(info); EXPECT_TRUE(info.m_profileId.isValid() || !checkProfile); //EXPECT_EQ(ProfileId("4d9061de-7c20-4cc9-9f55-b8d6228da6ae"), info.m_profileId); EXPECT_EQ(spaceId, info.m_spaceId); EXPECT_STREQ("Promo", info.m_type.getUtf8()); EXPECT_STREQ("MainMenu1", info.m_placement.getUtf8()); EXPECT_EQ(10u, info.m_priority); EXPECT_EQ(30u, info.m_displayTime); EXPECT_EQ(DateTime(2015, 4, 28, 13, 1, 0), info.m_publicationDate); EXPECT_STREQ("en-US", info.m_locale.getUtf8()); EXPECT_STREQ("News Title #1", info.m_title.getUtf8()); EXPECT_STREQ("News Content #1", info.m_body.getUtf8()); EXPECT_STREQ("https://ingame-news-preview-backoffice.ubisoft.org/Content/IGN_STG_87x37.png", info.m_mediaUrl.getUtf8()); EXPECT_STREQ("Image", info.m_mediaType.getUtf8()); ASSERT_EQ(2u, info.m_links.size()); { const NewsLink& link1 = info.m_links.front(); EXPECT_STREQ("weblink", link1.m_type.getUtf8()); EXPECT_STREQ("http://www.ubi.com", link1.m_param.getUtf8()); EXPECT_STREQ("", link1.m_actionName.getUtf8()); EXPECT_STREQ("", link1.m_actionDescription.getUtf8()); } { const NewsLink& link2 = info.m_links.back(); EXPECT_STREQ("weblink", link2.m_type.getUtf8()); EXPECT_STREQ("http://www.ubi.com/frca/", link2.m_param.getUtf8()); EXPECT_STREQ("", link2.m_actionName.getUtf8()); EXPECT_STREQ("", link2.m_actionDescription.getUtf8()); } EXPECT_STREQ("{\"J\":5,\"0\":\"X\"}", info.m_object.getUtf8()); ASSERT_TRUE(info.m_summary.isSpecified()); EXPECT_STREQ("", info.m_summary.value().getUtf8()); EXPECT_EQ(0u, info.m_tags.size()); } // ::testing::AssertionResult // return ::testing::AssertionFailure() << "Request time out after " << NS_COMMON::DEFAULT_WAIT_TIME << " ms"; // ::testing::AssertionSuccess(); static ::testing::AssertionResult validateNews(const SpaceId& spaceId, const Vector& news, bool checkProfile) { bool isNewsFound = false; for (const auto& it : news) { if (it.m_id == "ignt.63") { isNewsFound = true; validateInstance(it, spaceId, checkProfile); break; } } return isNewsFound ? ::testing::AssertionSuccess() : ::testing::AssertionFailure() << "News not found among " << news.size() << " news in the list"; } }; const SpaceId spaceId(US_TEST_NS::SPACE_ID_US_SDK_PC); { LocalizationHelper::setLocaleCode("en-US"); { const AsyncResult > result = getFacade().getNewsClient().requestProfileNews(spaceId); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); EXPECT_TRUE(Local::validateNews(spaceId, result.getResult(), true)); } { const AsyncResult > result = getFacade().getNewsClient().requestSpaceNews(spaceId); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); EXPECT_TRUE(Local::validateNews(spaceId, result.getResult(), false)); //profile news points to the space news. } } { LocalizationHelper::setLocaleCode("fr-CA"); { const AsyncResult > result = getFacade().getNewsClient().requestProfileNews(spaceId); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); EXPECT_FALSE(Local::validateNews(spaceId, result.getResult(), true)); } { const AsyncResult > result = getFacade().getNewsClient().requestSpaceNews(spaceId); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); EXPECT_FALSE(Local::validateNews(spaceId, result.getResult(), false)); //profile news points to the space news. } } } /// @test Requests news to the server for a space that has no news provisioned. #if (defined(US_TARGET_IOS) && !defined(US_UPLAY_LOGIN_FOR_IOS)) || defined(US_CHINA_SERVICE_UNAVAILABLE) // return HTTP_403_FORBIDDEN TEST_F(NEWS, DISABLED_US_RequestNewsNoNewsForSpaceId) // News Services does not support Game Center tickets #else TEST_F(NEWS, US_RequestNewsNoNewsForSpaceId) #endif { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Status code: 404", LogLevel::Error, Times(1)); }); ASSERT_TRUE(AsyncHelper::waitFailure(getFacade().getNewsClient() .requestProfileNews(SpaceId("11111111-2222-3333-4444-555566667777")), Errors::HTTP_404_NOT_FOUND)); } #if !defined(US_DLL) /// @test Requests news with a successful response from server and a valid JSON TEST_F(NEWS_MOCK, USNOT_RequestNewsProfile) { ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNews, MockResultHelper::createSuccessResult(TestNews_BF::createMockResult())); const AsyncResult > newsResult = getFacade().getNewsClient().requestProfileNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult)); const Vector& news0 = newsResult.getResult(); ASSERT_TRUE(TestNews_BF::checkResultingNews(news0)) << "News configuration is wrong"; { const NewsInfo& info = news0.front(); EXPECT_TRUE(info.m_profileId.isValid()); EXPECT_EQ(ProfileId(DUMMY_PROFILE_ID), info.m_profileId); EXPECT_EQ(SpaceId("3a441107-673a-40b7-a304-0cd5fcb7ee9b"), info.m_spaceId); EXPECT_STREQ("neolane.AC4_DLC_01", info.m_id.getUtf8()); EXPECT_STREQ("DLCOffer", info.m_type.getUtf8()); EXPECT_STREQ("mainMenu1", info.m_placement.getUtf8()); EXPECT_EQ(1u, info.m_priority); EXPECT_EQ(20u, info.m_displayTime); EXPECT_EQ(DateTime(2014, 11, 11, 12, 0, 0), info.m_publicationDate); EXPECT_STREQ("en-US", info.m_locale.getUtf8()); EXPECT_STREQ("New DLC Released", info.m_title.getUtf8()); EXPECT_STREQ("Get the Season Pass DLC from the Marketplace", info.m_body.getUtf8()); EXPECT_STREQ("http://static8.ubisoft.com/234224/asset34.png", info.m_mediaUrl.getUtf8()); EXPECT_STREQ("image/png", info.m_mediaType.getUtf8()); { const NewsLink& link1 = info.m_links.front(); EXPECT_STREQ("pstore", link1.m_type.getUtf8()); EXPECT_STREQ("0x555308796ea1e800", link1.m_param.getUtf8()); EXPECT_STREQ("OpenedTheStoreForSeasonPass", link1.m_actionName.getUtf8()); EXPECT_STREQ("Buy the Season Pass", link1.m_actionDescription.getUtf8()); } { const NewsLink& link2 = info.m_links.back(); EXPECT_STREQ("web", link2.m_type.getUtf8()); EXPECT_STREQ("http://acu.ubisoft.com/dlc1/description.html", link2.m_param.getUtf8()); EXPECT_STREQ("MoreInfoOnSeasonPass", link2.m_actionName.getUtf8()); EXPECT_STREQ("More info...", link2.m_actionDescription.getUtf8()); } EXPECT_STREQ("{\"assetId\":13}", info.m_object.getUtf8()); } { const NewsInfo& info = news0.back(); EXPECT_TRUE(info.m_profileId.isValid()); EXPECT_EQ(ProfileId(DUMMY_PROFILE_ID), info.m_profileId); EXPECT_EQ(SpaceId("3a441107-673a-40b7-a304-0cd5fcb7ee9b"), info.m_spaceId); EXPECT_STREQ("neolane2.AC4_DLC_06", info.m_id.getUtf8()); EXPECT_STREQ("DLCOffer", info.m_type.getUtf8()); EXPECT_STREQ("mainMenu3", info.m_placement.getUtf8()); EXPECT_EQ(2u, info.m_priority); EXPECT_EQ(35u, info.m_displayTime); EXPECT_EQ(DateTime(2014, 11, 22, 17, 0, 0), info.m_publicationDate); EXPECT_STREQ("en-US", info.m_locale.getUtf8()); EXPECT_STREQ("New DLC Released", info.m_title.getUtf8()); EXPECT_STREQ("Get the Season Pass DLC from the Marketplace", info.m_body.getUtf8()); EXPECT_STREQ("http://static8.ubisoft.com/234224/asset34.png", info.m_mediaUrl.getUtf8()); EXPECT_STREQ("image/png", info.m_mediaType.getUtf8()); { const NewsLink& link1 = info.m_links.front(); EXPECT_STREQ("pstore", link1.m_type.getUtf8()); EXPECT_STREQ("0x555308796ea1e800", link1.m_param.getUtf8()); EXPECT_STREQ("OpenedTheStoreForSeasonPass", link1.m_actionName.getUtf8()); EXPECT_STREQ("Buy the Season Pass", link1.m_actionDescription.getUtf8()); } { const NewsLink& link2 = info.m_links.back(); EXPECT_STREQ("sstore", link2.m_type.getUtf8()); EXPECT_STREQ("0x555308796ea1e801", link2.m_param.getUtf8()); EXPECT_STREQ("MoreInfoOnSeasonPass", link2.m_actionName.getUtf8()); EXPECT_STREQ("More info...", link2.m_actionDescription.getUtf8()); } EXPECT_STREQ("{\"assetId\":13}", info.m_object.getUtf8()); } } #endif #if !defined(US_DLL) /// @test Requests news with a successful response from server and a valid JSON TEST_F(NEWS_MOCK, USNOT_RequestNewsProfileCache) { ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); const String jsonBody = TestNews_BF::createMockResult(); { US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNews, MockResultHelper::createSuccessResult(jsonBody)); } NewsClient& client = getFacade().getNewsClient(); const AsyncResult > newsResult = client.requestProfileNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult)); const Vector& news0 = newsResult.getResult(); ASSERT_TRUE(TestNews_BF::checkResultingNews(news0)) << "News configuration is wrong"; // Requesting news a second time. This shall not affect the mock call expectations. { const AsyncResult > newsResult2 = client.requestProfileNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult2)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResult2.getResult())); } // Requesting news a third time after requesting to clear the cache. // This simulate the behaviour after a call to CacheManager::invalidateCaches() // This requires new mock call expectations. { NewsProxy::invalidateCache(client, CacheUnit::NewsProfile); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNews, MockResultHelper::createSuccessResult(jsonBody)); const AsyncResult > newsResult3 = client.requestProfileNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult3)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResult3.getResult())); } // Requesting news a fourth time. This shall not affect the mock call expectations. // The clear cache request only applies once. { const AsyncResult > newsResult4 = client.requestProfileNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult4)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResult4.getResult())); } const SpaceId spaceId5("3a441107-673a-40b7-a304-0cd5fcb7FAKE"); // Requesting news a fifth time on a different space ID. // This shall requires a new set of the mock call expectations. { // Note that the same JSON is sent here for a different Space Id... US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNews, MockResultHelper::createSuccessResult(jsonBody)); const AsyncResult > newsResult5 = client.requestProfileNews(spaceId5); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult5)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResult5.getResult())); } // Requesting news a sixth time for many space IDs. // This shall requires a new set of the mock call expectations. { // Note that the same JSON is sent here for a different Space Id... US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNews, MockResultHelper::createSuccessResult(jsonBody)); const AsyncResult > newsResult6 = client.requestProfileNews(SpaceId("3a441107-673a-40b7-a304-0cd5fcbFAKE1")); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult6)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResult6.getResult())); } // Requesting news a seventh time. This shall not affect the mock call expectations. { const AsyncResult > newsResult7 = client.requestProfileNews(spaceId5); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult7)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResult7.getResult())); } // Requesting news shall not affect the mock call expectations { const AsyncResult > newsResultTemp = client.requestProfileNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResultTemp)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResultTemp.getResult())); } // Sleeping so all entries in cache expires // This requires new mock call expectations. { // A quick check to make sure the mocked TTL is in an acceptable range ASSERT_LT(ParametersSpaceMockHelper::s_MOCK_TIME_TO_LIVE_RESOURCE_MSEC, 15000); US_TEST_NS::Helper::sleep(ParametersSpaceMockHelper::s_MOCK_TIME_TO_LIVE_RESOURCE_MSEC * 2); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNews, MockResultHelper::createSuccessResult(jsonBody)); const AsyncResult > newsResultTemp = client.requestProfileNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResultTemp)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResultTemp.getResult())); } // Requesting news shall not affect the mock call expectations { const AsyncResult > newsResultTemp = client.requestProfileNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResultTemp)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResultTemp.getResult())); } } #endif #if !defined(US_DLL) /// @test Requests news with a successful response from server and a valid JSON TEST_F(NEWS_MOCK, USNOT_RequestNewsSpace) { ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); SAVE_ALLOC_COUNT(count); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNewsSpace, MockResultHelper::createSuccessResult(TestNews_BF::createMockResult())); EXPECT_ALLOC_COUNT_PC_EQ(28, count); const AsyncResult > newsResult = getFacade().getNewsClient().requestSpaceNews(); EXPECT_ALLOC_COUNT_PC_EQ(31, count); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult)); // Check resulting news content const Vector& news0 = newsResult.getResult(); ASSERT_TRUE(TestNews_BF::checkResultingNews(news0)); { const NewsInfo& info = news0.front(); EXPECT_TRUE(info.m_profileId.isValid()); EXPECT_EQ(ProfileId(DUMMY_PROFILE_ID), info.m_profileId); EXPECT_EQ(SpaceId("3a441107-673a-40b7-a304-0cd5fcb7ee9b"), info.m_spaceId); EXPECT_STREQ("neolane.AC4_DLC_01", info.m_id.getUtf8()); EXPECT_STREQ("DLCOffer", info.m_type.getUtf8()); EXPECT_STREQ("mainMenu1", info.m_placement.getUtf8()); EXPECT_EQ(1u, info.m_priority); EXPECT_EQ(20u, info.m_displayTime); EXPECT_EQ(DateTime(2014, 11, 11, 12, 0, 0), info.m_publicationDate); EXPECT_STREQ("en-US", info.m_locale.getUtf8()); EXPECT_STREQ("New DLC Released", info.m_title.getUtf8()); EXPECT_STREQ("Get the Season Pass DLC from the Marketplace", info.m_body.getUtf8()); EXPECT_STREQ("http://static8.ubisoft.com/234224/asset34.png", info.m_mediaUrl.getUtf8()); EXPECT_STREQ("image/png", info.m_mediaType.getUtf8()); { const NewsLink& link1 = info.m_links.front(); EXPECT_STREQ("pstore", link1.m_type.getUtf8()); EXPECT_STREQ("0x555308796ea1e800", link1.m_param.getUtf8()); EXPECT_STREQ("OpenedTheStoreForSeasonPass", link1.m_actionName.getUtf8()); EXPECT_STREQ("Buy the Season Pass", link1.m_actionDescription.getUtf8()); } { const NewsLink& link2 = info.m_links.back(); EXPECT_STREQ("web", link2.m_type.getUtf8()); EXPECT_STREQ("http://acu.ubisoft.com/dlc1/description.html", link2.m_param.getUtf8()); EXPECT_STREQ("MoreInfoOnSeasonPass", link2.m_actionName.getUtf8()); EXPECT_STREQ("More info...", link2.m_actionDescription.getUtf8()); } EXPECT_STREQ("{\"assetId\":13}", info.m_object.getUtf8()); } { const NewsInfo& info = news0.back(); EXPECT_TRUE(info.m_profileId.isValid()); EXPECT_EQ(ProfileId(DUMMY_PROFILE_ID), info.m_profileId); EXPECT_EQ(SpaceId("3a441107-673a-40b7-a304-0cd5fcb7ee9b"), info.m_spaceId); EXPECT_STREQ("neolane2.AC4_DLC_06", info.m_id.getUtf8()); EXPECT_STREQ("DLCOffer", info.m_type.getUtf8()); EXPECT_STREQ("mainMenu3", info.m_placement.getUtf8()); EXPECT_EQ(2u, info.m_priority); EXPECT_EQ(35u, info.m_displayTime); EXPECT_EQ(DateTime(2014, 11, 22, 17, 0, 0), info.m_publicationDate); EXPECT_STREQ("en-US", info.m_locale.getUtf8()); EXPECT_STREQ("New DLC Released", info.m_title.getUtf8()); EXPECT_STREQ("Get the Season Pass DLC from the Marketplace", info.m_body.getUtf8()); EXPECT_STREQ("http://static8.ubisoft.com/234224/asset34.png", info.m_mediaUrl.getUtf8()); EXPECT_STREQ("image/png", info.m_mediaType.getUtf8()); { const NewsLink& link1 = info.m_links.front(); EXPECT_STREQ("pstore", link1.m_type.getUtf8()); EXPECT_STREQ("0x555308796ea1e800", link1.m_param.getUtf8()); EXPECT_STREQ("OpenedTheStoreForSeasonPass", link1.m_actionName.getUtf8()); EXPECT_STREQ("Buy the Season Pass", link1.m_actionDescription.getUtf8()); } { const NewsLink& link2 = info.m_links.back(); EXPECT_STREQ("sstore", link2.m_type.getUtf8()); EXPECT_STREQ("0x555308796ea1e801", link2.m_param.getUtf8()); EXPECT_STREQ("MoreInfoOnSeasonPass", link2.m_actionName.getUtf8()); EXPECT_STREQ("More info...", link2.m_actionDescription.getUtf8()); } EXPECT_STREQ("{\"assetId\":13}", info.m_object.getUtf8()); } EXPECT_ALLOC_COUNT_PC_EQ(4938, count); } #endif #if !defined(US_DLL) /// @test Requests news with a successful response from server and a valid JSON TEST_F(NEWS_MOCK, USNOT_RequestNewsSpaceCache) { ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); SAVE_ALLOC_COUNT(count); const String jsonBody = TestNews_BF::createMockResult(); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNewsSpace, MockResultHelper::createSuccessResult(jsonBody)); NewsClient& client = getFacade().getNewsClient(); EXPECT_ALLOC_COUNT_PC_EQ(28, count); const AsyncResult > newsResult = client.requestSpaceNews(); EXPECT_ALLOC_COUNT_PC_EQ(31, count); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult)); // Check resulting news content const Vector& news0 = newsResult.getResult(); ASSERT_TRUE(TestNews_BF::checkResultingNews(news0)); // Requesting news a second time. This shall not affect the mock call expectations. { const AsyncResult > newsResult2 = client.requestSpaceNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult2)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResult2.getResult())); } // Requesting news a third time after requesting to clear the cache. // This simulate the behaviour after a call to CacheManager::invalidateCaches() // This requires new mock call expectations. { NewsProxy::invalidateCache(client, CacheUnit::NewsSpace); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNewsSpace, MockResultHelper::createSuccessResult(jsonBody)); const AsyncResult > newsResult3 = client.requestSpaceNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult3)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResult3.getResult())); } // Requesting news a fourth time. This shall not affect the mock call expectations. // The clear cache request only applies once. { const AsyncResult > newsResult4 = client.requestSpaceNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult4)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResult4.getResult())); } const SpaceId spaceId5("3a441107-673a-40b7-a304-0cd5fcb7FAKE"); // Requesting news a fifth time on a different space ID. // This shall requires a new set of the mock call expectations. { // Note that the same JSON is sent here for a different Space Id... US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNewsSpace, MockResultHelper::createSuccessResult(jsonBody)); const AsyncResult > newsResult5 = client.requestSpaceNews(spaceId5); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult5)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResult5.getResult())); } // Requesting news a sixth time for many space IDs. // This shall requires a new set of the mock call expectations. { // Note that the same JSON is sent here for a different Space Id... US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNewsSpace, MockResultHelper::createSuccessResult(jsonBody)); const AsyncResult > newsResult6 = client.requestSpaceNews(SpaceId("3a441107-673a-40b7-a304-0cd5fcbFAKE1")); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult6)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResult6.getResult())); } // Requesting news a seventh time. This shall not affect the mock call expectations. { const AsyncResult > newsResult7 = client.requestSpaceNews(spaceId5); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult7)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResult7.getResult())); } // Requesting news shall not affect the mock call expectations { const AsyncResult > newsResultTemp = client.requestSpaceNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResultTemp)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResultTemp.getResult())); } // Sleeping so all entries in cache expires // This requires new mock call expectations. { US_TEST_NS::Helper::sleep(ParametersSpaceMockHelper::s_MOCK_TIME_TO_LIVE_RESOURCE_MSEC * 2); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNewsSpace, MockResultHelper::createSuccessResult(jsonBody)); const AsyncResult > newsResultTemp = client.requestSpaceNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResultTemp)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResultTemp.getResult())); } // Requesting news shall not affect the mock call expectations { const AsyncResult > newsResultTemp = client.requestSpaceNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResultTemp)); ASSERT_TRUE(TestNews_BF::checkResultingNews(newsResultTemp.getResult())); } EXPECT_ALLOC_COUNT_PC_EQ(4938, count); } #endif #if !defined(US_DLL) /// @test Requests news with a successful response from server and an invalid JSON TEST_F(NEWS_MOCK, USNOT_RequestNewsErrorJsonSyntax) { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Request news failed. Invalid JSON in response's body", LogLevel::Error, Times(2)); }); ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); { testing::InSequence s; const MockAsyncResult mockResult = MockResultHelper::createSuccessResult( TestNews_BF::createMockResult().replace("{", "")); // Omitting the opening bracket for invalid JSON. US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNews, mockResult); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNewsSpace, mockResult); } EXPECT_TRUE(AsyncHelper::waitFailure(getFacade().getNewsClient().requestProfileNews(), Errors::CORE_INVALID_JSON_FORMAT)); EXPECT_TRUE(AsyncHelper::waitFailure(getFacade().getNewsClient().requestSpaceNews(), Errors::CORE_INVALID_JSON_FORMAT)); } #endif #if !defined(US_DLL) /// @test Requests news with a successful response from server and a valid JSON (missing fields) TEST_F(NEWS_MOCK, USNOT_RequestNewsErrorJsonMissingFields) { ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); { testing::InSequence s; const MockAsyncResult mockResult = MockResultHelper::createSuccessResult( TestNews_BF::createMockResult().replace("\"newsId\":\"neolane.AC4_DLC_01\",", "")); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNews, mockResult); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNewsSpace, mockResult); } EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getNewsClient().requestProfileNews())); EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getNewsClient().requestSpaceNews())); } #endif #if !defined(US_DLL) /// @test Requests news with a successful response from server and a valid JSON (extra fields) TEST_F(NEWS_MOCK, USNOT_RequestNewsJsonExtraFields) { ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); { const String jsonBody = TestNews_BF::createMockResult() .replace("\"newsId\":\"neolane.AC4_DLC_01\",", "\"newsId\":\"neolane.AC4_DLC_01\",\"priorityExtraField1\": 1,"); testing::InSequence s; const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(jsonBody); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNews, mockResult); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNewsSpace, mockResult); } EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getNewsClient().requestProfileNews())); EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getNewsClient().requestSpaceNews())); } #endif #if !defined(US_DLL) /// @test Requests News parsing a JSON structure containing extra Root node. TEST_F(NEWS_MOCK, USNOT_RequestNewsWithExtraRootNode) { ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); { const String jsonBody = TestNews_BF::createMockResult(); // Add extra root node // Extra node must be first in json 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()); testing::InSequence s; const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(jsonBodyExtraNode); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNews, mockResult); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNewsSpace, mockResult); } { const AsyncResult > newsResult = getFacade().getNewsClient().requestProfileNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult)); EXPECT_EQ(6, newsResult.getResult().size()); } { const AsyncResult > newsResult = getFacade().getNewsClient().requestSpaceNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult)); EXPECT_EQ(6, newsResult.getResult().size()); } } #endif #if !defined(US_DLL) /// @test Requests news with an HTTP error from server. TEST_F(NEWS_MOCK, USNOT_RequestNewsErrorHttp) { ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Status code: 400", LogLevel::Error, Times(2)); }); { testing::InSequence s; const MockAsyncResult mockResult = MockResultHelper::createHttpErrorResult(RestStatusCode::Error400, "{\"error\":\"myerror\"}"); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNews, mockResult); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNewsSpace, mockResult); } EXPECT_TRUE(AsyncHelper::waitFailure(getFacade().getNewsClient().requestProfileNews(), Errors::NEWS_GENERIC_FAILURE)); EXPECT_TRUE(AsyncHelper::waitFailure(getFacade().getNewsClient().requestSpaceNews(), Errors::NEWS_GENERIC_FAILURE)); } #endif #if !defined(US_DLL) /// @test Check the default spaceId when no spaceId is given TEST_F(NEWS_MOCK, USNOT_RequestProfileNewsDefaultParameter) { ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); HttpGet request(StringUrl("")); US_EXPECT_CALL(US_TEST_NS::Action::GetNews) .WillOnce(testing::DoAll( testing::SaveArg<0>(reinterpret_cast(&request)), testing::Return(MockResultHelper::createSuccessResult()))); EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getNewsClient().requestProfileNews())); const String spaceIdQuery = [&]() { StringStream query; query << "spaceId=" << getFacade().getWorkingSpaceId(); return query.getContent(); }(); EXPECT_NE(String::npos, URLInfo(request.getUrl()).getQuery().findSubstringCase(spaceIdQuery)); } #endif #if !defined(US_DLL) /// @test Check the default spaceId when no spaceId is given TEST_F(NEWS_MOCK, USNOT_RequestSpaceNewsDefaultParameter) { ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); HttpGet request(StringUrl("")); US_EXPECT_CALL(US_TEST_NS::Action::GetNewsSpace) .WillOnce(testing::DoAll( testing::SaveArg<0>(reinterpret_cast(&request)), testing::Return(MockResultHelper::createSuccessResult()))); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().getNewsClient().requestSpaceNews())); const String spaceIdQuery = [&]() { StringStream query; query << "spaceId=" << getFacade().getWorkingSpaceId(); return query.getContent(); }(); EXPECT_TRUE(URLInfo(request.getUrl()).getQuery().findSubstringCase(spaceIdQuery) != String::npos) << "Failed to find the Space id '" << spaceIdQuery.getUtf8() << "' into URL: " << request.getUrl().getUtf8(); } #endif /// @test Check that no request is sent and an error is raised when given spaceId is invalid TEST_F(NEWS_MOCK, USNOT_RequestProfileNewsInvalidSpaceId) { US_EXPECT_CALL(US_TEST_NS::Action::GetNews).Times(0); EXPECT_TRUE(AsyncHelper::waitFailure(getFacade().getNewsClient().requestProfileNews(SpaceId("InvalidSpaceId")), Errors::NEWS_INVALID_PARAM)); } /// @test Check that no request is sent and an error is raised when given spaceId is invalid TEST_F(NEWS_MOCK, USNOT_RequestSpaceNewsInvalidSpaceId) { US_EXPECT_CALL(US_TEST_NS::Action::GetNewsSpace).Times(0); EXPECT_TRUE(AsyncHelper::waitFailure(getFacade().getNewsClient().requestSpaceNews(SpaceId("InvalidSpaceId")), Errors::NEWS_INVALID_PARAM)); } /// @test Check the default Ubi-Market header when a country code is given TEST_F(NEWS_MOCK, USNOT_RequestNewsSpecifiedCountry) { const SpaceId spaceSdk = SpaceId("3a441107-673a-40b7-a304-0cd5fcb7ee9b"); HttpGet requestSpace(StringUrl("")); US_EXPECT_CALL(US_TEST_NS::Action::GetNewsSpace) .WillOnce(testing::DoAll( testing::SaveArg<0>(reinterpret_cast(&requestSpace)), testing::Return(MockResultHelper::createSuccessResult()))); EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getNewsClient().requestSpaceNews(spaceSdk, CountryName::UnitedStates))); EXPECT_NE(String::npos, requestSpace.getHeader("Ubi-Market").findSubstringCase("US")); HttpGet requestProfile(StringUrl("")); US_EXPECT_CALL(US_TEST_NS::Action::GetNews) .WillOnce(testing::DoAll( testing::SaveArg<0>(reinterpret_cast(&requestProfile)), testing::Return(MockResultHelper::createSuccessResult()))); EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getNewsClient().requestProfileNews(spaceSdk, CountryName::France))); EXPECT_NE(String::npos, requestProfile.getHeader("Ubi-Market").findSubstringCase("FR")); } #if !defined(US_DLL) /// @test Validates the push of the player.news.action and player.news.impression. TEST_F(NEWS_MOCK, USNOT_NewsActionAndImpression) { HttpPost httpRequest(StringUrl(""), String()); { US_EXPECT_CALL(US_TEST_NS::Action::DeleteSession) .WillOnce(testing::Return(MockResultHelper::createSuccessResult())); US_EXPECT_CALL(US_TEST_NS::Action::SendEvents) .WillOnce(testing::DoAll( testing::SaveArg<0>(static_cast(&httpRequest)), testing::Return(MockResultHelper::createSuccessResult()))); } waitForPostLoginCompletion(); const String newsId1("News2"); const String placement1("Placement1"); const String action("Action1"); ASSERT_TRUE(getFacade().getNewsClient().reportNewsAction(newsId1, placement1, action)); const String newsId2("News2"); const String placement2("Placement2"); const TimeSeconds duration = 10ul; ASSERT_TRUE(getFacade().getNewsClient().reportNewsImpression(newsId2, placement2, duration)); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().deleteSession())); { Map expectedEvents; expectedEvents[0] = "game.start"; expectedEvents[1] = "player.start"; expectedEvents[2] = "player.news.action"; expectedEvents[3] = "player.news.impression"; ASSERT_THAT(TestNews_BF::extractEventsFromRequest(httpRequest), expectedEvents); } const Json requestBodyJson(httpRequest.getBodyAsString()); for (const auto& it : requestBodyJson["events"].getValueArray()) { if (it["type"].getValueString() == "player.news.action") { EXPECT_EQ(newsId1, it["typeData"]["newsId"].getValueString()); EXPECT_EQ(placement1, it["typeData"]["placement"].getValueString()); EXPECT_EQ(action, it["typeData"]["actionName"].getValueString()); } if (it["type"].getValueString() == "player.news.impression") { EXPECT_EQ(newsId2, it["typeData"]["newsId"].getValueString()); EXPECT_EQ(placement2, it["typeData"]["placement"].getValueString()); EXPECT_EQ(duration, it["typeData"]["duration"].getValueInteger()); } } } #endif #if defined(US_TARGET_PS4) || defined(US_TARGET_XONE) || defined(US_TARGET_KILI) /// @test Checks that the country is correctly retrieved. Note : account country for PS4, console country for XBoxOne. TEST_F(NEWS_MOCK, LOCAL_DetectMarket) { HttpGet requestNews(StringUrl("")); { const MockAsyncResult mockResult = MockResultHelper::createSuccessResult(); US_EXPECT_CALL(US_TEST_NS::Action::GetNewsSpace) .WillOnce(testing::DoAll(testing::SaveArg<0>(reinterpret_cast(&requestNews)), testing::Return(mockResult))); } EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getNewsClient().requestSpaceNews())); EXPECT_EQ("US", requestNews.getHeader("Ubi-Market")); } #endif #if defined(US_SDK_FULL) // Market detection only done in full sdk #if !defined(US_TARGET_PS4) && !defined(US_TARGET_XONE) && !defined(US_TARGET_KILI) /// @test Checks that the market is correctly detected. TEST_F(NEWS_MOCK, LOCAL_DetectMarket) { // Burundi chosen as value that is probably not a default value anywhere US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetUser, MockResultHelper::createSuccessResult("{\"country\":\"BI\"}")); HttpGet requestNews(StringUrl("")); US_EXPECT_CALL(US_TEST_NS::Action::GetNewsSpace) .WillOnce(testing::DoAll( testing::SaveArg<0>(reinterpret_cast(&requestNews)), testing::Return(MockResultHelper::createSuccessResult()))); EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getNewsClient().requestSpaceNews())); EXPECT_EQ("BI", requestNews.getHeader("Ubi-Market")); } /// @test Checks that the Ubi-Market is not sent when requesting the user localization returns an error TEST_F(NEWS_MOCK, LOCAL_DetectMarketUserLocalizationError) { PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Status code: 400", LogLevel::Error, Times(1)); }); US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetUser, MockResultHelper::createHttpErrorResult(RestStatusCode::Error400, "{\"error\":\"myError\"}")); HttpGet requestNews(StringUrl("")); US_EXPECT_CALL(US_TEST_NS::Action::GetNewsSpace) .WillOnce(testing::DoAll( testing::SaveArg<0>(reinterpret_cast(&requestNews)), testing::Return(MockResultHelper::createSuccessResult()))); EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getNewsClient().requestSpaceNews())); EXPECT_EQ(0, requestNews.getHeader("Ubi-Market").getLength()); } #if !defined(US_DLL) /// @test Checks that the Ubi-Market is not sent when the feature switch for user is disabled TEST_F(NEWS_MOCK, LOCAL_DetectMarketFeatureSwitchUsersDisabled) { ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); US_EXPECT_CALL(US_TEST_NS::Action::GetUser).Times(0); HttpGet requestNews(StringUrl("")); US_EXPECT_CALL(US_TEST_NS::Action::GetNewsSpace) .WillOnce(testing::DoAll( testing::SaveArg<0>(reinterpret_cast(&requestNews)), testing::Return(MockResultHelper::createSuccessResult()))); EXPECT_TRUE(AsyncHelper::waitSuccess(getFacade().getNewsClient().requestSpaceNews())); EXPECT_EQ(0, requestNews.getHeader("Ubi-Market").getLength()); } #endif #endif // defined(US_SDK_FULL) #endif #if !defined(US_DLL) /// @test The news service guarantees the order in which the links are returned by their API. /// The SDK must return the links and sub-links in the same order. TEST_F(NEWS_MOCK, LOCAL_ConfirmNewsLinksOrder) { ParametersClientProxy::enableSwitch(getFacadeInternal(), FeatureSwitchId::Users, false); // Avoids the request to get the country ASSERT_FALSE(getFacade().getParametersClient().isUsFeatureSwitchEnabled(FeatureSwitchId::Users)); // Allows to mock a news with various link types and multiple sub-links (2x weblink) struct Local { static Json createMock() { JsonWriter newsWrapperWriter; JsonWriter newsArrayWriter(JsonWriterType::Array); JsonWriter writer; writer["profileId"] = "aaaa1111-bbbb-2222-cccc-3333dddd4444"; // <<<<<< missing field writer["spaceId"] = "11112222-3333-4444-5555-666677778888"; writer["newsId"] = "aaaabbbbcccc-dddd-eeee-ffff-123456781234"; // This is not a GUID writer["type"] = "myNewsType"; writer["placement"] = "myNewsPlacement"; writer["priority"] = 123; writer["displayTime"] = 60; writer["publicationDate"] = "2014-11-11T12:00:00"; writer["locale"] = "en-us"; writer["title"] = "myNewsTitle"; writer["body"] = "myNewsBody"; writer["mediaURL"] = "http://myNewsUrl.com"; writer["mediaType"] = "myNewsMediaType"; { Vector links; links.reserve(4); // Adding a popup type link { JsonWriter link; link["type"] = "popup"; link["param"] = "myLinkParam0"; link["actionName"] = "myLinkActionName0"; link["actionDescription"] = "myLinkActionDesc0"; links.push_back(link.getJson()); } // Adding two weblink type for (uint32 i = 1; i < 3; ++i) { JsonWriter link; link["type"] = "weblink"; link["param"] = String::formatText("myLinkParam%d", i); link["actionName"] = String::formatText("myLinkActionName%d", i); link["actionDescription"] = String::formatText("myLinkActionDesc%d", i); links.push_back(link.getJson()); } // Adding an image type link { JsonWriter link; link["type"] = "image"; link["param"] = "myLinkParam3"; link["actionName"] = "myLinkActionName3"; link["actionDescription"] = "myLinkActionDesc3"; links.push_back(link.getJson()); } writer["links"] = links; } { JsonWriter obj; obj["field"] = "value"; writer["obj"] = obj.getJson(); } newsArrayWriter.addItemToArray(writer.getJson()); newsWrapperWriter["news"] = newsArrayWriter.getJson(); return newsWrapperWriter.getJson(); } }; US_EXPECT_CALL_SIMPLE(US_TEST_NS::Action::GetNews, MockResultHelper::createSuccessResult(Local::createMock().renderContent())); const AsyncResult> newsResult = getFacade().getNewsClient().requestProfileNews(); ASSERT_TRUE(AsyncHelper::waitSuccess(newsResult)); const Vector& news = newsResult.getResult(); ASSERT_TRUE(news.size() == 1u); const NewsInfo& info = news[0]; ASSERT_TRUE(info.m_links.size() == 4u); // Verify the order of the links type is popup->weblink->weblink->image for 4 links provided EXPECT_STREQ("popup", info.m_links[0].m_type.getUtf8()); EXPECT_STREQ("weblink", info.m_links[1].m_type.getUtf8()); EXPECT_STREQ("weblink", info.m_links[2].m_type.getUtf8()); EXPECT_STREQ("image", info.m_links[3].m_type.getUtf8()); // Verify the order of the sub-links (weblink) is link1->link2 EXPECT_STREQ("myLinkParam2", info.m_links[2].m_param.getUtf8()); EXPECT_STREQ("myLinkParam1", info.m_links[1].m_param.getUtf8()); } #if defined(US_TARGET_WINDOWS) && defined(US_SDK_TEST_CHINA) /// @test Checks that the railId and the Tencent session ticket are present in the url of the news request TEST_F(NEWS_MOCK_NOINIT, USNOT_LoginCheckChinaNewsUrl) { const LoginMockNoInitScopedUninit autoUninit(*this); { US_NS::initializeSdk(); const ApplicationId chinaPcAppId(US_TEST_NS::SPACE_ID_US_SDK_PC_CHINA_RETAIL); const String chinaPcBuildId("CHINA_IS_PROD"); US_NS::HttpConfig httpConfig; // Proxy needed for the manual http request to azure httpConfig.m_proxy.m_proxyType = HttpProxyConfig::Type::Enabled; httpConfig.m_proxy.m_host = "proxy.ubisoft.org"; httpConfig.m_proxy.m_port = 3128; configureSdk(GameConfig( chinaPcAppId, chinaPcBuildId, OnlineAccessContext::China, GameConfigEvent(String(), US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()), GameConfigConsole()), SystemConfig(US_NS::ThreadingConfig(), httpConfig)); SetUpAfterInit(); mockFullLogin(); { const String tencentTicket("DummyTencentSessionTicket"); // Perform the login // Session doesn't have to be valid for our AppId 586cc2e2-29c0-4522-8626-a1159939abe4 (UbiServices SDK PC China RETAIL) // A valid session is only possible when using this AppId 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 String weGameToken(CredentialsTypeHelper::getWeGameToken(sessionRailId, playerRailId, gameRailId)); const PlayerCredentials credentials(weGameToken, CredentialsType::WeGame, playerRailId); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().createSession(credentials, {}, {}))); waitForPostLoginCompletion(); ASSERT_TRUE(US_TEST_NS::Helper::waitForWebsocketInit(getFacade())); const MockAsyncResult mockResultSuccess = MockResultHelper::createSuccessResult("{}"); HttpGet requestGetNews((StringUrl())); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "/mock-spaces-news") .WillOnce(DoAll(testing::SaveArg<0>(static_cast(&requestGetNews)), testing::Return(mockResultSuccess))); const String currentProfile = getFacade().getAuthenticationClient().getSessionInfo().getProfileId(); US_EXPECT_CALL_HTTP(getMockHttpClientImpl(), HttpMethod::HTTP_GET, "/mock-users/" + currentProfile + "?fields=country,preferredLanguage") .Times(testing::AnyNumber()); const String currentSpace = getFacade().getWorkingSpaceId(); const AsyncResult > result = getFacade().getNewsClient().requestSpaceNewsTencent(tencentTicket, SpaceId(currentSpace)); ASSERT_TRUE(AsyncHelper::waitSuccess(result)); // /mock-spaces-news?wegameid=playerRailId&session_ticket=tencentTicket&spaceId=currentSpace EXPECT_TRUE(requestGetNews.getUrl().findSubstringCase("wegameid=" + playerRailId)) << "wegameid is not set."; EXPECT_TRUE(requestGetNews.getUrl().findSubstringCase("session_ticket=" + tencentTicket)) << "session_ticket is not set."; EXPECT_TRUE(requestGetNews.getUrl().findSubstringCase("spaceId=" + currentSpace)) << "spaceId is not set."; } } } /// @test Checks that requesting china news in a Standard online context fails TEST_F(NEWS_MOCK_NOINIT, USNOT_RequestChinaNewsInNormalOnlineContext) { const LoginMockNoInitScopedUninit autoUninit(*this); { US_NS::initializeSdk(); const ApplicationId chinaPcAppId(US_TEST_NS::SPACE_ID_US_SDK_PC_CHINA_RETAIL); const String chinaPcBuildId("CHINA_IS_PROD"); US_NS::HttpConfig httpConfig; // Proxy needed for the manual http request to azure httpConfig.m_proxy.m_proxyType = HttpProxyConfig::Type::Enabled; httpConfig.m_proxy.m_host = "proxy.ubisoft.org"; httpConfig.m_proxy.m_port = 3128; configureSdk(GameConfig( chinaPcAppId, chinaPcBuildId, OnlineAccessContext::Standard, GameConfigEvent(String(), US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()), GameConfigConsole()), SystemConfig(US_NS::ThreadingConfig(), httpConfig)); SetUpAfterInit(); mockFullLogin(); { const String tencentTicket("DummyTencentSessionTicket"); // Perform the login // Those IDs are from Identity Team // Session doesn't have to be valid for our AppId 586cc2e2-29c0-4522-8626-a1159939abe4 (UbiServices SDK PC China RETAIL) // A valid session is only possible when using WeGame SDK 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 String weGameToken(CredentialsTypeHelper::getWeGameToken(sessionRailId, playerRailId, gameRailId)); const PlayerCredentials credentials(weGameToken, CredentialsType::WeGame, playerRailId); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().createSession(credentials, {}, {}))); waitForPostLoginCompletion(); ASSERT_TRUE(US_TEST_NS::Helper::waitForWebsocketInit(getFacade())); const String currentSpace = getFacade().getWorkingSpaceId(); PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Cannot perform request in an online context different than China", LogLevel::Error, Times(2)); }); const AsyncResult > result = getFacade().getNewsClient().requestSpaceNewsTencent(tencentTicket, SpaceId(currentSpace)); const AsyncResult > result2 = getFacade().getNewsClient().requestProfileNewsTencent(tencentTicket, SpaceId(currentSpace)); ASSERT_TRUE(AsyncHelper::waitFailure(result, Errors::NEWS_GENERIC_FAILURE)); ASSERT_TRUE(AsyncHelper::waitFailure(result2, Errors::NEWS_GENERIC_FAILURE)); } } } /// @test Checks that requesting china news without a valid Tencent session ticket fails TEST_F(NEWS_MOCK_NOINIT, USNOT_RequestChinaNewsInvalidTencentSessionTicket) { const LoginMockNoInitScopedUninit autoUninit(*this); { US_NS::initializeSdk(); const ApplicationId chinaPcAppId(US_TEST_NS::SPACE_ID_US_SDK_PC_CHINA_RETAIL); const String chinaPcBuildId("CHINA_IS_PROD"); US_NS::HttpConfig httpConfig; // Proxy needed for the manual http request to azure httpConfig.m_proxy.m_proxyType = HttpProxyConfig::Type::Enabled; httpConfig.m_proxy.m_host = "proxy.ubisoft.org"; httpConfig.m_proxy.m_port = 3128; configureSdk(GameConfig( chinaPcAppId, chinaPcBuildId, OnlineAccessContext::China, GameConfigEvent(String(), US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()), GameConfigConsole()), SystemConfig(US_NS::ThreadingConfig(), httpConfig)); SetUpAfterInit(); mockFullLogin(); { // Perform the login // Those IDs are from Identity Team // Session doesn't have to be valid for our AppId 586cc2e2-29c0-4522-8626-a1159939abe4 (UbiServices SDK PC China RETAIL) // A valid session is only possible when using WeGame SDK 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 String weGameToken(CredentialsTypeHelper::getWeGameToken(sessionRailId, playerRailId, gameRailId)); const PlayerCredentials credentials(weGameToken, CredentialsType::WeGame, playerRailId); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().createSession(credentials, {}, {}))); waitForPostLoginCompletion(); ASSERT_TRUE(US_TEST_NS::Helper::waitForWebsocketInit(getFacade())); const String currentSpace = getFacade().getWorkingSpaceId(); PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Cannot perform request with an empty Tencent session ticket", LogLevel::Error, Times(2)); }); const AsyncResult > result = getFacade().getNewsClient().requestSpaceNewsTencent("", SpaceId(currentSpace)); const AsyncResult > result2 = getFacade().getNewsClient().requestProfileNewsTencent("", SpaceId(currentSpace)); ASSERT_TRUE(AsyncHelper::waitFailure(result, Errors::NEWS_INVALID_PARAM)); ASSERT_TRUE(AsyncHelper::waitFailure(result2, Errors::NEWS_INVALID_PARAM)); } } } /// @test Checks that requesting Standard news in a China online context fails TEST_F(NEWS_MOCK_NOINIT, USNOT_RequestNewsInChinaOnlineContext) { const LoginMockNoInitScopedUninit autoUninit(*this); { US_NS::initializeSdk(); const ApplicationId chinaPcAppId(US_TEST_NS::SPACE_ID_US_SDK_PC_CHINA_RETAIL); const String chinaPcBuildId("CHINA_IS_PROD"); US_NS::HttpConfig httpConfig; // Proxy needed for the manual http request to azure httpConfig.m_proxy.m_proxyType = HttpProxyConfig::Type::Enabled; httpConfig.m_proxy.m_host = "proxy.ubisoft.org"; httpConfig.m_proxy.m_port = 3128; configureSdk(GameConfig( chinaPcAppId, chinaPcBuildId, OnlineAccessContext::China, GameConfigEvent(String(), US_TEST_NS::US_SDK_DUMMY_GAME_SKU, Vector()), GameConfigConsole()), SystemConfig(US_NS::ThreadingConfig(), httpConfig)); SetUpAfterInit(); mockFullLogin(); { // Perform the login // Those IDs are from Identity Team // Session doesn't have to be valid for our AppId 586cc2e2-29c0-4522-8626-a1159939abe4 (UbiServices SDK PC China RETAIL) // A valid session is only possible when using WeGame SDK 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 String weGameToken(CredentialsTypeHelper::getWeGameToken(sessionRailId, playerRailId, gameRailId)); const PlayerCredentials credentials(weGameToken, CredentialsType::WeGame, playerRailId); ASSERT_TRUE(AsyncHelper::waitSuccess(getFacade().createSession(credentials, {}, {}))); waitForPostLoginCompletion(); ASSERT_TRUE(US_TEST_NS::Helper::waitForWebsocketInit(getFacade())); const String currentSpace = getFacade().getWorkingSpaceId(); PrepareLoggingMock([](US_TEST_NS::MockLogDevice& device) { US_EXPECT_LOG("Cannot perform requestNews in a China online context. Use requestNewsTencent instead", LogLevel::Error, Times(2)); }); const AsyncResult > result = getFacade().getNewsClient().requestSpaceNews(SpaceId(currentSpace)); const AsyncResult > result2 = getFacade().getNewsClient().requestProfileNews(SpaceId(currentSpace)); ASSERT_TRUE(AsyncHelper::waitFailure(result, Errors::NEWS_GENERIC_FAILURE)); ASSERT_TRUE(AsyncHelper::waitFailure(result2, Errors::NEWS_GENERIC_FAILURE)); } } } #endif // defined(US_TARGET_WINDOWS) && defined(US_SDK_TEST_CHINA) #endif };