Refactoring some tests in peerconnectioninterface_unittest.cc.

Some tests were passing in a local description created from hard-coded
SDP strings, which won't work in the future (since some attributes such
as the fingerprint and ICE ufrag/pwd are non-modifiable). These tests
now do the typical approach of calling CreateOffer and modifying the
result if necessary.

Also added some non-const versions of the SessionDescription accessor
helper functions, since that makes it much easier to modify a
SessionDescription. Previous alternatives were re-implementing the
helper methods from scratch, or converting the description to SDP,
modifying it, and converting it back.

R=tommi@webrtc.org

Review URL: https://codereview.webrtc.org/1966333002 .

Cr-Commit-Position: refs/heads/master@{#12704}
This commit is contained in:
Taylor Brandstetter 2016-05-12 08:14:50 -07:00
parent d8b0109327
commit dc4eb8c5b3
3 changed files with 194 additions and 87 deletions

View File

@ -239,8 +239,9 @@ static const char kSdpStringMs1Video1[] =
return; \
}
using rtc::scoped_refptr;
using ::testing::Exactly;
using cricket::StreamParams;
using rtc::scoped_refptr;
using webrtc::AudioSourceInterface;
using webrtc::AudioTrack;
using webrtc::AudioTrackInterface;
@ -248,6 +249,7 @@ using webrtc::DataBuffer;
using webrtc::DataChannelInterface;
using webrtc::FakeConstraints;
using webrtc::IceCandidateInterface;
using webrtc::JsepSessionDescription;
using webrtc::MediaConstraintsInterface;
using webrtc::MediaStream;
using webrtc::MediaStreamInterface;
@ -325,12 +327,26 @@ bool ContainsSender(
return false;
}
// Check if |senders| contains the specified sender, by id and stream id.
bool ContainsSender(
const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& senders,
const std::string& id,
const std::string& stream_id) {
for (const auto& sender : senders) {
if (sender->id() == id && sender->stream_id() == stream_id) {
return true;
}
}
return false;
}
// Create a collection of streams.
// CreateStreamCollection(1) creates a collection that
// correspond to kSdpStringWithStream1.
// CreateStreamCollection(2) correspond to kSdpStringWithStream1And2.
rtc::scoped_refptr<StreamCollection> CreateStreamCollection(
int number_of_streams) {
int number_of_streams,
int tracks_per_stream) {
rtc::scoped_refptr<StreamCollection> local_collection(
StreamCollection::Create());
@ -338,16 +354,19 @@ rtc::scoped_refptr<StreamCollection> CreateStreamCollection(
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream(
webrtc::MediaStream::Create(kStreams[i]));
// Add a local audio track.
rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
webrtc::AudioTrack::Create(kAudioTracks[i], nullptr));
stream->AddTrack(audio_track);
for (int j = 0; j < tracks_per_stream; ++j) {
// Add a local audio track.
rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
webrtc::AudioTrack::Create(kAudioTracks[i * tracks_per_stream + j],
nullptr));
stream->AddTrack(audio_track);
// Add a local video track.
rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
webrtc::VideoTrack::Create(kVideoTracks[i],
webrtc::FakeVideoTrackSource::Create()));
stream->AddTrack(video_track);
// Add a local video track.
rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
webrtc::VideoTrack::Create(kVideoTracks[i * tracks_per_stream + j],
webrtc::FakeVideoTrackSource::Create()));
stream->AddTrack(video_track);
}
local_collection->AddStream(stream);
}
@ -1984,7 +2003,7 @@ TEST_F(PeerConnectionInterfaceTest, UpdateRemoteStreams) {
CreatePeerConnection(&constraints);
CreateAndSetRemoteOffer(kSdpStringWithStream1);
rtc::scoped_refptr<StreamCollection> reference(CreateStreamCollection(1));
rtc::scoped_refptr<StreamCollection> reference(CreateStreamCollection(1, 1));
EXPECT_TRUE(
CompareStreamCollections(observer_.remote_streams(), reference.get()));
MediaStreamInterface* remote_stream = observer_.remote_streams()->at(0);
@ -1994,7 +2013,7 @@ TEST_F(PeerConnectionInterfaceTest, UpdateRemoteStreams) {
// MediaStream.
CreateAndSetRemoteOffer(kSdpStringWithStream1And2);
rtc::scoped_refptr<StreamCollection> reference2(CreateStreamCollection(2));
rtc::scoped_refptr<StreamCollection> reference2(CreateStreamCollection(2, 1));
EXPECT_TRUE(
CompareStreamCollections(observer_.remote_streams(), reference2.get()));
}
@ -2260,7 +2279,7 @@ TEST_F(PeerConnectionInterfaceTest, VerifyDefaultStreamIsNotCreated) {
true);
CreatePeerConnection(&constraints);
CreateAndSetRemoteOffer(kSdpStringWithStream1);
rtc::scoped_refptr<StreamCollection> reference(CreateStreamCollection(1));
rtc::scoped_refptr<StreamCollection> reference(CreateStreamCollection(1, 1));
EXPECT_TRUE(
CompareStreamCollections(observer_.remote_streams(), reference.get()));
@ -2277,16 +2296,15 @@ TEST_F(PeerConnectionInterfaceTest, LocalDescriptionChanged) {
constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
true);
CreatePeerConnection(&constraints);
// Create an offer just to ensure we have an identity before we manually
// call SetLocalDescription.
std::unique_ptr<SessionDescriptionInterface> throwaway;
ASSERT_TRUE(DoCreateOffer(&throwaway, nullptr));
std::unique_ptr<SessionDescriptionInterface> desc_1 =
CreateSessionDescriptionAndReference(2, 2);
// Create an offer with 1 stream with 2 tracks of each type.
rtc::scoped_refptr<StreamCollection> stream_collection =
CreateStreamCollection(1, 2);
pc_->AddStream(stream_collection->at(0));
std::unique_ptr<SessionDescriptionInterface> offer;
ASSERT_TRUE(DoCreateOffer(&offer, nullptr));
EXPECT_TRUE(DoSetLocalDescription(offer.release()));
pc_->AddStream(reference_collection_->at(0));
EXPECT_TRUE(DoSetLocalDescription(desc_1.release()));
auto senders = pc_->GetSenders();
EXPECT_EQ(4u, senders.size());
EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
@ -2295,11 +2313,12 @@ TEST_F(PeerConnectionInterfaceTest, LocalDescriptionChanged) {
EXPECT_TRUE(ContainsSender(senders, kVideoTracks[1]));
// Remove an audio and video track.
pc_->RemoveStream(reference_collection_->at(0));
std::unique_ptr<SessionDescriptionInterface> desc_2 =
CreateSessionDescriptionAndReference(1, 1);
pc_->AddStream(reference_collection_->at(0));
EXPECT_TRUE(DoSetLocalDescription(desc_2.release()));
pc_->RemoveStream(stream_collection->at(0));
stream_collection = CreateStreamCollection(1, 1);
pc_->AddStream(stream_collection->at(0));
ASSERT_TRUE(DoCreateOffer(&offer, nullptr));
EXPECT_TRUE(DoSetLocalDescription(offer.release()));
senders = pc_->GetSenders();
EXPECT_EQ(2u, senders.size());
EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
@ -2316,19 +2335,20 @@ TEST_F(PeerConnectionInterfaceTest,
constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
true);
CreatePeerConnection(&constraints);
// Create an offer just to ensure we have an identity before we manually
// call SetLocalDescription.
std::unique_ptr<SessionDescriptionInterface> throwaway;
ASSERT_TRUE(DoCreateOffer(&throwaway, nullptr));
std::unique_ptr<SessionDescriptionInterface> desc_1 =
CreateSessionDescriptionAndReference(2, 2);
rtc::scoped_refptr<StreamCollection> stream_collection =
CreateStreamCollection(1, 2);
// Add a stream to create the offer, but remove it afterwards.
pc_->AddStream(stream_collection->at(0));
std::unique_ptr<SessionDescriptionInterface> offer;
ASSERT_TRUE(DoCreateOffer(&offer, nullptr));
pc_->RemoveStream(stream_collection->at(0));
EXPECT_TRUE(DoSetLocalDescription(desc_1.release()));
EXPECT_TRUE(DoSetLocalDescription(offer.release()));
auto senders = pc_->GetSenders();
EXPECT_EQ(0u, senders.size());
pc_->AddStream(reference_collection_->at(0));
pc_->AddStream(stream_collection->at(0));
senders = pc_->GetSenders();
EXPECT_EQ(4u, senders.size());
EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
@ -2345,37 +2365,44 @@ TEST_F(PeerConnectionInterfaceTest,
constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
true);
CreatePeerConnection(&constraints);
// Create an offer just to ensure we have an identity before we manually
// call SetLocalDescription.
std::unique_ptr<SessionDescriptionInterface> throwaway;
ASSERT_TRUE(DoCreateOffer(&throwaway, nullptr));
std::unique_ptr<SessionDescriptionInterface> desc =
CreateSessionDescriptionAndReference(1, 1);
std::string sdp;
desc->ToString(&sdp);
rtc::scoped_refptr<StreamCollection> stream_collection =
CreateStreamCollection(2, 1);
pc_->AddStream(stream_collection->at(0));
std::unique_ptr<SessionDescriptionInterface> offer;
ASSERT_TRUE(DoCreateOffer(&offer, nullptr));
// Grab a copy of the offer before it gets passed into the PC.
std::unique_ptr<JsepSessionDescription> modified_offer(
new JsepSessionDescription(JsepSessionDescription::kOffer));
modified_offer->Initialize(offer->description()->Copy(), offer->session_id(),
offer->session_version());
EXPECT_TRUE(DoSetLocalDescription(offer.release()));
pc_->AddStream(reference_collection_->at(0));
EXPECT_TRUE(DoSetLocalDescription(desc.release()));
auto senders = pc_->GetSenders();
EXPECT_EQ(2u, senders.size());
EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
EXPECT_TRUE(ContainsSender(senders, kVideoTracks[0]));
// Change the ssrc of the audio and video track.
std::string ssrc_org = "a=ssrc:1";
std::string ssrc_to = "a=ssrc:97";
rtc::replace_substrs(ssrc_org.c_str(), ssrc_org.length(), ssrc_to.c_str(),
ssrc_to.length(), &sdp);
ssrc_org = "a=ssrc:2";
ssrc_to = "a=ssrc:98";
rtc::replace_substrs(ssrc_org.c_str(), ssrc_org.length(), ssrc_to.c_str(),
ssrc_to.length(), &sdp);
std::unique_ptr<SessionDescriptionInterface> updated_desc(
webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer, sdp,
nullptr));
cricket::MediaContentDescription* desc =
cricket::GetFirstAudioContentDescription(modified_offer->description());
ASSERT_TRUE(desc != NULL);
for (StreamParams& stream : desc->mutable_streams()) {
for (unsigned int& ssrc : stream.ssrcs) {
++ssrc;
}
}
EXPECT_TRUE(DoSetLocalDescription(updated_desc.release()));
desc =
cricket::GetFirstVideoContentDescription(modified_offer->description());
ASSERT_TRUE(desc != NULL);
for (StreamParams& stream : desc->mutable_streams()) {
for (unsigned int& ssrc : stream.ssrcs) {
++ssrc;
}
}
EXPECT_TRUE(DoSetLocalDescription(modified_offer.release()));
senders = pc_->GetSenders();
EXPECT_EQ(2u, senders.size());
EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
@ -2392,43 +2419,36 @@ TEST_F(PeerConnectionInterfaceTest,
constraints.AddMandatory(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp,
true);
CreatePeerConnection(&constraints);
// Create an offer just to ensure we have an identity before we manually
// call SetLocalDescription.
std::unique_ptr<SessionDescriptionInterface> throwaway;
ASSERT_TRUE(DoCreateOffer(&throwaway, nullptr));
std::unique_ptr<SessionDescriptionInterface> desc =
CreateSessionDescriptionAndReference(1, 1);
std::string sdp;
desc->ToString(&sdp);
rtc::scoped_refptr<StreamCollection> stream_collection =
CreateStreamCollection(2, 1);
pc_->AddStream(stream_collection->at(0));
std::unique_ptr<SessionDescriptionInterface> offer;
ASSERT_TRUE(DoCreateOffer(&offer, nullptr));
EXPECT_TRUE(DoSetLocalDescription(offer.release()));
pc_->AddStream(reference_collection_->at(0));
EXPECT_TRUE(DoSetLocalDescription(desc.release()));
auto senders = pc_->GetSenders();
EXPECT_EQ(2u, senders.size());
EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
EXPECT_TRUE(ContainsSender(senders, kVideoTracks[0]));
EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0], kStreams[0]));
EXPECT_TRUE(ContainsSender(senders, kVideoTracks[0], kStreams[0]));
// Add a new MediaStream but with the same tracks as in the first stream.
rtc::scoped_refptr<webrtc::MediaStreamInterface> stream_1(
webrtc::MediaStream::Create(kStreams[1]));
stream_1->AddTrack(reference_collection_->at(0)->GetVideoTracks()[0]);
stream_1->AddTrack(reference_collection_->at(0)->GetAudioTracks()[0]);
stream_1->AddTrack(stream_collection->at(0)->GetVideoTracks()[0]);
stream_1->AddTrack(stream_collection->at(0)->GetAudioTracks()[0]);
pc_->AddStream(stream_1);
// Replace msid in the original SDP.
rtc::replace_substrs(kStreams[0], strlen(kStreams[0]), kStreams[1],
strlen(kStreams[1]), &sdp);
ASSERT_TRUE(DoCreateOffer(&offer, nullptr));
EXPECT_TRUE(DoSetLocalDescription(offer.release()));
std::unique_ptr<SessionDescriptionInterface> updated_desc(
webrtc::CreateSessionDescription(SessionDescriptionInterface::kOffer, sdp,
nullptr));
EXPECT_TRUE(DoSetLocalDescription(updated_desc.release()));
senders = pc_->GetSenders();
EXPECT_EQ(2u, senders.size());
EXPECT_TRUE(ContainsSender(senders, kAudioTracks[0]));
EXPECT_TRUE(ContainsSender(senders, kVideoTracks[0]));
auto new_senders = pc_->GetSenders();
// Should be the same senders as before, but with updated stream id.
// Note that this behavior is subject to change in the future.
// We may decide the PC should ignore existing tracks in AddStream.
EXPECT_EQ(senders, new_senders);
EXPECT_TRUE(ContainsSender(new_senders, kAudioTracks[0], kStreams[1]));
EXPECT_TRUE(ContainsSender(new_senders, kVideoTracks[0], kStreams[1]));
}
// The PeerConnectionMediaConfig tests below verify that configuration

