1 // Copyright 2013 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 "sync/test/accounts_client/test_accounts_client.h"
11 #include "base/json/json_reader.h"
12 #include "base/json/json_writer.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/run_loop.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/time/time.h"
17 #include "base/values.h"
18 #include "net/base/url_util.h"
19 #include "net/http/http_status_code.h"
20 #include "net/url_request/url_fetcher.h"
21 #include "net/url_request/url_fetcher_delegate.h"
22 #include "net/url_request/url_request.h"
23 #include "net/url_request/url_request_context_getter.h"
24 #include "sync/test/accounts_client/url_request_context_getter.h"
29 static const int kMaxSessionLifetimeSeconds
= 30 * 60;
30 static const string kClaimPath
= "claim";
31 static const string kReleasePath
= "release";
32 static const base::TimeDelta kRequestTimeout
= base::TimeDelta::FromSeconds(10);
34 AccountSession::AccountSession() {}
35 AccountSession::~AccountSession() {}
37 class AccountsRequestDelegate
: public net::URLFetcherDelegate
{
39 AccountsRequestDelegate(base::RunLoop
* run_loop
) : response_(""),
40 success_(false), run_loop_(run_loop
) {}
42 void OnURLFetchComplete(const net::URLFetcher
* source
) override
{
43 string url
= source
->GetURL().spec();
44 source
->GetResponseAsString(&response_
);
46 if (!source
->GetStatus().is_success()) {
47 int error
= source
->GetStatus().error();
48 DVLOG(0) << "The request failed with error code " << error
<< "."
49 << "\nRequested URL: " << url
<< ".";
50 } else if (source
->GetResponseCode() != net::HTTP_OK
) {
51 DVLOG(0) << "The request failed with response code "
52 << source
->GetResponseCode() << "."
53 << "\nRequested URL: " << url
54 << "\nResponse body: \"" << response_
<< "\"";
62 string
response() const { return response_
; }
63 bool success() const { return success_
; }
68 base::RunLoop
* run_loop_
;
71 TestAccountsClient::TestAccountsClient(const string
& server
,
72 const string
& account_space
,
73 const vector
<string
>& usernames
)
74 : server_(server
), account_space_(account_space
), usernames_(usernames
) {
77 TestAccountsClient::~TestAccountsClient() {}
79 bool TestAccountsClient::ClaimAccount(AccountSession
* session
) {
80 GURL url
= CreateGURLWithPath(kClaimPath
);
81 url
= net::AppendQueryParameter(url
, "account_space", account_space_
);
82 string max_lifetime_seconds
= base::StringPrintf("%d",
83 kMaxSessionLifetimeSeconds
);
84 url
= net::AppendQueryParameter(url
, "max_lifetime_seconds",
85 max_lifetime_seconds
);
87 // TODO(pvalenzuela): Select N random usernames instead of all usernames.
88 for (vector
<string
>::iterator it
= usernames_
.begin();
89 it
!= usernames_
.end(); ++it
) {
90 url
= net::AppendQueryParameter(url
, "username", *it
);
94 if (!SendRequest(url
, &response
)) {
98 scoped_ptr
<base::Value
> value(base::JSONReader::Read(response
));
99 base::DictionaryValue
* dict_value
;
100 if (value
!= NULL
&& value
->GetAsDictionary(&dict_value
) &&
101 dict_value
!= NULL
) {
102 dict_value
->GetString("username", &session
->username
);
103 dict_value
->GetString("account_space", &session
->account_space
);
104 dict_value
->GetString("session_id", &session
->session_id
);
105 dict_value
->GetString("expiration_time", &session
->expiration_time
);
113 void TestAccountsClient::ReleaseAccount(const AccountSession
& session
) {
114 // The expiration_time field is ignored since it isn't passed as part of the
116 if (session
.username
.empty() || session
.account_space
.empty() ||
117 account_space_
.compare(session
.account_space
) != 0 ||
118 session
.session_id
.empty()) {
122 GURL url
= CreateGURLWithPath(kReleasePath
);
123 url
= net::AppendQueryParameter(url
, "account_space", session
.account_space
);
124 url
= net::AppendQueryParameter(url
, "username", session
.username
);
125 url
= net::AppendQueryParameter(url
, "session_id", session
.session_id
);
127 // This operation is best effort, so don't send any errors back to the caller.
129 SendRequest(url
, &response
);
132 GURL
TestAccountsClient::CreateGURLWithPath(const string
& path
) {
133 return GURL(base::StringPrintf("%s/%s", server_
.c_str(), path
.c_str()));
137 bool TestAccountsClient::SendRequest(const GURL
& url
, string
* response
) {
138 base::MessageLoop
* loop
= base::MessageLoop::current();
139 scoped_refptr
<URLRequestContextGetter
> context_getter(
140 new URLRequestContextGetter(loop
->message_loop_proxy()));
142 base::RunLoop run_loop
;
144 AccountsRequestDelegate
delegate(&run_loop
);
145 scoped_ptr
<net::URLFetcher
> fetcher(net::URLFetcher::Create(
146 url
, net::URLFetcher::POST
, &delegate
));
147 fetcher
->SetRequestContext(context_getter
.get());
148 fetcher
->SetUploadData("application/json", "");
151 base::MessageLoop::current()->PostDelayedTask(FROM_HERE
,
152 run_loop
.QuitClosure(),
156 if (delegate
.success()) {
157 *response
= delegate
.response();
160 return delegate
.success();