[go: nahoru, domu]

blob: d97348f73fd9ea764b7887f3b17ce61e14721336 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/check.h"
#include "base/functional/callback_helpers.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/tests/bindings_test_base.h"
#include "mojo/public/cpp/bindings/tests/connection_group_unittest.test-mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace test {
namespace connection_group_unittest {
class ConnectionGroupTest : public testing::Test {
public:
ConnectionGroupTest() = default;
ConnectionGroupTest(const ConnectionGroupTest&) = delete;
ConnectionGroupTest& operator=(const ConnectionGroupTest&) = delete;
private:
base::test::TaskEnvironment task_environment_;
};
using ConnectionGroupBindingsTest = BindingsTestBase;
class TestInterfaceImpl : public mojom::TestInterface {
public:
explicit TestInterfaceImpl(PendingReceiver<mojom::TestInterface> receiver) {
receivers_.Add(this, std::move(receiver));
receivers_.set_disconnect_handler(base::BindRepeating(
&TestInterfaceImpl::OnDisconnect, base::Unretained(this)));
}
TestInterfaceImpl(const TestInterfaceImpl&) = delete;
TestInterfaceImpl& operator=(const TestInterfaceImpl&) = delete;
~TestInterfaceImpl() override = default;
void WaitForDisconnect() {
base::RunLoop loop;
wait_for_disconnect_closure_ = loop.QuitClosure();
loop.Run();
}
private:
void OnDisconnect() {
if (wait_for_disconnect_closure_)
std::move(wait_for_disconnect_closure_).Run();
}
// mojom::TestInterface:
void BindReceiver(
mojo::PendingReceiver<mojom::TestInterface> receiver) override {
receivers_.Add(this, std::move(receiver));
}
ReceiverSet<mojom::TestInterface> receivers_;
base::OnceClosure wait_for_disconnect_closure_;
};
TEST_P(ConnectionGroupBindingsTest, RefCounting) {
ConnectionGroup::Ref ref =
ConnectionGroup::Create(base::DoNothing(), nullptr);
auto group = ref.GetGroupForTesting();
// The initial ref is valid but does not increase the ref-count.
EXPECT_TRUE(ref);
EXPECT_EQ(0u, group->GetNumRefsForTesting());
// Moving the initial ref preserves its weak type.
ConnectionGroup::Ref moved_ref = std::move(ref);
EXPECT_FALSE(ref);
EXPECT_TRUE(moved_ref);
EXPECT_EQ(0u, group->GetNumRefsForTesting());
ref = std::move(moved_ref);
EXPECT_FALSE(moved_ref);
EXPECT_TRUE(ref);
EXPECT_EQ(0u, group->GetNumRefsForTesting());
// Any copy of the initial ref does increase ref-count.
ConnectionGroup::Ref copy = ref;
EXPECT_TRUE(ref);
EXPECT_TRUE(copy);
EXPECT_EQ(1u, group->GetNumRefsForTesting());
copy.reset();
EXPECT_TRUE(ref);
EXPECT_FALSE(copy);
EXPECT_EQ(0u, group->GetNumRefsForTesting());
}
TEST_P(ConnectionGroupBindingsTest, PassedEndpointsInheritFromReceiver) {
Remote<mojom::TestInterface> remote;
auto pending_receiver = remote.BindNewPipeAndPassReceiver();
ConnectionGroup::Ref ref =
ConnectionGroup::Create(base::DoNothing(), nullptr);
auto group = ref.GetGroupForTesting();
pending_receiver.set_connection_group(std::move(ref));
TestInterfaceImpl impl(std::move(pending_receiver));
EXPECT_EQ(0u, group->GetNumRefsForTesting());
// Verify that the connection group references spread to receivers passed over
// the main interface.
Remote<mojom::TestInterface> remote2;
remote->BindReceiver(remote2.BindNewPipeAndPassReceiver());
remote2.FlushForTesting();
EXPECT_EQ(1u, group->GetNumRefsForTesting());
Remote<mojom::TestInterface> remote3;
remote->BindReceiver(remote3.BindNewPipeAndPassReceiver());
remote3.FlushForTesting();
EXPECT_EQ(2u, group->GetNumRefsForTesting());
remote2.reset();
impl.WaitForDisconnect();
EXPECT_EQ(1u, group->GetNumRefsForTesting());
remote3.reset();
impl.WaitForDisconnect();
EXPECT_EQ(0u, group->GetNumRefsForTesting());
// Verify that group references continue to propagate through arbitrarily many
// indirections (i.e. receivers passed over receivers passed over receivers,
// etc.)
remote->BindReceiver(remote2.BindNewPipeAndPassReceiver());
remote2->BindReceiver(remote3.BindNewPipeAndPassReceiver());
mojo::Remote<mojom::TestInterface> remote4;
remote3->BindReceiver(remote4.BindNewPipeAndPassReceiver());
remote4.FlushForTesting();
EXPECT_EQ(3u, group->GetNumRefsForTesting());
remote2.reset();
impl.WaitForDisconnect();
EXPECT_EQ(2u, group->GetNumRefsForTesting());
remote3.reset();
impl.WaitForDisconnect();
EXPECT_EQ(1u, group->GetNumRefsForTesting());
remote4.reset();
impl.WaitForDisconnect();
EXPECT_EQ(0u, group->GetNumRefsForTesting());
}
TEST_F(ConnectionGroupTest, NotifyOnDecrementToZero) {
base::RunLoop loop;
ConnectionGroup::Ref ref = ConnectionGroup::Create(
loop.QuitClosure(), base::SequencedTaskRunner::GetCurrentDefault());
auto group = ref.GetGroupForTesting();
EXPECT_EQ(0u, group->GetNumRefsForTesting());
ConnectionGroup::Ref copy = ref;
EXPECT_EQ(1u, group->GetNumRefsForTesting());
copy.reset();
EXPECT_EQ(0u, group->GetNumRefsForTesting());
loop.Run();
}
TEST_F(ConnectionGroupTest, NotifyOnDecrementToZeroMultipleTimes) {
absl::optional<base::RunLoop> loop;
ConnectionGroup::Ref ref =
ConnectionGroup::Create(base::BindLambdaForTesting([&] {
ASSERT_TRUE(loop.has_value());
loop->Quit();
}),
base::SequencedTaskRunner::GetCurrentDefault());
auto group = ref.GetGroupForTesting();
ConnectionGroup::Ref copy = ref;
EXPECT_EQ(1u, group->GetNumRefsForTesting());
copy.reset();
EXPECT_EQ(0u, group->GetNumRefsForTesting());
loop.emplace();
loop->Run();
EXPECT_EQ(0u, group->GetNumRefsForTesting());
copy = ref;
EXPECT_EQ(1u, group->GetNumRefsForTesting());
copy.reset();
EXPECT_EQ(0u, group->GetNumRefsForTesting());
loop.emplace();
loop->Run();
}
INSTANTIATE_MOJO_BINDINGS_TEST_SUITE_P(ConnectionGroupBindingsTest);
} // namespace connection_group_unittest
} // namespace test
} // namespace mojo