Chromium Code Reviews| Index: webrtc/api/quictransport_unittest.cc |
| diff --git a/webrtc/api/quictransport_unittest.cc b/webrtc/api/quictransport_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..954a258ebaf4714715cf83a47e71d5b92a7ec112 |
| --- /dev/null |
| +++ b/webrtc/api/quictransport_unittest.cc |
| @@ -0,0 +1,229 @@ |
| +/* |
| + * 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/quictransport.h" |
| + |
| +#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::QuicDataChannel; |
| +using webrtc::QuicTransport; |
| +using cricket::FakeTransportChannel; |
| +using cricket::QuicTransportChannel; |
| +using cricket::ReliableQuicStream; |
| + |
| +// Timeout for asynchronous operations. |
| +static const int kTimeoutMs = 1000; // milliseconds |
| + |
| +class QuicDataChannelForTest : public QuicDataChannel { |
| + public: |
| + QuicDataChannelForTest(QuicTransportChannel* quic_transport_channel, |
| + const webrtc::DataChannelInit* config) |
| + : QuicDataChannel(quic_transport_channel, |
| + rtc::Thread::Current(), |
| + rtc::Thread::Current(), |
| + "testing", |
| + config) {} |
| + void OnIncomingStream(ReliableQuicStream* stream, |
| + rtc::ByteBuffer* remaining_bytes) override { |
| + stream_ids_.insert(stream->id()); |
| + uint64_t message_id; |
| + remaining_bytes->ReadVarint(&message_id); |
| + std::string message; |
| + remaining_bytes->ReadString(&message, remaining_bytes->Length()); |
| + messages_[message_id] = message; |
| + } |
| + bool has_stream(net::QuicStreamId id) const { |
| + return stream_ids_.find(id) != stream_ids_.end(); |
| + } |
| + bool has_message(uint64_t id, std::string message) const { |
| + const auto& kv = messages_.find(id); |
| + return kv != messages_.end() && kv->second == message; |
| + } |
| + |
| + private: |
| + std::set<net::QuicStreamId> stream_ids_; |
| + std::unordered_map<uint64_t, std::string> messages_; |
| +}; |
| + |
| +// A peer who creates one or more QuicDataChannels to send or receive data. |
| +class QuicTransportPeer { |
| + public: |
| + QuicTransportPeer() |
| + : ice_transport_channel_("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(rtc::scoped_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(QuicTransportPeer* other_peer) { |
| + ice_transport_channel_.Connect(); |
| + other_peer->ice_transport_channel_.Connect(); |
| + ice_transport_channel_.SetDestination(&other_peer->ice_transport_channel_); |
| + } |
| + |
| + rtc::scoped_ptr<rtc::SSLFingerprint>& local_fingerprint() { |
| + return local_fingerprint_; |
| + } |
| + |
| + QuicTransportChannel* quic_transport_channel() { |
| + return &quic_transport_channel_; |
| + } |
| + |
| + private: |
| + // Creates a fingerprint from a certificate. |
| + rtc::SSLFingerprint* CreateFingerprint(rtc::RTCCertificate* cert) { |
| + std::string digest_algorithm; |
| + cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm); |
| + rtc::scoped_ptr<rtc::SSLFingerprint> fingerprint( |
| + rtc::SSLFingerprint::Create(digest_algorithm, cert->identity())); |
| + return fingerprint.release(); |
| + } |
| + |
| + FakeTransportChannel ice_transport_channel_; |
| + QuicTransportChannel quic_transport_channel_; |
| + |
| + rtc::scoped_ptr<rtc::SSLFingerprint> local_fingerprint_; |
| +}; |
| + |
| +class QuicTransportTest : public testing::Test { |
| + public: |
| + QuicTransportTest() : quic_transport_(peer2_.quic_transport_channel()) {} |
| + |
| + void EstablishConnection() { |
| + SetCryptoParameters(); |
| + peer1_.Connect(&peer2_); |
| + ASSERT_TRUE_WAIT(peer1_.quic_transport_channel()->writable() && |
| + peer2_.quic_transport_channel()->writable(), |
| + kTimeoutMs); |
| + } |
| + |
| + // 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); |
| + |
| + rtc::scoped_ptr<rtc::SSLFingerprint>& peer1_fingerprint = |
| + peer1_.local_fingerprint(); |
| + rtc::scoped_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: |
| + QuicTransportPeer peer1_; |
| + QuicTransportPeer peer2_; |
| + |
| + QuicTransport quic_transport_; |
| +}; |
| + |
| +TEST_F(QuicTransportTest, ReceiveMessagesForSingleDataChannel) { |
| + EstablishConnection(); |
| + webrtc::DataChannelInit config; |
| + config.id = 1337; |
| + QuicDataChannelForTest peer2_data_channel(peer2_.quic_transport_channel(), |
| + &config); |
| + quic_transport_.RegisterDataChannel(&peer2_data_channel); |
| + |
| + ReliableQuicStream* stream1 = |
| + peer1_.quic_transport_channel()->CreateQuicStream(); |
| + rtc::ByteBuffer byte_buffer1(nullptr, 100, |
| + rtc::ByteBuffer::ByteOrder::ORDER_HOST); |
| + byte_buffer1.WriteVarint(1337); |
| + byte_buffer1.WriteVarint(26); |
| + byte_buffer1.WriteString("Testing"); |
| + stream1->Write(byte_buffer1.Data(), byte_buffer1.Length()); |
| + ASSERT_TRUE_WAIT(peer2_data_channel.has_stream(stream1->id()) && |
| + peer2_data_channel.has_message(7, "Testing"), |
| + kTimeoutMs); |
| + |
| + ReliableQuicStream* stream2 = |
| + peer1_.quic_transport_channel()->CreateQuicStream(); |
| + rtc::ByteBuffer byte_buffer2(nullptr, 100, |
| + rtc::ByteBuffer::ByteOrder::ORDER_HOST); |
| + byte_buffer2.WriteVarint(1337); |
| + byte_buffer2.WriteVarint(402); |
| + byte_buffer2.WriteString("Hello, World!"); |
| + stream2->Write(byte_buffer2.Data(), byte_buffer2.Length()); |
| + ASSERT_TRUE_WAIT(peer2_data_channel.has_stream(stream1->id()) && |
| + peer2_data_channel.has_message(402, "Hello, World!"), |
| + kTimeoutMs); |
| +} |
| + |
| +TEST_F(QuicTransportTest, ReceiveMessagesForMultipleDataChannels) { |
| + EstablishConnection(); |
| + |
| + std::vector<rtc::scoped_ptr<QuicDataChannelForTest>> data_channels; |
| + for (int data_channel_id = 0; data_channel_id < 10; ++data_channel_id) { |
| + webrtc::DataChannelInit config; |
| + config.id = data_channel_id; |
| + rtc::scoped_ptr<QuicDataChannelForTest> data_channel( |
| + new QuicDataChannelForTest(peer2_.quic_transport_channel(), &config)); |
| + quic_transport_.RegisterDataChannel(data_channel.get()); |
| + data_channels.push_back(std::move(data_channel)); |
| + } |
| + |
| + for (int data_channel_id = 0; data_channel_id < 10; ++data_channel_id) { |
| + ReliableQuicStream* stream1 = |
| + peer1_.quic_transport_channel()->CreateQuicStream(); |
| + rtc::ByteBuffer byte_buffer1(nullptr, 100, |
| + rtc::ByteBuffer::ByteOrder::ORDER_HOST); |
| + byte_buffer1.WriteVarint(data_channel_id); |
| + byte_buffer1.WriteVarint(26); |
| + byte_buffer1.WriteString("Testing"); |
| + stream1->Write(byte_buffer1.Data(), byte_buffer1.Length()); |
| + |
| + QuicDataChannelForTest* peer2_data_channel = |
| + data_channels[data_channel_id].get(); |
| + ASSERT_TRUE_WAIT(peer2_data_channel->has_stream(stream1->id()) && |
| + peer2_data_channel->has_message(7, "Testing"), |
| + kTimeoutMs); |
| + |
| + ReliableQuicStream* stream2 = |
| + peer1_.quic_transport_channel()->CreateQuicStream(); |
| + rtc::ByteBuffer byte_buffer2(nullptr, 100, |
| + rtc::ByteBuffer::ByteOrder::ORDER_HOST); |
| + byte_buffer2.WriteVarint(data_channel_id); |
| + byte_buffer2.WriteVarint(402); |
| + byte_buffer2.WriteString("Hello, World!"); |
|
pthatcher1
2016/03/30 20:34:49
It's probably worth making a WriteMessage(dcid, ms
mikescarlett
2016/04/05 19:58:51
Added a helper method.
|
| + stream2->Write(byte_buffer2.Data(), byte_buffer2.Length()); |
| + ASSERT_TRUE_WAIT(peer2_data_channel->has_stream(stream1->id()) && |
| + peer2_data_channel->has_message(402, "Hello, World!"), |
| + kTimeoutMs); |
| + } |
| +} |