Chromium Code Reviews| 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; | |
|
xunjieli
2016/04/08 17:46:15
Why is this a static bool?
mef
2016/04/08 20:40:43
It's a kludge because I'm having troubles with Set
| |
| 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 |