summaryrefslogtreecommitdiff
path: root/chromium/services/network/mdns_responder_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/services/network/mdns_responder_unittest.cc')
-rw-r--r--chromium/services/network/mdns_responder_unittest.cc103
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