|  | // Copyright (c) 2019 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 "quic/qbone/bonnet/tun_device_packet_exchanger.h" | 
|  |  | 
|  | #include "quic/platform/api/quic_test.h" | 
|  | #include "quic/qbone/bonnet/mock_packet_exchanger_stats_interface.h" | 
|  | #include "quic/qbone/mock_qbone_client.h" | 
|  | #include "quic/qbone/platform/mock_kernel.h" | 
|  |  | 
|  | namespace quic { | 
|  | namespace { | 
|  |  | 
|  | const size_t kMtu = 1000; | 
|  | const size_t kMaxPendingPackets = 5; | 
|  | const int kFd = 15; | 
|  |  | 
|  | using ::testing::_; | 
|  | using ::testing::Invoke; | 
|  | using ::testing::StrEq; | 
|  | using ::testing::StrictMock; | 
|  |  | 
|  | class MockVisitor : public QbonePacketExchanger::Visitor { | 
|  | public: | 
|  | MOCK_METHOD(void, OnReadError, (const std::string&), (override)); | 
|  | MOCK_METHOD(void, OnWriteError, (const std::string&), (override)); | 
|  | }; | 
|  |  | 
|  | class TunDevicePacketExchangerTest : public QuicTest { | 
|  | protected: | 
|  | TunDevicePacketExchangerTest() | 
|  | : exchanger_(kMtu, &mock_kernel_, nullptr, &mock_visitor_, | 
|  | kMaxPendingPackets, false, &mock_stats_, | 
|  | absl::string_view()) { | 
|  | exchanger_.set_file_descriptor(kFd); | 
|  | } | 
|  |  | 
|  | ~TunDevicePacketExchangerTest() override = default; | 
|  |  | 
|  | MockKernel mock_kernel_; | 
|  | StrictMock<MockVisitor> mock_visitor_; | 
|  | StrictMock<MockQboneClient> mock_client_; | 
|  | StrictMock<MockPacketExchangerStatsInterface> mock_stats_; | 
|  | TunDevicePacketExchanger exchanger_; | 
|  | }; | 
|  |  | 
|  | TEST_F(TunDevicePacketExchangerTest, WritePacketReturnsFalseOnError) { | 
|  | std::string packet = "fake packet"; | 
|  | EXPECT_CALL(mock_kernel_, write(kFd, _, packet.size())) | 
|  | .WillOnce(Invoke([](int fd, const void* buf, size_t count) { | 
|  | errno = ECOMM; | 
|  | return -1; | 
|  | })); | 
|  |  | 
|  | EXPECT_CALL(mock_visitor_, OnWriteError(_)); | 
|  | exchanger_.WritePacketToNetwork(packet.data(), packet.size()); | 
|  | } | 
|  |  | 
|  | TEST_F(TunDevicePacketExchangerTest, | 
|  | WritePacketReturnFalseAndBlockedOnBlockedTunnel) { | 
|  | std::string packet = "fake packet"; | 
|  | EXPECT_CALL(mock_kernel_, write(kFd, _, packet.size())) | 
|  | .WillOnce(Invoke([](int fd, const void* buf, size_t count) { | 
|  | errno = EAGAIN; | 
|  | return -1; | 
|  | })); | 
|  |  | 
|  | EXPECT_CALL(mock_stats_, OnWriteError(_)).Times(1); | 
|  | exchanger_.WritePacketToNetwork(packet.data(), packet.size()); | 
|  | } | 
|  |  | 
|  | TEST_F(TunDevicePacketExchangerTest, WritePacketReturnsTrueOnSuccessfulWrite) { | 
|  | std::string packet = "fake packet"; | 
|  | EXPECT_CALL(mock_kernel_, write(kFd, _, packet.size())) | 
|  | .WillOnce(Invoke([packet](int fd, const void* buf, size_t count) { | 
|  | EXPECT_THAT(reinterpret_cast<const char*>(buf), StrEq(packet)); | 
|  | return count; | 
|  | })); | 
|  |  | 
|  | EXPECT_CALL(mock_stats_, OnPacketWritten(_)).Times(1); | 
|  | exchanger_.WritePacketToNetwork(packet.data(), packet.size()); | 
|  | } | 
|  |  | 
|  | TEST_F(TunDevicePacketExchangerTest, ReadPacketReturnsNullOnError) { | 
|  | EXPECT_CALL(mock_kernel_, read(kFd, _, kMtu)) | 
|  | .WillOnce(Invoke([](int fd, void* buf, size_t count) { | 
|  | errno = ECOMM; | 
|  | return -1; | 
|  | })); | 
|  | EXPECT_CALL(mock_visitor_, OnReadError(_)); | 
|  | exchanger_.ReadAndDeliverPacket(&mock_client_); | 
|  | } | 
|  |  | 
|  | TEST_F(TunDevicePacketExchangerTest, ReadPacketReturnsNullOnBlockedRead) { | 
|  | EXPECT_CALL(mock_kernel_, read(kFd, _, kMtu)) | 
|  | .WillOnce(Invoke([](int fd, void* buf, size_t count) { | 
|  | errno = EAGAIN; | 
|  | return -1; | 
|  | })); | 
|  | EXPECT_CALL(mock_stats_, OnReadError(_)).Times(1); | 
|  | EXPECT_FALSE(exchanger_.ReadAndDeliverPacket(&mock_client_)); | 
|  | } | 
|  |  | 
|  | TEST_F(TunDevicePacketExchangerTest, | 
|  | ReadPacketReturnsThePacketOnSuccessfulRead) { | 
|  | std::string packet = "fake_packet"; | 
|  | EXPECT_CALL(mock_kernel_, read(kFd, _, kMtu)) | 
|  | .WillOnce(Invoke([packet](int fd, void* buf, size_t count) { | 
|  | memcpy(buf, packet.data(), packet.size()); | 
|  | return packet.size(); | 
|  | })); | 
|  | EXPECT_CALL(mock_client_, ProcessPacketFromNetwork(StrEq(packet))); | 
|  | EXPECT_CALL(mock_stats_, OnPacketRead(_)).Times(1); | 
|  | EXPECT_TRUE(exchanger_.ReadAndDeliverPacket(&mock_client_)); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace quic |