// Copyright 2015 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 #include "base/callback_helpers.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "blimp/common/proto/blimp_message.pb.h" #include "blimp/net/blimp_message_processor.h" #include "blimp/net/browser_connection_handler.h" #include "blimp/net/common.h" #include "blimp/net/connection_error_observer.h" #include "blimp/net/test_common.h" #include "net/base/completion_callback.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using testing::_; using testing::InSequence; using testing::Return; using testing::SaveArg; namespace blimp { namespace { // Compares two blimp messages and ignores message_id field. MATCHER_P(EqualsMessageIgnoringId, message, "") { BlimpMessage expected_message = message; expected_message.clear_message_id(); BlimpMessage actual_message = arg; actual_message.clear_message_id(); std::string expected_serialized; std::string actual_serialized; expected_message.SerializeToString(&expected_serialized); actual_message.SerializeToString(&actual_serialized); return expected_serialized == actual_serialized; } class FakeFeature { public: FakeFeature(BlimpMessage::Type type, BrowserConnectionHandler* connection_handler) { outgoing_message_processor_ = connection_handler->RegisterFeature(type, &incoming_message_processor_); } ~FakeFeature() {} BlimpMessageProcessor* outgoing_message_processor() { return outgoing_message_processor_.get(); } MockBlimpMessageProcessor* incoming_message_processor() { return &incoming_message_processor_; } private: testing::StrictMock incoming_message_processor_; scoped_ptr outgoing_message_processor_; }; class FakeBlimpConnection : public BlimpConnection, public BlimpMessageProcessor { public: FakeBlimpConnection() {} ~FakeBlimpConnection() override {} void set_other_end(FakeBlimpConnection* other_end) { other_end_ = other_end; } ConnectionErrorObserver* error_observer() { return error_observer_; } // BlimpConnection implementation. void AddConnectionErrorObserver(ConnectionErrorObserver* observer) override { error_observer_ = observer; } void SetIncomingMessageProcessor(BlimpMessageProcessor* processor) override { incoming_message_processor_ = processor; } BlimpMessageProcessor* GetOutgoingMessageProcessor() override { return this; } private: void ForwardMessage(scoped_ptr message) { other_end_->incoming_message_processor_->ProcessMessage( std::move(message), net::CompletionCallback()); } // BlimpMessageProcessor implementation. void ProcessMessage(scoped_ptr message, const net::CompletionCallback& callback) override { base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&FakeBlimpConnection::ForwardMessage, base::Unretained(this), base::Passed(&message))); callback.Run(net::OK); } FakeBlimpConnection* other_end_ = nullptr; ConnectionErrorObserver* error_observer_ = nullptr; BlimpMessageProcessor* incoming_message_processor_ = nullptr; }; scoped_ptr CreateInputMessage(int tab_id) { scoped_ptr output(new BlimpMessage); output->set_type(BlimpMessage::INPUT); output->set_target_tab_id(tab_id); return output; } scoped_ptr CreateControlMessage(int tab_id) { scoped_ptr output(new BlimpMessage); output->set_type(BlimpMessage::TAB_CONTROL); output->set_target_tab_id(tab_id); return output; } class BrowserConnectionHandlerTest : public testing::Test { public: BrowserConnectionHandlerTest() : client_connection_handler_(new BrowserConnectionHandler), engine_connection_handler_(new BrowserConnectionHandler) { SetupConnections(); client_input_feature_.reset( new FakeFeature(BlimpMessage::INPUT, client_connection_handler_.get())); engine_input_feature_.reset( new FakeFeature(BlimpMessage::INPUT, engine_connection_handler_.get())); client_control_feature_.reset(new FakeFeature( BlimpMessage::TAB_CONTROL, client_connection_handler_.get())); engine_control_feature_.reset(new FakeFeature( BlimpMessage::TAB_CONTROL, engine_connection_handler_.get())); } ~BrowserConnectionHandlerTest() override {} void TearDown() override { base::RunLoop().RunUntilIdle(); } protected: void SetupConnections() { client_connection_ = new FakeBlimpConnection(); engine_connection_ = new FakeBlimpConnection(); client_connection_->set_other_end(engine_connection_); engine_connection_->set_other_end(client_connection_); client_connection_handler_->HandleConnection( make_scoped_ptr(client_connection_)); engine_connection_handler_->HandleConnection( make_scoped_ptr(engine_connection_)); } base::MessageLoop message_loop_; FakeBlimpConnection* client_connection_; FakeBlimpConnection* engine_connection_; scoped_ptr client_connection_handler_; scoped_ptr engine_connection_handler_; scoped_ptr client_input_feature_; scoped_ptr engine_input_feature_; scoped_ptr client_control_feature_; scoped_ptr engine_control_feature_; }; TEST_F(BrowserConnectionHandlerTest, ExchangeMessages) { scoped_ptr client_input_message = CreateInputMessage(1); scoped_ptr client_control_message = CreateControlMessage(1); scoped_ptr engine_control_message = CreateControlMessage(2); EXPECT_CALL( *(engine_input_feature_->incoming_message_processor()), MockableProcessMessage(EqualsMessageIgnoringId(*client_input_message), _)) .RetiresOnSaturation(); EXPECT_CALL(*(engine_control_feature_->incoming_message_processor()), MockableProcessMessage( EqualsMessageIgnoringId(*client_control_message), _)) .RetiresOnSaturation(); EXPECT_CALL(*(client_control_feature_->incoming_message_processor()), MockableProcessMessage( EqualsMessageIgnoringId(*engine_control_message), _)) .RetiresOnSaturation(); client_input_feature_->outgoing_message_processor()->ProcessMessage( std::move(client_input_message), net::CompletionCallback()); client_control_feature_->outgoing_message_processor()->ProcessMessage( std::move(client_control_message), net::CompletionCallback()); engine_control_feature_->outgoing_message_processor()->ProcessMessage( std::move(engine_control_message), net::CompletionCallback()); } TEST_F(BrowserConnectionHandlerTest, ConnectionError) { // Engine will not get message after connection error. client_connection_->error_observer()->OnConnectionError(net::ERR_FAILED); scoped_ptr client_input_message = CreateInputMessage(1); client_input_feature_->outgoing_message_processor()->ProcessMessage( std::move(client_input_message), net::CompletionCallback()); } TEST_F(BrowserConnectionHandlerTest, ReconnectionAfterError) { scoped_ptr client_input_message = CreateInputMessage(1); EXPECT_CALL( *(engine_input_feature_->incoming_message_processor()), MockableProcessMessage(EqualsMessageIgnoringId(*client_input_message), _)) .RetiresOnSaturation(); // Simulate a connection failure. client_connection_->error_observer()->OnConnectionError(net::ERR_FAILED); engine_connection_->error_observer()->OnConnectionError(net::ERR_FAILED); // Message will be queued to be transmitted when the connection is // re-established. client_input_feature_->outgoing_message_processor()->ProcessMessage( std::move(client_input_message), net::CompletionCallback()); // Simulates reconnection. SetupConnections(); } } // namespace } // namespace blimp