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); |
+ } |
+} |