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