diff options
author | pvalenzuela@chromium.org <pvalenzuela@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-03 00:44:52 +0000 |
---|---|---|
committer | pvalenzuela@chromium.org <pvalenzuela@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-03 00:44:52 +0000 |
commit | 0f02f8a7f5bb9cb99b6323e1901ae6abac593adc (patch) | |
tree | 3be482121188c366a46ed81672d931660f608313 /sync | |
parent | 583cd380b86cfc3318e11bef2f564e8423983e59 (diff) | |
download | chromium_src-0f02f8a7f5bb9cb99b6323e1901ae6abac593adc.zip chromium_src-0f02f8a7f5bb9cb99b6323e1901ae6abac593adc.tar.gz chromium_src-0f02f8a7f5bb9cb99b6323e1901ae6abac593adc.tar.bz2 |
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
Diffstat (limited to 'sync')
-rw-r--r-- | sync/sync_tests.gypi | 41 | ||||
-rw-r--r-- | sync/test/accounts_client/test_accounts_client.cc | 120 | ||||
-rw-r--r-- | sync/test/accounts_client/test_accounts_client.h | 63 | ||||
-rw-r--r-- | sync/test/accounts_client/test_accounts_client_unittest.cc | 95 |
4 files changed, 319 insertions, 0 deletions
diff --git a/sync/sync_tests.gypi b/sync/sync_tests.gypi index f7e2b64..b570384 100644 --- a/sync/sync_tests.gypi +++ b/sync/sync_tests.gypi @@ -608,5 +608,46 @@ }, ], }], + # TODO(pvalenzuela): Remove these OS restrictions when moving end-to-end + # tests to other platforms. + ['OS != "ios" and OS != "win"', { + 'targets': [ + # Test support files for using the Test Accounts service. + { + 'target_name': 'test_support_accounts_client', + 'type': 'static_library', + 'direct_dependent_settings': { + 'include_dirs': [ + '..', + ], + }, + 'dependencies': [ + '../base/base.gyp:base', + ], + 'sources': [ + 'test/accounts_client/test_accounts_client.cc', + 'test/accounts_client/test_accounts_client.h', + ], + 'link_settings': { + 'libraries': [ '-lcurl', ], + }, + }, + + # The Sync end-to-end (and associated infrastructure) tests. + { + 'target_name': 'sync_endtoend_tests', + 'type': '<(gtest_target_type)', + 'dependencies': [ + '../base/base.gyp:run_all_unittests', + '../testing/gmock.gyp:gmock', + '../testing/gtest.gyp:gtest', + 'test_support_accounts_client', + ], + 'sources': [ + 'test/accounts_client/test_accounts_client_unittest.cc', + ], + }, + ] + }], ], } diff --git a/sync/test/accounts_client/test_accounts_client.cc b/sync/test/accounts_client/test_accounts_client.cc new file mode 100644 index 0000000..9bf82c1 --- /dev/null +++ b/sync/test/accounts_client/test_accounts_client.cc @@ -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."; +} diff --git a/sync/test/accounts_client/test_accounts_client.h b/sync/test/accounts_client/test_accounts_client.h new file mode 100644 index 0000000..68f2b2e --- /dev/null +++ b/sync/test/accounts_client/test_accounts_client.h @@ -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_ diff --git a/sync/test/accounts_client/test_accounts_client_unittest.cc b/sync/test/accounts_client/test_accounts_client_unittest.cc new file mode 100644 index 0000000..f70eab9 --- /dev/null +++ b/sync/test/accounts_client/test_accounts_client_unittest.cc @@ -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); +} |