blob: 609eabbc9c72b539af34e1377282b44aa7aa11d4 [file] [log] [blame]
// Copyright 2020 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_remote_set.h"
#include <utility>
#include <string>
#include "base/test/null_task_runner.h"
#include "mojo/public/cpp/bindings/pending_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"
namespace blink {
namespace {
class FakeContextNotifier final : public GarbageCollected<FakeContextNotifier>,
public ContextLifecycleNotifier {
public:
FakeContextNotifier() = default;
void AddContextLifecycleObserver(
ContextLifecycleObserver* observer) override {
observers_.AddObserver(observer);
}
void RemoveContextLifecycleObserver(
ContextLifecycleObserver* observer) override {
observers_.RemoveObserver(observer);
}
void NotifyContextDestroyed() {
observers_.ForEachObserver([](ContextLifecycleObserver* observer) {
observer->ContextDestroyed();
});
}
void Trace(Visitor* visitor) const override {
visitor->Trace(observers_);
ContextLifecycleNotifier::Trace(visitor);
}
private:
HeapObserverSet<ContextLifecycleObserver> observers_;
};
template <HeapMojoWrapperMode Mode>
class HeapMojoRemoteSetGCBaseTest;
template <HeapMojoWrapperMode Mode>
class GCOwner : public GarbageCollected<GCOwner<Mode>> {
public:
explicit GCOwner(FakeContextNotifier* context,
HeapMojoRemoteSetGCBaseTest<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_); }
HeapMojoRemoteSet<sample::blink::Service, Mode>& remote_set() {
return remote_set_;
}
private:
HeapMojoRemoteSet<sample::blink::Service, Mode> remote_set_;
HeapMojoRemoteSetGCBaseTest<Mode>* test_;
};
template <HeapMojoWrapperMode Mode>
class HeapMojoRemoteSetGCBaseTest : public TestSupportingGC {
public:
FakeContextNotifier* 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<FakeContextNotifier>();
owner_ = MakeGarbageCollected<GCOwner<Mode>>(context(), this);
}
void TearDown() override {
owner_ = nullptr;
PreciselyCollectGarbage();
}
Persistent<FakeContextNotifier> context_;
Persistent<GCOwner<Mode>> owner_;
bool is_owner_alive_ = false;
scoped_refptr<base::NullTaskRunner> null_task_runner_ =
base::MakeRefCounted<base::NullTaskRunner>();
};
} // namespace
class HeapMojoRemoteSetGCWithContextObserverTest
: public HeapMojoRemoteSetGCBaseTest<
HeapMojoWrapperMode::kWithContextObserver> {};
class HeapMojoRemoteSetGCWithoutContextObserverTest
: public HeapMojoRemoteSetGCBaseTest<
HeapMojoWrapperMode::kForceWithoutContextObserver> {};
// GC the HeapMojoRemoteSet with context observer and verify that the remote
// is no longer part of the set, and that the service was deleted.
TEST_F(HeapMojoRemoteSetGCWithContextObserverTest, RemovesRemote) {
auto& remote_set = owner()->remote_set();
auto remote = mojo::PendingRemote<sample::blink::Service>(
mojo::MessagePipe().handle0, 0);
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(HeapMojoRemoteSetGCWithContextObserverTest, NoClearOnConservativeGC) {
auto* wrapper = owner_->remote_set().wrapper_.Get();
auto remote = mojo::PendingRemote<sample::blink::Service>(
mojo::MessagePipe().handle0, 0);
mojo::RemoteSetElementId rid =
owner()->remote_set().Add(std::move(remote), task_runner());
EXPECT_TRUE(wrapper->remote_set().Contains(rid));
ClearOwner();
EXPECT_TRUE(is_owner_alive_);
ConservativelyCollectGarbage();
EXPECT_TRUE(wrapper->remote_set().Contains(rid));
EXPECT_TRUE(is_owner_alive_);
}
// GC the HeapMojoRemoteSet without context observer and verify that the
// remote is no longer part of the set, and that the service was deleted.
TEST_F(HeapMojoRemoteSetGCWithoutContextObserverTest, RemovesRemote) {
auto& remote_set = owner()->remote_set();
auto remote = mojo::PendingRemote<sample::blink::Service>(
mojo::MessagePipe().handle0, 0);
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 HeapMojoRemoteSet with context observer and verify that the remote
// is no longer part of the set, and that the service was deleted.
TEST_F(HeapMojoRemoteSetGCWithContextObserverTest, ClearLeavesSetEmpty) {
auto& remote_set = owner()->remote_set();
auto remote = mojo::PendingRemote<sample::blink::Service>(
mojo::MessagePipe().handle0, 0);
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 HeapMojoRemoteSet without context observer and verify that the
// remote is no longer part of the set, and that the service was deleted.
TEST_F(HeapMojoRemoteSetGCWithoutContextObserverTest, ClearLeavesSetEmpty) {
auto& remote_set = owner()->remote_set();
auto remote = mojo::PendingRemote<sample::blink::Service>(
mojo::MessagePipe().handle0, 0);
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(HeapMojoRemoteSetGCWithContextObserverTest, AddSeveralRemoteSet) {
auto& remote_set = owner()->remote_set();
EXPECT_TRUE(remote_set.empty());
EXPECT_EQ(remote_set.size(), 0u);
auto remote_1 = mojo::PendingRemote<sample::blink::Service>(
mojo::MessagePipe().handle0, 0);
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);
auto remote_2 = mojo::PendingRemote<sample::blink::Service>(
mojo::MessagePipe().handle0, 0);
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