Home | History | Annotate | Download | only in integration
      1 // Copyright (c) 2012 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 
      5 #include "chrome/browser/sync/test/integration/sync_test.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/bind.h"
     11 #include "base/command_line.h"
     12 #include "base/memory/ref_counted.h"
     13 #include "base/message_loop/message_loop.h"
     14 #include "base/path_service.h"
     15 #include "base/process/launch.h"
     16 #include "base/strings/string_util.h"
     17 #include "base/strings/stringprintf.h"
     18 #include "base/strings/utf_string_conversions.h"
     19 #include "base/synchronization/waitable_event.h"
     20 #include "base/test/test_timeouts.h"
     21 #include "base/threading/platform_thread.h"
     22 #include "base/values.h"
     23 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
     24 #include "chrome/browser/history/history_service_factory.h"
     25 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
     26 #include "chrome/browser/lifetime/application_lifetime.h"
     27 #include "chrome/browser/profiles/profile.h"
     28 #include "chrome/browser/profiles/profile_manager.h"
     29 #include "chrome/browser/search_engines/template_url_service.h"
     30 #include "chrome/browser/search_engines/template_url_service_factory.h"
     31 #include "chrome/browser/signin/profile_identity_provider.h"
     32 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
     33 #include "chrome/browser/signin/signin_manager_factory.h"
     34 #include "chrome/browser/sync/profile_sync_service.h"
     35 #include "chrome/browser/sync/profile_sync_service_factory.h"
     36 #include "chrome/browser/sync/test/integration/fake_server_invalidation_service.h"
     37 #include "chrome/browser/sync/test/integration/p2p_invalidation_forwarder.h"
     38 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
     39 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
     40 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
     41 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
     42 #include "chrome/browser/ui/browser.h"
     43 #include "chrome/browser/ui/browser_finder.h"
     44 #include "chrome/browser/ui/host_desktop.h"
     45 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     46 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
     47 #include "chrome/common/chrome_paths.h"
     48 #include "chrome/common/chrome_switches.h"
     49 #include "chrome/test/base/testing_browser_process.h"
     50 #include "chrome/test/base/ui_test_utils.h"
     51 #include "components/bookmarks/test/bookmark_test_helpers.h"
     52 #include "components/google/core/browser/google_url_tracker.h"
     53 #include "components/invalidation/invalidation_service.h"
     54 #include "components/invalidation/invalidation_switches.h"
     55 #include "components/invalidation/p2p_invalidation_service.h"
     56 #include "components/invalidation/p2p_invalidator.h"
     57 #include "components/invalidation/profile_invalidation_provider.h"
     58 #include "components/keyed_service/core/keyed_service.h"
     59 #include "components/os_crypt/os_crypt.h"
     60 #include "components/signin/core/browser/signin_manager.h"
     61 #include "content/public/browser/web_contents.h"
     62 #include "content/public/test/test_browser_thread.h"
     63 #include "google_apis/gaia/gaia_urls.h"
     64 #include "net/base/escape.h"
     65 #include "net/base/load_flags.h"
     66 #include "net/base/network_change_notifier.h"
     67 #include "net/proxy/proxy_config.h"
     68 #include "net/proxy/proxy_config_service_fixed.h"
     69 #include "net/proxy/proxy_service.h"
     70 #include "net/test/spawned_test_server/spawned_test_server.h"
     71 #include "net/url_request/test_url_fetcher_factory.h"
     72 #include "net/url_request/url_fetcher.h"
     73 #include "net/url_request/url_fetcher_delegate.h"
     74 #include "net/url_request/url_request_context.h"
     75 #include "net/url_request/url_request_context_getter.h"
     76 #include "sync/engine/sync_scheduler_impl.h"
     77 #include "sync/protocol/sync.pb.h"
     78 #include "sync/test/fake_server/fake_server.h"
     79 #include "sync/test/fake_server/fake_server_network_resources.h"
     80 #include "url/gurl.h"
     81 
     82 #if defined(OS_CHROMEOS)
     83 #include "chromeos/chromeos_switches.h"
     84 #endif
     85 
     86 using content::BrowserThread;
     87 
     88 namespace switches {
     89 const char kPasswordFileForTest[] = "password-file-for-test";
     90 const char kSyncUserForTest[] = "sync-user-for-test";
     91 const char kSyncPasswordForTest[] = "sync-password-for-test";
     92 const char kSyncServerCommandLine[] = "sync-server-command-line";
     93 }
     94 
     95 namespace {
     96 
     97 // Helper class that checks whether a sync test server is running or not.
     98 class SyncServerStatusChecker : public net::URLFetcherDelegate {
     99  public:
    100   SyncServerStatusChecker() : running_(false) {}
    101 
    102   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE {
    103     std::string data;
    104     source->GetResponseAsString(&data);
    105     running_ =
    106         (source->GetStatus().status() == net::URLRequestStatus::SUCCESS &&
    107         source->GetResponseCode() == 200 && data.find("ok") == 0);
    108     base::MessageLoop::current()->Quit();
    109   }
    110 
    111   bool running() const { return running_; }
    112 
    113  private:
    114   bool running_;
    115 };
    116 
    117 bool IsEncryptionComplete(const ProfileSyncService* service) {
    118   return service->EncryptEverythingEnabled() && !service->encryption_pending();
    119 }
    120 
    121 // Helper class to wait for encryption to complete.
    122 class EncryptionChecker : public SingleClientStatusChangeChecker {
    123  public:
    124   explicit EncryptionChecker(ProfileSyncService* service)
    125       : SingleClientStatusChangeChecker(service) {}
    126 
    127   virtual bool IsExitConditionSatisfied() OVERRIDE {
    128     return IsEncryptionComplete(service());
    129   }
    130 
    131   virtual std::string GetDebugMessage() const OVERRIDE {
    132     return "Encryption";
    133   }
    134 };
    135 
    136 void SetProxyConfigCallback(
    137     base::WaitableEvent* done,
    138     net::URLRequestContextGetter* url_request_context_getter,
    139     const net::ProxyConfig& proxy_config) {
    140   net::ProxyService* proxy_service =
    141       url_request_context_getter->GetURLRequestContext()->proxy_service();
    142   proxy_service->ResetConfigService(
    143       new net::ProxyConfigServiceFixed(proxy_config));
    144   done->Signal();
    145 }
    146 
    147 KeyedService* BuildFakeServerProfileInvalidationProvider(
    148     content::BrowserContext* context) {
    149   return new invalidation::ProfileInvalidationProvider(
    150       scoped_ptr<invalidation::InvalidationService>(
    151           new fake_server::FakeServerInvalidationService));
    152 }
    153 
    154 KeyedService* BuildP2PProfileInvalidationProvider(
    155     content::BrowserContext* context,
    156     syncer::P2PNotificationTarget notification_target) {
    157   Profile* profile = static_cast<Profile*>(context);
    158   return new invalidation::ProfileInvalidationProvider(
    159       scoped_ptr<invalidation::InvalidationService>(
    160           new invalidation::P2PInvalidationService(
    161               scoped_ptr<IdentityProvider>(new ProfileIdentityProvider(
    162                   SigninManagerFactory::GetForProfile(profile),
    163                   ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
    164                   LoginUIServiceFactory::GetForProfile(profile))),
    165               profile->GetRequestContext(),
    166               notification_target)));
    167 }
    168 
    169 KeyedService* BuildSelfNotifyingP2PProfileInvalidationProvider(
    170     content::BrowserContext* context) {
    171   return BuildP2PProfileInvalidationProvider(context, syncer::NOTIFY_ALL);
    172 }
    173 
    174 KeyedService* BuildRealisticP2PProfileInvalidationProvider(
    175     content::BrowserContext* context) {
    176   return BuildP2PProfileInvalidationProvider(context, syncer::NOTIFY_OTHERS);
    177 }
    178 
    179 }  // namespace
    180 
    181 SyncTest::SyncTest(TestType test_type)
    182     : test_type_(test_type),
    183       server_type_(SERVER_TYPE_UNDECIDED),
    184       num_clients_(-1),
    185       use_verifier_(true),
    186       notifications_enabled_(true),
    187       test_server_handle_(base::kNullProcessHandle) {
    188   sync_datatype_helper::AssociateWithTest(this);
    189   switch (test_type_) {
    190     case SINGLE_CLIENT:
    191     case SINGLE_CLIENT_LEGACY: {
    192       num_clients_ = 1;
    193       break;
    194     }
    195     case TWO_CLIENT:
    196     case TWO_CLIENT_LEGACY: {
    197       num_clients_ = 2;
    198       break;
    199     }
    200     case MULTIPLE_CLIENT: {
    201       num_clients_ = 3;
    202       break;
    203     }
    204   }
    205 }
    206 
    207 SyncTest::~SyncTest() {}
    208 
    209 void SyncTest::SetUp() {
    210   base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
    211   if (cl->HasSwitch(switches::kPasswordFileForTest)) {
    212     ReadPasswordFile();
    213   } else if (cl->HasSwitch(switches::kSyncUserForTest) &&
    214              cl->HasSwitch(switches::kSyncPasswordForTest)) {
    215     username_ = cl->GetSwitchValueASCII(switches::kSyncUserForTest);
    216     password_ = cl->GetSwitchValueASCII(switches::kSyncPasswordForTest);
    217   } else {
    218     username_ = "user (at) gmail.com";
    219     password_ = "password";
    220   }
    221 
    222   if (username_.empty() || password_.empty())
    223     LOG(FATAL) << "Cannot run sync tests without GAIA credentials.";
    224 
    225   // Sets |server_type_| if it wasn't specified by the test.
    226   DecideServerType();
    227 
    228   // Mock the Mac Keychain service.  The real Keychain can block on user input.
    229 #if defined(OS_MACOSX)
    230   OSCrypt::UseMockKeychain(true);
    231 #endif
    232 
    233   // Start up a sync test server if one is needed and setup mock gaia responses.
    234   // Note: This must be done prior to the call to SetupClients() because we want
    235   // the mock gaia responses to be available before GaiaUrls is initialized.
    236   SetUpTestServerIfRequired();
    237 
    238   // Yield control back to the InProcessBrowserTest framework.
    239   InProcessBrowserTest::SetUp();
    240 }
    241 
    242 void SyncTest::TearDown() {
    243   // Clear any mock gaia responses that might have been set.
    244   ClearMockGaiaResponses();
    245 
    246   // Allow the InProcessBrowserTest framework to perform its tear down.
    247   InProcessBrowserTest::TearDown();
    248 
    249   // Stop the local python test server. This is a no-op if one wasn't started.
    250   TearDownLocalPythonTestServer();
    251 
    252   // Stop the local sync test server. This is a no-op if one wasn't started.
    253   TearDownLocalTestServer();
    254 
    255   fake_server_.reset();
    256 }
    257 
    258 void SyncTest::SetUpCommandLine(base::CommandLine* cl) {
    259   AddTestSwitches(cl);
    260   AddOptionalTypesToCommandLine(cl);
    261 
    262 #if defined(OS_CHROMEOS)
    263   cl->AppendSwitch(chromeos::switches::kIgnoreUserProfileMappingForTests);
    264 #endif
    265 }
    266 
    267 void SyncTest::AddTestSwitches(base::CommandLine* cl) {
    268   // Disable non-essential access of external network resources.
    269   if (!cl->HasSwitch(switches::kDisableBackgroundNetworking))
    270     cl->AppendSwitch(switches::kDisableBackgroundNetworking);
    271 
    272   if (!cl->HasSwitch(switches::kSyncShortInitialRetryOverride))
    273     cl->AppendSwitch(switches::kSyncShortInitialRetryOverride);
    274 }
    275 
    276 void SyncTest::AddOptionalTypesToCommandLine(base::CommandLine* cl) {}
    277 
    278 // static
    279 Profile* SyncTest::MakeProfile(const base::FilePath::StringType name) {
    280   base::FilePath path;
    281   PathService::Get(chrome::DIR_USER_DATA, &path);
    282   path = path.Append(name);
    283 
    284   if (!base::PathExists(path))
    285     CHECK(base::CreateDirectory(path));
    286 
    287   Profile* profile =
    288       Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
    289   g_browser_process->profile_manager()->RegisterTestingProfile(profile,
    290                                                                true,
    291                                                                true);
    292   return profile;
    293 }
    294 
    295 Profile* SyncTest::GetProfile(int index) {
    296   if (profiles_.empty())
    297     LOG(FATAL) << "SetupClients() has not yet been called.";
    298   if (index < 0 || index >= static_cast<int>(profiles_.size()))
    299     LOG(FATAL) << "GetProfile(): Index is out of bounds.";
    300   return profiles_[index];
    301 }
    302 
    303 Browser* SyncTest::GetBrowser(int index) {
    304   if (browsers_.empty())
    305     LOG(FATAL) << "SetupClients() has not yet been called.";
    306   if (index < 0 || index >= static_cast<int>(browsers_.size()))
    307     LOG(FATAL) << "GetBrowser(): Index is out of bounds.";
    308   return browsers_[index];
    309 }
    310 
    311 ProfileSyncServiceHarness* SyncTest::GetClient(int index) {
    312   if (clients_.empty())
    313     LOG(FATAL) << "SetupClients() has not yet been called.";
    314   if (index < 0 || index >= static_cast<int>(clients_.size()))
    315     LOG(FATAL) << "GetClient(): Index is out of bounds.";
    316   return clients_[index];
    317 }
    318 
    319 ProfileSyncService* SyncTest::GetSyncService(int index) {
    320   return ProfileSyncServiceFactory::GetForProfile(GetProfile(index));
    321 }
    322 
    323 std::vector<ProfileSyncService*> SyncTest::GetSyncServices() {
    324   std::vector<ProfileSyncService*> services;
    325   for (int i = 0; i < num_clients(); ++i) {
    326     services.push_back(GetSyncService(i));
    327   }
    328   return services;
    329 }
    330 
    331 Profile* SyncTest::verifier() {
    332   if (verifier_ == NULL)
    333     LOG(FATAL) << "SetupClients() has not yet been called.";
    334   return verifier_;
    335 }
    336 
    337 void SyncTest::DisableVerifier() {
    338   use_verifier_ = false;
    339 }
    340 
    341 bool SyncTest::SetupClients() {
    342   if (num_clients_ <= 0)
    343     LOG(FATAL) << "num_clients_ incorrectly initialized.";
    344   if (!profiles_.empty() || !browsers_.empty() || !clients_.empty())
    345     LOG(FATAL) << "SetupClients() has already been called.";
    346 
    347   // Create the required number of sync profiles, browsers and clients.
    348   profiles_.resize(num_clients_);
    349   browsers_.resize(num_clients_);
    350   clients_.resize(num_clients_);
    351   invalidation_forwarders_.resize(num_clients_);
    352   fake_server_invalidation_services_.resize(num_clients_);
    353   for (int i = 0; i < num_clients_; ++i) {
    354     InitializeInstance(i);
    355   }
    356 
    357   // Create the verifier profile.
    358   verifier_ = MakeProfile(FILE_PATH_LITERAL("Verifier"));
    359   test::WaitForBookmarkModelToLoad(
    360       BookmarkModelFactory::GetForProfile(verifier()));
    361   ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
    362       verifier(), Profile::EXPLICIT_ACCESS));
    363   ui_test_utils::WaitForTemplateURLServiceToLoad(
    364       TemplateURLServiceFactory::GetForProfile(verifier()));
    365   return (verifier_ != NULL);
    366 }
    367 
    368 void SyncTest::InitializeInstance(int index) {
    369   profiles_[index] = MakeProfile(
    370       base::StringPrintf(FILE_PATH_LITERAL("Profile%d"), index));
    371   EXPECT_FALSE(GetProfile(index) == NULL) << "Could not create Profile "
    372                                           << index << ".";
    373 
    374   browsers_[index] = new Browser(Browser::CreateParams(
    375       GetProfile(index), chrome::GetActiveDesktop()));
    376   EXPECT_FALSE(GetBrowser(index) == NULL) << "Could not create Browser "
    377                                           << index << ".";
    378 
    379 
    380   // Make sure the ProfileSyncService has been created before creating the
    381   // ProfileSyncServiceHarness - some tests expect the ProfileSyncService to
    382   // already exist.
    383   ProfileSyncService* profile_sync_service =
    384       ProfileSyncServiceFactory::GetForProfile(GetProfile(index));
    385 
    386   if (server_type_ == IN_PROCESS_FAKE_SERVER) {
    387     // TODO(pvalenzuela): Run the fake server via EmbeddedTestServer.
    388     profile_sync_service->OverrideNetworkResourcesForTest(
    389         make_scoped_ptr<syncer::NetworkResources>(
    390             new fake_server::FakeServerNetworkResources(fake_server_.get())));
    391   }
    392 
    393   clients_[index] =
    394       ProfileSyncServiceHarness::Create(
    395           GetProfile(index),
    396           username_,
    397           password_);
    398   EXPECT_FALSE(GetClient(index) == NULL) << "Could not create Client "
    399                                          << index << ".";
    400   InitializeInvalidations(index);
    401 
    402   test::WaitForBookmarkModelToLoad(
    403       BookmarkModelFactory::GetForProfile(GetProfile(index)));
    404   ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
    405       GetProfile(index), Profile::EXPLICIT_ACCESS));
    406   ui_test_utils::WaitForTemplateURLServiceToLoad(
    407       TemplateURLServiceFactory::GetForProfile(GetProfile(index)));
    408 }
    409 
    410 void SyncTest::InitializeInvalidations(int index) {
    411   if (server_type_ == IN_PROCESS_FAKE_SERVER) {
    412     CHECK(fake_server_.get());
    413     fake_server::FakeServerInvalidationService* invalidation_service =
    414         static_cast<fake_server::FakeServerInvalidationService*>(
    415             static_cast<invalidation::ProfileInvalidationProvider*>(
    416                 invalidation::ProfileInvalidationProviderFactory::
    417                     GetInstance()->SetTestingFactoryAndUse(
    418                         GetProfile(index),
    419                         BuildFakeServerProfileInvalidationProvider))->
    420                             GetInvalidationService());
    421     fake_server_->AddObserver(invalidation_service);
    422     if (TestUsesSelfNotifications()) {
    423       invalidation_service->EnableSelfNotifications();
    424     } else {
    425       invalidation_service->DisableSelfNotifications();
    426     }
    427     fake_server_invalidation_services_[index] = invalidation_service;
    428   } else {
    429     invalidation::P2PInvalidationService* p2p_invalidation_service =
    430         static_cast<invalidation::P2PInvalidationService*>(
    431             static_cast<invalidation::ProfileInvalidationProvider*>(
    432                 invalidation::ProfileInvalidationProviderFactory::
    433                     GetInstance()->SetTestingFactoryAndUse(
    434                         GetProfile(index),
    435                         TestUsesSelfNotifications() ?
    436                             BuildSelfNotifyingP2PProfileInvalidationProvider :
    437                             BuildRealisticP2PProfileInvalidationProvider))->
    438                                 GetInvalidationService());
    439     p2p_invalidation_service->UpdateCredentials(username_, password_);
    440     // Start listening for and emitting notifications of commits.
    441     invalidation_forwarders_[index] =
    442         new P2PInvalidationForwarder(clients_[index]->service(),
    443                                      p2p_invalidation_service);
    444   }
    445 }
    446 
    447 bool SyncTest::SetupSync() {
    448   // Create sync profiles and clients if they haven't already been created.
    449   if (profiles_.empty()) {
    450     if (!SetupClients())
    451       LOG(FATAL) << "SetupClients() failed.";
    452   }
    453 
    454   // Sync each of the profiles.
    455   for (int i = 0; i < num_clients_; ++i) {
    456     if (!GetClient(i)->SetupSync())
    457       LOG(FATAL) << "SetupSync() failed.";
    458   }
    459 
    460   // Because clients may modify sync data as part of startup (for example local
    461   // session-releated data is rewritten), we need to ensure all startup-based
    462   // changes have propagated between the clients.
    463   //
    464   // Tests that don't use self-notifications can't await quiescense.  They'll
    465   // have to find their own way of waiting for an initial state if they really
    466   // need such guarantees.
    467   if (TestUsesSelfNotifications()) {
    468     AwaitQuiescence();
    469   }
    470 
    471   return true;
    472 }
    473 
    474 void SyncTest::CleanUpOnMainThread() {
    475   for (size_t i = 0; i < clients_.size(); ++i) {
    476     clients_[i]->service()->DisableForUser();
    477   }
    478 
    479   // Some of the pending messages might rely on browser windows still being
    480   // around, so run messages both before and after closing all browsers.
    481   content::RunAllPendingInMessageLoop();
    482   // Close all browser windows.
    483   chrome::CloseAllBrowsers();
    484   content::RunAllPendingInMessageLoop();
    485 
    486   if (fake_server_.get()) {
    487     std::vector<fake_server::FakeServerInvalidationService*>::const_iterator it;
    488     for (it = fake_server_invalidation_services_.begin();
    489          it != fake_server_invalidation_services_.end(); ++it) {
    490       fake_server_->RemoveObserver(*it);
    491     }
    492   }
    493 
    494   // All browsers should be closed at this point, or else we could see memory
    495   // corruption in QuitBrowser().
    496   CHECK_EQ(0U, chrome::GetTotalBrowserCount());
    497   invalidation_forwarders_.clear();
    498   fake_server_invalidation_services_.clear();
    499   clients_.clear();
    500 }
    501 
    502 void SyncTest::SetUpInProcessBrowserTestFixture() {
    503   // We don't take a reference to |resolver|, but mock_host_resolver_override_
    504   // does, so effectively assumes ownership.
    505   net::RuleBasedHostResolverProc* resolver =
    506       new net::RuleBasedHostResolverProc(host_resolver());
    507   resolver->AllowDirectLookup("*.google.com");
    508   // On Linux, we use Chromium's NSS implementation which uses the following
    509   // hosts for certificate verification. Without these overrides, running the
    510   // integration tests on Linux causes error as we make external DNS lookups.
    511   resolver->AllowDirectLookup("*.thawte.com");
    512   resolver->AllowDirectLookup("*.geotrust.com");
    513   resolver->AllowDirectLookup("*.gstatic.com");
    514   mock_host_resolver_override_.reset(
    515       new net::ScopedDefaultHostResolverProc(resolver));
    516 }
    517 
    518 void SyncTest::TearDownInProcessBrowserTestFixture() {
    519   mock_host_resolver_override_.reset();
    520 }
    521 
    522 void SyncTest::ReadPasswordFile() {
    523   base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
    524   password_file_ = cl->GetSwitchValuePath(switches::kPasswordFileForTest);
    525   if (password_file_.empty())
    526     LOG(FATAL) << "Can't run live server test without specifying --"
    527                << switches::kPasswordFileForTest << "=<filename>";
    528   std::string file_contents;
    529   base::ReadFileToString(password_file_, &file_contents);
    530   ASSERT_NE(file_contents, "") << "Password file \""
    531       << password_file_.value() << "\" does not exist.";
    532   std::vector<std::string> tokens;
    533   std::string delimiters = "\r\n";
    534   Tokenize(file_contents, delimiters, &tokens);
    535   ASSERT_EQ(2U, tokens.size()) << "Password file \""
    536       << password_file_.value()
    537       << "\" must contain exactly two lines of text.";
    538   username_ = tokens[0];
    539   password_ = tokens[1];
    540 }
    541 
    542 void SyncTest::SetupMockGaiaResponses() {
    543   factory_.reset(new net::URLFetcherImplFactory());
    544   fake_factory_.reset(new net::FakeURLFetcherFactory(factory_.get()));
    545   fake_factory_->SetFakeResponse(
    546       GaiaUrls::GetInstance()->get_user_info_url(),
    547       "email=user (at) gmail.com\ndisplayEmail=user (at) gmail.com",
    548       net::HTTP_OK,
    549       net::URLRequestStatus::SUCCESS);
    550   fake_factory_->SetFakeResponse(
    551       GaiaUrls::GetInstance()->issue_auth_token_url(),
    552       "auth",
    553       net::HTTP_OK,
    554       net::URLRequestStatus::SUCCESS);
    555   fake_factory_->SetFakeResponse(
    556       GURL(GoogleURLTracker::kSearchDomainCheckURL),
    557       ".google.com",
    558       net::HTTP_OK,
    559       net::URLRequestStatus::SUCCESS);
    560   fake_factory_->SetFakeResponse(
    561       GaiaUrls::GetInstance()->client_login_to_oauth2_url(),
    562       "some_response",
    563       net::HTTP_OK,
    564       net::URLRequestStatus::SUCCESS);
    565   fake_factory_->SetFakeResponse(
    566       GaiaUrls::GetInstance()->oauth2_token_url(),
    567       "{"
    568       "  \"refresh_token\": \"rt1\","
    569       "  \"access_token\": \"at1\","
    570       "  \"expires_in\": 3600,"
    571       "  \"token_type\": \"Bearer\""
    572       "}",
    573       net::HTTP_OK,
    574       net::URLRequestStatus::SUCCESS);
    575   fake_factory_->SetFakeResponse(
    576       GaiaUrls::GetInstance()->oauth_user_info_url(),
    577       "{"
    578       "  \"id\": \"12345\""
    579       "}",
    580       net::HTTP_OK,
    581       net::URLRequestStatus::SUCCESS);
    582   fake_factory_->SetFakeResponse(
    583       GaiaUrls::GetInstance()->oauth1_login_url(),
    584       "SID=sid\nLSID=lsid\nAuth=auth_token",
    585       net::HTTP_OK,
    586       net::URLRequestStatus::SUCCESS);
    587   fake_factory_->SetFakeResponse(
    588       GaiaUrls::GetInstance()->oauth2_revoke_url(),
    589       "",
    590       net::HTTP_OK,
    591       net::URLRequestStatus::SUCCESS);
    592 }
    593 
    594 void SyncTest::SetOAuth2TokenResponse(const std::string& response_data,
    595                                       net::HttpStatusCode response_code,
    596                                       net::URLRequestStatus::Status status) {
    597   ASSERT_TRUE(NULL != fake_factory_.get());
    598   fake_factory_->SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
    599                                  response_data, response_code, status);
    600 }
    601 
    602 void SyncTest::ClearMockGaiaResponses() {
    603   // Clear any mock gaia responses that might have been set.
    604   if (fake_factory_) {
    605     fake_factory_->ClearFakeResponses();
    606     fake_factory_.reset();
    607   }
    608 
    609   // Cancel any outstanding URL fetches and destroy the URLFetcherImplFactory we
    610   // created.
    611   net::URLFetcher::CancelAll();
    612   factory_.reset();
    613 }
    614 
    615 void SyncTest::DecideServerType() {
    616   // Only set |server_type_| if it hasn't already been set. This allows for
    617   // tests to explicitly set this value in each test class if needed.
    618   if (server_type_ == SERVER_TYPE_UNDECIDED) {
    619     base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
    620     if (!cl->HasSwitch(switches::kSyncServiceURL) &&
    621         !cl->HasSwitch(switches::kSyncServerCommandLine)) {
    622       // If neither a sync server URL nor a sync server command line is
    623       // provided, start up a local sync test server and point Chrome
    624       // to its URL.  This is the most common configuration, and the only
    625       // one that makes sense for most developers. FakeServer is the
    626       // current solution but some scenarios are only supported by the
    627       // legacy python server.
    628       switch (test_type_) {
    629         case SINGLE_CLIENT:
    630         case TWO_CLIENT:
    631         case MULTIPLE_CLIENT:
    632           server_type_ = IN_PROCESS_FAKE_SERVER;
    633           break;
    634         default:
    635           server_type_ = LOCAL_PYTHON_SERVER;
    636       }
    637     } else if (cl->HasSwitch(switches::kSyncServiceURL) &&
    638                cl->HasSwitch(switches::kSyncServerCommandLine)) {
    639       // If a sync server URL and a sync server command line are provided,
    640       // start up a local sync server by running the command line. Chrome
    641       // will connect to the server at the URL that was provided.
    642       server_type_ = LOCAL_LIVE_SERVER;
    643     } else if (cl->HasSwitch(switches::kSyncServiceURL) &&
    644                !cl->HasSwitch(switches::kSyncServerCommandLine)) {
    645       // If a sync server URL is provided, but not a server command line,
    646       // it is assumed that the server is already running. Chrome will
    647       // automatically connect to it at the URL provided. There is nothing
    648       // to do here.
    649       server_type_ = EXTERNAL_LIVE_SERVER;
    650     } else {
    651       // If a sync server command line is provided, but not a server URL,
    652       // we flag an error.
    653       LOG(FATAL) << "Can't figure out how to run a server.";
    654     }
    655   }
    656 }
    657 
    658 // Start up a local sync server based on the value of server_type_, which
    659 // was determined from the command line parameters.
    660 void SyncTest::SetUpTestServerIfRequired() {
    661   if (server_type_ == LOCAL_PYTHON_SERVER) {
    662     if (!SetUpLocalPythonTestServer())
    663       LOG(FATAL) << "Failed to set up local python sync and XMPP servers";
    664     SetupMockGaiaResponses();
    665   } else if (server_type_ == LOCAL_LIVE_SERVER) {
    666     // Using mock gaia credentials requires the use of a mock XMPP server.
    667     if (username_ == "user (at) gmail.com" && !SetUpLocalPythonTestServer())
    668       LOG(FATAL) << "Failed to set up local python XMPP server";
    669     if (!SetUpLocalTestServer())
    670       LOG(FATAL) << "Failed to set up local test server";
    671   } else if (server_type_ == IN_PROCESS_FAKE_SERVER) {
    672     fake_server_.reset(new fake_server::FakeServer());
    673     SetupMockGaiaResponses();
    674   } else if (server_type_ == EXTERNAL_LIVE_SERVER) {
    675     // Nothing to do; we'll just talk to the URL we were given.
    676   } else {
    677     LOG(FATAL) << "Don't know which server environment to run test in.";
    678   }
    679 }
    680 
    681 bool SyncTest::SetUpLocalPythonTestServer() {
    682   EXPECT_TRUE(sync_server_.Start())
    683       << "Could not launch local python test server.";
    684 
    685   base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
    686   if (server_type_ == LOCAL_PYTHON_SERVER) {
    687     std::string sync_service_url = sync_server_.GetURL("chromiumsync").spec();
    688     cl->AppendSwitchASCII(switches::kSyncServiceURL, sync_service_url);
    689     DVLOG(1) << "Started local python sync server at " << sync_service_url;
    690   }
    691 
    692   int xmpp_port = 0;
    693   if (!sync_server_.server_data().GetInteger("xmpp_port", &xmpp_port)) {
    694     LOG(ERROR) << "Could not find valid xmpp_port value";
    695     return false;
    696   }
    697   if ((xmpp_port <= 0) || (xmpp_port > kuint16max)) {
    698     LOG(ERROR) << "Invalid xmpp port: " << xmpp_port;
    699     return false;
    700   }
    701 
    702   net::HostPortPair xmpp_host_port_pair(sync_server_.host_port_pair());
    703   xmpp_host_port_pair.set_port(xmpp_port);
    704   xmpp_port_.reset(new net::ScopedPortException(xmpp_port));
    705 
    706   if (!cl->HasSwitch(invalidation::switches::kSyncNotificationHostPort)) {
    707     cl->AppendSwitchASCII(invalidation::switches::kSyncNotificationHostPort,
    708                           xmpp_host_port_pair.ToString());
    709     // The local XMPP server only supports insecure connections.
    710     cl->AppendSwitch(invalidation::switches::kSyncAllowInsecureXmppConnection);
    711   }
    712   DVLOG(1) << "Started local python XMPP server at "
    713            << xmpp_host_port_pair.ToString();
    714 
    715   return true;
    716 }
    717 
    718 bool SyncTest::SetUpLocalTestServer() {
    719   base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
    720   base::CommandLine::StringType server_cmdline_string =
    721       cl->GetSwitchValueNative(switches::kSyncServerCommandLine);
    722   base::CommandLine::StringVector server_cmdline_vector;
    723   base::CommandLine::StringType delimiters(FILE_PATH_LITERAL(" "));
    724   Tokenize(server_cmdline_string, delimiters, &server_cmdline_vector);
    725   base::CommandLine server_cmdline(server_cmdline_vector);
    726   base::LaunchOptions options;
    727 #if defined(OS_WIN)
    728   options.start_hidden = true;
    729 #endif
    730   if (!base::LaunchProcess(server_cmdline, options, &test_server_handle_))
    731     LOG(ERROR) << "Could not launch local test server.";
    732 
    733   const base::TimeDelta kMaxWaitTime = TestTimeouts::action_max_timeout();
    734   const int kNumIntervals = 15;
    735   if (WaitForTestServerToStart(kMaxWaitTime, kNumIntervals)) {
    736     DVLOG(1) << "Started local test server at "
    737              << cl->GetSwitchValueASCII(switches::kSyncServiceURL) << ".";
    738     return true;
    739   } else {
    740     LOG(ERROR) << "Could not start local test server at "
    741                << cl->GetSwitchValueASCII(switches::kSyncServiceURL) << ".";
    742     return false;
    743   }
    744 }
    745 
    746 bool SyncTest::TearDownLocalPythonTestServer() {
    747   if (!sync_server_.Stop()) {
    748     LOG(ERROR) << "Could not stop local python test server.";
    749     return false;
    750   }
    751   xmpp_port_.reset();
    752   return true;
    753 }
    754 
    755 bool SyncTest::TearDownLocalTestServer() {
    756   if (test_server_handle_ != base::kNullProcessHandle) {
    757     EXPECT_TRUE(base::KillProcess(test_server_handle_, 0, false))
    758         << "Could not stop local test server.";
    759     base::CloseProcessHandle(test_server_handle_);
    760     test_server_handle_ = base::kNullProcessHandle;
    761   }
    762   return true;
    763 }
    764 
    765 bool SyncTest::WaitForTestServerToStart(base::TimeDelta wait, int intervals) {
    766   for (int i = 0; i < intervals; ++i) {
    767     if (IsTestServerRunning())
    768       return true;
    769     base::PlatformThread::Sleep(wait / intervals);
    770   }
    771   return false;
    772 }
    773 
    774 bool SyncTest::IsTestServerRunning() {
    775   base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
    776   std::string sync_url = cl->GetSwitchValueASCII(switches::kSyncServiceURL);
    777   GURL sync_url_status(sync_url.append("/healthz"));
    778   SyncServerStatusChecker delegate;
    779   scoped_ptr<net::URLFetcher> fetcher(net::URLFetcher::Create(
    780     sync_url_status, net::URLFetcher::GET, &delegate));
    781   fetcher->SetLoadFlags(net::LOAD_DISABLE_CACHE |
    782                         net::LOAD_DO_NOT_SEND_COOKIES |
    783                         net::LOAD_DO_NOT_SAVE_COOKIES);
    784   fetcher->SetRequestContext(g_browser_process->system_request_context());
    785   fetcher->Start();
    786   content::RunMessageLoop();
    787   return delegate.running();
    788 }
    789 
    790 void SyncTest::EnableNetwork(Profile* profile) {
    791   // TODO(pvalenzuela): Remove this restriction when FakeServer's observers
    792   // (namely FakeServerInvaldationService) are aware of a network disconnect.
    793   ASSERT_NE(IN_PROCESS_FAKE_SERVER, server_type_)
    794       << "FakeServer does not support EnableNetwork.";
    795   SetProxyConfig(profile->GetRequestContext(),
    796                  net::ProxyConfig::CreateDirect());
    797   if (notifications_enabled_) {
    798     EnableNotificationsImpl();
    799   }
    800   // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed.
    801   net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
    802 }
    803 
    804 void SyncTest::DisableNetwork(Profile* profile) {
    805   // TODO(pvalenzuela): Remove this restriction when FakeServer's observers
    806   // (namely FakeServerInvaldationService) are aware of a network disconnect.
    807   ASSERT_NE(IN_PROCESS_FAKE_SERVER, server_type_)
    808       << "FakeServer does not support DisableNetwork.";
    809   DisableNotificationsImpl();
    810   // Set the current proxy configuration to a nonexistent proxy to effectively
    811   // disable networking.
    812   net::ProxyConfig config;
    813   config.proxy_rules().ParseFromString("http=127.0.0.1:0");
    814   SetProxyConfig(profile->GetRequestContext(), config);
    815   // TODO(rsimha): Remove this line once http://crbug.com/53857 is fixed.
    816   net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
    817 }
    818 
    819 bool SyncTest::TestUsesSelfNotifications() {
    820   return true;
    821 }
    822 
    823 bool SyncTest::EnableEncryption(int index) {
    824   ProfileSyncService* service = GetClient(index)->service();
    825 
    826   if (::IsEncryptionComplete(service))
    827     return true;
    828 
    829   service->EnableEncryptEverything();
    830 
    831   // In order to kick off the encryption we have to reconfigure. Just grab the
    832   // currently synced types and use them.
    833   const syncer::ModelTypeSet synced_datatypes =
    834       service->GetPreferredDataTypes();
    835   bool sync_everything = synced_datatypes.Equals(syncer::ModelTypeSet::All());
    836   service->OnUserChoseDatatypes(sync_everything, synced_datatypes);
    837 
    838   // Wait some time to let the enryption finish.
    839   EncryptionChecker checker(service);
    840   checker.Wait();
    841 
    842   return !checker.TimedOut();
    843 }
    844 
    845 bool SyncTest::IsEncryptionComplete(int index) {
    846   return ::IsEncryptionComplete(GetClient(index)->service());
    847 }
    848 
    849 bool SyncTest::AwaitQuiescence() {
    850   return ProfileSyncServiceHarness::AwaitQuiescence(clients());
    851 }
    852 
    853 bool SyncTest::ServerSupportsNotificationControl() const {
    854   EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_);
    855 
    856   // Supported only if we're using the python testserver.
    857   return server_type_ == LOCAL_PYTHON_SERVER;
    858 }
    859 
    860 void SyncTest::DisableNotificationsImpl() {
    861   ASSERT_TRUE(ServerSupportsNotificationControl());
    862   std::string path = "chromiumsync/disablenotifications";
    863   ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
    864   ASSERT_EQ("Notifications disabled",
    865             base::UTF16ToASCII(
    866                 browser()->tab_strip_model()->GetActiveWebContents()->
    867                     GetTitle()));
    868 }
    869 
    870 void SyncTest::DisableNotifications() {
    871   DisableNotificationsImpl();
    872   notifications_enabled_ = false;
    873 }
    874 
    875 void SyncTest::EnableNotificationsImpl() {
    876   ASSERT_TRUE(ServerSupportsNotificationControl());
    877   std::string path = "chromiumsync/enablenotifications";
    878   ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
    879   ASSERT_EQ("Notifications enabled",
    880             base::UTF16ToASCII(
    881                 browser()->tab_strip_model()->GetActiveWebContents()->
    882                     GetTitle()));
    883 }
    884 
    885 void SyncTest::EnableNotifications() {
    886   EnableNotificationsImpl();
    887   notifications_enabled_ = true;
    888 }
    889 
    890 void SyncTest::TriggerNotification(syncer::ModelTypeSet changed_types) {
    891   ASSERT_TRUE(ServerSupportsNotificationControl());
    892   const std::string& data =
    893       syncer::P2PNotificationData(
    894           "from_server",
    895           syncer::NOTIFY_ALL,
    896           syncer::ObjectIdInvalidationMap::InvalidateAll(
    897               syncer::ModelTypeSetToObjectIdSet(changed_types))).ToString();
    898   const std::string& path =
    899       std::string("chromiumsync/sendnotification?channel=") +
    900       syncer::kSyncP2PNotificationChannel + "&data=" + data;
    901   ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
    902   ASSERT_EQ("Notification sent",
    903             base::UTF16ToASCII(
    904                 browser()->tab_strip_model()->GetActiveWebContents()->
    905                     GetTitle()));
    906 }
    907 
    908 bool SyncTest::ServerSupportsErrorTriggering() const {
    909   EXPECT_NE(SERVER_TYPE_UNDECIDED, server_type_);
    910 
    911   // Supported only if we're using the python testserver.
    912   return server_type_ == LOCAL_PYTHON_SERVER;
    913 }
    914 
    915 void SyncTest::TriggerMigrationDoneError(syncer::ModelTypeSet model_types) {
    916   ASSERT_TRUE(ServerSupportsErrorTriggering());
    917   std::string path = "chromiumsync/migrate";
    918   char joiner = '?';
    919   for (syncer::ModelTypeSet::Iterator it = model_types.First();
    920        it.Good(); it.Inc()) {
    921     path.append(
    922         base::StringPrintf(
    923             "%ctype=%d", joiner,
    924             syncer::GetSpecificsFieldNumberFromModelType(it.Get())));
    925     joiner = '&';
    926   }
    927   ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
    928   ASSERT_EQ("Migration: 200",
    929             base::UTF16ToASCII(
    930                 browser()->tab_strip_model()->GetActiveWebContents()->
    931                     GetTitle()));
    932 }
    933 
    934 void SyncTest::TriggerTransientError() {
    935   ASSERT_TRUE(ServerSupportsErrorTriggering());
    936   std::string path = "chromiumsync/transienterror";
    937   ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
    938   ASSERT_EQ("Transient error",
    939             base::UTF16ToASCII(
    940                 browser()->tab_strip_model()->GetActiveWebContents()->
    941                     GetTitle()));
    942 }
    943 
    944 void SyncTest::TriggerXmppAuthError() {
    945   ASSERT_TRUE(ServerSupportsErrorTriggering());
    946   std::string path = "chromiumsync/xmppcred";
    947   ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
    948 }
    949 
    950 namespace {
    951 
    952 sync_pb::SyncEnums::ErrorType
    953     GetClientToServerResponseErrorType(
    954         syncer::SyncProtocolErrorType error) {
    955   switch (error) {
    956     case syncer::SYNC_SUCCESS:
    957       return sync_pb::SyncEnums::SUCCESS;
    958     case syncer::NOT_MY_BIRTHDAY:
    959       return sync_pb::SyncEnums::NOT_MY_BIRTHDAY;
    960     case syncer::THROTTLED:
    961       return sync_pb::SyncEnums::THROTTLED;
    962     case syncer::CLEAR_PENDING:
    963       return sync_pb::SyncEnums::CLEAR_PENDING;
    964     case syncer::TRANSIENT_ERROR:
    965       return sync_pb::SyncEnums::TRANSIENT_ERROR;
    966     case syncer::MIGRATION_DONE:
    967       return sync_pb::SyncEnums::MIGRATION_DONE;
    968     case syncer::UNKNOWN_ERROR:
    969       return sync_pb::SyncEnums::UNKNOWN;
    970     case syncer::INVALID_CREDENTIAL:
    971       NOTREACHED();   // NOTREACHED() because auth error is not set through
    972                       // error code in sync response.
    973       return sync_pb::SyncEnums::UNKNOWN;
    974     case syncer::DISABLED_BY_ADMIN:
    975       return sync_pb::SyncEnums::DISABLED_BY_ADMIN;
    976     case syncer::USER_ROLLBACK:
    977       return sync_pb::SyncEnums::USER_ROLLBACK;
    978     case syncer::NON_RETRIABLE_ERROR:
    979       return sync_pb::SyncEnums::UNKNOWN;
    980   }
    981   return sync_pb::SyncEnums::UNKNOWN;
    982 }
    983 
    984 sync_pb::SyncEnums::Action GetClientToServerResponseAction(
    985     const syncer::ClientAction& action) {
    986   switch (action) {
    987     case syncer::UPGRADE_CLIENT:
    988       return sync_pb::SyncEnums::UPGRADE_CLIENT;
    989     case syncer::CLEAR_USER_DATA_AND_RESYNC:
    990       return sync_pb::SyncEnums::CLEAR_USER_DATA_AND_RESYNC;
    991     case syncer::ENABLE_SYNC_ON_ACCOUNT:
    992       return sync_pb::SyncEnums::ENABLE_SYNC_ON_ACCOUNT;
    993     case syncer::STOP_AND_RESTART_SYNC:
    994       return sync_pb::SyncEnums::STOP_AND_RESTART_SYNC;
    995     case syncer::DISABLE_SYNC_ON_CLIENT:
    996       return sync_pb::SyncEnums::DISABLE_SYNC_ON_CLIENT;
    997     case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT:
    998     case syncer::DISABLE_SYNC_AND_ROLLBACK:
    999     case syncer::ROLLBACK_DONE:
   1000       NOTREACHED();   // No corresponding proto action for these. Shouldn't
   1001                       // test.
   1002       return sync_pb::SyncEnums::UNKNOWN_ACTION;
   1003     case syncer::UNKNOWN_ACTION:
   1004       return sync_pb::SyncEnums::UNKNOWN_ACTION;
   1005   }
   1006   return sync_pb::SyncEnums::UNKNOWN_ACTION;
   1007 }
   1008 
   1009 }  // namespace
   1010 
   1011 void SyncTest::TriggerSyncError(const syncer::SyncProtocolError& error,
   1012                                 SyncErrorFrequency frequency) {
   1013   ASSERT_TRUE(ServerSupportsErrorTriggering());
   1014   std::string path = "chromiumsync/error";
   1015   int error_type =
   1016       static_cast<int>(GetClientToServerResponseErrorType(
   1017           error.error_type));
   1018   int action = static_cast<int>(GetClientToServerResponseAction(
   1019       error.action));
   1020 
   1021   path.append(base::StringPrintf("?error=%d", error_type));
   1022   path.append(base::StringPrintf("&action=%d", action));
   1023 
   1024   path.append(base::StringPrintf("&error_description=%s",
   1025                                  error.error_description.c_str()));
   1026   path.append(base::StringPrintf("&url=%s", error.url.c_str()));
   1027   path.append(base::StringPrintf("&frequency=%d", frequency));
   1028 
   1029   ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
   1030   std::string output = base::UTF16ToASCII(
   1031       browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
   1032   ASSERT_TRUE(output.find("SetError: 200") != base::string16::npos);
   1033 }
   1034 
   1035 void SyncTest::TriggerCreateSyncedBookmarks() {
   1036   ASSERT_TRUE(ServerSupportsErrorTriggering());
   1037   std::string path = "chromiumsync/createsyncedbookmarks";
   1038   ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
   1039   ASSERT_EQ("Synced Bookmarks",
   1040             base::UTF16ToASCII(
   1041                 browser()->tab_strip_model()->GetActiveWebContents()->
   1042                     GetTitle()));
   1043 }
   1044 
   1045 void SyncTest::SetProxyConfig(net::URLRequestContextGetter* context_getter,
   1046                               const net::ProxyConfig& proxy_config) {
   1047   base::WaitableEvent done(false, false);
   1048   BrowserThread::PostTask(
   1049       BrowserThread::IO, FROM_HERE,
   1050       base::Bind(&SetProxyConfigCallback, &done,
   1051                  make_scoped_refptr(context_getter), proxy_config));
   1052   done.Wait();
   1053 }
   1054 
   1055 fake_server::FakeServer* SyncTest::GetFakeServer() const {
   1056   return fake_server_.get();
   1057 }
   1058