| // Copyright 2025 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 "quiche/quic/moqt/relay_namespace_tree.h" | |
| #include <memory> | |
| #include "quiche/quic/moqt/moqt_messages.h" | |
| #include "quiche/quic/moqt/test_tools/mock_moqt_session.h" | |
| #include "quiche/common/platform/api/quiche_expect_bug.h" | |
| #include "quiche/common/platform/api/quiche_test.h" | |
| namespace moqt { | |
| namespace test { | |
| class TestRelayNamespaceTree : public RelayNamespaceTree { | |
| public: | |
| using RelayNamespaceTree::NumNamespaces; | |
| }; | |
| using ::testing::_; | |
| class RelayNamespaceTreeTest : public quiche::test::QuicheTest { | |
| public: | |
| RelayNamespaceTreeTest() : session_(std::make_unique<MockMoqtSession>()) {} | |
| TestRelayNamespaceTree tree_; | |
| TrackNamespace a_{"a"}, ab_{"a", "b"}, abc_{"a", "b", "c"}; | |
| std::unique_ptr<MockMoqtSession> session_; | |
| }; | |
| TEST_F(RelayNamespaceTreeTest, AddGetRemovePublisher) { | |
| EXPECT_EQ(tree_.NumNamespaces(), 0u); | |
| EXPECT_EQ(tree_.GetValidPublisher(ab_), nullptr); | |
| tree_.AddPublisher(ab_, session_.get()); | |
| EXPECT_EQ(tree_.NumNamespaces(), 2u); | |
| EXPECT_EQ(tree_.GetValidPublisher(a_), nullptr); | |
| EXPECT_EQ(tree_.GetValidPublisher(ab_), session_.get()); | |
| EXPECT_EQ(tree_.GetValidPublisher(abc_), session_.get()); | |
| tree_.RemovePublisher(ab_, session_.get()); | |
| EXPECT_EQ(tree_.NumNamespaces(), 0u); | |
| EXPECT_EQ(tree_.GetValidPublisher(ab_), nullptr); | |
| } | |
| TEST_F(RelayNamespaceTreeTest, AddGetRemoveListener) { | |
| // Add a listener to a namespace that has no publishers. | |
| EXPECT_EQ(tree_.NumNamespaces(), 0u); | |
| tree_.AddSubscriber(ab_, session_.get()); | |
| EXPECT_EQ(tree_.NumNamespaces(), 2u); | |
| EXPECT_CALL(*session_, PublishNamespace).Times(0); | |
| tree_.AddPublisher(a_, session_.get()); | |
| EXPECT_CALL(*session_, PublishNamespace(ab_, _, _)); | |
| tree_.AddPublisher(ab_, session_.get()); | |
| EXPECT_CALL(*session_, PublishNamespace(abc_, _, _)); | |
| tree_.AddPublisher(abc_, session_.get()); | |
| EXPECT_EQ(tree_.NumNamespaces(), 3u); | |
| // Second publisher creates no new notifications, and delays OnNamespaceDone. | |
| auto session2 = std::make_unique<MockMoqtSession>(); | |
| EXPECT_CALL(*session_, PublishNamespace).Times(0); | |
| tree_.AddPublisher(ab_, session2.get()); | |
| EXPECT_CALL(*session_, PublishNamespaceDone).Times(0); | |
| tree_.RemovePublisher(ab_, session_.get()); | |
| EXPECT_CALL(*session_, PublishNamespaceDone(ab_)); | |
| tree_.RemovePublisher(ab_, session2.get()); | |
| // Removing the listener disables notifications. | |
| tree_.RemoveSubscriber(ab_, session_.get()); | |
| EXPECT_CALL(*session_, PublishNamespace).Times(0); | |
| tree_.AddPublisher(ab_, session2.get()); | |
| } | |
| TEST_F(RelayNamespaceTreeTest, SessionDestroyed) { | |
| tree_.AddSubscriber(ab_, session_.get()); | |
| EXPECT_CALL(*session_, PublishNamespace(ab_, _, _)); | |
| tree_.AddPublisher(ab_, session_.get()); | |
| EXPECT_NE(tree_.GetValidPublisher(ab_), nullptr); | |
| // First session dies. It should have removed the namespace! | |
| session_.reset(); | |
| EXPECT_QUICHE_BUG( | |
| tree_.GetValidPublisher(ab_), | |
| "Publisher WeakPtr is invalid but not removed from the set"); | |
| } | |
| TEST_F(RelayNamespaceTreeTest, AddListenerToExistingPublisher) { | |
| tree_.AddPublisher(a_, session_.get()); | |
| tree_.AddPublisher(ab_, session_.get()); | |
| tree_.AddPublisher(abc_, session_.get()); | |
| EXPECT_CALL(*session_, PublishNamespace(ab_, _, _)); | |
| EXPECT_CALL(*session_, PublishNamespace(abc_, _, _)); | |
| tree_.AddSubscriber(ab_, session_.get()); | |
| } | |
| TEST_F(RelayNamespaceTreeTest, MaxSizeNamespace) { | |
| tree_.AddSubscriber(a_, session_.get()); | |
| TrackNamespace big_namespace{"a", "b", "c", "d", "e", "f", "g", "h", | |
| "i", "j", "k", "l", "m", "n", "o", "p", | |
| "q", "r", "s", "t", "u", "v", "w", "x", | |
| "y", "z", "1", "2", "3", "4", "5", "6"}; | |
| EXPECT_CALL(*session_, PublishNamespace(big_namespace, _, _)); | |
| tree_.AddPublisher(big_namespace, session_.get()); | |
| } | |
| // TODO(martinduke): Add tests for published tracks. | |
| } // namespace test | |
| } // namespace moqt |