View File

@ -1919,10 +1919,9 @@ bool IsDataContent(const ContentInfo* content) {
const ContentInfo* GetFirstMediaContent(const ContentInfos& contents,
MediaType media_type) {
for (ContentInfos::const_iterator content = contents.begin();
content != contents.end(); content++) {
if (IsMediaContentOfType(&*content, media_type)) {
return &*content;
for (const ContentInfo& content : contents) {
if (IsMediaContentOfType(&content, media_type)) {
return &content;
}
}
return nullptr;
@ -1986,4 +1985,77 @@ const DataContentDescription* GetFirstDataContentDescription(
GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
}
//
// Non-const versions of the above functions.
//
ContentInfo* GetFirstMediaContent(ContentInfos& contents,
MediaType media_type) {
for (ContentInfo& content : contents) {
if (IsMediaContentOfType(&content, media_type)) {
return &content;
}
}
return nullptr;
}
ContentInfo* GetFirstAudioContent(ContentInfos& contents) {
return GetFirstMediaContent(contents, MEDIA_TYPE_AUDIO);
}
ContentInfo* GetFirstVideoContent(ContentInfos& contents) {
return GetFirstMediaContent(contents, MEDIA_TYPE_VIDEO);
}
ContentInfo* GetFirstDataContent(ContentInfos& contents) {
return GetFirstMediaContent(contents, MEDIA_TYPE_DATA);
}
static ContentInfo* GetFirstMediaContent(SessionDescription* sdesc,
MediaType media_type) {
if (sdesc == nullptr) {
return nullptr;
}
return GetFirstMediaContent(sdesc->contents(), media_type);
}
ContentInfo* GetFirstAudioContent(SessionDescription* sdesc) {
return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
}
ContentInfo* GetFirstVideoContent(SessionDescription* sdesc) {
return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
}
ContentInfo* GetFirstDataContent(SessionDescription* sdesc) {
return GetFirstMediaContent(sdesc, MEDIA_TYPE_DATA);
}
MediaContentDescription* GetFirstMediaContentDescription(
SessionDescription* sdesc,
MediaType media_type) {
ContentInfo* content = GetFirstMediaContent(sdesc, media_type);
ContentDescription* description = content ? content->description : NULL;
return static_cast<MediaContentDescription*>(description);
}
AudioContentDescription* GetFirstAudioContentDescription(
SessionDescription* sdesc) {
return static_cast<AudioContentDescription*>(
GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_AUDIO));
}
VideoContentDescription* GetFirstVideoContentDescription(
SessionDescription* sdesc) {
return static_cast<VideoContentDescription*>(
GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_VIDEO));
}
DataContentDescription* GetFirstDataContentDescription(
SessionDescription* sdesc) {
return static_cast<DataContentDescription*>(
GetFirstMediaContentDescription(sdesc, MEDIA_TYPE_DATA));
}
} // namespace cricket

View File

@ -532,6 +532,21 @@ const VideoContentDescription* GetFirstVideoContentDescription(
const SessionDescription* sdesc);
const DataContentDescription* GetFirstDataContentDescription(
const SessionDescription* sdesc);
// Non-const versions of the above functions.
// Useful when modifying an existing description.
ContentInfo* GetFirstMediaContent(ContentInfos& contents, MediaType media_type);
ContentInfo* GetFirstAudioContent(ContentInfos& contents);
ContentInfo* GetFirstVideoContent(ContentInfos& contents);
ContentInfo* GetFirstDataContent(ContentInfos& contents);
ContentInfo* GetFirstAudioContent(SessionDescription* sdesc);
ContentInfo* GetFirstVideoContent(SessionDescription* sdesc);
ContentInfo* GetFirstDataContent(SessionDescription* sdesc);
AudioContentDescription* GetFirstAudioContentDescription(
SessionDescription* sdesc);
VideoContentDescription* GetFirstVideoContentDescription(
SessionDescription* sdesc);
DataContentDescription* GetFirstDataContentDescription(
SessionDescription* sdesc);
void GetSupportedAudioCryptoSuites(std::vector<int>* crypto_suites);
void GetSupportedVideoCryptoSuites(std::vector<int>* crypto_suites);