| Index: chrome/browser/local_discovery/privetv3_session_unittest.cc
|
| diff --git a/chrome/browser/local_discovery/privetv3_session_unittest.cc b/chrome/browser/local_discovery/privetv3_session_unittest.cc
|
| index c7e794394ee0a82c9b0dd334c29a50e1a5eaa8be..7b6f195dc5345328f1dca5f6eb03ff119bf55944 100644
|
| --- a/chrome/browser/local_discovery/privetv3_session_unittest.cc
|
| +++ b/chrome/browser/local_discovery/privetv3_session_unittest.cc
|
| @@ -4,9 +4,14 @@
|
|
|
| #include "chrome/browser/local_discovery/privetv3_session.h"
|
|
|
| +#include "base/base64.h"
|
| +#include "base/strings/stringprintf.h"
|
| #include "chrome/browser/local_discovery/privet_http.h"
|
| #include "content/public/test/test_utils.h"
|
| +#include "crypto/hmac.h"
|
| +#include "crypto/p224_spake.h"
|
| #include "net/url_request/test_url_fetcher_factory.h"
|
| +#include "net/url_request/url_request_test_util.h"
|
| #include "testing/gmock/include/gmock/gmock.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| @@ -15,76 +20,213 @@ namespace local_discovery {
|
| namespace {
|
|
|
| using testing::Invoke;
|
| -using testing::InvokeWithoutArgs;
|
| +using testing::SaveArg;
|
| using testing::StrictMock;
|
| using testing::_;
|
|
|
| +using PairingType = PrivetV3Session::PairingType;
|
| +using Result = PrivetV3Session::Result;
|
| +
|
| +const char kInfoResponse[] =
|
| + "{\"version\":\"3.0\","
|
| + "\"endpoints\":{\"httpsPort\": 443},"
|
| + "\"authentication\":{"
|
| + " \"mode\":[\"anonymous\",\"pairing\",\"cloud\"],"
|
| + " \"pairing\":[\"pinCode\",\"embeddedCode\"],"
|
| + " \"crypto\":[\"p224_spake2\"]"
|
| + "}}";
|
| +
|
| +class MockPrivetHTTPClient : public PrivetHTTPClient {
|
| + public:
|
| + MockPrivetHTTPClient() {
|
| + request_context_ =
|
| + new net::TestURLRequestContextGetter(base::MessageLoopProxy::current());
|
| + }
|
| +
|
| + MOCK_METHOD0(GetName, const std::string&());
|
| + MOCK_METHOD1(
|
| + CreateInfoOperationPtr,
|
| + PrivetJSONOperation*(const PrivetJSONOperation::ResultCallback&));
|
| +
|
| + virtual void RefreshPrivetToken(
|
| + const PrivetURLFetcher::TokenCallback& callback) override {
|
| + FAIL();
|
| + }
|
| +
|
| + virtual scoped_ptr<PrivetJSONOperation> CreateInfoOperation(
|
| + const PrivetJSONOperation::ResultCallback& callback) override {
|
| + return make_scoped_ptr(CreateInfoOperationPtr(callback));
|
| + }
|
| +
|
| + virtual scoped_ptr<PrivetURLFetcher> CreateURLFetcher(
|
| + const GURL& url,
|
| + net::URLFetcher::RequestType request_type,
|
| + PrivetURLFetcher::Delegate* delegate) override {
|
| + return make_scoped_ptr(new PrivetURLFetcher(
|
| + url, request_type, request_context_.get(), delegate));
|
| + }
|
| +
|
| + scoped_refptr<net::TestURLRequestContextGetter> request_context_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| class PrivetV3SessionTest : public testing::Test {
|
| public:
|
| - PrivetV3SessionTest() : session_(scoped_ptr<PrivetHTTPClient>()) {}
|
| + PrivetV3SessionTest()
|
| + : fetcher_factory_(nullptr),
|
| + session_(make_scoped_ptr(new MockPrivetHTTPClient())) {}
|
|
|
| virtual ~PrivetV3SessionTest() {}
|
|
|
| - MOCK_METHOD2(OnInitialized,
|
| - void(PrivetV3Session::Result,
|
| - const std::vector<PrivetV3Session::PairingType>&));
|
| - MOCK_METHOD1(OnPairingStarted, void(PrivetV3Session::Result));
|
| - MOCK_METHOD1(OnCodeConfirmed, void(PrivetV3Session::Result));
|
| - MOCK_METHOD2(OnMessageSend,
|
| - void(PrivetV3Session::Result,
|
| - const base::DictionaryValue& value));
|
| + MOCK_METHOD2(OnInitialized, void(Result, const std::vector<PairingType>&));
|
| + MOCK_METHOD1(OnPairingStarted, void(Result));
|
| + MOCK_METHOD1(OnCodeConfirmed, void(Result));
|
| + MOCK_METHOD2(OnMessageSend, void(Result, const base::DictionaryValue& value));
|
| + MOCK_METHOD1(OnPostData, void(const base::DictionaryValue& data));
|
|
|
| protected:
|
| virtual void SetUp() override {
|
| EXPECT_CALL(*this, OnInitialized(_, _)).Times(0);
|
| EXPECT_CALL(*this, OnPairingStarted(_)).Times(0);
|
| EXPECT_CALL(*this, OnCodeConfirmed(_)).Times(0);
|
| + EXPECT_CALL(*this, OnMessageSend(_, _)).Times(0);
|
| + EXPECT_CALL(*this, OnPostData(_)).Times(0);
|
| + session_.on_post_data_ =
|
| + base::Bind(&PrivetV3SessionTest::OnPostData, base::Unretained(this));
|
| }
|
|
|
| - PrivetV3Session session_;
|
| base::MessageLoop loop_;
|
| base::Closure quit_closure_;
|
| + net::FakeURLFetcherFactory fetcher_factory_;
|
| + PrivetV3Session session_;
|
| };
|
|
|
| -TEST_F(PrivetV3SessionTest, Pairing) {
|
| - {
|
| - base::RunLoop run_loop;
|
| - EXPECT_CALL(*this,
|
| - OnInitialized(PrivetV3Session::Result::STATUS_SUCCESS, _))
|
| - .Times(1)
|
| - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
|
| - session_.Init(base::Bind(&PrivetV3SessionTest::OnInitialized,
|
| - base::Unretained(this)));
|
| - run_loop.Run();
|
| - }
|
| +TEST_F(PrivetV3SessionTest, InitError) {
|
| + EXPECT_CALL(*this, OnInitialized(Result::STATUS_CONNECTIONERROR, _)).Times(1);
|
| + fetcher_factory_.SetFakeResponse(GURL("http://host/privet/info"), "",
|
| + net::HTTP_OK, net::URLRequestStatus::FAILED);
|
| + session_.Init(
|
| + base::Bind(&PrivetV3SessionTest::OnInitialized, base::Unretained(this)));
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
|
|
| - {
|
| - base::RunLoop run_loop;
|
| - EXPECT_CALL(*this,
|
| - OnPairingStarted(PrivetV3Session::Result::STATUS_SUCCESS))
|
| - .Times(1)
|
| - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
|
| - session_.StartPairing(PrivetV3Session::PairingType::PAIRING_TYPE_PINCODE,
|
| - base::Bind(&PrivetV3SessionTest::OnPairingStarted,
|
| - base::Unretained(this)));
|
| - run_loop.Run();
|
| - }
|
| +TEST_F(PrivetV3SessionTest, VersionError) {
|
| + std::string response(kInfoResponse);
|
| + ReplaceFirstSubstringAfterOffset(&response, 0, "3.0", "4.1");
|
| +
|
| + EXPECT_CALL(*this, OnInitialized(Result::STATUS_SESSIONERROR, _)).Times(1);
|
| + fetcher_factory_.SetFakeResponse(GURL("http://host/privet/info"), response,
|
| + net::HTTP_OK,
|
| + net::URLRequestStatus::SUCCESS);
|
| + session_.Init(
|
| + base::Bind(&PrivetV3SessionTest::OnInitialized, base::Unretained(this)));
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
|
|
| - {
|
| - base::RunLoop run_loop;
|
| - EXPECT_CALL(*this, OnCodeConfirmed(PrivetV3Session::Result::STATUS_SUCCESS))
|
| - .Times(1)
|
| - .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
|
| - session_.ConfirmCode("1234",
|
| - base::Bind(&PrivetV3SessionTest::OnCodeConfirmed,
|
| - base::Unretained(this)));
|
| - run_loop.Run();
|
| - }
|
| +TEST_F(PrivetV3SessionTest, ModeError) {
|
| + std::string response(kInfoResponse);
|
| + ReplaceFirstSubstringAfterOffset(&response, 0, "mode", "mode_");
|
| +
|
| + EXPECT_CALL(*this, OnInitialized(Result::STATUS_SESSIONERROR, _)).Times(1);
|
| + fetcher_factory_.SetFakeResponse(GURL("http://host/privet/info"), response,
|
| + net::HTTP_OK,
|
| + net::URLRequestStatus::SUCCESS);
|
| + session_.Init(
|
| + base::Bind(&PrivetV3SessionTest::OnInitialized, base::Unretained(this)));
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(PrivetV3SessionTest, Pairing) {
|
| + std::vector<PairingType> pairings;
|
| + EXPECT_CALL(*this, OnInitialized(Result::STATUS_SUCCESS, _))
|
| + .WillOnce(SaveArg<1>(&pairings));
|
| + fetcher_factory_.SetFakeResponse(GURL("http://host/privet/info"),
|
| + kInfoResponse, net::HTTP_OK,
|
| + net::URLRequestStatus::SUCCESS);
|
| +
|
| + session_.Init(
|
| + base::Bind(&PrivetV3SessionTest::OnInitialized, base::Unretained(this)));
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_EQ(2u, pairings.size());
|
| + EXPECT_EQ(PairingType::PAIRING_TYPE_PINCODE, pairings[0]);
|
| + EXPECT_EQ(PairingType::PAIRING_TYPE_EMBEDDEDCODE, pairings[1]);
|
| +
|
| + crypto::P224EncryptedKeyExchange spake(
|
| + crypto::P224EncryptedKeyExchange::kPeerTypeServer, "testPin");
|
| +
|
| + EXPECT_CALL(*this, OnPairingStarted(Result::STATUS_SUCCESS)).Times(1);
|
| + EXPECT_CALL(*this, OnPostData(_))
|
| + .WillOnce(
|
| + testing::Invoke([this, &spake](const base::DictionaryValue& data) {
|
| + std::string pairing_type;
|
| + EXPECT_TRUE(data.GetString("pairing", &pairing_type));
|
| + EXPECT_EQ("embeddedCode", pairing_type);
|
| +
|
| + std::string crypto_type;
|
| + EXPECT_TRUE(data.GetString("crypto", &crypto_type));
|
| + EXPECT_EQ("p224_spake2", crypto_type);
|
| +
|
| + std::string device_commitment;
|
| + base::Base64Encode(spake.GetNextMessage(), &device_commitment);
|
| + fetcher_factory_.SetFakeResponse(
|
| + GURL("http://host/privet/v3/pairing/start"),
|
| + base::StringPrintf(
|
| + "{\"deviceCommitment\":\"%s\",\"sessionId\":\"testId\"}",
|
| + device_commitment.c_str()),
|
| + net::HTTP_OK, net::URLRequestStatus::SUCCESS);
|
| + }));
|
| + session_.StartPairing(PairingType::PAIRING_TYPE_EMBEDDEDCODE,
|
| + base::Bind(&PrivetV3SessionTest::OnPairingStarted,
|
| + base::Unretained(this)));
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_CALL(*this, OnCodeConfirmed(Result::STATUS_SUCCESS)).Times(1);
|
| + EXPECT_CALL(*this, OnPostData(_))
|
| + .WillOnce(
|
| + testing::Invoke([this, &spake](const base::DictionaryValue& data) {
|
| + std::string commitment_base64;
|
| + EXPECT_TRUE(data.GetString("clientCommitment", &commitment_base64));
|
| + std::string commitment;
|
| + EXPECT_TRUE(base::Base64Decode(commitment_base64, &commitment));
|
| +
|
| + std::string session_id;
|
| + EXPECT_TRUE(data.GetString("sessionId", &session_id));
|
| + EXPECT_EQ("testId", session_id);
|
| +
|
| + EXPECT_EQ(spake.ProcessMessage(commitment),
|
| + crypto::P224EncryptedKeyExchange::kResultPending);
|
| +
|
| + std::string fingerprint("testFinterprint");
|
| + std::string fingerprint_base64;
|
| + base::Base64Encode(fingerprint, &fingerprint_base64);
|
| +
|
| + crypto::HMAC hmac(crypto::HMAC::SHA256);
|
| + const std::string& key = spake.GetUnverifiedKey();
|
| + EXPECT_TRUE(hmac.Init(key));
|
| + std::string signature(hmac.DigestLength(), ' ');
|
| + EXPECT_TRUE(hmac.Sign(fingerprint, reinterpret_cast<unsigned char*>(
|
| + string_as_array(&signature)),
|
| + signature.size()));
|
| +
|
| + std::string signature_base64;
|
| + base::Base64Encode(signature, &signature_base64);
|
| +
|
| + fetcher_factory_.SetFakeResponse(
|
| + GURL("http://host/privet/v3/pairing/confirm"),
|
| + base::StringPrintf(
|
| + "{\"certFingerprint\":\"%s\",\"certSignature\":\"%s\"}",
|
| + fingerprint_base64.c_str(), signature_base64.c_str()),
|
| + net::HTTP_OK, net::URLRequestStatus::SUCCESS);
|
| + }));
|
| + session_.ConfirmCode("testPin",
|
| + base::Bind(&PrivetV3SessionTest::OnCodeConfirmed,
|
| + base::Unretained(this)));
|
| + base::RunLoop().RunUntilIdle();
|
| }
|
|
|
| // TODO(vitalybuka): replace PrivetHTTPClient with regular URL fetcher and
|
| // implement SendMessage test.
|
|
|
| -} // namespace
|
| -
|
| } // namespace local_discovery
|
|
|