Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(235)

Unified Diff: webrtc/api/quicdatatransport_unittest.cc

Issue 1886623002: Add QuicDataChannel and QuicDataTransport classes (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« webrtc/api/quicdatachannel.cc ('K') | « webrtc/api/quicdatatransport.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/api/quicdatatransport_unittest.cc
diff --git a/webrtc/api/quicdatatransport_unittest.cc b/webrtc/api/quicdatatransport_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ba0fd51cff4c03a469d8e3195c5da88a531712b8
--- /dev/null
+++ b/webrtc/api/quicdatatransport_unittest.cc
@@ -0,0 +1,340 @@
+/*
+ * 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 <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()
+ : 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(QuicDataTransportPeer* 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_;
+ }
+
+ // 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;
+ quic_data_transport_.EncodeHeader(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(
+ rtc::Thread::Current(), rtc::Thread::Current(), "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);
+ rtc::scoped_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_;
+ rtc::scoped_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() {
+ peer1_.quic_data_transport()->SetTransportChannel(
+ peer1_.quic_transport_channel());
+ 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);
+
+ 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:
+ 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_TRUE_WAIT(observer.messages_received() == 1, kTimeoutMs);
+ EXPECT_EQ("Testing", observer.messages()[0]);
+
+ uint64_t message2_id = 402u;
+ peer1_.WriteMessage(data_channel_id, message2_id, "Hello, World!");
+ ASSERT_TRUE_WAIT(observer.messages_received() == 2, kTimeoutMs);
+ EXPECT_EQ("Hello, World!", observer.messages()[1]);
+
+ uint64_t message3_id = 100260415u;
+ peer1_.WriteMessage(data_channel_id, message3_id, "Third message");
+ ASSERT_TRUE_WAIT(observer.messages_received() == 3, 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_TRUE_WAIT(observer.messages_received() == 1, kTimeoutMs);
+ EXPECT_EQ("Testing", observer.messages()[0]);
+
+ uint64_t message2_id = 1372643095u;
+ peer1_.WriteMessage(data_channel_id, message2_id, "Hello, World!");
+ ASSERT_TRUE_WAIT(observer.messages_received() == 2, 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_TRUE_WAIT(observer2.messages_received() == 1, kTimeoutMs);
+ EXPECT_EQ("Peer 1 message 1", observer2.messages()[0]);
+
+ peer1_data_channel->Send(webrtc::DataBuffer("Peer 1 message 2"));
+ ASSERT_TRUE_WAIT(observer2.messages_received() == 2, kTimeoutMs);
+ EXPECT_EQ("Peer 1 message 2", observer2.messages()[1]);
+
+ peer2_data_channel->Send(webrtc::DataBuffer("Peer 2 message 1"));
+ ASSERT_TRUE_WAIT(observer1.messages_received() == 1, kTimeoutMs);
+ EXPECT_EQ("Peer 2 message 1", observer1.messages()[0]);
+
+ peer2_data_channel->Send(webrtc::DataBuffer("Peer 2 message 2"));
+ ASSERT_TRUE_WAIT(observer1.messages_received() == 2, kTimeoutMs);
+ EXPECT_EQ("Peer 2 message 2", observer1.messages()[1]);
+ }
+}
+
+} // namespace
« webrtc/api/quicdatachannel.cc ('K') | « webrtc/api/quicdatatransport.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698