mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-15 06:40:43 +01:00

This is a reland of 3df5dcac9b
Original change's description:
> Rewrite WebRtcSession media tests as PeerConnection tests
>
> Bug: webrtc:8222
> Change-Id: I782a3227e30de70eb8f6c26a48723cb3510a84ad
> Reviewed-on: https://webrtc-review.googlesource.com/6640
> Commit-Queue: Steve Anton <steveanton@webrtc.org>
> Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#20364}
Bug: webrtc:8222
Change-Id: I0a5398170d469eb9223bc781bfb417a85a72a2d2
Reviewed-on: https://webrtc-review.googlesource.com/14380
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20377}
506 lines
19 KiB
C++
506 lines
19 KiB
C++
/*
|
|
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
// This file contains tests that check the PeerConnection's signaling state
|
|
// machine, as well as tests that check basic, media-agnostic aspects of SDP.
|
|
|
|
#include <tuple>
|
|
|
|
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
|
|
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
|
|
#include "api/peerconnectionproxy.h"
|
|
#include "pc/peerconnection.h"
|
|
#include "pc/peerconnectionwrapper.h"
|
|
#include "pc/sdputils.h"
|
|
#ifdef WEBRTC_ANDROID
|
|
#include "pc/test/androidtestinitializer.h"
|
|
#endif
|
|
#include "pc/test/fakeaudiocapturemodule.h"
|
|
#include "pc/test/fakertccertificategenerator.h"
|
|
#include "rtc_base/gunit.h"
|
|
#include "rtc_base/ptr_util.h"
|
|
#include "rtc_base/stringutils.h"
|
|
#include "rtc_base/virtualsocketserver.h"
|
|
#include "test/gmock.h"
|
|
|
|
namespace webrtc {
|
|
|
|
using SignalingState = PeerConnectionInterface::SignalingState;
|
|
using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
|
|
using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
|
|
using ::testing::Bool;
|
|
using ::testing::Combine;
|
|
using ::testing::Values;
|
|
|
|
class PeerConnectionWrapperForSignalingTest : public PeerConnectionWrapper {
|
|
public:
|
|
using PeerConnectionWrapper::PeerConnectionWrapper;
|
|
|
|
bool initial_offerer() {
|
|
return GetInternalPeerConnection()->initial_offerer();
|
|
}
|
|
|
|
PeerConnection* GetInternalPeerConnection() {
|
|
auto* pci = reinterpret_cast<
|
|
PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(pc());
|
|
return reinterpret_cast<PeerConnection*>(pci->internal());
|
|
}
|
|
};
|
|
|
|
class PeerConnectionSignalingTest : public ::testing::Test {
|
|
protected:
|
|
typedef std::unique_ptr<PeerConnectionWrapperForSignalingTest> WrapperPtr;
|
|
|
|
PeerConnectionSignalingTest()
|
|
: vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
|
|
#ifdef WEBRTC_ANDROID
|
|
InitializeAndroidObjects();
|
|
#endif
|
|
pc_factory_ = CreatePeerConnectionFactory(
|
|
rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
|
|
FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
|
|
CreateBuiltinAudioDecoderFactory(), nullptr, nullptr);
|
|
}
|
|
|
|
WrapperPtr CreatePeerConnection() {
|
|
return CreatePeerConnection(RTCConfiguration());
|
|
}
|
|
|
|
WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
|
|
auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
|
|
auto pc = pc_factory_->CreatePeerConnection(config, nullptr, nullptr,
|
|
observer.get());
|
|
if (!pc) {
|
|
return nullptr;
|
|
}
|
|
|
|
return rtc::MakeUnique<PeerConnectionWrapperForSignalingTest>(
|
|
pc_factory_, pc, std::move(observer));
|
|
}
|
|
|
|
// Accepts the same arguments as CreatePeerConnection and adds default audio
|
|
// and video tracks.
|
|
template <typename... Args>
|
|
WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
|
|
auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
|
|
if (!wrapper) {
|
|
return nullptr;
|
|
}
|
|
wrapper->AddAudioTrack("a");
|
|
wrapper->AddVideoTrack("v");
|
|
return wrapper;
|
|
}
|
|
|
|
std::unique_ptr<rtc::VirtualSocketServer> vss_;
|
|
rtc::AutoSocketServerThread main_;
|
|
rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
|
|
};
|
|
|
|
TEST_F(PeerConnectionSignalingTest, SetLocalOfferTwiceWorks) {
|
|
auto caller = CreatePeerConnection();
|
|
|
|
EXPECT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
|
|
EXPECT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
|
|
}
|
|
|
|
TEST_F(PeerConnectionSignalingTest, SetRemoteOfferTwiceWorks) {
|
|
auto caller = CreatePeerConnection();
|
|
auto callee = CreatePeerConnection();
|
|
|
|
EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
|
|
EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
|
|
}
|
|
|
|
TEST_F(PeerConnectionSignalingTest, FailToSetNullLocalDescription) {
|
|
auto caller = CreatePeerConnection();
|
|
std::string error;
|
|
ASSERT_FALSE(caller->SetLocalDescription(nullptr, &error));
|
|
EXPECT_EQ("SessionDescription is NULL.", error);
|
|
}
|
|
|
|
TEST_F(PeerConnectionSignalingTest, FailToSetNullRemoteDescription) {
|
|
auto caller = CreatePeerConnection();
|
|
std::string error;
|
|
ASSERT_FALSE(caller->SetRemoteDescription(nullptr, &error));
|
|
EXPECT_EQ("SessionDescription is NULL.", error);
|
|
}
|
|
|
|
// The following parameterized test verifies that calls to various signaling
|
|
// methods on PeerConnection will succeed/fail depending on what is the
|
|
// PeerConnection's signaling state. Note that the test tries many different
|
|
// forms of SignalingState::kClosed by arriving at a valid state then calling
|
|
// |Close()|. This is intended to catch cases where the PeerConnection signaling
|
|
// method ignores the closed flag but may work/not work because of the single
|
|
// state the PeerConnection was created in before it was closed.
|
|
|
|
class PeerConnectionSignalingStateTest
|
|
: public PeerConnectionSignalingTest,
|
|
public ::testing::WithParamInterface<std::tuple<SignalingState, bool>> {
|
|
protected:
|
|
RTCConfiguration GetConfig() {
|
|
RTCConfiguration config;
|
|
config.certificates.push_back(
|
|
FakeRTCCertificateGenerator::GenerateCertificate());
|
|
return config;
|
|
}
|
|
|
|
WrapperPtr CreatePeerConnectionInState(SignalingState state) {
|
|
return CreatePeerConnectionInState(std::make_tuple(state, false));
|
|
}
|
|
|
|
WrapperPtr CreatePeerConnectionInState(
|
|
std::tuple<SignalingState, bool> state_tuple) {
|
|
SignalingState state = std::get<0>(state_tuple);
|
|
bool closed = std::get<1>(state_tuple);
|
|
|
|
auto wrapper = CreatePeerConnectionWithAudioVideo(GetConfig());
|
|
switch (state) {
|
|
case SignalingState::kStable: {
|
|
break;
|
|
}
|
|
case SignalingState::kHaveLocalOffer: {
|
|
wrapper->SetLocalDescription(wrapper->CreateOffer());
|
|
break;
|
|
}
|
|
case SignalingState::kHaveLocalPrAnswer: {
|
|
auto caller = CreatePeerConnectionWithAudioVideo(GetConfig());
|
|
wrapper->SetRemoteDescription(caller->CreateOffer());
|
|
auto answer = wrapper->CreateAnswer();
|
|
wrapper->SetLocalDescription(CloneSessionDescriptionAsType(
|
|
answer.get(), SessionDescriptionInterface::kPrAnswer));
|
|
break;
|
|
}
|
|
case SignalingState::kHaveRemoteOffer: {
|
|
auto caller = CreatePeerConnectionWithAudioVideo(GetConfig());
|
|
wrapper->SetRemoteDescription(caller->CreateOffer());
|
|
break;
|
|
}
|
|
case SignalingState::kHaveRemotePrAnswer: {
|
|
auto callee = CreatePeerConnectionWithAudioVideo(GetConfig());
|
|
callee->SetRemoteDescription(wrapper->CreateOfferAndSetAsLocal());
|
|
auto answer = callee->CreateAnswer();
|
|
wrapper->SetRemoteDescription(CloneSessionDescriptionAsType(
|
|
answer.get(), SessionDescriptionInterface::kPrAnswer));
|
|
break;
|
|
}
|
|
case SignalingState::kClosed: {
|
|
RTC_NOTREACHED() << "Set the second member of the tuple to true to "
|
|
"achieve a closed state from an existing, valid "
|
|
"state.";
|
|
}
|
|
}
|
|
|
|
RTC_DCHECK_EQ(state, wrapper->pc()->signaling_state());
|
|
|
|
if (closed) {
|
|
wrapper->pc()->Close();
|
|
RTC_DCHECK_EQ(SignalingState::kClosed, wrapper->signaling_state());
|
|
}
|
|
|
|
return wrapper;
|
|
}
|
|
};
|
|
|
|
::testing::AssertionResult AssertStartsWith(const char* str_expr,
|
|
const char* prefix_expr,
|
|
const std::string& str,
|
|
const std::string& prefix) {
|
|
if (rtc::starts_with(str.c_str(), prefix.c_str())) {
|
|
return ::testing::AssertionSuccess();
|
|
} else {
|
|
return ::testing::AssertionFailure()
|
|
<< str_expr << "\nwhich is\n\"" << str << "\"\ndoes not start with\n"
|
|
<< prefix_expr << "\nwhich is\n\"" << prefix << "\"";
|
|
}
|
|
}
|
|
|
|
TEST_P(PeerConnectionSignalingStateTest, CreateOffer) {
|
|
auto wrapper = CreatePeerConnectionInState(GetParam());
|
|
if (wrapper->signaling_state() != SignalingState::kClosed) {
|
|
EXPECT_TRUE(wrapper->CreateOffer());
|
|
} else {
|
|
std::string error;
|
|
ASSERT_FALSE(wrapper->CreateOffer(RTCOfferAnswerOptions(), &error));
|
|
EXPECT_PRED_FORMAT2(AssertStartsWith, error,
|
|
"CreateOffer called when PeerConnection is closed.");
|
|
}
|
|
}
|
|
|
|
TEST_P(PeerConnectionSignalingStateTest, CreateAnswer) {
|
|
auto wrapper = CreatePeerConnectionInState(GetParam());
|
|
if (wrapper->signaling_state() == SignalingState::kHaveLocalPrAnswer ||
|
|
wrapper->signaling_state() == SignalingState::kHaveRemoteOffer) {
|
|
EXPECT_TRUE(wrapper->CreateAnswer());
|
|
} else {
|
|
std::string error;
|
|
ASSERT_FALSE(wrapper->CreateAnswer(RTCOfferAnswerOptions(), &error));
|
|
if (wrapper->signaling_state() == SignalingState::kClosed) {
|
|
EXPECT_PRED_FORMAT2(AssertStartsWith, error,
|
|
"CreateAnswer called when PeerConnection is closed.");
|
|
} else if (wrapper->signaling_state() ==
|
|
SignalingState::kHaveRemotePrAnswer) {
|
|
EXPECT_PRED_FORMAT2(AssertStartsWith, error,
|
|
"CreateAnswer called without remote offer.");
|
|
} else {
|
|
EXPECT_PRED_FORMAT2(
|
|
AssertStartsWith, error,
|
|
"CreateAnswer can't be called before SetRemoteDescription.");
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_P(PeerConnectionSignalingStateTest, SetLocalOffer) {
|
|
auto wrapper = CreatePeerConnectionInState(GetParam());
|
|
if (wrapper->signaling_state() == SignalingState::kStable ||
|
|
wrapper->signaling_state() == SignalingState::kHaveLocalOffer) {
|
|
// Need to call CreateOffer on the PeerConnection under test, otherwise when
|
|
// setting the local offer it will want to verify the DTLS fingerprint
|
|
// against the locally generated certificate, but without a call to
|
|
// CreateOffer the certificate will never be generated.
|
|
EXPECT_TRUE(wrapper->SetLocalDescription(wrapper->CreateOffer()));
|
|
} else {
|
|
auto wrapper_for_offer =
|
|
CreatePeerConnectionInState(SignalingState::kHaveLocalOffer);
|
|
auto offer =
|
|
CloneSessionDescription(wrapper_for_offer->pc()->local_description());
|
|
|
|
std::string error;
|
|
ASSERT_FALSE(wrapper->SetLocalDescription(std::move(offer), &error));
|
|
EXPECT_PRED_FORMAT2(
|
|
AssertStartsWith, error,
|
|
"Failed to set local offer sdp: Called in wrong state:");
|
|
}
|
|
}
|
|
|
|
TEST_P(PeerConnectionSignalingStateTest, SetLocalPrAnswer) {
|
|
auto wrapper_for_pranswer =
|
|
CreatePeerConnectionInState(SignalingState::kHaveLocalPrAnswer);
|
|
auto pranswer =
|
|
CloneSessionDescription(wrapper_for_pranswer->pc()->local_description());
|
|
|
|
auto wrapper = CreatePeerConnectionInState(GetParam());
|
|
if (wrapper->signaling_state() == SignalingState::kHaveLocalPrAnswer ||
|
|
wrapper->signaling_state() == SignalingState::kHaveRemoteOffer) {
|
|
EXPECT_TRUE(wrapper->SetLocalDescription(std::move(pranswer)));
|
|
} else {
|
|
std::string error;
|
|
ASSERT_FALSE(wrapper->SetLocalDescription(std::move(pranswer), &error));
|
|
EXPECT_PRED_FORMAT2(
|
|
AssertStartsWith, error,
|
|
"Failed to set local pranswer sdp: Called in wrong state:");
|
|
}
|
|
}
|
|
|
|
TEST_P(PeerConnectionSignalingStateTest, SetLocalAnswer) {
|
|
auto wrapper_for_answer =
|
|
CreatePeerConnectionInState(SignalingState::kHaveRemoteOffer);
|
|
auto answer = wrapper_for_answer->CreateAnswer();
|
|
|
|
auto wrapper = CreatePeerConnectionInState(GetParam());
|
|
if (wrapper->signaling_state() == SignalingState::kHaveLocalPrAnswer ||
|
|
wrapper->signaling_state() == SignalingState::kHaveRemoteOffer) {
|
|
EXPECT_TRUE(wrapper->SetLocalDescription(std::move(answer)));
|
|
} else {
|
|
std::string error;
|
|
ASSERT_FALSE(wrapper->SetLocalDescription(std::move(answer), &error));
|
|
EXPECT_PRED_FORMAT2(
|
|
AssertStartsWith, error,
|
|
"Failed to set local answer sdp: Called in wrong state:");
|
|
}
|
|
}
|
|
|
|
TEST_P(PeerConnectionSignalingStateTest, SetRemoteOffer) {
|
|
auto wrapper_for_offer =
|
|
CreatePeerConnectionInState(SignalingState::kHaveRemoteOffer);
|
|
auto offer =
|
|
CloneSessionDescription(wrapper_for_offer->pc()->remote_description());
|
|
|
|
auto wrapper = CreatePeerConnectionInState(GetParam());
|
|
if (wrapper->signaling_state() == SignalingState::kStable ||
|
|
wrapper->signaling_state() == SignalingState::kHaveRemoteOffer) {
|
|
EXPECT_TRUE(wrapper->SetRemoteDescription(std::move(offer)));
|
|
} else {
|
|
std::string error;
|
|
ASSERT_FALSE(wrapper->SetRemoteDescription(std::move(offer), &error));
|
|
EXPECT_PRED_FORMAT2(
|
|
AssertStartsWith, error,
|
|
"Failed to set remote offer sdp: Called in wrong state:");
|
|
}
|
|
}
|
|
|
|
TEST_P(PeerConnectionSignalingStateTest, SetRemotePrAnswer) {
|
|
auto wrapper_for_pranswer =
|
|
CreatePeerConnectionInState(SignalingState::kHaveRemotePrAnswer);
|
|
auto pranswer =
|
|
CloneSessionDescription(wrapper_for_pranswer->pc()->remote_description());
|
|
|
|
auto wrapper = CreatePeerConnectionInState(GetParam());
|
|
if (wrapper->signaling_state() == SignalingState::kHaveLocalOffer ||
|
|
wrapper->signaling_state() == SignalingState::kHaveRemotePrAnswer) {
|
|
EXPECT_TRUE(wrapper->SetRemoteDescription(std::move(pranswer)));
|
|
} else {
|
|
std::string error;
|
|
ASSERT_FALSE(wrapper->SetRemoteDescription(std::move(pranswer), &error));
|
|
EXPECT_PRED_FORMAT2(
|
|
AssertStartsWith, error,
|
|
"Failed to set remote pranswer sdp: Called in wrong state:");
|
|
}
|
|
}
|
|
|
|
TEST_P(PeerConnectionSignalingStateTest, SetRemoteAnswer) {
|
|
auto wrapper_for_answer =
|
|
CreatePeerConnectionInState(SignalingState::kHaveRemoteOffer);
|
|
auto answer = wrapper_for_answer->CreateAnswer();
|
|
|
|
auto wrapper = CreatePeerConnectionInState(GetParam());
|
|
if (wrapper->signaling_state() == SignalingState::kHaveLocalOffer ||
|
|
wrapper->signaling_state() == SignalingState::kHaveRemotePrAnswer) {
|
|
EXPECT_TRUE(wrapper->SetRemoteDescription(std::move(answer)));
|
|
} else {
|
|
std::string error;
|
|
ASSERT_FALSE(wrapper->SetRemoteDescription(std::move(answer), &error));
|
|
EXPECT_PRED_FORMAT2(
|
|
AssertStartsWith, error,
|
|
"Failed to set remote answer sdp: Called in wrong state:");
|
|
}
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(PeerConnectionSignalingTest,
|
|
PeerConnectionSignalingStateTest,
|
|
Combine(Values(SignalingState::kStable,
|
|
SignalingState::kHaveLocalOffer,
|
|
SignalingState::kHaveLocalPrAnswer,
|
|
SignalingState::kHaveRemoteOffer,
|
|
SignalingState::kHaveRemotePrAnswer),
|
|
Bool()));
|
|
|
|
TEST_F(PeerConnectionSignalingTest,
|
|
CreateAnswerSucceedsIfStableAndRemoteDescriptionIsOffer) {
|
|
auto caller = CreatePeerConnection();
|
|
auto callee = CreatePeerConnection();
|
|
|
|
ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
|
|
ASSERT_TRUE(
|
|
caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
|
|
|
|
ASSERT_EQ(SignalingState::kStable, callee->signaling_state());
|
|
EXPECT_TRUE(callee->CreateAnswer());
|
|
}
|
|
|
|
TEST_F(PeerConnectionSignalingTest,
|
|
CreateAnswerFailsIfStableButRemoteDescriptionIsAnswer) {
|
|
auto caller = CreatePeerConnection();
|
|
auto callee = CreatePeerConnection();
|
|
|
|
ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
|
|
ASSERT_TRUE(
|
|
caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
|
|
|
|
ASSERT_EQ(SignalingState::kStable, caller->signaling_state());
|
|
std::string error;
|
|
ASSERT_FALSE(caller->CreateAnswer(RTCOfferAnswerOptions(), &error));
|
|
EXPECT_EQ("CreateAnswer called without remote offer.", error);
|
|
}
|
|
|
|
// According to https://tools.ietf.org/html/rfc3264#section-8, the session id
|
|
// stays the same but the version must be incremented if a later, different
|
|
// session description is generated. These two tests verify that is the case for
|
|
// both offers and answers.
|
|
TEST_F(PeerConnectionSignalingTest,
|
|
SessionVersionIncrementedInSubsequentDifferentOffer) {
|
|
auto caller = CreatePeerConnection();
|
|
auto callee = CreatePeerConnection();
|
|
|
|
auto original_offer = caller->CreateOfferAndSetAsLocal();
|
|
const std::string original_id = original_offer->session_id();
|
|
const std::string original_version = original_offer->session_version();
|
|
|
|
ASSERT_TRUE(callee->SetRemoteDescription(std::move(original_offer)));
|
|
ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateAnswer()));
|
|
|
|
// Add track to get a different offer.
|
|
caller->AddAudioTrack("a");
|
|
|
|
auto later_offer = caller->CreateOffer();
|
|
|
|
EXPECT_EQ(original_id, later_offer->session_id());
|
|
EXPECT_LT(rtc::FromString<uint64_t>(original_version),
|
|
rtc::FromString<uint64_t>(later_offer->session_version()));
|
|
}
|
|
TEST_F(PeerConnectionSignalingTest,
|
|
SessionVersionIncrementedInSubsequentDifferentAnswer) {
|
|
auto caller = CreatePeerConnection();
|
|
auto callee = CreatePeerConnection();
|
|
|
|
ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
|
|
|
|
auto original_answer = callee->CreateAnswerAndSetAsLocal();
|
|
const std::string original_id = original_answer->session_id();
|
|
const std::string original_version = original_answer->session_version();
|
|
|
|
// Add track to get a different answer.
|
|
callee->AddAudioTrack("a");
|
|
|
|
auto later_answer = callee->CreateAnswer();
|
|
|
|
EXPECT_EQ(original_id, later_answer->session_id());
|
|
EXPECT_LT(rtc::FromString<uint64_t>(original_version),
|
|
rtc::FromString<uint64_t>(later_answer->session_version()));
|
|
}
|
|
|
|
TEST_F(PeerConnectionSignalingTest, InitiatorFlagSetOnCallerAndNotOnCallee) {
|
|
auto caller = CreatePeerConnectionWithAudioVideo();
|
|
auto callee = CreatePeerConnectionWithAudioVideo();
|
|
|
|
EXPECT_FALSE(caller->initial_offerer());
|
|
EXPECT_FALSE(callee->initial_offerer());
|
|
|
|
ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
|
|
|
|
EXPECT_TRUE(caller->initial_offerer());
|
|
EXPECT_FALSE(callee->initial_offerer());
|
|
|
|
ASSERT_TRUE(
|
|
caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
|
|
|
|
EXPECT_TRUE(caller->initial_offerer());
|
|
EXPECT_FALSE(callee->initial_offerer());
|
|
}
|
|
|
|
// Test creating a PeerConnection, request multiple offers, destroy the
|
|
// PeerConnection and make sure we get success/failure callbacks for all of the
|
|
// requests.
|
|
// Background: crbug.com/507307
|
|
TEST_F(PeerConnectionSignalingTest, CreateOffersAndShutdown) {
|
|
auto caller = CreatePeerConnection();
|
|
|
|
RTCOfferAnswerOptions options;
|
|
options.offer_to_receive_audio =
|
|
RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
|
|
|
|
rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observers[100];
|
|
for (auto& observer : observers) {
|
|
observer =
|
|
new rtc::RefCountedObject<MockCreateSessionDescriptionObserver>();
|
|
caller->pc()->CreateOffer(observer, options);
|
|
}
|
|
|
|
// Destroy the PeerConnection.
|
|
caller.reset(nullptr);
|
|
|
|
for (auto& observer : observers) {
|
|
// We expect to have received a notification now even if the PeerConnection
|
|
// was terminated. The offer creation may or may not have succeeded, but we
|
|
// must have received a notification.
|
|
EXPECT_TRUE(observer->called());
|
|
}
|
|
}
|
|
|
|
} // namespace webrtc
|