| // 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/session_namespace_tree.h" | |
| #include <cstdint> | |
| #include "quiche/quic/moqt/moqt_messages.h" | |
| #include "quiche/quic/moqt/test_tools/mock_moqt_session.h" | |
| #include "quiche/quic/platform/api/quic_test.h" | |
| #include "quiche/common/platform/api/quiche_test.h" | |
| namespace moqt { | |
| namespace test { | |
| class TestSessionNamespaceTree : public SessionNamespaceTree { | |
| public: | |
| TestSessionNamespaceTree() = default; | |
| using SessionNamespaceTree::NumSubscriptions; | |
| }; | |
| class SessionNamespaceTreeTest : public quic::test::QuicTest { | |
| public: | |
| void TestAddSucceeds(TrackNamespace track_namespace) { | |
| uint64_t num_subscriptions_before = tree_.NumSubscriptions(); | |
| EXPECT_TRUE(tree_.SubscribeNamespace(track_namespace)); | |
| EXPECT_EQ(tree_.NumSubscriptions(), num_subscriptions_before + 1); | |
| } | |
| void TestAddFails(TrackNamespace track_namespace) { | |
| uint64_t num_subscriptions_before = tree_.NumSubscriptions(); | |
| EXPECT_FALSE(tree_.SubscribeNamespace(track_namespace)); | |
| EXPECT_EQ(tree_.NumSubscriptions(), num_subscriptions_before); | |
| } | |
| void TestRemoveSucceeds(TrackNamespace track_namespace) { | |
| uint64_t num_subscriptions_before = tree_.NumSubscriptions(); | |
| tree_.UnsubscribeNamespace(track_namespace); | |
| EXPECT_EQ(tree_.NumSubscriptions(), num_subscriptions_before - 1); | |
| } | |
| void TestRemoveFails(TrackNamespace track_namespace) { | |
| uint64_t num_subscriptions_before = tree_.NumSubscriptions(); | |
| tree_.UnsubscribeNamespace(track_namespace); | |
| EXPECT_EQ(tree_.NumSubscriptions(), num_subscriptions_before); | |
| } | |
| MockMoqtSession session_; | |
| TestSessionNamespaceTree tree_; | |
| TrackNamespace ab_{"a", "b"}, abc_{"a", "b", "c"}, abcd_{"a", "b", "c", "d"}; | |
| }; | |
| TEST_F(SessionNamespaceTreeTest, AddNamespaces) { | |
| TestAddSucceeds(abc_); | |
| // No parents, children, or equivalents of what's already there. | |
| TestAddFails(ab_); | |
| TestAddFails(abc_); | |
| TestAddFails(abcd_); | |
| // Siblings are fine. | |
| TestAddSucceeds(TrackNamespace{"a", "b", "d"}); | |
| // Totally different root is fine. | |
| TestAddSucceeds(TrackNamespace{"b", "c"}); | |
| } | |
| TEST_F(SessionNamespaceTreeTest, RemoveNamespaces) { | |
| // Removing from an empty tree doesn't do anything. | |
| TestRemoveFails(abc_); | |
| // UnsubscribeNamespace doesn't do anything if the namespace isn't present. | |
| TestAddSucceeds(abc_); | |
| TestRemoveFails(ab_); | |
| TestRemoveFails(abcd_); | |
| // Exact match works. Now re-adding can succeed. | |
| TestRemoveSucceeds(abc_); | |
| TestAddSucceeds(abc_); | |
| // Add another ref count on ab_. | |
| TrackNamespace abd{"a", "b", "d"}; | |
| TestAddSucceeds(abd); | |
| // Higher namespace is blocked. | |
| TestAddFails(ab_); | |
| // Removing one doesn't remove the block. | |
| TestRemoveSucceeds(abc_); | |
| TestAddFails(ab_); | |
| // Removing both allows add. | |
| TestRemoveSucceeds(abd); | |
| TestAddSucceeds(ab_); | |
| } | |
| } // namespace test | |
| } // namespace moqt |