text: // Copyright 2015 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 "remoting/protocol/client_video_dispatcher.h"
  
  #include <memory>
  #include <vector>
  
  #include "base/bind.h"
  #include "base/message_loop/message_loop.h"
  #include "base/run_loop.h"
  #include "remoting/base/buffered_socket_writer.h"
  #include "remoting/base/constants.h"
  #include "remoting/proto/video.pb.h"
  #include "remoting/protocol/fake_stream_socket.h"
  #include "remoting/protocol/message_reader.h"
  #include "remoting/protocol/message_serialization.h"
  #include "remoting/protocol/protocol_mock_objects.h"
  #include "remoting/protocol/stream_message_pipe_adapter.h"
  #include "remoting/protocol/video_stub.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  namespace remoting {
  namespace protocol {
  
  class ClientVideoDispatcherTest : public testing::Test,
                                    public VideoStub,
                                    public ChannelDispatcherBase::EventHandler {
   public:
    ClientVideoDispatcherTest();
  
    // VideoStub interface.
    void ProcessVideoPacket(std::unique_ptr<VideoPacket> video_packet,
                            const base::Closure& done) override;
  
    // ChannelDispatcherBase::EventHandler interface.
    void OnChannelInitialized(ChannelDispatcherBase* channel_dispatcher) override;
    void OnChannelClosed(ChannelDispatcherBase* channel_dispatcher) override;
  
   protected:
    void OnChannelError(int error);
  
    void OnMessageReceived(std::unique_ptr<CompoundBuffer> buffer);
    void OnReadError(int error);
  
    base::MessageLoop message_loop_;
  
    // Set to true in OnChannelInitialized().
    bool initialized_ = false;
  
    // Client side.
    FakeStreamChannelFactory client_channel_factory_;
    StreamMessageChannelFactoryAdapter channel_factory_adapter_;
    MockClientStub client_stub_;
    ClientVideoDispatcher dispatcher_;
  
    // Host side.
    FakeStreamSocket host_socket_;
    MessageReader reader_;
    BufferedSocketWriter writer_;
  
    std::vector<std::unique_ptr<VideoPacket>> video_packets_;
    std::vector<base::Closure> packet_done_callbacks_;
  
    std::vector<std::unique_ptr<VideoAck>> ack_messages_;
  };
  
  ClientVideoDispatcherTest::ClientVideoDispatcherTest()
      : channel_factory_adapter_(
            &client_channel_factory_,
            base::Bind(&ClientVideoDispatcherTest::OnChannelError,
                       base::Unretained(this))),
        dispatcher_(this, &client_stub_) {
    dispatcher_.Init(&channel_factory_adapter_, this);
    base::RunLoop().RunUntilIdle();
    DCHECK(initialized_);
    host_socket_.PairWith(
        client_channel_factory_.GetFakeChannel(kVideoChannelName));
    reader_.StartReading(&host_socket_,
                         base::Bind(&ClientVideoDispatcherTest::OnMessageReceived,
                                    base::Unretained(this)),
                         base::Bind(&ClientVideoDispatcherTest::OnReadError,
                                    base::Unretained(this)));
    writer_.Start(
        base::Bind(&P2PStreamSocket::Write, base::Unretained(&host_socket_)),
        BufferedSocketWriter::WriteFailedCallback());
  }
  
  void ClientVideoDispatcherTest::ProcessVideoPacket(
      std::unique_ptr<VideoPacket> video_packet,
      const base::Closure& done) {
    video_packets_.push_back(std::move(video_packet));
    packet_done_callbacks_.push_back(done);
  }
  
  void ClientVideoDispatcherTest::OnChannelInitialized(
      ChannelDispatcherBase* channel_dispatcher) {
    initialized_ = true;
  }
  
  void ClientVideoDispatcherTest::OnChannelClosed(
      ChannelDispatcherBase* channel_dispatcher) {
    // Don't expect channels to be closed.
    FAIL();
  }
  
  void ClientVideoDispatcherTest::OnChannelError(int error) {
    // Don't expect channel creation to fail.
    FAIL();
  }
  
  void ClientVideoDispatcherTest::OnMessageReceived(
      std::unique_ptr<CompoundBuffer> buffer) {
    std::unique_ptr<VideoAck> ack = ParseMessage<VideoAck>(buffer.get());
    EXPECT_TRUE(ack);
    ack_messages_.push_back(std::move(ack));
  }
  
  void ClientVideoDispatcherTest::OnReadError(int error) {
    LOG(FATAL) << "Unexpected read error: " << error;
  }
  
  // Verify that the client can receive video packets and acks are not sent for
  // VideoPackets that don't have frame_id field set.
  TEST_F(ClientVideoDispatcherTest, WithoutAcks) {
    VideoPacket packet;
    packet.set_data(std::string());
  
    // Send a VideoPacket and verify that the client receives it.
    writer_.Write(SerializeAndFrameMessage(packet), base::Closure());
    base::RunLoop().RunUntilIdle();
    EXPECT_EQ(1U, video_packets_.size());
  
    packet_done_callbacks_.front().Run();
    base::RunLoop().RunUntilIdle();
  
    // Ack should never be sent for the packet without frame_id.
    EXPECT_TRUE(ack_messages_.empty());
  }
  
  // Verifies that the dispatcher sends Ack message with correct rendering delay.
  TEST_F(ClientVideoDispatcherTest, WithAcks) {
    int kTestFrameId = 3;
  
    VideoPacket packet;
    packet.set_data(std::string());
    packet.set_frame_id(kTestFrameId);
  
    // Send a VideoPacket and verify that the client receives it.
    writer_.Write(SerializeAndFrameMessage(packet), base::Closure());
    base::RunLoop().RunUntilIdle();
    EXPECT_EQ(1U, video_packets_.size());
  
    // Ack should only be sent after the packet is processed.
    EXPECT_TRUE(ack_messages_.empty());
    base::RunLoop().RunUntilIdle();
  
    // Fake completion of video packet decoding, to trigger the Ack.
    packet_done_callbacks_.front().Run();
    base::RunLoop().RunUntilIdle();
  
    // Verify that the Ack message has been received.
    ASSERT_EQ(1U, ack_messages_.size());
    EXPECT_EQ(kTestFrameId, ack_messages_[0]->frame_id());
  }
  
  // Verifies that the dispatcher properly synthesizes VideoLayout message when
  // screen size changes.
  TEST_F(ClientVideoDispatcherTest, VideoLayout) {
    const int kScreenSize = 100;
    const float kScaleFactor = 2.0;
  
    VideoPacket packet;
    packet.set_data(std::string());
    packet.set_frame_id(42);
    packet.mutable_format()->set_screen_width(kScreenSize);
    packet.mutable_format()->set_screen_height(kScreenSize);
    packet.mutable_format()->set_x_dpi(kDefaultDpi * kScaleFactor);
    packet.mutable_format()->set_y_dpi(kDefaultDpi * kScaleFactor);
  
    VideoLayout layout;
    EXPECT_CALL(client_stub_, SetVideoLayout(testing::_))
        .WillOnce(testing::SaveArg<0>(&layout));
  
    // Send a VideoPacket and verify that the client receives it.
    writer_.Write(SerializeAndFrameMessage(packet), base::Closure());
    base::RunLoop().RunUntilIdle();
  
    ASSERT_EQ(1, layout.video_track_size());
    EXPECT_EQ(0, layout.video_track(0).position_x());
    EXPECT_EQ(0, layout.video_track(0).position_y());
    EXPECT_EQ(kScreenSize / kScaleFactor, layout.video_track(0).width());
    EXPECT_EQ(kScreenSize / kScaleFactor, layout.video_track(0).height());
    EXPECT_EQ(kDefaultDpi * kScaleFactor, layout.video_track(0).x_dpi());
    EXPECT_EQ(kDefaultDpi * kScaleFactor, layout.video_track(0).y_dpi());
  }
  
  // Verify that Ack messages are sent in correct order.
  TEST_F(ClientVideoDispatcherTest, AcksOrder) {
    int kTestFrameId = 3;
  
    VideoPacket packet;
    packet.set_data(std::string());
    packet.set_frame_id(kTestFrameId);
  
    // Send two VideoPackets.
    writer_.Write(SerializeAndFrameMessage(packet), base::Closure());
    base::RunLoop().RunUntilIdle();
  
    packet.set_frame_id(kTestFrameId + 1);
    writer_.Write(SerializeAndFrameMessage(packet), base::Closure());
    base::RunLoop().RunUntilIdle();
  
    EXPECT_EQ(2U, video_packets_.size());
    EXPECT_TRUE(ack_messages_.empty());
  
    // Call completion callbacks in revers order.
    packet_done_callbacks_[1].Run();
    packet_done_callbacks_[0].Run();
  
    base::RunLoop().RunUntilIdle();
  
    // Verify order of Ack messages.
    ASSERT_EQ(2U, ack_messages_.size());
    EXPECT_EQ(kTestFrameId, ack_messages_[0]->frame_id());
    EXPECT_EQ(kTestFrameId + 1, ack_messages_[1]->frame_id());
  }
  
  }  // namespace protocol
  }  // namespace remoting
  