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 DCHECK(!user_name_
.empty());
35 DCHECK(service_environment
< kUnknownEnvironment
);
37 PopulateApplicationNames();
38 PopulateApplicationDetailsMap();
41 AppRemotingTestDriverEnvironment::~AppRemotingTestDriverEnvironment() {
44 bool AppRemotingTestDriverEnvironment::Initialize(
45 const std::string
& auth_code
) {
46 if (!access_token_
.empty()) {
50 // If a unit test has set |test_refresh_token_store_| then we should use it
51 // below. Note that we do not want to destroy the test object.
52 scoped_ptr
<RefreshTokenStore
> temporary_refresh_token_store
;
53 RefreshTokenStore
* refresh_token_store
= test_refresh_token_store_
;
54 if (!refresh_token_store
) {
55 temporary_refresh_token_store
= RefreshTokenStore::OnDisk(user_name_
);
56 refresh_token_store
= temporary_refresh_token_store
.get();
59 // Check to see if we have a refresh token stored for this user.
60 refresh_token_
= refresh_token_store
->FetchRefreshToken();
61 if (refresh_token_
.empty()) {
62 // This isn't necessarily an error as this might be a first run scenario.
63 DVLOG(1) << "No refresh token stored for " << user_name_
;
65 if (auth_code
.empty()) {
66 // No token and no Auth code means no service connectivity, bail!
67 LOG(ERROR
) << "Cannot retrieve an access token without a stored refresh"
68 << " token on disk or an auth_code passed into the tool";
73 if (!RetrieveAccessToken(auth_code
)) {
74 // If we cannot retrieve an access token, then nothing is going to work and
75 // we should let the caller know that our object is not ready to be used.
82 bool AppRemotingTestDriverEnvironment::RefreshAccessToken() {
83 DCHECK(!refresh_token_
.empty());
85 // Empty auth code is used when refreshing.
86 return RetrieveAccessToken(std::string());
89 bool AppRemotingTestDriverEnvironment::GetRemoteHostInfoForApplicationId(
90 const std::string
& application_id
,
91 RemoteHostInfo
* remote_host_info
) {
92 DCHECK(!application_id
.empty());
93 DCHECK(remote_host_info
);
95 if (access_token_
.empty()) {
96 LOG(ERROR
) << "RemoteHostInfo requested without a valid access token. "
97 << "Ensure the environment object has been initialized.";
101 scoped_ptr
<base::MessageLoopForIO
> message_loop
;
102 if (!base::MessageLoop::current()) {
103 // Create a temporary message loop if the current thread does not already
104 // have one so we can use its task runner for our network request.
105 message_loop
.reset(new base::MessageLoopForIO
);
108 base::RunLoop run_loop
;
110 RemoteHostInfoCallback remote_host_info_fetch_callback
= base::Bind(
111 &AppRemotingTestDriverEnvironment::OnRemoteHostInfoRetrieved
,
112 base::Unretained(this), run_loop
.QuitClosure(), remote_host_info
);
114 // If a unit test has set |test_remote_host_info_fetcher_| then we should use
115 // it below. Note that we do not want to destroy the test object at the end
116 // of the function which is why we have the dance below.
117 scoped_ptr
<RemoteHostInfoFetcher
> temporary_remote_host_info_fetcher
;
118 RemoteHostInfoFetcher
* remote_host_info_fetcher
=
119 test_remote_host_info_fetcher_
;
120 if (!remote_host_info_fetcher
) {
121 temporary_remote_host_info_fetcher
.reset(new RemoteHostInfoFetcher());
122 remote_host_info_fetcher
= temporary_remote_host_info_fetcher
.get();
125 remote_host_info_fetcher
->RetrieveRemoteHostInfo(
126 application_id
, access_token_
, service_environment_
,
127 remote_host_info_fetch_callback
);
131 return remote_host_info
->IsReadyForConnection();
134 void AppRemotingTestDriverEnvironment::ShowHostAvailability() {
135 const char kHostAvailabilityFormatString
[] = "%-25s%-35s%-10s";
136 std::vector
<std::string
>::const_iterator it
= application_names_
.begin();
138 LOG(INFO
) << base::StringPrintf(kHostAvailabilityFormatString
,
139 "Application Name", "Application ID",
142 while (it
!= application_names_
.end()) {
143 std::string application_name
= *it
;
145 const RemoteApplicationDetails
& application_details
=
146 GetDetailsFromAppName(application_name
);
148 RemoteHostInfo remote_host_info
;
149 GetRemoteHostInfoForApplicationId(application_details
.application_id
,
153 RemoteHostStatus remote_host_status
= remote_host_info
.remote_host_status
;
154 if (remote_host_status
== kRemoteHostStatusReady
) {
156 } else if (remote_host_status
== kRemoteHostStatusPending
) {
157 status
= "Pending :|";
159 status
= "Unknown :(";
162 LOG(INFO
) << base::StringPrintf(
163 kHostAvailabilityFormatString
, application_name
.c_str(),
164 application_details
.application_id
.c_str(), status
.c_str());
170 const RemoteApplicationDetails
&
171 AppRemotingTestDriverEnvironment::GetDetailsFromAppName(
172 const std::string
& application_name
) {
173 std::map
<std::string
, RemoteApplicationDetails
>::const_iterator
174 map_pair_iterator
= application_details_map_
.find(application_name
);
175 DCHECK(map_pair_iterator
!= application_details_map_
.end());
177 return map_pair_iterator
->second
;
180 void AppRemotingTestDriverEnvironment::SetAccessTokenFetcherForTest(
181 AccessTokenFetcher
* access_token_fetcher
) {
182 DCHECK(access_token_fetcher
);
184 test_access_token_fetcher_
= access_token_fetcher
;
187 void AppRemotingTestDriverEnvironment::SetRefreshTokenStoreForTest(
188 RefreshTokenStore
* refresh_token_store
) {
189 DCHECK(refresh_token_store
);
191 test_refresh_token_store_
= refresh_token_store
;
194 void AppRemotingTestDriverEnvironment::SetRemoteHostInfoFetcherForTest(
195 RemoteHostInfoFetcher
* remote_host_info_fetcher
) {
196 DCHECK(remote_host_info_fetcher
);
198 test_remote_host_info_fetcher_
= remote_host_info_fetcher
;
201 bool AppRemotingTestDriverEnvironment::RetrieveAccessToken(
202 const std::string
& auth_code
) {
203 scoped_ptr
<base::MessageLoopForIO
> message_loop
;
205 if (!base::MessageLoop::current()) {
206 // Create a temporary message loop if the current thread does not already
207 // have one so we can use its task runner for our network request.
208 message_loop
.reset(new base::MessageLoopForIO
);
211 base::RunLoop run_loop
;
213 access_token_
.clear();
215 AccessTokenCallback access_token_callback
=
216 base::Bind(&AppRemotingTestDriverEnvironment::OnAccessTokenRetrieved
,
217 base::Unretained(this), run_loop
.QuitClosure());
219 // If a unit test has set |test_access_token_fetcher_| then we should use it
220 // below. Note that we do not want to destroy the test object at the end of
221 // the function which is why we have the dance below.
222 scoped_ptr
<AccessTokenFetcher
> temporary_access_token_fetcher
;
223 AccessTokenFetcher
* access_token_fetcher
= test_access_token_fetcher_
;
224 if (!access_token_fetcher
) {
225 temporary_access_token_fetcher
.reset(new AccessTokenFetcher());
226 access_token_fetcher
= temporary_access_token_fetcher
.get();
229 if (!auth_code
.empty()) {
230 // If the user passed in an authcode, then use it to retrieve an
231 // updated access/refresh token.
232 access_token_fetcher
->GetAccessTokenFromAuthCode(auth_code
,
233 access_token_callback
);
235 DCHECK(!refresh_token_
.empty());
237 access_token_fetcher
->GetAccessTokenFromRefreshToken(refresh_token_
,
238 access_token_callback
);
243 // If we were using an auth_code and received a valid refresh token,
244 // then we want to store it locally. If we had an auth code and did not
245 // receive a refresh token, then we should let the user know and exit.
246 if (!auth_code
.empty()) {
247 if (!refresh_token_
.empty()) {
248 // If a unit test has set |test_refresh_token_store_| then we should use
249 // it below. Note that we do not want to destroy the test object.
250 scoped_ptr
<RefreshTokenStore
> temporary_refresh_token_store
;
251 RefreshTokenStore
* refresh_token_store
= test_refresh_token_store_
;
252 if (!refresh_token_store
) {
253 temporary_refresh_token_store
= RefreshTokenStore::OnDisk(user_name_
);
254 refresh_token_store
= temporary_refresh_token_store
.get();
257 if (!refresh_token_store
->StoreRefreshToken(refresh_token_
)) {
258 // If we failed to persist the refresh token, then we should let the
259 // user sort out the issue before continuing.
263 LOG(ERROR
) << "Failed to use AUTH CODE to retrieve a refresh token.\n"
264 << "Was the one-time use AUTH CODE used more than once?";
269 if (access_token_
.empty()) {
270 LOG(ERROR
) << "Failed to retrieve access token.";
277 void AppRemotingTestDriverEnvironment::OnAccessTokenRetrieved(
278 base::Closure done_closure
,
279 const std::string
& access_token
,
280 const std::string
& refresh_token
) {
281 access_token_
= access_token
;
282 refresh_token_
= refresh_token
;
287 void AppRemotingTestDriverEnvironment::OnRemoteHostInfoRetrieved(
288 base::Closure done_closure
,
289 RemoteHostInfo
* remote_host_info
,
290 const RemoteHostInfo
& retrieved_remote_host_info
) {
291 DCHECK(remote_host_info
);
293 *remote_host_info
= retrieved_remote_host_info
;
299 } // namespace remoting