|  | // Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "remoting/test/app_remoting_test_driver_environment.h" | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | #include "base/files/file_path.h" | 
|  | #include "remoting/test/fake_access_token_fetcher.h" | 
|  | #include "remoting/test/fake_app_remoting_report_issue_request.h" | 
|  | #include "remoting/test/fake_refresh_token_store.h" | 
|  | #include "remoting/test/fake_remote_host_info_fetcher.h" | 
|  | #include "remoting/test/mock_access_token_fetcher.h" | 
|  | #include "remoting/test/refresh_token_store.h" | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace { | 
|  | const char kAuthCodeValue[] = "4/892379827345jkefvkdfbv"; | 
|  | const char kUserNameValue[] = "remoting_user@gmail.com"; | 
|  | const char kTestApplicationId[] = "sadlkjlsjgadjfgoajdfgagb"; | 
|  | const char kAnotherTestApplicationId[] = "waklgoisdhfnvjkdsfbljn"; | 
|  | const char kTestHostId1[] = "awesome_test_host_id"; | 
|  | const char kTestHostId2[] = "super_awesome_test_host_id"; | 
|  | const char kTestHostId3[] = "uber_awesome_test_host_id"; | 
|  | } | 
|  |  | 
|  | namespace remoting { | 
|  | namespace test { | 
|  |  | 
|  | using testing::_; | 
|  |  | 
|  | class AppRemotingTestDriverEnvironmentTest : public ::testing::Test { | 
|  | public: | 
|  | AppRemotingTestDriverEnvironmentTest(); | 
|  | ~AppRemotingTestDriverEnvironmentTest() override; | 
|  |  | 
|  | FakeAccessTokenFetcher* fake_access_token_fetcher() const { | 
|  | return fake_access_token_fetcher_; | 
|  | } | 
|  |  | 
|  | protected: | 
|  | void Initialize(); | 
|  | void Initialize( | 
|  | const AppRemotingTestDriverEnvironment::EnvironmentOptions& options); | 
|  |  | 
|  | FakeAccessTokenFetcher* fake_access_token_fetcher_; | 
|  | FakeAppRemotingReportIssueRequest fake_report_issue_request_; | 
|  | FakeRefreshTokenStore fake_token_store_; | 
|  | FakeRemoteHostInfoFetcher fake_remote_host_info_fetcher_; | 
|  | MockAccessTokenFetcher mock_access_token_fetcher_; | 
|  |  | 
|  | scoped_ptr<AppRemotingTestDriverEnvironment> environment_object_; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(AppRemotingTestDriverEnvironmentTest); | 
|  | }; | 
|  |  | 
|  | AppRemotingTestDriverEnvironmentTest::AppRemotingTestDriverEnvironmentTest() | 
|  | : fake_access_token_fetcher_(nullptr) { | 
|  | } | 
|  |  | 
|  | AppRemotingTestDriverEnvironmentTest::~AppRemotingTestDriverEnvironmentTest() { | 
|  | } | 
|  |  | 
|  | void AppRemotingTestDriverEnvironmentTest::Initialize() { | 
|  | AppRemotingTestDriverEnvironment::EnvironmentOptions options; | 
|  | options.user_name = kUserNameValue; | 
|  | options.service_environment = kDeveloperEnvironment; | 
|  |  | 
|  | Initialize(options); | 
|  | } | 
|  |  | 
|  | void AppRemotingTestDriverEnvironmentTest::Initialize( | 
|  | const AppRemotingTestDriverEnvironment::EnvironmentOptions& options) { | 
|  | environment_object_.reset(new AppRemotingTestDriverEnvironment(options)); | 
|  |  | 
|  | scoped_ptr<FakeAccessTokenFetcher> fake_access_token_fetcher( | 
|  | new FakeAccessTokenFetcher()); | 
|  | fake_access_token_fetcher_ = fake_access_token_fetcher.get(); | 
|  | mock_access_token_fetcher_.SetAccessTokenFetcher( | 
|  | fake_access_token_fetcher.Pass()); | 
|  |  | 
|  | environment_object_->SetAccessTokenFetcherForTest( | 
|  | &mock_access_token_fetcher_); | 
|  | environment_object_->SetAppRemotingReportIssueRequestForTest( | 
|  | &fake_report_issue_request_); | 
|  | environment_object_->SetRefreshTokenStoreForTest(&fake_token_store_); | 
|  | environment_object_->SetRemoteHostInfoFetcherForTest( | 
|  | &fake_remote_host_info_fetcher_); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, InitializeObjectWithAuthCode) { | 
|  | Initialize(); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _)); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _)) | 
|  | .Times(0); | 
|  |  | 
|  | EXPECT_TRUE(environment_object_->Initialize(kAuthCodeValue)); | 
|  | EXPECT_TRUE(fake_token_store_.refresh_token_write_attempted()); | 
|  | EXPECT_EQ(fake_token_store_.stored_refresh_token_value(), | 
|  | kFakeAccessTokenFetcherRefreshTokenValue); | 
|  | EXPECT_EQ(environment_object_->user_name(), kUserNameValue); | 
|  | EXPECT_EQ(environment_object_->access_token(), | 
|  | kFakeAccessTokenFetcherAccessTokenValue); | 
|  |  | 
|  | // Attempt to init again, we should not see any additional calls or errors. | 
|  | EXPECT_TRUE(environment_object_->Initialize(kAuthCodeValue)); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, | 
|  | InitializeObjectWithAuthCodeFailed) { | 
|  | Initialize(); | 
|  |  | 
|  | fake_access_token_fetcher()->set_fail_access_token_from_auth_code(true); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _)); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _)) | 
|  | .Times(0); | 
|  |  | 
|  | EXPECT_FALSE(environment_object_->Initialize(kAuthCodeValue)); | 
|  | EXPECT_FALSE(fake_token_store_.refresh_token_write_attempted()); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, InitializeObjectWithRefreshToken) { | 
|  | Initialize(); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _)); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _)) | 
|  | .Times(0); | 
|  |  | 
|  | // Pass in an empty auth code since we are using a refresh token. | 
|  | EXPECT_TRUE(environment_object_->Initialize(std::string())); | 
|  |  | 
|  | // We should not write the refresh token a second time if we read from the | 
|  | // disk originally. | 
|  | EXPECT_FALSE(fake_token_store_.refresh_token_write_attempted()); | 
|  |  | 
|  | // Verify the object was initialized correctly. | 
|  | EXPECT_EQ(environment_object_->user_name(), kUserNameValue); | 
|  | EXPECT_EQ(environment_object_->access_token(), | 
|  | kFakeAccessTokenFetcherAccessTokenValue); | 
|  |  | 
|  | // Attempt to init again, we should not see any additional calls or errors. | 
|  | EXPECT_TRUE(environment_object_->Initialize(std::string())); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, TearDownAfterInitializeSucceeds) { | 
|  | Initialize(); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _)); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _)) | 
|  | .Times(0); | 
|  |  | 
|  | // Pass in an empty auth code since we are using a refresh token. | 
|  | EXPECT_TRUE(environment_object_->Initialize(std::string())); | 
|  |  | 
|  | // Note: We are using a static cast here because the TearDown() method is | 
|  | //       private as it is an interface method that we only want to call | 
|  | //       directly in tests or by the GTEST framework. | 
|  | static_cast<testing::Environment*>(environment_object_.get())->TearDown(); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, | 
|  | InitializeObjectWithRefreshTokenFailed) { | 
|  | Initialize(); | 
|  |  | 
|  | fake_access_token_fetcher()->set_fail_access_token_from_refresh_token(true); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _)); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _)) | 
|  | .Times(0); | 
|  |  | 
|  | // Pass in an empty auth code since we are using a refresh token. | 
|  | EXPECT_FALSE(environment_object_->Initialize(std::string())); | 
|  | EXPECT_FALSE(fake_token_store_.refresh_token_write_attempted()); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, | 
|  | InitializeObjectNoAuthCodeOrRefreshToken) { | 
|  | Initialize(); | 
|  |  | 
|  | // Neither method should be called in this scenario. | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _)) | 
|  | .Times(0); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _)) | 
|  | .Times(0); | 
|  |  | 
|  | // Clear out the 'stored' refresh token value. | 
|  | fake_token_store_.set_refresh_token_value(std::string()); | 
|  |  | 
|  | // With no auth code or refresh token, then the initialization should fail. | 
|  | EXPECT_FALSE(environment_object_->Initialize(std::string())); | 
|  | EXPECT_FALSE(fake_token_store_.refresh_token_write_attempted()); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, | 
|  | InitializeObjectWithAuthCodeWriteFailed) { | 
|  | Initialize(); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _)); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromRefreshToken(_, _)) | 
|  | .Times(0); | 
|  |  | 
|  | // Simulate a failure writing the token to the disk. | 
|  | fake_token_store_.set_refresh_token_write_succeeded(false); | 
|  |  | 
|  | EXPECT_FALSE(environment_object_->Initialize(kAuthCodeValue)); | 
|  | EXPECT_TRUE(fake_token_store_.refresh_token_write_attempted()); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, | 
|  | RefreshAccessTokenAfterUsingAuthCode) { | 
|  | Initialize(); | 
|  |  | 
|  | { | 
|  | testing::InSequence call_sequence; | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _)); | 
|  |  | 
|  | EXPECT_CALL(mock_access_token_fetcher_, | 
|  | GetAccessTokenFromRefreshToken(_, _)); | 
|  | } | 
|  |  | 
|  | EXPECT_TRUE(environment_object_->Initialize(kAuthCodeValue)); | 
|  | EXPECT_TRUE(fake_token_store_.refresh_token_write_attempted()); | 
|  | EXPECT_EQ(fake_token_store_.stored_refresh_token_value(), | 
|  | kFakeAccessTokenFetcherRefreshTokenValue); | 
|  | EXPECT_EQ(environment_object_->user_name(), kUserNameValue); | 
|  | EXPECT_EQ(environment_object_->access_token(), | 
|  | kFakeAccessTokenFetcherAccessTokenValue); | 
|  |  | 
|  | // Attempt to init again, we should not see any additional calls or errors. | 
|  | EXPECT_TRUE(environment_object_->RefreshAccessToken()); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, RefreshAccessTokenFailure) { | 
|  | Initialize(); | 
|  |  | 
|  | { | 
|  | testing::InSequence call_sequence; | 
|  |  | 
|  | // Mock is set up for this call to succeed. | 
|  | EXPECT_CALL(mock_access_token_fetcher_, GetAccessTokenFromAuthCode(_, _)); | 
|  |  | 
|  | // Mock is set up for this call to fail. | 
|  | EXPECT_CALL(mock_access_token_fetcher_, | 
|  | GetAccessTokenFromRefreshToken(_, _)); | 
|  | } | 
|  |  | 
|  | EXPECT_TRUE(environment_object_->Initialize(kAuthCodeValue)); | 
|  | EXPECT_TRUE(fake_token_store_.refresh_token_write_attempted()); | 
|  | EXPECT_EQ(fake_token_store_.stored_refresh_token_value(), | 
|  | kFakeAccessTokenFetcherRefreshTokenValue); | 
|  | EXPECT_EQ(environment_object_->user_name(), kUserNameValue); | 
|  | EXPECT_EQ(environment_object_->access_token(), | 
|  | kFakeAccessTokenFetcherAccessTokenValue); | 
|  |  | 
|  | fake_access_token_fetcher()->set_fail_access_token_from_refresh_token(true); | 
|  |  | 
|  | // We expect the refresh to have failed, the user name to remain valid, | 
|  | // and the access token to have been cleared. | 
|  | EXPECT_FALSE(environment_object_->RefreshAccessToken()); | 
|  | EXPECT_TRUE(environment_object_->access_token().empty()); | 
|  | EXPECT_EQ(environment_object_->user_name(), kUserNameValue); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, GetRemoteHostInfoSuccess) { | 
|  | Initialize(); | 
|  |  | 
|  | // Pass in an empty auth code since we are using a refresh token. | 
|  | EXPECT_TRUE(environment_object_->Initialize(std::string())); | 
|  |  | 
|  | RemoteHostInfo remote_host_info; | 
|  | EXPECT_TRUE(environment_object_->GetRemoteHostInfoForApplicationId( | 
|  | kTestApplicationId, &remote_host_info)); | 
|  | EXPECT_TRUE(remote_host_info.IsReadyForConnection()); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, GetRemoteHostInfoFailure) { | 
|  | Initialize(); | 
|  |  | 
|  | // Pass in an empty auth code since we are using a refresh token. | 
|  | EXPECT_TRUE(environment_object_->Initialize(std::string())); | 
|  |  | 
|  | fake_remote_host_info_fetcher_.set_fail_retrieve_remote_host_info(true); | 
|  |  | 
|  | RemoteHostInfo remote_host_info; | 
|  | EXPECT_FALSE(environment_object_->GetRemoteHostInfoForApplicationId( | 
|  | kTestApplicationId, &remote_host_info)); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, | 
|  | GetRemoteHostInfoWithoutInitializing) { | 
|  | Initialize(); | 
|  |  | 
|  | RemoteHostInfo remote_host_info; | 
|  | EXPECT_FALSE(environment_object_->GetRemoteHostInfoForApplicationId( | 
|  | kTestApplicationId, &remote_host_info)); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, NoRemoteHostsReleasedOnTearDown) { | 
|  | // Use the default options as the flag to release the remote hosts is not | 
|  | // enabled by default. | 
|  | Initialize(); | 
|  |  | 
|  | // Pass in an empty auth code since we are using a refresh token. | 
|  | EXPECT_TRUE(environment_object_->Initialize(std::string())); | 
|  |  | 
|  | RemoteHostInfo remote_host_info; | 
|  | EXPECT_TRUE(environment_object_->GetRemoteHostInfoForApplicationId( | 
|  | kTestApplicationId, &remote_host_info)); | 
|  | EXPECT_TRUE(remote_host_info.IsReadyForConnection()); | 
|  |  | 
|  | EXPECT_EQ(fake_report_issue_request_.get_host_ids_released().size(), 0UL); | 
|  |  | 
|  | environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId1); | 
|  |  | 
|  | // Note: We are using a static cast here because the TearDown() method is | 
|  | //       private as it is an interface method that we only want to call | 
|  | //       directly in tests or by the GTEST framework. | 
|  | static_cast<testing::Environment*>(environment_object_.get())->TearDown(); | 
|  |  | 
|  | // Verify no hosts were released via a report issue request. | 
|  | EXPECT_EQ(fake_report_issue_request_.get_host_ids_released().size(), 0UL); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, OneRemoteHostReleasedOnTearDown) { | 
|  | AppRemotingTestDriverEnvironment::EnvironmentOptions options; | 
|  | options.user_name = kUserNameValue; | 
|  | options.release_hosts_when_done = true; | 
|  | options.service_environment = kDeveloperEnvironment; | 
|  | Initialize(options); | 
|  |  | 
|  | // Pass in an empty auth code since we are using a refresh token. | 
|  | EXPECT_TRUE(environment_object_->Initialize(std::string())); | 
|  |  | 
|  | RemoteHostInfo remote_host_info; | 
|  | EXPECT_TRUE(environment_object_->GetRemoteHostInfoForApplicationId( | 
|  | kTestApplicationId, &remote_host_info)); | 
|  | EXPECT_TRUE(remote_host_info.IsReadyForConnection()); | 
|  |  | 
|  | EXPECT_EQ(fake_report_issue_request_.get_host_ids_released().size(), 0UL); | 
|  |  | 
|  | environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId1); | 
|  |  | 
|  | // Note: We are using a static cast here because the TearDown() method is | 
|  | //       private as it is an interface method that we only want to call | 
|  | //       directly in tests or by the GTEST framework. | 
|  | static_cast<testing::Environment*>(environment_object_.get())->TearDown(); | 
|  |  | 
|  | std::string expected_host( | 
|  | MakeFormattedStringForReleasedHost(kTestApplicationId, kTestHostId1)); | 
|  | std::vector<std::string> actual_host_list = | 
|  | fake_report_issue_request_.get_host_ids_released(); | 
|  |  | 
|  | EXPECT_EQ(actual_host_list.size(), 1UL); | 
|  | EXPECT_EQ(actual_host_list[0], expected_host); | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, RemoteHostsReleasedOnTearDown) { | 
|  | AppRemotingTestDriverEnvironment::EnvironmentOptions options; | 
|  | options.user_name = kUserNameValue; | 
|  | options.release_hosts_when_done = true; | 
|  | options.service_environment = kDeveloperEnvironment; | 
|  | Initialize(options); | 
|  |  | 
|  | // Pass in an empty auth code since we are using a refresh token. | 
|  | EXPECT_TRUE(environment_object_->Initialize(std::string())); | 
|  |  | 
|  | RemoteHostInfo remote_host_info; | 
|  | EXPECT_TRUE(environment_object_->GetRemoteHostInfoForApplicationId( | 
|  | kTestApplicationId, &remote_host_info)); | 
|  | EXPECT_TRUE(remote_host_info.IsReadyForConnection()); | 
|  |  | 
|  | std::vector<std::string> expected_host_list; | 
|  | environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId1); | 
|  | expected_host_list.push_back( | 
|  | MakeFormattedStringForReleasedHost(kTestApplicationId, kTestHostId1)); | 
|  |  | 
|  | environment_object_->AddHostToReleaseList(kAnotherTestApplicationId, | 
|  | kTestHostId2); | 
|  | expected_host_list.push_back(MakeFormattedStringForReleasedHost( | 
|  | kAnotherTestApplicationId, kTestHostId2)); | 
|  |  | 
|  | environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId3); | 
|  | expected_host_list.push_back( | 
|  | MakeFormattedStringForReleasedHost(kTestApplicationId, kTestHostId3)); | 
|  |  | 
|  | // Note: We are using a static cast here because the TearDown() method is | 
|  | //       private as it is an interface method that we only want to call | 
|  | //       directly in tests or by the GTEST framework. | 
|  | static_cast<testing::Environment*>(environment_object_.get())->TearDown(); | 
|  |  | 
|  | std::vector<std::string> actual_host_list = | 
|  | fake_report_issue_request_.get_host_ids_released(); | 
|  |  | 
|  | std::sort(actual_host_list.begin(), actual_host_list.end()); | 
|  | std::sort(expected_host_list.begin(), expected_host_list.end()); | 
|  |  | 
|  | EXPECT_EQ(actual_host_list.size(), expected_host_list.size()); | 
|  | for (size_t i = 0; i < actual_host_list.size(); ++i) { | 
|  | EXPECT_EQ(actual_host_list[i], expected_host_list[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(AppRemotingTestDriverEnvironmentTest, RemoteHostsReleasedOnce) { | 
|  | AppRemotingTestDriverEnvironment::EnvironmentOptions options; | 
|  | options.user_name = kUserNameValue; | 
|  | options.release_hosts_when_done = true; | 
|  | options.service_environment = kDeveloperEnvironment; | 
|  | Initialize(options); | 
|  |  | 
|  | // Pass in an empty auth code since we are using a refresh token. | 
|  | EXPECT_TRUE(environment_object_->Initialize(std::string())); | 
|  |  | 
|  | RemoteHostInfo remote_host_info; | 
|  | EXPECT_TRUE(environment_object_->GetRemoteHostInfoForApplicationId( | 
|  | kTestApplicationId, &remote_host_info)); | 
|  | EXPECT_TRUE(remote_host_info.IsReadyForConnection()); | 
|  |  | 
|  | std::vector<std::string> expected_host_list; | 
|  | environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId1); | 
|  | expected_host_list.push_back( | 
|  | MakeFormattedStringForReleasedHost(kTestApplicationId, kTestHostId1)); | 
|  |  | 
|  | environment_object_->AddHostToReleaseList(kAnotherTestApplicationId, | 
|  | kTestHostId2); | 
|  | expected_host_list.push_back(MakeFormattedStringForReleasedHost( | 
|  | kAnotherTestApplicationId, kTestHostId2)); | 
|  |  | 
|  | environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId3); | 
|  | expected_host_list.push_back( | 
|  | MakeFormattedStringForReleasedHost(kTestApplicationId, kTestHostId3)); | 
|  |  | 
|  | // Attempt to add the previous hosts again, they should not be added since | 
|  | // they will already exist in the list of hosts to release. | 
|  | environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId1); | 
|  | environment_object_->AddHostToReleaseList(kAnotherTestApplicationId, | 
|  | kTestHostId2); | 
|  | environment_object_->AddHostToReleaseList(kTestApplicationId, kTestHostId3); | 
|  |  | 
|  | // Note: We are using a static cast here because the TearDown() method is | 
|  | //       private as it is an interface method that we only want to call | 
|  | //       directly in tests or by the GTEST framework. | 
|  | static_cast<testing::Environment*>(environment_object_.get())->TearDown(); | 
|  |  | 
|  | std::vector<std::string> actual_host_list = | 
|  | fake_report_issue_request_.get_host_ids_released(); | 
|  |  | 
|  | std::sort(actual_host_list.begin(), actual_host_list.end()); | 
|  | std::sort(expected_host_list.begin(), expected_host_list.end()); | 
|  |  | 
|  | EXPECT_EQ(actual_host_list.size(), expected_host_list.size()); | 
|  | for (size_t i = 0; i < actual_host_list.size(); ++i) { | 
|  | EXPECT_EQ(actual_host_list[i], expected_host_list[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace remoting |