1 /*
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 #include <memory>
12 #include <set>
13 #include <string>
14 #include <utility>
15 #include <vector>
16
17 #include "absl/types/optional.h"
18 #include "api/async_resolver_factory.h"
19 #include "api/call/call_factory_interface.h"
20 #include "api/jsep.h"
21 #include "api/jsep_session_description.h"
22 #include "api/peer_connection_interface.h"
23 #include "api/rtc_error.h"
24 #include "api/scoped_refptr.h"
25 #include "api/task_queue/default_task_queue_factory.h"
26 #include "api/task_queue/task_queue_factory.h"
27 #include "media/base/fake_media_engine.h"
28 #include "media/base/media_engine.h"
29 #include "p2p/base/mock_async_resolver.h"
30 #include "p2p/base/port_allocator.h"
31 #include "p2p/client/basic_port_allocator.h"
32 #include "pc/peer_connection.h"
33 #include "pc/peer_connection_factory.h"
34 #include "pc/peer_connection_proxy.h"
35 #include "pc/peer_connection_wrapper.h"
36 #include "pc/sdp_utils.h"
37 #include "pc/test/mock_peer_connection_observers.h"
38 #include "pc/usage_pattern.h"
39 #include "pc/webrtc_sdp.h"
40 #include "rtc_base/arraysize.h"
41 #include "rtc_base/checks.h"
42 #include "rtc_base/fake_mdns_responder.h"
43 #include "rtc_base/fake_network.h"
44 #include "rtc_base/gunit.h"
45 #include "rtc_base/mdns_responder_interface.h"
46 #include "rtc_base/socket_address.h"
47 #include "rtc_base/thread.h"
48 #include "rtc_base/virtual_socket_server.h"
49 #include "system_wrappers/include/metrics.h"
50 #include "test/gmock.h"
51 #include "test/gtest.h"
52
53 namespace webrtc {
54
55 using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
56 using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
57 using ::testing::NiceMock;
58 using ::testing::Values;
59
60 static const char kUsagePatternMetric[] = "WebRTC.PeerConnection.UsagePattern";
61 static constexpr int kDefaultTimeout = 10000;
62 static const rtc::SocketAddress kLocalAddrs[2] = {
63 rtc::SocketAddress("1.1.1.1", 0), rtc::SocketAddress("2.2.2.2", 0)};
64 static const rtc::SocketAddress kPrivateLocalAddress("10.1.1.1", 0);
65 static const rtc::SocketAddress kPrivateIpv6LocalAddress("fd12:3456:789a:1::1",
66 0);
67
MakeUsageFingerprint(std::set<UsageEvent> events)68 int MakeUsageFingerprint(std::set<UsageEvent> events) {
69 int signature = 0;
70 for (const auto it : events) {
71 signature |= static_cast<int>(it);
72 }
73 return signature;
74 }
75
76 class PeerConnectionFactoryForUsageHistogramTest
77 : public PeerConnectionFactory {
78 public:
PeerConnectionFactoryForUsageHistogramTest()79 PeerConnectionFactoryForUsageHistogramTest()
80 : PeerConnectionFactory([] {
81 PeerConnectionFactoryDependencies dependencies;
82 dependencies.network_thread = rtc::Thread::Current();
83 dependencies.worker_thread = rtc::Thread::Current();
84 dependencies.signaling_thread = rtc::Thread::Current();
85 dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
86 dependencies.media_engine =
87 std::make_unique<cricket::FakeMediaEngine>();
88 dependencies.call_factory = CreateCallFactory();
89 return dependencies;
90 }()) {}
91 };
92
93 class PeerConnectionWrapperForUsageHistogramTest;
94
95 typedef PeerConnectionWrapperForUsageHistogramTest* RawWrapperPtr;
96
97 class ObserverForUsageHistogramTest : public MockPeerConnectionObserver {
98 public:
99 void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override;
100
OnInterestingUsage(int usage_pattern)101 void OnInterestingUsage(int usage_pattern) override {
102 interesting_usage_detected_ = usage_pattern;
103 }
104
PrepareToExchangeCandidates(RawWrapperPtr other)105 void PrepareToExchangeCandidates(RawWrapperPtr other) {
106 candidate_target_ = other;
107 }
108
HaveDataChannel()109 bool HaveDataChannel() { return last_datachannel_ != nullptr; }
110
interesting_usage_detected()111 absl::optional<int> interesting_usage_detected() {
112 return interesting_usage_detected_;
113 }
114
ClearInterestingUsageDetector()115 void ClearInterestingUsageDetector() {
116 interesting_usage_detected_ = absl::optional<int>();
117 }
118
candidate_gathered() const119 bool candidate_gathered() const { return candidate_gathered_; }
120
121 private:
122 absl::optional<int> interesting_usage_detected_;
123 bool candidate_gathered_ = false;
124 RawWrapperPtr candidate_target_; // Note: Not thread-safe against deletions.
125 };
126
127 class PeerConnectionWrapperForUsageHistogramTest
128 : public PeerConnectionWrapper {
129 public:
130 using PeerConnectionWrapper::PeerConnectionWrapper;
131
GetInternalPeerConnection()132 PeerConnection* GetInternalPeerConnection() {
133 auto* pci =
134 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
135 pc());
136 return static_cast<PeerConnection*>(pci->internal());
137 }
138
139 // Override with different return type
observer()140 ObserverForUsageHistogramTest* observer() {
141 return static_cast<ObserverForUsageHistogramTest*>(
142 PeerConnectionWrapper::observer());
143 }
144
PrepareToExchangeCandidates(PeerConnectionWrapperForUsageHistogramTest * other)145 void PrepareToExchangeCandidates(
146 PeerConnectionWrapperForUsageHistogramTest* other) {
147 observer()->PrepareToExchangeCandidates(other);
148 other->observer()->PrepareToExchangeCandidates(this);
149 }
150
IsConnected()151 bool IsConnected() {
152 return pc()->ice_connection_state() ==
153 PeerConnectionInterface::kIceConnectionConnected ||
154 pc()->ice_connection_state() ==
155 PeerConnectionInterface::kIceConnectionCompleted;
156 }
157
HaveDataChannel()158 bool HaveDataChannel() {
159 return static_cast<ObserverForUsageHistogramTest*>(observer())
160 ->HaveDataChannel();
161 }
BufferIceCandidate(const webrtc::IceCandidateInterface * candidate)162 void BufferIceCandidate(const webrtc::IceCandidateInterface* candidate) {
163 std::string sdp;
164 EXPECT_TRUE(candidate->ToString(&sdp));
165 std::unique_ptr<webrtc::IceCandidateInterface> candidate_copy(
166 CreateIceCandidate(candidate->sdp_mid(), candidate->sdp_mline_index(),
167 sdp, nullptr));
168 buffered_candidates_.push_back(std::move(candidate_copy));
169 }
170
AddBufferedIceCandidates()171 void AddBufferedIceCandidates() {
172 for (const auto& candidate : buffered_candidates_) {
173 EXPECT_TRUE(pc()->AddIceCandidate(candidate.get()));
174 }
175 buffered_candidates_.clear();
176 }
177
178 // This method performs the following actions in sequence:
179 // 1. Exchange Offer and Answer.
180 // 2. Exchange ICE candidates after both caller and callee complete
181 // gathering.
182 // 3. Wait for ICE to connect.
183 //
184 // This guarantees a deterministic sequence of events and also rules out the
185 // occurrence of prflx candidates if the offer/answer signaling and the
186 // candidate trickling race in order. In case prflx candidates need to be
187 // simulated, see the approach used by tests below for that.
ConnectTo(PeerConnectionWrapperForUsageHistogramTest * callee)188 bool ConnectTo(PeerConnectionWrapperForUsageHistogramTest* callee) {
189 PrepareToExchangeCandidates(callee);
190 if (!ExchangeOfferAnswerWith(callee)) {
191 return false;
192 }
193 // Wait until the gathering completes before we signal the candidate.
194 WAIT(observer()->ice_gathering_complete_, kDefaultTimeout);
195 WAIT(callee->observer()->ice_gathering_complete_, kDefaultTimeout);
196 AddBufferedIceCandidates();
197 callee->AddBufferedIceCandidates();
198 WAIT(IsConnected(), kDefaultTimeout);
199 WAIT(callee->IsConnected(), kDefaultTimeout);
200 return IsConnected() && callee->IsConnected();
201 }
202
GenerateOfferAndCollectCandidates()203 bool GenerateOfferAndCollectCandidates() {
204 auto offer = CreateOffer(RTCOfferAnswerOptions());
205 if (!offer) {
206 return false;
207 }
208 bool set_local_offer =
209 SetLocalDescription(CloneSessionDescription(offer.get()));
210 EXPECT_TRUE(set_local_offer);
211 if (!set_local_offer) {
212 return false;
213 }
214 EXPECT_TRUE_WAIT(observer()->ice_gathering_complete_, kDefaultTimeout);
215 return true;
216 }
217
ice_gathering_state()218 webrtc::PeerConnectionInterface::IceGatheringState ice_gathering_state() {
219 return pc()->ice_gathering_state();
220 }
221
222 private:
223 // Candidates that have been sent but not yet configured
224 std::vector<std::unique_ptr<webrtc::IceCandidateInterface>>
225 buffered_candidates_;
226 };
227
228 // Buffers candidates until we add them via AddBufferedIceCandidates.
OnIceCandidate(const webrtc::IceCandidateInterface * candidate)229 void ObserverForUsageHistogramTest::OnIceCandidate(
230 const webrtc::IceCandidateInterface* candidate) {
231 // If target is not set, ignore. This happens in one-ended unit tests.
232 if (candidate_target_) {
233 this->candidate_target_->BufferIceCandidate(candidate);
234 }
235 candidate_gathered_ = true;
236 }
237
238 class PeerConnectionUsageHistogramTest : public ::testing::Test {
239 protected:
240 typedef std::unique_ptr<PeerConnectionWrapperForUsageHistogramTest>
241 WrapperPtr;
242
PeerConnectionUsageHistogramTest()243 PeerConnectionUsageHistogramTest()
244 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
245 webrtc::metrics::Reset();
246 }
247
CreatePeerConnection()248 WrapperPtr CreatePeerConnection() {
249 RTCConfiguration config;
250 config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
251 return CreatePeerConnection(
252 config, PeerConnectionFactoryInterface::Options(), nullptr);
253 }
254
CreatePeerConnection(const RTCConfiguration & config)255 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
256 return CreatePeerConnection(
257 config, PeerConnectionFactoryInterface::Options(), nullptr);
258 }
259
CreatePeerConnectionWithMdns(const RTCConfiguration & config)260 WrapperPtr CreatePeerConnectionWithMdns(const RTCConfiguration& config) {
261 auto resolver_factory =
262 std::make_unique<NiceMock<webrtc::MockAsyncResolverFactory>>();
263
264 webrtc::PeerConnectionDependencies deps(nullptr /* observer_in */);
265
266 auto fake_network = NewFakeNetwork();
267 fake_network->set_mdns_responder(
268 std::make_unique<webrtc::FakeMdnsResponder>(rtc::Thread::Current()));
269 fake_network->AddInterface(NextLocalAddress());
270
271 std::unique_ptr<cricket::BasicPortAllocator> port_allocator(
272 new cricket::BasicPortAllocator(
273 fake_network,
274 std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get())));
275
276 deps.async_resolver_factory = std::move(resolver_factory);
277 deps.allocator = std::move(port_allocator);
278
279 return CreatePeerConnection(
280 config, PeerConnectionFactoryInterface::Options(), std::move(deps));
281 }
282
CreatePeerConnectionWithImmediateReport()283 WrapperPtr CreatePeerConnectionWithImmediateReport() {
284 RTCConfiguration configuration;
285 configuration.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
286 configuration.report_usage_pattern_delay_ms = 0;
287 return CreatePeerConnection(
288 configuration, PeerConnectionFactoryInterface::Options(), nullptr);
289 }
290
CreatePeerConnectionWithPrivateLocalAddresses()291 WrapperPtr CreatePeerConnectionWithPrivateLocalAddresses() {
292 auto* fake_network = NewFakeNetwork();
293 fake_network->AddInterface(NextLocalAddress());
294 fake_network->AddInterface(kPrivateLocalAddress);
295
296 auto port_allocator = std::make_unique<cricket::BasicPortAllocator>(
297 fake_network,
298 std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()));
299 RTCConfiguration config;
300 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
301 return CreatePeerConnection(config,
302 PeerConnectionFactoryInterface::Options(),
303 std::move(port_allocator));
304 }
305
CreatePeerConnectionWithPrivateIpv6LocalAddresses()306 WrapperPtr CreatePeerConnectionWithPrivateIpv6LocalAddresses() {
307 auto* fake_network = NewFakeNetwork();
308 fake_network->AddInterface(NextLocalAddress());
309 fake_network->AddInterface(kPrivateIpv6LocalAddress);
310
311 auto port_allocator = std::make_unique<cricket::BasicPortAllocator>(
312 fake_network,
313 std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()));
314
315 RTCConfiguration config;
316 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
317 return CreatePeerConnection(config,
318 PeerConnectionFactoryInterface::Options(),
319 std::move(port_allocator));
320 }
321
CreatePeerConnection(const RTCConfiguration & config,const PeerConnectionFactoryInterface::Options factory_options,std::unique_ptr<cricket::PortAllocator> allocator)322 WrapperPtr CreatePeerConnection(
323 const RTCConfiguration& config,
324 const PeerConnectionFactoryInterface::Options factory_options,
325 std::unique_ptr<cricket::PortAllocator> allocator) {
326 PeerConnectionDependencies deps(nullptr);
327 deps.allocator = std::move(allocator);
328
329 return CreatePeerConnection(config, factory_options, std::move(deps));
330 }
331
CreatePeerConnection(const RTCConfiguration & config,const PeerConnectionFactoryInterface::Options factory_options,PeerConnectionDependencies deps)332 WrapperPtr CreatePeerConnection(
333 const RTCConfiguration& config,
334 const PeerConnectionFactoryInterface::Options factory_options,
335 PeerConnectionDependencies deps) {
336 auto pc_factory =
337 rtc::make_ref_counted<PeerConnectionFactoryForUsageHistogramTest>();
338 pc_factory->SetOptions(factory_options);
339
340 // If no allocator is provided, one will be created using a network manager
341 // that uses the host network. This doesn't work on all trybots.
342 if (!deps.allocator) {
343 auto fake_network = NewFakeNetwork();
344 fake_network->AddInterface(NextLocalAddress());
345 deps.allocator = std::make_unique<cricket::BasicPortAllocator>(
346 fake_network,
347 std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()));
348 }
349
350 auto observer = std::make_unique<ObserverForUsageHistogramTest>();
351 deps.observer = observer.get();
352
353 auto result =
354 pc_factory->CreatePeerConnectionOrError(config, std::move(deps));
355 if (!result.ok()) {
356 return nullptr;
357 }
358
359 observer->SetPeerConnectionInterface(result.value().get());
360 auto wrapper = std::make_unique<PeerConnectionWrapperForUsageHistogramTest>(
361 pc_factory, result.MoveValue(), std::move(observer));
362 return wrapper;
363 }
364
ObservedFingerprint()365 int ObservedFingerprint() {
366 // This works correctly only if there is only one sample value
367 // that has been counted.
368 // Returns -1 for "not found".
369 return webrtc::metrics::MinSample(kUsagePatternMetric);
370 }
371
372 // The PeerConnection's port allocator is tied to the PeerConnection's
373 // lifetime and expects the underlying NetworkManager to outlive it. That
374 // prevents us from having the PeerConnectionWrapper own the fake network.
375 // Therefore, the test fixture will own all the fake networks even though
376 // tests should access the fake network through the PeerConnectionWrapper.
NewFakeNetwork()377 rtc::FakeNetworkManager* NewFakeNetwork() {
378 fake_networks_.emplace_back(std::make_unique<rtc::FakeNetworkManager>());
379 return fake_networks_.back().get();
380 }
381
NextLocalAddress()382 rtc::SocketAddress NextLocalAddress() {
383 RTC_DCHECK(next_local_address_ < (int)arraysize(kLocalAddrs));
384 return kLocalAddrs[next_local_address_++];
385 }
386
387 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
388 int next_local_address_ = 0;
389 std::unique_ptr<rtc::VirtualSocketServer> vss_;
390 rtc::AutoSocketServerThread main_;
391 };
392
TEST_F(PeerConnectionUsageHistogramTest,UsageFingerprintHistogramFromTimeout)393 TEST_F(PeerConnectionUsageHistogramTest, UsageFingerprintHistogramFromTimeout) {
394 auto pc = CreatePeerConnectionWithImmediateReport();
395
396 int expected_fingerprint = MakeUsageFingerprint({});
397 EXPECT_METRIC_EQ_WAIT(1, webrtc::metrics::NumSamples(kUsagePatternMetric),
398 kDefaultTimeout);
399 EXPECT_METRIC_EQ(
400 1, webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint));
401 }
402
403 #ifndef WEBRTC_ANDROID
404 // These tests do not work on Android. Why is unclear.
405 // https://bugs.webrtc.org/9461
406
407 // Test getting the usage fingerprint for an audio/video connection.
TEST_F(PeerConnectionUsageHistogramTest,FingerprintAudioVideo)408 TEST_F(PeerConnectionUsageHistogramTest, FingerprintAudioVideo) {
409 auto caller = CreatePeerConnection();
410 auto callee = CreatePeerConnection();
411 caller->AddAudioTrack("audio");
412 caller->AddVideoTrack("video");
413 ASSERT_TRUE(caller->ConnectTo(callee.get()));
414 caller->pc()->Close();
415 callee->pc()->Close();
416 int expected_fingerprint = MakeUsageFingerprint(
417 {UsageEvent::AUDIO_ADDED, UsageEvent::VIDEO_ADDED,
418 UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
419 UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED,
420 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::ADD_ICE_CANDIDATE_SUCCEEDED,
421 UsageEvent::ICE_STATE_CONNECTED, UsageEvent::REMOTE_CANDIDATE_ADDED,
422 UsageEvent::DIRECT_CONNECTION_SELECTED, UsageEvent::CLOSE_CALLED});
423 // In this case, we may or may not have PRIVATE_CANDIDATE_COLLECTED,
424 // depending on the machine configuration.
425 EXPECT_METRIC_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric));
426 EXPECT_METRIC_TRUE(
427 webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint) ==
428 2 ||
429 webrtc::metrics::NumEvents(
430 kUsagePatternMetric,
431 expected_fingerprint |
432 static_cast<int>(UsageEvent::PRIVATE_CANDIDATE_COLLECTED)) == 2);
433 }
434
435 // Test getting the usage fingerprint when the caller collects an mDNS
436 // candidate.
TEST_F(PeerConnectionUsageHistogramTest,FingerprintWithMdnsCaller)437 TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithMdnsCaller) {
438 RTCConfiguration config;
439 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
440
441 // Enable hostname candidates with mDNS names.
442 auto caller = CreatePeerConnectionWithMdns(config);
443 auto callee = CreatePeerConnection(config);
444
445 caller->AddAudioTrack("audio");
446 caller->AddVideoTrack("video");
447 ASSERT_TRUE(caller->ConnectTo(callee.get()));
448 caller->pc()->Close();
449 callee->pc()->Close();
450
451 int expected_fingerprint_caller = MakeUsageFingerprint(
452 {UsageEvent::AUDIO_ADDED, UsageEvent::VIDEO_ADDED,
453 UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
454 UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED,
455 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::MDNS_CANDIDATE_COLLECTED,
456 UsageEvent::ADD_ICE_CANDIDATE_SUCCEEDED, UsageEvent::ICE_STATE_CONNECTED,
457 UsageEvent::REMOTE_CANDIDATE_ADDED,
458 UsageEvent::DIRECT_CONNECTION_SELECTED, UsageEvent::CLOSE_CALLED});
459
460 // Without a resolver, the callee cannot resolve the received mDNS candidate
461 // but can still connect with the caller via a prflx candidate. As a result,
462 // the bit for the direct connection should not be logged.
463 int expected_fingerprint_callee = MakeUsageFingerprint(
464 {UsageEvent::AUDIO_ADDED, UsageEvent::VIDEO_ADDED,
465 UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
466 UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED,
467 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::ADD_ICE_CANDIDATE_SUCCEEDED,
468 UsageEvent::REMOTE_MDNS_CANDIDATE_ADDED, UsageEvent::ICE_STATE_CONNECTED,
469 UsageEvent::REMOTE_CANDIDATE_ADDED, UsageEvent::CLOSE_CALLED});
470 EXPECT_METRIC_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric));
471 EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
472 expected_fingerprint_caller));
473 EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
474 expected_fingerprint_callee));
475 }
476
477 // Test getting the usage fingerprint when the callee collects an mDNS
478 // candidate.
TEST_F(PeerConnectionUsageHistogramTest,FingerprintWithMdnsCallee)479 TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithMdnsCallee) {
480 RTCConfiguration config;
481 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
482
483 // Enable hostname candidates with mDNS names.
484 auto caller = CreatePeerConnection(config);
485 auto callee = CreatePeerConnectionWithMdns(config);
486
487 caller->AddAudioTrack("audio");
488 caller->AddVideoTrack("video");
489 ASSERT_TRUE(caller->ConnectTo(callee.get()));
490 caller->pc()->Close();
491 callee->pc()->Close();
492
493 // Similar to the test above, the caller connects with the callee via a prflx
494 // candidate.
495 int expected_fingerprint_caller = MakeUsageFingerprint(
496 {UsageEvent::AUDIO_ADDED, UsageEvent::VIDEO_ADDED,
497 UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
498 UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED,
499 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::ADD_ICE_CANDIDATE_SUCCEEDED,
500 UsageEvent::REMOTE_MDNS_CANDIDATE_ADDED, UsageEvent::ICE_STATE_CONNECTED,
501 UsageEvent::REMOTE_CANDIDATE_ADDED, UsageEvent::CLOSE_CALLED});
502
503 int expected_fingerprint_callee = MakeUsageFingerprint(
504 {UsageEvent::AUDIO_ADDED, UsageEvent::VIDEO_ADDED,
505 UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
506 UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED,
507 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::MDNS_CANDIDATE_COLLECTED,
508 UsageEvent::ADD_ICE_CANDIDATE_SUCCEEDED, UsageEvent::ICE_STATE_CONNECTED,
509 UsageEvent::REMOTE_CANDIDATE_ADDED,
510 UsageEvent::DIRECT_CONNECTION_SELECTED, UsageEvent::CLOSE_CALLED});
511 EXPECT_METRIC_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric));
512 EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
513 expected_fingerprint_caller));
514 EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
515 expected_fingerprint_callee));
516 }
517
518 #ifdef WEBRTC_HAVE_SCTP
TEST_F(PeerConnectionUsageHistogramTest,FingerprintDataOnly)519 TEST_F(PeerConnectionUsageHistogramTest, FingerprintDataOnly) {
520 auto caller = CreatePeerConnection();
521 auto callee = CreatePeerConnection();
522 caller->CreateDataChannel("foodata");
523 ASSERT_TRUE(caller->ConnectTo(callee.get()));
524 ASSERT_TRUE_WAIT(callee->HaveDataChannel(), kDefaultTimeout);
525 caller->pc()->Close();
526 callee->pc()->Close();
527 int expected_fingerprint = MakeUsageFingerprint(
528 {UsageEvent::DATA_ADDED, UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
529 UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED,
530 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::ADD_ICE_CANDIDATE_SUCCEEDED,
531 UsageEvent::ICE_STATE_CONNECTED, UsageEvent::REMOTE_CANDIDATE_ADDED,
532 UsageEvent::DIRECT_CONNECTION_SELECTED, UsageEvent::CLOSE_CALLED});
533 EXPECT_METRIC_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric));
534 EXPECT_METRIC_TRUE(
535 webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint) ==
536 2 ||
537 webrtc::metrics::NumEvents(
538 kUsagePatternMetric,
539 expected_fingerprint |
540 static_cast<int>(UsageEvent::PRIVATE_CANDIDATE_COLLECTED)) == 2);
541 }
542 #endif // WEBRTC_HAVE_SCTP
543 #endif // WEBRTC_ANDROID
544
TEST_F(PeerConnectionUsageHistogramTest,FingerprintStunTurn)545 TEST_F(PeerConnectionUsageHistogramTest, FingerprintStunTurn) {
546 RTCConfiguration configuration;
547 configuration.sdp_semantics = SdpSemantics::kUnifiedPlan;
548 PeerConnection::IceServer server;
549 server.urls = {"stun:dummy.stun.server"};
550 configuration.servers.push_back(server);
551 server.urls = {"turn:dummy.turn.server"};
552 server.username = "username";
553 server.password = "password";
554 configuration.servers.push_back(server);
555 auto caller = CreatePeerConnection(configuration);
556 ASSERT_TRUE(caller);
557 caller->pc()->Close();
558 int expected_fingerprint = MakeUsageFingerprint(
559 {UsageEvent::STUN_SERVER_ADDED, UsageEvent::TURN_SERVER_ADDED,
560 UsageEvent::CLOSE_CALLED});
561 EXPECT_METRIC_EQ(1, webrtc::metrics::NumSamples(kUsagePatternMetric));
562 EXPECT_METRIC_EQ(
563 1, webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint));
564 }
565
TEST_F(PeerConnectionUsageHistogramTest,FingerprintStunTurnInReconfiguration)566 TEST_F(PeerConnectionUsageHistogramTest, FingerprintStunTurnInReconfiguration) {
567 RTCConfiguration configuration;
568 configuration.sdp_semantics = SdpSemantics::kUnifiedPlan;
569 PeerConnection::IceServer server;
570 server.urls = {"stun:dummy.stun.server"};
571 configuration.servers.push_back(server);
572 server.urls = {"turn:dummy.turn.server"};
573 server.username = "username";
574 server.password = "password";
575 configuration.servers.push_back(server);
576 auto caller = CreatePeerConnection();
577 ASSERT_TRUE(caller);
578 ASSERT_TRUE(caller->pc()->SetConfiguration(configuration).ok());
579 caller->pc()->Close();
580 int expected_fingerprint = MakeUsageFingerprint(
581 {UsageEvent::STUN_SERVER_ADDED, UsageEvent::TURN_SERVER_ADDED,
582 UsageEvent::CLOSE_CALLED});
583 EXPECT_METRIC_EQ(1, webrtc::metrics::NumSamples(kUsagePatternMetric));
584 EXPECT_METRIC_EQ(
585 1, webrtc::metrics::NumEvents(kUsagePatternMetric, expected_fingerprint));
586 }
587
TEST_F(PeerConnectionUsageHistogramTest,FingerprintWithPrivateIPCaller)588 TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithPrivateIPCaller) {
589 auto caller = CreatePeerConnectionWithPrivateLocalAddresses();
590 auto callee = CreatePeerConnection();
591 caller->AddAudioTrack("audio");
592 ASSERT_TRUE(caller->ConnectTo(callee.get()));
593 caller->pc()->Close();
594 callee->pc()->Close();
595
596 int expected_fingerprint_caller = MakeUsageFingerprint(
597 {UsageEvent::AUDIO_ADDED, UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
598 UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED,
599 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::PRIVATE_CANDIDATE_COLLECTED,
600 UsageEvent::ADD_ICE_CANDIDATE_SUCCEEDED, UsageEvent::ICE_STATE_CONNECTED,
601 UsageEvent::REMOTE_CANDIDATE_ADDED,
602 UsageEvent::DIRECT_CONNECTION_SELECTED, UsageEvent::CLOSE_CALLED});
603
604 int expected_fingerprint_callee = MakeUsageFingerprint(
605 {UsageEvent::AUDIO_ADDED, UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
606 UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED,
607 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::ADD_ICE_CANDIDATE_SUCCEEDED,
608 UsageEvent::REMOTE_PRIVATE_CANDIDATE_ADDED,
609 UsageEvent::ICE_STATE_CONNECTED, UsageEvent::REMOTE_CANDIDATE_ADDED,
610 UsageEvent::DIRECT_CONNECTION_SELECTED, UsageEvent::CLOSE_CALLED});
611 EXPECT_METRIC_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric));
612 EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
613 expected_fingerprint_caller));
614 EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
615 expected_fingerprint_callee));
616 }
617
TEST_F(PeerConnectionUsageHistogramTest,FingerprintWithPrivateIpv6Callee)618 TEST_F(PeerConnectionUsageHistogramTest, FingerprintWithPrivateIpv6Callee) {
619 auto caller = CreatePeerConnection();
620 auto callee = CreatePeerConnectionWithPrivateIpv6LocalAddresses();
621 caller->AddAudioTrack("audio");
622 ASSERT_TRUE(caller->ConnectTo(callee.get()));
623 caller->pc()->Close();
624 callee->pc()->Close();
625
626 int expected_fingerprint_caller = MakeUsageFingerprint(
627 {UsageEvent::AUDIO_ADDED, UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
628 UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED,
629 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::ADD_ICE_CANDIDATE_SUCCEEDED,
630 UsageEvent::REMOTE_PRIVATE_CANDIDATE_ADDED,
631 UsageEvent::ICE_STATE_CONNECTED, UsageEvent::REMOTE_CANDIDATE_ADDED,
632 UsageEvent::REMOTE_IPV6_CANDIDATE_ADDED,
633 UsageEvent::DIRECT_CONNECTION_SELECTED, UsageEvent::CLOSE_CALLED});
634
635 int expected_fingerprint_callee = MakeUsageFingerprint(
636 {UsageEvent::AUDIO_ADDED, UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
637 UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED,
638 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::PRIVATE_CANDIDATE_COLLECTED,
639 UsageEvent::IPV6_CANDIDATE_COLLECTED,
640 UsageEvent::ADD_ICE_CANDIDATE_SUCCEEDED,
641 UsageEvent::REMOTE_CANDIDATE_ADDED, UsageEvent::ICE_STATE_CONNECTED,
642 UsageEvent::DIRECT_CONNECTION_SELECTED, UsageEvent::CLOSE_CALLED});
643 EXPECT_METRIC_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric));
644 EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
645 expected_fingerprint_caller));
646 EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
647 expected_fingerprint_callee));
648 }
649
650 #ifndef WEBRTC_ANDROID
651 #ifdef WEBRTC_HAVE_SCTP
652 // Test that the usage pattern bits for adding remote (private IPv6) candidates
653 // are set when the remote candidates are retrieved from the Offer SDP instead
654 // of trickled ICE messages.
TEST_F(PeerConnectionUsageHistogramTest,AddRemoteCandidatesFromRemoteDescription)655 TEST_F(PeerConnectionUsageHistogramTest,
656 AddRemoteCandidatesFromRemoteDescription) {
657 // We construct the following data-channel-only scenario. The caller collects
658 // IPv6 private local candidates and appends them in the Offer as in
659 // non-trickled sessions. The callee collects mDNS candidates that are not
660 // contained in the Answer as in Trickle ICE. Only the Offer and Answer are
661 // signaled and we expect a connection with prflx remote candidates at the
662 // caller side.
663 auto caller = CreatePeerConnectionWithPrivateIpv6LocalAddresses();
664 RTCConfiguration config;
665 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
666 auto callee = CreatePeerConnectionWithMdns(config);
667 caller->CreateDataChannel("test_channel");
668 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
669 // Wait until the gathering completes so that the session description would
670 // have contained ICE candidates.
671 EXPECT_EQ_WAIT(webrtc::PeerConnectionInterface::kIceGatheringComplete,
672 caller->ice_gathering_state(), kDefaultTimeout);
673 EXPECT_TRUE(caller->observer()->candidate_gathered());
674 // Get the current offer that contains candidates and pass it to the callee.
675 //
676 // Note that we cannot use CloneSessionDescription on `cur_offer` to obtain an
677 // SDP with candidates. The method above does not strictly copy everything, in
678 // particular, not copying the ICE candidates.
679 // TODO(qingsi): Technically, this is a bug. Fix it.
680 auto cur_offer = caller->pc()->local_description();
681 ASSERT_TRUE(cur_offer);
682 std::string sdp_with_candidates_str;
683 cur_offer->ToString(&sdp_with_candidates_str);
684 auto offer = std::make_unique<JsepSessionDescription>(SdpType::kOffer);
685 ASSERT_TRUE(SdpDeserialize(sdp_with_candidates_str, offer.get(),
686 nullptr /* error */));
687 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
688
689 // By default, the Answer created does not contain ICE candidates.
690 auto answer = callee->CreateAnswer();
691 callee->SetLocalDescription(CloneSessionDescription(answer.get()));
692 caller->SetRemoteDescription(std::move(answer));
693 EXPECT_TRUE_WAIT(caller->IsConnected(), kDefaultTimeout);
694 EXPECT_TRUE_WAIT(callee->IsConnected(), kDefaultTimeout);
695 // The callee needs to process the open message to have the data channel open.
696 EXPECT_TRUE_WAIT(callee->observer()->last_datachannel_ != nullptr,
697 kDefaultTimeout);
698 caller->pc()->Close();
699 callee->pc()->Close();
700
701 // The caller should not have added any remote candidate either via
702 // AddIceCandidate or from the remote description. Also, the caller connects
703 // with the callee via a prflx candidate and hence no direct connection bit
704 // should be set.
705 int expected_fingerprint_caller = MakeUsageFingerprint(
706 {UsageEvent::DATA_ADDED, UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
707 UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED,
708 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::PRIVATE_CANDIDATE_COLLECTED,
709 UsageEvent::IPV6_CANDIDATE_COLLECTED, UsageEvent::ICE_STATE_CONNECTED,
710 UsageEvent::CLOSE_CALLED});
711
712 int expected_fingerprint_callee = MakeUsageFingerprint(
713 {UsageEvent::DATA_ADDED, UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
714 UsageEvent::SET_REMOTE_DESCRIPTION_SUCCEEDED,
715 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::MDNS_CANDIDATE_COLLECTED,
716 UsageEvent::REMOTE_CANDIDATE_ADDED,
717 UsageEvent::REMOTE_PRIVATE_CANDIDATE_ADDED,
718 UsageEvent::REMOTE_IPV6_CANDIDATE_ADDED, UsageEvent::ICE_STATE_CONNECTED,
719 UsageEvent::DIRECT_CONNECTION_SELECTED, UsageEvent::CLOSE_CALLED});
720 EXPECT_METRIC_EQ(2, webrtc::metrics::NumSamples(kUsagePatternMetric));
721 EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
722 expected_fingerprint_caller));
723 EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(kUsagePatternMetric,
724 expected_fingerprint_callee));
725 }
726
TEST_F(PeerConnectionUsageHistogramTest,NotableUsageNoted)727 TEST_F(PeerConnectionUsageHistogramTest, NotableUsageNoted) {
728 auto caller = CreatePeerConnection();
729 caller->CreateDataChannel("foo");
730 caller->GenerateOfferAndCollectCandidates();
731 caller->pc()->Close();
732 int expected_fingerprint = MakeUsageFingerprint(
733 {UsageEvent::DATA_ADDED, UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
734 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::CLOSE_CALLED});
735 EXPECT_METRIC_EQ(1, webrtc::metrics::NumSamples(kUsagePatternMetric));
736 EXPECT_METRIC_TRUE(
737 expected_fingerprint == ObservedFingerprint() ||
738 (expected_fingerprint |
739 static_cast<int>(UsageEvent::PRIVATE_CANDIDATE_COLLECTED)) ==
740 ObservedFingerprint());
741 EXPECT_METRIC_EQ(absl::make_optional(ObservedFingerprint()),
742 caller->observer()->interesting_usage_detected());
743 }
744
TEST_F(PeerConnectionUsageHistogramTest,NotableUsageOnEventFiring)745 TEST_F(PeerConnectionUsageHistogramTest, NotableUsageOnEventFiring) {
746 auto caller = CreatePeerConnection();
747 caller->CreateDataChannel("foo");
748 caller->GenerateOfferAndCollectCandidates();
749 int expected_fingerprint = MakeUsageFingerprint(
750 {UsageEvent::DATA_ADDED, UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
751 UsageEvent::CANDIDATE_COLLECTED});
752 EXPECT_METRIC_EQ(0, webrtc::metrics::NumSamples(kUsagePatternMetric));
753 caller->GetInternalPeerConnection()->RequestUsagePatternReportForTesting();
754 EXPECT_METRIC_EQ_WAIT(1, webrtc::metrics::NumSamples(kUsagePatternMetric),
755 kDefaultTimeout);
756 EXPECT_METRIC_TRUE(
757 expected_fingerprint == ObservedFingerprint() ||
758 (expected_fingerprint |
759 static_cast<int>(UsageEvent::PRIVATE_CANDIDATE_COLLECTED)) ==
760 ObservedFingerprint());
761 EXPECT_METRIC_EQ(absl::make_optional(ObservedFingerprint()),
762 caller->observer()->interesting_usage_detected());
763 }
764
TEST_F(PeerConnectionUsageHistogramTest,NoNotableUsageOnEventFiringAfterClose)765 TEST_F(PeerConnectionUsageHistogramTest,
766 NoNotableUsageOnEventFiringAfterClose) {
767 auto caller = CreatePeerConnection();
768 caller->CreateDataChannel("foo");
769 caller->GenerateOfferAndCollectCandidates();
770 int expected_fingerprint = MakeUsageFingerprint(
771 {UsageEvent::DATA_ADDED, UsageEvent::SET_LOCAL_DESCRIPTION_SUCCEEDED,
772 UsageEvent::CANDIDATE_COLLECTED, UsageEvent::CLOSE_CALLED});
773 EXPECT_METRIC_EQ(0, webrtc::metrics::NumSamples(kUsagePatternMetric));
774 caller->pc()->Close();
775 EXPECT_METRIC_EQ(1, webrtc::metrics::NumSamples(kUsagePatternMetric));
776 caller->GetInternalPeerConnection()->RequestUsagePatternReportForTesting();
777 caller->observer()->ClearInterestingUsageDetector();
778 EXPECT_METRIC_EQ_WAIT(2, webrtc::metrics::NumSamples(kUsagePatternMetric),
779 kDefaultTimeout);
780 EXPECT_METRIC_TRUE(
781 expected_fingerprint == ObservedFingerprint() ||
782 (expected_fingerprint |
783 static_cast<int>(UsageEvent::PRIVATE_CANDIDATE_COLLECTED)) ==
784 ObservedFingerprint());
785 // After close, the usage-detection callback should NOT have been called.
786 EXPECT_METRIC_FALSE(caller->observer()->interesting_usage_detected());
787 }
788 #endif
789 #endif
790
791 } // namespace webrtc
792