blob: adfbd15b42b60c64202aa6ff3b43e335e79da2ff [file] [log] [blame]
// 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 "blimp/net/browser_connection_handler.h"
#include <stddef.h>
#include <string>
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "blimp/common/proto/blimp_message.pb.h"
#include "blimp/net/blimp_message_processor.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::FeatureCase feature_case,
BrowserConnectionHandler* connection_handler) {
outgoing_message_processor_ = connection_handler->RegisterFeature(
feature_case, &incoming_message_processor_);
}
~FakeFeature() {}
BlimpMessageProcessor* outgoing_message_processor() {
return outgoing_message_processor_.get();
}
MockBlimpMessageProcessor* incoming_message_processor() {
return &incoming_message_processor_;
}
private:
testing::StrictMock<MockBlimpMessageProcessor> incoming_message_processor_;
std::unique_ptr<BlimpMessageProcessor> 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(std::unique_ptr<BlimpMessage> message) {
other_end_->incoming_message_processor_->ProcessMessage(
std::move(message), net::CompletionCallback());
}
// BlimpMessageProcessor implementation.
void ProcessMessage(std::unique_ptr<BlimpMessage> message,
const net::CompletionCallback& callback) override {
base::ThreadTaskRunnerHandle::Get()->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;
};
std::unique_ptr<BlimpMessage> CreateInputMessage(int tab_id) {
std::unique_ptr<BlimpMessage> output(new BlimpMessage);
output->mutable_input();
output->set_target_tab_id(tab_id);
return output;
}
std::unique_ptr<BlimpMessage> CreateControlMessage(int tab_id) {
std::unique_ptr<BlimpMessage> output(new BlimpMessage);
output->mutable_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::kInput, client_connection_handler_.get()));
engine_input_feature_.reset(new FakeFeature(
BlimpMessage::kInput, engine_connection_handler_.get()));
client_control_feature_.reset(new FakeFeature(
BlimpMessage::kTabControl, client_connection_handler_.get()));
engine_control_feature_.reset(new FakeFeature(
BlimpMessage::kTabControl, 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(
base::WrapUnique(client_connection_));
engine_connection_handler_->HandleConnection(
base::WrapUnique(engine_connection_));
}
base::MessageLoop message_loop_;
FakeBlimpConnection* client_connection_;
FakeBlimpConnection* engine_connection_;
std::unique_ptr<BrowserConnectionHandler> client_connection_handler_;
std::unique_ptr<BrowserConnectionHandler> engine_connection_handler_;
std::unique_ptr<FakeFeature> client_input_feature_;
std::unique_ptr<FakeFeature> engine_input_feature_;
std::unique_ptr<FakeFeature> client_control_feature_;
std::unique_ptr<FakeFeature> engine_control_feature_;
};
TEST_F(BrowserConnectionHandlerTest, ExchangeMessages) {
std::unique_ptr<BlimpMessage> client_input_message = CreateInputMessage(1);
std::unique_ptr<BlimpMessage> client_control_message =
CreateControlMessage(1);
std::unique_ptr<BlimpMessage> 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);
std::unique_ptr<BlimpMessage> client_input_message = CreateInputMessage(1);
client_input_feature_->outgoing_message_processor()->ProcessMessage(
std::move(client_input_message), net::CompletionCallback());
}
TEST_F(BrowserConnectionHandlerTest, ReconnectionAfterError) {
std::unique_ptr<BlimpMessage> 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