blob: 282ce1ce53d7ae2cfd21249073c47c905c2e0ea0 [file] [log] [blame]
Steve Anton8d3444d2017-10-20 15:30:51 -07001/*
2 * Copyright 2017 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
11// This file contains tests that check the PeerConnection's signaling state
12// machine, as well as tests that check basic, media-agnostic aspects of SDP.
13
14#include <tuple>
15
16#include "api/audio_codecs/builtin_audio_decoder_factory.h"
17#include "api/audio_codecs/builtin_audio_encoder_factory.h"
18#include "api/peerconnectionproxy.h"
19#include "pc/peerconnection.h"
20#include "pc/peerconnectionwrapper.h"
21#include "pc/sdputils.h"
22#ifdef WEBRTC_ANDROID
23#include "pc/test/androidtestinitializer.h"
24#endif
25#include "pc/test/fakeaudiocapturemodule.h"
26#include "pc/test/fakertccertificategenerator.h"
27#include "rtc_base/gunit.h"
28#include "rtc_base/ptr_util.h"
29#include "rtc_base/stringutils.h"
30#include "rtc_base/virtualsocketserver.h"
31#include "test/gmock.h"
32
33namespace webrtc {
34
35using SignalingState = PeerConnectionInterface::SignalingState;
36using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
37using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
38using ::testing::Bool;
39using ::testing::Combine;
40using ::testing::Values;
41
42class PeerConnectionWrapperForSignalingTest : public PeerConnectionWrapper {
43 public:
44 using PeerConnectionWrapper::PeerConnectionWrapper;
45
46 bool initial_offerer() {
47 return GetInternalPeerConnection()->initial_offerer();
48 }
49
50 PeerConnection* GetInternalPeerConnection() {
Mirko Bonadeie97de912017-12-13 11:29:34 +010051 auto* pci =
52 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
53 pc());
54 return static_cast<PeerConnection*>(pci->internal());
Steve Anton8d3444d2017-10-20 15:30:51 -070055 }
56};
57
58class PeerConnectionSignalingTest : public ::testing::Test {
59 protected:
60 typedef std::unique_ptr<PeerConnectionWrapperForSignalingTest> WrapperPtr;
61
62 PeerConnectionSignalingTest()
63 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
64#ifdef WEBRTC_ANDROID
65 InitializeAndroidObjects();
66#endif
67 pc_factory_ = CreatePeerConnectionFactory(
68 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
69 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
70 CreateBuiltinAudioDecoderFactory(), nullptr, nullptr);
71 }
72
73 WrapperPtr CreatePeerConnection() {
74 return CreatePeerConnection(RTCConfiguration());
75 }
76
77 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
78 auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
79 auto pc = pc_factory_->CreatePeerConnection(config, nullptr, nullptr,
80 observer.get());
81 if (!pc) {
82 return nullptr;
83 }
84
85 return rtc::MakeUnique<PeerConnectionWrapperForSignalingTest>(
86 pc_factory_, pc, std::move(observer));
87 }
88
89 // Accepts the same arguments as CreatePeerConnection and adds default audio
90 // and video tracks.
91 template <typename... Args>
92 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
93 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
94 if (!wrapper) {
95 return nullptr;
96 }
97 wrapper->AddAudioTrack("a");
98 wrapper->AddVideoTrack("v");
99 return wrapper;
100 }
101
102 std::unique_ptr<rtc::VirtualSocketServer> vss_;
103 rtc::AutoSocketServerThread main_;
104 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
105};
106
107TEST_F(PeerConnectionSignalingTest, SetLocalOfferTwiceWorks) {
108 auto caller = CreatePeerConnection();
109
110 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
111 EXPECT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
112}
113
114TEST_F(PeerConnectionSignalingTest, SetRemoteOfferTwiceWorks) {
115 auto caller = CreatePeerConnection();
116 auto callee = CreatePeerConnection();
117
118 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
119 EXPECT_TRUE(callee->SetRemoteDescription(caller->CreateOffer()));
120}
121
122TEST_F(PeerConnectionSignalingTest, FailToSetNullLocalDescription) {
123 auto caller = CreatePeerConnection();
124 std::string error;
125 ASSERT_FALSE(caller->SetLocalDescription(nullptr, &error));
126 EXPECT_EQ("SessionDescription is NULL.", error);
127}
128
129TEST_F(PeerConnectionSignalingTest, FailToSetNullRemoteDescription) {
130 auto caller = CreatePeerConnection();
131 std::string error;
132 ASSERT_FALSE(caller->SetRemoteDescription(nullptr, &error));
133 EXPECT_EQ("SessionDescription is NULL.", error);
134}
135
136// The following parameterized test verifies that calls to various signaling
137// methods on PeerConnection will succeed/fail depending on what is the
138// PeerConnection's signaling state. Note that the test tries many different
139// forms of SignalingState::kClosed by arriving at a valid state then calling
140// |Close()|. This is intended to catch cases where the PeerConnection signaling
141// method ignores the closed flag but may work/not work because of the single
142// state the PeerConnection was created in before it was closed.
143
144class PeerConnectionSignalingStateTest
145 : public PeerConnectionSignalingTest,
146 public ::testing::WithParamInterface<std::tuple<SignalingState, bool>> {
147 protected:
148 RTCConfiguration GetConfig() {
149 RTCConfiguration config;
150 config.certificates.push_back(
151 FakeRTCCertificateGenerator::GenerateCertificate());
152 return config;
153 }
154
155 WrapperPtr CreatePeerConnectionInState(SignalingState state) {
156 return CreatePeerConnectionInState(std::make_tuple(state, false));
157 }
158
159 WrapperPtr CreatePeerConnectionInState(
160 std::tuple<SignalingState, bool> state_tuple) {
161 SignalingState state = std::get<0>(state_tuple);
162 bool closed = std::get<1>(state_tuple);
163
164 auto wrapper = CreatePeerConnectionWithAudioVideo(GetConfig());
165 switch (state) {
166 case SignalingState::kStable: {
167 break;
168 }
169 case SignalingState::kHaveLocalOffer: {
170 wrapper->SetLocalDescription(wrapper->CreateOffer());
171 break;
172 }
173 case SignalingState::kHaveLocalPrAnswer: {
174 auto caller = CreatePeerConnectionWithAudioVideo(GetConfig());
175 wrapper->SetRemoteDescription(caller->CreateOffer());
176 auto answer = wrapper->CreateAnswer();
Steve Antona3a92c22017-12-07 10:27:41 -0800177 wrapper->SetLocalDescription(
178 CloneSessionDescriptionAsType(answer.get(), SdpType::kPrAnswer));
Steve Anton8d3444d2017-10-20 15:30:51 -0700179 break;
180 }
181 case SignalingState::kHaveRemoteOffer: {
182 auto caller = CreatePeerConnectionWithAudioVideo(GetConfig());
183 wrapper->SetRemoteDescription(caller->CreateOffer());
184 break;
185 }
186 case SignalingState::kHaveRemotePrAnswer: {
187 auto callee = CreatePeerConnectionWithAudioVideo(GetConfig());
188 callee->SetRemoteDescription(wrapper->CreateOfferAndSetAsLocal());
189 auto answer = callee->CreateAnswer();
Steve Antona3a92c22017-12-07 10:27:41 -0800190 wrapper->SetRemoteDescription(
191 CloneSessionDescriptionAsType(answer.get(), SdpType::kPrAnswer));
Steve Anton8d3444d2017-10-20 15:30:51 -0700192 break;
193 }
194 case SignalingState::kClosed: {
195 RTC_NOTREACHED() << "Set the second member of the tuple to true to "
196 "achieve a closed state from an existing, valid "
197 "state.";
198 }
199 }
200
201 RTC_DCHECK_EQ(state, wrapper->pc()->signaling_state());
202
203 if (closed) {
204 wrapper->pc()->Close();
205 RTC_DCHECK_EQ(SignalingState::kClosed, wrapper->signaling_state());
206 }
207
208 return wrapper;
209 }
210};
211
212::testing::AssertionResult AssertStartsWith(const char* str_expr,
213 const char* prefix_expr,
214 const std::string& str,
215 const std::string& prefix) {
216 if (rtc::starts_with(str.c_str(), prefix.c_str())) {
217 return ::testing::AssertionSuccess();
218 } else {
219 return ::testing::AssertionFailure()
220 << str_expr << "\nwhich is\n\"" << str << "\"\ndoes not start with\n"
221 << prefix_expr << "\nwhich is\n\"" << prefix << "\"";
222 }
223}
224
225TEST_P(PeerConnectionSignalingStateTest, CreateOffer) {
226 auto wrapper = CreatePeerConnectionInState(GetParam());
227 if (wrapper->signaling_state() != SignalingState::kClosed) {
228 EXPECT_TRUE(wrapper->CreateOffer());
229 } else {
230 std::string error;
231 ASSERT_FALSE(wrapper->CreateOffer(RTCOfferAnswerOptions(), &error));
232 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
233 "CreateOffer called when PeerConnection is closed.");
234 }
235}
236
237TEST_P(PeerConnectionSignalingStateTest, CreateAnswer) {
238 auto wrapper = CreatePeerConnectionInState(GetParam());
239 if (wrapper->signaling_state() == SignalingState::kHaveLocalPrAnswer ||
240 wrapper->signaling_state() == SignalingState::kHaveRemoteOffer) {
241 EXPECT_TRUE(wrapper->CreateAnswer());
242 } else {
243 std::string error;
244 ASSERT_FALSE(wrapper->CreateAnswer(RTCOfferAnswerOptions(), &error));
245 if (wrapper->signaling_state() == SignalingState::kClosed) {
246 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
247 "CreateAnswer called when PeerConnection is closed.");
248 } else if (wrapper->signaling_state() ==
249 SignalingState::kHaveRemotePrAnswer) {
250 EXPECT_PRED_FORMAT2(AssertStartsWith, error,
251 "CreateAnswer called without remote offer.");
252 } else {
253 EXPECT_PRED_FORMAT2(
254 AssertStartsWith, error,
255 "CreateAnswer can't be called before SetRemoteDescription.");
256 }
257 }
258}
259
260TEST_P(PeerConnectionSignalingStateTest, SetLocalOffer) {
261 auto wrapper = CreatePeerConnectionInState(GetParam());
262 if (wrapper->signaling_state() == SignalingState::kStable ||
263 wrapper->signaling_state() == SignalingState::kHaveLocalOffer) {
264 // Need to call CreateOffer on the PeerConnection under test, otherwise when
265 // setting the local offer it will want to verify the DTLS fingerprint
266 // against the locally generated certificate, but without a call to
267 // CreateOffer the certificate will never be generated.
268 EXPECT_TRUE(wrapper->SetLocalDescription(wrapper->CreateOffer()));
269 } else {
270 auto wrapper_for_offer =
271 CreatePeerConnectionInState(SignalingState::kHaveLocalOffer);
272 auto offer =
273 CloneSessionDescription(wrapper_for_offer->pc()->local_description());
274
275 std::string error;
276 ASSERT_FALSE(wrapper->SetLocalDescription(std::move(offer), &error));
277 EXPECT_PRED_FORMAT2(
278 AssertStartsWith, error,
279 "Failed to set local offer sdp: Called in wrong state:");
280 }
281}
282
283TEST_P(PeerConnectionSignalingStateTest, SetLocalPrAnswer) {
284 auto wrapper_for_pranswer =
285 CreatePeerConnectionInState(SignalingState::kHaveLocalPrAnswer);
286 auto pranswer =
287 CloneSessionDescription(wrapper_for_pranswer->pc()->local_description());
288
289 auto wrapper = CreatePeerConnectionInState(GetParam());
290 if (wrapper->signaling_state() == SignalingState::kHaveLocalPrAnswer ||
291 wrapper->signaling_state() == SignalingState::kHaveRemoteOffer) {
292 EXPECT_TRUE(wrapper->SetLocalDescription(std::move(pranswer)));
293 } else {
294 std::string error;
295 ASSERT_FALSE(wrapper->SetLocalDescription(std::move(pranswer), &error));
296 EXPECT_PRED_FORMAT2(
297 AssertStartsWith, error,
298 "Failed to set local pranswer sdp: Called in wrong state:");
299 }
300}
301
302TEST_P(PeerConnectionSignalingStateTest, SetLocalAnswer) {
303 auto wrapper_for_answer =
304 CreatePeerConnectionInState(SignalingState::kHaveRemoteOffer);
305 auto answer = wrapper_for_answer->CreateAnswer();
306
307 auto wrapper = CreatePeerConnectionInState(GetParam());
308 if (wrapper->signaling_state() == SignalingState::kHaveLocalPrAnswer ||
309 wrapper->signaling_state() == SignalingState::kHaveRemoteOffer) {
310 EXPECT_TRUE(wrapper->SetLocalDescription(std::move(answer)));
311 } else {
312 std::string error;
313 ASSERT_FALSE(wrapper->SetLocalDescription(std::move(answer), &error));
314 EXPECT_PRED_FORMAT2(
315 AssertStartsWith, error,
316 "Failed to set local answer sdp: Called in wrong state:");
317 }
318}
319
320TEST_P(PeerConnectionSignalingStateTest, SetRemoteOffer) {
321 auto wrapper_for_offer =
322 CreatePeerConnectionInState(SignalingState::kHaveRemoteOffer);
323 auto offer =
324 CloneSessionDescription(wrapper_for_offer->pc()->remote_description());
325
326 auto wrapper = CreatePeerConnectionInState(GetParam());
327 if (wrapper->signaling_state() == SignalingState::kStable ||
328 wrapper->signaling_state() == SignalingState::kHaveRemoteOffer) {
329 EXPECT_TRUE(wrapper->SetRemoteDescription(std::move(offer)));
330 } else {
331 std::string error;
332 ASSERT_FALSE(wrapper->SetRemoteDescription(std::move(offer), &error));
333 EXPECT_PRED_FORMAT2(
334 AssertStartsWith, error,
335 "Failed to set remote offer sdp: Called in wrong state:");
336 }
337}
338
339TEST_P(PeerConnectionSignalingStateTest, SetRemotePrAnswer) {
340 auto wrapper_for_pranswer =
341 CreatePeerConnectionInState(SignalingState::kHaveRemotePrAnswer);
342 auto pranswer =
343 CloneSessionDescription(wrapper_for_pranswer->pc()->remote_description());
344
345 auto wrapper = CreatePeerConnectionInState(GetParam());
346 if (wrapper->signaling_state() == SignalingState::kHaveLocalOffer ||
347 wrapper->signaling_state() == SignalingState::kHaveRemotePrAnswer) {
348 EXPECT_TRUE(wrapper->SetRemoteDescription(std::move(pranswer)));
349 } else {
350 std::string error;
351 ASSERT_FALSE(wrapper->SetRemoteDescription(std::move(pranswer), &error));
352 EXPECT_PRED_FORMAT2(
353 AssertStartsWith, error,
354 "Failed to set remote pranswer sdp: Called in wrong state:");
355 }
356}
357
358TEST_P(PeerConnectionSignalingStateTest, SetRemoteAnswer) {
359 auto wrapper_for_answer =
360 CreatePeerConnectionInState(SignalingState::kHaveRemoteOffer);
361 auto answer = wrapper_for_answer->CreateAnswer();
362
363 auto wrapper = CreatePeerConnectionInState(GetParam());
364 if (wrapper->signaling_state() == SignalingState::kHaveLocalOffer ||
365 wrapper->signaling_state() == SignalingState::kHaveRemotePrAnswer) {
366 EXPECT_TRUE(wrapper->SetRemoteDescription(std::move(answer)));
367 } else {
368 std::string error;
369 ASSERT_FALSE(wrapper->SetRemoteDescription(std::move(answer), &error));
370 EXPECT_PRED_FORMAT2(
371 AssertStartsWith, error,
372 "Failed to set remote answer sdp: Called in wrong state:");
373 }
374}
375
376INSTANTIATE_TEST_CASE_P(PeerConnectionSignalingTest,
377 PeerConnectionSignalingStateTest,
378 Combine(Values(SignalingState::kStable,
379 SignalingState::kHaveLocalOffer,
380 SignalingState::kHaveLocalPrAnswer,
381 SignalingState::kHaveRemoteOffer,
382 SignalingState::kHaveRemotePrAnswer),
383 Bool()));
384
385TEST_F(PeerConnectionSignalingTest,
386 CreateAnswerSucceedsIfStableAndRemoteDescriptionIsOffer) {
387 auto caller = CreatePeerConnection();
388 auto callee = CreatePeerConnection();
389
390 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
391 ASSERT_TRUE(
392 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
393
394 ASSERT_EQ(SignalingState::kStable, callee->signaling_state());
395 EXPECT_TRUE(callee->CreateAnswer());
396}
397
398TEST_F(PeerConnectionSignalingTest,
399 CreateAnswerFailsIfStableButRemoteDescriptionIsAnswer) {
400 auto caller = CreatePeerConnection();
401 auto callee = CreatePeerConnection();
402
403 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
404 ASSERT_TRUE(
405 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
406
407 ASSERT_EQ(SignalingState::kStable, caller->signaling_state());
408 std::string error;
409 ASSERT_FALSE(caller->CreateAnswer(RTCOfferAnswerOptions(), &error));
410 EXPECT_EQ("CreateAnswer called without remote offer.", error);
411}
412
413// According to https://tools.ietf.org/html/rfc3264#section-8, the session id
414// stays the same but the version must be incremented if a later, different
415// session description is generated. These two tests verify that is the case for
416// both offers and answers.
417TEST_F(PeerConnectionSignalingTest,
418 SessionVersionIncrementedInSubsequentDifferentOffer) {
419 auto caller = CreatePeerConnection();
420 auto callee = CreatePeerConnection();
421
422 auto original_offer = caller->CreateOfferAndSetAsLocal();
423 const std::string original_id = original_offer->session_id();
424 const std::string original_version = original_offer->session_version();
425
426 ASSERT_TRUE(callee->SetRemoteDescription(std::move(original_offer)));
427 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateAnswer()));
428
429 // Add track to get a different offer.
430 caller->AddAudioTrack("a");
431
432 auto later_offer = caller->CreateOffer();
433
434 EXPECT_EQ(original_id, later_offer->session_id());
435 EXPECT_LT(rtc::FromString<uint64_t>(original_version),
436 rtc::FromString<uint64_t>(later_offer->session_version()));
437}
438TEST_F(PeerConnectionSignalingTest,
439 SessionVersionIncrementedInSubsequentDifferentAnswer) {
440 auto caller = CreatePeerConnection();
441 auto callee = CreatePeerConnection();
442
443 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
444
445 auto original_answer = callee->CreateAnswerAndSetAsLocal();
446 const std::string original_id = original_answer->session_id();
447 const std::string original_version = original_answer->session_version();
448
449 // Add track to get a different answer.
450 callee->AddAudioTrack("a");
451
452 auto later_answer = callee->CreateAnswer();
453
454 EXPECT_EQ(original_id, later_answer->session_id());
455 EXPECT_LT(rtc::FromString<uint64_t>(original_version),
456 rtc::FromString<uint64_t>(later_answer->session_version()));
457}
458
459TEST_F(PeerConnectionSignalingTest, InitiatorFlagSetOnCallerAndNotOnCallee) {
460 auto caller = CreatePeerConnectionWithAudioVideo();
461 auto callee = CreatePeerConnectionWithAudioVideo();
462
463 EXPECT_FALSE(caller->initial_offerer());
464 EXPECT_FALSE(callee->initial_offerer());
465
466 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
467
468 EXPECT_TRUE(caller->initial_offerer());
469 EXPECT_FALSE(callee->initial_offerer());
470
471 ASSERT_TRUE(
472 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
473
474 EXPECT_TRUE(caller->initial_offerer());
475 EXPECT_FALSE(callee->initial_offerer());
476}
477
478// Test creating a PeerConnection, request multiple offers, destroy the
479// PeerConnection and make sure we get success/failure callbacks for all of the
480// requests.
481// Background: crbug.com/507307
482TEST_F(PeerConnectionSignalingTest, CreateOffersAndShutdown) {
483 auto caller = CreatePeerConnection();
484
485 RTCOfferAnswerOptions options;
486 options.offer_to_receive_audio =
487 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
488
489 rtc::scoped_refptr<MockCreateSessionDescriptionObserver> observers[100];
490 for (auto& observer : observers) {
491 observer =
492 new rtc::RefCountedObject<MockCreateSessionDescriptionObserver>();
493 caller->pc()->CreateOffer(observer, options);
494 }
495
496 // Destroy the PeerConnection.
497 caller.reset(nullptr);
498
499 for (auto& observer : observers) {
500 // We expect to have received a notification now even if the PeerConnection
501 // was terminated. The offer creation may or may not have succeeded, but we
502 // must have received a notification.
503 EXPECT_TRUE(observer->called());
504 }
505}
506
507} // namespace webrtc