blob: af03c51ae02cb6e959bf0438771a399b80dc8e45 [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_receiver.h"
#include "base/test/null_task_runner.h"
#include "base/test/scoped_feature_list.h"
#include "mojo/public/cpp/bindings/remote.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/features.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"
#include "third_party/blink/renderer/platform/wtf/buildflags.h"
namespace blink {
namespace {
template <HeapMojoWrapperMode Mode>
class HeapMojoReceiverGCBaseTest;
template <HeapMojoWrapperMode Mode>
class ReceiverOwner : public GarbageCollected<ReceiverOwner<Mode>>,
public sample::blink::Service {
USING_PRE_FINALIZER(ReceiverOwner, Dispose);
public:
explicit ReceiverOwner(MockContextLifecycleNotifier* context,
HeapMojoReceiverGCBaseTest<Mode>* test = nullptr)
: receiver_(this, context), test_(test) {
if (test_)
test_->set_is_owner_alive(true);
}
void Dispose() {
if (test_)
test_->set_is_owner_alive(false);
}
HeapMojoReceiver<sample::blink::Service, ReceiverOwner, Mode>& receiver() {
return receiver_;
}
void Trace(Visitor* visitor) const { visitor->Trace(receiver_); }
private:
// sample::blink::Service implementation
void Frobinate(sample::blink::FooPtr foo,
sample::blink::Service::BazOptions options,
mojo::PendingRemote<sample::blink::Port> port,
sample::blink::Service::FrobinateCallback callback) override {}
void GetPort(mojo::PendingReceiver<sample::blink::Port> port) override {}
HeapMojoReceiver<sample::blink::Service, ReceiverOwner, Mode> receiver_;
HeapMojoReceiverGCBaseTest<Mode>* test_;
};
template <HeapMojoWrapperMode Mode>
class HeapMojoReceiverGCBaseTest : public TestSupportingGC {
public:
base::RunLoop& run_loop() { return run_loop_; }
bool& disconnected() { return disconnected_; }
void set_is_owner_alive(bool alive) { is_owner_alive_ = alive; }
void ClearOwner() { owner_ = nullptr; }
protected:
void SetUp() override {
disconnected_ = false;
context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<ReceiverOwner<Mode>>(context_, this);
scoped_refptr<base::NullTaskRunner> null_task_runner =
base::MakeRefCounted<base::NullTaskRunner>();
remote_ = mojo::Remote<sample::blink::Service>(
owner_->receiver().BindNewPipeAndPassRemote(null_task_runner));
remote_.set_disconnect_handler(WTF::Bind(
[](HeapMojoReceiverGCBaseTest* receiver_test) {
receiver_test->run_loop().Quit();
receiver_test->disconnected() = true;
},
WTF::Unretained(this)));
}
void TearDown() override {
owner_ = nullptr;
PreciselyCollectGarbage();
}
Persistent<MockContextLifecycleNotifier> context_;
Persistent<ReceiverOwner<Mode>> owner_;
bool is_owner_alive_ = false;
base::RunLoop run_loop_;
mojo::Remote<sample::blink::Service> remote_;
bool disconnected_ = false;
};
template <HeapMojoWrapperMode Mode>
class HeapMojoReceiverDisconnectWithReasonHandlerBaseTest
: public HeapMojoReceiverGCBaseTest<Mode> {
public:
std::string& disconnected_reason() { return disconnected_reason_; }
protected:
void SetUp() override {
CHECK(disconnected_reason_.empty());
this->disconnected_ = false;
this->context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
this->owner_ =
MakeGarbageCollected<ReceiverOwner<Mode>>(this->context_, this);
scoped_refptr<base::NullTaskRunner> null_task_runner =
base::MakeRefCounted<base::NullTaskRunner>();
this->remote_ = mojo::Remote<sample::blink::Service>(
this->owner_->receiver().BindNewPipeAndPassRemote(null_task_runner));
this->remote_.set_disconnect_with_reason_handler(WTF::Bind(
[](HeapMojoReceiverDisconnectWithReasonHandlerBaseTest* receiver_test,
const uint32_t custom_reason, const std::string& description) {
receiver_test->run_loop().Quit();
receiver_test->disconnected_reason() = description;
},
WTF::Unretained(this)));
}
std::string disconnected_reason_;
};
template <HeapMojoWrapperMode Mode>
class HeapMojoReceiverDestroyContextBaseTest : public TestSupportingGC {
protected:
void SetUp() override {
context_ = MakeGarbageCollected<MockContextLifecycleNotifier>();
owner_ = MakeGarbageCollected<ReceiverOwner<Mode>>(context_);
scoped_refptr<base::NullTaskRunner> null_task_runner =
base::MakeRefCounted<base::NullTaskRunner>();
remote_ = mojo::Remote<sample::blink::Service>(
owner_->receiver().BindNewPipeAndPassRemote(null_task_runner));
}
Persistent<MockContextLifecycleNotifier> context_;
Persistent<ReceiverOwner<Mode>> owner_;
mojo::Remote<sample::blink::Service> remote_;
};
} // namespace
class HeapMojoReceiverGCWithContextObserverTest
: public HeapMojoReceiverGCBaseTest<
HeapMojoWrapperMode::kWithContextObserver> {};
class HeapMojoReceiverGCWithoutContextObserverTest
: public HeapMojoReceiverGCBaseTest<
HeapMojoWrapperMode::kForceWithoutContextObserver> {};
class HeapMojoReceiverDestroyContextWithContextObserverTest
: public HeapMojoReceiverDestroyContextBaseTest<
HeapMojoWrapperMode::kWithContextObserver> {};
class HeapMojoReceiverDestroyContextWithoutContextObserverTest
: public HeapMojoReceiverDestroyContextBaseTest<
HeapMojoWrapperMode::kWithoutContextObserver> {};
class HeapMojoReceiverDestroyContextForceWithoutContextObserverTest
: public HeapMojoReceiverDestroyContextBaseTest<
HeapMojoWrapperMode::kForceWithoutContextObserver> {};
class HeapMojoReceiverDisconnectWithReasonHandlerWithContextObserverTest
: public HeapMojoReceiverDisconnectWithReasonHandlerBaseTest<
HeapMojoWrapperMode::kWithContextObserver> {};
class HeapMojoReceiverDisconnectWithReasonHandlerWithoutContextObserverTest
: public HeapMojoReceiverDisconnectWithReasonHandlerBaseTest<
HeapMojoWrapperMode::kForceWithoutContextObserver> {};
// Make HeapMojoReceiver with context observer garbage collected and check that
// the connection is disconnected right after the marking phase.
// TODO(1056170): Re-enable test.
#if !BUILDFLAG(USE_V8_OILPAN)
TEST_F(HeapMojoReceiverGCWithContextObserverTest, ResetsOnGC) {
ClearOwner();
EXPECT_FALSE(disconnected());
PreciselyCollectGarbage();
run_loop().Run();
EXPECT_TRUE(disconnected());
CompleteSweepingIfNeeded();
}
#endif // !USE_V8_OILPAN
// Check that the owner
TEST_F(HeapMojoReceiverGCWithContextObserverTest, NoResetOnConservativeGC) {
auto* wrapper = owner_->receiver().wrapper_.Get();
EXPECT_TRUE(owner_->receiver().is_bound());
ClearOwner();
EXPECT_TRUE(is_owner_alive_);
// The stack scanning should find |wrapper| and keep the Wrapper alive.
ConservativelyCollectGarbage();
EXPECT_TRUE(wrapper->receiver().is_bound());
EXPECT_TRUE(is_owner_alive_);
}
// Make HeapMojoReceiver without context observer garbage collected and check
// that the connection is disconnected right after the marking phase.
// TODO(1056170): Re-enable test.
#if !BUILDFLAG(USE_V8_OILPAN)
TEST_F(HeapMojoReceiverGCWithoutContextObserverTest, ResetsOnGC) {
ClearOwner();
EXPECT_FALSE(disconnected());
PreciselyCollectGarbage();
run_loop().Run();
EXPECT_TRUE(disconnected());
CompleteSweepingIfNeeded();
}
#endif // !USE_V8_OILPAN
// Destroy the context with context observer and check that the connection is
// disconnected.
TEST_F(HeapMojoReceiverDestroyContextWithContextObserverTest,
ResetsOnContextDestroyed) {
EXPECT_TRUE(owner_->receiver().is_bound());
context_->NotifyContextDestroyed();
EXPECT_FALSE(owner_->receiver().is_bound());
}
// Destroy the context with context observer and check that the connection is
// disconnected.
TEST_F(HeapMojoReceiverDestroyContextWithoutContextObserverTest,
ResetsOnContextDestroyedWhenFinchEnabled) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeaturesAndParameters(
{{kHeapMojoUseContextObserver, {}}}, {});
EXPECT_TRUE(owner_->receiver().is_bound());
context_->NotifyContextDestroyed();
EXPECT_FALSE(owner_->receiver().is_bound());
}
// Destroy the context without context observer and check that the connection is
// still connected.
TEST_F(HeapMojoReceiverDestroyContextWithoutContextObserverTest,
ResetsOnContextDestroyedWhenFinchDisabled) {
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeaturesAndParameters({}, {kHeapMojoUseContextObserver});
EXPECT_TRUE(owner_->receiver().is_bound());
context_->NotifyContextDestroyed();
EXPECT_TRUE(owner_->receiver().is_bound());
}
// Destroy the context without context observer and check that the connection is
// still connected.
TEST_F(HeapMojoReceiverDestroyContextForceWithoutContextObserverTest,
ResetsOnContextDestroyed) {
EXPECT_TRUE(owner_->receiver().is_bound());
context_->NotifyContextDestroyed();
EXPECT_TRUE(owner_->receiver().is_bound());
}
// Reset the receiver with custom reason and check that the specified handler is
// fired.
TEST_F(HeapMojoReceiverDisconnectWithReasonHandlerWithContextObserverTest,
ResetWithReason) {
EXPECT_TRUE(disconnected_reason().empty());
const std::string message = "test message";
const uint32_t reason = 0;
owner_->receiver().ResetWithReason(reason, message);
run_loop().Run();
EXPECT_EQ(disconnected_reason(), message);
}
// Reset the receiver with custom reason and check that the specified handler is
// fired.
TEST_F(HeapMojoReceiverDisconnectWithReasonHandlerWithoutContextObserverTest,
ResetWithReason) {
EXPECT_TRUE(disconnected_reason().empty());
const std::string message = "test message";
const uint32_t reason = 0;
owner_->receiver().ResetWithReason(reason, message);
run_loop().Run();
EXPECT_EQ(disconnected_reason(), message);
}
} // namespace blink