1 // Copyright 2023 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/moqt/moqt_subscribe_windows.h"
6
7 #include <optional>
8
9 #include "quiche/quic/moqt/moqt_messages.h"
10 #include "quiche/quic/platform/api/quic_expect_bug.h"
11 #include "quiche/quic/platform/api/quic_test.h"
12 #include "quiche/common/platform/api/quiche_export.h"
13 #include "quiche/web_transport/web_transport.h"
14
15 namespace moqt {
16
17 namespace test {
18
19 class QUICHE_EXPORT SubscribeWindowTest : public quic::test::QuicTest {
20 public:
SubscribeWindowTest()21 SubscribeWindowTest() {}
22
23 const uint64_t subscribe_id_ = 2;
24 const uint64_t start_group_ = 4;
25 const uint64_t start_object_ = 0;
26 const uint64_t end_group_ = 5;
27 const uint64_t end_object_ = 5;
28 };
29
TEST_F(SubscribeWindowTest,Queries)30 TEST_F(SubscribeWindowTest, Queries) {
31 SubscribeWindow window(subscribe_id_, MoqtForwardingPreference::kObject,
32 start_group_, start_object_, end_group_, end_object_);
33 EXPECT_EQ(window.subscribe_id(), 2);
34 EXPECT_TRUE(window.InWindow(FullSequence(4, 0)));
35 EXPECT_TRUE(window.InWindow(FullSequence(5, 5)));
36 EXPECT_FALSE(window.InWindow(FullSequence(5, 6)));
37 EXPECT_FALSE(window.InWindow(FullSequence(6, 0)));
38 EXPECT_FALSE(window.InWindow(FullSequence(3, 12)));
39 }
40
TEST_F(SubscribeWindowTest,AddQueryRemoveStreamIdTrack)41 TEST_F(SubscribeWindowTest, AddQueryRemoveStreamIdTrack) {
42 SubscribeWindow window(subscribe_id_, MoqtForwardingPreference::kTrack,
43 start_group_, start_object_, end_group_, end_object_);
44 window.AddStream(4, 0, 2);
45 EXPECT_QUIC_BUG(window.AddStream(5, 2, 6), "Stream already added");
46 EXPECT_EQ(*window.GetStreamForSequence(FullSequence(5, 2)), 2);
47 window.RemoveStream(7, 2);
48 EXPECT_FALSE(window.GetStreamForSequence(FullSequence(4, 0)).has_value());
49 }
50
TEST_F(SubscribeWindowTest,AddQueryRemoveStreamIdGroup)51 TEST_F(SubscribeWindowTest, AddQueryRemoveStreamIdGroup) {
52 SubscribeWindow window(subscribe_id_, MoqtForwardingPreference::kGroup,
53 start_group_, start_object_, end_group_, end_object_);
54 window.AddStream(4, 0, 2);
55 EXPECT_FALSE(window.GetStreamForSequence(FullSequence(5, 0)).has_value());
56 window.AddStream(5, 2, 6);
57 EXPECT_QUIC_BUG(window.AddStream(5, 3, 6), "Stream already added");
58 EXPECT_EQ(*window.GetStreamForSequence(FullSequence(4, 1)), 2);
59 EXPECT_EQ(*window.GetStreamForSequence(FullSequence(5, 0)), 6);
60 window.RemoveStream(5, 1);
61 EXPECT_FALSE(window.GetStreamForSequence(FullSequence(5, 2)).has_value());
62 }
63
TEST_F(SubscribeWindowTest,AddQueryRemoveStreamIdObject)64 TEST_F(SubscribeWindowTest, AddQueryRemoveStreamIdObject) {
65 SubscribeWindow window(subscribe_id_, MoqtForwardingPreference::kObject,
66 start_group_, start_object_, end_group_, end_object_);
67 window.AddStream(4, 0, 2);
68 window.AddStream(4, 1, 6);
69 window.AddStream(4, 2, 10);
70 EXPECT_QUIC_BUG(window.AddStream(4, 2, 14), "Stream already added");
71 EXPECT_EQ(*window.GetStreamForSequence(FullSequence(4, 0)), 2);
72 EXPECT_EQ(*window.GetStreamForSequence(FullSequence(4, 2)), 10);
73 EXPECT_FALSE(window.GetStreamForSequence(FullSequence(4, 4)).has_value());
74 EXPECT_FALSE(window.GetStreamForSequence(FullSequence(5, 0)).has_value());
75 window.RemoveStream(4, 2);
76 EXPECT_FALSE(window.GetStreamForSequence(FullSequence(4, 2)).has_value());
77 }
78
TEST_F(SubscribeWindowTest,AddQueryRemoveStreamIdDatagram)79 TEST_F(SubscribeWindowTest, AddQueryRemoveStreamIdDatagram) {
80 SubscribeWindow window(subscribe_id_, MoqtForwardingPreference::kDatagram,
81 start_group_, start_object_, end_group_, end_object_);
82 EXPECT_QUIC_BUG(window.AddStream(4, 0, 2), "Adding a stream for datagram");
83 }
84
85 class QUICHE_EXPORT MoqtSubscribeWindowsTest : public quic::test::QuicTest {
86 public:
MoqtSubscribeWindowsTest()87 MoqtSubscribeWindowsTest() : windows_(MoqtForwardingPreference::kObject) {}
88 MoqtSubscribeWindows windows_;
89 };
90
TEST_F(MoqtSubscribeWindowsTest,IsEmpty)91 TEST_F(MoqtSubscribeWindowsTest, IsEmpty) {
92 EXPECT_TRUE(windows_.IsEmpty());
93 windows_.AddWindow(0, 1, 3);
94 EXPECT_FALSE(windows_.IsEmpty());
95 }
96
TEST_F(MoqtSubscribeWindowsTest,IsSubscribed)97 TEST_F(MoqtSubscribeWindowsTest, IsSubscribed) {
98 EXPECT_TRUE(windows_.IsEmpty());
99 // The first two windows overlap; the third is open-ended.
100 windows_.AddWindow(0, 1, 0, 3, 9);
101 windows_.AddWindow(1, 2, 4, 4, 3);
102 windows_.AddWindow(2, 10, 0);
103 EXPECT_FALSE(windows_.IsEmpty());
104 EXPECT_TRUE(windows_.SequenceIsSubscribed(FullSequence(0, 8)).empty());
105 auto hits = windows_.SequenceIsSubscribed(FullSequence(1, 0));
106 EXPECT_EQ(hits.size(), 1);
107 EXPECT_EQ(hits[0]->subscribe_id(), 0);
108 EXPECT_TRUE(windows_.SequenceIsSubscribed(FullSequence(4, 4)).empty());
109 EXPECT_TRUE(windows_.SequenceIsSubscribed(FullSequence(8, 3)).empty());
110 hits = windows_.SequenceIsSubscribed(FullSequence(100, 7));
111 EXPECT_EQ(hits.size(), 1);
112 EXPECT_EQ(hits[0]->subscribe_id(), 2);
113 hits = windows_.SequenceIsSubscribed(FullSequence(3, 0));
114 EXPECT_EQ(hits.size(), 2);
115 EXPECT_EQ(hits[0]->subscribe_id() + hits[1]->subscribe_id(), 1);
116 }
117
TEST_F(MoqtSubscribeWindowsTest,AddGetRemoveWindow)118 TEST_F(MoqtSubscribeWindowsTest, AddGetRemoveWindow) {
119 windows_.AddWindow(0, 1, 0, 3, 9);
120 SubscribeWindow* window = windows_.GetWindow(0);
121 EXPECT_EQ(window->subscribe_id(), 0);
122 EXPECT_EQ(windows_.GetWindow(1), nullptr);
123 windows_.RemoveWindow(0);
124 EXPECT_EQ(windows_.GetWindow(0), nullptr);
125 }
126
127 } // namespace test
128
129 } // namespace moqt
130