Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / tools / flip_server / spdy_interface_test.cc
blob8a9cb2adc4890299579abe757a2fac75093e873e
1 // Copyright 2013 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.
5 #include "net/tools/flip_server/spdy_interface.h"
7 #include <list>
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string_piece.h"
11 #include "net/spdy/buffered_spdy_framer.h"
12 #include "net/tools/balsa/balsa_enums.h"
13 #include "net/tools/balsa/balsa_headers.h"
14 #include "net/tools/flip_server/flip_config.h"
15 #include "net/tools/flip_server/flip_test_utils.h"
16 #include "net/tools/flip_server/mem_cache.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 namespace net {
22 using ::base::StringPiece;
23 using ::testing::_;
24 using ::testing::InSequence;
25 using ::testing::InvokeWithoutArgs;
26 using ::testing::Return;
27 using ::testing::SaveArg;
28 using ::testing::Values;
30 namespace {
32 struct StringSaver {
33 public:
34 StringSaver() : data(NULL), size(0) {}
35 void Save() { string = std::string(data, size); }
37 const char* data;
38 size_t size;
39 std::string string;
42 class SpdyFramerVisitor : public BufferedSpdyFramerVisitorInterface {
43 public:
44 virtual ~SpdyFramerVisitor() {}
45 MOCK_METHOD1(OnError, void(SpdyFramer::SpdyError));
46 MOCK_METHOD2(OnStreamError, void(SpdyStreamId, const std::string&));
47 MOCK_METHOD6(OnSynStream,
48 void(SpdyStreamId,
49 SpdyStreamId,
50 SpdyPriority,
51 bool,
52 bool,
53 const SpdyHeaderBlock&));
54 MOCK_METHOD3(OnSynReply, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
55 MOCK_METHOD7(OnHeaders,
56 void(SpdyStreamId stream_id,
57 bool has_priority,
58 SpdyPriority priority,
59 SpdyStreamId parent_stream_id,
60 bool exclusive,
61 bool fin,
62 const SpdyHeaderBlock& headers));
63 MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId, size_t, bool));
64 MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId,
65 const char*,
66 size_t,
67 bool));
68 MOCK_METHOD2(OnStreamPadding, void(SpdyStreamId, size_t));
69 MOCK_METHOD1(OnSettings, void(bool clear_persisted));
70 MOCK_METHOD3(OnSetting, void(SpdySettingsIds, uint8, uint32));
71 MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
72 MOCK_METHOD2(OnRstStream, void(SpdyStreamId, SpdyRstStreamStatus));
73 MOCK_METHOD2(OnGoAway, void(SpdyStreamId, SpdyGoAwayStatus));
74 MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId, int));
75 MOCK_METHOD3(OnPushPromise,
76 void(SpdyStreamId, SpdyStreamId, const SpdyHeaderBlock&));
77 MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type));
80 class FakeSMConnection : public SMConnection {
81 public:
82 FakeSMConnection(EpollServer* epoll_server,
83 SSLState* ssl_state,
84 MemoryCache* memory_cache,
85 FlipAcceptor* acceptor,
86 std::string log_prefix)
87 : SMConnection(epoll_server,
88 ssl_state,
89 memory_cache,
90 acceptor,
91 log_prefix) {}
93 MOCK_METHOD0(Cleanup, void());
94 MOCK_METHOD8(InitSMConnection,
95 void(SMConnectionPoolInterface*,
96 SMInterface*,
97 EpollServer*,
98 int,
99 std::string,
100 std::string,
101 std::string,
102 bool));
105 // This class is almost SpdySM, except one function.
106 // This class is the test target of tests in this file.
107 class TestSpdySM : public SpdySM {
108 public:
109 virtual ~TestSpdySM() {}
110 TestSpdySM(SMConnection* connection,
111 SMInterface* sm_http_interface,
112 EpollServer* epoll_server,
113 MemoryCache* memory_cache,
114 FlipAcceptor* acceptor,
115 SpdyMajorVersion version)
116 : SpdySM(connection,
117 sm_http_interface,
118 epoll_server,
119 memory_cache,
120 acceptor,
121 version) {}
123 MOCK_METHOD2(FindOrMakeNewSMConnectionInterface,
124 SMInterface*(const std::string&, const std::string&));
127 class SpdySMTestBase : public ::testing::TestWithParam<SpdyMajorVersion> {
128 public:
129 explicit SpdySMTestBase(FlipHandlerType type) {
130 SSLState* ssl_state = NULL;
131 mock_another_interface_.reset(new MockSMInterface);
132 memory_cache_.reset(new MemoryCache);
133 acceptor_.reset(new FlipAcceptor(type,
134 "127.0.0.1",
135 "8941",
136 "ssl_cert_filename",
137 "ssl_key_filename",
138 "127.0.0.1",
139 "8942",
140 "127.0.0.1",
141 "8943",
144 true,
146 false,
147 true,
148 NULL));
149 epoll_server_.reset(new EpollServer);
150 connection_.reset(new FakeSMConnection(epoll_server_.get(),
151 ssl_state,
152 memory_cache_.get(),
153 acceptor_.get(),
154 "log_prefix"));
156 interface_.reset(new TestSpdySM(connection_.get(),
157 mock_another_interface_.get(),
158 epoll_server_.get(),
159 memory_cache_.get(),
160 acceptor_.get(),
161 GetParam()));
163 spdy_framer_.reset(new BufferedSpdyFramer(GetParam(), true));
164 spdy_framer_visitor_.reset(new SpdyFramerVisitor);
165 spdy_framer_->set_visitor(spdy_framer_visitor_.get());
168 virtual ~SpdySMTestBase() {
169 if (acceptor_->listen_fd_ >= 0) {
170 epoll_server_->UnregisterFD(acceptor_->listen_fd_);
171 close(acceptor_->listen_fd_);
172 acceptor_->listen_fd_ = -1;
174 OutputList& output_list = *connection_->output_list();
175 for (OutputList::const_iterator i = output_list.begin();
176 i != output_list.end();
177 ++i) {
178 delete *i;
180 output_list.clear();
183 bool HasStream(uint32 stream_id) {
184 return interface_->output_ordering().ExistsInPriorityMaps(stream_id);
187 protected:
188 scoped_ptr<MockSMInterface> mock_another_interface_;
189 scoped_ptr<MemoryCache> memory_cache_;
190 scoped_ptr<FlipAcceptor> acceptor_;
191 scoped_ptr<EpollServer> epoll_server_;
192 scoped_ptr<FakeSMConnection> connection_;
193 scoped_ptr<TestSpdySM> interface_;
194 scoped_ptr<BufferedSpdyFramer> spdy_framer_;
195 scoped_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
198 class SpdySMProxyTest : public SpdySMTestBase {
199 public:
200 SpdySMProxyTest() : SpdySMTestBase(FLIP_HANDLER_PROXY) {}
201 virtual ~SpdySMProxyTest() {}
204 class SpdySMServerTest : public SpdySMTestBase {
205 public:
206 SpdySMServerTest() : SpdySMTestBase(FLIP_HANDLER_SPDY_SERVER) {}
207 virtual ~SpdySMServerTest() {}
210 INSTANTIATE_TEST_CASE_P(SpdySMProxyTest, SpdySMProxyTest, Values(SPDY3, HTTP2));
211 INSTANTIATE_TEST_CASE_P(SpdySMServerTest, SpdySMServerTest, Values(HTTP2));
213 TEST_P(SpdySMProxyTest, InitSMConnection) {
215 InSequence s;
216 EXPECT_CALL(*connection_, InitSMConnection(_, _, _, _, _, _, _, _));
218 interface_->InitSMConnection(
219 NULL, NULL, epoll_server_.get(), -1, "", "", "", false);
222 TEST_P(SpdySMProxyTest, OnStreamFrameData) {
223 BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
224 scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
225 uint32 stream_id = 92;
226 uint32 associated_id = 43;
227 SpdyHeaderBlock block;
228 testing::MockFunction<void(int)> checkpoint; // NOLINT
230 scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12, false));
231 block[":method"] = "GET";
232 block[":host"] = "www.example.com";
233 block[":path"] = "/path";
234 block[":scheme"] = "http";
235 block["foo"] = "bar";
237 InSequence s;
238 EXPECT_CALL(*interface_,
239 FindOrMakeNewSMConnectionInterface(_, _))
240 .WillOnce(Return(mock_interface.get()));
241 EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
242 EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _)).Times(1);
243 EXPECT_CALL(checkpoint, Call(0));
244 EXPECT_CALL(*mock_interface,
245 ProcessWriteInput(frame->data(), frame->size())).Times(1);
248 visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
249 checkpoint.Call(0);
250 visitor->OnStreamFrameData(stream_id, frame->data(), frame->size(), true);
253 TEST_P(SpdySMProxyTest, OnRstStream) {
254 BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
255 uint32 stream_id = 82;
256 MemCacheIter mci;
257 mci.stream_id = stream_id;
260 BalsaHeaders headers;
261 std::string filename = "foobar";
262 memory_cache_->InsertFile(&headers, filename, "");
263 mci.file_data = memory_cache_->GetFileData(filename);
266 interface_->AddToOutputOrder(mci);
267 ASSERT_TRUE(HasStream(stream_id));
268 visitor->OnRstStream(stream_id, RST_STREAM_INVALID);
269 ASSERT_FALSE(HasStream(stream_id));
272 TEST_P(SpdySMProxyTest, ProcessReadInput) {
273 ASSERT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME,
274 interface_->spdy_framer()->state());
275 interface_->ProcessReadInput("", 1);
276 ASSERT_EQ(SpdyFramer::SPDY_READING_COMMON_HEADER,
277 interface_->spdy_framer()->state());
280 TEST_P(SpdySMProxyTest, ResetForNewConnection) {
281 uint32 stream_id = 13;
282 MemCacheIter mci;
283 mci.stream_id = stream_id;
284 // incomplete input
285 const char input[] = {'\0', '\0', '\0'};
288 BalsaHeaders headers;
289 std::string filename = "foobar";
290 memory_cache_->InsertFile(&headers, filename, "");
291 mci.file_data = memory_cache_->GetFileData(filename);
294 interface_->AddToOutputOrder(mci);
295 ASSERT_TRUE(HasStream(stream_id));
296 interface_->ProcessReadInput(input, sizeof(input));
297 ASSERT_NE(SpdyFramer::SPDY_READY_FOR_FRAME,
298 interface_->spdy_framer()->state());
300 interface_->ResetForNewConnection();
301 ASSERT_FALSE(HasStream(stream_id));
302 ASSERT_TRUE(interface_->spdy_framer() == NULL);
305 TEST_P(SpdySMProxyTest, CreateFramer) {
306 interface_->ResetForNewConnection();
307 interface_->CreateFramer(SPDY3);
308 ASSERT_TRUE(interface_->spdy_framer() != NULL);
309 ASSERT_EQ(interface_->spdy_version(), SPDY3);
311 interface_->ResetForNewConnection();
312 interface_->CreateFramer(HTTP2);
313 ASSERT_TRUE(interface_->spdy_framer() != NULL);
314 ASSERT_EQ(interface_->spdy_version(), HTTP2);
317 TEST_P(SpdySMProxyTest, PostAcceptHook) {
318 interface_->PostAcceptHook();
320 ASSERT_EQ(1u, connection_->output_list()->size());
321 std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
322 DataFrame* df = *i++;
325 InSequence s;
326 EXPECT_CALL(*spdy_framer_visitor_, OnSettings(false));
327 EXPECT_CALL(*spdy_framer_visitor_,
328 OnSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 0u, 100u));
330 spdy_framer_->ProcessInput(df->data, df->size);
333 TEST_P(SpdySMProxyTest, NewStream) {
334 // TODO(yhirano): SpdySM::NewStream leads to crash when
335 // acceptor_->flip_handler_type_ != FLIP_HANDLER_SPDY_SERVER.
336 // It should be fixed though I don't know the solution now.
339 TEST_P(SpdySMProxyTest, AddToOutputOrder) {
340 uint32 stream_id = 13;
341 MemCacheIter mci;
342 mci.stream_id = stream_id;
345 BalsaHeaders headers;
346 std::string filename = "foobar";
347 memory_cache_->InsertFile(&headers, filename, "");
348 mci.file_data = memory_cache_->GetFileData(filename);
351 interface_->AddToOutputOrder(mci);
352 ASSERT_TRUE(HasStream(stream_id));
355 TEST_P(SpdySMProxyTest, SendErrorNotFound) {
356 uint32 stream_id = 82;
357 SpdyHeaderBlock actual_header_block;
358 const char* actual_data;
359 size_t actual_size;
360 testing::MockFunction<void(int)> checkpoint; // NOLINT
362 interface_->SendErrorNotFound(stream_id);
364 ASSERT_EQ(2u, connection_->output_list()->size());
367 InSequence s;
368 if (GetParam() < HTTP2) {
369 EXPECT_CALL(*spdy_framer_visitor_,
370 OnSynReply(stream_id, false, _))
371 .WillOnce(SaveArg<2>(&actual_header_block));
372 } else {
373 EXPECT_CALL(*spdy_framer_visitor_,
374 OnHeaders(stream_id, /*has_priority=*/false, _, _, _,
375 /*fin=*/false, _))
376 .WillOnce(SaveArg<6>(&actual_header_block));
378 EXPECT_CALL(checkpoint, Call(0));
379 EXPECT_CALL(*spdy_framer_visitor_,
380 OnDataFrameHeader(stream_id, _, true));
381 EXPECT_CALL(*spdy_framer_visitor_,
382 OnStreamFrameData(stream_id, _, _, false)).Times(1)
383 .WillOnce(DoAll(SaveArg<1>(&actual_data),
384 SaveArg<2>(&actual_size)));
385 EXPECT_CALL(*spdy_framer_visitor_,
386 OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
389 std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
390 DataFrame* df = *i++;
391 spdy_framer_->ProcessInput(df->data, df->size);
392 checkpoint.Call(0);
393 df = *i++;
394 spdy_framer_->ProcessInput(df->data, df->size);
396 ASSERT_EQ(2, spdy_framer_->frames_received());
397 ASSERT_EQ(2u, actual_header_block.size());
398 ASSERT_EQ("404 Not Found", actual_header_block[":status"]);
399 ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
400 ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
403 TEST_P(SpdySMProxyTest, SendSynStream) {
404 uint32 stream_id = 82;
405 BalsaHeaders headers;
406 SpdyHeaderBlock actual_header_block;
407 headers.AppendHeader("key1", "value1");
408 headers.AppendHeader("Host", "www.example.com");
409 headers.SetRequestFirstlineFromStringPieces("GET", "/path", "HTTP/1.1");
411 interface_->SendSynStream(stream_id, headers);
413 ASSERT_EQ(1u, connection_->output_list()->size());
414 std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
415 DataFrame* df = *i++;
418 InSequence s;
419 EXPECT_CALL(*spdy_framer_visitor_,
420 OnSynStream(stream_id, 0, _, false, false, _))
421 .WillOnce(SaveArg<5>(&actual_header_block));
424 spdy_framer_->ProcessInput(df->data, df->size);
425 ASSERT_EQ(1, spdy_framer_->frames_received());
426 ASSERT_EQ(5u, actual_header_block.size());
427 ASSERT_EQ("GET", actual_header_block[":method"]);
428 ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
429 ASSERT_EQ("/path", actual_header_block[":path"]);
430 ASSERT_EQ("www.example.com", actual_header_block[":host"]);
431 ASSERT_EQ("value1", actual_header_block["key1"]);
434 TEST_P(SpdySMProxyTest, SendSynReply) {
435 uint32 stream_id = 82;
436 BalsaHeaders headers;
437 SpdyHeaderBlock actual_header_block;
438 headers.AppendHeader("key1", "value1");
439 headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
441 interface_->SendSynReply(stream_id, headers);
443 ASSERT_EQ(1u, connection_->output_list()->size());
444 std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
445 DataFrame* df = *i++;
448 InSequence s;
449 if (GetParam() < HTTP2) {
450 EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
451 .WillOnce(SaveArg<2>(&actual_header_block));
452 } else {
453 EXPECT_CALL(*spdy_framer_visitor_,
454 OnHeaders(stream_id, /*has_priority=*/false, _, _, _,
455 /*fin=*/false, _))
456 .WillOnce(SaveArg<6>(&actual_header_block));
460 spdy_framer_->ProcessInput(df->data, df->size);
461 ASSERT_EQ(1, spdy_framer_->frames_received());
462 ASSERT_EQ(3u, actual_header_block.size());
463 ASSERT_EQ("200 OK", actual_header_block[":status"]);
464 ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
465 ASSERT_EQ("value1", actual_header_block["key1"]);
468 TEST_P(SpdySMProxyTest, SendDataFrame) {
469 uint32 stream_id = 133;
470 SpdyDataFlags flags = DATA_FLAG_NONE;
471 const char* actual_data;
472 size_t actual_size;
474 interface_->SendDataFrame(stream_id, "hello", 5, flags, true);
476 ASSERT_EQ(1u, connection_->output_list()->size());
477 std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
478 DataFrame* df = *i++;
481 InSequence s;
482 EXPECT_CALL(*spdy_framer_visitor_,
483 OnDataFrameHeader(stream_id, _, false));
484 EXPECT_CALL(*spdy_framer_visitor_,
485 OnStreamFrameData(stream_id, _, _, false))
486 .WillOnce(DoAll(SaveArg<1>(&actual_data), SaveArg<2>(&actual_size)));
489 spdy_framer_->ProcessInput(df->data, df->size);
490 ASSERT_EQ(1, spdy_framer_->frames_received());
491 ASSERT_EQ("hello", StringPiece(actual_data, actual_size));
494 TEST_P(SpdySMProxyTest, SendLongDataFrame) {
495 uint32 stream_id = 133;
496 SpdyDataFlags flags = DATA_FLAG_NONE;
497 const char* actual_data;
498 size_t actual_size;
500 std::string data = std::string(kSpdySegmentSize, 'a') +
501 std::string(kSpdySegmentSize, 'b') + "c";
502 interface_->SendDataFrame(stream_id, data.data(), data.size(), flags, true);
505 InSequence s;
506 for (int i = 0; i < 3; ++i) {
507 EXPECT_CALL(*spdy_framer_visitor_,
508 OnDataFrameHeader(stream_id, _, false));
509 EXPECT_CALL(*spdy_framer_visitor_,
510 OnStreamFrameData(stream_id, _, _, false))
511 .WillOnce(DoAll(SaveArg<1>(&actual_data),
512 SaveArg<2>(&actual_size)));
516 ASSERT_EQ(3u, connection_->output_list()->size());
517 std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
518 DataFrame* df = *i++;
519 spdy_framer_->ProcessInput(df->data, df->size);
520 ASSERT_EQ(std::string(kSpdySegmentSize, 'a'),
521 StringPiece(actual_data, actual_size));
523 df = *i++;
524 spdy_framer_->ProcessInput(df->data, df->size);
525 ASSERT_EQ(std::string(kSpdySegmentSize, 'b'),
526 StringPiece(actual_data, actual_size));
528 df = *i++;
529 spdy_framer_->ProcessInput(df->data, df->size);
530 ASSERT_EQ("c", StringPiece(actual_data, actual_size));
533 TEST_P(SpdySMServerTest, OnSynStream) {
534 BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
535 uint32 stream_id = 82;
536 SpdyHeaderBlock spdy_headers;
537 spdy_headers["url"] = "http://www.example.com/path";
538 spdy_headers["method"] = "GET";
539 spdy_headers["scheme"] = "http";
540 spdy_headers["version"] = "HTTP/1.1";
543 BalsaHeaders headers;
544 memory_cache_->InsertFile(&headers, "GET_/path", "");
546 visitor->OnSynStream(stream_id, 0, 0, true, true, spdy_headers);
547 ASSERT_TRUE(HasStream(stream_id));
550 TEST_P(SpdySMServerTest, NewStream) {
551 uint32 stream_id = 13;
552 std::string filename = "foobar";
555 BalsaHeaders headers;
556 memory_cache_->InsertFile(&headers, filename, "");
559 interface_->NewStream(stream_id, 0, filename);
560 ASSERT_TRUE(HasStream(stream_id));
563 TEST_P(SpdySMServerTest, NewStreamError) {
564 uint32 stream_id = 82;
565 SpdyHeaderBlock actual_header_block;
566 const char* actual_data;
567 size_t actual_size;
568 testing::MockFunction<void(int)> checkpoint; // NOLINT
570 interface_->NewStream(stream_id, 0, "nonexistingfile");
572 ASSERT_EQ(2u, connection_->output_list()->size());
575 InSequence s;
576 if (GetParam() < HTTP2) {
577 EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
578 .WillOnce(SaveArg<2>(&actual_header_block));
579 } else {
580 EXPECT_CALL(*spdy_framer_visitor_,
581 OnHeaders(stream_id, /*has_priority=*/false, _, _, _,
582 /*fin=*/false, _))
583 .WillOnce(SaveArg<6>(&actual_header_block));
585 EXPECT_CALL(checkpoint, Call(0));
586 EXPECT_CALL(*spdy_framer_visitor_,
587 OnDataFrameHeader(stream_id, _, true));
588 EXPECT_CALL(*spdy_framer_visitor_,
589 OnStreamFrameData(stream_id, _, _, false)).Times(1)
590 .WillOnce(DoAll(SaveArg<1>(&actual_data),
591 SaveArg<2>(&actual_size)));
592 EXPECT_CALL(*spdy_framer_visitor_,
593 OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
596 std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
597 DataFrame* df = *i++;
598 spdy_framer_->ProcessInput(df->data, df->size);
599 checkpoint.Call(0);
600 df = *i++;
601 spdy_framer_->ProcessInput(df->data, df->size);
603 ASSERT_EQ(2, spdy_framer_->frames_received());
604 ASSERT_EQ(2u, actual_header_block.size());
605 ASSERT_EQ("404 Not Found", actual_header_block["status"]);
606 ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
607 ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
610 } // namespace
612 } // namespace net