diff --git a/blimp/common/BUILD.gn b/blimp/common/BUILD.gn index 57dc9ca7cfa0e1..e0ca99834e26e9 100644 --- a/blimp/common/BUILD.gn +++ b/blimp/common/BUILD.gn @@ -66,6 +66,7 @@ source_set("unit_tests") { deps = [ ":common", + ":test_support", "//base", "//blimp/common/proto", "//blimp/net:test_support", diff --git a/blimp/common/blob_cache/blob_cache.h b/blimp/common/blob_cache/blob_cache.h index 45c9eb9de438a9..1f8a2932723640 100644 --- a/blimp/common/blob_cache/blob_cache.h +++ b/blimp/common/blob_cache/blob_cache.h @@ -14,8 +14,11 @@ namespace blimp { using BlobId = std::string; -using BlobData = base::RefCountedData; -using BlobDataPtr = scoped_refptr; +using BlobData = base::RefCountedData; + +// Immutable, ref-counted representation of blob payloads, suitable for sharing +// across threads. +using BlobDataPtr = scoped_refptr; // An interface for a cache of blobs. class BLIMP_COMMON_EXPORT BlobCache { diff --git a/blimp/common/blob_cache/in_memory_blob_cache_unittest.cc b/blimp/common/blob_cache/in_memory_blob_cache_unittest.cc index 6eb98ff6c4aa39..9cc24d71d13e4b 100644 --- a/blimp/common/blob_cache/in_memory_blob_cache_unittest.cc +++ b/blimp/common/blob_cache/in_memory_blob_cache_unittest.cc @@ -11,6 +11,7 @@ #include "base/memory/ref_counted.h" #include "blimp/common/blob_cache/blob_cache.h" #include "blimp/common/blob_cache/in_memory_blob_cache.h" +#include "blimp/common/blob_cache/test_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace blimp { @@ -21,10 +22,6 @@ const char kBar[] = "bar"; const char kDeadbeef[] = "\xde\xad\xbe\xef"; const char kForbiddenCode[] = "\x4b\x1d\xc0\xd3"; -BlobDataPtr CreateBlobDataPtr(const std::string& data) { - return new BlobData(data); -} - class InMemoryBlobCacheTest : public testing::Test { public: InMemoryBlobCacheTest() {} diff --git a/blimp/common/create_blimp_message.cc b/blimp/common/create_blimp_message.cc index 460560c6851c65..a3af17d6c8baf4 100644 --- a/blimp/common/create_blimp_message.cc +++ b/blimp/common/create_blimp_message.cc @@ -8,6 +8,7 @@ #include "base/logging.h" #include "blimp/common/proto/blimp_message.pb.h" +#include "blimp/common/proto/blob_channel.pb.h" #include "blimp/common/proto/compositor.pb.h" #include "blimp/common/proto/input.pb.h" #include "blimp/common/proto/render_widget.pb.h" @@ -80,6 +81,13 @@ std::unique_ptr CreateBlimpMessage( return output; } +std::unique_ptr CreateBlimpMessage( + BlobChannelMessage** blob_channel_message) { + std::unique_ptr output(new BlimpMessage); + *blob_channel_message = output->mutable_blob_channel(); + return output; +} + std::unique_ptr CreateStartConnectionMessage( const std::string& client_token, int protocol_version) { diff --git a/blimp/common/create_blimp_message.h b/blimp/common/create_blimp_message.h index ab8a16dd873e1e..e201459c67e153 100644 --- a/blimp/common/create_blimp_message.h +++ b/blimp/common/create_blimp_message.h @@ -15,6 +15,7 @@ namespace blimp { class BlimpMessage; +class BlobChannelMessage; class CompositorMessage; class EngineSettingsMessage; class ImeMessage; @@ -66,6 +67,9 @@ BLIMP_COMMON_EXPORT std::unique_ptr CreateBlimpMessage( BLIMP_COMMON_EXPORT std::unique_ptr CreateBlimpMessage( EngineSettingsMessage** engine_settings); +BLIMP_COMMON_EXPORT std::unique_ptr CreateBlimpMessage( + BlobChannelMessage** blob_channel_message); + BLIMP_COMMON_EXPORT std::unique_ptr CreateStartConnectionMessage( const std::string& client_token, int protocol_version); diff --git a/blimp/common/create_blimp_message_unittest.cc b/blimp/common/create_blimp_message_unittest.cc index 063eed58aadbc9..2546b784903fb1 100644 --- a/blimp/common/create_blimp_message_unittest.cc +++ b/blimp/common/create_blimp_message_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/memory/ptr_util.h" #include "blimp/common/create_blimp_message.h" #include "blimp/common/proto/blimp_message.pb.h" #include "blimp/common/proto/compositor.pb.h" @@ -92,5 +93,13 @@ TEST(CreateBlimpMessageTest, StartConnectionMessage) { message->protocol_control().start_connection().protocol_version()); } +TEST(CreateBlimpMessageTest, BlobChannelMessage) { + BlobChannelMessage* details; + std::unique_ptr message = CreateBlimpMessage(&details); + ASSERT_TRUE(message); + EXPECT_EQ(details, &message->blob_channel()); + EXPECT_EQ(BlimpMessage::kBlobChannel, message->feature_case()); +} + } // namespace } // namespace blimp diff --git a/blimp/common/logging.cc b/blimp/common/logging.cc index fc612ac531283a..174c2b4554a111 100644 --- a/blimp/common/logging.cc +++ b/blimp/common/logging.cc @@ -12,8 +12,10 @@ #include "base/json/string_escape.h" #include "base/lazy_instance.h" #include "base/memory/ptr_util.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "blimp/common/create_blimp_message.h" #include "blimp/common/proto/blimp_message.pb.h" namespace blimp { @@ -248,6 +250,28 @@ class TabControlLogExtractor : public LogExtractor { } }; +// Logs fields from BLOB_CHANNEL messages. +class BlobChannelLogExtractor : public LogExtractor { + void ExtractFields(const BlimpMessage& message, + LogFields* output) const override { + switch (message.blob_channel().type_case()) { + case BlobChannelMessage::TypeCase::kTransferBlob: + AddField("subtype", "TRANSFER_BLOB", output); + AddField("id", + base::HexEncode( + message.blob_channel().transfer_blob().blob_id().data(), + message.blob_channel().transfer_blob().blob_id().size()), + output); + AddField("payload_size", + message.blob_channel().transfer_blob().payload().size(), + output); + break; + case BlobChannelMessage::TypeCase::TYPE_NOT_SET: // unknown + break; + } + } +}; + // No fields are extracted from |message|. class NullLogExtractor : public LogExtractor { void ExtractFields(const BlimpMessage& message, @@ -271,6 +295,8 @@ BlimpMessageLogger::BlimpMessageLogger() { base::WrapUnique(new SettingsLogExtractor)); AddHandler("TAB_CONTROL", BlimpMessage::kTabControl, base::WrapUnique(new TabControlLogExtractor)); + AddHandler("BLOB_CHANNEL", BlimpMessage::kBlobChannel, + base::WrapUnique(new BlobChannelLogExtractor)); } BlimpMessageLogger::~BlimpMessageLogger() {} diff --git a/blimp/common/logging_unittest.cc b/blimp/common/logging_unittest.cc index 58b4b742935aaa..6d2edbd4be950d 100644 --- a/blimp/common/logging_unittest.cc +++ b/blimp/common/logging_unittest.cc @@ -7,8 +7,10 @@ #include "base/at_exit.h" #include "base/strings/stringprintf.h" +#include "blimp/common/create_blimp_message.h" #include "blimp/common/logging.h" #include "blimp/common/proto/blimp_message.pb.h" +#include "blimp/common/proto/blob_channel.pb.h" #include "blimp/net/test_common.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -220,6 +222,18 @@ TEST_F(LoggingTest, RenderWidget) { deleted_msg); } +TEST_F(LoggingTest, BlobChannel) { + BlobChannelMessage* blob_message = nullptr; + std::unique_ptr blimp_message = + CreateBlimpMessage(&blob_message); + blob_message->mutable_transfer_blob()->set_blob_id("AAA"); + blob_message->mutable_transfer_blob()->set_payload("123"); + + VerifyLogOutput( + "type=BLOB_CHANNEL subtype=TRANSFER_BLOB id=\"414141\" payload_size=3", + *blimp_message); +} + TEST_F(LoggingTest, Settings) { BlimpMessage message; message.mutable_settings() diff --git a/blimp/common/proto/BUILD.gn b/blimp/common/proto/BUILD.gn index a56bfa6c4d96b4..de71aee082193d 100644 --- a/blimp/common/proto/BUILD.gn +++ b/blimp/common/proto/BUILD.gn @@ -27,6 +27,7 @@ proto_library("proto_internal") { sources = [ "blimp_message.proto", "blob_cache.proto", + "blob_channel.proto", "compositor.proto", "ime.proto", "input.proto", diff --git a/blimp/common/proto/blimp_message.proto b/blimp/common/proto/blimp_message.proto index 4efdd8813036ec..b0580ef2bbbf4b 100644 --- a/blimp/common/proto/blimp_message.proto +++ b/blimp/common/proto/blimp_message.proto @@ -23,6 +23,7 @@ syntax = "proto2"; option optimize_for = LITE_RUNTIME; +import "blob_channel.proto"; import "compositor.proto"; import "ime.proto"; import "input.proto"; @@ -61,6 +62,7 @@ message BlimpMessage { ProtocolControlMessage protocol_control = 45; ImeMessage ime = 46; SettingsMessage settings = 47; + BlobChannelMessage blob_channel = 48; } } diff --git a/blimp/common/proto/blob_channel.proto b/blimp/common/proto/blob_channel.proto new file mode 100644 index 00000000000000..0f862f71cb2e42 --- /dev/null +++ b/blimp/common/proto/blob_channel.proto @@ -0,0 +1,21 @@ +// Copyright 2016 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. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package blimp; + +message TransferBlob { + optional string blob_id = 1; + optional bytes payload = 2; +} + +message BlobChannelMessage { + oneof type { + // Engine => Client types. + TransferBlob transfer_blob = 1; + } +} diff --git a/blimp/net/BUILD.gn b/blimp/net/BUILD.gn index dae07a1426f0a9..bad2a509ae5fae 100644 --- a/blimp/net/BUILD.gn +++ b/blimp/net/BUILD.gn @@ -27,6 +27,10 @@ component("net") { "blob_channel/blob_channel_receiver.h", "blob_channel/blob_channel_sender.cc", "blob_channel/blob_channel_sender.h", + "blob_channel/helium_blob_receiver_delegate.cc", + "blob_channel/helium_blob_receiver_delegate.h", + "blob_channel/helium_blob_sender_delegate.cc", + "blob_channel/helium_blob_sender_delegate.h", "browser_connection_handler.cc", "browser_connection_handler.h", "client_connection_manager.cc", @@ -84,6 +88,8 @@ source_set("test_support") { testonly = true sources = [ + "blob_channel/mock_blob_channel_receiver.cc", + "blob_channel/mock_blob_channel_receiver.h", "test_common.cc", "test_common.h", ] @@ -110,6 +116,7 @@ source_set("unit_tests") { "blob_channel/blob_channel_integration_test.cc", "blob_channel/blob_channel_receiver_unittest.cc", "blob_channel/blob_channel_sender_unittest.cc", + "blob_channel/helium_blob_channel_unittest.cc", "browser_connection_handler_unittest.cc", "client_connection_manager_unittest.cc", "compressed_packet_unittest.cc", diff --git a/blimp/net/blob_channel/blob_channel_integration_test.cc b/blimp/net/blob_channel/blob_channel_integration_test.cc index fe5b54d52e76a3..3ef93393a64ece 100644 --- a/blimp/net/blob_channel/blob_channel_integration_test.cc +++ b/blimp/net/blob_channel/blob_channel_integration_test.cc @@ -12,6 +12,7 @@ #include "blimp/common/blob_cache/test_util.h" #include "blimp/net/blob_channel/blob_channel_receiver.h" #include "blimp/net/blob_channel/blob_channel_sender.h" +#include "blimp/net/blob_channel/mock_blob_channel_receiver.h" #include "blimp/net/test_common.h" #include "testing/gtest/include/gtest/gtest.h" @@ -29,30 +30,19 @@ const char kBlobPayload[] = "bar1"; // after |this| is deleted. class SenderDelegateProxy : public BlobChannelSender::Delegate { public: - SenderDelegateProxy() {} + explicit SenderDelegateProxy(BlobChannelReceiver* receiver) + : receiver_(receiver) {} ~SenderDelegateProxy() override {} - // Returns a receiver object that will receive proxied calls sent to |this|. - std::unique_ptr GetReceiverDelegate() { - DCHECK(!receiver_); - receiver_ = new ReceiverDelegate; - return base::WrapUnique(receiver_); - } - private: - class ReceiverDelegate : public BlobChannelReceiver::Delegate { - public: - using BlobChannelReceiver::Delegate::OnBlobReceived; - }; - // BlobChannelSender implementation. void DeliverBlob(const BlobId& id, BlobDataPtr data) override { base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&ReceiverDelegate::OnBlobReceived, + FROM_HERE, base::Bind(&BlobChannelReceiver::OnBlobReceived, base::Unretained(receiver_), id, data)); } - ReceiverDelegate* receiver_ = nullptr; + BlobChannelReceiver* receiver_; DISALLOW_COPY_AND_ASSIGN(SenderDelegateProxy); }; @@ -62,18 +52,28 @@ class SenderDelegateProxy : public BlobChannelSender::Delegate { class BlobChannelIntegrationTest : public testing::Test { public: BlobChannelIntegrationTest() { - std::unique_ptr sender_delegate( - new SenderDelegateProxy); - receiver_.reset( - new BlobChannelReceiver(base::WrapUnique(new InMemoryBlobCache), - sender_delegate->GetReceiverDelegate())); - sender_.reset(new BlobChannelSender(base::WrapUnique(new InMemoryBlobCache), - std::move(sender_delegate))); + BlobChannelReceiver* stored_receiver; + std::unique_ptr receiver_delegate( + new MockBlobChannelReceiverDelegate); + receiver_delegate_ = receiver_delegate.get(); + + EXPECT_CALL(*receiver_delegate, SetReceiver(_)) + .WillOnce(SaveArg<0>(&stored_receiver)); + + receiver_ = BlobChannelReceiver::Create( + base::WrapUnique(new InMemoryBlobCache), std::move(receiver_delegate)); + + EXPECT_EQ(receiver_.get(), stored_receiver); + + sender_.reset(new BlobChannelSender( + base::WrapUnique(new InMemoryBlobCache), + base::WrapUnique(new SenderDelegateProxy(receiver_.get())))); } ~BlobChannelIntegrationTest() override {} protected: + MockBlobChannelReceiverDelegate* receiver_delegate_; std::unique_ptr receiver_; std::unique_ptr sender_; base::MessageLoop message_loop_; diff --git a/blimp/net/blob_channel/blob_channel_receiver.cc b/blimp/net/blob_channel/blob_channel_receiver.cc index 7200dd3219e3b1..da89c2f6b7f8ba 100644 --- a/blimp/net/blob_channel/blob_channel_receiver.cc +++ b/blimp/net/blob_channel/blob_channel_receiver.cc @@ -6,46 +6,64 @@ #include "base/logging.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "blimp/common/blob_cache/blob_cache.h" namespace blimp { +namespace { -BlobChannelReceiver::Delegate::Delegate() {} +// Takes incoming blobs from |delegate_| stores them in |cache_|, and provides +// callers a getter interface for accessing blobs from |cache_|. +class BLIMP_NET_EXPORT BlobChannelReceiverImpl : public BlobChannelReceiver { + public: + BlobChannelReceiverImpl(std::unique_ptr cache, + std::unique_ptr delegate); + ~BlobChannelReceiverImpl() override; -BlobChannelReceiver::Delegate::~Delegate() { - DCHECK(!receiver_); -} + // BlobChannelReceiver implementation. + BlobDataPtr Get(const BlobId& id) override; + void OnBlobReceived(const BlobId& id, BlobDataPtr data) override; -void BlobChannelReceiver::Delegate::SetReceiver(BlobChannelReceiver* receiver) { - receiver_ = receiver; -} + private: + std::unique_ptr cache_; + std::unique_ptr delegate_; + + // Guards against concurrent access to |cache_|. + base::Lock cache_lock_; + + DISALLOW_COPY_AND_ASSIGN(BlobChannelReceiverImpl); +}; -void BlobChannelReceiver::Delegate::OnBlobReceived(const BlobId& id, - BlobDataPtr data) { - if (receiver_) { - receiver_->OnBlobReceived(id, data); - } +} // namespace + +// static +std::unique_ptr BlobChannelReceiver::Create( + std::unique_ptr cache, + std::unique_ptr delegate) { + return base::WrapUnique( + new BlobChannelReceiverImpl(std::move(cache), std::move(delegate))); } -BlobChannelReceiver::BlobChannelReceiver(std::unique_ptr cache, - std::unique_ptr delegate) +BlobChannelReceiverImpl::BlobChannelReceiverImpl( + std::unique_ptr cache, + std::unique_ptr delegate) : cache_(std::move(cache)), delegate_(std::move(delegate)) { DCHECK(cache_); + delegate_->SetReceiver(this); } -BlobChannelReceiver::~BlobChannelReceiver() { - delegate_->SetReceiver(nullptr); -} +BlobChannelReceiverImpl::~BlobChannelReceiverImpl() {} -BlobDataPtr BlobChannelReceiver::Get(const BlobId& id) { +BlobDataPtr BlobChannelReceiverImpl::Get(const BlobId& id) { DVLOG(2) << "Get blob: " << id; base::AutoLock lock(cache_lock_); return cache_->Get(id); } -void BlobChannelReceiver::OnBlobReceived(const BlobId& id, BlobDataPtr data) { +void BlobChannelReceiverImpl::OnBlobReceived(const BlobId& id, + BlobDataPtr data) { DVLOG(2) << "Blob received: " << id; base::AutoLock lock(cache_lock_); diff --git a/blimp/net/blob_channel/blob_channel_receiver.h b/blimp/net/blob_channel/blob_channel_receiver.h index bdfcd236bd62e5..d9ae4a03db921e 100644 --- a/blimp/net/blob_channel/blob_channel_receiver.h +++ b/blimp/net/blob_channel/blob_channel_receiver.h @@ -16,52 +16,31 @@ namespace blimp { class BlobCache; -// Receives blobs from a remote sender. class BLIMP_NET_EXPORT BlobChannelReceiver { public: class Delegate { public: - Delegate(); - virtual ~Delegate(); - - protected: - // Forwards incoming blob data to |receiver_|. - void OnBlobReceived(const BlobId& id, BlobDataPtr data); - - private: - friend class BlobChannelReceiver; + virtual ~Delegate() {} // Sets the Receiver object which will take incoming blobs. - void SetReceiver(BlobChannelReceiver* receiver); - - BlobChannelReceiver* receiver_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(Delegate); + virtual void SetReceiver(BlobChannelReceiver* receiver) = 0; }; - BlobChannelReceiver(std::unique_ptr cache, - std::unique_ptr delegate); - ~BlobChannelReceiver(); + virtual ~BlobChannelReceiver() {} + + // Constructs a BlobChannelReceiverImpl object for use. + static std::unique_ptr Create( + std::unique_ptr cache, + std::unique_ptr delegate); // Gets a blob from the BlobChannel. // Returns nullptr if the blob is not available in the channel. // Can be accessed concurrently from any thread. Calling code must ensure that // the object instance outlives all calls to Get(). - BlobDataPtr Get(const BlobId& id); - - private: - friend class Delegate; + virtual BlobDataPtr Get(const BlobId& id) = 0; // Called by Delegate::OnBlobReceived() when a blob arrives over the channel. - void OnBlobReceived(const BlobId& id, BlobDataPtr data); - - std::unique_ptr cache_; - std::unique_ptr delegate_; - - // Guards against concurrent access to |cache_|. - base::Lock cache_lock_; - - DISALLOW_COPY_AND_ASSIGN(BlobChannelReceiver); + virtual void OnBlobReceived(const BlobId& id, BlobDataPtr data) = 0; }; } // namespace blimp diff --git a/blimp/net/blob_channel/blob_channel_receiver_unittest.cc b/blimp/net/blob_channel/blob_channel_receiver_unittest.cc index 3a42ffe3d6c7ec..62b675550ce5c0 100644 --- a/blimp/net/blob_channel/blob_channel_receiver_unittest.cc +++ b/blimp/net/blob_channel/blob_channel_receiver_unittest.cc @@ -10,6 +10,7 @@ #include "base/memory/ref_counted.h" #include "blimp/common/blob_cache/mock_blob_cache.h" #include "blimp/net/blob_channel/blob_channel_receiver.h" +#include "blimp/net/blob_channel/mock_blob_channel_receiver.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -18,6 +19,7 @@ namespace { using testing::_; using testing::Return; +using testing::SaveArg; const char kBlobId[] = "blob-1"; const char kBlobPayload[] = "blob-1-payload"; @@ -31,26 +33,26 @@ MATCHER_P(BlobDataEqual, expected, "") { return expected->data == arg->data; } -class NullBlobReceiverDelegate : public BlobChannelReceiver::Delegate { - public: - using BlobChannelReceiver::Delegate::OnBlobReceived; -}; - class BlobChannelReceiverTest : public testing::Test { public: - BlobChannelReceiverTest() - : delegate_(new NullBlobReceiverDelegate), - cache_(new testing::StrictMock), - blob_receiver_(new BlobChannelReceiver(base::WrapUnique(cache_), - base::WrapUnique(delegate_))) + BlobChannelReceiverTest() : cache_(new testing::StrictMock) { + BlobChannelReceiver* stored_receiver; + std::unique_ptr receiver_delegate( + new MockBlobChannelReceiverDelegate); + receiver_delegate_ = receiver_delegate.get(); + + EXPECT_CALL(*receiver_delegate, SetReceiver(_)) + .WillOnce(SaveArg<0>(&stored_receiver)); - {} + blob_receiver_ = BlobChannelReceiver::Create(base::WrapUnique(cache_), + std::move(receiver_delegate)); + } ~BlobChannelReceiverTest() override {} - NullBlobReceiverDelegate* delegate_; testing::StrictMock* cache_; std::unique_ptr blob_receiver_; + MockBlobChannelReceiverDelegate* receiver_delegate_; }; TEST_F(BlobChannelReceiverTest, GetKnownBlob) { @@ -69,7 +71,7 @@ TEST_F(BlobChannelReceiverTest, GetFromDelegateReceiveMethod) { EXPECT_CALL(*cache_, Put(kBlobId, BlobDataEqual(payload))); EXPECT_CALL(*cache_, Get(kBlobId)).WillOnce(Return(payload)); - delegate_->OnBlobReceived(kBlobId, payload); + blob_receiver_->OnBlobReceived(kBlobId, payload); auto result = blob_receiver_->Get(kBlobId); diff --git a/blimp/net/blob_channel/helium_blob_channel_unittest.cc b/blimp/net/blob_channel/helium_blob_channel_unittest.cc new file mode 100644 index 00000000000000..38a81e8387c6fc --- /dev/null +++ b/blimp/net/blob_channel/helium_blob_channel_unittest.cc @@ -0,0 +1,73 @@ +// Copyright 2016 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 + +#include "base/memory/ptr_util.h" +#include "blimp/common/blob_cache/id_util.h" +#include "blimp/common/blob_cache/test_util.h" +#include "blimp/net/blob_channel/helium_blob_receiver_delegate.h" +#include "blimp/net/blob_channel/helium_blob_sender_delegate.h" +#include "blimp/net/blob_channel/mock_blob_channel_receiver.h" +#include "blimp/net/test_common.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blimp { +namespace { + +using testing::_; +using testing::SaveArg; + +const char kBlobId[] = "foo1"; +const char kBlobPayload[] = "bar1"; + +class HeliumBlobChannelTest : public testing::Test { + public: + HeliumBlobChannelTest() : receiver_delegate_(new HeliumBlobReceiverDelegate) { + receiver_delegate_->SetReceiver(&mock_receiver_); + sender_delegate_.set_outgoing_message_processor( + base::WrapUnique(receiver_delegate_)); + } + + ~HeliumBlobChannelTest() override {} + + protected: + const std::string blob_id_ = CalculateBlobId(kBlobId); + + MockBlobChannelReceiver mock_receiver_; + HeliumBlobReceiverDelegate* receiver_delegate_; + HeliumBlobSenderDelegate sender_delegate_; + + private: + DISALLOW_COPY_AND_ASSIGN(HeliumBlobChannelTest); +}; + +// Verifies the content of BlimpMessages generated by the Sender. +TEST_F(HeliumBlobChannelTest, TransferBlobContents) { + BlimpMessage captured_msg; + MockBlimpMessageProcessor* mock_processor = new MockBlimpMessageProcessor; + EXPECT_CALL(*mock_processor, MockableProcessMessage(_, _)) + .WillOnce(SaveArg<0>(&captured_msg)); + sender_delegate_.set_outgoing_message_processor( + base::WrapUnique(mock_processor)); + + sender_delegate_.DeliverBlob(blob_id_, CreateBlobDataPtr(kBlobPayload)); + + EXPECT_EQ(BlobChannelMessage::TypeCase::kTransferBlob, + captured_msg.blob_channel().type_case()); + EXPECT_EQ(blob_id_, captured_msg.blob_channel().transfer_blob().blob_id()); + EXPECT_EQ(kBlobPayload, + captured_msg.blob_channel().transfer_blob().payload()); +} + +// Verifies that the Receiver understands messages sent by the Sender. +TEST_F(HeliumBlobChannelTest, TransferBlobCompatibility) { + EXPECT_CALL(mock_receiver_, + OnBlobReceived(blob_id_, BlobDataPtrEqualsString(kBlobPayload))); + sender_delegate_.DeliverBlob(blob_id_, CreateBlobDataPtr(kBlobPayload)); +} + +} // namespace +} // namespace blimp diff --git a/blimp/net/blob_channel/helium_blob_receiver_delegate.cc b/blimp/net/blob_channel/helium_blob_receiver_delegate.cc new file mode 100644 index 00000000000000..b433b79e3b0f2d --- /dev/null +++ b/blimp/net/blob_channel/helium_blob_receiver_delegate.cc @@ -0,0 +1,54 @@ +// Copyright 2016 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 "blimp/net/blob_channel/helium_blob_receiver_delegate.h" + +#include "blimp/common/blob_cache/blob_cache.h" +#include "blimp/common/proto/blimp_message.pb.h" +#include "blimp/common/proto/blob_channel.pb.h" +#include "net/base/net_errors.h" + +namespace blimp { + +HeliumBlobReceiverDelegate::HeliumBlobReceiverDelegate() {} + +HeliumBlobReceiverDelegate::~HeliumBlobReceiverDelegate() {} + +void HeliumBlobReceiverDelegate::SetReceiver(BlobChannelReceiver* receiver) { + DCHECK(receiver); + receiver_ = receiver; +} + +void HeliumBlobReceiverDelegate::ProcessMessage( + std::unique_ptr message, + const net::CompletionCallback& callback) { + if (!message->has_blob_channel()) { + DLOG(WARNING) << "BlobChannel message has no |blob_channel| submessage."; + callback.Run(net::ERR_INVALID_ARGUMENT); + return; + } + + // Take a mutable pointer to the blob_channel message so that we can re-use + // its allocated buffers. + BlobChannelMessage* blob_msg = message->mutable_blob_channel(); + if (blob_msg->type_case() != BlobChannelMessage::TypeCase::kTransferBlob) { + callback.Run(net::ERR_NOT_IMPLEMENTED); + return; + } + + if (blob_msg->transfer_blob().blob_id().empty()) { + callback.Run(net::ERR_INVALID_ARGUMENT); + return; + } + + // Create a temporarily non-const BlobData so that we may efficiently reuse + // the allocated payload string via string::swap(). + scoped_refptr blob_data(new BlobData); + blob_data->data.swap(*blob_msg->mutable_transfer_blob()->mutable_payload()); + receiver_->OnBlobReceived(blob_msg->transfer_blob().blob_id(), blob_data); + + callback.Run(net::OK); +} + +} // namespace blimp diff --git a/blimp/net/blob_channel/helium_blob_receiver_delegate.h b/blimp/net/blob_channel/helium_blob_receiver_delegate.h new file mode 100644 index 00000000000000..f2f817d94f9aa6 --- /dev/null +++ b/blimp/net/blob_channel/helium_blob_receiver_delegate.h @@ -0,0 +1,43 @@ +// Copyright 2016 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 BLIMP_NET_BLOB_CHANNEL_HELIUM_BLOB_RECEIVER_DELEGATE_H_ +#define BLIMP_NET_BLOB_CHANNEL_HELIUM_BLOB_RECEIVER_DELEGATE_H_ + +#include + +#include "blimp/net/blimp_message_processor.h" +#include "blimp/net/blimp_net_export.h" +#include "blimp/net/blob_channel/blob_channel_receiver.h" +#include "net/base/completion_callback.h" + +namespace blimp { + +// Receives and processes incoming blob messages in BlimpMessage format and +// passes them to an attached BlobChannelReceiver. +// The caller must provide the receiver object via SetReceiver() before any +// messages can be processed. +class BLIMP_NET_EXPORT HeliumBlobReceiverDelegate + : public BlobChannelReceiver::Delegate, + public BlimpMessageProcessor { + public: + HeliumBlobReceiverDelegate(); + ~HeliumBlobReceiverDelegate() override; + + // Sets the Receiver object which will take incoming blobs. + void SetReceiver(BlobChannelReceiver* receiver) override; + + private: + // BlimpMessageProcessor implementation. + void ProcessMessage(std::unique_ptr message, + const net::CompletionCallback& callback) override; + + BlobChannelReceiver* receiver_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(HeliumBlobReceiverDelegate); +}; + +} // namespace blimp + +#endif // BLIMP_NET_BLOB_CHANNEL_HELIUM_BLOB_RECEIVER_DELEGATE_H_ diff --git a/blimp/net/blob_channel/helium_blob_sender_delegate.cc b/blimp/net/blob_channel/helium_blob_sender_delegate.cc new file mode 100644 index 00000000000000..ac18fcfc4b3e47 --- /dev/null +++ b/blimp/net/blob_channel/helium_blob_sender_delegate.cc @@ -0,0 +1,40 @@ +// Copyright 2016 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 "blimp/net/blob_channel/helium_blob_sender_delegate.h" + +#include "blimp/common/create_blimp_message.h" +#include "blimp/common/proto/blimp_message.pb.h" +#include "blimp/common/proto/blob_channel.pb.h" +#include "net/base/net_errors.h" + +namespace blimp { +namespace { + +void DoNothingCompletionCallback(int) {} + +} // namespace + +HeliumBlobSenderDelegate::HeliumBlobSenderDelegate() {} + +HeliumBlobSenderDelegate::~HeliumBlobSenderDelegate() {} + +void HeliumBlobSenderDelegate::DeliverBlob(const BlobId& id, BlobDataPtr data) { + BlobChannelMessage* blob_message; + std::unique_ptr message = CreateBlimpMessage(&blob_message); + blob_message->mutable_transfer_blob()->set_payload(&data->data[0], + data->data.size()); + blob_message->mutable_transfer_blob()->set_blob_id(id); + outgoing_processor_->ProcessMessage(std::move(message), + base::Bind(&DoNothingCompletionCallback)); +} + +void HeliumBlobSenderDelegate::ProcessMessage( + std::unique_ptr message, + const net::CompletionCallback& callback) { + NOTIMPLEMENTED(); + callback.Run(net::ERR_NOT_IMPLEMENTED); +} + +} // namespace blimp diff --git a/blimp/net/blob_channel/helium_blob_sender_delegate.h b/blimp/net/blob_channel/helium_blob_sender_delegate.h new file mode 100644 index 00000000000000..4d8367e73d2477 --- /dev/null +++ b/blimp/net/blob_channel/helium_blob_sender_delegate.h @@ -0,0 +1,47 @@ +// Copyright 2016 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 BLIMP_NET_BLOB_CHANNEL_HELIUM_BLOB_SENDER_DELEGATE_H_ +#define BLIMP_NET_BLOB_CHANNEL_HELIUM_BLOB_SENDER_DELEGATE_H_ + +#include +#include + +#include "blimp/net/blimp_message_processor.h" +#include "blimp/net/blimp_net_export.h" +#include "blimp/net/blob_channel/blob_channel_receiver.h" +#include "blimp/net/blob_channel/blob_channel_sender.h" + +namespace blimp { + +// Sends blob messages as Helium messages to a BlimpMessageProcessor. +class BLIMP_NET_EXPORT HeliumBlobSenderDelegate + : public BlobChannelSender::Delegate, + public BlimpMessageProcessor { + public: + HeliumBlobSenderDelegate(); + ~HeliumBlobSenderDelegate() override; + + // Sets the message processor to which blob messages will be sent. + void set_outgoing_message_processor( + std::unique_ptr processor) { + outgoing_processor_ = std::move(processor); + } + + // BlobSender::Delegate implementation. + void DeliverBlob(const BlobId& id, BlobDataPtr data) override; + + private: + // BlimpMessageProcessor implementation. + void ProcessMessage(std::unique_ptr message, + const net::CompletionCallback& callback) override; + + std::unique_ptr outgoing_processor_; + + DISALLOW_COPY_AND_ASSIGN(HeliumBlobSenderDelegate); +}; + +} // namespace blimp + +#endif // BLIMP_NET_BLOB_CHANNEL_HELIUM_BLOB_SENDER_DELEGATE_H_ diff --git a/blimp/net/blob_channel/mock_blob_channel_receiver.cc b/blimp/net/blob_channel/mock_blob_channel_receiver.cc new file mode 100644 index 00000000000000..f5bd4405479a22 --- /dev/null +++ b/blimp/net/blob_channel/mock_blob_channel_receiver.cc @@ -0,0 +1,15 @@ +// Copyright 2016 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 "blimp/net/blob_channel/mock_blob_channel_receiver.h" + +namespace blimp { + +MockBlobChannelReceiver::MockBlobChannelReceiver() {} +MockBlobChannelReceiver::~MockBlobChannelReceiver() {} + +MockBlobChannelReceiverDelegate::MockBlobChannelReceiverDelegate() {} +MockBlobChannelReceiverDelegate::~MockBlobChannelReceiverDelegate() {} + +} // namespace blimp diff --git a/blimp/net/blob_channel/mock_blob_channel_receiver.h b/blimp/net/blob_channel/mock_blob_channel_receiver.h new file mode 100644 index 00000000000000..64d9e7557fce09 --- /dev/null +++ b/blimp/net/blob_channel/mock_blob_channel_receiver.h @@ -0,0 +1,41 @@ +// Copyright 2016 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 BLIMP_NET_BLOB_CHANNEL_MOCK_BLOB_CHANNEL_RECEIVER_H_ +#define BLIMP_NET_BLOB_CHANNEL_MOCK_BLOB_CHANNEL_RECEIVER_H_ + +#include +#include + +#include "blimp/net/blob_channel/blob_channel_receiver.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace blimp { + +class MockBlobChannelReceiver : public BlobChannelReceiver { + public: + MockBlobChannelReceiver(); + ~MockBlobChannelReceiver(); + + MOCK_METHOD1(Get, BlobDataPtr(const BlobId& id)); + MOCK_METHOD2(OnBlobReceived, void(const BlobId& id, BlobDataPtr data)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockBlobChannelReceiver); +}; + +class MockBlobChannelReceiverDelegate : public BlobChannelReceiver::Delegate { + public: + MockBlobChannelReceiverDelegate(); + ~MockBlobChannelReceiverDelegate() override; + + MOCK_METHOD1(SetReceiver, void(BlobChannelReceiver* receiver)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockBlobChannelReceiverDelegate); +}; + +} // namespace blimp + +#endif // BLIMP_NET_BLOB_CHANNEL_MOCK_BLOB_CHANNEL_RECEIVER_H_ diff --git a/blimp/net/test_common.h b/blimp/net/test_common.h index 5aaae7eee0a4ca..c726feba5a8c26 100644 --- a/blimp/net/test_common.h +++ b/blimp/net/test_common.h @@ -60,6 +60,11 @@ MATCHER_P(BufferEqualsProto, message, "") { return expected_serialized == actual_serialized; } +// Checks if the contents of a BlobDataPtr match the string |expected|. +MATCHER_P(BlobDataPtrEqualsString, expected, "") { + return expected == arg->data; +} + // GMock action that writes data from a string to an IOBuffer. // // buf_idx (template parameter 0): 0-based index of the IOBuffer arg.