Rewrite WebRtcSession data channel tests as PeerConnection tests

Bug: webrtc:8222
Change-Id: I1382a0727b04dfd33e79992841d885f640b3a032
Reviewed-on: https://webrtc-review.googlesource.com/8281
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20398}
diff --git a/pc/peerconnection_datachannel_unittest.cc b/pc/peerconnection_datachannel_unittest.cc
new file mode 100644
index 0000000..918544c
--- /dev/null
+++ b/pc/peerconnection_datachannel_unittest.cc
@@ -0,0 +1,301 @@
+/*
+ *  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.
+ */
+
+#include <tuple>
+
+#include "api/peerconnectionproxy.h"
+#include "media/base/fakemediaengine.h"
+#include "pc/mediasession.h"
+#include "pc/peerconnection.h"
+#include "pc/peerconnectionfactory.h"
+#include "pc/peerconnectionwrapper.h"
+#ifdef WEBRTC_ANDROID
+#include "pc/test/androidtestinitializer.h"
+#endif
+#include "pc/test/fakesctptransport.h"
+#include "rtc_base/gunit.h"
+#include "rtc_base/ptr_util.h"
+#include "rtc_base/virtualsocketserver.h"
+
+namespace webrtc {
+
+using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
+using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
+using ::testing::Values;
+
+class PeerConnectionFactoryForDataChannelTest
+    : public rtc::RefCountedObject<PeerConnectionFactory> {
+ public:
+  PeerConnectionFactoryForDataChannelTest()
+      : rtc::RefCountedObject<PeerConnectionFactory>(
+            rtc::Thread::Current(),
+            rtc::Thread::Current(),
+            rtc::Thread::Current(),
+            rtc::MakeUnique<cricket::FakeMediaEngine>(),
+            CreateCallFactory(),
+            nullptr) {}
+
+  std::unique_ptr<cricket::SctpTransportInternalFactory>
+  CreateSctpTransportInternalFactory() {
+    auto factory = rtc::MakeUnique<FakeSctpTransportFactory>();
+    last_fake_sctp_transport_factory_ = factory.get();
+    return factory;
+  }
+
+  FakeSctpTransportFactory* last_fake_sctp_transport_factory_ = nullptr;
+};
+
+class PeerConnectionWrapperForDataChannelTest : public PeerConnectionWrapper {
+ public:
+  using PeerConnectionWrapper::PeerConnectionWrapper;
+
+  FakeSctpTransportFactory* sctp_transport_factory() {
+    return sctp_transport_factory_;
+  }
+
+  void set_sctp_transport_factory(
+      FakeSctpTransportFactory* sctp_transport_factory) {
+    sctp_transport_factory_ = sctp_transport_factory;
+  }
+
+  rtc::Optional<std::string> sctp_content_name() {
+    return GetInternalPeerConnection()->sctp_content_name();
+  }
+
+  rtc::Optional<std::string> sctp_transport_name() {
+    return GetInternalPeerConnection()->sctp_transport_name();
+  }
+
+  PeerConnection* GetInternalPeerConnection() {
+    auto* pci = reinterpret_cast<
+        PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(pc());
+    return reinterpret_cast<PeerConnection*>(pci->internal());
+  }
+
+ private:
+  FakeSctpTransportFactory* sctp_transport_factory_ = nullptr;
+};
+
+class PeerConnectionDataChannelTest : public ::testing::Test {
+ protected:
+  typedef std::unique_ptr<PeerConnectionWrapperForDataChannelTest> WrapperPtr;
+
+  PeerConnectionDataChannelTest()
+      : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
+#ifdef WEBRTC_ANDROID
+    InitializeAndroidObjects();
+#endif
+  }
+
+  WrapperPtr CreatePeerConnection() {
+    return CreatePeerConnection(RTCConfiguration());
+  }
+
+  WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
+    return CreatePeerConnection(config,
+                                PeerConnectionFactoryInterface::Options());
+  }
+
+  WrapperPtr CreatePeerConnection(
+      const RTCConfiguration& config,
+      const PeerConnectionFactoryInterface::Options factory_options) {
+    rtc::scoped_refptr<PeerConnectionFactoryForDataChannelTest> pc_factory(
+        new PeerConnectionFactoryForDataChannelTest());
+    pc_factory->SetOptions(factory_options);
+    RTC_CHECK(pc_factory->Initialize());
+    auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
+    auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
+                                               observer.get());
+    if (!pc) {
+      return nullptr;
+    }
+
+    auto wrapper = rtc::MakeUnique<PeerConnectionWrapperForDataChannelTest>(
+        pc_factory, pc, std::move(observer));
+    RTC_DCHECK(pc_factory->last_fake_sctp_transport_factory_);
+    wrapper->set_sctp_transport_factory(
+        pc_factory->last_fake_sctp_transport_factory_);
+    return wrapper;
+  }
+
+  // Accepts the same arguments as CreatePeerConnection and adds a default data
+  // channel.
+  template <typename... Args>
+  WrapperPtr CreatePeerConnectionWithDataChannel(Args&&... args) {
+    auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
+    if (!wrapper) {
+      return nullptr;
+    }
+    EXPECT_TRUE(wrapper->pc()->CreateDataChannel("dc", nullptr));
+    return wrapper;
+  }
+
+  // Changes the SCTP data channel port on the given session description.
+  void ChangeSctpPortOnDescription(cricket::SessionDescription* desc,
+                                   int port) {
+    cricket::DataCodec sctp_codec(cricket::kGoogleSctpDataCodecPlType,
+                                  cricket::kGoogleSctpDataCodecName);
+    sctp_codec.SetParam(cricket::kCodecParamPort, port);
+
+    auto* data_content = cricket::GetFirstDataContent(desc);
+    RTC_DCHECK(data_content);
+    auto* data_desc = static_cast<cricket::DataContentDescription*>(
+        data_content->description);
+    data_desc->set_codecs({sctp_codec});
+  }
+
+  std::unique_ptr<rtc::VirtualSocketServer> vss_;
+  rtc::AutoSocketServerThread main_;
+};
+
+TEST_F(PeerConnectionDataChannelTest,
+       NoSctpTransportCreatedIfRtpDataChannelEnabled) {
+  RTCConfiguration config;
+  config.enable_rtp_data_channel = true;
+  auto caller = CreatePeerConnectionWithDataChannel(config);
+
+  ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
+  EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
+}
+
+TEST_F(PeerConnectionDataChannelTest,
+       RtpDataChannelCreatedEvenIfSctpAvailable) {
+  RTCConfiguration config;
+  config.enable_rtp_data_channel = true;
+  PeerConnectionFactoryInterface::Options options;
+  options.disable_sctp_data_channels = false;
+  auto caller = CreatePeerConnectionWithDataChannel(config, options);
+
+  ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
+  EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
+}
+
+// Test that sctp_content_name/sctp_transport_name (used for stats) are correct
+// before and after BUNDLE is negotiated.
+TEST_F(PeerConnectionDataChannelTest, SctpContentAndTransportNameSetCorrectly) {
+  auto caller = CreatePeerConnection();
+  auto callee = CreatePeerConnection();
+
+  // Initially these fields should be empty.
+  EXPECT_FALSE(caller->sctp_content_name());
+  EXPECT_FALSE(caller->sctp_transport_name());
+
+  // Create offer with audio/video/data.
+  // Default bundle policy is "balanced", so data should be using its own
+  // transport.
+  caller->AddAudioTrack("a");
+  caller->AddVideoTrack("v");
+  caller->pc()->CreateDataChannel("dc", nullptr);
+  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
+
+  ASSERT_TRUE(caller->sctp_content_name());
+  EXPECT_EQ(cricket::CN_DATA, *caller->sctp_content_name());
+  ASSERT_TRUE(caller->sctp_transport_name());
+  EXPECT_EQ(cricket::CN_DATA, *caller->sctp_transport_name());
+
+  // Create answer that finishes BUNDLE negotiation, which means everything
+  // should be bundled on the first transport (audio).
+  RTCOfferAnswerOptions options;
+  options.use_rtp_mux = true;
+  ASSERT_TRUE(
+      caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
+
+  ASSERT_TRUE(caller->sctp_content_name());
+  EXPECT_EQ(cricket::CN_DATA, *caller->sctp_content_name());
+  ASSERT_TRUE(caller->sctp_transport_name());
+  EXPECT_EQ(cricket::CN_AUDIO, *caller->sctp_transport_name());
+}
+
+TEST_F(PeerConnectionDataChannelTest,
+       CreateOfferWithNoDataChannelsGivesNoDataSection) {
+  auto caller = CreatePeerConnection();
+  auto offer = caller->CreateOffer();
+
+  EXPECT_FALSE(offer->description()->GetContentByName(cricket::CN_DATA));
+  EXPECT_FALSE(offer->description()->GetTransportInfoByName(cricket::CN_DATA));
+}
+
+TEST_F(PeerConnectionDataChannelTest,
+       CreateAnswerWithRemoteSctpDataChannelIncludesDataSection) {
+  auto caller = CreatePeerConnectionWithDataChannel();
+  auto callee = CreatePeerConnection();
+
+  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
+
+  auto answer = callee->CreateAnswer();
+  ASSERT_TRUE(answer);
+  auto* data_content =
+      answer->description()->GetContentByName(cricket::CN_DATA);
+  ASSERT_TRUE(data_content);
+  EXPECT_FALSE(data_content->rejected);
+  EXPECT_TRUE(answer->description()->GetTransportInfoByName(cricket::CN_DATA));
+}
+
+TEST_F(PeerConnectionDataChannelTest,
+       CreateDataChannelWithDtlsDisabledSucceeds) {
+  RTCConfiguration config;
+  config.enable_dtls_srtp.emplace(false);
+  auto caller = CreatePeerConnection();
+
+  EXPECT_TRUE(caller->pc()->CreateDataChannel("dc", nullptr));
+}
+
+TEST_F(PeerConnectionDataChannelTest, CreateDataChannelWithSctpDisabledFails) {
+  PeerConnectionFactoryInterface::Options options;
+  options.disable_sctp_data_channels = true;
+  auto caller = CreatePeerConnection(RTCConfiguration(), options);
+
+  EXPECT_FALSE(caller->pc()->CreateDataChannel("dc", nullptr));
+}
+
+// Test that if a callee has SCTP disabled and receives an offer with an SCTP
+// data channel, the data section is rejected and no SCTP transport is created
+// on the callee.
+TEST_F(PeerConnectionDataChannelTest,
+       DataSectionRejectedIfCalleeHasSctpDisabled) {
+  auto caller = CreatePeerConnectionWithDataChannel();
+  PeerConnectionFactoryInterface::Options options;
+  options.disable_sctp_data_channels = true;
+  auto callee = CreatePeerConnection(RTCConfiguration(), options);
+
+  ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
+
+  EXPECT_FALSE(callee->sctp_transport_factory()->last_fake_sctp_transport());
+
+  auto answer = callee->CreateAnswer();
+  auto* data_content =
+      answer->description()->GetContentByName(cricket::CN_DATA);
+  ASSERT_TRUE(data_content);
+  EXPECT_TRUE(data_content->rejected);
+}
+
+TEST_F(PeerConnectionDataChannelTest, SctpPortPropagatedFromSdpToTransport) {
+  constexpr int kNewSendPort = 9998;
+  constexpr int kNewRecvPort = 7775;
+
+  auto caller = CreatePeerConnectionWithDataChannel();
+  auto callee = CreatePeerConnectionWithDataChannel();
+
+  auto offer = caller->CreateOffer();
+  ChangeSctpPortOnDescription(offer->description(), kNewSendPort);
+  ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
+
+  auto answer = callee->CreateAnswer();
+  ChangeSctpPortOnDescription(answer->description(), kNewRecvPort);
+  ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
+
+  auto* callee_transport =
+      callee->sctp_transport_factory()->last_fake_sctp_transport();
+  ASSERT_TRUE(callee_transport);
+  EXPECT_EQ(kNewSendPort, callee_transport->remote_port());
+  EXPECT_EQ(kNewRecvPort, callee_transport->local_port());
+}
+
+}  // namespace webrtc