blob: 8e3a8041c0c27527728712a491e1fa01c479f005 [file] [log] [blame]
// 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 <memory>
#include <string>
#include <utility>
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/pickle.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread.h"
#include "content/public/browser/browser_associated_interface.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/test/test_browser_associated_interfaces.mojom.h"
#include "ipc/ipc_channel_factory.h"
#include "ipc/ipc_channel_mojo.h"
#include "ipc/ipc_channel_proxy.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_message.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
const int kNumTestMessages = 100;
class BrowserAssociatedInterfaceTest : public testing::Test {
public:
static void AddFilterToChannel(BrowserMessageFilter* filter,
IPC::ChannelProxy* channel) {
filter->RegisterAssociatedInterfaces(channel);
channel->AddFilter(filter->GetFilter());
}
};
class ProxyRunner : public IPC::Listener {
public:
ProxyRunner(mojo::ScopedMessagePipeHandle pipe,
bool for_server,
scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner) {
std::unique_ptr<IPC::ChannelFactory> factory;
if (for_server) {
factory = IPC::ChannelMojo::CreateServerFactory(
std::move(pipe), ipc_task_runner,
base::ThreadTaskRunnerHandle::Get());
} else {
factory = IPC::ChannelMojo::CreateClientFactory(
std::move(pipe), ipc_task_runner,
base::ThreadTaskRunnerHandle::Get());
}
channel_ =
IPC::ChannelProxy::Create(std::move(factory), this, ipc_task_runner,
base::ThreadTaskRunnerHandle::Get());
}
void ShutDown() { channel_.reset(); }
IPC::ChannelProxy* channel() { return channel_.get(); }
private:
// IPC::Listener:
bool OnMessageReceived(const IPC::Message& message) override { return false; }
std::unique_ptr<IPC::ChannelProxy> channel_;
};
class TestDriverMessageFilter
: public BrowserMessageFilter,
public BrowserAssociatedInterface<
mojom::BrowserAssociatedInterfaceTestDriver>,
public mojom::BrowserAssociatedInterfaceTestDriver {
public:
TestDriverMessageFilter()
: BrowserMessageFilter(0),
BrowserAssociatedInterface<mojom::BrowserAssociatedInterfaceTestDriver>(
this, this) {
}
private:
~TestDriverMessageFilter() override {}
// BrowserMessageFilter:
bool OnMessageReceived(const IPC::Message& message) override {
std::string actual_string;
base::PickleIterator iter(message);
EXPECT_TRUE(iter.ReadString(&actual_string));
EXPECT_EQ(next_expected_string_, actual_string);
message_count_++;
return true;
}
void OnFilterRemoved() override {
// Check that the bindings are cleared by
// BrowserAssociatedInterface::ClearBindings() callbacks.
EXPECT_FALSE(internal_state_->bindings_.has_value());
}
// mojom::BrowserAssociatedInterfaceTestDriver:
void ExpectString(const std::string& expected) override {
next_expected_string_ = expected;
}
void RequestQuit(RequestQuitCallback callback) override {
EXPECT_EQ(kNumTestMessages, message_count_);
std::move(callback).Run();
base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
std::string next_expected_string_;
int message_count_ = 0;
};
class TestClientRunner {
public:
explicit TestClientRunner(mojo::ScopedMessagePipeHandle pipe)
: client_thread_("Test client") {
client_thread_.Start();
client_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(&RunTestClient, std::move(pipe)));
}
~TestClientRunner() {
client_thread_.Stop();
base::RunLoop().RunUntilIdle();
}
private:
static void RunTestClient(mojo::ScopedMessagePipeHandle pipe) {
base::Thread io_thread("Client IO thread");
io_thread.StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
ProxyRunner proxy(std::move(pipe), false, io_thread.task_runner());
mojom::BrowserAssociatedInterfaceTestDriverAssociatedPtr driver;
proxy.channel()->GetRemoteAssociatedInterface(&driver);
for (int i = 0; i < kNumTestMessages; ++i) {
std::string next_message = base::StringPrintf("test %d", i);
driver->ExpectString(next_message);
std::unique_ptr<IPC::Message> message(new IPC::Message);
message->WriteString(next_message);
proxy.channel()->Send(message.release());
}
driver->RequestQuit(base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
base::RunLoop(base::RunLoop::Type::kNestableTasksAllowed).Run();
proxy.ShutDown();
io_thread.Stop();
base::RunLoop().RunUntilIdle();
}
base::Thread client_thread_;
};
TEST_F(BrowserAssociatedInterfaceTest, Basic) {
TestBrowserThreadBundle browser_threads_;
mojo::MessagePipe pipe;
ProxyRunner proxy(std::move(pipe.handle0), true,
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
AddFilterToChannel(new TestDriverMessageFilter, proxy.channel());
TestClientRunner client(std::move(pipe.handle1));
base::RunLoop().Run();
proxy.ShutDown();
base::RunLoop().RunUntilIdle();
}
} // namespace content