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