| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import <Foundation/Foundation.h> |
| 6 #include <stdint.h> |
| 7 |
| 8 #include "base/logging.h" |
| 9 #include "base/mac/scoped_nsobject.h" |
| 10 #include "base/strings/string_util.h" |
| 11 #include "base/strings/sys_string_conversions.h" |
| 12 #include "base/synchronization/waitable_event.h" |
| 13 #include "components/cronet/ios/cronet_c_for_grpc.h" |
| 14 #include "components/cronet/ios/cronet_environment.h" |
| 15 #include "components/cronet/ios/test/quic_test_server.h" |
| 16 #include "net/base/mac/url_conversions.h" |
| 17 #include "net/base/test_data_directory.h" |
| 18 #include "net/cert/mock_cert_verifier.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" |
| 20 #include "testing/gtest_mac.h" |
| 21 #include "url/gurl.h" |
| 22 |
| 23 class CronetBidirectionalStreamTest : public ::testing::Test { |
| 24 protected: |
| 25 CronetBidirectionalStreamTest() {} |
| 26 ~CronetBidirectionalStreamTest() override {} |
| 27 |
| 28 void SetUp() override { |
| 29 static bool initialized = false; |
| 30 if (!initialized) { |
| 31 initialized = true; |
| 32 cronet::CronetEnvironment::Initialize(); |
| 33 cronet::StartQuicTestServer(); |
| 34 } |
| 35 |
| 36 cronet_environment_ = new cronet::CronetEnvironment("CronetTest/1.0.0.0"); |
| 37 cronet_environment_->set_http2_enabled(true); |
| 38 cronet_environment_->set_quic_enabled(true); |
| 39 cronet_environment_->set_ssl_key_log_file_name("SSLKEYLOGFILE"); |
| 40 |
| 41 scoped_ptr<net::MockCertVerifier> mock_cert_verifier( |
| 42 new net::MockCertVerifier()); |
| 43 mock_cert_verifier->set_default_result(net::OK); |
| 44 |
| 45 // cronet_environment_->set_cert_verifier(std::move(mock_cert_verifier)); |
| 46 cronet_environment_->set_host_resolver_rules( |
| 47 "MAP test.example.com 127.0.0.1"); |
| 48 cronet_environment_->AddQuicHint("test.example.com", 6121, 6121); |
| 49 |
| 50 cronet_environment_->Install(); |
| 51 |
| 52 cronet_engine_.obj = cronet_environment_; |
| 53 |
| 54 // logging::SetMinLogLevel(-5); |
| 55 cronet_environment_->StartNetLog("cronet_netlog.json", true); |
| 56 //[CronetEngine startNetLogToFile:@"cronet_test_netlog.json" logBytes:YES]; |
| 57 } |
| 58 |
| 59 void TearDown() override { |
| 60 // cronet::ShutdownQuicTestServer(); |
| 61 cronet_environment_->StopNetLog(); |
| 62 //[CronetEngine stopNetLog]; |
| 63 //[CronetEngine uninstall]; |
| 64 } |
| 65 |
| 66 cronet_engine* engine() { return &cronet_engine_; } |
| 67 |
| 68 private: |
| 69 static cronet::CronetEnvironment* cronet_environment_; |
| 70 static cronet_engine cronet_engine_; |
| 71 }; |
| 72 |
| 73 cronet::CronetEnvironment* CronetBidirectionalStreamTest::cronet_environment_; |
| 74 cronet_engine CronetBidirectionalStreamTest::cronet_engine_; |
| 75 |
| 76 class TestBidirectionalStreamCallback { |
| 77 public: |
| 78 enum ResponseStep { |
| 79 NOTHING, |
| 80 ON_REQUEST_HEADERS_SENT, |
| 81 ON_RESPONSE_STARTED, |
| 82 ON_READ_COMPLETED, |
| 83 ON_WRITE_COMPLETED, |
| 84 ON_TRAILERS, |
| 85 ON_CANCELED, |
| 86 ON_FAILED, |
| 87 ON_SUCCEEDED |
| 88 }; |
| 89 |
| 90 cronet_bidirectional_stream* stream; |
| 91 base::WaitableEvent stream_done_event; |
| 92 |
| 93 // Test parameters. |
| 94 std::map<std::string, std::string> request_headers; |
| 95 std::list<std::string> write_data; |
| 96 std::string expected_negotiated_protocol; |
| 97 ResponseStep cancel_from_step; |
| 98 size_t read_buffer_size; |
| 99 |
| 100 // Test results. |
| 101 ResponseStep response_step; |
| 102 char* read_buffer; |
| 103 std::map<std::string, std::string> response_headers; |
| 104 std::map<std::string, std::string> response_trailers; |
| 105 std::vector<std::string> read_data; |
| 106 |
| 107 TestBidirectionalStreamCallback() |
| 108 : stream(nullptr), |
| 109 stream_done_event(true, false), |
| 110 expected_negotiated_protocol("quic/1+spdy/3"), |
| 111 cancel_from_step(NOTHING), |
| 112 read_buffer_size(32768), |
| 113 response_step(NOTHING), |
| 114 read_buffer(nullptr) {} |
| 115 |
| 116 ~TestBidirectionalStreamCallback() { |
| 117 if (read_buffer) |
| 118 delete read_buffer; |
| 119 } |
| 120 |
| 121 static TestBidirectionalStreamCallback* FromStream( |
| 122 cronet_bidirectional_stream* stream) { |
| 123 DCHECK(stream); |
| 124 return (TestBidirectionalStreamCallback*)stream->annotation; |
| 125 } |
| 126 |
| 127 bool MaybeCancel(cronet_bidirectional_stream* stream, ResponseStep step) { |
| 128 DCHECK(stream == this->stream); |
| 129 response_step = step; |
| 130 DLOG(WARNING) << "Step: " << step; |
| 131 |
| 132 if (step != cancel_from_step) |
| 133 return false; |
| 134 |
| 135 cronet_bidirectional_stream_cancel(stream); |
| 136 return true; |
| 137 } |
| 138 |
| 139 void SignalDone() { stream_done_event.Signal(); } |
| 140 |
| 141 void BlockForDone() { stream_done_event.Wait(); } |
| 142 |
| 143 void AddWriteData(const std::string& data) { write_data.push_back(data); } |
| 144 |
| 145 void MaybeWriteNextData(cronet_bidirectional_stream* stream) { |
| 146 DCHECK(stream == this->stream); |
| 147 if (write_data.empty()) |
| 148 return; |
| 149 cronet_bidirectional_stream_write(stream, write_data.front().c_str(), |
| 150 write_data.front().size(), |
| 151 write_data.size() == 1); |
| 152 } |
| 153 |
| 154 cronet_bidirectional_stream_callback* callback() const { return &s_callback; } |
| 155 |
| 156 private: |
| 157 // C callbacks. |
| 158 static void on_request_headers_sent_callback( |
| 159 cronet_bidirectional_stream* stream) { |
| 160 TestBidirectionalStreamCallback* test = FromStream(stream); |
| 161 if (test->MaybeCancel(stream, ON_REQUEST_HEADERS_SENT)) |
| 162 return; |
| 163 test->MaybeWriteNextData(stream); |
| 164 } |
| 165 |
| 166 static void on_response_headers_received_callback( |
| 167 cronet_bidirectional_stream* stream, |
| 168 const cronet_bidirectional_stream_header_array* headers, |
| 169 const char* negotiated_protocol) { |
| 170 TestBidirectionalStreamCallback* test = FromStream(stream); |
| 171 ASSERT_EQ(test->expected_negotiated_protocol, |
| 172 std::string(negotiated_protocol)); |
| 173 for (size_t i = 0; i < headers->count; ++i) { |
| 174 test->response_headers[headers->headers[i].key] = |
| 175 headers->headers[i].value; |
| 176 } |
| 177 if (test->MaybeCancel(stream, ON_RESPONSE_STARTED)) |
| 178 return; |
| 179 test->read_buffer = new char[test->read_buffer_size]; |
| 180 cronet_bidirectional_stream_read(stream, test->read_buffer, |
| 181 test->read_buffer_size); |
| 182 } |
| 183 |
| 184 static void on_read_completed_callback(cronet_bidirectional_stream* stream, |
| 185 char* data, |
| 186 int count) { |
| 187 TestBidirectionalStreamCallback* test = FromStream(stream); |
| 188 test->read_data.push_back(std::string(data, count)); |
| 189 if (test->MaybeCancel(stream, ON_READ_COMPLETED)) |
| 190 return; |
| 191 if (count == 0) |
| 192 return; |
| 193 cronet_bidirectional_stream_read(stream, test->read_buffer, |
| 194 test->read_buffer_size); |
| 195 } |
| 196 |
| 197 static void on_write_completed_callback(cronet_bidirectional_stream* stream, |
| 198 const char* data) { |
| 199 TestBidirectionalStreamCallback* test = FromStream(stream); |
| 200 ASSERT_EQ(test->write_data.front().c_str(), data); |
| 201 if (test->MaybeCancel(stream, ON_WRITE_COMPLETED)) |
| 202 return; |
| 203 test->write_data.pop_front(); |
| 204 test->MaybeWriteNextData(stream); |
| 205 } |
| 206 |
| 207 static void on_response_trailers_received_callback( |
| 208 cronet_bidirectional_stream* stream, |
| 209 const cronet_bidirectional_stream_header_array* trailers) { |
| 210 TestBidirectionalStreamCallback* test = FromStream(stream); |
| 211 if (test->MaybeCancel(stream, ON_TRAILERS)) |
| 212 return; |
| 213 } |
| 214 |
| 215 static void on_succeded_callback(cronet_bidirectional_stream* stream) { |
| 216 TestBidirectionalStreamCallback* test = FromStream(stream); |
| 217 test->MaybeCancel(stream, ON_SUCCEEDED); |
| 218 test->SignalDone(); |
| 219 } |
| 220 |
| 221 static void on_failed_callback(cronet_bidirectional_stream* stream, |
| 222 int net_error) { |
| 223 TestBidirectionalStreamCallback* test = FromStream(stream); |
| 224 test->MaybeCancel(stream, ON_FAILED); |
| 225 test->SignalDone(); |
| 226 } |
| 227 |
| 228 static void on_canceled_callback(cronet_bidirectional_stream* stream) { |
| 229 TestBidirectionalStreamCallback* test = FromStream(stream); |
| 230 test->MaybeCancel(stream, ON_CANCELED); |
| 231 test->SignalDone(); |
| 232 } |
| 233 |
| 234 static cronet_bidirectional_stream_callback s_callback; |
| 235 }; |
| 236 |
| 237 cronet_bidirectional_stream_callback |
| 238 TestBidirectionalStreamCallback::s_callback = { |
| 239 on_request_headers_sent_callback, |
| 240 on_response_headers_received_callback, |
| 241 on_read_completed_callback, |
| 242 on_write_completed_callback, |
| 243 on_response_trailers_received_callback, |
| 244 on_succeded_callback, |
| 245 on_failed_callback, |
| 246 on_canceled_callback}; |
| 247 |
| 248 TEST_F(CronetBidirectionalStreamTest, StartExampleBidiStream) { |
| 249 TestBidirectionalStreamCallback test; |
| 250 test.AddWriteData("Hello, "); |
| 251 test.AddWriteData("world!"); |
| 252 test.read_buffer_size = 2; |
| 253 test.stream = |
| 254 cronet_bidirectional_stream_create(engine(), &test, test.callback()); |
| 255 DCHECK(test.stream); |
| 256 cronet_bidirectional_stream_header headers[] = { |
| 257 {"header1", "foo"}, {"header2", "bar"}, |
| 258 }; |
| 259 cronet_bidirectional_stream_header_array headers_array = {2, 2, headers}; |
| 260 cronet_bidirectional_stream_start(test.stream, |
| 261 "https://test.example.com:6121", 0, "POST", |
| 262 &headers_array, false); |
| 263 test.BlockForDone(); |
| 264 ASSERT_EQ(std::string("404"), test.response_headers[":status"]); |
| 265 ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step); |
| 266 ASSERT_EQ(std::string("fi"), test.read_data.front()); |
| 267 ASSERT_EQ(std::string("file not found"), |
| 268 base::JoinString(test.read_data, "")); |
| 269 cronet_bidirectional_stream_destroy(test.stream); |
| 270 } |
| 271 |
| 272 TEST_F(CronetBidirectionalStreamTest, CancelOnRead) { |
| 273 TestBidirectionalStreamCallback test; |
| 274 test.stream = |
| 275 cronet_bidirectional_stream_create(engine(), &test, test.callback()); |
| 276 DCHECK(test.stream); |
| 277 test.cancel_from_step = TestBidirectionalStreamCallback::ON_READ_COMPLETED; |
| 278 cronet_bidirectional_stream_header headers[] = { |
| 279 {"header1", "foo"}, {"header2", "bar"}, |
| 280 }; |
| 281 cronet_bidirectional_stream_header_array headers_array = {2, 2, headers}; |
| 282 cronet_bidirectional_stream_start(test.stream, |
| 283 "https://test.example.com:6121", 0, "POST", |
| 284 &headers_array, true); |
| 285 test.BlockForDone(); |
| 286 ASSERT_EQ(std::string("404"), test.response_headers[":status"]); |
| 287 ASSERT_EQ(std::string("file not found"), test.read_data.front()); |
| 288 ASSERT_EQ(TestBidirectionalStreamCallback::ON_CANCELED, test.response_step); |
| 289 cronet_bidirectional_stream_destroy(test.stream); |
| 290 } |
| 291 |
| 292 TEST_F(CronetBidirectionalStreamTest, CancelOnResponse) { |
| 293 TestBidirectionalStreamCallback test; |
| 294 test.stream = |
| 295 cronet_bidirectional_stream_create(engine(), &test, test.callback()); |
| 296 DCHECK(test.stream); |
| 297 test.cancel_from_step = TestBidirectionalStreamCallback::ON_RESPONSE_STARTED; |
| 298 cronet_bidirectional_stream_header headers[] = { |
| 299 {"header1", "foo"}, {"header2", "bar"}, |
| 300 }; |
| 301 cronet_bidirectional_stream_header_array headers_array = {2, 2, headers}; |
| 302 cronet_bidirectional_stream_start(test.stream, |
| 303 "https://test.example.com:6121", 0, "POST", |
| 304 &headers_array, true); |
| 305 test.BlockForDone(); |
| 306 ASSERT_EQ(std::string("404"), test.response_headers[":status"]); |
| 307 ASSERT_TRUE(test.read_data.empty()); |
| 308 ASSERT_EQ(TestBidirectionalStreamCallback::ON_CANCELED, test.response_step); |
| 309 cronet_bidirectional_stream_destroy(test.stream); |
| 310 } |
| 311 |
| 312 TEST_F(CronetBidirectionalStreamTest, GoogleIt) { |
| 313 TestBidirectionalStreamCallback test; |
| 314 test.stream = |
| 315 cronet_bidirectional_stream_create(engine(), &test, test.callback()); |
| 316 DCHECK(test.stream); |
| 317 test.cancel_from_step = TestBidirectionalStreamCallback::ON_READ_COMPLETED; |
| 318 test.expected_negotiated_protocol = "h2"; |
| 319 cronet_bidirectional_stream_header headers[] = { |
| 320 {"header1", "foo"}, {"header2", "bar"}, |
| 321 }; |
| 322 cronet_bidirectional_stream_header_array headers_array = {2, 2, headers}; |
| 323 cronet_bidirectional_stream_start(test.stream, "https://www.google.com", 0, |
| 324 "GET", &headers_array, true); |
| 325 test.BlockForDone(); |
| 326 ASSERT_EQ(std::string("200"), test.response_headers[":status"]); |
| 327 ASSERT_EQ(TestBidirectionalStreamCallback::ON_CANCELED, test.response_step); |
| 328 cronet_bidirectional_stream_destroy(test.stream); |
| 329 } |
| OLD | NEW |