blob: 33f5bbd7ae96a80483baa92b615e0ab4e4e70ce7 [file] [log] [blame]
// Copyright (c) 2012 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 "net/quic/quic_stream_factory.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
#include "base/string_util.h"
#include "net/base/mock_host_resolver.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/http/http_util.h"
#include "net/quic/quic_http_stream.h"
#include "net/quic/test_tools/mock_clock.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/socket/socket_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
namespace test {
class QuicStreamFactoryTest : public ::testing::Test {
protected:
QuicStreamFactoryTest()
: factory_(&host_resolver_, &socket_factory_,
base::Bind(&QuicStreamFactoryTest::GenerateGuid),
new MockClock()),
host_port_proxy_pair_(HostPortPair("www.google.com", 443),
ProxyServer::Direct()) {
}
scoped_ptr<QuicEncryptedPacket> ConstructChlo() {
scoped_ptr<QuicPacket> chlo(ConstructHandshakePacket(0xDEADBEEF, kCHLO));
QuicFramer framer(QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL));
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*chlo));
}
scoped_ptr<QuicEncryptedPacket> ConstructShlo() {
scoped_ptr<QuicPacket> shlo(ConstructHandshakePacket(0xDEADBEEF, kSHLO));
QuicFramer framer(QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL));
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*shlo));
}
scoped_ptr<QuicEncryptedPacket> ConstructRstPacket(
QuicPacketSequenceNumber num,
QuicStreamId stream_id) {
QuicPacketHeader header;
header.guid = 0xDEADBEEF;
header.packet_sequence_number = num;
header.flags = PACKET_FLAGS_NONE;
header.fec_group = 0;
QuicRstStreamFrame rst(stream_id, 0, QUIC_NO_ERROR);
return scoped_ptr<QuicEncryptedPacket>(
ConstructPacket(header, QuicFrame(&rst)));
}
scoped_ptr<QuicEncryptedPacket> ConstructAckPacket(
QuicPacketSequenceNumber largest_received,
QuicPacketSequenceNumber least_unacked) {
QuicPacketHeader header;
header.guid = 0xDEADBEEF;
header.packet_sequence_number = 2;
header.flags = PACKET_FLAGS_NONE;
header.fec_group = 0;
QuicAckFrame ack(largest_received, least_unacked);
return scoped_ptr<QuicEncryptedPacket>(
ConstructPacket(header, QuicFrame(&ack)));
}
// Returns a newly created packet to send congestion feedback data.
scoped_ptr<QuicEncryptedPacket> ConstructFeedbackPacket(
QuicPacketSequenceNumber sequence_number) {
QuicPacketHeader header;
header.guid = 0xDEADBEEF;
header.packet_sequence_number = sequence_number;
header.flags = PACKET_FLAGS_NONE;
header.fec_group = 0;
QuicCongestionFeedbackFrame frame;
frame.type = kTCP;
frame.tcp.accumulated_number_of_lost_packets = 0;
frame.tcp.receive_window = 16000;
return scoped_ptr<QuicEncryptedPacket>(
ConstructPacket(header, QuicFrame(&frame)));
}
scoped_ptr<QuicEncryptedPacket> ConstructPacket(
const QuicPacketHeader& header,
const QuicFrame& frame) {
QuicFramer framer(QuicDecrypter::Create(kNULL),
QuicEncrypter::Create(kNULL));
QuicFrames frames;
frames.push_back(frame);
scoped_ptr<QuicPacket> packet(
framer.ConstructFrameDataPacket(header, frames));
return scoped_ptr<QuicEncryptedPacket>(framer.EncryptPacket(*packet));
}
MockHostResolver host_resolver_;
MockClientSocketFactory socket_factory_;
QuicStreamFactory factory_;
HostPortProxyPair host_port_proxy_pair_;
BoundNetLog net_log_;
TestCompletionCallback callback_;
private:
static uint64 GenerateGuid() {
return 0xDEADBEEF;
}
};
TEST_F(QuicStreamFactoryTest, CreateIfSessionExists) {
EXPECT_EQ(NULL, factory_.CreateIfSessionExists(host_port_proxy_pair_,
net_log_).get());
}
TEST_F(QuicStreamFactoryTest, Create) {
scoped_ptr<QuicEncryptedPacket> chlo(ConstructChlo());
scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 1));
scoped_ptr<QuicEncryptedPacket> feedback(ConstructFeedbackPacket(3));
scoped_ptr<QuicEncryptedPacket> rst3(ConstructRstPacket(4, 3));
scoped_ptr<QuicEncryptedPacket> rst5(ConstructRstPacket(5, 5));
scoped_ptr<QuicEncryptedPacket> rst7(ConstructRstPacket(6, 7));
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, chlo->data(), chlo->length()),
MockWrite(SYNCHRONOUS, ack->data(), ack->length()),
MockWrite(SYNCHRONOUS, feedback->data(), feedback->length()),
MockWrite(SYNCHRONOUS, rst3->data(), rst3->length()),
MockWrite(SYNCHRONOUS, rst5->data(), rst5->length()),
MockWrite(SYNCHRONOUS, rst7->data(), rst7->length()),
};
scoped_ptr<QuicEncryptedPacket> shlo(ConstructShlo());
scoped_ptr<QuicEncryptedPacket> ack2(ConstructAckPacket(2, 0));
MockRead reads[] = {
MockRead(SYNCHRONOUS, shlo->data(), shlo->length()),
MockRead(SYNCHRONOUS, ack2->data(), ack2->length()),
MockRead(ASYNC, OK), // EOF
};
StaticSocketDataProvider socket_data(reads, arraysize(reads),
writes, arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, net_log_,
callback_.callback()));
EXPECT_EQ(OK, callback_.WaitForResult());
scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
// Will reset stream 3.
stream = factory_.CreateIfSessionExists(host_port_proxy_pair_, net_log_);
EXPECT_TRUE(stream.get());
QuicStreamRequest request2(&factory_);
EXPECT_EQ(OK, request2.Request(host_port_proxy_pair_, net_log_,
callback_.callback()));
stream = request2.ReleaseStream(); // Will reset stream 5.
stream.reset(); // Will reset stream 7.
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
}
TEST_F(QuicStreamFactoryTest, CreateError) {
StaticSocketDataProvider socket_data(NULL, 0, NULL, 0);
socket_factory_.AddSocketDataProvider(&socket_data);
host_resolver_.rules()->AddSimulatedFailure("www.google.com");
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, net_log_,
callback_.callback()));
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback_.WaitForResult());
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
}
TEST_F(QuicStreamFactoryTest, CancelCreate) {
scoped_ptr<QuicEncryptedPacket> chlo(ConstructChlo());
scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 1));
scoped_ptr<QuicEncryptedPacket> feedback(ConstructFeedbackPacket(3));
scoped_ptr<QuicEncryptedPacket> rst3(ConstructRstPacket(4, 3));
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, chlo->data(), chlo->length()),
MockWrite(SYNCHRONOUS, ack->data(), ack->length()),
MockWrite(SYNCHRONOUS, feedback->data(), feedback->length()),
MockWrite(SYNCHRONOUS, rst3->data(), rst3->length()),
};
scoped_ptr<QuicEncryptedPacket> shlo(ConstructShlo());
scoped_ptr<QuicEncryptedPacket> ack2(ConstructAckPacket(2, 0));
MockRead reads[] = {
MockRead(SYNCHRONOUS, shlo->data(), shlo->length()),
MockRead(SYNCHRONOUS, ack2->data(), ack2->length()),
MockRead(ASYNC, OK), // EOF
};
StaticSocketDataProvider socket_data(reads, arraysize(reads),
writes, arraysize(writes));
socket_factory_.AddSocketDataProvider(&socket_data);
{
QuicStreamRequest request(&factory_);
EXPECT_EQ(ERR_IO_PENDING, request.Request(host_port_proxy_pair_, net_log_,
callback_.callback()));
}
base::RunLoop run_loop;
run_loop.RunUntilIdle();
scoped_ptr<QuicHttpStream> stream(
factory_.CreateIfSessionExists(host_port_proxy_pair_, net_log_));
EXPECT_TRUE(stream.get());
stream.reset();
EXPECT_TRUE(socket_data.at_read_eof());
EXPECT_TRUE(socket_data.at_write_eof());
}
} // namespace test
} // namespace net