diff options
Diffstat (limited to 'chromium/services/network/mdns_responder_unittest.cc')
-rw-r--r-- | chromium/services/network/mdns_responder_unittest.cc | 103 |
1 files changed, 100 insertions, 3 deletions
diff --git a/chromium/services/network/mdns_responder_unittest.cc b/chromium/services/network/mdns_responder_unittest.cc index 94d3d9db5f0..16f10eb8494 100644 --- a/chromium/services/network/mdns_responder_unittest.cc +++ b/chromium/services/network/mdns_responder_unittest.cc @@ -31,10 +31,11 @@ namespace network { namespace { +using ::testing::_; +using ::testing::AnyNumber; using ::testing::Invoke; using ::testing::NiceMock; using ::testing::Return; -using ::testing::_; using ServiceError = MdnsResponderManager::ServiceError; const net::IPAddress kPublicAddrs[2] = {net::IPAddress(11, 11, 11, 11), @@ -107,6 +108,37 @@ class MockFailingMdnsSocketFactory : public net::MDnsSocketFactory { return -1; } + // Emulates IO blocking in sending packets if |BlockSend()| is called, in + // which case the completion callback is not invoked until |ResumeSend()| is + // called. + int MaybeBlockSend(const std::string& packet, + const std::string& address, + net::CompletionRepeatingCallback callback) { + OnSendTo(packet); + if (block_send_) { + blocked_packet_size_ = packet.size(); + blocked_send_callback_ = std::move(callback); + } else { + task_runner_->PostTask( + FROM_HERE, + base::BindOnce([](net::CompletionRepeatingCallback callback, + size_t packet_size) { callback.Run(packet_size); }, + callback, packet.size())); + } + return -1; + } + + void BlockSend() { + DCHECK(!block_send_); + block_send_ = true; + } + + void ResumeSend() { + DCHECK(block_send_); + block_send_ = false; + blocked_send_callback_.Run(blocked_packet_size_); + } + // Emulates the asynchronous contract of invoking |callback| in the RecvFrom // primitive but failed receiving; int FailToRecv(net::IOBuffer* buffer, @@ -122,6 +154,9 @@ class MockFailingMdnsSocketFactory : public net::MDnsSocketFactory { } private: + bool block_send_ = false; + size_t blocked_packet_size_ = 0; + net::CompletionRepeatingCallback blocked_send_callback_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_; }; @@ -283,6 +318,14 @@ class MdnsResponderTest : public testing::Test { Reset(); } + ~MdnsResponderTest() { + // Goodbye messages are scheduled when the responder service |host_manager_| + // is destroyed and can be synchronously sent if the rate limiting permits. + // See ResponseScheduler::DispatchPendingPackets(). + EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(AnyNumber()); + EXPECT_CALL(failing_socket_factory_, OnSendTo(_)).Times(AnyNumber()); + } + void Reset(bool use_failing_socket_factory = false) { client_[0].reset(); client_[1].reset(); @@ -365,12 +408,12 @@ class MdnsResponderTest : public testing::Test { base::test::ScopedTaskEnvironment scoped_task_environment_{ base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME}; - mojom::MdnsResponderPtr client_[2]; - std::unique_ptr<MdnsResponderManager> host_manager_; // Overrides the current thread task runner, so we can simulate the passage // of time and avoid any actual sleeps. NiceMock<net::MockMDnsSocketFactory> socket_factory_; NiceMock<MockFailingMdnsSocketFactory> failing_socket_factory_; + mojom::MdnsResponderPtr client_[2]; + std::unique_ptr<MdnsResponderManager> host_manager_; std::string last_name_created_; }; @@ -1013,4 +1056,58 @@ TEST_F(MdnsResponderTest, ManagerCanRestartAfterAllSocketHandlersFailToRead) { tester.ExpectTotalCount(kServiceErrorHistogram, 2); } +// Test that sending packets on an interface can be blocked by an incomplete +// send on the same interface. Blocked packets are later flushed when sending is +// unblocked. +TEST_F(MdnsResponderTest, IncompleteSendBlocksFollowingSends) { + auto create_send_blocking_socket = + [this](std::vector<std::unique_ptr<net::DatagramServerSocket>>* sockets) { + auto socket = + std::make_unique<NiceMock<net::MockMDnsDatagramServerSocket>>( + net::ADDRESS_FAMILY_IPV4); + + ON_CALL(*socket, SendToInternal(_, _, _)) + .WillByDefault( + Invoke(&failing_socket_factory_, + &MockFailingMdnsSocketFactory::MaybeBlockSend)); + ON_CALL(*socket, RecvFromInternal(_, _, _, _)) + .WillByDefault(Return(-1)); + + sockets->push_back(std::move(socket)); + }; + EXPECT_CALL(failing_socket_factory_, CreateSockets(_)) + .WillOnce(Invoke(create_send_blocking_socket)); + Reset(true /* use_failing_socket_factory */); + + const auto& addr1 = kPublicAddrs[0]; + std::string expected_announcement1 = + CreateResolutionResponse(kDefaultTtl, {{"0.local", addr1}}); + // Mocked CreateSockets above only creates one socket. + // We schedule to send the announcement for |kNumAnnouncementsPerInterface| + // times but the second announcement is blocked by the first one in this case. + EXPECT_CALL(failing_socket_factory_, OnSendTo(expected_announcement1)) + .Times(1); + failing_socket_factory_.BlockSend(); + const auto name1 = CreateNameForAddress(0, addr1); + RunUntilNoTasksRemain(); + + const auto& addr2 = kPublicAddrs[1]; + std::string expected_announcement2 = + CreateResolutionResponse(kDefaultTtl, {{"1.local", addr2}}); + // The announcement for the following name should also be blocked. + const auto name2 = CreateNameForAddress(0, addr2); + EXPECT_CALL(failing_socket_factory_, OnSendTo(expected_announcement2)) + .Times(0); + RunUntilNoTasksRemain(); + + // We later unblock sending packets. Previously scheduled announcements should + // be flushed. + EXPECT_CALL(failing_socket_factory_, OnSendTo(expected_announcement1)) + .Times(kNumAnnouncementsPerInterface - 1); + EXPECT_CALL(failing_socket_factory_, OnSendTo(expected_announcement2)) + .Times(kNumAnnouncementsPerInterface); + failing_socket_factory_.ResumeSend(); + RunUntilNoTasksRemain(); +} + } // namespace network |