xref: /aosp_15_r20/external/webrtc/net/dcsctp/rx/traditional_reassembly_streams_test.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 #include "net/dcsctp/rx/traditional_reassembly_streams.h"
11 
12 #include <cstdint>
13 #include <memory>
14 #include <utility>
15 
16 #include "net/dcsctp/common/handover_testing.h"
17 #include "net/dcsctp/common/sequence_numbers.h"
18 #include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
19 #include "net/dcsctp/packet/chunk/forward_tsn_common.h"
20 #include "net/dcsctp/packet/data.h"
21 #include "net/dcsctp/rx/reassembly_streams.h"
22 #include "net/dcsctp/testing/data_generator.h"
23 #include "rtc_base/gunit.h"
24 #include "test/gmock.h"
25 
26 namespace dcsctp {
27 namespace {
28 using ::testing::ElementsAre;
29 using ::testing::MockFunction;
30 using ::testing::NiceMock;
31 using ::testing::Property;
32 
33 class TraditionalReassemblyStreamsTest : public testing::Test {
34  protected:
tsn(uint32_t value)35   UnwrappedTSN tsn(uint32_t value) { return tsn_.Unwrap(TSN(value)); }
36 
TraditionalReassemblyStreamsTest()37   TraditionalReassemblyStreamsTest() {}
38   DataGenerator gen_;
39   UnwrappedTSN::Unwrapper tsn_;
40 };
41 
TEST_F(TraditionalReassemblyStreamsTest,AddUnorderedMessageReturnsCorrectSize)42 TEST_F(TraditionalReassemblyStreamsTest,
43        AddUnorderedMessageReturnsCorrectSize) {
44   NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
45 
46   TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
47 
48   EXPECT_EQ(streams.Add(tsn(1), gen_.Unordered({1}, "B")), 1);
49   EXPECT_EQ(streams.Add(tsn(2), gen_.Unordered({2, 3, 4})), 3);
50   EXPECT_EQ(streams.Add(tsn(3), gen_.Unordered({5, 6})), 2);
51   // Adding the end fragment should make it empty again.
52   EXPECT_EQ(streams.Add(tsn(4), gen_.Unordered({7}, "E")), -6);
53 }
54 
TEST_F(TraditionalReassemblyStreamsTest,AddSimpleOrderedMessageReturnsCorrectSize)55 TEST_F(TraditionalReassemblyStreamsTest,
56        AddSimpleOrderedMessageReturnsCorrectSize) {
57   NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
58 
59   TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
60 
61   EXPECT_EQ(streams.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
62   EXPECT_EQ(streams.Add(tsn(2), gen_.Ordered({2, 3, 4})), 3);
63   EXPECT_EQ(streams.Add(tsn(3), gen_.Ordered({5, 6})), 2);
64   EXPECT_EQ(streams.Add(tsn(4), gen_.Ordered({7}, "E")), -6);
65 }
66 
TEST_F(TraditionalReassemblyStreamsTest,AddMoreComplexOrderedMessageReturnsCorrectSize)67 TEST_F(TraditionalReassemblyStreamsTest,
68        AddMoreComplexOrderedMessageReturnsCorrectSize) {
69   NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
70 
71   TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
72 
73   EXPECT_EQ(streams.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
74   Data late = gen_.Ordered({2, 3, 4});
75   EXPECT_EQ(streams.Add(tsn(3), gen_.Ordered({5, 6})), 2);
76   EXPECT_EQ(streams.Add(tsn(4), gen_.Ordered({7}, "E")), 1);
77 
78   EXPECT_EQ(streams.Add(tsn(5), gen_.Ordered({1}, "BE")), 1);
79   EXPECT_EQ(streams.Add(tsn(6), gen_.Ordered({5, 6}, "B")), 2);
80   EXPECT_EQ(streams.Add(tsn(7), gen_.Ordered({7}, "E")), 1);
81   EXPECT_EQ(streams.Add(tsn(2), std::move(late)), -8);
82 }
83 
TEST_F(TraditionalReassemblyStreamsTest,DeleteUnorderedMessageReturnsCorrectSize)84 TEST_F(TraditionalReassemblyStreamsTest,
85        DeleteUnorderedMessageReturnsCorrectSize) {
86   NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
87 
88   TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
89 
90   EXPECT_EQ(streams.Add(tsn(1), gen_.Unordered({1}, "B")), 1);
91   EXPECT_EQ(streams.Add(tsn(2), gen_.Unordered({2, 3, 4})), 3);
92   EXPECT_EQ(streams.Add(tsn(3), gen_.Unordered({5, 6})), 2);
93 
94   EXPECT_EQ(streams.HandleForwardTsn(tsn(3), {}), 6u);
95 }
96 
TEST_F(TraditionalReassemblyStreamsTest,DeleteSimpleOrderedMessageReturnsCorrectSize)97 TEST_F(TraditionalReassemblyStreamsTest,
98        DeleteSimpleOrderedMessageReturnsCorrectSize) {
99   NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
100 
101   TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
102 
103   EXPECT_EQ(streams.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
104   EXPECT_EQ(streams.Add(tsn(2), gen_.Ordered({2, 3, 4})), 3);
105   EXPECT_EQ(streams.Add(tsn(3), gen_.Ordered({5, 6})), 2);
106 
107   ForwardTsnChunk::SkippedStream skipped[] = {
108       ForwardTsnChunk::SkippedStream(StreamID(1), SSN(0))};
109   EXPECT_EQ(streams.HandleForwardTsn(tsn(3), skipped), 6u);
110 }
111 
TEST_F(TraditionalReassemblyStreamsTest,DeleteManyOrderedMessagesReturnsCorrectSize)112 TEST_F(TraditionalReassemblyStreamsTest,
113        DeleteManyOrderedMessagesReturnsCorrectSize) {
114   NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
115 
116   TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
117 
118   EXPECT_EQ(streams.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
119   gen_.Ordered({2, 3, 4});
120   EXPECT_EQ(streams.Add(tsn(3), gen_.Ordered({5, 6})), 2);
121   EXPECT_EQ(streams.Add(tsn(4), gen_.Ordered({7}, "E")), 1);
122 
123   EXPECT_EQ(streams.Add(tsn(5), gen_.Ordered({1}, "BE")), 1);
124   EXPECT_EQ(streams.Add(tsn(6), gen_.Ordered({5, 6}, "B")), 2);
125   EXPECT_EQ(streams.Add(tsn(7), gen_.Ordered({7}, "E")), 1);
126 
127   // Expire all three messages
128   ForwardTsnChunk::SkippedStream skipped[] = {
129       ForwardTsnChunk::SkippedStream(StreamID(1), SSN(2))};
130   EXPECT_EQ(streams.HandleForwardTsn(tsn(8), skipped), 8u);
131 }
132 
TEST_F(TraditionalReassemblyStreamsTest,DeleteOrderedMessageDelivesTwoReturnsCorrectSize)133 TEST_F(TraditionalReassemblyStreamsTest,
134        DeleteOrderedMessageDelivesTwoReturnsCorrectSize) {
135   NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
136 
137   TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
138 
139   EXPECT_EQ(streams.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
140   gen_.Ordered({2, 3, 4});
141   EXPECT_EQ(streams.Add(tsn(3), gen_.Ordered({5, 6})), 2);
142   EXPECT_EQ(streams.Add(tsn(4), gen_.Ordered({7}, "E")), 1);
143 
144   EXPECT_EQ(streams.Add(tsn(5), gen_.Ordered({1}, "BE")), 1);
145   EXPECT_EQ(streams.Add(tsn(6), gen_.Ordered({5, 6}, "B")), 2);
146   EXPECT_EQ(streams.Add(tsn(7), gen_.Ordered({7}, "E")), 1);
147 
148   // The first ordered message expire, and the following two are delivered.
149   ForwardTsnChunk::SkippedStream skipped[] = {
150       ForwardTsnChunk::SkippedStream(StreamID(1), SSN(0))};
151   EXPECT_EQ(streams.HandleForwardTsn(tsn(4), skipped), 8u);
152 }
153 
TEST_F(TraditionalReassemblyStreamsTest,NoStreamsCanBeHandedOver)154 TEST_F(TraditionalReassemblyStreamsTest, NoStreamsCanBeHandedOver) {
155   NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
156 
157   TraditionalReassemblyStreams streams1("", on_assembled.AsStdFunction());
158   EXPECT_TRUE(streams1.GetHandoverReadiness().IsReady());
159 
160   DcSctpSocketHandoverState state;
161   streams1.AddHandoverState(state);
162   g_handover_state_transformer_for_test(&state);
163   TraditionalReassemblyStreams streams2("", on_assembled.AsStdFunction());
164   streams2.RestoreFromState(state);
165 
166   EXPECT_EQ(streams2.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
167   EXPECT_EQ(streams2.Add(tsn(2), gen_.Ordered({2, 3, 4})), 3);
168   EXPECT_EQ(streams2.Add(tsn(1), gen_.Unordered({1}, "B")), 1);
169   EXPECT_EQ(streams2.Add(tsn(2), gen_.Unordered({2, 3, 4})), 3);
170 }
171 
TEST_F(TraditionalReassemblyStreamsTest,OrderedStreamsCanBeHandedOverWhenNoUnassembledChunksExist)172 TEST_F(TraditionalReassemblyStreamsTest,
173        OrderedStreamsCanBeHandedOverWhenNoUnassembledChunksExist) {
174   NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
175 
176   TraditionalReassemblyStreams streams1("", on_assembled.AsStdFunction());
177 
178   EXPECT_EQ(streams1.Add(tsn(1), gen_.Ordered({1}, "B")), 1);
179   EXPECT_EQ(streams1.GetHandoverReadiness(),
180             HandoverReadinessStatus(
181                 HandoverUnreadinessReason::kOrderedStreamHasUnassembledChunks));
182   EXPECT_EQ(streams1.Add(tsn(2), gen_.Ordered({2, 3, 4})), 3);
183   EXPECT_EQ(streams1.GetHandoverReadiness(),
184             HandoverReadinessStatus(
185                 HandoverUnreadinessReason::kOrderedStreamHasUnassembledChunks));
186   EXPECT_EQ(streams1.Add(tsn(3), gen_.Ordered({5, 6})), 2);
187   EXPECT_EQ(streams1.GetHandoverReadiness(),
188             HandoverReadinessStatus(
189                 HandoverUnreadinessReason::kOrderedStreamHasUnassembledChunks));
190 
191   ForwardTsnChunk::SkippedStream skipped[] = {
192       ForwardTsnChunk::SkippedStream(StreamID(1), SSN(0))};
193   EXPECT_EQ(streams1.HandleForwardTsn(tsn(3), skipped), 6u);
194   EXPECT_TRUE(streams1.GetHandoverReadiness().IsReady());
195 
196   DcSctpSocketHandoverState state;
197   streams1.AddHandoverState(state);
198   g_handover_state_transformer_for_test(&state);
199   TraditionalReassemblyStreams streams2("", on_assembled.AsStdFunction());
200   streams2.RestoreFromState(state);
201   EXPECT_EQ(streams2.Add(tsn(4), gen_.Ordered({7})), 1);
202 }
203 
TEST_F(TraditionalReassemblyStreamsTest,UnorderedStreamsCanBeHandedOverWhenNoUnassembledChunksExist)204 TEST_F(TraditionalReassemblyStreamsTest,
205        UnorderedStreamsCanBeHandedOverWhenNoUnassembledChunksExist) {
206   NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
207 
208   TraditionalReassemblyStreams streams1("", on_assembled.AsStdFunction());
209 
210   EXPECT_EQ(streams1.Add(tsn(1), gen_.Unordered({1}, "B")), 1);
211   EXPECT_EQ(
212       streams1.GetHandoverReadiness(),
213       HandoverReadinessStatus(
214           HandoverUnreadinessReason::kUnorderedStreamHasUnassembledChunks));
215   EXPECT_EQ(streams1.Add(tsn(2), gen_.Unordered({2, 3, 4})), 3);
216   EXPECT_EQ(
217       streams1.GetHandoverReadiness(),
218       HandoverReadinessStatus(
219           HandoverUnreadinessReason::kUnorderedStreamHasUnassembledChunks));
220   EXPECT_EQ(streams1.Add(tsn(3), gen_.Unordered({5, 6})), 2);
221   EXPECT_EQ(
222       streams1.GetHandoverReadiness(),
223       HandoverReadinessStatus(
224           HandoverUnreadinessReason::kUnorderedStreamHasUnassembledChunks));
225 
226   EXPECT_EQ(streams1.HandleForwardTsn(tsn(3), {}), 6u);
227   EXPECT_TRUE(streams1.GetHandoverReadiness().IsReady());
228 
229   DcSctpSocketHandoverState state;
230   streams1.AddHandoverState(state);
231   g_handover_state_transformer_for_test(&state);
232   TraditionalReassemblyStreams streams2("", on_assembled.AsStdFunction());
233   streams2.RestoreFromState(state);
234   EXPECT_EQ(streams2.Add(tsn(4), gen_.Unordered({7})), 1);
235 }
236 
TEST_F(TraditionalReassemblyStreamsTest,CanDeleteFirstOrderedMessage)237 TEST_F(TraditionalReassemblyStreamsTest, CanDeleteFirstOrderedMessage) {
238   NiceMock<MockFunction<ReassemblyStreams::OnAssembledMessage>> on_assembled;
239   EXPECT_CALL(on_assembled,
240               Call(ElementsAre(tsn(2)),
241                    Property(&DcSctpMessage::payload, ElementsAre(2, 3, 4))));
242 
243   TraditionalReassemblyStreams streams("", on_assembled.AsStdFunction());
244 
245   // Not received, SID=1. TSN=1, SSN=0
246   gen_.Ordered({1}, "BE");
247   // And deleted (SID=1, TSN=1, SSN=0)
248   ForwardTsnChunk::SkippedStream skipped[] = {
249       ForwardTsnChunk::SkippedStream(StreamID(1), SSN(0))};
250   EXPECT_EQ(streams.HandleForwardTsn(tsn(1), skipped), 0u);
251 
252   // Receive SID=1, TSN=2, SSN=1
253   EXPECT_EQ(streams.Add(tsn(2), gen_.Ordered({2, 3, 4}, "BE")), 0);
254 }
255 
256 }  // namespace
257 }  // namespace dcsctp
258