|  | // Copyright (c) 2012 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 <string> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/bind_helpers.h" | 
|  | #include "base/callback.h" | 
|  | #include "base/message_loop/message_loop.h" | 
|  | #include "base/run_loop.h" | 
|  | #include "base/synchronization/waitable_event.h" | 
|  | #include "net/base/net_errors.h" | 
|  | #include "net/socket/socket.h" | 
|  | #include "remoting/protocol/fake_stream_socket.h" | 
|  | #include "remoting/protocol/message_reader.h" | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "third_party/webrtc/base/byteorder.h" | 
|  |  | 
|  | using testing::_; | 
|  | using testing::DoAll; | 
|  | using testing::Mock; | 
|  | using testing::SaveArg; | 
|  |  | 
|  | namespace remoting { | 
|  | namespace protocol { | 
|  |  | 
|  | namespace { | 
|  | const char kTestMessage1[] = "Message1"; | 
|  | const char kTestMessage2[] = "Message2"; | 
|  | }  // namespace | 
|  |  | 
|  | class MockMessageReceivedCallback { | 
|  | public: | 
|  | MOCK_METHOD0(OnMessage, void()); | 
|  | }; | 
|  |  | 
|  | class MessageReaderTest : public testing::Test { | 
|  | public: | 
|  | // Following two methods are used by the ReadFromCallback test. | 
|  | void AddSecondMessage() { AddMessage(kTestMessage2); } | 
|  |  | 
|  | // Used by the DeleteFromCallback() test. | 
|  | void DeleteReader() { reader_.reset(); } | 
|  |  | 
|  | protected: | 
|  | void SetUp() override { | 
|  | reader_.reset(new MessageReader()); | 
|  | } | 
|  |  | 
|  | void InitReader() { | 
|  | reader_->StartReading( | 
|  | &socket_, | 
|  | base::Bind(&MessageReaderTest::OnMessage, base::Unretained(this)), | 
|  | base::Bind(&MessageReaderTest::OnReadError, base::Unretained(this))); | 
|  | } | 
|  |  | 
|  | void AddMessage(const std::string& message) { | 
|  | std::string data = std::string(4, ' ') + message; | 
|  | rtc::SetBE32(const_cast<char*>(data.data()), message.size()); | 
|  |  | 
|  | socket_.AppendInputData(data); | 
|  | } | 
|  |  | 
|  | bool CompareResult(CompoundBuffer* buffer, const std::string& expected) { | 
|  | std::string result(buffer->total_bytes(), ' '); | 
|  | buffer->CopyTo(const_cast<char*>(result.data()), result.size()); | 
|  | return result == expected; | 
|  | } | 
|  |  | 
|  | void OnReadError(int error) { | 
|  | read_error_ = error; | 
|  | reader_.reset(); | 
|  | } | 
|  |  | 
|  | void OnMessage(std::unique_ptr<CompoundBuffer> buffer) { | 
|  | messages_.push_back(std::move(buffer)); | 
|  | callback_.OnMessage(); | 
|  | } | 
|  |  | 
|  | base::MessageLoop message_loop_; | 
|  | std::unique_ptr<MessageReader> reader_; | 
|  | FakeStreamSocket socket_; | 
|  | MockMessageReceivedCallback callback_; | 
|  | int read_error_ = 0; | 
|  | std::vector<std::unique_ptr<CompoundBuffer>> messages_; | 
|  | }; | 
|  |  | 
|  | // Receive one message. | 
|  | TEST_F(MessageReaderTest, OneMessage) { | 
|  | AddMessage(kTestMessage1); | 
|  |  | 
|  | EXPECT_CALL(callback_, OnMessage()).Times(1); | 
|  |  | 
|  | InitReader(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | EXPECT_TRUE(socket_.read_pending()); | 
|  | EXPECT_EQ(1U, messages_.size()); | 
|  | } | 
|  |  | 
|  | // Receive two messages in one packet. | 
|  | TEST_F(MessageReaderTest, TwoMessages_Together) { | 
|  | AddMessage(kTestMessage1); | 
|  | AddMessage(kTestMessage2); | 
|  |  | 
|  | EXPECT_CALL(callback_, OnMessage()).Times(2); | 
|  |  | 
|  | InitReader(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | Mock::VerifyAndClearExpectations(&callback_); | 
|  | Mock::VerifyAndClearExpectations(&socket_); | 
|  |  | 
|  | EXPECT_TRUE(CompareResult(messages_[0].get(), kTestMessage1)); | 
|  | EXPECT_TRUE(CompareResult(messages_[1].get(), kTestMessage2)); | 
|  |  | 
|  | EXPECT_TRUE(socket_.read_pending()); | 
|  | } | 
|  |  | 
|  | // Receive two messages in separate packets. | 
|  | TEST_F(MessageReaderTest, TwoMessages_Separately) { | 
|  | AddMessage(kTestMessage1); | 
|  |  | 
|  | EXPECT_CALL(callback_, OnMessage()) | 
|  | .Times(1); | 
|  |  | 
|  | InitReader(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | Mock::VerifyAndClearExpectations(&callback_); | 
|  | Mock::VerifyAndClearExpectations(&socket_); | 
|  |  | 
|  | EXPECT_TRUE(CompareResult(messages_[0].get(), kTestMessage1)); | 
|  |  | 
|  | EXPECT_TRUE(socket_.read_pending()); | 
|  |  | 
|  | // Write another message and verify that we receive it. | 
|  | EXPECT_CALL(callback_, OnMessage()) | 
|  | .Times(1); | 
|  | AddMessage(kTestMessage2); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | EXPECT_TRUE(CompareResult(messages_[1].get(), kTestMessage2)); | 
|  |  | 
|  | EXPECT_TRUE(socket_.read_pending()); | 
|  | } | 
|  |  | 
|  | // Read() returns error. | 
|  | TEST_F(MessageReaderTest, ReadError) { | 
|  | socket_.AppendReadError(net::ERR_FAILED); | 
|  |  | 
|  | EXPECT_CALL(callback_, OnMessage()).Times(0); | 
|  |  | 
|  | InitReader(); | 
|  |  | 
|  | EXPECT_EQ(net::ERR_FAILED, read_error_); | 
|  | EXPECT_FALSE(reader_); | 
|  | } | 
|  |  | 
|  | // Verify that we the OnMessage callback is not reentered. | 
|  | TEST_F(MessageReaderTest, ReadFromCallback) { | 
|  | AddMessage(kTestMessage1); | 
|  |  | 
|  | EXPECT_CALL(callback_, OnMessage()) | 
|  | .Times(2) | 
|  | .WillOnce(Invoke(this, &MessageReaderTest::AddSecondMessage)); | 
|  |  | 
|  | InitReader(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  |  | 
|  | EXPECT_TRUE(socket_.read_pending()); | 
|  | } | 
|  |  | 
|  | // Verify that we stop getting callbacks after deleting MessageReader. | 
|  | TEST_F(MessageReaderTest, DeleteFromCallback) { | 
|  | AddMessage(kTestMessage1); | 
|  | AddMessage(kTestMessage2); | 
|  |  | 
|  | // OnMessage() should never be called for the second message. | 
|  | EXPECT_CALL(callback_, OnMessage()) | 
|  | .Times(1) | 
|  | .WillOnce(Invoke(this, &MessageReaderTest::DeleteReader)); | 
|  |  | 
|  | InitReader(); | 
|  | base::RunLoop().RunUntilIdle(); | 
|  | } | 
|  |  | 
|  | }  // namespace protocol | 
|  | }  // namespace remoting |