host_list_service_unittest.mm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #if !defined(__has_feature) || !__has_feature(objc_arc)
  5. #error "This file requires ARC support."
  6. #endif
  7. #include "remoting/ios/facade/host_list_service.h"
  8. #import <Foundation/Foundation.h>
  9. #import "remoting/ios/facade/remoting_authentication.h"
  10. #import "remoting/ios/facade/remoting_service.h"
  11. #import "third_party/ocmock/OCMock/OCMock.h"
  12. #include "base/bind.h"
  13. #include "base/run_loop.h"
  14. #include "base/test/task_environment.h"
  15. #include "base/threading/sequenced_task_runner_handle.h"
  16. #include "net/http/http_status_code.h"
  17. #include "remoting/base/directory_service_client.h"
  18. #include "remoting/base/fake_oauth_token_getter.h"
  19. #include "remoting/base/protobuf_http_status.h"
  20. #include "remoting/base/protobuf_http_test_responder.h"
  21. #include "services/network/public/cpp/shared_url_loader_factory.h"
  22. #include "testing/gtest/include/gtest/gtest.h"
  23. #include "testing/gtest_mac.h"
  24. #include "testing/platform_test.h"
  25. #include "ui/base/l10n/l10n_util.h"
  26. #include "ui/base/resource/resource_bundle.h"
  27. #include "ui/display/screen.h"
  28. #define EXPECT_HOST_LIST_STATE(expected) \
  29. EXPECT_EQ(expected, host_list_service_.state())
  30. #define EXPECT_NO_FETCH_FAILURE() \
  31. EXPECT_TRUE(host_list_service_.last_fetch_failure() == nullptr)
  32. namespace remoting {
  33. namespace {
  34. apis::v1::HostInfo CreateFakeHost(const std::string& host_id) {
  35. apis::v1::HostInfo fake_host;
  36. fake_host.set_host_id(host_id);
  37. return fake_host;
  38. }
  39. apis::v1::GetHostListResponse CreateFakeHostListResponse(
  40. const std::string& host_id = "fake_host") {
  41. apis::v1::GetHostListResponse response;
  42. *response.add_hosts() = CreateFakeHost(host_id);
  43. return response;
  44. }
  45. } // namespace
  46. class HostListServiceTest : public PlatformTest {
  47. public:
  48. HostListServiceTest();
  49. ~HostListServiceTest() override;
  50. protected:
  51. // Respond to a GetHostList request and block until the host list state is
  52. // changed.
  53. void BlockAndRespondGetHostList(
  54. const ProtobufHttpStatus& status,
  55. const apis::v1::GetHostListResponse& response);
  56. void NotifyUserUpdate(bool is_signed_in);
  57. base::test::TaskEnvironment task_environment_;
  58. ProtobufHttpTestResponder test_responder_;
  59. FakeOAuthTokenGetter oauth_token_getter_{OAuthTokenGetter::Status::SUCCESS,
  60. "", ""};
  61. HostListService host_list_service_;
  62. int on_fetch_failed_call_count_ = 0;
  63. int on_host_list_state_changed_call_count_ = 0;
  64. id remoting_authentication_mock_;
  65. id remoting_service_mock_;
  66. private:
  67. base::CallbackListSubscription host_list_state_subscription_;
  68. base::CallbackListSubscription fetch_failure_subscription_;
  69. display::ScopedNativeScreen screen_;
  70. };
  71. HostListServiceTest::HostListServiceTest()
  72. : host_list_service_(base::SequenceBound<DirectoryServiceClient>(
  73. task_environment_.GetMainThreadTaskRunner(),
  74. &oauth_token_getter_,
  75. test_responder_.GetUrlLoaderFactory())) {
  76. static const char use_cocoa_locale[] = "";
  77. l10n_util::OverrideLocaleWithCocoaLocale();
  78. ui::ResourceBundle::InitSharedInstanceWithLocale(
  79. use_cocoa_locale, NULL, ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES);
  80. on_fetch_failed_call_count_ = 0;
  81. on_host_list_state_changed_call_count_ = 0;
  82. remoting_authentication_mock_ =
  83. OCMProtocolMock(@protocol(RemotingAuthentication));
  84. remoting_service_mock_ = OCMClassMock([RemotingService class]);
  85. OCMStub([remoting_service_mock_ instance]).andReturn(remoting_service_mock_);
  86. OCMStub([remoting_service_mock_ authentication])
  87. .andReturn(remoting_authentication_mock_);
  88. host_list_state_subscription_ =
  89. host_list_service_.RegisterHostListStateCallback(base::BindRepeating(
  90. [](HostListServiceTest* that) {
  91. that->on_host_list_state_changed_call_count_++;
  92. },
  93. base::Unretained(this)));
  94. fetch_failure_subscription_ =
  95. host_list_service_.RegisterFetchFailureCallback(base::BindRepeating(
  96. [](HostListServiceTest* that) {
  97. that->on_fetch_failed_call_count_++;
  98. },
  99. base::Unretained(this)));
  100. }
  101. HostListServiceTest::~HostListServiceTest() {
  102. ui::ResourceBundle::CleanupSharedInstance();
  103. }
  104. void HostListServiceTest::BlockAndRespondGetHostList(
  105. const ProtobufHttpStatus& status,
  106. const apis::v1::GetHostListResponse& response) {
  107. base::RunLoop run_loop;
  108. auto subscription =
  109. host_list_service_.RegisterHostListStateCallback(run_loop.QuitClosure());
  110. if (status.ok()) {
  111. test_responder_.AddResponseToMostRecentRequestUrl(response);
  112. } else {
  113. test_responder_.AddErrorToMostRecentRequestUrl(status);
  114. }
  115. run_loop.Run();
  116. }
  117. void HostListServiceTest::NotifyUserUpdate(bool is_signed_in) {
  118. NSDictionary* user_info =
  119. is_signed_in ? @{kUserInfo : [[UserInfo alloc] init]} : @{};
  120. [NSNotificationCenter.defaultCenter postNotificationName:kUserDidUpdate
  121. object:nil
  122. userInfo:user_info];
  123. }
  124. TEST_F(HostListServiceTest, SuccessfullyFetchedOneHost) {
  125. EXPECT_HOST_LIST_STATE(HostListService::State::NOT_FETCHED);
  126. EXPECT_NO_FETCH_FAILURE();
  127. host_list_service_.RequestFetch();
  128. EXPECT_HOST_LIST_STATE(HostListService::State::FETCHING);
  129. EXPECT_NO_FETCH_FAILURE();
  130. BlockAndRespondGetHostList(ProtobufHttpStatus::OK(),
  131. CreateFakeHostListResponse("fake_host_1"));
  132. EXPECT_HOST_LIST_STATE(HostListService::State::FETCHED);
  133. EXPECT_NO_FETCH_FAILURE();
  134. EXPECT_EQ(1u, host_list_service_.hosts().size());
  135. EXPECT_EQ("fake_host_1", host_list_service_.hosts()[0].host_id());
  136. EXPECT_EQ(2, on_host_list_state_changed_call_count_);
  137. EXPECT_EQ(0, on_fetch_failed_call_count_);
  138. }
  139. TEST_F(HostListServiceTest, SuccessfullyFetchedTwoHosts_HostListSorted) {
  140. EXPECT_HOST_LIST_STATE(HostListService::State::NOT_FETCHED);
  141. EXPECT_NO_FETCH_FAILURE();
  142. host_list_service_.RequestFetch();
  143. EXPECT_HOST_LIST_STATE(HostListService::State::FETCHING);
  144. EXPECT_NO_FETCH_FAILURE();
  145. apis::v1::GetHostListResponse response;
  146. response.add_hosts()->set_host_name("Host 2");
  147. response.add_hosts()->set_host_name("Host 1");
  148. BlockAndRespondGetHostList(ProtobufHttpStatus::OK(), response);
  149. EXPECT_HOST_LIST_STATE(HostListService::State::FETCHED);
  150. EXPECT_NO_FETCH_FAILURE();
  151. EXPECT_EQ(2u, host_list_service_.hosts().size());
  152. EXPECT_EQ("Host 1", host_list_service_.hosts()[0].host_name());
  153. EXPECT_EQ("Host 2", host_list_service_.hosts()[1].host_name());
  154. EXPECT_EQ(2, on_host_list_state_changed_call_count_);
  155. EXPECT_EQ(0, on_fetch_failed_call_count_);
  156. }
  157. TEST_F(HostListServiceTest, FetchHostListRequestFailed) {
  158. EXPECT_HOST_LIST_STATE(HostListService::State::NOT_FETCHED);
  159. EXPECT_NO_FETCH_FAILURE();
  160. host_list_service_.RequestFetch();
  161. EXPECT_HOST_LIST_STATE(HostListService::State::FETCHING);
  162. EXPECT_NO_FETCH_FAILURE();
  163. BlockAndRespondGetHostList(
  164. ProtobufHttpStatus(ProtobufHttpStatus::Code::INTERNAL, "Internal error"),
  165. {});
  166. EXPECT_HOST_LIST_STATE(HostListService::State::NOT_FETCHED);
  167. EXPECT_EQ(HostListService::FetchFailureReason::UNKNOWN_ERROR,
  168. host_list_service_.last_fetch_failure()->reason);
  169. EXPECT_EQ("Internal error",
  170. host_list_service_.last_fetch_failure()->localized_description);
  171. EXPECT_TRUE(host_list_service_.hosts().empty());
  172. EXPECT_EQ(2, on_host_list_state_changed_call_count_);
  173. EXPECT_EQ(1, on_fetch_failed_call_count_);
  174. }
  175. TEST_F(HostListServiceTest, FetchHostListRequestUnauthenticated_signOut) {
  176. EXPECT_HOST_LIST_STATE(HostListService::State::NOT_FETCHED);
  177. EXPECT_NO_FETCH_FAILURE();
  178. host_list_service_.RequestFetch();
  179. EXPECT_HOST_LIST_STATE(HostListService::State::FETCHING);
  180. EXPECT_NO_FETCH_FAILURE();
  181. OCMExpect([remoting_authentication_mock_ logout]);
  182. BlockAndRespondGetHostList(
  183. ProtobufHttpStatus(ProtobufHttpStatus::Code::UNAUTHENTICATED,
  184. "Unauthenticated"),
  185. {});
  186. EXPECT_HOST_LIST_STATE(HostListService::State::NOT_FETCHED);
  187. [remoting_authentication_mock_ verifyAtLocation:nil];
  188. EXPECT_EQ(2, on_host_list_state_changed_call_count_);
  189. EXPECT_EQ(1, on_fetch_failed_call_count_);
  190. }
  191. TEST_F(HostListServiceTest, RequestFetchWhileFetching_ignoreSecondRequest) {
  192. EXPECT_HOST_LIST_STATE(HostListService::State::NOT_FETCHED);
  193. host_list_service_.RequestFetch();
  194. EXPECT_HOST_LIST_STATE(HostListService::State::FETCHING);
  195. host_list_service_.RequestFetch();
  196. EXPECT_HOST_LIST_STATE(HostListService::State::FETCHING);
  197. EXPECT_EQ(1, on_host_list_state_changed_call_count_);
  198. EXPECT_EQ(0, on_fetch_failed_call_count_);
  199. }
  200. TEST_F(HostListServiceTest, UserLogOut_cancelFetch) {
  201. EXPECT_HOST_LIST_STATE(HostListService::State::NOT_FETCHED);
  202. host_list_service_.RequestFetch();
  203. EXPECT_HOST_LIST_STATE(HostListService::State::FETCHING);
  204. NotifyUserUpdate(false);
  205. EXPECT_HOST_LIST_STATE(HostListService::State::NOT_FETCHED);
  206. EXPECT_EQ(2, on_host_list_state_changed_call_count_);
  207. EXPECT_EQ(0, on_fetch_failed_call_count_);
  208. }
  209. TEST_F(HostListServiceTest, UserSwitchAccount_cancelThenRequestNewFetch) {
  210. EXPECT_HOST_LIST_STATE(HostListService::State::NOT_FETCHED);
  211. host_list_service_.RequestFetch();
  212. EXPECT_HOST_LIST_STATE(HostListService::State::FETCHING);
  213. ASSERT_EQ(1, test_responder_.GetNumPending());
  214. NotifyUserUpdate(true);
  215. // The HostListService should have cancelled the previous request and created
  216. // a new request.
  217. ASSERT_EQ(2, test_responder_.GetNumPending());
  218. ASSERT_FALSE(test_responder_.GetPendingRequest(0).client.is_connected());
  219. ASSERT_TRUE(test_responder_.GetPendingRequest(1).client.is_connected());
  220. EXPECT_HOST_LIST_STATE(HostListService::State::FETCHING);
  221. BlockAndRespondGetHostList(ProtobufHttpStatus::OK(),
  222. CreateFakeHostListResponse("fake_host_id"));
  223. EXPECT_HOST_LIST_STATE(HostListService::State::FETCHED);
  224. EXPECT_EQ(1u, host_list_service_.hosts().size());
  225. EXPECT_EQ("fake_host_id", host_list_service_.hosts()[0].host_id());
  226. // Note that there is an extra FETCHING->NOT_FETCH change during
  227. // NotifyUserUpdate(true).
  228. EXPECT_EQ(4, on_host_list_state_changed_call_count_);
  229. EXPECT_EQ(0, on_fetch_failed_call_count_);
  230. }
  231. } // namespace remoting