1 // Copyright 2015 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.
5 #include "remoting/test/app_remoting_test_driver_environment.h"
11 #include "base/bind.h"
12 #include "base/callback_forward.h"
13 #include "base/logging.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/run_loop.h"
16 #include "base/strings/stringprintf.h"
17 #include "remoting/test/access_token_fetcher.h"
18 #include "remoting/test/app_remoting_report_issue_request.h"
19 #include "remoting/test/refresh_token_store.h"
20 #include "remoting/test/remote_host_info.h"
25 AppRemotingTestDriverEnvironment
* AppRemotingSharedData
;
27 AppRemotingTestDriverEnvironment::EnvironmentOptions::EnvironmentOptions()
28 : refresh_token_file_path(base::FilePath()),
29 service_environment(kUnknownEnvironment
),
30 release_hosts_when_done(false) {
33 AppRemotingTestDriverEnvironment::EnvironmentOptions::~EnvironmentOptions() {
36 AppRemotingTestDriverEnvironment::AppRemotingTestDriverEnvironment(
37 const EnvironmentOptions
& options
)
38 : user_name_(options
.user_name
),
39 service_environment_(options
.service_environment
),
40 release_hosts_when_done_(options
.release_hosts_when_done
),
41 refresh_token_file_path_(options
.refresh_token_file_path
),
42 test_access_token_fetcher_(nullptr),
43 test_app_remoting_report_issue_request_(nullptr),
44 test_refresh_token_store_(nullptr),
45 test_remote_host_info_fetcher_(nullptr) {
46 DCHECK(!user_name_
.empty());
47 DCHECK(service_environment_
< kUnknownEnvironment
);
49 PopulateApplicationNames();
50 PopulateApplicationDetailsMap();
53 AppRemotingTestDriverEnvironment::~AppRemotingTestDriverEnvironment() {
56 bool AppRemotingTestDriverEnvironment::Initialize(
57 const std::string
& auth_code
) {
58 if (!access_token_
.empty()) {
62 if (!base::MessageLoop::current()) {
63 message_loop_
.reset(new base::MessageLoopForIO
);
66 // If a unit test has set |test_refresh_token_store_| then we should use it
67 // below. Note that we do not want to destroy the test object.
68 scoped_ptr
<RefreshTokenStore
> temporary_refresh_token_store
;
69 RefreshTokenStore
* refresh_token_store
= test_refresh_token_store_
;
70 if (!refresh_token_store
) {
71 temporary_refresh_token_store
=
72 RefreshTokenStore::OnDisk(user_name_
, refresh_token_file_path_
);
73 refresh_token_store
= temporary_refresh_token_store
.get();
76 // Check to see if we have a refresh token stored for this user.
77 refresh_token_
= refresh_token_store
->FetchRefreshToken();
78 if (refresh_token_
.empty()) {
79 // This isn't necessarily an error as this might be a first run scenario.
80 VLOG(2) << "No refresh token stored for " << user_name_
;
82 if (auth_code
.empty()) {
83 // No token and no Auth code means no service connectivity, bail!
84 LOG(ERROR
) << "Cannot retrieve an access token without a stored refresh"
85 << " token on disk or an auth_code passed into the tool";
90 if (!RetrieveAccessToken(auth_code
)) {
91 // If we cannot retrieve an access token, then nothing is going to work and
92 // we should let the caller know that our object is not ready to be used.
99 bool AppRemotingTestDriverEnvironment::RefreshAccessToken() {
100 DCHECK(!refresh_token_
.empty());
102 // Empty auth code is used when refreshing.
103 return RetrieveAccessToken(std::string());
106 bool AppRemotingTestDriverEnvironment::GetRemoteHostInfoForApplicationId(
107 const std::string
& application_id
,
108 RemoteHostInfo
* remote_host_info
) {
109 DCHECK(!application_id
.empty());
110 DCHECK(remote_host_info
);
112 if (access_token_
.empty()) {
113 LOG(ERROR
) << "RemoteHostInfo requested without a valid access token. "
114 << "Ensure the environment object has been initialized.";
118 base::RunLoop run_loop
;
120 RemoteHostInfoCallback remote_host_info_fetch_callback
= base::Bind(
121 &AppRemotingTestDriverEnvironment::OnRemoteHostInfoRetrieved
,
122 base::Unretained(this), run_loop
.QuitClosure(), remote_host_info
);
124 // If a unit test has set |test_remote_host_info_fetcher_| then we should use
125 // it below. Note that we do not want to destroy the test object at the end
126 // of the function which is why we have the dance below.
127 scoped_ptr
<RemoteHostInfoFetcher
> temporary_remote_host_info_fetcher
;
128 RemoteHostInfoFetcher
* remote_host_info_fetcher
=
129 test_remote_host_info_fetcher_
;
130 if (!remote_host_info_fetcher
) {
131 temporary_remote_host_info_fetcher
.reset(new RemoteHostInfoFetcher());
132 remote_host_info_fetcher
= temporary_remote_host_info_fetcher
.get();
135 remote_host_info_fetcher
->RetrieveRemoteHostInfo(
136 application_id
, access_token_
, service_environment_
,
137 remote_host_info_fetch_callback
);
141 return remote_host_info
->IsReadyForConnection();
144 void AppRemotingTestDriverEnvironment::AddHostToReleaseList(
145 const std::string
& application_id
,
146 const std::string
& host_id
) {
147 if (!release_hosts_when_done_
) {
151 auto map_iterator
= host_ids_to_release_
.find(application_id
);
152 if (map_iterator
== host_ids_to_release_
.end()) {
153 std::vector
<std::string
> host_id_list(1, host_id
);
154 host_ids_to_release_
.insert(std::make_pair(application_id
, host_id_list
));
156 std::vector
<std::string
>* host_ids
= &map_iterator
->second
;
157 if (std::find(host_ids
->begin(), host_ids
->end(), host_id
) ==
159 host_ids
->push_back(host_id
);
164 void AppRemotingTestDriverEnvironment::ShowHostAvailability() {
165 const char kHostAvailabilityFormatString
[] = "%-25s%-35s%-10s";
167 LOG(INFO
) << base::StringPrintf(kHostAvailabilityFormatString
,
168 "Application Name", "Application ID",
171 for (const auto& application_name
: application_names_
) {
172 const RemoteApplicationDetails
& application_details
=
173 GetDetailsFromAppName(application_name
);
175 RemoteHostInfo remote_host_info
;
176 GetRemoteHostInfoForApplicationId(application_details
.application_id
,
180 RemoteHostStatus remote_host_status
= remote_host_info
.remote_host_status
;
181 if (remote_host_status
== kRemoteHostStatusReady
) {
183 } else if (remote_host_status
== kRemoteHostStatusPending
) {
184 status
= "Pending :|";
186 status
= "Unknown :(";
189 LOG(INFO
) << base::StringPrintf(
190 kHostAvailabilityFormatString
, application_name
.c_str(),
191 application_details
.application_id
.c_str(), status
.c_str());
195 const RemoteApplicationDetails
&
196 AppRemotingTestDriverEnvironment::GetDetailsFromAppName(
197 const std::string
& application_name
) {
198 const auto map_pair_iterator
=
199 application_details_map_
.find(application_name
);
200 DCHECK(map_pair_iterator
!= application_details_map_
.end());
202 return map_pair_iterator
->second
;
205 void AppRemotingTestDriverEnvironment::SetAccessTokenFetcherForTest(
206 AccessTokenFetcher
* access_token_fetcher
) {
207 DCHECK(access_token_fetcher
);
209 test_access_token_fetcher_
= access_token_fetcher
;
212 void AppRemotingTestDriverEnvironment::SetAppRemotingReportIssueRequestForTest(
213 AppRemotingReportIssueRequest
* app_remoting_report_issue_request
) {
214 DCHECK(app_remoting_report_issue_request
);
216 test_app_remoting_report_issue_request_
= app_remoting_report_issue_request
;
219 void AppRemotingTestDriverEnvironment::SetRefreshTokenStoreForTest(
220 RefreshTokenStore
* refresh_token_store
) {
221 DCHECK(refresh_token_store
);
223 test_refresh_token_store_
= refresh_token_store
;
226 void AppRemotingTestDriverEnvironment::SetRemoteHostInfoFetcherForTest(
227 RemoteHostInfoFetcher
* remote_host_info_fetcher
) {
228 DCHECK(remote_host_info_fetcher
);
230 test_remote_host_info_fetcher_
= remote_host_info_fetcher
;
233 void AppRemotingTestDriverEnvironment::TearDown() {
234 // If a unit test has set |test_app_remoting_report_issue_request_| then we
235 // should use it below. Note that we do not want to destroy the test object
236 // at the end of the function which is why we have the dance below.
237 scoped_ptr
<AppRemotingReportIssueRequest
> temporary_report_issue_request
;
238 AppRemotingReportIssueRequest
* report_issue_request
=
239 test_app_remoting_report_issue_request_
;
240 if (!report_issue_request
) {
241 temporary_report_issue_request
.reset(new AppRemotingReportIssueRequest());
242 report_issue_request
= temporary_report_issue_request
.get();
245 for (const auto& kvp
: host_ids_to_release_
) {
246 std::string application_id
= kvp
.first
;
247 VLOG(1) << "Releasing hosts for application: " << application_id
;
249 for (const auto& host_id
: kvp
.second
) {
250 base::RunLoop run_loop
;
252 VLOG(1) << " Releasing host: " << host_id
;
253 bool request_started
= report_issue_request
->Start(
254 application_id
, host_id
, access_token_
, service_environment_
, true,
255 run_loop
.QuitClosure());
257 if (request_started
) {
260 LOG(ERROR
) << "Failed to send ReportIssueRequest for: "
261 << application_id
<< ", " << host_id
;
265 temporary_report_issue_request
.reset();
267 // Letting the MessageLoop tear down during the test destructor results in
268 // errors after test completion, when the MessageLoop dtor touches the
269 // registered AtExitManager. The AtExitManager is torn down before the test
270 // destructor is executed, so we tear down the MessageLoop here, while it is
272 message_loop_
.reset();
275 bool AppRemotingTestDriverEnvironment::RetrieveAccessToken(
276 const std::string
& auth_code
) {
277 base::RunLoop run_loop
;
279 access_token_
.clear();
281 AccessTokenCallback access_token_callback
=
282 base::Bind(&AppRemotingTestDriverEnvironment::OnAccessTokenRetrieved
,
283 base::Unretained(this), run_loop
.QuitClosure());
285 // If a unit test has set |test_access_token_fetcher_| then we should use it
286 // below. Note that we do not want to destroy the test object at the end of
287 // the function which is why we have the dance below.
288 scoped_ptr
<AccessTokenFetcher
> temporary_access_token_fetcher
;
289 AccessTokenFetcher
* access_token_fetcher
= test_access_token_fetcher_
;
290 if (!access_token_fetcher
) {
291 temporary_access_token_fetcher
.reset(new AccessTokenFetcher());
292 access_token_fetcher
= temporary_access_token_fetcher
.get();
295 if (!auth_code
.empty()) {
296 // If the user passed in an authcode, then use it to retrieve an
297 // updated access/refresh token.
298 access_token_fetcher
->GetAccessTokenFromAuthCode(auth_code
,
299 access_token_callback
);
301 DCHECK(!refresh_token_
.empty());
303 access_token_fetcher
->GetAccessTokenFromRefreshToken(refresh_token_
,
304 access_token_callback
);
309 // If we were using an auth_code and received a valid refresh token,
310 // then we want to store it locally. If we had an auth code and did not
311 // receive a refresh token, then we should let the user know and exit.
312 if (!auth_code
.empty()) {
313 if (!refresh_token_
.empty()) {
314 // If a unit test has set |test_refresh_token_store_| then we should use
315 // it below. Note that we do not want to destroy the test object.
316 scoped_ptr
<RefreshTokenStore
> temporary_refresh_token_store
;
317 RefreshTokenStore
* refresh_token_store
= test_refresh_token_store_
;
318 if (!refresh_token_store
) {
319 temporary_refresh_token_store
=
320 RefreshTokenStore::OnDisk(user_name_
, refresh_token_file_path_
);
321 refresh_token_store
= temporary_refresh_token_store
.get();
324 if (!refresh_token_store
->StoreRefreshToken(refresh_token_
)) {
325 // If we failed to persist the refresh token, then we should let the
326 // user sort out the issue before continuing.
330 LOG(ERROR
) << "Failed to use AUTH CODE to retrieve a refresh token.\n"
331 << "Was the one-time use AUTH CODE used more than once?";
336 if (access_token_
.empty()) {
337 LOG(ERROR
) << "Failed to retrieve access token.";
344 void AppRemotingTestDriverEnvironment::OnAccessTokenRetrieved(
345 base::Closure done_closure
,
346 const std::string
& access_token
,
347 const std::string
& refresh_token
) {
348 access_token_
= access_token
;
349 refresh_token_
= refresh_token
;
354 void AppRemotingTestDriverEnvironment::OnRemoteHostInfoRetrieved(
355 base::Closure done_closure
,
356 RemoteHostInfo
* remote_host_info
,
357 const RemoteHostInfo
& retrieved_remote_host_info
) {
358 DCHECK(remote_host_info
);
360 *remote_host_info
= retrieved_remote_host_info
;
366 } // namespace remoting