blob: df34fb04d75b4114a540ebdbbe4dd52d4589c588 [file] [log] [blame]
// Copyright 2018 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.
// This file tests the RTCQuicStream Blink bindings, QuicStreamProxy and
// QuicStreamHost by mocking out the underlying P2PQuicTransport.
// Everything is run on a single thread but with separate TestSimpleTaskRunners
// for the main thread / worker thread.
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/test/mock_p2p_quic_stream.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_stream_event.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_quic_transport_test.h"
namespace blink {
namespace {
using testing::_;
using testing::ElementsAre;
using testing::InvokeWithoutArgs;
using testing::Return;
using testing::SaveArg;
NotShared<DOMUint8Array> CreateUint8Array(const Vector<uint8_t>& data) {
return NotShared<DOMUint8Array>(
DOMUint8Array::Create(data.data(), data.size()));
}
NotShared<DOMUint8Array> CreateUint8ArrayOfLength(uint32_t length) {
return NotShared<DOMUint8Array>(DOMUint8Array::Create(length));
}
} // namespace
class RTCQuicStreamTest : public RTCQuicTransportTest {
public:
RTCQuicStream* CreateQuicStream(V8TestingScope& scope,
MockP2PQuicStream* mock_stream) {
auto p2p_quic_transport = std::make_unique<MockP2PQuicTransport>();
EXPECT_CALL(*p2p_quic_transport, CreateStream())
.WillOnce(Return(mock_stream));
Persistent<RTCQuicTransport> quic_transport =
CreateConnectedQuicTransport(scope, std::move(p2p_quic_transport));
return quic_transport->createStream(ASSERT_NO_EXCEPTION);
}
};
// Test that RTCQuicTransport.createStream causes CreateStream to be called on
// the underlying transport and a P2PQuicStream::Delegate to be set on the
// underlying P2PQuicStream.
TEST_F(RTCQuicStreamTest, RTCQuicTransportCreateStreamCallsUnderlying) {
V8TestingScope scope;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
EXPECT_CALL(*p2p_quic_stream, SetDelegate(_))
.WillOnce(testing::Invoke(
[](P2PQuicStream::Delegate* delegate) { EXPECT_TRUE(delegate); }));
auto p2p_quic_transport = std::make_unique<MockP2PQuicTransport>();
EXPECT_CALL(*p2p_quic_transport, CreateStream())
.WillOnce(Return(p2p_quic_stream.get()));
Persistent<RTCQuicTransport> quic_transport =
CreateConnectedQuicTransport(scope, std::move(p2p_quic_transport));
Persistent<RTCQuicStream> quic_stream =
quic_transport->createStream(ASSERT_NO_EXCEPTION);
RunUntilIdle();
}
// Test that calling OnStream on the P2PQuicTransport delegate causes a
// quicstream event to fire with a new RTCQuicStream.
TEST_F(RTCQuicStreamTest, NewRemoteStreamFiresEvent) {
V8TestingScope scope;
P2PQuicTransport::Delegate* transport_delegate = nullptr;
Persistent<RTCQuicTransport> quic_transport =
CreateConnectedQuicTransport(scope, &transport_delegate);
Persistent<MockEventListener> quic_stream_listener =
CreateMockEventListener();
EXPECT_CALL(*quic_stream_listener, Invoke(_, _))
.WillOnce(testing::Invoke([](ExecutionContext*, Event* event) {
auto* stream_event = static_cast<RTCQuicStreamEvent*>(event);
EXPECT_NE(nullptr, stream_event->stream());
}));
quic_transport->addEventListener(event_type_names::kQuicstream,
quic_stream_listener);
ASSERT_TRUE(transport_delegate);
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
EXPECT_CALL(*p2p_quic_stream, SetDelegate(_))
.WillOnce(testing::Invoke(
[](P2PQuicStream::Delegate* delegate) { EXPECT_TRUE(delegate); }));
transport_delegate->OnStream(p2p_quic_stream.get());
RunUntilIdle();
}
// Test that calling reset() calls Reset() on the underlying P2PQuicStream.
TEST_F(RTCQuicStreamTest, ResetCallsUnderlying) {
V8TestingScope scope;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
EXPECT_CALL(*p2p_quic_stream, Reset()).Times(1);
auto p2p_quic_transport = std::make_unique<MockP2PQuicTransport>();
EXPECT_CALL(*p2p_quic_transport, CreateStream())
.WillOnce(Return(p2p_quic_stream.get()));
Persistent<RTCQuicTransport> quic_transport =
CreateConnectedQuicTransport(scope, std::move(p2p_quic_transport));
Persistent<RTCQuicStream> stream =
quic_transport->createStream(ASSERT_NO_EXCEPTION);
stream->reset();
RunUntilIdle();
}
// Test that calling OnRemoteReset() on the P2PQuicStream delegate fires a
// statechange event to 'closed'.
TEST_F(RTCQuicStreamTest, OnRemoteResetFiresStateChangeToClosed) {
V8TestingScope scope;
P2PQuicStream::Delegate* stream_delegate = nullptr;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
EXPECT_CALL(*p2p_quic_stream, SetDelegate(_))
.WillOnce(SaveArg<0>(&stream_delegate));
auto p2p_quic_transport = std::make_unique<MockP2PQuicTransport>();
EXPECT_CALL(*p2p_quic_transport, CreateStream())
.WillOnce(Return(p2p_quic_stream.get()));
Persistent<RTCQuicTransport> quic_transport =
CreateConnectedQuicTransport(scope, std::move(p2p_quic_transport));
Persistent<RTCQuicStream> quic_stream =
quic_transport->createStream(ASSERT_NO_EXCEPTION);
Persistent<MockEventListener> state_change_listener =
CreateMockEventListener();
EXPECT_CALL(*state_change_listener, Invoke(_, _))
.WillOnce(InvokeWithoutArgs(
[quic_stream]() { EXPECT_EQ("closed", quic_stream->state()); }));
quic_stream->addEventListener(event_type_names::kStatechange,
state_change_listener);
RunUntilIdle();
ASSERT_TRUE(stream_delegate);
stream_delegate->OnRemoteReset();
RunUntilIdle();
}
// Test that a pending OnRemoteReset() is ignored if reset() is called first.
TEST_F(RTCQuicStreamTest, PendingOnRemoteResetIgnoredAfterReset) {
V8TestingScope scope;
P2PQuicStream::Delegate* stream_delegate = nullptr;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
EXPECT_CALL(*p2p_quic_stream, SetDelegate(_))
.WillOnce(SaveArg<0>(&stream_delegate));
auto p2p_quic_transport = std::make_unique<MockP2PQuicTransport>();
EXPECT_CALL(*p2p_quic_transport, CreateStream())
.WillOnce(Return(p2p_quic_stream.get()));
Persistent<RTCQuicTransport> quic_transport =
CreateConnectedQuicTransport(scope, std::move(p2p_quic_transport));
Persistent<RTCQuicStream> quic_stream =
quic_transport->createStream(ASSERT_NO_EXCEPTION);
// Expect no statechange event since reset() will already transition the state
// to 'closed'.
Persistent<MockEventListener> state_change_listener =
CreateMockEventListener();
EXPECT_CALL(*state_change_listener, Invoke(_, _)).Times(0);
quic_stream->addEventListener(event_type_names::kStatechange,
state_change_listener);
RunUntilIdle();
ASSERT_TRUE(stream_delegate);
stream_delegate->OnRemoteReset();
quic_stream->reset();
EXPECT_EQ("closed", quic_stream->state());
RunUntilIdle();
EXPECT_EQ("closed", quic_stream->state());
}
// The following group tests write(), finish(), writeBufferedAmount(), and
// maxWriteBufferdAmount().
// Test that write() adds to writeBufferedAmount().
TEST_F(RTCQuicStreamTest, WriteAddsToWriteBufferedAmount) {
V8TestingScope scope;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
stream->write(CreateUint8Array({1, 2}), ASSERT_NO_EXCEPTION);
EXPECT_EQ(2u, stream->writeBufferedAmount());
stream->write(CreateUint8Array({3, 4, 5}), ASSERT_NO_EXCEPTION);
EXPECT_EQ(5u, stream->writeBufferedAmount());
RunUntilIdle();
}
// Test that write() calls WriteData() on the underlying P2PQuicStream.
TEST_F(RTCQuicStreamTest, WriteCallsWriteData) {
V8TestingScope scope;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
EXPECT_CALL(*p2p_quic_stream, WriteData(_, _))
.WillOnce(testing::Invoke([](Vector<uint8_t> data, bool fin) {
EXPECT_THAT(data, ElementsAre(1, 2, 3, 4));
EXPECT_FALSE(fin);
}));
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
stream->write(CreateUint8Array({1, 2, 3, 4}), ASSERT_NO_EXCEPTION);
RunUntilIdle();
}
// Test that write() with no data succeeds but does not post a WriteData() to
// the underlying P2PQuicStream.
TEST_F(RTCQuicStreamTest, WriteWithEmptyArrayDoesNotCallWriteData) {
V8TestingScope scope;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
EXPECT_CALL(*p2p_quic_stream, WriteData(_, _)).Times(0);
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
stream->write(CreateUint8Array({}), ASSERT_NO_EXCEPTION);
RunUntilIdle();
}
// Test that finish() calls WriteData() on the underlying P2PQuicStream.
TEST_F(RTCQuicStreamTest, FinishCallsWriteData) {
V8TestingScope scope;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>();
EXPECT_CALL(*p2p_quic_stream, WriteData(_, _))
.WillOnce(testing::Invoke([](Vector<uint8_t> data, bool fin) {
EXPECT_THAT(data, ElementsAre());
EXPECT_TRUE(fin);
}));
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
stream->finish();
RunUntilIdle();
}
// Test that writeBufferedAmount is decreased when receiving OnWriteDataConsumed
// from the underlying P2PQuicStream.
TEST_F(RTCQuicStreamTest, OnWriteDataConsumedSubtractsFromWriteBufferedAmount) {
V8TestingScope scope;
P2PQuicStream::Delegate* stream_delegate = nullptr;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
stream->write(CreateUint8ArrayOfLength(4), ASSERT_NO_EXCEPTION);
RunUntilIdle();
ASSERT_TRUE(stream_delegate);
stream_delegate->OnWriteDataConsumed(4);
RunUntilIdle();
EXPECT_EQ(0u, stream->writeBufferedAmount());
}
// Test that writeBufferedAmount is set to 0 if the stream was reset by the
// remote peer.
TEST_F(RTCQuicStreamTest, OnRemoteResetSetsWriteBufferedAmountToZero) {
V8TestingScope scope;
P2PQuicStream::Delegate* stream_delegate = nullptr;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
stream->write(CreateUint8ArrayOfLength(4), ASSERT_NO_EXCEPTION);
RunUntilIdle();
ASSERT_TRUE(stream_delegate);
stream_delegate->OnRemoteReset();
RunUntilIdle();
EXPECT_EQ(0u, stream->writeBufferedAmount());
RunUntilIdle();
}
// Test that write throws an InvalidStateError if the stream was reset by the
// remote peer.
TEST_F(RTCQuicStreamTest, WriteThrowsIfRemoteReset) {
V8TestingScope scope;
P2PQuicStream::Delegate* stream_delegate = nullptr;
auto p2p_quic_stream = std::make_unique<MockP2PQuicStream>(&stream_delegate);
Persistent<RTCQuicStream> stream =
CreateQuicStream(scope, p2p_quic_stream.get());
RunUntilIdle();
ASSERT_TRUE(stream_delegate);
stream_delegate->OnRemoteReset();
RunUntilIdle();
stream->write(CreateUint8ArrayOfLength(1), scope.GetExceptionState());
EXPECT_EQ(DOMExceptionCode::kInvalidStateError,
scope.GetExceptionState().CodeAs<DOMExceptionCode>());
RunUntilIdle();
}
} // namespace blink