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