diff --git a/net/dcsctp/socket/dcsctp_socket_test.cc b/net/dcsctp/socket/dcsctp_socket_test.cc index a7e2c7a90f..4d8fc8ae86 100644 --- a/net/dcsctp/socket/dcsctp_socket_test.cc +++ b/net/dcsctp/socket/dcsctp_socket_test.cc @@ -23,6 +23,7 @@ #include "api/array_view.h" #include "net/dcsctp/common/handover_testing.h" #include "net/dcsctp/common/math.h" +#include "net/dcsctp/packet/chunk/abort_chunk.h" #include "net/dcsctp/packet/chunk/chunk.h" #include "net/dcsctp/packet/chunk/cookie_ack_chunk.h" #include "net/dcsctp/packet/chunk/cookie_echo_chunk.h" @@ -34,6 +35,7 @@ #include "net/dcsctp/packet/chunk/idata_chunk.h" #include "net/dcsctp/packet/chunk/init_ack_chunk.h" #include "net/dcsctp/packet/chunk/init_chunk.h" +#include "net/dcsctp/packet/chunk/reconfig_chunk.h" #include "net/dcsctp/packet/chunk/sack_chunk.h" #include "net/dcsctp/packet/chunk/shutdown_chunk.h" #include "net/dcsctp/packet/error_cause/error_cause.h" @@ -41,6 +43,7 @@ #include "net/dcsctp/packet/parameter/heartbeat_info_parameter.h" #include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h" #include "net/dcsctp/packet/parameter/parameter.h" +#include "net/dcsctp/packet/parameter/reconfiguration_response_parameter.h" #include "net/dcsctp/packet/sctp_packet.h" #include "net/dcsctp/packet/tlv_trait.h" #include "net/dcsctp/public/dcsctp_message.h" @@ -65,6 +68,7 @@ using ::testing::Eq; using ::testing::HasSubstr; using ::testing::IsEmpty; using ::testing::Not; +using ::testing::Property; using ::testing::SizeIs; using ::testing::UnorderedElementsAre; @@ -74,243 +78,135 @@ constexpr size_t kSmallMessageSize = 10; constexpr int kMaxBurstPackets = 4; constexpr DcSctpOptions kDefaultOptions; -MATCHER_P(HasDataChunkWithStreamId, stream_id, "") { +MATCHER_P(HasChunks, chunks, "") { absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); if (!packet.has_value()) { *result_listener << "data didn't parse as an SctpPacket"; return false; } - if (packet->descriptors()[0].type != DataChunk::kType) { - *result_listener << "the first chunk in the packet is not a data chunk"; - return false; - } - - absl::optional dc = - DataChunk::Parse(packet->descriptors()[0].data); - if (!dc.has_value()) { - *result_listener << "The first chunk didn't parse as a data chunk"; - return false; - } - - if (dc->stream_id() != stream_id) { - *result_listener << "the stream_id is " << *dc->stream_id(); - return false; - } - - return true; + return ExplainMatchResult(chunks, packet->descriptors(), result_listener); } -MATCHER_P(HasDataChunkWithPPID, ppid, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; - return false; - } - - if (packet->descriptors()[0].type != DataChunk::kType) { - *result_listener << "the first chunk in the packet is not a data chunk"; - return false; - } - - absl::optional dc = - DataChunk::Parse(packet->descriptors()[0].data); - if (!dc.has_value()) { - *result_listener << "The first chunk didn't parse as a data chunk"; - return false; - } - - if (dc->ppid() != ppid) { - *result_listener << "the ppid is " << *dc->ppid(); - return false; - } - - return true; +MATCHER_P(IsChunkType, chunk_type, "") { + return ExplainMatchResult(chunk_type, arg.type, result_listener); } -MATCHER_P(HasDataChunkWithSsn, ssn, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; +MATCHER_P(IsDataChunk, properties, "") { + if (arg.type != DataChunk::kType) { + *result_listener << "the chunk is not a data chunk"; return false; } - if (packet->descriptors()[0].type != DataChunk::kType) { - *result_listener << "the first chunk in the packet is not a data chunk"; + absl::optional chunk = DataChunk::Parse(arg.data); + if (!chunk.has_value()) { + *result_listener << "The chunk didn't parse as a data chunk"; return false; } - absl::optional dc = - DataChunk::Parse(packet->descriptors()[0].data); - if (!dc.has_value()) { - *result_listener << "The first chunk didn't parse as a data chunk"; - return false; - } - - if (dc->ssn() != ssn) { - *result_listener << "the ssn is " << *dc->ssn(); - return false; - } - - return true; + return ExplainMatchResult(properties, *chunk, result_listener); } -MATCHER_P(HasDataChunkWithMid, mid, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; +MATCHER_P(IsSack, properties, "") { + if (arg.type != SackChunk::kType) { + *result_listener << "the chunk is not a sack chunk"; return false; } - if (packet->descriptors()[0].type != IDataChunk::kType) { - *result_listener << "the first chunk in the packet is not an i-data chunk"; + absl::optional chunk = SackChunk::Parse(arg.data); + if (!chunk.has_value()) { + *result_listener << "The chunk didn't parse as a sack chunk"; return false; } - absl::optional dc = - IDataChunk::Parse(packet->descriptors()[0].data); - if (!dc.has_value()) { - *result_listener << "The first chunk didn't parse as an i-data chunk"; - return false; - } - - if (dc->message_id() != mid) { - *result_listener << "the mid is " << *dc->message_id(); - return false; - } - - return true; + return ExplainMatchResult(properties, *chunk, result_listener); } -MATCHER_P(HasSackWithCumAckTsn, tsn, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; +MATCHER_P(IsReConfig, properties, "") { + if (arg.type != ReConfigChunk::kType) { + *result_listener << "the chunk is not a re-config chunk"; return false; } - if (packet->descriptors()[0].type != SackChunk::kType) { - *result_listener << "the first chunk in the packet is not a data chunk"; + absl::optional chunk = ReConfigChunk::Parse(arg.data); + if (!chunk.has_value()) { + *result_listener << "The chunk didn't parse as a re-config chunk"; return false; } - absl::optional sc = - SackChunk::Parse(packet->descriptors()[0].data); - if (!sc.has_value()) { - *result_listener << "The first chunk didn't parse as a data chunk"; - return false; - } - - if (sc->cumulative_tsn_ack() != tsn) { - *result_listener << "the cum_ack_tsn is " << *sc->cumulative_tsn_ack(); - return false; - } - - return true; + return ExplainMatchResult(properties, *chunk, result_listener); } -MATCHER(HasSackWithNoGapAckBlocks, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; +MATCHER_P(IsHeartbeatAck, properties, "") { + if (arg.type != HeartbeatAckChunk::kType) { + *result_listener << "the chunk is not a HeartbeatAckChunk"; return false; } - if (packet->descriptors()[0].type != SackChunk::kType) { - *result_listener << "the first chunk in the packet is not a data chunk"; + absl::optional chunk = HeartbeatAckChunk::Parse(arg.data); + if (!chunk.has_value()) { + *result_listener << "The chunk didn't parse as a HeartbeatAckChunk"; return false; } - absl::optional sc = - SackChunk::Parse(packet->descriptors()[0].data); - if (!sc.has_value()) { - *result_listener << "The first chunk didn't parse as a data chunk"; - return false; - } - - if (!sc->gap_ack_blocks().empty()) { - *result_listener << "there are gap ack blocks"; - return false; - } - - return true; + return ExplainMatchResult(properties, *chunk, result_listener); } -MATCHER_P(HasReconfigWithStreams, streams_matcher, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; +MATCHER_P(IsHeartbeatRequest, properties, "") { + if (arg.type != HeartbeatRequestChunk::kType) { + *result_listener << "the chunk is not a HeartbeatRequestChunk"; return false; } - if (packet->descriptors()[0].type != ReConfigChunk::kType) { - *result_listener << "the first chunk in the packet is not a data chunk"; + absl::optional chunk = + HeartbeatRequestChunk::Parse(arg.data); + if (!chunk.has_value()) { + *result_listener << "The chunk didn't parse as a HeartbeatRequestChunk"; return false; } - absl::optional reconfig = - ReConfigChunk::Parse(packet->descriptors()[0].data); - if (!reconfig.has_value()) { - *result_listener << "The first chunk didn't parse as a data chunk"; - return false; - } - - const Parameters& parameters = reconfig->parameters(); - if (parameters.descriptors().size() != 1 || - parameters.descriptors()[0].type != - OutgoingSSNResetRequestParameter::kType) { - *result_listener << "Expected the reconfig chunk to have an outgoing SSN " - "reset request parameter"; - return false; - } - - absl::optional p = - OutgoingSSNResetRequestParameter::Parse(parameters.descriptors()[0].data); - testing::Matcher> matcher = streams_matcher; - if (!matcher.MatchAndExplain(p->stream_ids(), result_listener)) { - return false; - } - - return true; + return ExplainMatchResult(properties, *chunk, result_listener); } -MATCHER_P(HasReconfigWithResponse, result, "") { - absl::optional packet = SctpPacket::Parse(arg, kDefaultOptions); - if (!packet.has_value()) { - *result_listener << "data didn't parse as an SctpPacket"; +MATCHER_P(HasParameters, parameters, "") { + return ExplainMatchResult(parameters, arg.parameters().descriptors(), + result_listener); +} + +MATCHER_P(IsOutgoingResetRequest, properties, "") { + if (arg.type != OutgoingSSNResetRequestParameter::kType) { + *result_listener + << "the parameter is not an OutgoingSSNResetRequestParameter"; return false; } - if (packet->descriptors()[0].type != ReConfigChunk::kType) { - *result_listener << "the first chunk in the packet is not a reconfig chunk"; + absl::optional parameter = + OutgoingSSNResetRequestParameter::Parse(arg.data); + if (!parameter.has_value()) { + *result_listener + << "The parameter didn't parse as an OutgoingSSNResetRequestParameter"; return false; } - absl::optional reconfig = - ReConfigChunk::Parse(packet->descriptors()[0].data); - if (!reconfig.has_value()) { - *result_listener << "The first chunk didn't parse as a reconfig chunk"; + return ExplainMatchResult(properties, *parameter, result_listener); +} + +MATCHER_P(IsReconfigurationResponse, properties, "") { + if (arg.type != ReconfigurationResponseParameter::kType) { + *result_listener + << "the parameter is not an ReconfigurationResponseParameter"; return false; } - const Parameters& parameters = reconfig->parameters(); - if (parameters.descriptors().size() != 1 || - parameters.descriptors()[0].type != - ReconfigurationResponseParameter::kType) { - *result_listener << "Expected the reconfig chunk to have a " - "ReconfigurationResponse Parameter"; + absl::optional parameter = + ReconfigurationResponseParameter::Parse(arg.data); + if (!parameter.has_value()) { + *result_listener + << "The parameter didn't parse as an ReconfigurationResponseParameter"; return false; } - absl::optional p = - ReconfigurationResponseParameter::Parse(parameters.descriptors()[0].data); - if (p->result() != result) { - *result_listener << "ReconfigurationResponse Parameter doesn't contain the " - "expected result"; - return false; - } - - return true; + return ExplainMatchResult(properties, *parameter, result_listener); } TSN AddTo(TSN tsn, int delta) { @@ -634,10 +530,8 @@ TEST(DcSctpSocketTest, ResendInitAndEstablishConnection) { a.socket.Connect(); // INIT is never received by Z. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket init_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(init_packet.descriptors()[0].type, InitChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(InitChunk::kType)))); AdvanceTime(a, z, a.options.t1_init_timeout); @@ -661,19 +555,15 @@ TEST(DcSctpSocketTest, ResendingInitTooManyTimesAborts) { a.socket.Connect(); // INIT is never received by Z. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket init_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(init_packet.descriptors()[0].type, InitChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(InitChunk::kType)))); for (int i = 0; i < *a.options.max_init_retransmits; ++i) { AdvanceTime(a, z, a.options.t1_init_timeout * (1 << i)); // INIT is resent - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket resent_init_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(resent_init_packet.descriptors()[0].type, InitChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(InitChunk::kType)))); } // Another timeout, after the max init retransmits. @@ -696,10 +586,8 @@ TEST(DcSctpSocketTest, ResendCookieEchoAndEstablishConnection) { a.socket.ReceivePacket(z.cb.ConsumeSentPacket()); // COOKIE_ECHO is never received by Z. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket init_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(init_packet.descriptors()[0].type, CookieEchoChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(CookieEchoChunk::kType)))); AdvanceTime(a, z, a.options.t1_init_timeout); @@ -724,19 +612,15 @@ TEST(DcSctpSocketTest, ResendingCookieEchoTooManyTimesAborts) { a.socket.ReceivePacket(z.cb.ConsumeSentPacket()); // COOKIE_ECHO is never received by Z. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket init_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(init_packet.descriptors()[0].type, CookieEchoChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(CookieEchoChunk::kType)))); for (int i = 0; i < *a.options.max_init_retransmits; ++i) { AdvanceTime(a, z, a.options.t1_cookie_timeout * (1 << i)); // COOKIE_ECHO is resent - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket resent_init_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(resent_init_packet.descriptors()[0].type, CookieEchoChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(CookieEchoChunk::kType)))); } // Another timeout, after the max init retransmits. @@ -763,12 +647,9 @@ TEST(DcSctpSocketTest, DoesntSendMorePacketsUntilCookieAckHasBeenReceived) { a.socket.ReceivePacket(z.cb.ConsumeSentPacket()); // COOKIE_ECHO is never received by Z. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket cookie_echo_packet1, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_THAT(cookie_echo_packet1.descriptors(), SizeIs(2)); - EXPECT_EQ(cookie_echo_packet1.descriptors()[0].type, CookieEchoChunk::kType); - EXPECT_EQ(cookie_echo_packet1.descriptors()[1].type, DataChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(CookieEchoChunk::kType), + IsDataChunk(_)))); EXPECT_THAT(a.cb.ConsumeSentPacket(), IsEmpty()); @@ -784,12 +665,9 @@ TEST(DcSctpSocketTest, DoesntSendMorePacketsUntilCookieAckHasBeenReceived) { AdvanceTime(a, z, a.options.t1_cookie_timeout - a.options.rto_initial); // And this COOKIE-ECHO and DATA is also lost - never received by Z. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket cookie_echo_packet2, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_THAT(cookie_echo_packet2.descriptors(), SizeIs(2)); - EXPECT_EQ(cookie_echo_packet2.descriptors()[0].type, CookieEchoChunk::kType); - EXPECT_EQ(cookie_echo_packet2.descriptors()[1].type, DataChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(CookieEchoChunk::kType), + IsDataChunk(_)))); EXPECT_THAT(a.cb.ConsumeSentPacket(), IsEmpty()); @@ -850,10 +728,8 @@ TEST(DcSctpSocketTest, ShutdownTimerExpiresTooManyTimeClosesConnection) { AdvanceTime(a, z, DurationMs(a.options.rto_initial * (1 << i))); // Dropping every shutdown chunk. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(packet.descriptors()[0].type, ShutdownChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(ShutdownChunk::kType)))); EXPECT_TRUE(a.cb.ConsumeSentPacket().empty()); } // The last expiry, makes it abort the connection. @@ -862,10 +738,8 @@ TEST(DcSctpSocketTest, ShutdownTimerExpiresTooManyTimeClosesConnection) { a.options.rto_initial * (1 << *a.options.max_retransmissions)); EXPECT_EQ(a.socket.state(), SocketState::kClosed); - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z.options)); - EXPECT_EQ(packet.descriptors()[0].type, AbortChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsChunkType(AbortChunk::kType)))); EXPECT_TRUE(a.cb.ConsumeSentPacket().empty()); } @@ -972,15 +846,11 @@ TEST_P(DcSctpSocketParametrizedTest, SendingHeartbeatAnswersWithAck) { a.socket.ReceivePacket(b.Build()); // HEARTBEAT_ACK is sent as a reply. Capture it. - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket ack_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z->options)); - ASSERT_THAT(ack_packet.descriptors(), SizeIs(1)); - ASSERT_HAS_VALUE_AND_ASSIGN( - HeartbeatAckChunk ack, - HeartbeatAckChunk::Parse(ack_packet.descriptors()[0].data)); - ASSERT_HAS_VALUE_AND_ASSIGN(HeartbeatInfoParameter info_param, ack.info()); - EXPECT_THAT(info_param.info(), ElementsAre(1, 2, 3, 4)); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsHeartbeatAck( + Property(&HeartbeatAckChunk::info, + Optional(Property(&HeartbeatInfoParameter::info, + ElementsAre(1, 2, 3, 4)))))))); MaybeHandoverSocketAndSendMessage(a, std::move(z)); } @@ -996,20 +866,16 @@ TEST_P(DcSctpSocketParametrizedTest, ExpectHeartbeatToBeSent) { AdvanceTime(a, *z, a.options.heartbeat_interval); - std::vector hb_packet_raw = a.cb.ConsumeSentPacket(); - ASSERT_HAS_VALUE_AND_ASSIGN(SctpPacket hb_packet, - SctpPacket::Parse(hb_packet_raw, z->options)); - ASSERT_THAT(hb_packet.descriptors(), SizeIs(1)); - ASSERT_HAS_VALUE_AND_ASSIGN( - HeartbeatRequestChunk hb, - HeartbeatRequestChunk::Parse(hb_packet.descriptors()[0].data)); - ASSERT_HAS_VALUE_AND_ASSIGN(HeartbeatInfoParameter info_param, hb.info()); - + std::vector packet = a.cb.ConsumeSentPacket(); // The info is a single 64-bit number. - EXPECT_THAT(hb.info()->info(), SizeIs(8)); + EXPECT_THAT( + packet, + HasChunks(ElementsAre(IsHeartbeatRequest(Property( + &HeartbeatRequestChunk::info, + Optional(Property(&HeartbeatInfoParameter::info, SizeIs(8)))))))); // Feed it to Sock-z and expect a HEARTBEAT_ACK that will be propagated back. - z->socket.ReceivePacket(hb_packet_raw); + z->socket.ReceivePacket(packet); a.socket.ReceivePacket(z->cb.ConsumeSentPacket()); MaybeHandoverSocketAndSendMessage(a, std::move(z)); @@ -1110,10 +976,8 @@ TEST_P(DcSctpSocketParametrizedTest, RecoversAfterASuccessfulAck) { RTC_LOG(LS_INFO) << "Expecting a new heartbeat"; AdvanceTime(a, *z, time_to_next_hearbeat); - ASSERT_HAS_VALUE_AND_ASSIGN( - SctpPacket another_packet, - SctpPacket::Parse(a.cb.ConsumeSentPacket(), z->options)); - EXPECT_EQ(another_packet.descriptors()[0].type, HeartbeatRequestChunk::kType); + EXPECT_THAT(a.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsHeartbeatRequest(_)))); } TEST_P(DcSctpSocketParametrizedTest, ResetStream) { @@ -1161,11 +1025,15 @@ TEST_P(DcSctpSocketParametrizedTest, ResetStreamWillMakeChunksStartAtZeroSsn) { a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), payload), {}); auto packet1 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet1, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT( + packet1, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(0)))))); z->socket.ReceivePacket(packet1); auto packet2 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet2, HasDataChunkWithSsn(SSN(1))); + EXPECT_THAT( + packet2, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(1)))))); z->socket.ReceivePacket(packet2); // Handle SACK @@ -1191,11 +1059,15 @@ TEST_P(DcSctpSocketParametrizedTest, ResetStreamWillMakeChunksStartAtZeroSsn) { a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), payload), {}); auto packet3 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet3, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT( + packet3, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(0)))))); z->socket.ReceivePacket(packet3); auto packet4 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet4, HasDataChunkWithSsn(SSN(1))); + EXPECT_THAT( + packet4, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(1)))))); z->socket.ReceivePacket(packet4); // Handle SACK @@ -1219,13 +1091,15 @@ TEST_P(DcSctpSocketParametrizedTest, a.socket.Send(DcSctpMessage(StreamID(1), PPID(53), payload), {}); auto packet1 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet1, HasDataChunkWithStreamId(StreamID(1))); - EXPECT_THAT(packet1, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet1, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::stream_id, StreamID(1)), + Property(&DataChunk::ssn, SSN(0))))))); z->socket.ReceivePacket(packet1); auto packet2 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet1, HasDataChunkWithStreamId(StreamID(1))); - EXPECT_THAT(packet2, HasDataChunkWithSsn(SSN(1))); + EXPECT_THAT(packet2, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::stream_id, StreamID(1)), + Property(&DataChunk::ssn, SSN(1))))))); z->socket.ReceivePacket(packet2); // Handle SACK @@ -1235,12 +1109,14 @@ TEST_P(DcSctpSocketParametrizedTest, a.socket.Send(DcSctpMessage(StreamID(3), PPID(53), payload), {}); a.socket.Send(DcSctpMessage(StreamID(3), PPID(53), payload), {}); auto packet3 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet3, HasDataChunkWithStreamId(StreamID(3))); - EXPECT_THAT(packet3, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet3, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::stream_id, StreamID(3)), + Property(&DataChunk::ssn, SSN(0))))))); z->socket.ReceivePacket(packet3); auto packet4 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet4, HasDataChunkWithStreamId(StreamID(3))); - EXPECT_THAT(packet4, HasDataChunkWithSsn(SSN(1))); + EXPECT_THAT(packet4, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::stream_id, StreamID(3)), + Property(&DataChunk::ssn, SSN(1))))))); z->socket.ReceivePacket(packet4); a.socket.ReceivePacket(z->cb.ConsumeSentPacket()); @@ -1274,13 +1150,16 @@ TEST_P(DcSctpSocketParametrizedTest, a.socket.Send(DcSctpMessage(StreamID(3), PPID(53), payload), {}); auto packet5 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet5, HasDataChunkWithStreamId(StreamID(1))); - EXPECT_THAT(packet5, HasDataChunkWithSsn(SSN(2))); // Unchanged. + EXPECT_THAT(packet5, + HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::stream_id, StreamID(1)), + Property(&DataChunk::ssn, SSN(2))))))); // Unchanged. z->socket.ReceivePacket(packet5); auto packet6 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet6, HasDataChunkWithStreamId(StreamID(3))); - EXPECT_THAT(packet6, HasDataChunkWithSsn(SSN(0))); // Reset. + EXPECT_THAT(packet6, HasChunks(ElementsAre(IsDataChunk(AllOf( + Property(&DataChunk::stream_id, StreamID(3)), + Property(&DataChunk::ssn, SSN(0))))))); // Reset z->socket.ReceivePacket(packet6); // Handle SACK @@ -1400,44 +1279,52 @@ TEST_P(DcSctpSocketParametrizedTest, SendManyFragmentedMessagesWithLimitedRtx) { // First DATA, first fragment std::vector packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(51))); + EXPECT_THAT(packet, HasChunks(ElementsAre( + IsDataChunk(Property(&DataChunk::ppid, PPID(51)))))); z->socket.ReceivePacket(std::move(packet)); // First DATA, second fragment (lost) packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(51))); + EXPECT_THAT(packet, HasChunks(ElementsAre( + IsDataChunk(Property(&DataChunk::ppid, PPID(51)))))); // Second DATA, first fragment packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(52))); + EXPECT_THAT(packet, HasChunks(ElementsAre( + IsDataChunk(Property(&DataChunk::ppid, PPID(52)))))); z->socket.ReceivePacket(std::move(packet)); // Second DATA, second fragment (lost) packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(52))); - EXPECT_THAT(packet, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::ppid, PPID(52)), + Property(&DataChunk::ssn, SSN(0))))))); // Third DATA, first fragment packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(53))); - EXPECT_THAT(packet, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::ppid, PPID(53)), + Property(&DataChunk::ssn, SSN(0))))))); z->socket.ReceivePacket(std::move(packet)); // Third DATA, second fragment (lost) packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(53))); - EXPECT_THAT(packet, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::ppid, PPID(53)), + Property(&DataChunk::ssn, SSN(0))))))); // Fourth DATA, first fragment packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(54))); - EXPECT_THAT(packet, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::ppid, PPID(54)), + Property(&DataChunk::ssn, SSN(0))))))); z->socket.ReceivePacket(std::move(packet)); // Fourth DATA, second fragment packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasDataChunkWithPPID(PPID(54))); - EXPECT_THAT(packet, HasDataChunkWithSsn(SSN(0))); + EXPECT_THAT(packet, HasChunks(ElementsAre(IsDataChunk( + AllOf(Property(&DataChunk::ppid, PPID(54)), + Property(&DataChunk::ssn, SSN(0))))))); z->socket.ReceivePacket(std::move(packet)); ExchangeMessages(a, *z); @@ -1562,7 +1449,9 @@ TEST(DcSctpSocketTest, PassingHighWatermarkWillOnlyAcceptCumAckTsn) { // First DATA will always trigger a SACK. It's not interesting. EXPECT_THAT(z.cb.ConsumeSentPacket(), - AllOf(HasSackWithCumAckTsn(tsn), HasSackWithNoGapAckBlocks())); + HasChunks(ElementsAre(IsSack( + AllOf(Property(&SackChunk::cumulative_tsn_ack, tsn), + Property(&SackChunk::gap_ack_blocks, IsEmpty())))))); // This DATA should be accepted - it's advancing cum ack tsn. z.socket.ReceivePacket( @@ -1575,9 +1464,10 @@ TEST(DcSctpSocketTest, PassingHighWatermarkWillOnlyAcceptCumAckTsn) { // The receiver might have moved into delayed ack mode. AdvanceTime(a, z, z.options.rto_initial); - EXPECT_THAT( - z.cb.ConsumeSentPacket(), - AllOf(HasSackWithCumAckTsn(AddTo(tsn, 1)), HasSackWithNoGapAckBlocks())); + EXPECT_THAT(z.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsSack( + AllOf(Property(&SackChunk::cumulative_tsn_ack, AddTo(tsn, 1)), + Property(&SackChunk::gap_ack_blocks, IsEmpty())))))); // This DATA will not be accepted - it's not advancing cum ack tsn. z.socket.ReceivePacket( @@ -1588,9 +1478,10 @@ TEST(DcSctpSocketTest, PassingHighWatermarkWillOnlyAcceptCumAckTsn) { .Build()); // Sack will be sent in IMMEDIATE mode when this is happening. - EXPECT_THAT( - z.cb.ConsumeSentPacket(), - AllOf(HasSackWithCumAckTsn(AddTo(tsn, 1)), HasSackWithNoGapAckBlocks())); + EXPECT_THAT(z.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsSack( + AllOf(Property(&SackChunk::cumulative_tsn_ack, AddTo(tsn, 1)), + Property(&SackChunk::gap_ack_blocks, IsEmpty())))))); // This DATA will not be accepted either. z.socket.ReceivePacket( @@ -1601,9 +1492,10 @@ TEST(DcSctpSocketTest, PassingHighWatermarkWillOnlyAcceptCumAckTsn) { .Build()); // Sack will be sent in IMMEDIATE mode when this is happening. - EXPECT_THAT( - z.cb.ConsumeSentPacket(), - AllOf(HasSackWithCumAckTsn(AddTo(tsn, 1)), HasSackWithNoGapAckBlocks())); + EXPECT_THAT(z.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsSack( + AllOf(Property(&SackChunk::cumulative_tsn_ack, AddTo(tsn, 1)), + Property(&SackChunk::gap_ack_blocks, IsEmpty())))))); // This DATA should be accepted, and it fills the reassembly queue. z.socket.ReceivePacket( @@ -1616,9 +1508,10 @@ TEST(DcSctpSocketTest, PassingHighWatermarkWillOnlyAcceptCumAckTsn) { // The receiver might have moved into delayed ack mode. AdvanceTime(a, z, z.options.rto_initial); - EXPECT_THAT( - z.cb.ConsumeSentPacket(), - AllOf(HasSackWithCumAckTsn(AddTo(tsn, 2)), HasSackWithNoGapAckBlocks())); + EXPECT_THAT(z.cb.ConsumeSentPacket(), + HasChunks(ElementsAre(IsSack( + AllOf(Property(&SackChunk::cumulative_tsn_ack, AddTo(tsn, 2)), + Property(&SackChunk::gap_ack_blocks, IsEmpty())))))); EXPECT_CALL(z.cb, OnAborted(ErrorKind::kResourceExhaustion, _)); EXPECT_CALL(z.cb, OnClosed).Times(0); @@ -2431,7 +2324,10 @@ TEST(DcSctpSocketTest, CloseStreamsWithPendingRequest) { a.socket.ResetStreams(std::vector({StreamID(1)})); std::vector packet = a.cb.ConsumeSentPacket(); - EXPECT_THAT(packet, HasReconfigWithStreams(ElementsAre(StreamID(1)))); + EXPECT_THAT(packet, HasChunks(ElementsAre(IsReConfig(HasParameters( + ElementsAre(IsOutgoingResetRequest(Property( + &OutgoingSSNResetRequestParameter::stream_ids, + ElementsAre(StreamID(1)))))))))); z.socket.ReceivePacket(std::move(packet)); // Sending more reset requests while this one is ongoing. @@ -2813,10 +2709,19 @@ TEST(DcSctpSocketTest, ResetStreamsDeferred) { auto data3 = a.cb.ConsumeSentPacket(); auto reconfig = a.cb.ConsumeSentPacket(); - EXPECT_THAT(data1, HasDataChunkWithSsn(SSN(0))); - EXPECT_THAT(data2, HasDataChunkWithSsn(SSN(0))); - EXPECT_THAT(data3, HasDataChunkWithSsn(SSN(1))); - EXPECT_THAT(reconfig, HasReconfigWithStreams(ElementsAre(StreamID(1)))); + EXPECT_THAT( + data1, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(0)))))); + EXPECT_THAT( + data2, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(0)))))); + EXPECT_THAT( + data3, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(1)))))); + EXPECT_THAT(reconfig, HasChunks(ElementsAre(IsReConfig(HasParameters( + ElementsAre(IsOutgoingResetRequest(Property( + &OutgoingSSNResetRequestParameter::stream_ids, + ElementsAre(StreamID(1)))))))))); // Receive them slightly out of order to make stream resetting deferred. z.socket.ReceivePacket(reconfig); @@ -2845,20 +2750,34 @@ TEST(DcSctpSocketTest, ResetStreamsDeferred) { AdvanceTime(a, z, a.options.rto_initial); auto reconfig2 = a.cb.ConsumeSentPacket(); - EXPECT_THAT(reconfig2, HasReconfigWithStreams(ElementsAre(StreamID(1)))); + EXPECT_THAT(reconfig2, HasChunks(ElementsAre(IsReConfig(HasParameters( + ElementsAre(IsOutgoingResetRequest(Property( + &OutgoingSSNResetRequestParameter::stream_ids, + ElementsAre(StreamID(1)))))))))); EXPECT_CALL(z.cb, OnIncomingStreamsReset(ElementsAre(StreamID(1)))); z.socket.ReceivePacket(reconfig2); auto reconfig3 = z.cb.ConsumeSentPacket(); - EXPECT_THAT(reconfig3, - HasReconfigWithResponse( - ReconfigurationResponseParameter::Result::kSuccessPerformed)); + EXPECT_THAT(reconfig3, HasChunks(ElementsAre(IsReConfig(HasParameters( + ElementsAre(IsReconfigurationResponse(Property( + &ReconfigurationResponseParameter::result, + ReconfigurationResponseParameter::Result:: + kSuccessPerformed)))))))); a.socket.ReceivePacket(reconfig3); - EXPECT_THAT(data1, HasDataChunkWithSsn(SSN(0))); - EXPECT_THAT(data2, HasDataChunkWithSsn(SSN(0))); - EXPECT_THAT(data3, HasDataChunkWithSsn(SSN(1))); - EXPECT_THAT(reconfig, HasReconfigWithStreams(ElementsAre(StreamID(1)))); + EXPECT_THAT( + data1, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(0)))))); + EXPECT_THAT( + data2, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(0)))))); + EXPECT_THAT( + data3, + HasChunks(ElementsAre(IsDataChunk(Property(&DataChunk::ssn, SSN(1)))))); + EXPECT_THAT(reconfig, HasChunks(ElementsAre(IsReConfig(HasParameters( + ElementsAre(IsOutgoingResetRequest(Property( + &OutgoingSSNResetRequestParameter::stream_ids, + ElementsAre(StreamID(1)))))))))); // Send a new message after the stream has been reset. a.socket.Send(DcSctpMessage(StreamID(1), PPID(55),