| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "modules/peerconnection/RTCDataChannel.h" |
| |
| #include <string> |
| #include "base/memory/scoped_refptr.h" |
| #include "bindings/core/v8/ExceptionState.h" |
| #include "core/dom/DOMException.h" |
| #include "core/dom/events/Event.h" |
| #include "core/testing/NullExecutionContext.h" |
| #include "core/typed_arrays/DOMArrayBuffer.h" |
| #include "platform/heap/Heap.h" |
| #include "platform/wtf/PtrUtil.h" |
| #include "platform/wtf/text/WTFString.h" |
| #include "public/platform/WebRTCDataChannelHandler.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace blink { |
| namespace { |
| |
| class MockHandler final : public WebRTCDataChannelHandler { |
| public: |
| MockHandler() |
| : client_(nullptr), |
| state_(WebRTCDataChannelHandlerClient::kReadyStateConnecting), |
| buffered_amount_(0) {} |
| void SetClient(WebRTCDataChannelHandlerClient* client) override { |
| client_ = client; |
| } |
| WebString Label() override { return WebString(""); } |
| bool Ordered() const override { return true; } |
| unsigned short MaxRetransmitTime() const override { return 0; } |
| unsigned short MaxRetransmits() const override { return 0; } |
| WebString Protocol() const override { return WebString(""); } |
| bool Negotiated() const override { return false; } |
| unsigned short Id() const override { return 0; } |
| |
| WebRTCDataChannelHandlerClient::ReadyState GetState() const override { |
| return state_; |
| } |
| unsigned long BufferedAmount() override { return buffered_amount_; } |
| bool SendStringData(const WebString& s) override { |
| buffered_amount_ += s.length(); |
| return true; |
| } |
| bool SendRawData(const char* data, size_t length) override { |
| buffered_amount_ += length; |
| return true; |
| } |
| void Close() override {} |
| |
| // Methods for testing. |
| void ChangeState(WebRTCDataChannelHandlerClient::ReadyState state) { |
| state_ = state; |
| if (client_) { |
| client_->DidChangeReadyState(state_); |
| } |
| } |
| void DrainBuffer(unsigned long bytes) { |
| unsigned long old_buffered_amount = buffered_amount_; |
| buffered_amount_ -= bytes; |
| if (client_) { |
| client_->DidDecreaseBufferedAmount(old_buffered_amount); |
| } |
| } |
| |
| private: |
| WebRTCDataChannelHandlerClient* client_; |
| WebRTCDataChannelHandlerClient::ReadyState state_; |
| unsigned long buffered_amount_; |
| }; |
| |
| } // namespace |
| |
| TEST(RTCDataChannelTest, BufferedAmount) { |
| MockHandler* handler = new MockHandler(); |
| RTCDataChannel* channel = RTCDataChannel::Create(new NullExecutionContext, |
| WTF::WrapUnique(handler)); |
| |
| handler->ChangeState(WebRTCDataChannelHandlerClient::kReadyStateOpen); |
| String message(std::string(100, 'A').c_str()); |
| channel->send(message, IGNORE_EXCEPTION_FOR_TESTING); |
| EXPECT_EQ(100U, channel->bufferedAmount()); |
| } |
| |
| TEST(RTCDataChannelTest, BufferedAmountLow) { |
| MockHandler* handler = new MockHandler(); |
| RTCDataChannel* channel = RTCDataChannel::Create(new NullExecutionContext, |
| WTF::WrapUnique(handler)); |
| |
| // Add and drain 100 bytes |
| handler->ChangeState(WebRTCDataChannelHandlerClient::kReadyStateOpen); |
| String message(std::string(100, 'A').c_str()); |
| channel->send(message, IGNORE_EXCEPTION_FOR_TESTING); |
| EXPECT_EQ(100U, channel->bufferedAmount()); |
| EXPECT_EQ(1U, channel->scheduled_events_.size()); |
| |
| handler->DrainBuffer(100); |
| EXPECT_EQ(0U, channel->bufferedAmount()); |
| EXPECT_EQ(2U, channel->scheduled_events_.size()); |
| EXPECT_EQ( |
| "bufferedamountlow", |
| std::string(channel->scheduled_events_.back()->type().Utf8().data())); |
| |
| // Add and drain 1 byte |
| channel->send("A", IGNORE_EXCEPTION_FOR_TESTING); |
| EXPECT_EQ(1U, channel->bufferedAmount()); |
| EXPECT_EQ(2U, channel->scheduled_events_.size()); |
| |
| handler->DrainBuffer(1); |
| EXPECT_EQ(0U, channel->bufferedAmount()); |
| EXPECT_EQ(3U, channel->scheduled_events_.size()); |
| EXPECT_EQ( |
| "bufferedamountlow", |
| std::string(channel->scheduled_events_.back()->type().Utf8().data())); |
| |
| // Set the threshold to 99 bytes, add 101, and drain 1 byte at a time. |
| channel->setBufferedAmountLowThreshold(99U); |
| channel->send(message, IGNORE_EXCEPTION_FOR_TESTING); |
| EXPECT_EQ(100U, channel->bufferedAmount()); |
| |
| channel->send("A", IGNORE_EXCEPTION_FOR_TESTING); |
| EXPECT_EQ(101U, channel->bufferedAmount()); |
| |
| handler->DrainBuffer(1); |
| EXPECT_EQ(100U, channel->bufferedAmount()); |
| EXPECT_EQ(3U, channel->scheduled_events_.size()); // No new events. |
| |
| handler->DrainBuffer(1); |
| EXPECT_EQ(99U, channel->bufferedAmount()); |
| EXPECT_EQ(4U, channel->scheduled_events_.size()); // One new event. |
| EXPECT_EQ( |
| "bufferedamountlow", |
| std::string(channel->scheduled_events_.back()->type().Utf8().data())); |
| |
| handler->DrainBuffer(1); |
| EXPECT_EQ(98U, channel->bufferedAmount()); |
| |
| channel->setBufferedAmountLowThreshold(97U); |
| EXPECT_EQ(4U, channel->scheduled_events_.size()); // No new events. |
| |
| handler->DrainBuffer(1); |
| EXPECT_EQ(97U, channel->bufferedAmount()); |
| EXPECT_EQ(5U, channel->scheduled_events_.size()); // New event. |
| EXPECT_EQ( |
| "bufferedamountlow", |
| std::string(channel->scheduled_events_.back()->type().Utf8().data())); |
| } |
| |
| TEST(RTCDataChannelTest, SendAfterContextDestroyed) { |
| MockHandler* handler = new MockHandler(); |
| RTCDataChannel* channel = RTCDataChannel::Create(new NullExecutionContext, |
| WTF::WrapUnique(handler)); |
| handler->ChangeState(WebRTCDataChannelHandlerClient::kReadyStateOpen); |
| channel->ContextDestroyed(nullptr); |
| |
| String message(std::string(100, 'A').c_str()); |
| DummyExceptionStateForTesting exception_state; |
| channel->send(message, exception_state); |
| |
| EXPECT_TRUE(exception_state.HadException()); |
| } |
| |
| TEST(RTCDataChannelTest, CloseAfterContextDestroyed) { |
| MockHandler* handler = new MockHandler(); |
| RTCDataChannel* channel = RTCDataChannel::Create(new NullExecutionContext, |
| WTF::WrapUnique(handler)); |
| handler->ChangeState(WebRTCDataChannelHandlerClient::kReadyStateOpen); |
| channel->ContextDestroyed(nullptr); |
| channel->close(); |
| EXPECT_EQ(String::FromUTF8("closed"), channel->readyState()); |
| } |
| |
| } // namespace blink |