Skip to content

Commit

Permalink
[Cronet] Add Hello World response to QuicTestServer and use it in bid…
Browse files Browse the repository at this point in the history
…irectional stream test.

BUG=601972
BUG=606818

Review-Url: https://codereview.chromium.org/1892423002
Cr-Commit-Position: refs/heads/master@{#390786}
  • Loading branch information
mef authored and Commit bot committed Apr 29, 2016
1 parent e830013 commit 5ef58ed
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 40 deletions.
8 changes: 6 additions & 2 deletions components/cronet/ios/cronet_bidirectional_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,9 @@ void CronetBidirectionalStream::ReadDataOnNetworkThread(
DCHECK(!read_buffer_);
if (read_state_ != WAITING_FOR_READ) {
DLOG(ERROR) << "Unexpected Read Data in read_state " << WAITING_FOR_READ;
OnFailed(net::ERR_UNEXPECTED);
// Invoke OnFailed unless it is already invoked.
if (read_state_ != ERROR)
OnFailed(net::ERR_UNEXPECTED);
return;
}
read_state_ = READING;
Expand All @@ -235,7 +237,9 @@ void CronetBidirectionalStream::WriteDataOnNetworkThread(
DCHECK(!write_buffer_);
if (write_state_ != WAITING_FOR_WRITE) {
DLOG(ERROR) << "Unexpected Write Data in write_state " << write_state_;
OnFailed(net::ERR_UNEXPECTED);
// Invoke OnFailed unless it is already invoked.
if (write_state_ != ERROR)
OnFailed(net::ERR_UNEXPECTED);
return;
}
write_state_ = WRITING;
Expand Down
122 changes: 96 additions & 26 deletions components/cronet/ios/test/cronet_bidirectional_stream_test.mm
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@
#include "url/gurl.h"

namespace {
const char kTestServerHost[] = "test.example.com";
const int kTestServerPort = 6121;
const char kTestServerUrl[] = "https://test.example.com:6121";

cronet_bidirectional_stream_header kTestHeaders[] = {
{"header1", "foo"},
Expand All @@ -37,6 +34,8 @@
2, 2, kTestHeaders};
} // namespace

namespace cronet {

class CronetBidirectionalStreamTest : public ::testing::Test {
protected:
CronetBidirectionalStreamTest() {}
Expand All @@ -49,11 +48,12 @@ void SetUp() override {
// Hack to work around issues with SetUp being called multiple times
// during the test, and QuicTestServer not shutting down / restarting
// gracefully.
cronet::CronetEnvironment::Initialize();
cronet::StartQuicTestServer();
CronetEnvironment::Initialize();
}

cronet_environment_ = new cronet::CronetEnvironment("CronetTest/1.0.0.0");
StartQuicTestServer();

cronet_environment_ = new CronetEnvironment("CronetTest/1.0.0.0");
cronet_environment_->set_http2_enabled(true);
cronet_environment_->set_quic_enabled(true);
cronet_environment_->set_ssl_key_log_file_name("SSLKEYLOGFILE");
Expand All @@ -66,7 +66,7 @@ void SetUp() override {
cronet_environment_->set_host_resolver_rules(
"MAP test.example.com 127.0.0.1,"
"MAP notfound.example.com ~NOTFOUND");
cronet_environment_->AddQuicHint(kTestServerHost, kTestServerPort,
cronet_environment_->AddQuicHint(kTestServerDomain, kTestServerPort,
kTestServerPort);

cronet_environment_->Start();
Expand All @@ -77,7 +77,7 @@ void SetUp() override {
}

void TearDown() override {
// cronet::ShutdownQuicTestServer();
ShutdownQuicTestServer();
cronet_environment_->StopNetLog();
//[CronetEngine stopNetLog];
//[CronetEngine uninstall];
Expand All @@ -86,18 +86,18 @@ void TearDown() override {
cronet_engine* engine() { return &cronet_engine_; }

private:
static cronet::CronetEnvironment* cronet_environment_;
static CronetEnvironment* cronet_environment_;
static cronet_engine cronet_engine_;
};

cronet::CronetEnvironment* CronetBidirectionalStreamTest::cronet_environment_;
CronetEnvironment* CronetBidirectionalStreamTest::cronet_environment_;
cronet_engine CronetBidirectionalStreamTest::cronet_engine_;

class TestBidirectionalStreamCallback {
public:
enum ResponseStep {
NOTHING,
ON_REQUEST_HEADERS_SENT,
ON_STREAM_READY,
ON_RESPONSE_STARTED,
ON_READ_COMPLETED,
ON_WRITE_COMPLETED,
Expand Down Expand Up @@ -146,7 +146,8 @@ void TearDown() override {
return (TestBidirectionalStreamCallback*)stream->annotation;
}

bool MaybeCancel(cronet_bidirectional_stream* stream, ResponseStep step) {
virtual bool MaybeCancel(cronet_bidirectional_stream* stream,
ResponseStep step) {
DCHECK_EQ(stream, this->stream);
response_step = step;
DLOG(WARNING) << "Step: " << step;
Expand All @@ -164,7 +165,7 @@ bool MaybeCancel(cronet_bidirectional_stream* stream, ResponseStep step) {

void AddWriteData(const std::string& data) { write_data.push_back(data); }

void MaybeWriteNextData(cronet_bidirectional_stream* stream) {
virtual void MaybeWriteNextData(cronet_bidirectional_stream* stream) {
DCHECK_EQ(stream, this->stream);
if (write_data.empty())
return;
Expand All @@ -177,10 +178,9 @@ void MaybeWriteNextData(cronet_bidirectional_stream* stream) {

private:
// C callbacks.
static void on_request_headers_sent_callback(
cronet_bidirectional_stream* stream) {
static void on_stream_ready_callback(cronet_bidirectional_stream* stream) {
TestBidirectionalStreamCallback* test = FromStream(stream);
if (test->MaybeCancel(stream, ON_REQUEST_HEADERS_SENT))
if (test->MaybeCancel(stream, ON_STREAM_READY))
return;
test->MaybeWriteNextData(stream);
}
Expand Down Expand Up @@ -230,6 +230,11 @@ static void on_response_trailers_received_callback(
cronet_bidirectional_stream* stream,
const cronet_bidirectional_stream_header_array* trailers) {
TestBidirectionalStreamCallback* test = FromStream(stream);
for (size_t i = 0; i < trailers->count; ++i) {
test->response_trailers[trailers->headers[i].key] =
trailers->headers[i].value;
}

if (test->MaybeCancel(stream, ON_TRAILERS))
return;
}
Expand Down Expand Up @@ -259,7 +264,7 @@ static void on_canceled_callback(cronet_bidirectional_stream* stream) {

cronet_bidirectional_stream_callback
TestBidirectionalStreamCallback::s_callback = {
on_request_headers_sent_callback,
on_stream_ready_callback,
on_response_headers_received_callback,
on_read_completed_callback,
on_write_completed_callback,
Expand All @@ -279,11 +284,14 @@ static void on_canceled_callback(cronet_bidirectional_stream* stream) {
cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
&kTestHeadersArray, false);
test.BlockForDone();
ASSERT_EQ(std::string("404"), test.response_headers[":status"]);
ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
ASSERT_EQ(std::string(kHelloHeaderValue),
test.response_headers[kHelloHeaderName]);
ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
ASSERT_EQ(std::string("fi"), test.read_data.front());
ASSERT_EQ(std::string("file not found"),
base::JoinString(test.read_data, ""));
ASSERT_EQ(std::string(kHelloBodyValue, 2), test.read_data.front());
ASSERT_EQ(std::string(kHelloBodyValue), base::JoinString(test.read_data, ""));
ASSERT_EQ(std::string(kHelloTrailerValue),
test.response_trailers[kHelloTrailerName]);
cronet_bidirectional_stream_destroy(test.stream);
}

Expand All @@ -296,8 +304,8 @@ static void on_canceled_callback(cronet_bidirectional_stream* stream) {
cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
&kTestHeadersArray, true);
test.BlockForDone();
ASSERT_EQ(std::string("404"), test.response_headers[":status"]);
ASSERT_EQ(std::string("file not found"), test.read_data.front());
ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
ASSERT_EQ(std::string(kHelloBodyValue), test.read_data.front());
ASSERT_EQ(TestBidirectionalStreamCallback::ON_CANCELED, test.response_step);
cronet_bidirectional_stream_destroy(test.stream);
}
Expand All @@ -311,7 +319,7 @@ static void on_canceled_callback(cronet_bidirectional_stream* stream) {
cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
&kTestHeadersArray, true);
test.BlockForDone();
ASSERT_EQ(std::string("404"), test.response_headers[":status"]);
ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
ASSERT_TRUE(test.read_data.empty());
ASSERT_EQ(TestBidirectionalStreamCallback::ON_CANCELED, test.response_step);
cronet_bidirectional_stream_destroy(test.stream);
Expand All @@ -326,8 +334,8 @@ static void on_canceled_callback(cronet_bidirectional_stream* stream) {
cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
&kTestHeadersArray, true);
test.BlockForDone();
ASSERT_EQ(std::string("404"), test.response_headers[":status"]);
ASSERT_EQ(std::string("file not found"), test.read_data.front());
ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
ASSERT_EQ(std::string(kHelloBodyValue), test.read_data.front());
ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
cronet_bidirectional_stream_destroy(test.stream);
}
Expand All @@ -347,6 +355,36 @@ static void on_canceled_callback(cronet_bidirectional_stream* stream) {
cronet_bidirectional_stream_destroy(test.stream);
}

TEST_F(CronetBidirectionalStreamTest,
StreamFailBeforeReadIsExecutedOnNetworkThread) {
class CustomTestBidirectionalStreamCallback
: public TestBidirectionalStreamCallback {
bool MaybeCancel(cronet_bidirectional_stream* stream,
ResponseStep step) override {
if (step == ResponseStep::ON_READ_COMPLETED) {
// Shut down the server, and the stream should error out.
// The second call to ShutdownQuicTestServer is no-op.
ShutdownQuicTestServer();
}
return TestBidirectionalStreamCallback::MaybeCancel(stream, step);
}
};

CustomTestBidirectionalStreamCallback test;
test.AddWriteData("Hello, ");
test.AddWriteData("world!");
test.read_buffer_size = 2;
test.stream =
cronet_bidirectional_stream_create(engine(), &test, test.callback());
DCHECK(test.stream);
cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
&kTestHeadersArray, false);
test.BlockForDone();
ASSERT_EQ(TestBidirectionalStreamCallback::ON_FAILED, test.response_step);
ASSERT_EQ(net::ERR_QUIC_PROTOCOL_ERROR, test.net_error);
cronet_bidirectional_stream_destroy(test.stream);
}

TEST_F(CronetBidirectionalStreamTest, WriteFailsBeforeRequestStarted) {
TestBidirectionalStreamCallback test;
test.stream =
Expand All @@ -360,6 +398,36 @@ static void on_canceled_callback(cronet_bidirectional_stream* stream) {
cronet_bidirectional_stream_destroy(test.stream);
}

TEST_F(CronetBidirectionalStreamTest,
StreamFailBeforeWriteIsExecutedOnNetworkThread) {
class CustomTestBidirectionalStreamCallback
: public TestBidirectionalStreamCallback {
bool MaybeCancel(cronet_bidirectional_stream* stream,
ResponseStep step) override {
if (step == ResponseStep::ON_WRITE_COMPLETED) {
// Shut down the server, and the stream should error out.
// The second call to ShutdownQuicTestServer is no-op.
ShutdownQuicTestServer();
}
return TestBidirectionalStreamCallback::MaybeCancel(stream, step);
}
};

CustomTestBidirectionalStreamCallback test;
test.AddWriteData("Test String");
test.AddWriteData("1234567890");
test.AddWriteData("woot!");
test.stream =
cronet_bidirectional_stream_create(engine(), &test, test.callback());
DCHECK(test.stream);
cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
&kTestHeadersArray, false);
test.BlockForDone();
ASSERT_EQ(TestBidirectionalStreamCallback::ON_FAILED, test.response_step);
ASSERT_EQ(net::ERR_QUIC_PROTOCOL_ERROR, test.net_error);
cronet_bidirectional_stream_destroy(test.stream);
}

TEST_F(CronetBidirectionalStreamTest, FailedResolution) {
TestBidirectionalStreamCallback test;
test.stream =
Expand All @@ -374,3 +442,5 @@ static void on_canceled_callback(cronet_bidirectional_stream* stream) {
ASSERT_EQ(net::ERR_NAME_NOT_RESOLVED, test.net_error);
cronet_bidirectional_stream_destroy(test.stream);
}

} // namespace cronet
50 changes: 38 additions & 12 deletions components/cronet/ios/test/quic_test_server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "quic_test_server.h"
#include "components/cronet/ios/test/quic_test_server.h"

#include "base/bind.h"
#include "base/files/file_path.h"
Expand All @@ -14,34 +14,58 @@
#include "net/base/ip_endpoint.h"
#include "net/base/test_data_directory.h"
#include "net/quic/crypto/proof_source_chromium.h"
#include "net/spdy/spdy_header_block.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_simple_server.h"

namespace cronet {

static const int kServerPort = 6121;
// This must match the certificate used (quic_test.example.com.crt and
// quic_test.example.com.key.pkcs8).
const char kTestServerDomain[] = "test.example.com";
const int kTestServerPort = 6121;
const char kTestServerHost[] = "test.example.com:6121";
const char kTestServerUrl[] = "https://test.example.com:6121/hello.txt";

const char kStatusHeader[] = ":status";

const char kHelloPath[] = "/hello.txt";
const char kHelloBodyValue[] = "Hello from QUIC Server";
const char kHelloStatus[] = "200";

const char kHelloHeaderName[] = "hello_header";
const char kHelloHeaderValue[] = "hello header value";

const char kHelloTrailerName[] = "hello_trailer";
const char kHelloTrailerValue[] = "hello trailer value";

base::Thread* g_quic_server_thread = nullptr;
net::QuicSimpleServer* g_quic_server = nullptr;

void SetupQuicInMemoryCache() {
static bool setup_done = false;
if (setup_done)
return;
setup_done = true;
net::SpdyHeaderBlock headers;
headers.ReplaceOrAppendHeader(kHelloHeaderName, kHelloHeaderValue);
headers.ReplaceOrAppendHeader(kStatusHeader, kHelloStatus);
net::SpdyHeaderBlock trailers;
trailers.ReplaceOrAppendHeader(kHelloTrailerName, kHelloTrailerValue);
net::QuicInMemoryCache::GetInstance()->AddResponse(
kTestServerHost, kHelloPath, headers, kHelloBodyValue, trailers);
}

void StartQuicServerOnServerThread(const base::FilePath& test_files_root,
base::WaitableEvent* server_started_event) {
DCHECK(g_quic_server_thread->task_runner()->BelongsToCurrentThread());
DCHECK(!g_quic_server);

// Set up in-memory cache.
/*
base::FilePath file_dir = test_files_root.Append("quic_data");
CHECK(base::PathExists(file_dir)) << "Quic data does not exist";
net::QuicInMemoryCache::GetInstance()->InitializeFromDirectory(
file_dir.value());
*/
SetupQuicInMemoryCache();
net::QuicConfig config;

// Set up server certs.
base::FilePath directory;
// CHECK(base::android::GetExternalStorageDirectory(&directory));
// directory = directory.Append("net/data/ssl/certificates");
directory = test_files_root;
// TODO(xunjieli): Use scoped_ptr when crbug.com/545474 is fixed.
net::ProofSourceChromium* proof_source = new net::ProofSourceChromium();
Expand All @@ -54,7 +78,7 @@ void StartQuicServerOnServerThread(const base::FilePath& test_files_root,

// Start listening.
int rv = g_quic_server->Listen(
net::IPEndPoint(net::IPAddress::IPv4AllZeros(), kServerPort));
net::IPEndPoint(net::IPAddress::IPv4AllZeros(), kTestServerPort));
CHECK_GE(rv, 0) << "Quic server fails to start";
server_started_event->Signal();
}
Expand Down Expand Up @@ -89,6 +113,8 @@ bool StartQuicTestServer() {
}

void ShutdownQuicTestServer() {
if (!g_quic_server_thread)
return;
DCHECK(!g_quic_server_thread->task_runner()->BelongsToCurrentThread());
base::WaitableEvent server_stopped_event(true, false);
g_quic_server_thread->task_runner()->PostTask(
Expand Down
16 changes: 16 additions & 0 deletions components/cronet/ios/test/quic_test_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@ bool StartQuicTestServer();

void ShutdownQuicTestServer();

extern const char kTestServerDomain[];
extern const int kTestServerPort;
extern const char kTestServerHost[];
extern const char kTestServerUrl[];

extern const char kStatusHeader[];

extern const char kHelloBodyValue[];
extern const char kHelloStatus[];

extern const char kHelloHeaderName[];
extern const char kHelloHeaderValue[];

extern const char kHelloTrailerName[];
extern const char kHelloTrailerValue[];

} // namespace cronet

#endif // COMPONENTS_CRONET_IOS_TEST_QUIC_TEST_SERVER_H_

0 comments on commit 5ef58ed

Please sign in to comment.