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/packet/chunk_validators.h"
11
12 #include <utility>
13
14 #include "rtc_base/gunit.h"
15 #include "test/gmock.h"
16
17 namespace dcsctp {
18 namespace {
19 using ::testing::ElementsAre;
20 using ::testing::IsEmpty;
21
TEST(ChunkValidatorsTest,NoGapAckBlocksAreValid)22 TEST(ChunkValidatorsTest, NoGapAckBlocksAreValid) {
23 SackChunk sack(TSN(123), /*a_rwnd=*/456,
24 /*gap_ack_blocks=*/{}, {});
25
26 EXPECT_TRUE(ChunkValidators::Validate(sack));
27
28 SackChunk clean = ChunkValidators::Clean(std::move(sack));
29 EXPECT_THAT(clean.gap_ack_blocks(), IsEmpty());
30 }
31
TEST(ChunkValidatorsTest,OneValidAckBlock)32 TEST(ChunkValidatorsTest, OneValidAckBlock) {
33 SackChunk sack(TSN(123), /*a_rwnd=*/456, {SackChunk::GapAckBlock(2, 3)}, {});
34
35 EXPECT_TRUE(ChunkValidators::Validate(sack));
36
37 SackChunk clean = ChunkValidators::Clean(std::move(sack));
38 EXPECT_THAT(clean.gap_ack_blocks(),
39 ElementsAre(SackChunk::GapAckBlock(2, 3)));
40 }
41
TEST(ChunkValidatorsTest,TwoValidAckBlocks)42 TEST(ChunkValidatorsTest, TwoValidAckBlocks) {
43 SackChunk sack(TSN(123), /*a_rwnd=*/456,
44 {SackChunk::GapAckBlock(2, 3), SackChunk::GapAckBlock(5, 6)},
45 {});
46
47 EXPECT_TRUE(ChunkValidators::Validate(sack));
48
49 SackChunk clean = ChunkValidators::Clean(std::move(sack));
50 EXPECT_THAT(
51 clean.gap_ack_blocks(),
52 ElementsAre(SackChunk::GapAckBlock(2, 3), SackChunk::GapAckBlock(5, 6)));
53 }
54
TEST(ChunkValidatorsTest,OneInvalidAckBlock)55 TEST(ChunkValidatorsTest, OneInvalidAckBlock) {
56 SackChunk sack(TSN(123), /*a_rwnd=*/456, {SackChunk::GapAckBlock(1, 2)}, {});
57
58 EXPECT_FALSE(ChunkValidators::Validate(sack));
59
60 // It's not strictly valid, but due to the renegable nature of gap ack blocks,
61 // the cum_ack_tsn can't simply be moved.
62 SackChunk clean = ChunkValidators::Clean(std::move(sack));
63 EXPECT_THAT(clean.gap_ack_blocks(),
64 ElementsAre(SackChunk::GapAckBlock(1, 2)));
65 }
66
TEST(ChunkValidatorsTest,RemovesInvalidGapAckBlockFromSack)67 TEST(ChunkValidatorsTest, RemovesInvalidGapAckBlockFromSack) {
68 SackChunk sack(TSN(123), /*a_rwnd=*/456,
69 {SackChunk::GapAckBlock(2, 3), SackChunk::GapAckBlock(6, 4)},
70 {});
71
72 EXPECT_FALSE(ChunkValidators::Validate(sack));
73
74 SackChunk clean = ChunkValidators::Clean(std::move(sack));
75
76 EXPECT_THAT(clean.gap_ack_blocks(),
77 ElementsAre(SackChunk::GapAckBlock(2, 3)));
78 }
79
TEST(ChunkValidatorsTest,SortsGapAckBlocksInOrder)80 TEST(ChunkValidatorsTest, SortsGapAckBlocksInOrder) {
81 SackChunk sack(TSN(123), /*a_rwnd=*/456,
82 {SackChunk::GapAckBlock(6, 7), SackChunk::GapAckBlock(3, 4)},
83 {});
84
85 EXPECT_FALSE(ChunkValidators::Validate(sack));
86
87 SackChunk clean = ChunkValidators::Clean(std::move(sack));
88
89 EXPECT_THAT(
90 clean.gap_ack_blocks(),
91 ElementsAre(SackChunk::GapAckBlock(3, 4), SackChunk::GapAckBlock(6, 7)));
92 }
93
TEST(ChunkValidatorsTest,MergesAdjacentBlocks)94 TEST(ChunkValidatorsTest, MergesAdjacentBlocks) {
95 SackChunk sack(TSN(123), /*a_rwnd=*/456,
96 {SackChunk::GapAckBlock(3, 4), SackChunk::GapAckBlock(5, 6)},
97 {});
98
99 EXPECT_FALSE(ChunkValidators::Validate(sack));
100
101 SackChunk clean = ChunkValidators::Clean(std::move(sack));
102
103 EXPECT_THAT(clean.gap_ack_blocks(),
104 ElementsAre(SackChunk::GapAckBlock(3, 6)));
105 }
106
TEST(ChunkValidatorsTest,MergesOverlappingByOne)107 TEST(ChunkValidatorsTest, MergesOverlappingByOne) {
108 SackChunk sack(TSN(123), /*a_rwnd=*/456,
109 {SackChunk::GapAckBlock(3, 4), SackChunk::GapAckBlock(4, 5)},
110 {});
111
112 SackChunk clean = ChunkValidators::Clean(std::move(sack));
113
114 EXPECT_FALSE(ChunkValidators::Validate(sack));
115
116 EXPECT_THAT(clean.gap_ack_blocks(),
117 ElementsAre(SackChunk::GapAckBlock(3, 5)));
118 }
119
TEST(ChunkValidatorsTest,MergesOverlappingByMore)120 TEST(ChunkValidatorsTest, MergesOverlappingByMore) {
121 SackChunk sack(TSN(123), /*a_rwnd=*/456,
122 {SackChunk::GapAckBlock(3, 10), SackChunk::GapAckBlock(4, 5)},
123 {});
124
125 EXPECT_FALSE(ChunkValidators::Validate(sack));
126
127 SackChunk clean = ChunkValidators::Clean(std::move(sack));
128
129 EXPECT_THAT(clean.gap_ack_blocks(),
130 ElementsAre(SackChunk::GapAckBlock(3, 10)));
131 }
132
TEST(ChunkValidatorsTest,MergesBlocksStartingWithSameStartOffset)133 TEST(ChunkValidatorsTest, MergesBlocksStartingWithSameStartOffset) {
134 SackChunk sack(TSN(123), /*a_rwnd=*/456,
135 {SackChunk::GapAckBlock(3, 7), SackChunk::GapAckBlock(3, 5),
136 SackChunk::GapAckBlock(3, 9)},
137 {});
138
139 EXPECT_FALSE(ChunkValidators::Validate(sack));
140
141 SackChunk clean = ChunkValidators::Clean(std::move(sack));
142
143 EXPECT_THAT(clean.gap_ack_blocks(),
144 ElementsAre(SackChunk::GapAckBlock(3, 9)));
145 }
146
TEST(ChunkValidatorsTest,MergesBlocksPartiallyOverlapping)147 TEST(ChunkValidatorsTest, MergesBlocksPartiallyOverlapping) {
148 SackChunk sack(TSN(123), /*a_rwnd=*/456,
149 {SackChunk::GapAckBlock(3, 7), SackChunk::GapAckBlock(5, 9)},
150 {});
151
152 EXPECT_FALSE(ChunkValidators::Validate(sack));
153
154 SackChunk clean = ChunkValidators::Clean(std::move(sack));
155
156 EXPECT_THAT(clean.gap_ack_blocks(),
157 ElementsAre(SackChunk::GapAckBlock(3, 9)));
158 }
159
160 } // namespace
161 } // namespace dcsctp
162