| // 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 |