forked from sanyaade-mobiledev/chromium.src
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial version of Test Accounts service client. This client will
allow Chrome Sync tests to utilize the upcoming Test Accounts service that allows short-term, exclusive access to test accounts for the purpose of testing against real servers. BUG= Review URL: https://chromiumcodereview.appspot.com/14295014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@198019 0039d316-1c4b-4281-b951-d872f2087c98
- Loading branch information
pvalenzuela@chromium.org
committed
May 3, 2013
1 parent
583cd38
commit 0f02f8a
Showing
4 changed files
with
319 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// Copyright 2013 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 "sync/test/accounts_client/test_accounts_client.h" | ||
|
||
#include <algorithm> | ||
#include <curl/curl.h> | ||
#include <string> | ||
#include <vector> | ||
|
||
#include "base/json/json_reader.h" | ||
#include "base/json/json_writer.h" | ||
#include "base/stringprintf.h" | ||
#include "base/values.h" | ||
|
||
using std::string; | ||
using std::vector; | ||
|
||
static const int kMaxSessionLifetimeSeconds = 30 * 60; | ||
static const string kClaimPath = "claim"; | ||
static const string kReleasePath = "release"; | ||
|
||
AccountSession::AccountSession() {} | ||
AccountSession::~AccountSession() {} | ||
|
||
TestAccountsClient::TestAccountsClient(const string& server, | ||
const string& account_space, | ||
const vector<string>& usernames) | ||
: server_(server), account_space_(account_space), usernames_(usernames) { | ||
} | ||
|
||
TestAccountsClient::~TestAccountsClient() {} | ||
|
||
AccountSession TestAccountsClient::ClaimAccount() { | ||
string post_fields; | ||
base::StringAppendF(&post_fields, "account_space=%s", account_space_.c_str()); | ||
base::StringAppendF(&post_fields, "&max_lifetime_seconds=%d", | ||
kMaxSessionLifetimeSeconds); | ||
|
||
// TODO(pvalenzuela): Select N random usernames instead of all usernames. | ||
for (vector<string>::iterator it = usernames_.begin(); | ||
it != usernames_.end(); ++it) { | ||
base::StringAppendF(&post_fields, "&username=%s", it->c_str()); | ||
} | ||
|
||
string response = SendRequest(kClaimPath, post_fields); | ||
scoped_ptr<Value> value(base::JSONReader::Read(response)); | ||
base::DictionaryValue* dict_value; | ||
AccountSession session; | ||
if (value != NULL && value->GetAsDictionary(&dict_value) && | ||
dict_value != NULL) { | ||
dict_value->GetString("username", &session.username); | ||
dict_value->GetString("account_space", &session.account_space); | ||
dict_value->GetString("session_id", &session.session_id); | ||
dict_value->GetString("expiration_time", &session.expiration_time); | ||
} else { | ||
session.error = response; | ||
} | ||
return session; | ||
} | ||
|
||
void TestAccountsClient::ReleaseAccount(const AccountSession& session) { | ||
string post_fields; | ||
// The expiration_time field is ignored since it isn't passed as part of the | ||
// release request. | ||
if (session.username.empty() || session.account_space.empty() || | ||
account_space_.compare(session.account_space) != 0 || | ||
session.session_id.empty()) { | ||
return; | ||
} | ||
|
||
base::StringAppendF(&post_fields, "account_space=%s", | ||
session.account_space.c_str()); | ||
base::StringAppendF(&post_fields, "&username=%s", session.username.c_str()); | ||
base::StringAppendF(&post_fields, "&session_id=%s", | ||
session.session_id.c_str()); | ||
|
||
// This operation is best effort, so don't send any errors back to the caller. | ||
SendRequest(kReleasePath, post_fields); | ||
} | ||
|
||
namespace { | ||
int CurlWriteFunction(char* data, | ||
size_t size, | ||
size_t nmemb, | ||
string* write_data) { | ||
if (write_data == NULL) { | ||
return 0; | ||
} | ||
write_data->append(data, size * nmemb); | ||
return size * nmemb; | ||
} | ||
} // namespace | ||
|
||
string TestAccountsClient::SendRequest(const string& path, | ||
const string& post_fields) { | ||
CURLcode res; | ||
string response_buffer; | ||
char error_buffer[CURL_ERROR_SIZE]; | ||
CURL* curl = curl_easy_init(); | ||
if (curl) { | ||
string url; | ||
base::SStringPrintf(&url, "%s/%s", server_.c_str(), path.c_str()); | ||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); | ||
curl_easy_setopt(curl, CURLOPT_POST, 1L); | ||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_fields.c_str()); | ||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteFunction); | ||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_buffer); | ||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer); | ||
res = curl_easy_perform(curl); | ||
curl_easy_cleanup(curl); | ||
if (res != CURLE_OK) { | ||
string error(error_buffer); | ||
return error; | ||
} | ||
return response_buffer; | ||
} | ||
return "There was an error establishing the connection."; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// Copyright 2013 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. | ||
|
||
#ifndef SYNC_TEST_ACCOUNTS_CLIENT_TEST_ACCOUNTS_CLIENT_H_ | ||
#define SYNC_TEST_ACCOUNTS_CLIENT_TEST_ACCOUNTS_CLIENT_H_ | ||
|
||
#include <curl/curl.h> | ||
#include <string> | ||
#include <vector> | ||
|
||
using std::string; | ||
using std::vector; | ||
|
||
// The data associated with an account session. | ||
struct AccountSession { | ||
AccountSession(); | ||
~AccountSession(); | ||
|
||
string username; | ||
string account_space; | ||
string session_id; | ||
string expiration_time; | ||
|
||
// Only set if there was an error. | ||
string error; | ||
}; | ||
|
||
// A test-side client for the Test Accounts service. This service provides | ||
// short-term, exclusive access to test accounts for the purpose of testing | ||
// against real Chrome Sync servers. | ||
class TestAccountsClient { | ||
public: | ||
// Creates a client associated with the given |server| URL (e.g., | ||
// http://service-runs-here.com), |account_space| (for account segregation), | ||
// and |usernames| (the collection of accounts to be chosen from). | ||
TestAccountsClient(const string& server, | ||
const string& account_space, | ||
const vector<string>& usernames); | ||
|
||
virtual ~TestAccountsClient(); | ||
|
||
// Attempts to claim an account via the Test Accounts service. If | ||
// successful, an AccountSession is returned containing the data associated | ||
// with the session. If an error occurred, then the AccountSession will only | ||
// have its error field set. | ||
AccountSession ClaimAccount(); | ||
|
||
// Attempts to release an account via the Test Accounts service. The value | ||
// of |session| should be one returned from ClaimAccount(). This function | ||
// is best-effort and fails silently. | ||
void ReleaseAccount(const AccountSession& session); | ||
|
||
// Sends an HTTP POST request to the Test Accounts service. | ||
virtual string SendRequest(const string& path, const string& post_fields); | ||
|
||
private: | ||
const string server_; | ||
const string account_space_; | ||
vector<string> usernames_; | ||
}; | ||
|
||
#endif // SYNC_TEST_ACCOUNTS_CLIENT_TEST_ACCOUNTS_CLIENT_H_ |
95 changes: 95 additions & 0 deletions
95
sync/test/accounts_client/test_accounts_client_unittest.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Copyright 2013 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 <vector> | ||
|
||
#include "sync/test/accounts_client/test_accounts_client.cc" | ||
#include "sync/test/accounts_client/test_accounts_client.h" | ||
#include "testing/gmock/include/gmock/gmock.h" | ||
#include "testing/gtest/include/gtest/gtest.h" | ||
|
||
using std::string; | ||
using std::vector; | ||
using testing::_; | ||
using testing::HasSubstr; | ||
using testing::Return; | ||
|
||
namespace { | ||
static const string kServer = "https://test-account-service"; | ||
static const string kUsername = "foobar@baz.com"; | ||
static const string kAccountSpace = "test_account_space"; | ||
static const string kSessionId = "1234-ABCD"; | ||
static const string kExpirationTime = "12:00"; | ||
} // namespace | ||
|
||
static AccountSession CreateValidAccountSession() { | ||
AccountSession session; | ||
session.username = kUsername; | ||
session.account_space = kAccountSpace; | ||
session.session_id = kSessionId; | ||
session.expiration_time = kExpirationTime; | ||
return session; | ||
} | ||
|
||
class NoNetworkTestAccountsClient : public TestAccountsClient { | ||
public: | ||
NoNetworkTestAccountsClient(const string& server, | ||
const string& account_space, | ||
vector<string> usernames) | ||
: TestAccountsClient(server, account_space, usernames) {} | ||
MOCK_METHOD2(SendRequest, | ||
string(const string&, const string&)); | ||
}; | ||
|
||
TEST(TestAccountsClientTest, ClaimAccountError) { | ||
vector<string> usernames; | ||
NoNetworkTestAccountsClient client(kServer, kAccountSpace, usernames); | ||
string error_response = "error!!!"; | ||
EXPECT_CALL(client, SendRequest(kClaimPath, _)) | ||
.WillOnce(Return(error_response)); | ||
AccountSession session = client.ClaimAccount(); | ||
EXPECT_EQ(error_response, session.error); | ||
} | ||
|
||
TEST(TestAccountsClientTest, ClaimAccountSuccess) { | ||
vector<string> usernames; | ||
usernames.push_back("foo0@gmail.com"); | ||
usernames.push_back("foo1@gmail.com"); | ||
usernames.push_back("foo2@gmail.com"); | ||
NoNetworkTestAccountsClient client(kServer, kAccountSpace, usernames); | ||
string success_response; | ||
base::StringAppendF(&success_response, "{ \"username\":\"%s\",", | ||
kUsername.c_str()); | ||
base::StringAppendF(&success_response, "\"account_space\":\"%s\",", | ||
kAccountSpace.c_str()); | ||
base::StringAppendF(&success_response, "\"session_id\":\"%s\",", | ||
kSessionId.c_str()); | ||
base::StringAppendF(&success_response, "\"expiration_time\":\"%s\"}", | ||
kExpirationTime.c_str()); | ||
EXPECT_CALL(client, SendRequest(kClaimPath, _)) | ||
.WillOnce(Return(success_response)); | ||
AccountSession session = client.ClaimAccount(); | ||
EXPECT_EQ(kUsername, session.username); | ||
EXPECT_EQ(kAccountSpace, session.account_space); | ||
EXPECT_EQ(kSessionId, session.session_id); | ||
EXPECT_EQ(kExpirationTime, session.expiration_time); | ||
} | ||
|
||
TEST(TestAccountsClientTest, ReleaseAccountEmptySession) { | ||
vector<string> usernames; | ||
NoNetworkTestAccountsClient client(kServer, kAccountSpace, usernames); | ||
AccountSession session; | ||
// No expectation for SendRequest is made because no network call should be | ||
// performed in this scenario. | ||
client.ReleaseAccount(session); | ||
} | ||
|
||
TEST(TestAccountsClientTest, ReleaseAccountSuccess) { | ||
vector<string> usernames; | ||
NoNetworkTestAccountsClient client(kServer, kAccountSpace, usernames); | ||
EXPECT_CALL(client, SendRequest(kReleasePath, _)) | ||
.WillOnce(Return("")); | ||
AccountSession session = CreateValidAccountSession(); | ||
client.ReleaseAccount(session); | ||
} |