// Copyright (c) 2012 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 "remoting/protocol/pairing_registry.h" #include <stdlib.h> #include <algorithm> #include "base/bind.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/thread_task_runner_handle.h" #include "base/values.h" #include "remoting/protocol/protocol_mock_objects.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using testing::Sequence; namespace { using remoting::protocol::PairingRegistry; class MockPairingRegistryCallbacks { public: MockPairingRegistryCallbacks() {} virtual ~MockPairingRegistryCallbacks() {} MOCK_METHOD1(DoneCallback, void(bool)); MOCK_METHOD1(GetAllPairingsCallbackPtr, void(base::ListValue*)); MOCK_METHOD1(GetPairingCallback, void(PairingRegistry::Pairing)); void GetAllPairingsCallback(scoped_ptr<base::ListValue> pairings) { GetAllPairingsCallbackPtr(pairings.get()); } private: DISALLOW_COPY_AND_ASSIGN(MockPairingRegistryCallbacks); }; // Verify that a pairing Dictionary has correct entries, but doesn't include // any shared secret. void VerifyPairing(PairingRegistry::Pairing expected, const base::DictionaryValue& actual) { std::string value; EXPECT_TRUE(actual.GetString(PairingRegistry::kClientNameKey, &value)); EXPECT_EQ(expected.client_name(), value); EXPECT_TRUE(actual.GetString(PairingRegistry::kClientIdKey, &value)); EXPECT_EQ(expected.client_id(), value); EXPECT_FALSE(actual.HasKey(PairingRegistry::kSharedSecretKey)); } } // namespace namespace remoting { namespace protocol { class PairingRegistryTest : public testing::Test { public: virtual void SetUp() OVERRIDE { callback_count_ = 0; } void set_pairings(scoped_ptr<base::ListValue> pairings) { pairings_ = pairings.Pass(); } void ExpectSecret(const std::string& expected, PairingRegistry::Pairing actual) { EXPECT_EQ(expected, actual.shared_secret()); ++callback_count_; } void ExpectSaveSuccess(bool success) { EXPECT_TRUE(success); ++callback_count_; } protected: base::MessageLoop message_loop_; base::RunLoop run_loop_; int callback_count_; scoped_ptr<base::ListValue> pairings_; }; TEST_F(PairingRegistryTest, CreateAndGetPairings) { scoped_refptr<PairingRegistry> registry = new SynchronousPairingRegistry( scoped_ptr<PairingRegistry::Delegate>(new MockPairingRegistryDelegate())); PairingRegistry::Pairing pairing_1 = registry->CreatePairing("my_client"); PairingRegistry::Pairing pairing_2 = registry->CreatePairing("my_client"); EXPECT_NE(pairing_1.shared_secret(), pairing_2.shared_secret()); registry->GetPairing(pairing_1.client_id(), base::Bind(&PairingRegistryTest::ExpectSecret, base::Unretained(this), pairing_1.shared_secret())); EXPECT_EQ(1, callback_count_); // Check that the second client is paired with a different shared secret. registry->GetPairing(pairing_2.client_id(), base::Bind(&PairingRegistryTest::ExpectSecret, base::Unretained(this), pairing_2.shared_secret())); EXPECT_EQ(2, callback_count_); } TEST_F(PairingRegistryTest, GetAllPairings) { scoped_refptr<PairingRegistry> registry = new SynchronousPairingRegistry( scoped_ptr<PairingRegistry::Delegate>(new MockPairingRegistryDelegate())); PairingRegistry::Pairing pairing_1 = registry->CreatePairing("client1"); PairingRegistry::Pairing pairing_2 = registry->CreatePairing("client2"); registry->GetAllPairings( base::Bind(&PairingRegistryTest::set_pairings, base::Unretained(this))); ASSERT_EQ(2u, pairings_->GetSize()); const base::DictionaryValue* actual_pairing_1; const base::DictionaryValue* actual_pairing_2; ASSERT_TRUE(pairings_->GetDictionary(0, &actual_pairing_1)); ASSERT_TRUE(pairings_->GetDictionary(1, &actual_pairing_2)); // Ordering is not guaranteed, so swap if necessary. std::string actual_client_id; ASSERT_TRUE(actual_pairing_1->GetString(PairingRegistry::kClientIdKey, &actual_client_id)); if (actual_client_id != pairing_1.client_id()) { std::swap(actual_pairing_1, actual_pairing_2); } VerifyPairing(pairing_1, *actual_pairing_1); VerifyPairing(pairing_2, *actual_pairing_2); } TEST_F(PairingRegistryTest, DeletePairing) { scoped_refptr<PairingRegistry> registry = new SynchronousPairingRegistry( scoped_ptr<PairingRegistry::Delegate>(new MockPairingRegistryDelegate())); PairingRegistry::Pairing pairing_1 = registry->CreatePairing("client1"); PairingRegistry::Pairing pairing_2 = registry->CreatePairing("client2"); registry->DeletePairing( pairing_1.client_id(), base::Bind(&PairingRegistryTest::ExpectSaveSuccess, base::Unretained(this))); // Re-read the list, and verify it only has the pairing_2 client. registry->GetAllPairings( base::Bind(&PairingRegistryTest::set_pairings, base::Unretained(this))); ASSERT_EQ(1u, pairings_->GetSize()); const base::DictionaryValue* actual_pairing_2; ASSERT_TRUE(pairings_->GetDictionary(0, &actual_pairing_2)); std::string actual_client_id; ASSERT_TRUE(actual_pairing_2->GetString(PairingRegistry::kClientIdKey, &actual_client_id)); EXPECT_EQ(pairing_2.client_id(), actual_client_id); } TEST_F(PairingRegistryTest, ClearAllPairings) { scoped_refptr<PairingRegistry> registry = new SynchronousPairingRegistry( scoped_ptr<PairingRegistry::Delegate>(new MockPairingRegistryDelegate())); PairingRegistry::Pairing pairing_1 = registry->CreatePairing("client1"); PairingRegistry::Pairing pairing_2 = registry->CreatePairing("client2"); registry->ClearAllPairings( base::Bind(&PairingRegistryTest::ExpectSaveSuccess, base::Unretained(this))); // Re-read the list, and verify it is empty. registry->GetAllPairings( base::Bind(&PairingRegistryTest::set_pairings, base::Unretained(this))); EXPECT_TRUE(pairings_->empty()); } ACTION_P(QuitMessageLoop, callback) { callback.Run(); } MATCHER_P(EqualsClientName, client_name, "") { return arg.client_name() == client_name; } MATCHER(NoPairings, "") { return arg->empty(); } TEST_F(PairingRegistryTest, SerializedRequests) { MockPairingRegistryCallbacks callbacks; Sequence s; EXPECT_CALL(callbacks, GetPairingCallback(EqualsClientName("client1"))) .InSequence(s); EXPECT_CALL(callbacks, GetPairingCallback(EqualsClientName("client2"))) .InSequence(s); EXPECT_CALL(callbacks, DoneCallback(true)) .InSequence(s); EXPECT_CALL(callbacks, GetPairingCallback(EqualsClientName("client1"))) .InSequence(s); EXPECT_CALL(callbacks, GetPairingCallback(EqualsClientName(""))) .InSequence(s); EXPECT_CALL(callbacks, DoneCallback(true)) .InSequence(s); EXPECT_CALL(callbacks, GetAllPairingsCallbackPtr(NoPairings())) .InSequence(s); EXPECT_CALL(callbacks, GetPairingCallback(EqualsClientName("client3"))) .InSequence(s) .WillOnce(QuitMessageLoop(run_loop_.QuitClosure())); scoped_refptr<PairingRegistry> registry = new PairingRegistry( base::ThreadTaskRunnerHandle::Get(), scoped_ptr<PairingRegistry::Delegate>(new MockPairingRegistryDelegate())); PairingRegistry::Pairing pairing_1 = registry->CreatePairing("client1"); PairingRegistry::Pairing pairing_2 = registry->CreatePairing("client2"); registry->GetPairing( pairing_1.client_id(), base::Bind(&MockPairingRegistryCallbacks::GetPairingCallback, base::Unretained(&callbacks))); registry->GetPairing( pairing_2.client_id(), base::Bind(&MockPairingRegistryCallbacks::GetPairingCallback, base::Unretained(&callbacks))); registry->DeletePairing( pairing_2.client_id(), base::Bind(&MockPairingRegistryCallbacks::DoneCallback, base::Unretained(&callbacks))); registry->GetPairing( pairing_1.client_id(), base::Bind(&MockPairingRegistryCallbacks::GetPairingCallback, base::Unretained(&callbacks))); registry->GetPairing( pairing_2.client_id(), base::Bind(&MockPairingRegistryCallbacks::GetPairingCallback, base::Unretained(&callbacks))); registry->ClearAllPairings( base::Bind(&MockPairingRegistryCallbacks::DoneCallback, base::Unretained(&callbacks))); registry->GetAllPairings( base::Bind(&MockPairingRegistryCallbacks::GetAllPairingsCallback, base::Unretained(&callbacks))); PairingRegistry::Pairing pairing_3 = registry->CreatePairing("client3"); registry->GetPairing( pairing_3.client_id(), base::Bind(&MockPairingRegistryCallbacks::GetPairingCallback, base::Unretained(&callbacks))); run_loop_.Run(); } } // namespace protocol } // namespace remoting