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

Unified Diff: components/cronet/ios/test/cronet_bidirectional_stream_test.mm

Issue 2487863003: Revert of Revert "Revert of Moving gRPC support interfaces out of cronet and into a new component. (patchset … (Closed)
Patch Set: Created 4 years, 1 month 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
« no previous file with comments | « components/cronet/ios/test/BUILD.gn ('k') | components/cronet/ios/test/cronet_http_test.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/cronet/ios/test/cronet_bidirectional_stream_test.mm
diff --git a/components/cronet/ios/test/cronet_bidirectional_stream_test.mm b/components/cronet/ios/test/cronet_bidirectional_stream_test.mm
new file mode 100644
index 0000000000000000000000000000000000000000..f6421d7a80a0cd0a1e517328ea79516eb3f06e70
--- /dev/null
+++ b/components/cronet/ios/test/cronet_bidirectional_stream_test.mm
@@ -0,0 +1,709 @@
+// Copyright 2016 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.
+
+#import <Cronet/Cronet.h>
+
+#include <stdint.h>
+#include <list>
+#include <map>
+#include <string>
+#include <Cronet/cronet_c_for_grpc.h>
+
+#include "base/at_exit.h"
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "components/cronet/ios/test/quic_test_server.h"
+#include "net/base/mac/url_conversions.h"
+#include "net/base/net_errors.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "url/gurl.h"
+
+namespace {
+
+cronet_bidirectional_stream_header kTestHeaders[] = {
+ {"header1", "foo"},
+ {"header2", "bar"},
+};
+const cronet_bidirectional_stream_header_array kTestHeadersArray = {
+ 2, 2, kTestHeaders};
+} // namespace
+
+namespace cronet {
+
+base::AtExitManager* g_at_exit_ = nullptr;
+
+void StartCronetIfNecessary() {
+ static bool initialized = false;
+ if (!initialized) {
+ initialized = true;
+ [Cronet setUserAgent:@"CronetTest/1.0.0.0" partial:NO];
+ [Cronet setHttp2Enabled:true];
+ [Cronet setQuicEnabled:true];
+ [Cronet setSslKeyLogFileName:@"SSLKEYLOGFILE"];
+
+ [Cronet addQuicHint:@"test.example.com"
+ port:cronet::kTestServerPort
+ altPort:cronet::kTestServerPort];
+ [Cronet enableTestCertVerifierForTesting];
+ [Cronet
+ setHostResolverRulesForTesting:@"MAP test.example.com 127.0.0.1,"
+ "MAP notfound.example.com ~NOTFOUND"];
+ [Cronet start];
+
+ // This method must be called once from the main thread.
+ if (!g_at_exit_)
+ g_at_exit_ = new base::AtExitManager;
+ }
+}
+
+class CronetBidirectionalStreamTest : public ::testing::TestWithParam<bool> {
+ protected:
+ CronetBidirectionalStreamTest() {}
+ ~CronetBidirectionalStreamTest() override {}
+
+ void SetUp() override {
+ StartCronetIfNecessary();
+ StartQuicTestServer();
+ [Cronet startNetLogToFile:@"cronet_netlog.json" logBytes:YES];
+ }
+
+ void TearDown() override {
+ ShutdownQuicTestServer();
+ [Cronet stopNetLog];
+ }
+
+ cronet_engine* engine() { return [Cronet getGlobalEngine]; }
+};
+
+class TestBidirectionalStreamCallback {
+ public:
+ enum ResponseStep {
+ NOTHING,
+ ON_STREAM_READY,
+ ON_RESPONSE_STARTED,
+ ON_READ_COMPLETED,
+ ON_WRITE_COMPLETED,
+ ON_TRAILERS,
+ ON_CANCELED,
+ ON_FAILED,
+ ON_SUCCEEDED
+ };
+
+ struct WriteData {
+ std::string buffer;
+ // If |flush| is true, then cronet_bidirectional_stream_flush() will be
+ // called after writing of the |buffer|.
+ bool flush;
+
+ WriteData(const std::string& buffer, bool flush);
+ ~WriteData();
+
+ DISALLOW_COPY_AND_ASSIGN(WriteData);
+ };
+
+ cronet_bidirectional_stream* stream;
+ base::WaitableEvent stream_done_event;
+
+ // Test parameters.
+ std::map<std::string, std::string> request_headers;
+ std::list<std::unique_ptr<WriteData>> write_data;
+ std::string expected_negotiated_protocol;
+ ResponseStep cancel_from_step;
+ size_t read_buffer_size;
+
+ // Test results.
+ ResponseStep response_step;
+ char* read_buffer;
+ std::map<std::string, std::string> response_headers;
+ std::map<std::string, std::string> response_trailers;
+ std::vector<std::string> read_data;
+ int net_error;
+
+ TestBidirectionalStreamCallback()
+ : stream(nullptr),
+ stream_done_event(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED),
+ expected_negotiated_protocol("quic/1+spdy/3"),
+ cancel_from_step(NOTHING),
+ read_buffer_size(32768),
+ response_step(NOTHING),
+ read_buffer(nullptr),
+ net_error(0) {}
+
+ ~TestBidirectionalStreamCallback() {
+ if (read_buffer)
+ delete read_buffer;
+ }
+
+ static TestBidirectionalStreamCallback* FromStream(
+ cronet_bidirectional_stream* stream) {
+ DCHECK(stream);
+ return (TestBidirectionalStreamCallback*)stream->annotation;
+ }
+
+ virtual bool MaybeCancel(cronet_bidirectional_stream* stream,
+ ResponseStep step) {
+ DCHECK_EQ(stream, this->stream);
+ response_step = step;
+ DLOG(WARNING) << "Step: " << step;
+
+ if (step != cancel_from_step)
+ return false;
+
+ cronet_bidirectional_stream_cancel(stream);
+ cronet_bidirectional_stream_write(stream, "abc", 3, false);
+
+ return true;
+ }
+
+ void SignalDone() { stream_done_event.Signal(); }
+
+ void BlockForDone() { stream_done_event.Wait(); }
+
+ void AddWriteData(const std::string& data) { AddWriteData(data, true); }
+ void AddWriteData(const std::string& data, bool flush) {
+ write_data.push_back(base::MakeUnique<WriteData>(data, flush));
+ }
+
+ virtual void MaybeWriteNextData(cronet_bidirectional_stream* stream) {
+ DCHECK_EQ(stream, this->stream);
+ if (write_data.empty())
+ return;
+ for (const auto& data : write_data) {
+ cronet_bidirectional_stream_write(stream, data->buffer.c_str(),
+ data->buffer.size(),
+ data == write_data.back());
+ if (data->flush) {
+ cronet_bidirectional_stream_flush(stream);
+ break;
+ }
+ }
+ }
+
+ cronet_bidirectional_stream_callback* callback() const { return &s_callback; }
+
+ private:
+ // C callbacks.
+ static void on_stream_ready_callback(cronet_bidirectional_stream* stream) {
+ TestBidirectionalStreamCallback* test = FromStream(stream);
+ if (test->MaybeCancel(stream, ON_STREAM_READY))
+ return;
+ test->MaybeWriteNextData(stream);
+ }
+
+ static void on_response_headers_received_callback(
+ cronet_bidirectional_stream* stream,
+ const cronet_bidirectional_stream_header_array* headers,
+ const char* negotiated_protocol) {
+ TestBidirectionalStreamCallback* test = FromStream(stream);
+ ASSERT_EQ(test->expected_negotiated_protocol,
+ std::string(negotiated_protocol));
+ for (size_t i = 0; i < headers->count; ++i) {
+ test->response_headers[headers->headers[i].key] =
+ headers->headers[i].value;
+ }
+ if (test->MaybeCancel(stream, ON_RESPONSE_STARTED))
+ return;
+ test->read_buffer = new char[test->read_buffer_size];
+ cronet_bidirectional_stream_read(stream, test->read_buffer,
+ test->read_buffer_size);
+ }
+
+ static void on_read_completed_callback(cronet_bidirectional_stream* stream,
+ char* data,
+ int count) {
+ TestBidirectionalStreamCallback* test = FromStream(stream);
+ test->read_data.push_back(std::string(data, count));
+ if (test->MaybeCancel(stream, ON_READ_COMPLETED))
+ return;
+ if (count == 0)
+ return;
+ cronet_bidirectional_stream_read(stream, test->read_buffer,
+ test->read_buffer_size);
+ }
+
+ static void on_write_completed_callback(cronet_bidirectional_stream* stream,
+ const char* data) {
+ TestBidirectionalStreamCallback* test = FromStream(stream);
+ ASSERT_EQ(test->write_data.front()->buffer.c_str(), data);
+ if (test->MaybeCancel(stream, ON_WRITE_COMPLETED))
+ return;
+ bool continue_writing = test->write_data.front()->flush;
+ test->write_data.pop_front();
+ if (continue_writing)
+ test->MaybeWriteNextData(stream);
+ }
+
+ 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;
+ }
+
+ static void on_succeded_callback(cronet_bidirectional_stream* stream) {
+ TestBidirectionalStreamCallback* test = FromStream(stream);
+ ASSERT_TRUE(test->write_data.empty());
+ test->MaybeCancel(stream, ON_SUCCEEDED);
+ test->SignalDone();
+ }
+
+ static void on_failed_callback(cronet_bidirectional_stream* stream,
+ int net_error) {
+ TestBidirectionalStreamCallback* test = FromStream(stream);
+ test->net_error = net_error;
+ test->MaybeCancel(stream, ON_FAILED);
+ test->SignalDone();
+ }
+
+ static void on_canceled_callback(cronet_bidirectional_stream* stream) {
+ TestBidirectionalStreamCallback* test = FromStream(stream);
+ test->MaybeCancel(stream, ON_CANCELED);
+ test->SignalDone();
+ }
+
+ static cronet_bidirectional_stream_callback s_callback;
+};
+
+cronet_bidirectional_stream_callback
+ TestBidirectionalStreamCallback::s_callback = {
+ on_stream_ready_callback,
+ on_response_headers_received_callback,
+ on_read_completed_callback,
+ on_write_completed_callback,
+ on_response_trailers_received_callback,
+ on_succeded_callback,
+ on_failed_callback,
+ on_canceled_callback};
+
+TestBidirectionalStreamCallback::WriteData::WriteData(const std::string& data,
+ bool flush_after)
+ : buffer(data), flush(flush_after) {}
+
+TestBidirectionalStreamCallback::WriteData::~WriteData() {}
+
+TEST_P(CronetBidirectionalStreamTest, StartExampleBidiStream) {
+ TestBidirectionalStreamCallback test;
+ test.AddWriteData("Hello, ");
+ test.AddWriteData("world!");
+ // Use small read buffer size to test that response is split properly.
+ test.read_buffer_size = 2;
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
+ &kTestHeadersArray, false);
+ test.BlockForDone();
+ 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(kHelloBodyValue, 2), test.read_data.front());
+ // Verify that individual read data joined using empty separator match
+ // expected body.
+ 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);
+}
+
+TEST_P(CronetBidirectionalStreamTest, SimplePutWithEmptyWriteDataAtTheEnd) {
+ TestBidirectionalStreamCallback test;
+ test.AddWriteData("Hello, ");
+ test.AddWriteData("world!");
+ test.AddWriteData("");
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "PUT",
+ &kTestHeadersArray, false);
+ test.BlockForDone();
+ 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(kHelloBodyValue), test.read_data.front());
+ ASSERT_EQ(std::string(kHelloTrailerValue),
+ test.response_trailers[kHelloTrailerName]);
+ cronet_bidirectional_stream_destroy(test.stream);
+}
+
+TEST_P(CronetBidirectionalStreamTest, SimpleGetWithFlush) {
+ TestBidirectionalStreamCallback test;
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_disable_auto_flush(test.stream, true);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ // Flush before start is ignored.
+ cronet_bidirectional_stream_flush(test.stream);
+ cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "GET",
+ &kTestHeadersArray, true);
+ test.BlockForDone();
+ 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(kHelloBodyValue), base::JoinString(test.read_data, ""));
+ ASSERT_EQ(std::string(kHelloTrailerValue),
+ test.response_trailers[kHelloTrailerName]);
+ // Flush after done is ignored.
+ cronet_bidirectional_stream_flush(test.stream);
+ cronet_bidirectional_stream_destroy(test.stream);
+}
+
+TEST_P(CronetBidirectionalStreamTest, SimplePostWithFlush) {
+ TestBidirectionalStreamCallback test;
+ test.AddWriteData("Test String", false);
+ test.AddWriteData("1234567890", false);
+ test.AddWriteData("woot!", true);
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_disable_auto_flush(test.stream, true);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ // Flush before start is ignored.
+ cronet_bidirectional_stream_flush(test.stream);
+ cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
+ &kTestHeadersArray, false);
+ test.BlockForDone();
+ 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(kHelloBodyValue), base::JoinString(test.read_data, ""));
+ ASSERT_EQ(std::string(kHelloTrailerValue),
+ test.response_trailers[kHelloTrailerName]);
+ // Flush after done is ignored.
+ cronet_bidirectional_stream_flush(test.stream);
+ cronet_bidirectional_stream_destroy(test.stream);
+}
+
+TEST_P(CronetBidirectionalStreamTest, SimplePostWithFlushTwice) {
+ TestBidirectionalStreamCallback test;
+ test.AddWriteData("Test String", false);
+ test.AddWriteData("1234567890", false);
+ test.AddWriteData("woot!", true);
+ test.AddWriteData("Test String", false);
+ test.AddWriteData("1234567890", false);
+ test.AddWriteData("woot!", true);
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_disable_auto_flush(test.stream, true);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ // Flush before start is ignored.
+ cronet_bidirectional_stream_flush(test.stream);
+ cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
+ &kTestHeadersArray, false);
+ test.BlockForDone();
+ 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(kHelloBodyValue), base::JoinString(test.read_data, ""));
+ ASSERT_EQ(std::string(kHelloTrailerValue),
+ test.response_trailers[kHelloTrailerName]);
+ // Flush after done is ignored.
+ cronet_bidirectional_stream_flush(test.stream);
+ cronet_bidirectional_stream_destroy(test.stream);
+}
+
+TEST_P(CronetBidirectionalStreamTest, SimplePostWithFlushAfterOneWrite) {
+ TestBidirectionalStreamCallback test;
+ test.AddWriteData("Test String", false);
+ test.AddWriteData("1234567890", false);
+ test.AddWriteData("woot!", true);
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_disable_auto_flush(test.stream, true);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ // Flush before start is ignored.
+ cronet_bidirectional_stream_flush(test.stream);
+ cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
+ &kTestHeadersArray, false);
+ test.BlockForDone();
+ 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(kHelloBodyValue), base::JoinString(test.read_data, ""));
+ ASSERT_EQ(std::string(kHelloTrailerValue),
+ test.response_trailers[kHelloTrailerName]);
+ // Flush after done is ignored.
+ cronet_bidirectional_stream_flush(test.stream);
+ cronet_bidirectional_stream_destroy(test.stream);
+}
+
+TEST_P(CronetBidirectionalStreamTest, TestDelayedFlush) {
+ class CustomTestBidirectionalStreamCallback
+ : public TestBidirectionalStreamCallback {
+ void MaybeWriteNextData(cronet_bidirectional_stream* stream) override {
+ DCHECK_EQ(stream, this->stream);
+ if (write_data.empty())
+ return;
+ // Write all buffers when stream is ready.
+ // Flush after "3" and "5".
+ // EndOfStream is set with "6" but not flushed, so it is not sent.
+ if (write_data.front()->buffer == "1") {
+ for (const auto& data : write_data) {
+ cronet_bidirectional_stream_write(stream, data->buffer.c_str(),
+ data->buffer.size(),
+ data == write_data.back());
+ if (data->flush) {
+ cronet_bidirectional_stream_flush(stream);
+ }
+ }
+ }
+ // Flush the final buffer with endOfStream flag.
+ if (write_data.front()->buffer == "6")
+ cronet_bidirectional_stream_flush(stream);
+ }
+ };
+
+ CustomTestBidirectionalStreamCallback test;
+ test.AddWriteData("1", false);
+ test.AddWriteData("2", false);
+ test.AddWriteData("3", true);
+ test.AddWriteData("4", false);
+ test.AddWriteData("5", true);
+ test.AddWriteData("6", false);
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_disable_auto_flush(test.stream, true);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ // Flush before start is ignored.
+ cronet_bidirectional_stream_flush(test.stream);
+ cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
+ &kTestHeadersArray, false);
+ test.BlockForDone();
+ // Flush after done is ignored.
+ cronet_bidirectional_stream_flush(test.stream);
+ cronet_bidirectional_stream_destroy(test.stream);
+}
+
+TEST_P(CronetBidirectionalStreamTest, CancelOnRead) {
+ TestBidirectionalStreamCallback test;
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ test.cancel_from_step = TestBidirectionalStreamCallback::ON_READ_COMPLETED;
+ cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
+ &kTestHeadersArray, true);
+ test.BlockForDone();
+ 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);
+}
+
+TEST_P(CronetBidirectionalStreamTest, CancelOnResponse) {
+ TestBidirectionalStreamCallback test;
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ test.cancel_from_step = TestBidirectionalStreamCallback::ON_RESPONSE_STARTED;
+ cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
+ &kTestHeadersArray, true);
+ test.BlockForDone();
+ 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);
+}
+
+TEST_P(CronetBidirectionalStreamTest, CancelOnSucceeded) {
+ TestBidirectionalStreamCallback test;
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ test.cancel_from_step = TestBidirectionalStreamCallback::ON_SUCCEEDED;
+ cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
+ &kTestHeadersArray, true);
+ test.BlockForDone();
+ 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);
+}
+
+TEST_P(CronetBidirectionalStreamTest, ReadFailsBeforeRequestStarted) {
+ TestBidirectionalStreamCallback test;
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ char read_buffer[1];
+ cronet_bidirectional_stream_read(test.stream, read_buffer,
+ sizeof(read_buffer));
+ test.BlockForDone();
+ ASSERT_TRUE(test.read_data.empty());
+ ASSERT_EQ(TestBidirectionalStreamCallback::ON_FAILED, test.response_step);
+ ASSERT_EQ(net::ERR_UNEXPECTED, test.net_error);
+ cronet_bidirectional_stream_destroy(test.stream);
+}
+
+TEST_P(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_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ 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_P(CronetBidirectionalStreamTest, WriteFailsBeforeRequestStarted) {
+ TestBidirectionalStreamCallback test;
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ cronet_bidirectional_stream_write(test.stream, "1", 1, false);
+ test.BlockForDone();
+ ASSERT_TRUE(test.read_data.empty());
+ ASSERT_EQ(TestBidirectionalStreamCallback::ON_FAILED, test.response_step);
+ ASSERT_EQ(net::ERR_UNEXPECTED, test.net_error);
+ cronet_bidirectional_stream_destroy(test.stream);
+}
+
+TEST_P(CronetBidirectionalStreamTest, StreamFailAfterStreamReadyCallback) {
+ class CustomTestBidirectionalStreamCallback
+ : public TestBidirectionalStreamCallback {
+ bool MaybeCancel(cronet_bidirectional_stream* stream,
+ ResponseStep step) override {
+ if (step == ResponseStep::ON_STREAM_READY) {
+ // 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.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
+ &kTestHeadersArray, false);
+ test.BlockForDone();
+ ASSERT_EQ(TestBidirectionalStreamCallback::ON_FAILED, test.response_step);
+ ASSERT_TRUE(test.net_error == net::ERR_QUIC_PROTOCOL_ERROR ||
+ test.net_error == net::ERR_QUIC_HANDSHAKE_FAILED);
+ cronet_bidirectional_stream_destroy(test.stream);
+}
+
+TEST_P(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_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ cronet_bidirectional_stream_start(test.stream, kTestServerUrl, 0, "POST",
+ &kTestHeadersArray, false);
+ test.BlockForDone();
+ ASSERT_EQ(TestBidirectionalStreamCallback::ON_FAILED, test.response_step);
+ ASSERT_TRUE(test.net_error == net::ERR_QUIC_PROTOCOL_ERROR ||
+ test.net_error == net::ERR_QUIC_HANDSHAKE_FAILED);
+ cronet_bidirectional_stream_destroy(test.stream);
+}
+
+TEST_P(CronetBidirectionalStreamTest, FailedResolution) {
+ TestBidirectionalStreamCallback test;
+ test.stream =
+ cronet_bidirectional_stream_create(engine(), &test, test.callback());
+ DCHECK(test.stream);
+ cronet_bidirectional_stream_delay_request_headers_until_flush(test.stream,
+ GetParam());
+ test.cancel_from_step = TestBidirectionalStreamCallback::ON_FAILED;
+ cronet_bidirectional_stream_start(test.stream, "https://notfound.example.com",
+ 0, "GET", &kTestHeadersArray, true);
+ test.BlockForDone();
+ ASSERT_TRUE(test.read_data.empty());
+ ASSERT_EQ(TestBidirectionalStreamCallback::ON_FAILED, test.response_step);
+ ASSERT_EQ(net::ERR_NAME_NOT_RESOLVED, test.net_error);
+ cronet_bidirectional_stream_destroy(test.stream);
+}
+
+INSTANTIATE_TEST_CASE_P(CronetBidirectionalStreamDelayRequestHeadersUntilFlush,
+ CronetBidirectionalStreamTest,
+ ::testing::Values(true, false));
+
+} // namespace cronet
« no previous file with comments | « components/cronet/ios/test/BUILD.gn ('k') | components/cronet/ios/test/cronet_http_test.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698