DataChannel: Add open/close stress test

Repeatedly open and close data channels on a peer connection
to check that the channels are properly negotiated and SCTP
stream IDs properly recycled.

Bug: webrtc:13994, chromium:1320194
Change-Id: I244911abb5abaf0a290de07a0d790cd1edffe8cb
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/260984
Commit-Queue: Florent Castelli <orphis@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Auto-Submit: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36780}
This commit is contained in:
Florent Castelli 2022-05-04 00:28:06 +02:00 committed by WebRTC LUCI CQ
parent 3180a5ad06
commit d4d97eb04d
2 changed files with 80 additions and 16 deletions

View File

@ -482,6 +482,69 @@ TEST_P(DataChannelIntegrationTest, StressTestUnorderedSctpDataChannel) {
EXPECT_EQ(sent_messages, callee_received_messages);
}
// Repeatedly open and close data channels on a peer connection to check that
// the channels are properly negotiated and SCTP stream IDs properly recycled.
TEST_P(DataChannelIntegrationTest, StressTestOpenCloseChannel) {
ASSERT_TRUE(CreatePeerConnectionWrappers());
ConnectFakeSignaling();
int channel_id = 0;
const size_t kChannelCount = 8;
const size_t kIterations = 10;
bool has_negotiated = false;
webrtc::DataChannelInit init;
for (size_t repeats = 0; repeats < kIterations; ++repeats) {
RTC_LOG(LS_INFO) << "Iteration " << (repeats + 1) << "/" << kIterations;
for (size_t i = 0; i < kChannelCount; ++i) {
rtc::StringBuilder sb;
sb << "channel-" << channel_id++;
caller()->CreateDataChannel(sb.Release(), &init);
}
ASSERT_EQ(caller()->data_channels().size(), kChannelCount);
if (!has_negotiated) {
caller()->CreateAndSetAndSignalOffer();
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
has_negotiated = true;
}
for (size_t i = 0; i < kChannelCount; ++i) {
EXPECT_EQ_WAIT(caller()->data_channels()[i]->state(),
DataChannelInterface::DataState::kOpen, kDefaultTimeout);
RTC_LOG(LS_INFO) << "Caller Channel "
<< caller()->data_channels()[i]->label() << " with id "
<< caller()->data_channels()[i]->id() << " is open.";
}
ASSERT_EQ_WAIT(callee()->data_channels().size(), kChannelCount,
kDefaultTimeout);
for (size_t i = 0; i < kChannelCount; ++i) {
EXPECT_EQ_WAIT(callee()->data_channels()[i]->state(),
DataChannelInterface::DataState::kOpen, kDefaultTimeout);
RTC_LOG(LS_INFO) << "Callee Channel "
<< callee()->data_channels()[i]->label() << " with id "
<< callee()->data_channels()[i]->id() << " is open.";
}
for (size_t i = 0; i < kChannelCount; ++i) {
caller()->data_channels()[i]->Close();
}
for (size_t i = 0; i < kChannelCount; ++i) {
EXPECT_EQ_WAIT(caller()->data_channels()[i]->state(),
DataChannelInterface::DataState::kClosed, kDefaultTimeout);
EXPECT_EQ_WAIT(callee()->data_channels()[i]->state(),
DataChannelInterface::DataState::kClosed, kDefaultTimeout);
}
caller()->data_channels().clear();
caller()->data_observers().clear();
callee()->data_channels().clear();
callee()->data_observers().clear();
}
}
// This test sets up a call between two parties with audio, and video. When
// audio and video are setup and flowing, an SCTP data channel is negotiated.
TEST_P(DataChannelIntegrationTest, AddSctpDataChannelInSubsequentOffer) {
@ -512,10 +575,10 @@ TEST_P(DataChannelIntegrationTest, AddSctpDataChannelInSubsequentOffer) {
kDefaultTimeout);
}
// Set up a connection initially just using SCTP data channels, later upgrading
// to audio/video, ensuring frames are received end-to-end. Effectively the
// inverse of the test above.
// This was broken in M57; see https://crbug.com/711243
// Set up a connection initially just using SCTP data channels, later
// upgrading to audio/video, ensuring frames are received end-to-end.
// Effectively the inverse of the test above. This was broken in M57; see
// https://crbug.com/711243
TEST_P(DataChannelIntegrationTest, SctpDataChannelToAudioVideoUpgrade) {
ASSERT_TRUE(CreatePeerConnectionWrappers());
ConnectFakeSignaling();
@ -573,8 +636,8 @@ TEST_P(DataChannelIntegrationTest,
kDefaultTimeout);
}
// Test that after closing PeerConnections, they stop sending any packets (ICE,
// DTLS, RTP...).
// Test that after closing PeerConnections, they stop sending any packets
// (ICE, DTLS, RTP...).
TEST_P(DataChannelIntegrationTest, ClosingConnectionStopsPacketFlow) {
// Set up audio/video/data, wait for some frames to be received.
ASSERT_TRUE(CreatePeerConnectionWrappers());
@ -629,9 +692,8 @@ TEST_P(DataChannelIntegrationTest, DtlsRoleIsSetNormally) {
->Information()
.role(),
DtlsTransportTlsRole::kClient);
// ID should be assigned according to the odd/even rule based on role; client
// gets even numbers, server gets odd ones.
// RFC 8832 section 6.
// ID should be assigned according to the odd/even rule based on role;
// client gets even numbers, server gets odd ones. RFC 8832 section 6.
// TODO(hta): Test multiple channels.
EXPECT_EQ(caller()->data_channel()->id(), 1);
}
@ -667,9 +729,8 @@ TEST_P(DataChannelIntegrationTest, DtlsRoleIsSetWhenReversed) {
->Information()
.role(),
DtlsTransportTlsRole::kServer);
// ID should be assigned according to the odd/even rule based on role; client
// gets even numbers, server gets odd ones.
// RFC 8832 section 6.
// ID should be assigned according to the odd/even rule based on role;
// client gets even numbers, server gets odd ones. RFC 8832 section 6.
// TODO(hta): Test multiple channels.
EXPECT_EQ(caller()->data_channel()->id(), 0);
}
@ -712,9 +773,8 @@ TEST_P(DataChannelIntegrationTest,
->Information()
.role(),
DtlsTransportTlsRole::kServer);
// ID should be assigned according to the odd/even rule based on role; client
// gets even numbers, server gets odd ones.
// RFC 8832 section 6.
// ID should be assigned according to the odd/even rule based on role;
// client gets even numbers, server gets odd ones. RFC 8832 section 6.
ASSERT_EQ(caller()->data_channels().size(), 2U);
ASSERT_EQ(callee()->data_channels().size(), 2U);
EXPECT_EQ(caller()->data_channels()[0]->id(), 0);

View File

@ -426,7 +426,7 @@ class PeerConnectionIntegrationWrapper : public webrtc::PeerConnectionObserver,
return data_channels_.back().get();
}
// Return all data channels.
const std::vector<rtc::scoped_refptr<DataChannelInterface>>& data_channels() {
std::vector<rtc::scoped_refptr<DataChannelInterface>>& data_channels() {
return data_channels_;
}
@ -437,6 +437,10 @@ class PeerConnectionIntegrationWrapper : public webrtc::PeerConnectionObserver,
return data_observers_.back().get();
}
std::vector<std::unique_ptr<MockDataChannelObserver>>& data_observers() {
return data_observers_;
}
int audio_frames_received() const {
return fake_audio_capture_module_->frames_received();
}