1*3f982cf4SFabien Sanglard // Copyright 2019 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard
5*3f982cf4SFabien Sanglard #include "discovery/mdns/mdns_sender.h"
6*3f982cf4SFabien Sanglard
7*3f982cf4SFabien Sanglard #include <memory>
8*3f982cf4SFabien Sanglard #include <vector>
9*3f982cf4SFabien Sanglard
10*3f982cf4SFabien Sanglard #include "discovery/mdns/mdns_records.h"
11*3f982cf4SFabien Sanglard #include "gmock/gmock.h"
12*3f982cf4SFabien Sanglard #include "gtest/gtest.h"
13*3f982cf4SFabien Sanglard #include "platform/test/fake_udp_socket.h"
14*3f982cf4SFabien Sanglard #include "platform/test/mock_udp_socket.h"
15*3f982cf4SFabien Sanglard
16*3f982cf4SFabien Sanglard namespace openscreen {
17*3f982cf4SFabien Sanglard namespace discovery {
18*3f982cf4SFabien Sanglard
19*3f982cf4SFabien Sanglard using testing::_;
20*3f982cf4SFabien Sanglard using testing::Args;
21*3f982cf4SFabien Sanglard using testing::Return;
22*3f982cf4SFabien Sanglard using testing::StrictMock;
23*3f982cf4SFabien Sanglard using testing::WithArgs;
24*3f982cf4SFabien Sanglard
25*3f982cf4SFabien Sanglard namespace {
26*3f982cf4SFabien Sanglard
ACTION_P(VoidPointerMatchesBytes,expected_data)27*3f982cf4SFabien Sanglard ACTION_P(VoidPointerMatchesBytes, expected_data) {
28*3f982cf4SFabien Sanglard const uint8_t* actual_data = static_cast<const uint8_t*>(arg0);
29*3f982cf4SFabien Sanglard for (size_t i = 0; i < expected_data.size(); ++i) {
30*3f982cf4SFabien Sanglard EXPECT_EQ(actual_data[i], expected_data[i]);
31*3f982cf4SFabien Sanglard }
32*3f982cf4SFabien Sanglard }
33*3f982cf4SFabien Sanglard
34*3f982cf4SFabien Sanglard } // namespace
35*3f982cf4SFabien Sanglard
36*3f982cf4SFabien Sanglard class MdnsSenderTest : public testing::Test {
37*3f982cf4SFabien Sanglard public:
MdnsSenderTest()38*3f982cf4SFabien Sanglard MdnsSenderTest()
39*3f982cf4SFabien Sanglard : a_question_(DomainName{"testing", "local"},
40*3f982cf4SFabien Sanglard DnsType::kA,
41*3f982cf4SFabien Sanglard DnsClass::kIN,
42*3f982cf4SFabien Sanglard ResponseType::kMulticast),
43*3f982cf4SFabien Sanglard a_record_(DomainName{"testing", "local"},
44*3f982cf4SFabien Sanglard DnsType::kA,
45*3f982cf4SFabien Sanglard DnsClass::kIN,
46*3f982cf4SFabien Sanglard RecordType::kShared,
47*3f982cf4SFabien Sanglard std::chrono::seconds(120),
48*3f982cf4SFabien Sanglard ARecordRdata(IPAddress{172, 0, 0, 1})),
49*3f982cf4SFabien Sanglard query_message_(1, MessageType::Query),
50*3f982cf4SFabien Sanglard response_message_(1, MessageType::Response),
51*3f982cf4SFabien Sanglard ipv4_multicast_endpoint_{
52*3f982cf4SFabien Sanglard .address = IPAddress(kDefaultMulticastGroupIPv4),
53*3f982cf4SFabien Sanglard .port = kDefaultMulticastPort},
54*3f982cf4SFabien Sanglard ipv6_multicast_endpoint_{
55*3f982cf4SFabien Sanglard .address = IPAddress(kDefaultMulticastGroupIPv6),
56*3f982cf4SFabien Sanglard .port = kDefaultMulticastPort} {
57*3f982cf4SFabien Sanglard query_message_.AddQuestion(a_question_);
58*3f982cf4SFabien Sanglard response_message_.AddAnswer(a_record_);
59*3f982cf4SFabien Sanglard }
60*3f982cf4SFabien Sanglard
61*3f982cf4SFabien Sanglard protected:
62*3f982cf4SFabien Sanglard // clang-format off
63*3f982cf4SFabien Sanglard const std::vector<uint8_t> kQueryBytes = {
64*3f982cf4SFabien Sanglard 0x00, 0x01, // ID = 1
65*3f982cf4SFabien Sanglard 0x00, 0x00, // FLAGS = None
66*3f982cf4SFabien Sanglard 0x00, 0x01, // Question count
67*3f982cf4SFabien Sanglard 0x00, 0x00, // Answer count
68*3f982cf4SFabien Sanglard 0x00, 0x00, // Authority count
69*3f982cf4SFabien Sanglard 0x00, 0x00, // Additional count
70*3f982cf4SFabien Sanglard // Question
71*3f982cf4SFabien Sanglard 0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
72*3f982cf4SFabien Sanglard 0x05, 'l', 'o', 'c', 'a', 'l',
73*3f982cf4SFabien Sanglard 0x00,
74*3f982cf4SFabien Sanglard 0x00, 0x01, // TYPE = A (1)
75*3f982cf4SFabien Sanglard 0x00, 0x01, // CLASS = IN (1)
76*3f982cf4SFabien Sanglard };
77*3f982cf4SFabien Sanglard
78*3f982cf4SFabien Sanglard const std::vector<uint8_t> kResponseBytes = {
79*3f982cf4SFabien Sanglard 0x00, 0x01, // ID = 1
80*3f982cf4SFabien Sanglard 0x84, 0x00, // FLAGS = AA | RESPONSE
81*3f982cf4SFabien Sanglard 0x00, 0x00, // Question count
82*3f982cf4SFabien Sanglard 0x00, 0x01, // Answer count
83*3f982cf4SFabien Sanglard 0x00, 0x00, // Authority count
84*3f982cf4SFabien Sanglard 0x00, 0x00, // Additional count
85*3f982cf4SFabien Sanglard // Answer
86*3f982cf4SFabien Sanglard 0x07, 't', 'e', 's', 't', 'i', 'n', 'g',
87*3f982cf4SFabien Sanglard 0x05, 'l', 'o', 'c', 'a', 'l',
88*3f982cf4SFabien Sanglard 0x00,
89*3f982cf4SFabien Sanglard 0x00, 0x01, // TYPE = A (1)
90*3f982cf4SFabien Sanglard 0x00, 0x01, // CLASS = IN (1)
91*3f982cf4SFabien Sanglard 0x00, 0x00, 0x00, 0x78, // TTL = 120 seconds
92*3f982cf4SFabien Sanglard 0x00, 0x04, // RDLENGTH = 4 bytes
93*3f982cf4SFabien Sanglard 0xac, 0x00, 0x00, 0x01, // 172.0.0.1
94*3f982cf4SFabien Sanglard };
95*3f982cf4SFabien Sanglard // clang-format on
96*3f982cf4SFabien Sanglard
97*3f982cf4SFabien Sanglard MdnsQuestion a_question_;
98*3f982cf4SFabien Sanglard MdnsRecord a_record_;
99*3f982cf4SFabien Sanglard MdnsMessage query_message_;
100*3f982cf4SFabien Sanglard MdnsMessage response_message_;
101*3f982cf4SFabien Sanglard IPEndpoint ipv4_multicast_endpoint_;
102*3f982cf4SFabien Sanglard IPEndpoint ipv6_multicast_endpoint_;
103*3f982cf4SFabien Sanglard };
104*3f982cf4SFabien Sanglard
TEST_F(MdnsSenderTest,SendMulticast)105*3f982cf4SFabien Sanglard TEST_F(MdnsSenderTest, SendMulticast) {
106*3f982cf4SFabien Sanglard StrictMock<MockUdpSocket> socket;
107*3f982cf4SFabien Sanglard EXPECT_CALL(socket, IsIPv4()).WillRepeatedly(Return(true));
108*3f982cf4SFabien Sanglard EXPECT_CALL(socket, IsIPv6()).WillRepeatedly(Return(true));
109*3f982cf4SFabien Sanglard MdnsSender sender(&socket);
110*3f982cf4SFabien Sanglard EXPECT_CALL(socket, SendMessage(_, kQueryBytes.size(), _))
111*3f982cf4SFabien Sanglard .WillOnce(WithArgs<0>(VoidPointerMatchesBytes(kQueryBytes)));
112*3f982cf4SFabien Sanglard EXPECT_EQ(sender.SendMulticast(query_message_), Error::Code::kNone);
113*3f982cf4SFabien Sanglard }
114*3f982cf4SFabien Sanglard
TEST_F(MdnsSenderTest,SendUnicastIPv4)115*3f982cf4SFabien Sanglard TEST_F(MdnsSenderTest, SendUnicastIPv4) {
116*3f982cf4SFabien Sanglard IPEndpoint endpoint{.address = IPAddress{192, 168, 1, 1}, .port = 31337};
117*3f982cf4SFabien Sanglard
118*3f982cf4SFabien Sanglard StrictMock<MockUdpSocket> socket;
119*3f982cf4SFabien Sanglard MdnsSender sender(&socket);
120*3f982cf4SFabien Sanglard EXPECT_CALL(socket, SendMessage(_, kResponseBytes.size(), _))
121*3f982cf4SFabien Sanglard .WillOnce(WithArgs<0>(VoidPointerMatchesBytes(kResponseBytes)));
122*3f982cf4SFabien Sanglard EXPECT_EQ(sender.SendMessage(response_message_, endpoint),
123*3f982cf4SFabien Sanglard Error::Code::kNone);
124*3f982cf4SFabien Sanglard }
125*3f982cf4SFabien Sanglard
TEST_F(MdnsSenderTest,SendUnicastIPv6)126*3f982cf4SFabien Sanglard TEST_F(MdnsSenderTest, SendUnicastIPv6) {
127*3f982cf4SFabien Sanglard constexpr uint16_t kIPv6AddressHextets[] = {
128*3f982cf4SFabien Sanglard 0xfe80, 0x0000, 0x0000, 0x0000, 0x0202, 0xb3ff, 0xfe1e, 0x8329,
129*3f982cf4SFabien Sanglard };
130*3f982cf4SFabien Sanglard IPEndpoint endpoint{.address = IPAddress(kIPv6AddressHextets), .port = 31337};
131*3f982cf4SFabien Sanglard
132*3f982cf4SFabien Sanglard StrictMock<MockUdpSocket> socket;
133*3f982cf4SFabien Sanglard MdnsSender sender(&socket);
134*3f982cf4SFabien Sanglard EXPECT_CALL(socket, SendMessage(_, kResponseBytes.size(), _))
135*3f982cf4SFabien Sanglard .WillOnce(WithArgs<0>(VoidPointerMatchesBytes(kResponseBytes)));
136*3f982cf4SFabien Sanglard EXPECT_EQ(sender.SendMessage(response_message_, endpoint),
137*3f982cf4SFabien Sanglard Error::Code::kNone);
138*3f982cf4SFabien Sanglard }
139*3f982cf4SFabien Sanglard
TEST_F(MdnsSenderTest,MessageTooBig)140*3f982cf4SFabien Sanglard TEST_F(MdnsSenderTest, MessageTooBig) {
141*3f982cf4SFabien Sanglard MdnsMessage big_message_(1, MessageType::Query);
142*3f982cf4SFabien Sanglard for (size_t i = 0; i < 100; ++i) {
143*3f982cf4SFabien Sanglard big_message_.AddQuestion(a_question_);
144*3f982cf4SFabien Sanglard big_message_.AddAnswer(a_record_);
145*3f982cf4SFabien Sanglard }
146*3f982cf4SFabien Sanglard
147*3f982cf4SFabien Sanglard StrictMock<MockUdpSocket> socket;
148*3f982cf4SFabien Sanglard EXPECT_CALL(socket, IsIPv4()).WillRepeatedly(Return(true));
149*3f982cf4SFabien Sanglard EXPECT_CALL(socket, IsIPv6()).WillRepeatedly(Return(true));
150*3f982cf4SFabien Sanglard MdnsSender sender(&socket);
151*3f982cf4SFabien Sanglard EXPECT_EQ(sender.SendMulticast(big_message_),
152*3f982cf4SFabien Sanglard Error::Code::kInsufficientBuffer);
153*3f982cf4SFabien Sanglard }
154*3f982cf4SFabien Sanglard
TEST_F(MdnsSenderTest,ReturnsErrorOnSocketFailure)155*3f982cf4SFabien Sanglard TEST_F(MdnsSenderTest, ReturnsErrorOnSocketFailure) {
156*3f982cf4SFabien Sanglard FakeUdpSocket::MockClient socket_client;
157*3f982cf4SFabien Sanglard FakeUdpSocket socket(nullptr, &socket_client);
158*3f982cf4SFabien Sanglard MdnsSender sender(&socket);
159*3f982cf4SFabien Sanglard Error error = Error(Error::Code::kConnectionFailed, "error message");
160*3f982cf4SFabien Sanglard socket.EnqueueSendResult(error);
161*3f982cf4SFabien Sanglard EXPECT_CALL(socket_client, OnSendError(_, error)).Times(1);
162*3f982cf4SFabien Sanglard EXPECT_EQ(sender.SendMulticast(query_message_), Error::Code::kNone);
163*3f982cf4SFabien Sanglard EXPECT_EQ(socket.send_queue_size(), size_t{0});
164*3f982cf4SFabien Sanglard }
165*3f982cf4SFabien Sanglard
166*3f982cf4SFabien Sanglard } // namespace discovery
167*3f982cf4SFabien Sanglard } // namespace openscreen
168