Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1203)

Unified Diff: net/websockets/websocket_deflate_stream_test.cc

Issue 39193005: Introduce WebSocketDeflatePredictor. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/websockets/websocket_deflate_stream_test.cc
diff --git a/net/websockets/websocket_deflate_stream_test.cc b/net/websockets/websocket_deflate_stream_test.cc
index 09b2c5cf1956e5d25838ca2177fcf84008c3bc13..399e74ccc092f8423338b0f81d75ac1609dabd27 100644
--- a/net/websockets/websocket_deflate_stream_test.cc
+++ b/net/websockets/websocket_deflate_stream_test.cc
@@ -5,6 +5,7 @@
#include "net/websockets/websocket_deflate_stream.h"
#include <stdint.h>
+#include <deque>
#include <string>
#include "base/basictypes.h"
@@ -15,6 +16,7 @@
#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
+#include "net/websockets/websocket_deflate_predictor.h"
#include "net/websockets/websocket_deflater.h"
#include "net/websockets/websocket_frame.h"
#include "net/websockets/websocket_inflater.h"
@@ -65,7 +67,7 @@ std::string ToString(const scoped_refptr<IOBuffer>& buffer, size_t size) {
return ToString(buffer.get(), size);
}
-std::string ToString(WebSocketFrame* frame) {
+std::string ToString(const WebSocketFrame* frame) {
return frame->data ? ToString(frame->data, frame->header.payload_length) : "";
}
@@ -101,14 +103,78 @@ class MockWebSocketStream : public WebSocketStream {
MOCK_CONST_METHOD0(GetExtensions, std::string());
};
+// This mock class relies on some assumptions.
+// - RecordInputDataFrame is called after the corresponding WriteFrames
+// call.
+// - RecordWrittenDataFrame is called before writing the frame.
+class WebSocketDeflatePredictorMock : public WebSocketDeflatePredictor {
+ public:
+ WebSocketDeflatePredictorMock() : result_(DEFLATE) {}
+ virtual ~WebSocketDeflatePredictorMock() {
+ DCHECK(frames_to_be_input_.empty());
+ DCHECK(frames_to_be_written_.empty());
+ }
+
Adam Rice 2013/10/30 00:28:07 Please add a comment that these implement the WebS
yhirano 2013/10/30 02:20:33 Done.
+ virtual Result Predict(const ScopedVector<WebSocketFrame>& frames,
+ size_t frame_index) OVERRIDE {
+ return result_;
+ }
+ virtual void RecordInputDataFrame(const WebSocketFrame* frame) OVERRIDE {
+ DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(frame->header.opcode));
+ DCHECK(!frame->header.reserved1);
+ DCHECK(!frames_to_be_input_.empty());
+ DCHECK_EQ(frame, frames_to_be_input_.front());
+ frames_to_be_input_.pop_front();
+ }
+ virtual void RecordWrittenDataFrame(const WebSocketFrame* frame) OVERRIDE {
+ DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(frame->header.opcode));
+ frames_to_be_written_.push_back(frame);
+ }
+
Adam Rice 2013/10/30 00:28:07 Please insert a comment here that the following me
yhirano 2013/10/30 02:20:33 Done.
+ void set_result(Result result) { result_ = result; }
+ void AddFrameToBeInput(const WebSocketFrame* frame) {
+ if (!WebSocketFrameHeader::IsKnownDataOpCode(frame->header.opcode))
+ return;
+ frames_to_be_input_.push_back(frame);
+ }
+ void AddFramesToBeInput(const ScopedVector<WebSocketFrame>& frames) {
+ for (size_t i = 0; i < frames.size(); ++i)
+ AddFrameToBeInput(frames[i]);
+ }
+ void VerifySentFrame(const WebSocketFrame* frame) {
+ if (!WebSocketFrameHeader::IsKnownDataOpCode(frame->header.opcode))
+ return;
+ DCHECK(!frames_to_be_written_.empty());
+ DCHECK_EQ(frame, frames_to_be_written_.front());
+ frames_to_be_written_.pop_front();
+ }
+ void VerifySentFrames(const ScopedVector<WebSocketFrame>& frames) {
+ for (size_t i = 0; i < frames.size(); ++i)
+ VerifySentFrame(frames[i]);
+ }
+ // Call this method in order to disable checks in the destructor when
+ // WriteFrames fails.
+ void Clear() {
+ frames_to_be_input_.clear();
+ frames_to_be_written_.clear();
+ }
+
+ private:
+ Result result_;
+ std::deque<const WebSocketFrame*> frames_to_be_input_;
Adam Rice 2013/10/30 00:28:07 If I understand correctly, these member variables
yhirano 2013/10/30 02:20:33 Done.
+ std::deque<const WebSocketFrame*> frames_to_be_written_;
+};
+
class WebSocketDeflateStreamTest : public ::testing::Test {
public:
WebSocketDeflateStreamTest()
: mock_stream_(NULL) {
mock_stream_ = new testing::StrictMock<MockWebSocketStream>;
+ predictor_ = new WebSocketDeflatePredictorMock;
deflate_stream_.reset(new WebSocketDeflateStream(
scoped_ptr<WebSocketStream>(mock_stream_),
- WebSocketDeflater::TAKE_OVER_CONTEXT));
+ WebSocketDeflater::TAKE_OVER_CONTEXT,
+ scoped_ptr<WebSocketDeflatePredictor>(predictor_)));
}
virtual ~WebSocketDeflateStreamTest() {}
@@ -116,10 +182,12 @@ class WebSocketDeflateStreamTest : public ::testing::Test {
scoped_ptr<WebSocketDeflateStream> deflate_stream_;
// |mock_stream_| will be deleted when |deflate_stream_| is destroyed.
MockWebSocketStream* mock_stream_;
+ // |predictor_| will be deleted when |deflate_stream_| is destroyed.
+ WebSocketDeflatePredictorMock* predictor_;
};
// Since WebSocketDeflater with DoNotTakeOverContext is well tested at
-// websocket_deflater_test.cc, we have only one test for this configuration
+// websocket_deflater_test.cc, we have only a few tests for this configuration
// here.
class WebSocketDeflateStreamWithDoNotTakeOverContextTest
: public ::testing::Test {
@@ -127,9 +195,11 @@ class WebSocketDeflateStreamWithDoNotTakeOverContextTest
WebSocketDeflateStreamWithDoNotTakeOverContextTest()
: mock_stream_(NULL) {
mock_stream_ = new testing::StrictMock<MockWebSocketStream>;
+ predictor_ = new WebSocketDeflatePredictorMock;
deflate_stream_.reset(new WebSocketDeflateStream(
scoped_ptr<WebSocketStream>(mock_stream_),
- WebSocketDeflater::DO_NOT_TAKE_OVER_CONTEXT));
+ WebSocketDeflater::DO_NOT_TAKE_OVER_CONTEXT,
+ scoped_ptr<WebSocketDeflatePredictor>(predictor_)));
}
virtual ~WebSocketDeflateStreamWithDoNotTakeOverContextTest() {}
@@ -137,6 +207,8 @@ class WebSocketDeflateStreamWithDoNotTakeOverContextTest
scoped_ptr<WebSocketDeflateStream> deflate_stream_;
// |mock_stream_| will be deleted when |deflate_stream_| is destroyed.
MockWebSocketStream* mock_stream_;
+ // |predictor_| will be deleted when |deflate_stream_| is destroyed.
+ WebSocketDeflatePredictorMock* predictor_;
};
// ReadFrameStub is a stub for WebSocketStream::ReadFrames.
@@ -173,20 +245,21 @@ class ReadFramesStub {
ScopedVector<WebSocketFrame>* frames_passed_;
};
-// WriteFrameStub is a stub for WebSocketStream::WriteFrames.
+// WriteFramesStub is a stub for WebSocketStream::WriteFrames.
// It returns |result_| and |frames_| to the caller and
// saves |callback| parameter to |callback_|.
class WriteFramesStub {
public:
- explicit WriteFramesStub(int result) : result_(result) {}
+ explicit WriteFramesStub(WebSocketDeflatePredictorMock* predictor,
+ int result)
+ : result_(result), predictor_(predictor) {}
int Call(ScopedVector<WebSocketFrame>* frames,
const CompletionCallback& callback) {
- for (size_t i = 0; i < frames->size(); ++i) {
- frames_.push_back((*frames)[i]);
- }
+ frames_.insert(frames_.end(), frames->begin(), frames->end());
frames->weak_clear();
callback_ = callback;
+ predictor_->VerifySentFrames(frames_);
return result_;
}
@@ -198,6 +271,7 @@ class WriteFramesStub {
int result_;
CompletionCallback callback_;
ScopedVector<WebSocketFrame> frames_;
+ WebSocketDeflatePredictorMock* predictor_;
};
TEST_F(WebSocketDeflateStreamTest, ReadFailedImmediately) {
@@ -791,14 +865,17 @@ TEST_F(WebSocketDeflateStreamTest, WriteFailedImmediately) {
}
AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "hello");
+ predictor_->AddFramesToBeInput(frames);
EXPECT_EQ(ERR_FAILED, deflate_stream_->WriteFrames(&frames, callback));
+ predictor_->Clear();
}
TEST_F(WebSocketDeflateStreamTest, WriteFrameImmediately) {
ScopedVector<WebSocketFrame> frames;
CompletionCallback callback;
- WriteFramesStub stub(OK);
+ WriteFramesStub stub(predictor_, OK);
AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
+ predictor_->AddFramesToBeInput(frames);
{
InSequence s;
EXPECT_CALL(*mock_stream_, WriteFrames(_, _))
@@ -815,7 +892,7 @@ TEST_F(WebSocketDeflateStreamTest, WriteFrameImmediately) {
}
TEST_F(WebSocketDeflateStreamTest, WriteFrameAsync) {
- WriteFramesStub stub(ERR_IO_PENDING);
+ WriteFramesStub stub(predictor_, ERR_IO_PENDING);
MockCallback mock_callback, checkpoint;
CompletionCallback callback =
base::Bind(&MockCallback::Call, base::Unretained(&mock_callback));
@@ -828,6 +905,7 @@ TEST_F(WebSocketDeflateStreamTest, WriteFrameAsync) {
EXPECT_CALL(mock_callback, Call(OK));
}
AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
+ predictor_->AddFramesToBeInput(frames);
ASSERT_EQ(ERR_IO_PENDING, deflate_stream_->WriteFrames(&frames, callback));
checkpoint.Call(0);
@@ -847,7 +925,8 @@ TEST_F(WebSocketDeflateStreamTest, WriteControlFrameBetweenDataFrames) {
AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kNoFlag, "Hel");
AppendTo(&frames, WebSocketFrameHeader::kOpCodePing, kFinal);
AppendTo(&frames, WebSocketFrameHeader::kOpCodeContinuation, kFinal, "lo");
- WriteFramesStub stub(OK);
+ predictor_->AddFramesToBeInput(frames);
+ WriteFramesStub stub(predictor_, OK);
CompletionCallback callback;
{
@@ -871,7 +950,8 @@ TEST_F(WebSocketDeflateStreamTest, WriteControlFrameBetweenDataFrames) {
TEST_F(WebSocketDeflateStreamTest, WriteEmptyMessage) {
ScopedVector<WebSocketFrame> frames;
AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal);
- WriteFramesStub stub(OK);
+ predictor_->AddFramesToBeInput(frames);
+ WriteFramesStub stub(predictor_, OK);
CompletionCallback callback;
{
@@ -888,10 +968,39 @@ TEST_F(WebSocketDeflateStreamTest, WriteEmptyMessage) {
EXPECT_EQ(std::string("\x02\x00", 2), ToString(frames_passed[0]));
}
+TEST_F(WebSocketDeflateStreamTest, WriteUncompressedMessage) {
+ ScopedVector<WebSocketFrame> frames;
+ AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kNoFlag, "AAAA");
+ AppendTo(&frames, WebSocketFrameHeader::kOpCodeContinuation, kFinal, "AAA");
+ predictor_->AddFramesToBeInput(frames);
+ WriteFramesStub stub(predictor_, OK);
+ CompletionCallback callback;
+
+ predictor_->set_result(WebSocketDeflatePredictor::DO_NOT_DEFLATE);
+
+ {
+ InSequence s;
+ EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _))
+ .WillOnce(Invoke(&stub, &WriteFramesStub::Call));
+ }
+ ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+ const ScopedVector<WebSocketFrame>& frames_passed = *stub.frames();
+ ASSERT_EQ(2u, frames_passed.size());
+ EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_passed[0]->header.opcode);
+ EXPECT_FALSE(frames_passed[0]->header.final);
+ EXPECT_FALSE(frames_passed[0]->header.reserved1);
+ EXPECT_EQ("AAAA", ToString(frames_passed[0]));
+ EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation,
+ frames_passed[1]->header.opcode);
+ EXPECT_TRUE(frames_passed[1]->header.final);
+ EXPECT_FALSE(frames_passed[1]->header.reserved1);
+ EXPECT_EQ("AAA", ToString(frames_passed[1]));
+}
+
TEST_F(WebSocketDeflateStreamTest, LargeDeflatedFramesShouldBeSplit) {
WebSocketDeflater deflater(WebSocketDeflater::TAKE_OVER_CONTEXT);
LinearCongruentialGenerator lcg(133);
- WriteFramesStub stub(OK);
+ WriteFramesStub stub(predictor_, OK);
CompletionCallback callback;
const size_t size = 1024;
@@ -912,9 +1021,11 @@ TEST_F(WebSocketDeflateStreamTest, LargeDeflatedFramesShouldBeSplit) {
deflater.AddBytes(data.data(), data.size());
FrameFlag flag = is_final ? kFinal : kNoFlag;
AppendTo(&frames, WebSocketFrameHeader::kOpCodeBinary, flag, data);
+ predictor_->AddFramesToBeInput(frames);
ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
- for (size_t i = 0; i < stub.frames()->size(); ++i)
- total_compressed_frames.push_back((*stub.frames())[i]);
+ total_compressed_frames.insert(total_compressed_frames.end(),
+ stub.frames()->begin(),
+ stub.frames()->end());
stub.frames()->weak_clear();
if (is_final)
break;
@@ -945,7 +1056,8 @@ TEST_F(WebSocketDeflateStreamTest, WriteMultipleMessages) {
ScopedVector<WebSocketFrame> frames;
AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
- WriteFramesStub stub(OK);
+ predictor_->AddFramesToBeInput(frames);
+ WriteFramesStub stub(predictor_, OK);
CompletionCallback callback;
{
@@ -972,7 +1084,8 @@ TEST_F(WebSocketDeflateStreamWithDoNotTakeOverContextTest,
ScopedVector<WebSocketFrame> frames;
AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kFinal, "Hello");
- WriteFramesStub stub(OK);
+ predictor_->AddFramesToBeInput(frames);
+ WriteFramesStub stub(predictor_, OK);
CompletionCallback callback;
{
@@ -995,6 +1108,58 @@ TEST_F(WebSocketDeflateStreamWithDoNotTakeOverContextTest,
ToString(frames_passed[1]));
}
+// In order to check the stream works correctly for multiple
+// "PossiblyCompressedMessage"s, we test various messages at one test case.
+TEST_F(WebSocketDeflateStreamWithDoNotTakeOverContextTest,
+ WritePossiblyCompressMessages) {
+ ScopedVector<WebSocketFrame> frames;
+ AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kNoFlag, "He");
+ AppendTo(&frames, WebSocketFrameHeader::kOpCodeContinuation, kFinal, "llo");
+ AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kNoFlag, "AAAAAAAAAA");
+ AppendTo(&frames, WebSocketFrameHeader::kOpCodeContinuation, kFinal, "AA");
+ AppendTo(&frames, WebSocketFrameHeader::kOpCodeText, kNoFlag, "XX");
+ AppendTo(&frames, WebSocketFrameHeader::kOpCodeContinuation, kFinal, "YY");
+ predictor_->AddFramesToBeInput(frames);
+ WriteFramesStub stub(predictor_, OK);
+ CompletionCallback callback;
+ predictor_->set_result(WebSocketDeflatePredictor::TRY_DEFLATE);
+
+ {
+ InSequence s;
+ EXPECT_CALL(*mock_stream_, WriteFrames(&frames, _))
+ .WillOnce(Invoke(&stub, &WriteFramesStub::Call));
+ }
+ ASSERT_EQ(OK, deflate_stream_->WriteFrames(&frames, callback));
+ const ScopedVector<WebSocketFrame>& frames_passed = *stub.frames();
+ ASSERT_EQ(5u, frames_passed.size());
+
+ EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_passed[0]->header.opcode);
+ EXPECT_FALSE(frames_passed[0]->header.final);
+ EXPECT_FALSE(frames_passed[0]->header.reserved1);
+ EXPECT_EQ("He", ToString(frames_passed[0]));
+ EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation,
+ frames_passed[1]->header.opcode);
+ EXPECT_TRUE(frames_passed[1]->header.final);
+ EXPECT_FALSE(frames_passed[1]->header.reserved1);
+ EXPECT_EQ("llo", ToString(frames_passed[1]));
+
+ EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_passed[2]->header.opcode);
+ EXPECT_TRUE(frames_passed[2]->header.final);
+ EXPECT_TRUE(frames_passed[2]->header.reserved1);
+ EXPECT_EQ(std::string("\x72\x74\x44\x00\x00\x00", 6),
+ ToString(frames_passed[2]));
+
+ EXPECT_EQ(WebSocketFrameHeader::kOpCodeText, frames_passed[3]->header.opcode);
+ EXPECT_FALSE(frames_passed[3]->header.final);
+ EXPECT_FALSE(frames_passed[3]->header.reserved1);
+ EXPECT_EQ("XX", ToString(frames_passed[3]));
+ EXPECT_EQ(WebSocketFrameHeader::kOpCodeContinuation,
+ frames_passed[4]->header.opcode);
+ EXPECT_TRUE(frames_passed[4]->header.final);
+ EXPECT_FALSE(frames_passed[4]->header.reserved1);
+ EXPECT_EQ("YY", ToString(frames_passed[4]));
+}
+
} // namespace
} // namespace net
« net/websockets/websocket_deflate_predictor.h ('K') | « net/websockets/websocket_deflate_stream.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698