3b98852015801139871be54c7b7ad765cebb7d62
[platform/framework/web/crosswalk.git] / src / net / tools / flip_server / spdy_interface_test.cc
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.
4
5 #include "net/tools/flip_server/spdy_interface.h"
6
7 #include <list>
8
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"
19
20 namespace net {
21
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;
29
30 namespace {
31
32 struct StringSaver {
33  public:
34   StringSaver() : data(NULL), size(0) {}
35   void Save() { string = std::string(data, size); }
36
37   const char* data;
38   size_t size;
39   std::string string;
40 };
41
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_METHOD7(OnSynStream,
48                void(SpdyStreamId,
49                     SpdyStreamId,
50                     SpdyPriority,
51                     uint8,
52                     bool,
53                     bool,
54                     const SpdyHeaderBlock&));
55   MOCK_METHOD3(OnSynStream, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
56   MOCK_METHOD3(OnSynReply, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
57   MOCK_METHOD3(OnHeaders, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
58   MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId, size_t, bool));
59   MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId,
60                                        const char*,
61                                        size_t,
62                                        bool));
63   MOCK_METHOD1(OnSettings, void(bool clear_persisted));
64   MOCK_METHOD3(OnSetting, void(SpdySettingsIds, uint8, uint32));
65   MOCK_METHOD1(OnPing, void(uint32 unique_id));
66   MOCK_METHOD2(OnRstStream, void(SpdyStreamId, SpdyRstStreamStatus));
67   MOCK_METHOD2(OnGoAway, void(SpdyStreamId, SpdyGoAwayStatus));
68   MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId, uint32));
69   MOCK_METHOD2(OnPushPromise, void(SpdyStreamId, SpdyStreamId));
70 };
71
72 class FakeSMConnection : public SMConnection {
73  public:
74   FakeSMConnection(EpollServer* epoll_server,
75                    SSLState* ssl_state,
76                    MemoryCache* memory_cache,
77                    FlipAcceptor* acceptor,
78                    std::string log_prefix)
79       : SMConnection(epoll_server,
80                      ssl_state,
81                      memory_cache,
82                      acceptor,
83                      log_prefix) {}
84
85   MOCK_METHOD0(Cleanup, void());
86   MOCK_METHOD8(InitSMConnection,
87                void(SMConnectionPoolInterface*,
88                     SMInterface*,
89                     EpollServer*,
90                     int,
91                     std::string,
92                     std::string,
93                     std::string,
94                     bool));
95 };
96
97 // This class is almost SpdySM, except one function.
98 // This class is the test target of tests in this file.
99 class TestSpdySM : public SpdySM {
100  public:
101   virtual ~TestSpdySM() {}
102   TestSpdySM(SMConnection* connection,
103              SMInterface* sm_http_interface,
104              EpollServer* epoll_server,
105              MemoryCache* memory_cache,
106              FlipAcceptor* acceptor,
107              SpdyMajorVersion version)
108       : SpdySM(connection,
109                sm_http_interface,
110                epoll_server,
111                memory_cache,
112                acceptor,
113                version) {}
114
115   MOCK_METHOD2(FindOrMakeNewSMConnectionInterface,
116                SMInterface*(const std::string&, const std::string&));
117 };
118
119 class SpdySMTestBase : public ::testing::TestWithParam<SpdyMajorVersion> {
120  public:
121   explicit SpdySMTestBase(FlipHandlerType type) {
122     SSLState* ssl_state = NULL;
123     mock_another_interface_.reset(new MockSMInterface);
124     memory_cache_.reset(new MemoryCache);
125     acceptor_.reset(new FlipAcceptor(type,
126                                      "127.0.0.1",
127                                      "8941",
128                                      "ssl_cert_filename",
129                                      "ssl_key_filename",
130                                      "127.0.0.1",
131                                      "8942",
132                                      "127.0.0.1",
133                                      "8943",
134                                      1,
135                                      0,
136                                      true,
137                                      1,
138                                      false,
139                                      true,
140                                      NULL));
141     epoll_server_.reset(new EpollServer);
142     connection_.reset(new FakeSMConnection(epoll_server_.get(),
143                                            ssl_state,
144                                            memory_cache_.get(),
145                                            acceptor_.get(),
146                                            "log_prefix"));
147
148     interface_.reset(new TestSpdySM(connection_.get(),
149                                     mock_another_interface_.get(),
150                                     epoll_server_.get(),
151                                     memory_cache_.get(),
152                                     acceptor_.get(),
153                                     GetParam()));
154
155     spdy_framer_.reset(new BufferedSpdyFramer(GetParam(), true));
156     spdy_framer_visitor_.reset(new SpdyFramerVisitor);
157     spdy_framer_->set_visitor(spdy_framer_visitor_.get());
158   }
159
160   virtual ~SpdySMTestBase() {
161     if (acceptor_->listen_fd_ >= 0) {
162       epoll_server_->UnregisterFD(acceptor_->listen_fd_);
163       close(acceptor_->listen_fd_);
164       acceptor_->listen_fd_ = -1;
165     }
166     OutputList& output_list = *connection_->output_list();
167     for (OutputList::const_iterator i = output_list.begin();
168          i != output_list.end();
169          ++i) {
170       delete *i;
171     }
172     output_list.clear();
173   }
174
175   bool HasStream(uint32 stream_id) {
176     return interface_->output_ordering().ExistsInPriorityMaps(stream_id);
177   }
178
179  protected:
180   scoped_ptr<MockSMInterface> mock_another_interface_;
181   scoped_ptr<MemoryCache> memory_cache_;
182   scoped_ptr<FlipAcceptor> acceptor_;
183   scoped_ptr<EpollServer> epoll_server_;
184   scoped_ptr<FakeSMConnection> connection_;
185   scoped_ptr<TestSpdySM> interface_;
186   scoped_ptr<BufferedSpdyFramer> spdy_framer_;
187   scoped_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
188 };
189
190 class SpdySMProxyTest : public SpdySMTestBase {
191  public:
192   SpdySMProxyTest() : SpdySMTestBase(FLIP_HANDLER_PROXY) {}
193   virtual ~SpdySMProxyTest() {}
194 };
195
196 class SpdySMServerTest : public SpdySMTestBase {
197  public:
198   SpdySMServerTest() : SpdySMTestBase(FLIP_HANDLER_SPDY_SERVER) {}
199   virtual ~SpdySMServerTest() {}
200 };
201
202 INSTANTIATE_TEST_CASE_P(SpdySMProxyTest,
203                         SpdySMProxyTest,
204                         Values(SPDY2, SPDY3, SPDY4));
205 INSTANTIATE_TEST_CASE_P(SpdySMServerTest, SpdySMServerTest, Values(SPDY2));
206
207 TEST_P(SpdySMProxyTest, InitSMConnection) {
208   {
209     InSequence s;
210     EXPECT_CALL(*connection_, InitSMConnection(_, _, _, _, _, _, _, _));
211   }
212   interface_->InitSMConnection(
213       NULL, NULL, epoll_server_.get(), -1, "", "", "", false);
214 }
215
216 TEST_P(SpdySMProxyTest, OnSynStream_SPDY2) {
217   if (GetParam() != SPDY2) {
218     // This test case is for SPDY2.
219     return;
220   }
221   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
222   scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
223   uint32 stream_id = 92;
224   uint32 associated_id = 43;
225   std::string expected = "GET /path HTTP/1.0\r\n"
226       "Host: 127.0.0.1\r\n"
227       "hoge: fuga\r\n\r\n";
228   SpdyHeaderBlock block;
229   block["method"] = "GET";
230   block["url"] = "/path";
231   block["scheme"] = "http";
232   block["version"] = "HTTP/1.0";
233   block["hoge"] = "fuga";
234   StringSaver saver;
235   {
236     InSequence s;
237     EXPECT_CALL(*interface_, FindOrMakeNewSMConnectionInterface(_, _))
238         .WillOnce(Return(mock_interface.get()));
239     EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
240     EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _))
241         .WillOnce(DoAll(SaveArg<0>(&saver.data),
242                         SaveArg<1>(&saver.size),
243                         InvokeWithoutArgs(&saver, &StringSaver::Save),
244                         Return(0)));
245   }
246   visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
247   ASSERT_EQ(expected, saver.string);
248 }
249
250 TEST_P(SpdySMProxyTest, OnSynStream) {
251   if (GetParam() == SPDY2) {
252     // This test case is not for SPDY2.
253     return;
254   }
255   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
256   scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
257   uint32 stream_id = 92;
258   uint32 associated_id = 43;
259   std::string expected = "GET /path HTTP/1.1\r\n"
260       "Host: 127.0.0.1\r\n"
261       "foo: bar\r\n\r\n";
262   SpdyHeaderBlock block;
263   block[":method"] = "GET";
264   block[":host"] = "www.example.com";
265   block[":path"] = "/path";
266   block[":scheme"] = "http";
267   block["foo"] = "bar";
268   StringSaver saver;
269   {
270     InSequence s;
271     EXPECT_CALL(*interface_,
272                 FindOrMakeNewSMConnectionInterface(_, _))
273         .WillOnce(Return(mock_interface.get()));
274     EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
275     EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _))
276         .WillOnce(DoAll(SaveArg<0>(&saver.data),
277                         SaveArg<1>(&saver.size),
278                         InvokeWithoutArgs(&saver, &StringSaver::Save),
279                         Return(0)));
280   }
281   visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
282   ASSERT_EQ(expected, saver.string);
283 }
284
285 TEST_P(SpdySMProxyTest, OnStreamFrameData_SPDY2) {
286   if (GetParam() != SPDY2) {
287     // This test case is for SPDY2.
288     return;
289   }
290   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
291   scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
292   uint32 stream_id = 92;
293   uint32 associated_id = 43;
294   SpdyHeaderBlock block;
295   testing::MockFunction<void(int)> checkpoint;  // NOLINT
296
297   scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12));
298   block["method"] = "GET";
299   block["url"] = "http://www.example.com/path";
300   block["scheme"] = "http";
301   block["version"] = "HTTP/1.0";
302   {
303     InSequence s;
304     EXPECT_CALL(*interface_, FindOrMakeNewSMConnectionInterface(_, _))
305         .WillOnce(Return(mock_interface.get()));
306     EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
307     EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _)).Times(1);
308     EXPECT_CALL(checkpoint, Call(0));
309     EXPECT_CALL(*mock_interface,
310                 ProcessWriteInput(frame->data(), frame->size())).Times(1);
311   }
312
313   visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
314   checkpoint.Call(0);
315   visitor->OnStreamFrameData(stream_id, frame->data(), frame->size(), true);
316 }
317
318 TEST_P(SpdySMProxyTest, OnStreamFrameData) {
319   if (GetParam() == SPDY2) {
320     // This test case is not for SPDY2.
321     return;
322   }
323   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
324   scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
325   uint32 stream_id = 92;
326   uint32 associated_id = 43;
327   SpdyHeaderBlock block;
328   testing::MockFunction<void(int)> checkpoint;  // NOLINT
329
330   scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12));
331   block[":method"] = "GET";
332   block[":host"] = "www.example.com";
333   block[":path"] = "/path";
334   block[":scheme"] = "http";
335   block["foo"] = "bar";
336   {
337     InSequence s;
338     EXPECT_CALL(*interface_,
339                 FindOrMakeNewSMConnectionInterface(_, _))
340         .WillOnce(Return(mock_interface.get()));
341     EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
342     EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _)).Times(1);
343     EXPECT_CALL(checkpoint, Call(0));
344     EXPECT_CALL(*mock_interface,
345                 ProcessWriteInput(frame->data(), frame->size())).Times(1);
346   }
347
348   visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
349   checkpoint.Call(0);
350   visitor->OnStreamFrameData(stream_id, frame->data(), frame->size(), true);
351 }
352
353 TEST_P(SpdySMProxyTest, OnRstStream) {
354   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
355   uint32 stream_id = 82;
356   MemCacheIter mci;
357   mci.stream_id = stream_id;
358
359   {
360     BalsaHeaders headers;
361     std::string filename = "foobar";
362     memory_cache_->InsertFile(&headers, filename, "");
363     mci.file_data = memory_cache_->GetFileData(filename);
364   }
365
366   interface_->AddToOutputOrder(mci);
367   ASSERT_TRUE(HasStream(stream_id));
368   visitor->OnRstStream(stream_id, RST_STREAM_INVALID);
369   ASSERT_FALSE(HasStream(stream_id));
370 }
371
372 TEST_P(SpdySMProxyTest, ProcessReadInput) {
373   ASSERT_EQ(SpdyFramer::SPDY_RESET, interface_->spdy_framer()->state());
374   interface_->ProcessReadInput("", 1);
375   ASSERT_EQ(SpdyFramer::SPDY_READING_COMMON_HEADER,
376             interface_->spdy_framer()->state());
377 }
378
379 TEST_P(SpdySMProxyTest, ResetForNewConnection) {
380   uint32 stream_id = 13;
381   MemCacheIter mci;
382   mci.stream_id = stream_id;
383   // incomplete input
384   const char input[] = {'\0', '\0', '\0'};
385
386   {
387     BalsaHeaders headers;
388     std::string filename = "foobar";
389     memory_cache_->InsertFile(&headers, filename, "");
390     mci.file_data = memory_cache_->GetFileData(filename);
391   }
392
393   interface_->AddToOutputOrder(mci);
394   ASSERT_TRUE(HasStream(stream_id));
395   interface_->ProcessReadInput(input, sizeof(input));
396   ASSERT_NE(SpdyFramer::SPDY_RESET, interface_->spdy_framer()->state());
397
398   interface_->ResetForNewConnection();
399   ASSERT_FALSE(HasStream(stream_id));
400   ASSERT_EQ(SpdyFramer::SPDY_RESET, interface_->spdy_framer()->state());
401 }
402
403 TEST_P(SpdySMProxyTest, PostAcceptHook) {
404   interface_->PostAcceptHook();
405
406   ASSERT_EQ(1u, connection_->output_list()->size());
407   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
408   DataFrame* df = *i++;
409
410   {
411     InSequence s;
412     EXPECT_CALL(*spdy_framer_visitor_, OnSettings(false));
413     EXPECT_CALL(*spdy_framer_visitor_,
414                 OnSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 0u, 100u));
415   }
416   spdy_framer_->ProcessInput(df->data, df->size);
417 }
418
419 TEST_P(SpdySMProxyTest, NewStream) {
420   // TODO(yhirano): SpdySM::NewStream leads to crash when
421   // acceptor_->flip_handler_type_ != FLIP_HANDLER_SPDY_SERVER.
422   // It should be fixed though I don't know the solution now.
423 }
424
425 TEST_P(SpdySMProxyTest, AddToOutputOrder) {
426   uint32 stream_id = 13;
427   MemCacheIter mci;
428   mci.stream_id = stream_id;
429
430   {
431     BalsaHeaders headers;
432     std::string filename = "foobar";
433     memory_cache_->InsertFile(&headers, filename, "");
434     mci.file_data = memory_cache_->GetFileData(filename);
435   }
436
437   interface_->AddToOutputOrder(mci);
438   ASSERT_TRUE(HasStream(stream_id));
439 }
440
441 TEST_P(SpdySMProxyTest, SendErrorNotFound_SPDY2) {
442   if (GetParam() != SPDY2) {
443     // This test is for SPDY2.
444     return;
445   }
446   uint32 stream_id = 82;
447   SpdyHeaderBlock actual_header_block;
448   const char* actual_data;
449   size_t actual_size;
450   testing::MockFunction<void(int)> checkpoint;  // NOLINT
451
452   interface_->SendErrorNotFound(stream_id);
453
454   ASSERT_EQ(2u, connection_->output_list()->size());
455
456   {
457     InSequence s;
458     EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
459         .WillOnce(SaveArg<2>(&actual_header_block));
460     EXPECT_CALL(checkpoint, Call(0));
461     EXPECT_CALL(*spdy_framer_visitor_,
462                 OnDataFrameHeader(stream_id, _, true));
463     EXPECT_CALL(*spdy_framer_visitor_,
464                 OnStreamFrameData(stream_id, _, _, false)).Times(1)
465         .WillOnce(DoAll(SaveArg<1>(&actual_data),
466                         SaveArg<2>(&actual_size)));
467     EXPECT_CALL(*spdy_framer_visitor_,
468                 OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
469   }
470
471   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
472   DataFrame* df = *i++;
473   spdy_framer_->ProcessInput(df->data, df->size);
474   checkpoint.Call(0);
475   df = *i++;
476   spdy_framer_->ProcessInput(df->data, df->size);
477
478   ASSERT_EQ(2, spdy_framer_->frames_received());
479   ASSERT_EQ(2u, actual_header_block.size());
480   ASSERT_EQ("404 Not Found", actual_header_block["status"]);
481   ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
482   ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
483 }
484
485 TEST_P(SpdySMProxyTest, SendErrorNotFound) {
486   if (GetParam() == SPDY2) {
487     // This test is not for SPDY2.
488     return;
489   }
490   uint32 stream_id = 82;
491   SpdyHeaderBlock actual_header_block;
492   const char* actual_data;
493   size_t actual_size;
494   testing::MockFunction<void(int)> checkpoint;  // NOLINT
495
496   interface_->SendErrorNotFound(stream_id);
497
498   ASSERT_EQ(2u, connection_->output_list()->size());
499
500   {
501     InSequence s;
502     EXPECT_CALL(*spdy_framer_visitor_,
503                 OnSynReply(stream_id, false, _))
504         .WillOnce(SaveArg<2>(&actual_header_block));
505     EXPECT_CALL(checkpoint, Call(0));
506     EXPECT_CALL(*spdy_framer_visitor_,
507                 OnDataFrameHeader(stream_id, _, true));
508     EXPECT_CALL(*spdy_framer_visitor_,
509                 OnStreamFrameData(stream_id, _, _, false)).Times(1)
510         .WillOnce(DoAll(SaveArg<1>(&actual_data),
511                         SaveArg<2>(&actual_size)));
512     EXPECT_CALL(*spdy_framer_visitor_,
513                 OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
514   }
515
516   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
517   DataFrame* df = *i++;
518   spdy_framer_->ProcessInput(df->data, df->size);
519   checkpoint.Call(0);
520   df = *i++;
521   spdy_framer_->ProcessInput(df->data, df->size);
522
523   ASSERT_EQ(2, spdy_framer_->frames_received());
524   ASSERT_EQ(2u, actual_header_block.size());
525   ASSERT_EQ("404 Not Found", actual_header_block[":status"]);
526   ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
527   ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
528 }
529
530 TEST_P(SpdySMProxyTest, SendSynStream_SPDY2) {
531   if (GetParam() != SPDY2) {
532     // This test is for SPDY2.
533     return;
534   }
535   uint32 stream_id = 82;
536   BalsaHeaders headers;
537   SpdyHeaderBlock actual_header_block;
538   headers.AppendHeader("key1", "value1");
539   headers.SetRequestFirstlineFromStringPieces("GET", "/path", "HTTP/1.0");
540
541   interface_->SendSynStream(stream_id, headers);
542
543   ASSERT_EQ(1u, connection_->output_list()->size());
544   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
545   DataFrame* df = *i++;
546
547   {
548     InSequence s;
549     EXPECT_CALL(*spdy_framer_visitor_,
550                 OnSynStream(stream_id, 0, _, _, false, false, _))
551         .WillOnce(SaveArg<6>(&actual_header_block));
552   }
553
554   spdy_framer_->ProcessInput(df->data, df->size);
555   ASSERT_EQ(1, spdy_framer_->frames_received());
556   ASSERT_EQ(4u, actual_header_block.size());
557   ASSERT_EQ("GET", actual_header_block["method"]);
558   ASSERT_EQ("HTTP/1.0", actual_header_block["version"]);
559   ASSERT_EQ("/path", actual_header_block["url"]);
560   ASSERT_EQ("value1", actual_header_block["key1"]);
561 }
562
563 TEST_P(SpdySMProxyTest, SendSynStream) {
564   if (GetParam() == SPDY2) {
565     // This test is not for SPDY2.
566     return;
567   }
568   uint32 stream_id = 82;
569   BalsaHeaders headers;
570   SpdyHeaderBlock actual_header_block;
571   headers.AppendHeader("key1", "value1");
572   headers.AppendHeader("Host", "www.example.com");
573   headers.SetRequestFirstlineFromStringPieces("GET", "/path", "HTTP/1.1");
574
575   interface_->SendSynStream(stream_id, headers);
576
577   ASSERT_EQ(1u, connection_->output_list()->size());
578   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
579   DataFrame* df = *i++;
580
581   {
582     InSequence s;
583     EXPECT_CALL(*spdy_framer_visitor_,
584                 OnSynStream(stream_id, 0, _, _, false, false, _))
585         .WillOnce(SaveArg<6>(&actual_header_block));
586   }
587
588   spdy_framer_->ProcessInput(df->data, df->size);
589   ASSERT_EQ(1, spdy_framer_->frames_received());
590   ASSERT_EQ(5u, actual_header_block.size());
591   ASSERT_EQ("GET", actual_header_block[":method"]);
592   ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
593   ASSERT_EQ("/path", actual_header_block[":path"]);
594   ASSERT_EQ("www.example.com", actual_header_block[":host"]);
595   ASSERT_EQ("value1", actual_header_block["key1"]);
596 }
597
598 TEST_P(SpdySMProxyTest, SendSynReply_SPDY2) {
599   if (GetParam() != SPDY2) {
600     // This test is for SPDY2.
601     return;
602   }
603   uint32 stream_id = 82;
604   BalsaHeaders headers;
605   SpdyHeaderBlock actual_header_block;
606   headers.AppendHeader("key1", "value1");
607   headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
608
609   interface_->SendSynReply(stream_id, headers);
610
611   ASSERT_EQ(1u, connection_->output_list()->size());
612   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
613   DataFrame* df = *i++;
614
615   {
616     InSequence s;
617     EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
618         .WillOnce(SaveArg<2>(&actual_header_block));
619   }
620
621   spdy_framer_->ProcessInput(df->data, df->size);
622   ASSERT_EQ(1, spdy_framer_->frames_received());
623   ASSERT_EQ(3u, actual_header_block.size());
624   ASSERT_EQ("200 OK", actual_header_block["status"]);
625   ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
626   ASSERT_EQ("value1", actual_header_block["key1"]);
627 }
628
629 TEST_P(SpdySMProxyTest, SendSynReply) {
630   if (GetParam() == SPDY2) {
631     // This test is not for SPDY2.
632     return;
633   }
634   uint32 stream_id = 82;
635   BalsaHeaders headers;
636   SpdyHeaderBlock actual_header_block;
637   headers.AppendHeader("key1", "value1");
638   headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
639
640   interface_->SendSynReply(stream_id, headers);
641
642   ASSERT_EQ(1u, connection_->output_list()->size());
643   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
644   DataFrame* df = *i++;
645
646   {
647     InSequence s;
648     EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
649         .WillOnce(SaveArg<2>(&actual_header_block));
650   }
651
652   spdy_framer_->ProcessInput(df->data, df->size);
653   ASSERT_EQ(1, spdy_framer_->frames_received());
654   ASSERT_EQ(3u, actual_header_block.size());
655   ASSERT_EQ("200 OK", actual_header_block[":status"]);
656   ASSERT_EQ("HTTP/1.1", actual_header_block[":version"]);
657   ASSERT_EQ("value1", actual_header_block["key1"]);
658 }
659
660 TEST_P(SpdySMProxyTest, SendDataFrame) {
661   uint32 stream_id = 133;
662   SpdyDataFlags flags = DATA_FLAG_NONE;
663   const char* actual_data;
664   size_t actual_size;
665
666   interface_->SendDataFrame(stream_id, "hello", 5, flags, true);
667
668   ASSERT_EQ(1u, connection_->output_list()->size());
669   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
670   DataFrame* df = *i++;
671
672   {
673     InSequence s;
674     EXPECT_CALL(*spdy_framer_visitor_,
675                 OnDataFrameHeader(stream_id, _, false));
676     EXPECT_CALL(*spdy_framer_visitor_,
677                 OnStreamFrameData(stream_id, _, _, false))
678         .WillOnce(DoAll(SaveArg<1>(&actual_data), SaveArg<2>(&actual_size)));
679   }
680
681   spdy_framer_->ProcessInput(df->data, df->size);
682   ASSERT_EQ(1, spdy_framer_->frames_received());
683   ASSERT_EQ("hello", StringPiece(actual_data, actual_size));
684 }
685
686 TEST_P(SpdySMProxyTest, SendLongDataFrame) {
687   uint32 stream_id = 133;
688   SpdyDataFlags flags = DATA_FLAG_NONE;
689   const char* actual_data;
690   size_t actual_size;
691
692   std::string data = std::string(kSpdySegmentSize, 'a') +
693                      std::string(kSpdySegmentSize, 'b') + "c";
694   interface_->SendDataFrame(stream_id, data.data(), data.size(), flags, true);
695
696   {
697     InSequence s;
698     for (int i = 0; i < 3; ++i) {
699         EXPECT_CALL(*spdy_framer_visitor_,
700                     OnDataFrameHeader(stream_id, _, false));
701         EXPECT_CALL(*spdy_framer_visitor_,
702                     OnStreamFrameData(stream_id, _, _, false))
703             .WillOnce(DoAll(SaveArg<1>(&actual_data),
704                             SaveArg<2>(&actual_size)));
705     }
706   }
707
708   ASSERT_EQ(3u, connection_->output_list()->size());
709   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
710   DataFrame* df = *i++;
711   spdy_framer_->ProcessInput(df->data, df->size);
712   ASSERT_EQ(std::string(kSpdySegmentSize, 'a'),
713             StringPiece(actual_data, actual_size));
714
715   df = *i++;
716   spdy_framer_->ProcessInput(df->data, df->size);
717   ASSERT_EQ(std::string(kSpdySegmentSize, 'b'),
718             StringPiece(actual_data, actual_size));
719
720   df = *i++;
721   spdy_framer_->ProcessInput(df->data, df->size);
722   ASSERT_EQ("c", StringPiece(actual_data, actual_size));
723 }
724
725 TEST_P(SpdySMProxyTest, SendEOF_SPDY2) {
726   // This test is for SPDY2.
727   if (GetParam() != SPDY2) {
728     return;
729   }
730
731   uint32 stream_id = 82;
732   // SPDY2 data frame
733   char empty_data_frame[] = {'\0', '\0', '\0', '\x52', '\x1', '\0', '\0', '\0'};
734   MemCacheIter mci;
735   mci.stream_id = stream_id;
736
737   {
738     BalsaHeaders headers;
739     std::string filename = "foobar";
740     memory_cache_->InsertFile(&headers, filename, "");
741     mci.file_data = memory_cache_->GetFileData(filename);
742   }
743
744   interface_->AddToOutputOrder(mci);
745   ASSERT_TRUE(HasStream(stream_id));
746   interface_->SendEOF(stream_id);
747   ASSERT_FALSE(HasStream(stream_id));
748
749   ASSERT_EQ(1u, connection_->output_list()->size());
750   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
751   DataFrame* df = *i++;
752   ASSERT_EQ(StringPiece(empty_data_frame, sizeof(empty_data_frame)),
753             StringPiece(df->data, df->size));
754 }
755
756 TEST_P(SpdySMProxyTest, SendEmptyDataFrame_SPDY2) {
757   // This test is for SPDY2.
758   if (GetParam() != SPDY2) {
759     return;
760   }
761
762   uint32 stream_id = 133;
763   SpdyDataFlags flags = DATA_FLAG_NONE;
764   // SPDY2 data frame
765   char expected[] = {'\0', '\0', '\0', '\x85', '\0', '\0', '\0', '\0'};
766
767   interface_->SendDataFrame(stream_id, "hello", 0, flags, true);
768
769   ASSERT_EQ(1u, connection_->output_list()->size());
770   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
771   DataFrame* df = *i++;
772
773   ASSERT_EQ(StringPiece(expected, sizeof(expected)),
774             StringPiece(df->data, df->size));
775 }
776
777 TEST_P(SpdySMServerTest, OnSynStream) {
778   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
779   uint32 stream_id = 82;
780   SpdyHeaderBlock spdy_headers;
781   spdy_headers["url"] = "http://www.example.com/path";
782   spdy_headers["method"] = "GET";
783   spdy_headers["scheme"] = "http";
784   spdy_headers["version"] = "HTTP/1.1";
785
786   {
787     BalsaHeaders headers;
788     memory_cache_->InsertFile(&headers, "GET_/path", "");
789   }
790   visitor->OnSynStream(stream_id, 0, 0, 0, true, true, spdy_headers);
791   ASSERT_TRUE(HasStream(stream_id));
792 }
793
794 TEST_P(SpdySMServerTest, NewStream) {
795   uint32 stream_id = 13;
796   std::string filename = "foobar";
797
798   {
799     BalsaHeaders headers;
800     memory_cache_->InsertFile(&headers, filename, "");
801   }
802
803   interface_->NewStream(stream_id, 0, filename);
804   ASSERT_TRUE(HasStream(stream_id));
805 }
806
807 TEST_P(SpdySMServerTest, NewStreamError) {
808   uint32 stream_id = 82;
809   SpdyHeaderBlock actual_header_block;
810   const char* actual_data;
811   size_t actual_size;
812   testing::MockFunction<void(int)> checkpoint;  // NOLINT
813
814   interface_->NewStream(stream_id, 0, "nonexistingfile");
815
816   ASSERT_EQ(2u, connection_->output_list()->size());
817
818   {
819     InSequence s;
820     EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
821         .WillOnce(SaveArg<2>(&actual_header_block));
822     EXPECT_CALL(checkpoint, Call(0));
823     EXPECT_CALL(*spdy_framer_visitor_,
824                 OnDataFrameHeader(stream_id, _, true));
825     EXPECT_CALL(*spdy_framer_visitor_,
826                 OnStreamFrameData(stream_id, _, _, false)).Times(1)
827         .WillOnce(DoAll(SaveArg<1>(&actual_data),
828                         SaveArg<2>(&actual_size)));
829     EXPECT_CALL(*spdy_framer_visitor_,
830                 OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
831   }
832
833   std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
834   DataFrame* df = *i++;
835   spdy_framer_->ProcessInput(df->data, df->size);
836   checkpoint.Call(0);
837   df = *i++;
838   spdy_framer_->ProcessInput(df->data, df->size);
839
840   ASSERT_EQ(2, spdy_framer_->frames_received());
841   ASSERT_EQ(2u, actual_header_block.size());
842   ASSERT_EQ("404 Not Found", actual_header_block["status"]);
843   ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
844   ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
845 }
846
847 }  // namespace
848
849 }  // namespace net