| Index: webrtc/p2p/quic/quictransportchannel_unittest.cc
|
| diff --git a/webrtc/p2p/quic/quictransportchannel_unittest.cc b/webrtc/p2p/quic/quictransportchannel_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c5c4d2012e44dfc5c7189ed6a2afe5d9754ae629
|
| --- /dev/null
|
| +++ b/webrtc/p2p/quic/quictransportchannel_unittest.cc
|
| @@ -0,0 +1,488 @@
|
| +/*
|
| + * Copyright 2016 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 "webrtc/p2p/quic/quictransportchannel.h"
|
| +
|
| +#include <set>
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| +#include "webrtc/base/common.h"
|
| +#include "webrtc/base/gunit.h"
|
| +#include "webrtc/base/scoped_ptr.h"
|
| +#include "webrtc/base/sslidentity.h"
|
| +#include "webrtc/p2p/base/faketransportcontroller.h"
|
| +
|
| +using cricket::ConnectionRole;
|
| +using cricket::IceRole;
|
| +using cricket::QuicTransportChannel;
|
| +using cricket::TransportChannel;
|
| +using cricket::TransportDescription;
|
| +
|
| +// Timeout in milliseconds for asynchronous operations in unit tests.
|
| +static const int kTimeoutMs = 1000;
|
| +
|
| +// Export keying material parameters.
|
| +static const char kExporterLabel[] = "label";
|
| +static const uint8_t kExporterContext[] = "context";
|
| +static const size_t kExporterContextLength = sizeof(kExporterContext);
|
| +static const size_t kOutputKeyLength = 20;
|
| +
|
| +// Packet size for SRTP.
|
| +static const size_t kPacketSize = 100;
|
| +
|
| +// Indicates ICE channel has no write error.
|
| +static const int kNoWriteError = 0;
|
| +
|
| +// ICE parameters.
|
| +static const char kIceUfrag[] = "TESTICEUFRAG0001";
|
| +static const char kIcePwd[] = "TESTICEPWD00000000000001";
|
| +
|
| +// QUIC packet parameters.
|
| +static const net::IPAddressNumber kIpAddress(net::kIPv4AddressSize, 0);
|
| +static const net::IPEndPoint kIpEndpoint(kIpAddress, 0);
|
| +
|
| +// Detects incoming RTP packets.
|
| +static bool IsRtpLeadByte(uint8_t b) {
|
| + return (b & 0xC0) == 0x80;
|
| +}
|
| +
|
| +// Maps SSL role to ICE connection role. The peer with a client role is assumed
|
| +// to be the one who initiates the connection.
|
| +static ConnectionRole SslRoleToConnectionRole(rtc::SSLRole ssl_role) {
|
| + return (ssl_role == rtc::SSL_CLIENT) ? cricket::CONNECTIONROLE_ACTIVE
|
| + : cricket::CONNECTIONROLE_PASSIVE;
|
| +}
|
| +
|
| +// Allows cricket::FakeTransportChannel to simulate write blocked
|
| +// and write error states.
|
| +// TODO(mikescarlett): Add this functionality to cricket::FakeTransportChannel.
|
| +class FailableTransportChannel : public cricket::FakeTransportChannel {
|
| + public:
|
| + FailableTransportChannel(const std::string& name, int component)
|
| + : cricket::FakeTransportChannel(name, component), error_(kNoWriteError) {}
|
| + int GetError() override { return error_; }
|
| + void SetError(int error) { error_ = error; }
|
| + int SendPacket(const char* data,
|
| + size_t len,
|
| + const rtc::PacketOptions& options,
|
| + int flags) override {
|
| + if (error_ == kNoWriteError) {
|
| + return cricket::FakeTransportChannel::SendPacket(data, len, options,
|
| + flags);
|
| + }
|
| + return -1;
|
| + }
|
| +
|
| + private:
|
| + int error_;
|
| +};
|
| +
|
| +// Peer who establishes a handshake using a QuicTransportChannel, which wraps
|
| +// a FailableTransportChannel to simulate network connectivity and ICE
|
| +// negotiation.
|
| +class QuicTestPeer : public sigslot::has_slots<> {
|
| + public:
|
| + explicit QuicTestPeer(const std::string& name)
|
| + : name_(name),
|
| + bytes_sent_(0),
|
| + ice_channel_(name_, 0),
|
| + quic_channel_(&ice_channel_) {
|
| + quic_channel_.SignalReadPacket.connect(
|
| + this, &QuicTestPeer::OnTransportChannelReadPacket);
|
| + ice_channel_.SetAsync(true);
|
| + rtc::scoped_refptr<rtc::RTCCertificate> local_cert =
|
| + rtc::RTCCertificate::Create(rtc::scoped_ptr<rtc::SSLIdentity>(
|
| + rtc::SSLIdentity::Generate(name_, rtc::KT_DEFAULT)));
|
| + quic_channel_.SetLocalCertificate(local_cert);
|
| + local_fingerprint_.reset(CreateFingerprint(local_cert.get()));
|
| + }
|
| +
|
| + // Connects |ice_channel_| to that of the other peer.
|
| + void Connect(QuicTestPeer* other_peer) {
|
| + ice_channel_.Connect();
|
| + other_peer->ice_channel_.Connect();
|
| + ice_channel_.SetDestination(&other_peer->ice_channel_);
|
| + }
|
| +
|
| + // Disconnects |ice_channel_|.
|
| + void Disconnect() { ice_channel_.SetDestination(nullptr); }
|
| +
|
| + // Generates ICE credentials and passes them to |quic_channel_|.
|
| + void SetIceParameters(IceRole local_ice_role,
|
| + ConnectionRole local_connection_role,
|
| + ConnectionRole remote_connection_role,
|
| + rtc::SSLFingerprint* remote_fingerprint) {
|
| + quic_channel_.SetIceRole(local_ice_role);
|
| + quic_channel_.SetIceTiebreaker(
|
| + (local_ice_role == cricket::ICEROLE_CONTROLLING) ? 1 : 2);
|
| +
|
| + TransportDescription local_desc(
|
| + std::vector<std::string>(), kIceUfrag, kIcePwd, cricket::ICEMODE_FULL,
|
| + local_connection_role, local_fingerprint_.get());
|
| + TransportDescription remote_desc(
|
| + std::vector<std::string>(), kIceUfrag, kIcePwd, cricket::ICEMODE_FULL,
|
| + remote_connection_role, remote_fingerprint);
|
| +
|
| + quic_channel_.SetIceCredentials(local_desc.ice_ufrag, local_desc.ice_pwd);
|
| + quic_channel_.SetRemoteIceCredentials(remote_desc.ice_ufrag,
|
| + remote_desc.ice_pwd);
|
| + }
|
| +
|
| + // Creates fingerprint from certificate.
|
| + rtc::SSLFingerprint* CreateFingerprint(rtc::RTCCertificate* cert) {
|
| + std::string digest_algorithm;
|
| + bool get_digest_algorithm =
|
| + cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm);
|
| + if (!get_digest_algorithm || digest_algorithm.empty()) {
|
| + return nullptr;
|
| + }
|
| + scoped_ptr<rtc::SSLFingerprint> fingerprint(
|
| + rtc::SSLFingerprint::Create(digest_algorithm, cert->identity()));
|
| + if (digest_algorithm != rtc::DIGEST_SHA_256) {
|
| + return nullptr;
|
| + }
|
| + return fingerprint.release();
|
| + }
|
| +
|
| + // Sends SRTP packet to the other peer via |quic_channel_|.
|
| + int SendSrtpPacket() {
|
| + char packet[kPacketSize];
|
| + packet[0] = 0x80; // Make the packet header look like RTP.
|
| + int rv = quic_channel_.SendPacket(
|
| + &packet[0], kPacketSize, rtc::PacketOptions(), cricket::PF_SRTP_BYPASS);
|
| + bytes_sent_ += rv;
|
| + return rv;
|
| + }
|
| +
|
| + // Sends a non-SRTP packet with the PF_SRTP_BYPASS flag via |quic_channel_|.
|
| + int SendInvalidSrtpPacket() {
|
| + char packet[kPacketSize];
|
| + // Fill the packet with 0 to form an invalid SRTP packet.
|
| + memset(packet, 0, kPacketSize);
|
| + return quic_channel_.SendPacket(
|
| + &packet[0], kPacketSize, rtc::PacketOptions(), cricket::PF_SRTP_BYPASS);
|
| + }
|
| +
|
| + // Sends an RTP packet to the other peer via |quic_channel_|, without the SRTP
|
| + // bypass flag.
|
| + int SendRtpPacket() {
|
| + char packet[kPacketSize];
|
| + packet[0] = 0x80; // Make the packet header look like RTP.
|
| + return quic_channel_.SendPacket(&packet[0], kPacketSize,
|
| + rtc::PacketOptions(), 0);
|
| + }
|
| +
|
| + void ClearBytesSent() { bytes_sent_ = 0; }
|
| +
|
| + void ClearBytesReceived() { bytes_received_ = 0; }
|
| +
|
| + void SetWriteError(int error) { ice_channel_.SetError(error); }
|
| +
|
| + size_t bytes_received() const { return bytes_received_; }
|
| +
|
| + size_t bytes_sent() const { return bytes_sent_; }
|
| +
|
| + FailableTransportChannel* ice_channel() { return &ice_channel_; }
|
| +
|
| + QuicTransportChannel* quic_channel() { return &quic_channel_; }
|
| +
|
| + rtc::scoped_ptr<rtc::SSLFingerprint>& local_fingerprint() {
|
| + return local_fingerprint_;
|
| + }
|
| +
|
| + private:
|
| + // QUIC channel callback.
|
| + void OnTransportChannelReadPacket(TransportChannel* channel,
|
| + const char* data,
|
| + size_t size,
|
| + const rtc::PacketTime& packet_time,
|
| + int flags) {
|
| + bytes_received_ += size;
|
| + // Only SRTP packets should have the bypass flag set.
|
| + int expected_flags = IsRtpLeadByte(data[0]) ? cricket::PF_SRTP_BYPASS : 0;
|
| + ASSERT_EQ(expected_flags, flags);
|
| + }
|
| +
|
| + std::string name_; // Channel name.
|
| + size_t bytes_sent_; // Bytes sent by QUIC channel.
|
| + size_t bytes_received_; // Bytes received by QUIC channel.
|
| + FailableTransportChannel ice_channel_; // Simulates an ICE channel.
|
| + QuicTransportChannel quic_channel_; // QUIC channel to test.
|
| + rtc::scoped_ptr<rtc::SSLFingerprint> local_fingerprint_;
|
| +};
|
| +
|
| +class QuicTransportChannelTest : public testing::Test {
|
| + public:
|
| + QuicTransportChannelTest() : peer1_("P1"), peer2_("P2") {}
|
| +
|
| + // Performs negotiation before QUIC handshake, then connects the fake
|
| + // transport channels of each peer. As a side effect, the QUIC channels
|
| + // start sending handshake messages. |peer1_| has a client role and |peer2_|
|
| + // has server role in the QUIC handshake.
|
| + void Connect() {
|
| + SetIceAndCryptoParameters(rtc::SSL_CLIENT, rtc::SSL_SERVER);
|
| + peer1_.Connect(&peer2_);
|
| + }
|
| +
|
| + // Disconnects the fake transport channels.
|
| + void Disconnect() {
|
| + peer1_.Disconnect();
|
| + peer2_.Disconnect();
|
| + }
|
| +
|
| + // Sets up ICE parameters and exchanges fingerprints before QUIC handshake.
|
| + void SetIceAndCryptoParameters(rtc::SSLRole peer1_ssl_role,
|
| + rtc::SSLRole peer2_ssl_role) {
|
| + peer1_.quic_channel()->SetSslRole(peer1_ssl_role);
|
| + peer2_.quic_channel()->SetSslRole(peer2_ssl_role);
|
| +
|
| + rtc::scoped_ptr<rtc::SSLFingerprint>& peer1_fingerprint =
|
| + peer1_.local_fingerprint();
|
| + rtc::scoped_ptr<rtc::SSLFingerprint>& peer2_fingerprint =
|
| + peer2_.local_fingerprint();
|
| +
|
| + peer1_.quic_channel()->SetRemoteFingerprint(
|
| + peer2_fingerprint->algorithm,
|
| + reinterpret_cast<const uint8_t*>(peer2_fingerprint->digest.data()),
|
| + peer2_fingerprint->digest.size());
|
| + peer2_.quic_channel()->SetRemoteFingerprint(
|
| + peer1_fingerprint->algorithm,
|
| + reinterpret_cast<const uint8_t*>(peer1_fingerprint->digest.data()),
|
| + peer1_fingerprint->digest.size());
|
| +
|
| + ConnectionRole peer1_connection_role =
|
| + SslRoleToConnectionRole(peer1_ssl_role);
|
| + ConnectionRole peer2_connection_role =
|
| + SslRoleToConnectionRole(peer2_ssl_role);
|
| +
|
| + peer1_.SetIceParameters(cricket::ICEROLE_CONTROLLED, peer1_connection_role,
|
| + peer2_connection_role, peer2_fingerprint.get());
|
| + peer2_.SetIceParameters(cricket::ICEROLE_CONTROLLING, peer2_connection_role,
|
| + peer1_connection_role, peer1_fingerprint.get());
|
| + }
|
| +
|
| + // Checks if QUIC handshake is done.
|
| + bool quic_connected() {
|
| + return peer1_.quic_channel()->quic_state() ==
|
| + cricket::QUIC_TRANSPORT_CONNECTED &&
|
| + peer2_.quic_channel()->quic_state() ==
|
| + cricket::QUIC_TRANSPORT_CONNECTED;
|
| + }
|
| +
|
| + // Checks if QUIC channels are writable.
|
| + bool quic_writable() {
|
| + return peer1_.quic_channel()->writable() &&
|
| + peer2_.quic_channel()->writable();
|
| + }
|
| +
|
| + protected:
|
| + // QUIC peer with a client role, who initiates the QUIC handshake.
|
| + QuicTestPeer peer1_;
|
| + // QUIC peer with a server role, who responds to the client peer.
|
| + QuicTestPeer peer2_;
|
| +};
|
| +
|
| +// Test that the QUIC channel passes ICE parameters to the underlying ICE
|
| +// channel.
|
| +TEST_F(QuicTransportChannelTest, ChannelSetupIce) {
|
| + SetIceAndCryptoParameters(rtc::SSL_CLIENT, rtc::SSL_SERVER);
|
| + FailableTransportChannel* channel1 = peer1_.ice_channel();
|
| + FailableTransportChannel* channel2 = peer2_.ice_channel();
|
| + EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel1->GetIceRole());
|
| + EXPECT_EQ(2u, channel1->IceTiebreaker());
|
| + EXPECT_EQ(kIceUfrag, channel1->ice_ufrag());
|
| + EXPECT_EQ(kIcePwd, channel1->ice_pwd());
|
| + EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel2->GetIceRole());
|
| + EXPECT_EQ(1u, channel2->IceTiebreaker());
|
| +}
|
| +
|
| +// Test that export keying material generates identical keys for both peers
|
| +// after the QUIC handshake.
|
| +TEST_F(QuicTransportChannelTest, ExportKeyingMaterial) {
|
| + Connect();
|
| + ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs);
|
| + uint8_t key1[kOutputKeyLength];
|
| + uint8_t key2[kOutputKeyLength];
|
| +
|
| + bool from_success = peer1_.quic_channel()->ExportKeyingMaterial(
|
| + kExporterLabel, kExporterContext, kExporterContextLength, true, key1,
|
| + kOutputKeyLength);
|
| + ASSERT_TRUE(from_success);
|
| + bool to_success = peer2_.quic_channel()->ExportKeyingMaterial(
|
| + kExporterLabel, kExporterContext, kExporterContextLength, true, key2,
|
| + kOutputKeyLength);
|
| + ASSERT_TRUE(to_success);
|
| +
|
| + EXPECT_EQ(0, memcmp(key1, key2, sizeof(key1)));
|
| +}
|
| +
|
| +// Test that the QUIC channel is not writable before the QUIC handshake.
|
| +TEST_F(QuicTransportChannelTest, NotWritableBeforeHandshake) {
|
| + Connect();
|
| + EXPECT_FALSE(quic_writable());
|
| + Disconnect();
|
| + EXPECT_FALSE(quic_writable());
|
| + Connect();
|
| + EXPECT_FALSE(quic_writable());
|
| +}
|
| +
|
| +// Test that once handshake begins, QUIC is not writable until its completion.
|
| +TEST_F(QuicTransportChannelTest, QuicHandshake) {
|
| + Connect();
|
| + EXPECT_FALSE(quic_writable());
|
| + ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs);
|
| + EXPECT_TRUE(quic_writable());
|
| +}
|
| +
|
| +// Test that Non-SRTP data is not sent using SendPacket(), regardless of QUIC
|
| +// channel state.
|
| +TEST_F(QuicTransportChannelTest, TransferNonSrtp) {
|
| + // Send data before ICE channel is connected.
|
| + peer1_.ClearBytesSent();
|
| + peer2_.ClearBytesReceived();
|
| + ASSERT_EQ(-1, peer1_.SendRtpPacket());
|
| + EXPECT_EQ(0u, peer1_.bytes_sent());
|
| + // Send data after ICE channel is connected, before QUIC handshake.
|
| + Connect();
|
| + peer1_.ClearBytesSent();
|
| + peer2_.ClearBytesReceived();
|
| + ASSERT_EQ(-1, peer1_.SendRtpPacket());
|
| + EXPECT_EQ(0u, peer1_.bytes_sent());
|
| + // Send data after QUIC handshake.
|
| + ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs);
|
| + peer1_.ClearBytesSent();
|
| + peer2_.ClearBytesReceived();
|
| + ASSERT_EQ(-1, peer1_.SendRtpPacket());
|
| + EXPECT_EQ(0u, peer1_.bytes_sent());
|
| +}
|
| +
|
| +// Test that SRTP data is always be sent, regardless of QUIC channel state, when
|
| +// the ICE channel is connected.
|
| +TEST_F(QuicTransportChannelTest, TransferSrtp) {
|
| + // Send data after ICE channel is connected, before QUIC handshake.
|
| + Connect();
|
| + peer1_.ClearBytesSent();
|
| + peer2_.ClearBytesReceived();
|
| + ASSERT_EQ(kPacketSize, static_cast<size_t>(peer1_.SendSrtpPacket()));
|
| + EXPECT_EQ_WAIT(kPacketSize, peer2_.bytes_received(), kTimeoutMs);
|
| + EXPECT_EQ(kPacketSize, peer1_.bytes_sent());
|
| + ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs);
|
| + // Send data after QUIC handshake.
|
| + peer1_.ClearBytesSent();
|
| + peer2_.ClearBytesReceived();
|
| + ASSERT_EQ(kPacketSize, static_cast<size_t>(peer1_.SendSrtpPacket()));
|
| + EXPECT_EQ_WAIT(kPacketSize, peer2_.bytes_received(), kTimeoutMs);
|
| + EXPECT_EQ(kPacketSize, peer1_.bytes_sent());
|
| +}
|
| +
|
| +// Test that invalid SRTP (non-SRTP data with
|
| +// PF_SRTP_BYPASS flag) fails to send with return value -1.
|
| +TEST_F(QuicTransportChannelTest, TransferInvalidSrtp) {
|
| + peer1_.ClearBytesSent();
|
| + peer2_.ClearBytesReceived();
|
| + EXPECT_EQ(-1, peer1_.SendInvalidSrtpPacket());
|
| + EXPECT_EQ(0u, peer2_.bytes_received());
|
| + Connect();
|
| + peer1_.ClearBytesSent();
|
| + peer2_.ClearBytesReceived();
|
| + EXPECT_EQ(-1, peer1_.SendInvalidSrtpPacket());
|
| + EXPECT_EQ(0u, peer2_.bytes_received());
|
| +}
|
| +
|
| +// Test that QuicTransportChannel::WritePacket blocks when the ICE
|
| +// channel is not writable, and otherwise succeeds.
|
| +TEST_F(QuicTransportChannelTest, QuicWritePacket) {
|
| + peer1_.ice_channel()->Connect();
|
| + peer2_.ice_channel()->Connect();
|
| + peer1_.ice_channel()->SetDestination(peer2_.ice_channel());
|
| + std::string packet = "FAKEQUICPACKET";
|
| +
|
| + // QUIC should be write blocked when the ICE channel is not writable.
|
| + peer1_.ice_channel()->SetWritable(false);
|
| + EXPECT_TRUE(peer1_.quic_channel()->IsWriteBlocked());
|
| + net::WriteResult write_blocked_result = peer1_.quic_channel()->WritePacket(
|
| + packet.data(), packet.size(), kIpAddress, kIpEndpoint);
|
| + EXPECT_EQ(net::WRITE_STATUS_BLOCKED, write_blocked_result.status);
|
| + EXPECT_EQ(EWOULDBLOCK, write_blocked_result.error_code);
|
| +
|
| + // QUIC should ignore errors when the ICE channel is writable.
|
| + peer1_.ice_channel()->SetWritable(true);
|
| + EXPECT_FALSE(peer1_.quic_channel()->IsWriteBlocked());
|
| + peer1_.SetWriteError(EWOULDBLOCK);
|
| + net::WriteResult ignore_error_result = peer1_.quic_channel()->WritePacket(
|
| + packet.data(), packet.size(), kIpAddress, kIpEndpoint);
|
| + EXPECT_EQ(net::WRITE_STATUS_OK, ignore_error_result.status);
|
| + EXPECT_EQ(0, ignore_error_result.bytes_written);
|
| +
|
| + peer1_.SetWriteError(kNoWriteError);
|
| + net::WriteResult no_error_result = peer1_.quic_channel()->WritePacket(
|
| + packet.data(), packet.size(), kIpAddress, kIpEndpoint);
|
| + EXPECT_EQ(net::WRITE_STATUS_OK, no_error_result.status);
|
| + EXPECT_EQ(static_cast<int>(packet.size()), no_error_result.bytes_written);
|
| +}
|
| +
|
| +// Test that SSL roles can be reversed before QUIC handshake.
|
| +TEST_F(QuicTransportChannelTest, QuicRoleReversalBeforeQuic) {
|
| + EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER));
|
| + EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_CLIENT));
|
| + EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER));
|
| +}
|
| +
|
| +// Test that SSL roles cannot be reversed after the QUIC handshake. SetSslRole
|
| +// returns true if the current SSL role equals the proposed SSL role.
|
| +TEST_F(QuicTransportChannelTest, QuicRoleReversalAfterQuic) {
|
| + Connect();
|
| + ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs);
|
| + EXPECT_FALSE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER));
|
| + EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_CLIENT));
|
| + EXPECT_FALSE(peer2_.quic_channel()->SetSslRole(rtc::SSL_CLIENT));
|
| + EXPECT_TRUE(peer2_.quic_channel()->SetSslRole(rtc::SSL_SERVER));
|
| +}
|
| +
|
| +// Set the SSL role, then test that GetSslRole returns the same value.
|
| +TEST_F(QuicTransportChannelTest, SetGetSslRole) {
|
| + ASSERT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER));
|
| + rtc::scoped_ptr<rtc::SSLRole> role(new rtc::SSLRole());
|
| + ASSERT_TRUE(peer1_.quic_channel()->GetSslRole(role.get()));
|
| + EXPECT_EQ(rtc::SSL_SERVER, *role);
|
| +}
|
| +
|
| +// Test that after the QUIC handshake is complete, the QUIC handshake remains
|
| +// confirmed even if the ICE channel reconnects.
|
| +TEST_F(QuicTransportChannelTest, HandshakeConfirmedAfterReconnect) {
|
| + Connect();
|
| + ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs);
|
| + Disconnect();
|
| + EXPECT_TRUE(quic_connected());
|
| + Connect();
|
| + EXPECT_TRUE(quic_connected());
|
| +}
|
| +
|
| +// Test that if the ICE channel becomes receiving after the QUIC channel is
|
| +// connected, then the QUIC channel becomes receiving.
|
| +TEST_F(QuicTransportChannelTest, IceReceivingAfterConnected) {
|
| + Connect();
|
| + ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs);
|
| + ASSERT_FALSE(peer1_.ice_channel()->receiving());
|
| + EXPECT_FALSE(peer1_.quic_channel()->receiving());
|
| + peer1_.ice_channel()->SetReceiving(true);
|
| + EXPECT_TRUE(peer1_.quic_channel()->receiving());
|
| +}
|
| +
|
| +// Test that if the ICE channel becomes receiving before the QUIC channel is
|
| +// connected, then the QUIC channel becomes receiving.
|
| +TEST_F(QuicTransportChannelTest, IceReceivingBeforeConnected) {
|
| + Connect();
|
| + peer1_.ice_channel()->SetReceiving(true);
|
| + ASSERT_TRUE(peer1_.ice_channel()->receiving());
|
| + ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs);
|
| + EXPECT_TRUE(peer1_.quic_channel()->receiving());
|
| +}
|
|
|