blob: 300b7bec109b9c028296688b70d7403c2973bd46 [file] [log] [blame]
// Copyright 2021 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 "third_party/blink/renderer/platform/mojo/heap_mojo_associated_remote_set.h"
#include <utility>
#include <string>
#include "base/macros.h"
#include "base/test/null_task_runner.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/remote_set.h"
#include "mojo/public/interfaces/bindings/tests/sample_service.mojom-blink.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/context_lifecycle_notifier.h"
#include "third_party/blink/renderer/platform/heap/heap_test_utilities.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap_observer_set.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h"
#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h"
#include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h"
namespace blink {
namespace {
template <HeapMojoWrapperMode Mode>
class HeapMojoAssociatedRemoteSetGCBaseTest;
template <HeapMojoWrapperMode Mode>
class GCOwner : public GarbageCollected<GCOwner<Mode>> {
public:
explicit GCOwner(MockContextLifecycleNotifier* context,
HeapMojoAssociatedRemoteSetGCBaseTest<Mode>* test)
: remote_set_(context), test_(test) {
test_->set_is_owner_alive(true);
}
void Dispose() { test_->set_is_owner_alive(false); }
void Trace(Visitor* visitor) const { visitor->Trace(remote_set_); }
HeapMojoAssociatedRemoteSet<sample::blink::Service, Mode>&
associated_remote_set() {
return remote_set_;
}
private:
HeapMojoAssociatedRemoteSet<sample::blink::Service, Mode> remote_set_;
HeapMojoAssociatedRemoteSetGCBaseTest<Mode>* test_;
};
template <HeapMojoWrapperMode Mode>
class HeapMojoAssociatedRemoteSetGCBaseTest : public TestSupportingGC {
public:
MockContextLifecycleNotifier* context() { return context_; }
scoped_refptr<base::NullTaskRunner> task_runner() {
return null_task_runner_;
}
GCOwner<Mode>* owner() { return owner_; }
void set_is_owner_alive(bool alive) { is_owner_alive_ = alive; }
void ClearOwner() { owner_ = nullptr; }
protected:
void SetUp() override {
context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<GCOwner<Mode>>(context(), this);
}
void TearDown() override {
owner_ = nullptr;
PreciselyCollectGarbage();
}
Persistent<MockContextLifecycleNotifier> context_;
Persistent<GCOwner<Mode>> owner_;
bool is_owner_alive_ = false;
scoped_refptr<base::NullTaskRunner> null_task_runner_ =
base::MakeRefCounted<base::NullTaskRunner>();
};
} // namespace
class HeapMojoAssociatedRemoteSetGCWithContextObserverTest
: public HeapMojoAssociatedRemoteSetGCBaseTest<
HeapMojoWrapperMode::kWithContextObserver> {};
class HeapMojoAssociatedRemoteSetGCWithoutContextObserverTest
: public HeapMojoAssociatedRemoteSetGCBaseTest<
HeapMojoWrapperMode::kForceWithoutContextObserver> {};
// GC the HeapMojoAssociatedRemoteSet with context observer and verify that the
// remote is no longer part of the set, and that the service was deleted.
TEST_F(HeapMojoAssociatedRemoteSetGCWithContextObserverTest, RemovesRemote) {
auto& remote_set = owner()->associated_remote_set();
mojo::PendingAssociatedRemote<sample::blink::Service> remote;
ignore_result(remote.InitWithNewEndpointAndPassReceiver());
mojo::RemoteSetElementId rid =
remote_set.Add(std::move(remote), task_runner());
EXPECT_TRUE(remote_set.Contains(rid));
remote_set.Remove(rid);
EXPECT_FALSE(remote_set.Contains(rid));
}
// Check that the wrapper does not outlive the owner when ConservativeGC finds
// the wrapper.
TEST_F(HeapMojoAssociatedRemoteSetGCWithContextObserverTest,
NoClearOnConservativeGC) {
auto* wrapper = owner_->associated_remote_set().wrapper_.Get();
mojo::PendingAssociatedRemote<sample::blink::Service> remote;
ignore_result(remote.InitWithNewEndpointAndPassReceiver());
mojo::RemoteSetElementId rid =
owner()->associated_remote_set().Add(std::move(remote), task_runner());
EXPECT_TRUE(wrapper->associated_remote_set().Contains(rid));
ClearOwner();
EXPECT_TRUE(is_owner_alive_);
ConservativelyCollectGarbage();
EXPECT_TRUE(wrapper->associated_remote_set().Contains(rid));
EXPECT_TRUE(is_owner_alive_);
}
// GC the HeapMojoAssociatedRemoteSet without context observer and verify that
// the remote is no longer part of the set, and that the service was deleted.
TEST_F(HeapMojoAssociatedRemoteSetGCWithoutContextObserverTest, RemovesRemote) {
auto& remote_set = owner()->associated_remote_set();
mojo::PendingAssociatedRemote<sample::blink::Service> remote;
ignore_result(remote.InitWithNewEndpointAndPassReceiver());
mojo::RemoteSetElementId rid =
remote_set.Add(std::move(remote), task_runner());
EXPECT_TRUE(remote_set.Contains(rid));
remote_set.Remove(rid);
EXPECT_FALSE(remote_set.Contains(rid));
}
// GC the HeapMojoAssociatedRemoteSet with context observer and verify that the
// remote is no longer part of the set, and that the service was deleted.
TEST_F(HeapMojoAssociatedRemoteSetGCWithContextObserverTest,
ClearLeavesSetEmpty) {
auto& remote_set = owner()->associated_remote_set();
mojo::PendingAssociatedRemote<sample::blink::Service> remote;
ignore_result(remote.InitWithNewEndpointAndPassReceiver());
mojo::RemoteSetElementId rid =
remote_set.Add(std::move(remote), task_runner());
EXPECT_TRUE(remote_set.Contains(rid));
remote_set.Clear();
EXPECT_FALSE(remote_set.Contains(rid));
}
// GC the HeapMojoAssociatedRemoteSet without context observer and verify that
// the remote is no longer part of the set, and that the service was deleted.
TEST_F(HeapMojoAssociatedRemoteSetGCWithoutContextObserverTest,
ClearLeavesSetEmpty) {
auto& remote_set = owner()->associated_remote_set();
mojo::PendingAssociatedRemote<sample::blink::Service> remote;
ignore_result(remote.InitWithNewEndpointAndPassReceiver());
mojo::RemoteSetElementId rid =
remote_set.Add(std::move(remote), task_runner());
EXPECT_TRUE(remote_set.Contains(rid));
remote_set.Clear();
EXPECT_FALSE(remote_set.Contains(rid));
}
// Add several remote and confirm that remote_set holds properly.
TEST_F(HeapMojoAssociatedRemoteSetGCWithContextObserverTest,
AddSeveralRemoteSet) {
auto& remote_set = owner()->associated_remote_set();
EXPECT_TRUE(remote_set.empty());
EXPECT_EQ(remote_set.size(), 0u);
mojo::PendingAssociatedRemote<sample::blink::Service> remote_1;
ignore_result(remote_1.InitWithNewEndpointAndPassReceiver());
mojo::RemoteSetElementId rid_1 =
remote_set.Add(std::move(remote_1), task_runner());
EXPECT_TRUE(remote_set.Contains(rid_1));
EXPECT_FALSE(remote_set.empty());
EXPECT_EQ(remote_set.size(), 1u);
mojo::PendingAssociatedRemote<sample::blink::Service> remote_2;
ignore_result(remote_2.InitWithNewEndpointAndPassReceiver());
mojo::RemoteSetElementId rid_2 =
remote_set.Add(std::move(remote_2), task_runner());
EXPECT_TRUE(remote_set.Contains(rid_1));
EXPECT_TRUE(remote_set.Contains(rid_2));
EXPECT_FALSE(remote_set.empty());
EXPECT_EQ(remote_set.size(), 2u);
remote_set.Clear();
EXPECT_FALSE(remote_set.Contains(rid_1));
EXPECT_FALSE(remote_set.Contains(rid_2));
EXPECT_TRUE(remote_set.empty());
EXPECT_EQ(remote_set.size(), 0u);
}
} // namespace blink