Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / net / spdy / buffered_spdy_framer_unittest.cc
1 // Copyright (c) 2012 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/spdy/buffered_spdy_framer.h"
6
7 #include "net/spdy/spdy_test_util_common.h"
8 #include "testing/platform_test.h"
9
10 namespace net {
11
12 namespace {
13
14 class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
15  public:
16   explicit TestBufferedSpdyVisitor(SpdyMajorVersion spdy_version)
17       : buffered_spdy_framer_(spdy_version, true),
18         error_count_(0),
19         setting_count_(0),
20         syn_frame_count_(0),
21         syn_reply_frame_count_(0),
22         headers_frame_count_(0),
23         push_promise_frame_count_(0),
24         header_stream_id_(static_cast<SpdyStreamId>(-1)),
25         promised_stream_id_(static_cast<SpdyStreamId>(-1)) {
26   }
27
28   virtual void OnError(SpdyFramer::SpdyError error_code) OVERRIDE {
29     LOG(INFO) << "SpdyFramer Error: " << error_code;
30     error_count_++;
31   }
32
33   virtual void OnStreamError(
34       SpdyStreamId stream_id,
35       const std::string& description) OVERRIDE {
36     LOG(INFO) << "SpdyFramer Error on stream: " << stream_id  << " "
37               << description;
38     error_count_++;
39   }
40
41   virtual void OnSynStream(SpdyStreamId stream_id,
42                            SpdyStreamId associated_stream_id,
43                            SpdyPriority priority,
44                            bool fin,
45                            bool unidirectional,
46                            const SpdyHeaderBlock& headers) OVERRIDE {
47     header_stream_id_ = stream_id;
48     EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream);
49     syn_frame_count_++;
50     headers_ = headers;
51   }
52
53   virtual void OnSynReply(SpdyStreamId stream_id,
54                           bool fin,
55                           const SpdyHeaderBlock& headers) OVERRIDE {
56     header_stream_id_ = stream_id;
57     EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream);
58     syn_reply_frame_count_++;
59     headers_ = headers;
60   }
61
62   virtual void OnHeaders(SpdyStreamId stream_id,
63                          bool fin,
64                          const SpdyHeaderBlock& headers) OVERRIDE {
65     header_stream_id_ = stream_id;
66     EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream);
67     headers_frame_count_++;
68     headers_ = headers;
69   }
70
71   virtual void OnDataFrameHeader(SpdyStreamId stream_id,
72                                  size_t length,
73                                  bool fin) OVERRIDE {
74     ADD_FAILURE() << "Unexpected OnDataFrameHeader call.";
75   }
76
77   virtual void OnStreamFrameData(SpdyStreamId stream_id,
78                                  const char* data,
79                                  size_t len,
80                                  bool fin) OVERRIDE {
81     LOG(FATAL) << "Unexpected OnStreamFrameData call.";
82   }
83
84   virtual void OnSettings(bool clear_persisted) OVERRIDE {}
85
86   virtual void OnSetting(SpdySettingsIds id,
87                          uint8 flags,
88                          uint32 value) OVERRIDE {
89     setting_count_++;
90   }
91
92   virtual void OnPing(SpdyPingId unique_id, bool is_ack) OVERRIDE {}
93
94   virtual void OnRstStream(SpdyStreamId stream_id,
95                            SpdyRstStreamStatus status) OVERRIDE {
96   }
97
98   virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
99                         SpdyGoAwayStatus status) OVERRIDE {
100   }
101
102   bool OnCredentialFrameData(const char*, size_t) {
103     LOG(FATAL) << "Unexpected OnCredentialFrameData call.";
104     return false;
105   }
106
107   void OnDataFrameHeader(const SpdyFrame* frame) {
108     LOG(FATAL) << "Unexpected OnDataFrameHeader call.";
109   }
110
111   void OnRstStream(const SpdyFrame& frame) {}
112   void OnGoAway(const SpdyFrame& frame) {}
113   void OnPing(const SpdyFrame& frame) {}
114   virtual void OnWindowUpdate(SpdyStreamId stream_id,
115                               uint32 delta_window_size) OVERRIDE {}
116
117   virtual void OnPushPromise(SpdyStreamId stream_id,
118                              SpdyStreamId promised_stream_id,
119                              const SpdyHeaderBlock& headers) OVERRIDE {
120     header_stream_id_ = stream_id;
121     EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream);
122     push_promise_frame_count_++;
123     promised_stream_id_ = promised_stream_id;
124     EXPECT_NE(promised_stream_id_, SpdyFramer::kInvalidStream);
125     headers_ = headers;
126   }
127
128   void OnCredential(const SpdyFrame& frame) {}
129
130   // Convenience function which runs a framer simulation with particular input.
131   void SimulateInFramer(const unsigned char* input, size_t size) {
132     buffered_spdy_framer_.set_visitor(this);
133     size_t input_remaining = size;
134     const char* input_ptr = reinterpret_cast<const char*>(input);
135     while (input_remaining > 0 &&
136            buffered_spdy_framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) {
137       // To make the tests more interesting, we feed random (amd small) chunks
138       // into the framer.  This simulates getting strange-sized reads from
139       // the socket.
140       const size_t kMaxReadSize = 32;
141       size_t bytes_read =
142           (rand() % std::min(input_remaining, kMaxReadSize)) + 1;
143       size_t bytes_processed =
144           buffered_spdy_framer_.ProcessInput(input_ptr, bytes_read);
145       input_remaining -= bytes_processed;
146       input_ptr += bytes_processed;
147     }
148   }
149
150   BufferedSpdyFramer buffered_spdy_framer_;
151
152   // Counters from the visitor callbacks.
153   int error_count_;
154   int setting_count_;
155   int syn_frame_count_;
156   int syn_reply_frame_count_;
157   int headers_frame_count_;
158   int push_promise_frame_count_;
159
160   // Header block streaming state:
161   SpdyStreamId header_stream_id_;
162   SpdyStreamId promised_stream_id_;
163
164   // Headers from OnSyn, OnSynReply, OnHeaders and OnPushPromise for
165   // verification.
166   SpdyHeaderBlock headers_;
167 };
168
169 }  // namespace
170
171 class BufferedSpdyFramerTest
172     : public PlatformTest,
173       public ::testing::WithParamInterface<NextProto> {
174  protected:
175   // Returns true if the two header blocks have equivalent content.
176   bool CompareHeaderBlocks(const SpdyHeaderBlock* expected,
177                            const SpdyHeaderBlock* actual) {
178     if (expected->size() != actual->size()) {
179       LOG(ERROR) << "Expected " << expected->size() << " headers; actually got "
180                  << actual->size() << ".";
181       return false;
182     }
183     for (SpdyHeaderBlock::const_iterator it = expected->begin();
184          it != expected->end();
185          ++it) {
186       SpdyHeaderBlock::const_iterator it2 = actual->find(it->first);
187       if (it2 == actual->end()) {
188         LOG(ERROR) << "Expected header name '" << it->first << "'.";
189         return false;
190       }
191       if (it->second.compare(it2->second) != 0) {
192         LOG(ERROR) << "Expected header named '" << it->first
193                    << "' to have a value of '" << it->second
194                    << "'. The actual value received was '" << it2->second
195                    << "'.";
196         return false;
197       }
198     }
199     return true;
200   }
201
202   SpdyMajorVersion spdy_version() {
203     return NextProtoToSpdyMajorVersion(GetParam());
204   }
205 };
206
207 INSTANTIATE_TEST_CASE_P(
208     NextProto,
209     BufferedSpdyFramerTest,
210     testing::Values(kProtoDeprecatedSPDY2,
211                     kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
212
213 TEST_P(BufferedSpdyFramerTest, OnSetting) {
214   SpdyFramer framer(spdy_version());
215   SpdySettingsIR settings_ir;
216   settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, false, false, 2);
217   settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, false, false, 3);
218   scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir));
219   TestBufferedSpdyVisitor visitor(spdy_version());
220
221   visitor.SimulateInFramer(
222       reinterpret_cast<unsigned char*>(control_frame->data()),
223       control_frame->size());
224   EXPECT_EQ(0, visitor.error_count_);
225   EXPECT_EQ(2, visitor.setting_count_);
226 }
227
228 TEST_P(BufferedSpdyFramerTest, ReadSynStreamHeaderBlock) {
229   if (spdy_version() > SPDY3) {
230     // SYN_STREAM not supported in SPDY>3.
231     return;
232   }
233   SpdyHeaderBlock headers;
234   headers["aa"] = "vv";
235   headers["bb"] = "ww";
236   BufferedSpdyFramer framer(spdy_version(), true);
237   scoped_ptr<SpdyFrame> control_frame(
238       framer.CreateSynStream(1,                        // stream_id
239                              0,                        // associated_stream_id
240                              1,                        // priority
241                              CONTROL_FLAG_NONE,
242                              &headers));
243   EXPECT_TRUE(control_frame.get() != NULL);
244
245   TestBufferedSpdyVisitor visitor(spdy_version());
246   visitor.SimulateInFramer(
247       reinterpret_cast<unsigned char*>(control_frame.get()->data()),
248       control_frame.get()->size());
249   EXPECT_EQ(0, visitor.error_count_);
250   EXPECT_EQ(1, visitor.syn_frame_count_);
251   EXPECT_EQ(0, visitor.syn_reply_frame_count_);
252   EXPECT_EQ(0, visitor.headers_frame_count_);
253   EXPECT_EQ(0, visitor.push_promise_frame_count_);
254   EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
255 }
256
257 TEST_P(BufferedSpdyFramerTest, ReadSynReplyHeaderBlock) {
258   if (spdy_version() > SPDY3) {
259     // SYN_REPLY not supported in SPDY>3.
260     return;
261   }
262   SpdyHeaderBlock headers;
263   headers["alpha"] = "beta";
264   headers["gamma"] = "delta";
265   BufferedSpdyFramer framer(spdy_version(), true);
266   scoped_ptr<SpdyFrame> control_frame(
267       framer.CreateSynReply(1,                        // stream_id
268                             CONTROL_FLAG_NONE,
269                             &headers));
270   EXPECT_TRUE(control_frame.get() != NULL);
271
272   TestBufferedSpdyVisitor visitor(spdy_version());
273   visitor.SimulateInFramer(
274       reinterpret_cast<unsigned char*>(control_frame.get()->data()),
275       control_frame.get()->size());
276   EXPECT_EQ(0, visitor.error_count_);
277   EXPECT_EQ(0, visitor.syn_frame_count_);
278   EXPECT_EQ(0, visitor.push_promise_frame_count_);
279   if(spdy_version() < SPDY4) {
280     EXPECT_EQ(1, visitor.syn_reply_frame_count_);
281     EXPECT_EQ(0, visitor.headers_frame_count_);
282   } else {
283     EXPECT_EQ(0, visitor.syn_reply_frame_count_);
284     EXPECT_EQ(1, visitor.headers_frame_count_);
285   }
286   EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
287 }
288
289 TEST_P(BufferedSpdyFramerTest, ReadHeadersHeaderBlock) {
290   SpdyHeaderBlock headers;
291   headers["alpha"] = "beta";
292   headers["gamma"] = "delta";
293   BufferedSpdyFramer framer(spdy_version(), true);
294   scoped_ptr<SpdyFrame> control_frame(
295       framer.CreateHeaders(1,                        // stream_id
296                            CONTROL_FLAG_NONE,
297                            &headers));
298   EXPECT_TRUE(control_frame.get() != NULL);
299
300   TestBufferedSpdyVisitor visitor(spdy_version());
301   visitor.SimulateInFramer(
302       reinterpret_cast<unsigned char*>(control_frame.get()->data()),
303       control_frame.get()->size());
304   EXPECT_EQ(0, visitor.error_count_);
305   EXPECT_EQ(0, visitor.syn_frame_count_);
306   EXPECT_EQ(0, visitor.syn_reply_frame_count_);
307   EXPECT_EQ(1, visitor.headers_frame_count_);
308   EXPECT_EQ(0, visitor.push_promise_frame_count_);
309   EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
310 }
311
312 TEST_P(BufferedSpdyFramerTest, ReadPushPromiseHeaderBlock) {
313   if (spdy_version() < SPDY4)
314     return;
315   SpdyHeaderBlock headers;
316   headers["alpha"] = "beta";
317   headers["gamma"] = "delta";
318   BufferedSpdyFramer framer(spdy_version(), true);
319   scoped_ptr<SpdyFrame> control_frame(
320       framer.CreatePushPromise(1, 2, &headers));
321   EXPECT_TRUE(control_frame.get() != NULL);
322
323   TestBufferedSpdyVisitor visitor(spdy_version());
324   visitor.SimulateInFramer(
325       reinterpret_cast<unsigned char*>(control_frame.get()->data()),
326       control_frame.get()->size());
327   EXPECT_EQ(0, visitor.error_count_);
328   EXPECT_EQ(0, visitor.syn_frame_count_);
329   EXPECT_EQ(0, visitor.syn_reply_frame_count_);
330   EXPECT_EQ(0, visitor.headers_frame_count_);
331   EXPECT_EQ(1, visitor.push_promise_frame_count_);
332   EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
333   EXPECT_EQ(1u, visitor.header_stream_id_);
334   EXPECT_EQ(2u, visitor.promised_stream_id_);
335 }
336
337 }  // namespace net