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/refresh_token_store.h"
19 #include "remoting/test/remote_host_info.h"
24 AppRemotingTestDriverEnvironment
* AppRemotingSharedData
;
26 AppRemotingTestDriverEnvironment::AppRemotingTestDriverEnvironment(
27 const std::string
& user_name
,
28 ServiceEnvironment service_environment
)
29 : user_name_(user_name
),
30 service_environment_(service_environment
),
31 test_access_token_fetcher_(nullptr),
32 test_refresh_token_store_(nullptr),
33 test_remote_host_info_fetcher_(nullptr),
34 message_loop_(new base::MessageLoopForIO()) {
35 DCHECK(!user_name_
.empty());
36 DCHECK(service_environment
< kUnknownEnvironment
);
38 PopulateApplicationNames();
39 PopulateApplicationDetailsMap();
42 AppRemotingTestDriverEnvironment::~AppRemotingTestDriverEnvironment() {
45 bool AppRemotingTestDriverEnvironment::Initialize(
46 const std::string
& auth_code
) {
47 if (!access_token_
.empty()) {
51 // If a unit test has set |test_refresh_token_store_| then we should use it
52 // below. Note that we do not want to destroy the test object.
53 scoped_ptr
<RefreshTokenStore
> temporary_refresh_token_store
;
54 RefreshTokenStore
* refresh_token_store
= test_refresh_token_store_
;
55 if (!refresh_token_store
) {
56 temporary_refresh_token_store
= RefreshTokenStore::OnDisk(user_name_
);
57 refresh_token_store
= temporary_refresh_token_store
.get();
60 // Check to see if we have a refresh token stored for this user.
61 refresh_token_
= refresh_token_store
->FetchRefreshToken();
62 if (refresh_token_
.empty()) {
63 // This isn't necessarily an error as this might be a first run scenario.
64 DVLOG(1) << "No refresh token stored for " << user_name_
;
66 if (auth_code
.empty()) {
67 // No token and no Auth code means no service connectivity, bail!
68 LOG(ERROR
) << "Cannot retrieve an access token without a stored refresh"
69 << " token on disk or an auth_code passed into the tool";
74 if (!RetrieveAccessToken(auth_code
)) {
75 // If we cannot retrieve an access token, then nothing is going to work and
76 // we should let the caller know that our object is not ready to be used.
83 bool AppRemotingTestDriverEnvironment::RefreshAccessToken() {
84 DCHECK(!refresh_token_
.empty());
86 // Empty auth code is used when refreshing.
87 return RetrieveAccessToken(std::string());
90 bool AppRemotingTestDriverEnvironment::GetRemoteHostInfoForApplicationId(
91 const std::string
& application_id
,
92 RemoteHostInfo
* remote_host_info
) {
93 DCHECK(!application_id
.empty());
94 DCHECK(remote_host_info
);
96 if (access_token_
.empty()) {
97 LOG(ERROR
) << "RemoteHostInfo requested without a valid access token. "
98 << "Ensure the environment object has been initialized.";
102 base::RunLoop run_loop
;
104 RemoteHostInfoCallback remote_host_info_fetch_callback
= base::Bind(
105 &AppRemotingTestDriverEnvironment::OnRemoteHostInfoRetrieved
,
106 base::Unretained(this), run_loop
.QuitClosure(), remote_host_info
);
108 // If a unit test has set |test_remote_host_info_fetcher_| then we should use
109 // it below. Note that we do not want to destroy the test object at the end
110 // of the function which is why we have the dance below.
111 scoped_ptr
<RemoteHostInfoFetcher
> temporary_remote_host_info_fetcher
;
112 RemoteHostInfoFetcher
* remote_host_info_fetcher
=
113 test_remote_host_info_fetcher_
;
114 if (!remote_host_info_fetcher
) {
115 temporary_remote_host_info_fetcher
.reset(new RemoteHostInfoFetcher());
116 remote_host_info_fetcher
= temporary_remote_host_info_fetcher
.get();
119 remote_host_info_fetcher
->RetrieveRemoteHostInfo(
120 application_id
, access_token_
, service_environment_
,
121 remote_host_info_fetch_callback
);
125 return remote_host_info
->IsReadyForConnection();
128 void AppRemotingTestDriverEnvironment::ShowHostAvailability() {
129 const char kHostAvailabilityFormatString
[] = "%-25s%-35s%-10s";
131 LOG(INFO
) << base::StringPrintf(kHostAvailabilityFormatString
,
132 "Application Name", "Application ID",
135 for (const auto& application_name
: application_names_
) {
136 const RemoteApplicationDetails
& application_details
=
137 GetDetailsFromAppName(application_name
);
139 RemoteHostInfo remote_host_info
;
140 GetRemoteHostInfoForApplicationId(application_details
.application_id
,
144 RemoteHostStatus remote_host_status
= remote_host_info
.remote_host_status
;
145 if (remote_host_status
== kRemoteHostStatusReady
) {
147 } else if (remote_host_status
== kRemoteHostStatusPending
) {
148 status
= "Pending :|";
150 status
= "Unknown :(";
153 LOG(INFO
) << base::StringPrintf(
154 kHostAvailabilityFormatString
, application_name
.c_str(),
155 application_details
.application_id
.c_str(), status
.c_str());
159 const RemoteApplicationDetails
&
160 AppRemotingTestDriverEnvironment::GetDetailsFromAppName(
161 const std::string
& application_name
) {
162 const auto map_pair_iterator
=
163 application_details_map_
.find(application_name
);
164 DCHECK(map_pair_iterator
!= application_details_map_
.end());
166 return map_pair_iterator
->second
;
169 void AppRemotingTestDriverEnvironment::SetAccessTokenFetcherForTest(
170 AccessTokenFetcher
* access_token_fetcher
) {
171 DCHECK(access_token_fetcher
);
173 test_access_token_fetcher_
= access_token_fetcher
;
176 void AppRemotingTestDriverEnvironment::SetRefreshTokenStoreForTest(
177 RefreshTokenStore
* refresh_token_store
) {
178 DCHECK(refresh_token_store
);
180 test_refresh_token_store_
= refresh_token_store
;
183 void AppRemotingTestDriverEnvironment::SetRemoteHostInfoFetcherForTest(
184 RemoteHostInfoFetcher
* remote_host_info_fetcher
) {
185 DCHECK(remote_host_info_fetcher
);
187 test_remote_host_info_fetcher_
= remote_host_info_fetcher
;
190 void AppRemotingTestDriverEnvironment::TearDown() {
191 // Letting the MessageLoop tear down during the test destructor results in
192 // errors after test completion, when the MessageLoop dtor touches the
193 // registered AtExitManager. The AtExitManager is torn down before the test
194 // destructor is executed, so we tear down the MessageLoop here, while it is
196 message_loop_
.reset();
199 bool AppRemotingTestDriverEnvironment::RetrieveAccessToken(
200 const std::string
& auth_code
) {
201 base::RunLoop run_loop
;
203 access_token_
.clear();
205 AccessTokenCallback access_token_callback
=
206 base::Bind(&AppRemotingTestDriverEnvironment::OnAccessTokenRetrieved
,
207 base::Unretained(this), run_loop
.QuitClosure());
209 // If a unit test has set |test_access_token_fetcher_| then we should use it
210 // below. Note that we do not want to destroy the test object at the end of
211 // the function which is why we have the dance below.
212 scoped_ptr
<AccessTokenFetcher
> temporary_access_token_fetcher
;
213 AccessTokenFetcher
* access_token_fetcher
= test_access_token_fetcher_
;
214 if (!access_token_fetcher
) {
215 temporary_access_token_fetcher
.reset(new AccessTokenFetcher());
216 access_token_fetcher
= temporary_access_token_fetcher
.get();
219 if (!auth_code
.empty()) {
220 // If the user passed in an authcode, then use it to retrieve an
221 // updated access/refresh token.
222 access_token_fetcher
->GetAccessTokenFromAuthCode(auth_code
,
223 access_token_callback
);
225 DCHECK(!refresh_token_
.empty());
227 access_token_fetcher
->GetAccessTokenFromRefreshToken(refresh_token_
,
228 access_token_callback
);
233 // If we were using an auth_code and received a valid refresh token,
234 // then we want to store it locally. If we had an auth code and did not
235 // receive a refresh token, then we should let the user know and exit.
236 if (!auth_code
.empty()) {
237 if (!refresh_token_
.empty()) {
238 // If a unit test has set |test_refresh_token_store_| then we should use
239 // it below. Note that we do not want to destroy the test object.
240 scoped_ptr
<RefreshTokenStore
> temporary_refresh_token_store
;
241 RefreshTokenStore
* refresh_token_store
= test_refresh_token_store_
;
242 if (!refresh_token_store
) {
243 temporary_refresh_token_store
= RefreshTokenStore::OnDisk(user_name_
);
244 refresh_token_store
= temporary_refresh_token_store
.get();
247 if (!refresh_token_store
->StoreRefreshToken(refresh_token_
)) {
248 // If we failed to persist the refresh token, then we should let the
249 // user sort out the issue before continuing.
253 LOG(ERROR
) << "Failed to use AUTH CODE to retrieve a refresh token.\n"
254 << "Was the one-time use AUTH CODE used more than once?";
259 if (access_token_
.empty()) {
260 LOG(ERROR
) << "Failed to retrieve access token.";
267 void AppRemotingTestDriverEnvironment::OnAccessTokenRetrieved(
268 base::Closure done_closure
,
269 const std::string
& access_token
,
270 const std::string
& refresh_token
) {
271 access_token_
= access_token
;
272 refresh_token_
= refresh_token
;
277 void AppRemotingTestDriverEnvironment::OnRemoteHostInfoRetrieved(
278 base::Closure done_closure
,
279 RemoteHostInfo
* remote_host_info
,
280 const RemoteHostInfo
& retrieved_remote_host_info
) {
281 DCHECK(remote_host_info
);
283 *remote_host_info
= retrieved_remote_host_info
;
289 } // namespace remoting