diff options
Diffstat (limited to 'net/flip/flip_framer_test.cc')
-rw-r--r-- | net/flip/flip_framer_test.cc | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/net/flip/flip_framer_test.cc b/net/flip/flip_framer_test.cc new file mode 100644 index 0000000..a786bc2 --- /dev/null +++ b/net/flip/flip_framer_test.cc @@ -0,0 +1,251 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <iostream> +#include "base/scoped_ptr.h" + +#include "flip_framer.h" // cross-google3 directory naming. +#include "flip_protocol.h" +#include "flip_frame_builder.h" +#ifdef _WIN32 +#include "testing/platform_test.h" +#else +#include "testing/base/public/gunit.h" + +#define PlatformTest ::testing::Test +#endif + +namespace flip { + +class FlipFramerTest : public PlatformTest { + public: + virtual void TearDown() {} +}; + +class TestFlipVisitor : public FlipFramerVisitorInterface { + public: + explicit TestFlipVisitor(FlipFramer* framer) + : framer_(framer), + error_count_(0), + syn_frame_count_(0), + syn_reply_frame_count_(0), + data_frame_count_(0), + fin_frame_count_(0) { + } + + void OnError(FlipFramer* f) { + error_count_++; + } + void OnStreamFrameData(FlipStreamId stream_id, + const char* data, + uint32 len) { + data_frame_count_++; +#ifdef TEST_LOGGING + std::cerr << "OnStreamFrameData(" << stream_id << ", \""; + if (len > 0) { + for (uint32 i = 0 ; i < len; ++i) { + std::cerr << std::hex << (0xFF & (unsigned int)data[i]) << std::dec; + } + } + std::cerr << "\", " << len << ")\n"; +#endif // TEST_LOGGING + } + + void OnControl(const FlipControlFrame* frame) { + FlipHeaderBlock headers; + bool parsed_headers = false; + switch (frame->type()) { + case SYN_STREAM: + parsed_headers = framer_->ParseHeaderBlock( + reinterpret_cast<const FlipFrame*>(frame), &headers); + DCHECK(parsed_headers); + syn_frame_count_++; + VLOG(2) << "OnSyn(" << frame->stream_id() << ")\n"; + break; + case SYN_REPLY: + parsed_headers = framer_->ParseHeaderBlock( + reinterpret_cast<const FlipFrame*>(frame), &headers); + DCHECK(parsed_headers); + syn_reply_frame_count_++; + VLOG(2) << "OnSynReply(" << frame->stream_id() << ")\n"; + break; + case FIN_STREAM: + fin_frame_count_++; + VLOG(2) << "OnFin(" << frame->stream_id() << ")\n"; + break; + default: + DCHECK(false); // Error! + } + } + + void OnLameDuck() { + } + + FlipFramer* framer_; + // Counters from the visitor callbacks. + int error_count_; + int syn_frame_count_; + int syn_reply_frame_count_; + int data_frame_count_; + int fin_frame_count_; +}; + +// Test our protocol constants +TEST_F(FlipFramerTest, ProtocolConstants) { + EXPECT_EQ(8, sizeof(FlipFrame)); + EXPECT_EQ(8, sizeof(FlipDataFrame)); + EXPECT_EQ(12, sizeof(FlipControlFrame)); + EXPECT_EQ(16, sizeof(FlipSynStreamControlFrame)); + EXPECT_EQ(16, sizeof(FlipSynReplyControlFrame)); + EXPECT_EQ(16, sizeof(FlipFinStreamControlFrame)); + EXPECT_EQ(1, SYN_STREAM); + EXPECT_EQ(2, SYN_REPLY); + EXPECT_EQ(3, FIN_STREAM); +} + +// Test that we can encode and decode a FlipHeaderBlock. +TEST_F(FlipFramerTest, HeaderBlock) { + FlipHeaderBlock headers; + headers["alpha"] = "beta"; + headers["gamma"] = "charlie"; + FlipFramer framer; + + // Encode the header block into a SynStream frame. + scoped_ptr<FlipSynStreamControlFrame> frame( + framer.CreateSynStream(1, 1, true, &headers)); + EXPECT_TRUE(frame.get() != NULL); + + FlipHeaderBlock new_headers; + FlipFrame* control_frame = reinterpret_cast<FlipFrame*>(frame.get()); + framer.ParseHeaderBlock(control_frame, &new_headers); + + EXPECT_EQ(headers.size(), new_headers.size()); + EXPECT_EQ(headers["alpha"], new_headers["alpha"]); + EXPECT_EQ(headers["gamma"], new_headers["gamma"]); +} + +TEST_F(FlipFramerTest, HeaderBlockBarfsOnOutOfOrderHeaders) { + FlipFrameBuilder frame; + + frame.WriteUInt16(kControlFlagMask | 1); + frame.WriteUInt16(SYN_STREAM); + frame.WriteUInt32(0); // Placeholder for the length. + frame.WriteUInt32(3); // stream_id + frame.WriteUInt16(0); // Priority. + + frame.WriteUInt16(2); // Number of headers. + FlipHeaderBlock::iterator it; + frame.WriteString("gamma"); + frame.WriteString("gamma"); + frame.WriteString("alpha"); + frame.WriteString("alpha"); + // write the length + frame.WriteUInt32ToOffset(4, frame.length() - sizeof(FlipFrame)); + + FlipHeaderBlock new_headers; + const FlipFrame* control_frame = frame.data(); + FlipFramer framer; + framer.set_enable_compression(false); + EXPECT_FALSE(framer.ParseHeaderBlock(control_frame, &new_headers)); +} + +TEST_F(FlipFramerTest, BasicCompression) { + FlipHeaderBlock headers; + headers["server"] = "FlipServer 1.0"; + headers["date"] = "Mon 12 Jan 2009 12:12:12 PST"; + headers["status"] = "200"; + headers["version"] = "HTTP/1.1"; + headers["content-type"] = "text/html"; + headers["content-length"] = "12"; + + FlipFramer framer; + scoped_ptr<FlipSynStreamControlFrame> + frame1(framer.CreateSynStream(1, 1, true, &headers)); + scoped_ptr<FlipSynStreamControlFrame> + frame2(framer.CreateSynStream(1, 1, true, &headers)); + + // Expect the second frame to be more compact than the first. + EXPECT_LE(frame2->length(), frame1->length()); + + // Decompress the first frame + scoped_ptr<FlipFrame> frame3( + framer.DecompressFrame(reinterpret_cast<FlipFrame*>(frame1.get()))); + + // Decompress the second frame + scoped_ptr<FlipFrame> frame4( + framer.DecompressFrame(reinterpret_cast<FlipFrame*>(frame2.get()))); + + // Expect frames 3 & 4 to be the same. + EXPECT_EQ(0, + memcmp(frame3.get(), frame4.get(), + sizeof(FlipFrame) + frame3->length())); +} + +TEST_F(FlipFramerTest, Basic) { + const unsigned char input[] = { + 0x80, 0x01, 0x00, 0x01, // SYN Stream #1 + 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x02, 'h', 'h', + 0x00, 0x02, 'v', 'v', + + 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 + 0x00, 0x00, 0x00, 0x0c, + 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, + + 0x80, 0x01, 0x00, 0x01, // SYN Stream #3 + 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 + 0x00, 0x00, 0x00, 0x08, + 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, + + 0x00, 0x00, 0x00, 0x01, // DATA on Stream #1 + 0x00, 0x00, 0x00, 0x04, + 0xde, 0xad, 0xbe, 0xef, + + 0x80, 0x01, 0x00, 0x03, // FIN on Stream #1 + 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x03, // DATA on Stream #3 + 0x00, 0x00, 0x00, 0x00, + + 0x80, 0x01, 0x00, 0x03, // FIN on Stream #3 + 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, + }; + + FlipFramer framer; + framer.set_enable_compression(false); + TestFlipVisitor visitor(&framer); + framer.set_visitor(&visitor); + size_t input_remaining = sizeof(input); + const char* input_ptr = reinterpret_cast<const char*>(input); + while (input_remaining > 0 && + framer.error_code() == FlipFramer::FLIP_NO_ERROR) { + size_t bytes_processed = framer.ProcessInput(input_ptr, sizeof(input)); + input_remaining -= bytes_processed; + input_ptr += bytes_processed; + if (framer.state() == FlipFramer::FLIP_DONE) + framer.Reset(); + } + EXPECT_EQ(0, visitor.error_count_); + EXPECT_EQ(2, visitor.syn_frame_count_); + EXPECT_EQ(0, visitor.syn_reply_frame_count_); + EXPECT_EQ(4, visitor.data_frame_count_); + EXPECT_EQ(2, visitor.fin_frame_count_); +} + +} // namespace flip + + |