Files
platform-external-webrtc/webrtc/api/quicdatatransport_unittest.cc
zhihuang f2c2f8f20c Refactoring on QUIC related classes.
Merge with the latest webrtc native code.
Remove deprecated function Connect() in QuicTransportChannel.
Fix the compiling issue and broken unit tests by adding the network thread to QUIC related classes.

Review-Url: https://codereview.webrtc.org/2089553002
Cr-Commit-Position: refs/heads/master@{#13472}
2016-07-13 21:13:56 +00:00

357 lines
14 KiB
C++

/*
* 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/api/quicdatatransport.h"
#include <memory>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
#include "webrtc/api/quicdatachannel.h"
#include "webrtc/base/bytebuffer.h"
#include "webrtc/base/gunit.h"
#include "webrtc/p2p/base/faketransportcontroller.h"
#include "webrtc/p2p/quic/quictransportchannel.h"
#include "webrtc/p2p/quic/reliablequicstream.h"
using webrtc::DataBuffer;
using webrtc::DataChannelInit;
using webrtc::DataChannelInterface;
using webrtc::DataChannelObserver;
using webrtc::QuicDataChannel;
using webrtc::QuicDataTransport;
using cricket::FakeTransportChannel;
using cricket::QuicTransportChannel;
using cricket::ReliableQuicStream;
namespace {
// Timeout for asynchronous operations.
static const int kTimeoutMs = 1000; // milliseconds
// FakeObserver receives messages from the data channel.
class FakeObserver : public DataChannelObserver {
public:
FakeObserver() {}
void OnStateChange() override {}
void OnBufferedAmountChange(uint64_t previous_amount) override {}
void OnMessage(const webrtc::DataBuffer& buffer) override {
messages_.push_back(std::string(buffer.data.data<char>(), buffer.size()));
}
const std::vector<std::string>& messages() const { return messages_; }
size_t messages_received() const { return messages_.size(); }
private:
std::vector<std::string> messages_;
};
// A peer who uses a QUIC transport channel and fake ICE transport channel to
// send or receive data.
class QuicDataTransportPeer {
public:
QuicDataTransportPeer()
: quic_data_transport_(rtc::Thread::Current(),
rtc::Thread::Current(),
rtc::Thread::Current()),
ice_transport_channel_(new FakeTransportChannel("data", 0)),
quic_transport_channel_(ice_transport_channel_) {
ice_transport_channel_->SetAsync(true);
}
void GenerateCertificateAndFingerprint() {
rtc::scoped_refptr<rtc::RTCCertificate> local_cert =
rtc::RTCCertificate::Create(std::unique_ptr<rtc::SSLIdentity>(
rtc::SSLIdentity::Generate("cert_name", rtc::KT_DEFAULT)));
quic_transport_channel_.SetLocalCertificate(local_cert);
local_fingerprint_.reset(CreateFingerprint(local_cert.get()));
}
// Connects |ice_transport_channel_| to that of the other peer.
void Connect(QuicDataTransportPeer* other_peer) {
ice_transport_channel_->SetDestination(other_peer->ice_transport_channel_);
}
std::unique_ptr<rtc::SSLFingerprint>& local_fingerprint() {
return local_fingerprint_;
}
QuicTransportChannel* quic_transport_channel() {
return &quic_transport_channel_;
}
// Write a messge directly to the ReliableQuicStream.
void WriteMessage(int data_channel_id,
uint64_t message_id,
const std::string& message) {
ReliableQuicStream* stream = quic_transport_channel_.CreateQuicStream();
rtc::CopyOnWriteBuffer payload;
webrtc::WriteQuicDataChannelMessageHeader(data_channel_id, message_id,
&payload);
stream->Write(payload.data<char>(), payload.size(), false);
stream->Write(message.data(), message.size(), true);
}
rtc::scoped_refptr<DataChannelInterface> CreateDataChannel(
const DataChannelInit* config) {
return quic_data_transport_.CreateDataChannel("testing", config);
}
QuicDataTransport* quic_data_transport() { return &quic_data_transport_; }
private:
// Creates a fingerprint from a certificate.
rtc::SSLFingerprint* CreateFingerprint(rtc::RTCCertificate* cert) {
std::string digest_algorithm;
cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm);
std::unique_ptr<rtc::SSLFingerprint> fingerprint(
rtc::SSLFingerprint::Create(digest_algorithm, cert->identity()));
return fingerprint.release();
}
QuicDataTransport quic_data_transport_;
FakeTransportChannel* ice_transport_channel_;
QuicTransportChannel quic_transport_channel_;
std::unique_ptr<rtc::SSLFingerprint> local_fingerprint_;
};
class QuicDataTransportTest : public testing::Test {
public:
QuicDataTransportTest() {}
void ConnectTransportChannels() {
SetCryptoParameters();
peer1_.Connect(&peer2_);
ASSERT_TRUE_WAIT(peer1_.quic_transport_channel()->writable() &&
peer2_.quic_transport_channel()->writable(),
kTimeoutMs);
}
void SetTransportChannels() {
ASSERT_TRUE(peer1_.quic_data_transport()->SetTransportChannel(
peer1_.quic_transport_channel()));
ASSERT_TRUE(peer2_.quic_data_transport()->SetTransportChannel(
peer2_.quic_transport_channel()));
}
// Sets crypto parameters required for the QUIC handshake.
void SetCryptoParameters() {
peer1_.GenerateCertificateAndFingerprint();
peer2_.GenerateCertificateAndFingerprint();
peer1_.quic_transport_channel()->SetSslRole(rtc::SSL_CLIENT);
peer2_.quic_transport_channel()->SetSslRole(rtc::SSL_SERVER);
std::unique_ptr<rtc::SSLFingerprint>& peer1_fingerprint =
peer1_.local_fingerprint();
std::unique_ptr<rtc::SSLFingerprint>& peer2_fingerprint =
peer2_.local_fingerprint();
peer1_.quic_transport_channel()->SetRemoteFingerprint(
peer2_fingerprint->algorithm,
reinterpret_cast<const uint8_t*>(peer2_fingerprint->digest.data()),
peer2_fingerprint->digest.size());
peer2_.quic_transport_channel()->SetRemoteFingerprint(
peer1_fingerprint->algorithm,
reinterpret_cast<const uint8_t*>(peer1_fingerprint->digest.data()),
peer1_fingerprint->digest.size());
}
protected:
QuicDataTransportPeer peer1_;
QuicDataTransportPeer peer2_;
};
// Tests creation and destruction of data channels.
TEST_F(QuicDataTransportTest, CreateAndDestroyDataChannels) {
QuicDataTransport* quic_data_transport = peer2_.quic_data_transport();
EXPECT_FALSE(quic_data_transport->HasDataChannels());
for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) {
EXPECT_FALSE(quic_data_transport->HasDataChannel(data_channel_id));
webrtc::DataChannelInit config;
config.id = data_channel_id;
rtc::scoped_refptr<DataChannelInterface> data_channel =
peer2_.CreateDataChannel(&config);
EXPECT_NE(nullptr, data_channel);
EXPECT_EQ(data_channel_id, data_channel->id());
EXPECT_TRUE(quic_data_transport->HasDataChannel(data_channel_id));
}
EXPECT_TRUE(quic_data_transport->HasDataChannels());
for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) {
quic_data_transport->DestroyDataChannel(data_channel_id);
EXPECT_FALSE(quic_data_transport->HasDataChannel(data_channel_id));
}
EXPECT_FALSE(quic_data_transport->HasDataChannels());
}
// Tests that the QuicDataTransport does not allow creating multiple
// QuicDataChannels with the same id.
TEST_F(QuicDataTransportTest, CannotCreateDataChannelsWithSameId) {
webrtc::DataChannelInit config;
config.id = 2;
EXPECT_NE(nullptr, peer2_.CreateDataChannel(&config));
EXPECT_EQ(nullptr, peer2_.CreateDataChannel(&config));
}
// Tests that any data channels created by the QuicDataTransport are in state
// kConnecting before the QuicTransportChannel is set, then transiton to state
// kOpen when the transport channel becomes writable.
TEST_F(QuicDataTransportTest, DataChannelsOpenWhenTransportChannelWritable) {
webrtc::DataChannelInit config1;
config1.id = 7;
rtc::scoped_refptr<DataChannelInterface> data_channel1 =
peer2_.CreateDataChannel(&config1);
EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel1->state());
SetTransportChannels();
EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel1->state());
webrtc::DataChannelInit config2;
config2.id = 14;
rtc::scoped_refptr<DataChannelInterface> data_channel2 =
peer2_.CreateDataChannel(&config2);
EXPECT_EQ(webrtc::DataChannelInterface::kConnecting, data_channel2->state());
// Existing data channels should open once the transport channel is writable.
ConnectTransportChannels();
EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, data_channel1->state(),
kTimeoutMs);
EXPECT_EQ_WAIT(webrtc::DataChannelInterface::kOpen, data_channel2->state(),
kTimeoutMs);
// Any data channels created afterwards should start in state kOpen.
webrtc::DataChannelInit config3;
config3.id = 21;
rtc::scoped_refptr<DataChannelInterface> data_channel3 =
peer2_.CreateDataChannel(&config3);
EXPECT_EQ(webrtc::DataChannelInterface::kOpen, data_channel3->state());
}
// Tests that the QuicTransport dispatches messages for one QuicDataChannel.
TEST_F(QuicDataTransportTest, ReceiveMessagesForSingleDataChannel) {
ConnectTransportChannels();
SetTransportChannels();
int data_channel_id = 1337;
webrtc::DataChannelInit config;
config.id = data_channel_id;
rtc::scoped_refptr<DataChannelInterface> peer2_data_channel =
peer2_.CreateDataChannel(&config);
FakeObserver observer;
peer2_data_channel->RegisterObserver(&observer);
uint64_t message1_id = 26u;
peer1_.WriteMessage(data_channel_id, message1_id, "Testing");
ASSERT_EQ_WAIT(1, observer.messages_received(), kTimeoutMs);
EXPECT_EQ("Testing", observer.messages()[0]);
uint64_t message2_id = 402u;
peer1_.WriteMessage(data_channel_id, message2_id, "Hello, World!");
ASSERT_EQ_WAIT(2, observer.messages_received(), kTimeoutMs);
EXPECT_EQ("Hello, World!", observer.messages()[1]);
uint64_t message3_id = 100260415u;
peer1_.WriteMessage(data_channel_id, message3_id, "Third message");
ASSERT_EQ_WAIT(3, observer.messages_received(), kTimeoutMs);
EXPECT_EQ("Third message", observer.messages()[2]);
}
// Tests that the QuicTransport dispatches messages to the correct data channel
// when multiple are in use.
TEST_F(QuicDataTransportTest, ReceiveMessagesForMultipleDataChannels) {
ConnectTransportChannels();
SetTransportChannels();
std::vector<rtc::scoped_refptr<DataChannelInterface>> data_channels;
for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) {
webrtc::DataChannelInit config;
config.id = data_channel_id;
data_channels.push_back(peer2_.CreateDataChannel(&config));
}
for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) {
uint64_t message1_id = 48023u;
FakeObserver observer;
DataChannelInterface* peer2_data_channel =
data_channels[data_channel_id].get();
peer2_data_channel->RegisterObserver(&observer);
peer1_.WriteMessage(data_channel_id, message1_id, "Testing");
ASSERT_EQ_WAIT(1, observer.messages_received(), kTimeoutMs);
EXPECT_EQ("Testing", observer.messages()[0]);
uint64_t message2_id = 1372643095u;
peer1_.WriteMessage(data_channel_id, message2_id, "Hello, World!");
ASSERT_EQ_WAIT(2, observer.messages_received(), kTimeoutMs);
EXPECT_EQ("Hello, World!", observer.messages()[1]);
}
}
// Tests end-to-end that both peers can use multiple QuicDataChannels to
// send/receive messages using a QuicDataTransport.
TEST_F(QuicDataTransportTest, EndToEndSendReceiveMessages) {
ConnectTransportChannels();
SetTransportChannels();
std::vector<rtc::scoped_refptr<DataChannelInterface>> peer1_data_channels;
std::vector<rtc::scoped_refptr<DataChannelInterface>> peer2_data_channels;
for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) {
webrtc::DataChannelInit config;
config.id = data_channel_id;
peer1_data_channels.push_back(peer1_.CreateDataChannel(&config));
peer2_data_channels.push_back(peer2_.CreateDataChannel(&config));
}
for (int data_channel_id = 0; data_channel_id < 5; ++data_channel_id) {
DataChannelInterface* peer1_data_channel =
peer1_data_channels[data_channel_id].get();
FakeObserver observer1;
peer1_data_channel->RegisterObserver(&observer1);
DataChannelInterface* peer2_data_channel =
peer2_data_channels[data_channel_id].get();
FakeObserver observer2;
peer2_data_channel->RegisterObserver(&observer2);
peer1_data_channel->Send(webrtc::DataBuffer("Peer 1 message 1"));
ASSERT_EQ_WAIT(1, observer2.messages_received(), kTimeoutMs);
EXPECT_EQ("Peer 1 message 1", observer2.messages()[0]);
peer1_data_channel->Send(webrtc::DataBuffer("Peer 1 message 2"));
ASSERT_EQ_WAIT(2, observer2.messages_received(), kTimeoutMs);
EXPECT_EQ("Peer 1 message 2", observer2.messages()[1]);
peer2_data_channel->Send(webrtc::DataBuffer("Peer 2 message 1"));
ASSERT_EQ_WAIT(1, observer1.messages_received(), kTimeoutMs);
EXPECT_EQ("Peer 2 message 1", observer1.messages()[0]);
peer2_data_channel->Send(webrtc::DataBuffer("Peer 2 message 2"));
ASSERT_EQ_WAIT(2, observer1.messages_received(), kTimeoutMs);
EXPECT_EQ("Peer 2 message 2", observer1.messages()[1]);
}
}
// Tests that SetTransportChannel returns false when setting a NULL transport
// channel or a transport channel that is not equivalent to the one already set.
TEST_F(QuicDataTransportTest, SetTransportChannelReturnValue) {
QuicDataTransport* quic_data_transport = peer1_.quic_data_transport();
EXPECT_FALSE(quic_data_transport->SetTransportChannel(nullptr));
QuicTransportChannel* transport_channel = peer1_.quic_transport_channel();
EXPECT_TRUE(quic_data_transport->SetTransportChannel(transport_channel));
EXPECT_TRUE(quic_data_transport->SetTransportChannel(transport_channel));
QuicTransportChannel* other_transport_channel =
peer2_.quic_transport_channel();
EXPECT_FALSE(
quic_data_transport->SetTransportChannel(other_transport_channel));
}
} // namespace