xref: /aosp_15_r20/external/ot-br-posix/tests/gtest/test_mdns_subscribe.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1*4a64e381SAndroid Build Coastguard Worker /*
2*4a64e381SAndroid Build Coastguard Worker  *    Copyright (c) 2023, The OpenThread Authors.
3*4a64e381SAndroid Build Coastguard Worker  *    All rights reserved.
4*4a64e381SAndroid Build Coastguard Worker  *
5*4a64e381SAndroid Build Coastguard Worker  *    Redistribution and use in source and binary forms, with or without
6*4a64e381SAndroid Build Coastguard Worker  *    modification, are permitted provided that the following conditions are met:
7*4a64e381SAndroid Build Coastguard Worker  *    1. Redistributions of source code must retain the above copyright
8*4a64e381SAndroid Build Coastguard Worker  *       notice, this list of conditions and the following disclaimer.
9*4a64e381SAndroid Build Coastguard Worker  *    2. Redistributions in binary form must reproduce the above copyright
10*4a64e381SAndroid Build Coastguard Worker  *       notice, this list of conditions and the following disclaimer in the
11*4a64e381SAndroid Build Coastguard Worker  *       documentation and/or other materials provided with the distribution.
12*4a64e381SAndroid Build Coastguard Worker  *    3. Neither the name of the copyright holder nor the
13*4a64e381SAndroid Build Coastguard Worker  *       names of its contributors may be used to endorse or promote products
14*4a64e381SAndroid Build Coastguard Worker  *       derived from this software without specific prior written permission.
15*4a64e381SAndroid Build Coastguard Worker  *
16*4a64e381SAndroid Build Coastguard Worker  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*4a64e381SAndroid Build Coastguard Worker  *    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*4a64e381SAndroid Build Coastguard Worker  *    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*4a64e381SAndroid Build Coastguard Worker  *    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*4a64e381SAndroid Build Coastguard Worker  *    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*4a64e381SAndroid Build Coastguard Worker  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*4a64e381SAndroid Build Coastguard Worker  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*4a64e381SAndroid Build Coastguard Worker  *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*4a64e381SAndroid Build Coastguard Worker  *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*4a64e381SAndroid Build Coastguard Worker  *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*4a64e381SAndroid Build Coastguard Worker  *    POSSIBILITY OF SUCH DAMAGE.
27*4a64e381SAndroid Build Coastguard Worker  */
28*4a64e381SAndroid Build Coastguard Worker 
29*4a64e381SAndroid Build Coastguard Worker #include <gtest/gtest.h>
30*4a64e381SAndroid Build Coastguard Worker #include <limits.h>
31*4a64e381SAndroid Build Coastguard Worker #include <netinet/in.h>
32*4a64e381SAndroid Build Coastguard Worker #include <signal.h>
33*4a64e381SAndroid Build Coastguard Worker 
34*4a64e381SAndroid Build Coastguard Worker #include <set>
35*4a64e381SAndroid Build Coastguard Worker #include <vector>
36*4a64e381SAndroid Build Coastguard Worker 
37*4a64e381SAndroid Build Coastguard Worker #include "common/mainloop.hpp"
38*4a64e381SAndroid Build Coastguard Worker #include "common/mainloop_manager.hpp"
39*4a64e381SAndroid Build Coastguard Worker #include "mdns/mdns.hpp"
40*4a64e381SAndroid Build Coastguard Worker 
41*4a64e381SAndroid Build Coastguard Worker using namespace otbr;
42*4a64e381SAndroid Build Coastguard Worker using namespace otbr::Mdns;
43*4a64e381SAndroid Build Coastguard Worker 
44*4a64e381SAndroid Build Coastguard Worker static constexpr int kTimeoutSeconds = 3;
45*4a64e381SAndroid Build Coastguard Worker 
RunMainloopUntilTimeout(int aSeconds)46*4a64e381SAndroid Build Coastguard Worker int RunMainloopUntilTimeout(int aSeconds)
47*4a64e381SAndroid Build Coastguard Worker {
48*4a64e381SAndroid Build Coastguard Worker     using namespace otbr;
49*4a64e381SAndroid Build Coastguard Worker 
50*4a64e381SAndroid Build Coastguard Worker     int  rval      = 0;
51*4a64e381SAndroid Build Coastguard Worker     auto beginTime = Clock::now();
52*4a64e381SAndroid Build Coastguard Worker 
53*4a64e381SAndroid Build Coastguard Worker     while (true)
54*4a64e381SAndroid Build Coastguard Worker     {
55*4a64e381SAndroid Build Coastguard Worker         MainloopContext mainloop;
56*4a64e381SAndroid Build Coastguard Worker 
57*4a64e381SAndroid Build Coastguard Worker         mainloop.mMaxFd   = -1;
58*4a64e381SAndroid Build Coastguard Worker         mainloop.mTimeout = {1, 0};
59*4a64e381SAndroid Build Coastguard Worker         FD_ZERO(&mainloop.mReadFdSet);
60*4a64e381SAndroid Build Coastguard Worker         FD_ZERO(&mainloop.mWriteFdSet);
61*4a64e381SAndroid Build Coastguard Worker         FD_ZERO(&mainloop.mErrorFdSet);
62*4a64e381SAndroid Build Coastguard Worker 
63*4a64e381SAndroid Build Coastguard Worker         MainloopManager::GetInstance().Update(mainloop);
64*4a64e381SAndroid Build Coastguard Worker         rval = select(mainloop.mMaxFd + 1, &mainloop.mReadFdSet, &mainloop.mWriteFdSet, &mainloop.mErrorFdSet,
65*4a64e381SAndroid Build Coastguard Worker                       (mainloop.mTimeout.tv_sec == INT_MAX ? nullptr : &mainloop.mTimeout));
66*4a64e381SAndroid Build Coastguard Worker 
67*4a64e381SAndroid Build Coastguard Worker         if (rval < 0)
68*4a64e381SAndroid Build Coastguard Worker         {
69*4a64e381SAndroid Build Coastguard Worker             perror("select");
70*4a64e381SAndroid Build Coastguard Worker             break;
71*4a64e381SAndroid Build Coastguard Worker         }
72*4a64e381SAndroid Build Coastguard Worker 
73*4a64e381SAndroid Build Coastguard Worker         MainloopManager::GetInstance().Process(mainloop);
74*4a64e381SAndroid Build Coastguard Worker 
75*4a64e381SAndroid Build Coastguard Worker         if (Clock::now() - beginTime >= std::chrono::seconds(aSeconds))
76*4a64e381SAndroid Build Coastguard Worker         {
77*4a64e381SAndroid Build Coastguard Worker             break;
78*4a64e381SAndroid Build Coastguard Worker         }
79*4a64e381SAndroid Build Coastguard Worker     }
80*4a64e381SAndroid Build Coastguard Worker 
81*4a64e381SAndroid Build Coastguard Worker     return rval;
82*4a64e381SAndroid Build Coastguard Worker }
83*4a64e381SAndroid Build Coastguard Worker 
AsSet(const Container & aContainer)84*4a64e381SAndroid Build Coastguard Worker template <typename Container> std::set<typename Container::value_type> AsSet(const Container &aContainer)
85*4a64e381SAndroid Build Coastguard Worker {
86*4a64e381SAndroid Build Coastguard Worker     return std::set<typename Container::value_type>(aContainer.begin(), aContainer.end());
87*4a64e381SAndroid Build Coastguard Worker }
88*4a64e381SAndroid Build Coastguard Worker 
NoOpCallback(void)89*4a64e381SAndroid Build Coastguard Worker Publisher::ResultCallback NoOpCallback(void)
90*4a64e381SAndroid Build Coastguard Worker {
91*4a64e381SAndroid Build Coastguard Worker     return [](otbrError aError) { OTBR_UNUSED_VARIABLE(aError); };
92*4a64e381SAndroid Build Coastguard Worker }
93*4a64e381SAndroid Build Coastguard Worker 
AsTxtMap(const Publisher::TxtData & aTxtData)94*4a64e381SAndroid Build Coastguard Worker std::map<std::string, std::vector<uint8_t>> AsTxtMap(const Publisher::TxtData &aTxtData)
95*4a64e381SAndroid Build Coastguard Worker {
96*4a64e381SAndroid Build Coastguard Worker     Publisher::TxtList                          txtList;
97*4a64e381SAndroid Build Coastguard Worker     std::map<std::string, std::vector<uint8_t>> map;
98*4a64e381SAndroid Build Coastguard Worker 
99*4a64e381SAndroid Build Coastguard Worker     Publisher::DecodeTxtData(txtList, aTxtData.data(), aTxtData.size());
100*4a64e381SAndroid Build Coastguard Worker     for (const auto &entry : txtList)
101*4a64e381SAndroid Build Coastguard Worker     {
102*4a64e381SAndroid Build Coastguard Worker         map[entry.mKey] = entry.mValue;
103*4a64e381SAndroid Build Coastguard Worker     }
104*4a64e381SAndroid Build Coastguard Worker 
105*4a64e381SAndroid Build Coastguard Worker     return map;
106*4a64e381SAndroid Build Coastguard Worker }
107*4a64e381SAndroid Build Coastguard Worker 
108*4a64e381SAndroid Build Coastguard Worker Publisher::TxtList sTxtList1{{"a", "1"}, {"b", "2"}};
109*4a64e381SAndroid Build Coastguard Worker Publisher::TxtData sTxtData1;
110*4a64e381SAndroid Build Coastguard Worker Ip6Address         sAddr1;
111*4a64e381SAndroid Build Coastguard Worker Ip6Address         sAddr2;
112*4a64e381SAndroid Build Coastguard Worker Ip6Address         sAddr3;
113*4a64e381SAndroid Build Coastguard Worker Ip6Address         sAddr4;
114*4a64e381SAndroid Build Coastguard Worker 
115*4a64e381SAndroid Build Coastguard Worker class MdnsTest : public ::testing::Test
116*4a64e381SAndroid Build Coastguard Worker {
117*4a64e381SAndroid Build Coastguard Worker protected:
MdnsTest()118*4a64e381SAndroid Build Coastguard Worker     MdnsTest()
119*4a64e381SAndroid Build Coastguard Worker     {
120*4a64e381SAndroid Build Coastguard Worker         SuccessOrDie(Ip6Address::FromString("2002::1", sAddr1), "");
121*4a64e381SAndroid Build Coastguard Worker         SuccessOrDie(Ip6Address::FromString("2002::2", sAddr2), "");
122*4a64e381SAndroid Build Coastguard Worker         SuccessOrDie(Ip6Address::FromString("2002::3", sAddr3), "");
123*4a64e381SAndroid Build Coastguard Worker         SuccessOrDie(Ip6Address::FromString("2002::4", sAddr4), "");
124*4a64e381SAndroid Build Coastguard Worker         SuccessOrDie(Publisher::EncodeTxtData(sTxtList1, sTxtData1), "");
125*4a64e381SAndroid Build Coastguard Worker     }
126*4a64e381SAndroid Build Coastguard Worker };
127*4a64e381SAndroid Build Coastguard Worker 
CreatePublisher(void)128*4a64e381SAndroid Build Coastguard Worker std::unique_ptr<Publisher> CreatePublisher(void)
129*4a64e381SAndroid Build Coastguard Worker {
130*4a64e381SAndroid Build Coastguard Worker     bool                       ready = false;
131*4a64e381SAndroid Build Coastguard Worker     std::unique_ptr<Publisher> publisher{Publisher::Create([&ready](Mdns::Publisher::State aState) {
132*4a64e381SAndroid Build Coastguard Worker         if (aState == Publisher::State::kReady)
133*4a64e381SAndroid Build Coastguard Worker         {
134*4a64e381SAndroid Build Coastguard Worker             ready = true;
135*4a64e381SAndroid Build Coastguard Worker         }
136*4a64e381SAndroid Build Coastguard Worker     })};
137*4a64e381SAndroid Build Coastguard Worker 
138*4a64e381SAndroid Build Coastguard Worker     publisher->Start();
139*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
140*4a64e381SAndroid Build Coastguard Worker     EXPECT_TRUE(ready);
141*4a64e381SAndroid Build Coastguard Worker 
142*4a64e381SAndroid Build Coastguard Worker     return publisher;
143*4a64e381SAndroid Build Coastguard Worker }
144*4a64e381SAndroid Build Coastguard Worker 
CheckServiceInstance(const Publisher::DiscoveredInstanceInfo aInstanceInfo,bool aRemoved,const std::string & aHostName,const std::vector<Ip6Address> & aAddresses,const std::string & aServiceName,uint16_t aPort,const Publisher::TxtData aTxtData)145*4a64e381SAndroid Build Coastguard Worker void CheckServiceInstance(const Publisher::DiscoveredInstanceInfo aInstanceInfo,
146*4a64e381SAndroid Build Coastguard Worker                           bool                                    aRemoved,
147*4a64e381SAndroid Build Coastguard Worker                           const std::string                      &aHostName,
148*4a64e381SAndroid Build Coastguard Worker                           const std::vector<Ip6Address>          &aAddresses,
149*4a64e381SAndroid Build Coastguard Worker                           const std::string                      &aServiceName,
150*4a64e381SAndroid Build Coastguard Worker                           uint16_t                                aPort,
151*4a64e381SAndroid Build Coastguard Worker                           const Publisher::TxtData                aTxtData)
152*4a64e381SAndroid Build Coastguard Worker {
153*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ(aRemoved, aInstanceInfo.mRemoved);
154*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ(aServiceName, aInstanceInfo.mName);
155*4a64e381SAndroid Build Coastguard Worker     if (!aRemoved)
156*4a64e381SAndroid Build Coastguard Worker     {
157*4a64e381SAndroid Build Coastguard Worker         EXPECT_EQ(aHostName, aInstanceInfo.mHostName);
158*4a64e381SAndroid Build Coastguard Worker         EXPECT_EQ(AsSet(aAddresses), AsSet(aInstanceInfo.mAddresses));
159*4a64e381SAndroid Build Coastguard Worker         EXPECT_EQ(aPort, aInstanceInfo.mPort);
160*4a64e381SAndroid Build Coastguard Worker         EXPECT_TRUE(AsTxtMap(aTxtData) == AsTxtMap(aInstanceInfo.mTxtData));
161*4a64e381SAndroid Build Coastguard Worker     }
162*4a64e381SAndroid Build Coastguard Worker }
163*4a64e381SAndroid Build Coastguard Worker 
CheckServiceInstanceAdded(const Publisher::DiscoveredInstanceInfo aInstanceInfo,const std::string & aHostName,const std::vector<Ip6Address> & aAddresses,const std::string & aServiceName,uint16_t aPort,const Publisher::TxtData aTxtData)164*4a64e381SAndroid Build Coastguard Worker void CheckServiceInstanceAdded(const Publisher::DiscoveredInstanceInfo aInstanceInfo,
165*4a64e381SAndroid Build Coastguard Worker                                const std::string                      &aHostName,
166*4a64e381SAndroid Build Coastguard Worker                                const std::vector<Ip6Address>          &aAddresses,
167*4a64e381SAndroid Build Coastguard Worker                                const std::string                      &aServiceName,
168*4a64e381SAndroid Build Coastguard Worker                                uint16_t                                aPort,
169*4a64e381SAndroid Build Coastguard Worker                                const Publisher::TxtData                aTxtData)
170*4a64e381SAndroid Build Coastguard Worker {
171*4a64e381SAndroid Build Coastguard Worker     CheckServiceInstance(aInstanceInfo, false, aHostName, aAddresses, aServiceName, aPort, aTxtData);
172*4a64e381SAndroid Build Coastguard Worker }
173*4a64e381SAndroid Build Coastguard Worker 
CheckServiceInstanceRemoved(const Publisher::DiscoveredInstanceInfo aInstanceInfo,const std::string & aServiceName)174*4a64e381SAndroid Build Coastguard Worker void CheckServiceInstanceRemoved(const Publisher::DiscoveredInstanceInfo aInstanceInfo, const std::string &aServiceName)
175*4a64e381SAndroid Build Coastguard Worker {
176*4a64e381SAndroid Build Coastguard Worker     CheckServiceInstance(aInstanceInfo, true, "", {}, aServiceName, 0, {});
177*4a64e381SAndroid Build Coastguard Worker }
178*4a64e381SAndroid Build Coastguard Worker 
CheckHostAdded(const Publisher::DiscoveredHostInfo & aHostInfo,const std::string & aHostName,const std::vector<Ip6Address> & aAddresses)179*4a64e381SAndroid Build Coastguard Worker void CheckHostAdded(const Publisher::DiscoveredHostInfo &aHostInfo,
180*4a64e381SAndroid Build Coastguard Worker                     const std::string                   &aHostName,
181*4a64e381SAndroid Build Coastguard Worker                     const std::vector<Ip6Address>       &aAddresses)
182*4a64e381SAndroid Build Coastguard Worker {
183*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ(aHostName, aHostInfo.mHostName);
184*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ(AsSet(aAddresses), AsSet(aHostInfo.mAddresses));
185*4a64e381SAndroid Build Coastguard Worker }
186*4a64e381SAndroid Build Coastguard Worker 
TEST_F(MdnsTest,SubscribeHost)187*4a64e381SAndroid Build Coastguard Worker TEST_F(MdnsTest, SubscribeHost)
188*4a64e381SAndroid Build Coastguard Worker {
189*4a64e381SAndroid Build Coastguard Worker     std::unique_ptr<Publisher>    pub = CreatePublisher();
190*4a64e381SAndroid Build Coastguard Worker     std::string                   lastHostName;
191*4a64e381SAndroid Build Coastguard Worker     Publisher::DiscoveredHostInfo lastHostInfo{};
192*4a64e381SAndroid Build Coastguard Worker 
193*4a64e381SAndroid Build Coastguard Worker     auto clearLastHost = [&lastHostName, &lastHostInfo] {
194*4a64e381SAndroid Build Coastguard Worker         lastHostName = "";
195*4a64e381SAndroid Build Coastguard Worker         lastHostInfo = {};
196*4a64e381SAndroid Build Coastguard Worker     };
197*4a64e381SAndroid Build Coastguard Worker 
198*4a64e381SAndroid Build Coastguard Worker     pub->AddSubscriptionCallbacks(
199*4a64e381SAndroid Build Coastguard Worker         nullptr,
200*4a64e381SAndroid Build Coastguard Worker         [&lastHostName, &lastHostInfo](const std::string &aHostName, const Publisher::DiscoveredHostInfo &aHostInfo) {
201*4a64e381SAndroid Build Coastguard Worker             lastHostName = aHostName;
202*4a64e381SAndroid Build Coastguard Worker             lastHostInfo = aHostInfo;
203*4a64e381SAndroid Build Coastguard Worker         });
204*4a64e381SAndroid Build Coastguard Worker     pub->SubscribeHost("host1");
205*4a64e381SAndroid Build Coastguard Worker 
206*4a64e381SAndroid Build Coastguard Worker     pub->PublishHost("host1", Publisher::AddressList{sAddr1, sAddr2}, NoOpCallback());
207*4a64e381SAndroid Build Coastguard Worker     pub->PublishService("host1", "service1", "_test._tcp", Publisher::SubTypeList{"_sub1", "_sub2"}, 11111, sTxtData1,
208*4a64e381SAndroid Build Coastguard Worker                         NoOpCallback());
209*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
210*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ("host1", lastHostName);
211*4a64e381SAndroid Build Coastguard Worker     CheckHostAdded(lastHostInfo, "host1.local.", {sAddr1, sAddr2});
212*4a64e381SAndroid Build Coastguard Worker     clearLastHost();
213*4a64e381SAndroid Build Coastguard Worker 
214*4a64e381SAndroid Build Coastguard Worker     pub->PublishService("host1", "service2", "_test._tcp", {}, 22222, {}, NoOpCallback());
215*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
216*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ("", lastHostName);
217*4a64e381SAndroid Build Coastguard Worker     clearLastHost();
218*4a64e381SAndroid Build Coastguard Worker 
219*4a64e381SAndroid Build Coastguard Worker     pub->PublishHost("host2", Publisher::AddressList{sAddr3}, NoOpCallback());
220*4a64e381SAndroid Build Coastguard Worker     pub->PublishService("host2", "service3", "_test._tcp", {}, 33333, {}, NoOpCallback());
221*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
222*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ("", lastHostName);
223*4a64e381SAndroid Build Coastguard Worker     clearLastHost();
224*4a64e381SAndroid Build Coastguard Worker }
225*4a64e381SAndroid Build Coastguard Worker 
TEST_F(MdnsTest,SubscribeServiceInstance)226*4a64e381SAndroid Build Coastguard Worker TEST_F(MdnsTest, SubscribeServiceInstance)
227*4a64e381SAndroid Build Coastguard Worker {
228*4a64e381SAndroid Build Coastguard Worker     std::unique_ptr<Publisher>        pub = CreatePublisher();
229*4a64e381SAndroid Build Coastguard Worker     std::string                       lastServiceType;
230*4a64e381SAndroid Build Coastguard Worker     Publisher::DiscoveredInstanceInfo lastInstanceInfo{};
231*4a64e381SAndroid Build Coastguard Worker 
232*4a64e381SAndroid Build Coastguard Worker     auto clearLastInstance = [&lastServiceType, &lastInstanceInfo] {
233*4a64e381SAndroid Build Coastguard Worker         lastServiceType  = "";
234*4a64e381SAndroid Build Coastguard Worker         lastInstanceInfo = {};
235*4a64e381SAndroid Build Coastguard Worker     };
236*4a64e381SAndroid Build Coastguard Worker 
237*4a64e381SAndroid Build Coastguard Worker     pub->AddSubscriptionCallbacks(
238*4a64e381SAndroid Build Coastguard Worker         [&lastServiceType, &lastInstanceInfo](const std::string                &aType,
239*4a64e381SAndroid Build Coastguard Worker                                               Publisher::DiscoveredInstanceInfo aInstanceInfo) {
240*4a64e381SAndroid Build Coastguard Worker             lastServiceType  = aType;
241*4a64e381SAndroid Build Coastguard Worker             lastInstanceInfo = aInstanceInfo;
242*4a64e381SAndroid Build Coastguard Worker         },
243*4a64e381SAndroid Build Coastguard Worker         nullptr);
244*4a64e381SAndroid Build Coastguard Worker     pub->SubscribeService("_test._tcp", "service1");
245*4a64e381SAndroid Build Coastguard Worker 
246*4a64e381SAndroid Build Coastguard Worker     pub->PublishHost("host1", Publisher::AddressList{sAddr1, sAddr2}, NoOpCallback());
247*4a64e381SAndroid Build Coastguard Worker     pub->PublishService("host1", "service1", "_test._tcp", Publisher::SubTypeList{"_sub1", "_sub2"}, 11111, sTxtData1,
248*4a64e381SAndroid Build Coastguard Worker                         NoOpCallback());
249*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
250*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ("_test._tcp", lastServiceType);
251*4a64e381SAndroid Build Coastguard Worker     CheckServiceInstanceAdded(lastInstanceInfo, "host1.local.", {sAddr1, sAddr2}, "service1", 11111, sTxtData1);
252*4a64e381SAndroid Build Coastguard Worker     clearLastInstance();
253*4a64e381SAndroid Build Coastguard Worker 
254*4a64e381SAndroid Build Coastguard Worker     pub->PublishService("host1", "service2", "_test._tcp", {}, 22222, {}, NoOpCallback());
255*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
256*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ("", lastServiceType);
257*4a64e381SAndroid Build Coastguard Worker     clearLastInstance();
258*4a64e381SAndroid Build Coastguard Worker 
259*4a64e381SAndroid Build Coastguard Worker     pub->PublishHost("host2", Publisher::AddressList{sAddr3}, NoOpCallback());
260*4a64e381SAndroid Build Coastguard Worker     pub->PublishService("host2", "service3", "_test._tcp", {}, 33333, {}, NoOpCallback());
261*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
262*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ("", lastServiceType);
263*4a64e381SAndroid Build Coastguard Worker     clearLastInstance();
264*4a64e381SAndroid Build Coastguard Worker }
265*4a64e381SAndroid Build Coastguard Worker 
TEST_F(MdnsTest,SubscribeServiceType)266*4a64e381SAndroid Build Coastguard Worker TEST_F(MdnsTest, SubscribeServiceType)
267*4a64e381SAndroid Build Coastguard Worker {
268*4a64e381SAndroid Build Coastguard Worker     std::unique_ptr<Publisher>        pub = CreatePublisher();
269*4a64e381SAndroid Build Coastguard Worker     std::string                       lastServiceType;
270*4a64e381SAndroid Build Coastguard Worker     Publisher::DiscoveredInstanceInfo lastInstanceInfo{};
271*4a64e381SAndroid Build Coastguard Worker 
272*4a64e381SAndroid Build Coastguard Worker     auto clearLastInstance = [&lastServiceType, &lastInstanceInfo] {
273*4a64e381SAndroid Build Coastguard Worker         lastServiceType  = "";
274*4a64e381SAndroid Build Coastguard Worker         lastInstanceInfo = {};
275*4a64e381SAndroid Build Coastguard Worker     };
276*4a64e381SAndroid Build Coastguard Worker 
277*4a64e381SAndroid Build Coastguard Worker     pub->AddSubscriptionCallbacks(
278*4a64e381SAndroid Build Coastguard Worker         [&lastServiceType, &lastInstanceInfo](const std::string                &aType,
279*4a64e381SAndroid Build Coastguard Worker                                               Publisher::DiscoveredInstanceInfo aInstanceInfo) {
280*4a64e381SAndroid Build Coastguard Worker             lastServiceType  = aType;
281*4a64e381SAndroid Build Coastguard Worker             lastInstanceInfo = aInstanceInfo;
282*4a64e381SAndroid Build Coastguard Worker         },
283*4a64e381SAndroid Build Coastguard Worker         nullptr);
284*4a64e381SAndroid Build Coastguard Worker     pub->SubscribeService("_test._tcp", "");
285*4a64e381SAndroid Build Coastguard Worker 
286*4a64e381SAndroid Build Coastguard Worker     pub->PublishHost("host1", Publisher::AddressList{sAddr1, sAddr2}, NoOpCallback());
287*4a64e381SAndroid Build Coastguard Worker     pub->PublishService("host1", "service1", "_test._tcp", Publisher::SubTypeList{"_sub1", "_sub2"}, 11111, sTxtData1,
288*4a64e381SAndroid Build Coastguard Worker                         NoOpCallback());
289*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
290*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ("_test._tcp", lastServiceType);
291*4a64e381SAndroid Build Coastguard Worker     CheckServiceInstanceAdded(lastInstanceInfo, "host1.local.", {sAddr1, sAddr2}, "service1", 11111, sTxtData1);
292*4a64e381SAndroid Build Coastguard Worker     clearLastInstance();
293*4a64e381SAndroid Build Coastguard Worker 
294*4a64e381SAndroid Build Coastguard Worker     pub->PublishService("host1", "service2", "_test._tcp", {}, 22222, {}, NoOpCallback());
295*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
296*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ("_test._tcp", lastServiceType);
297*4a64e381SAndroid Build Coastguard Worker     CheckServiceInstanceAdded(lastInstanceInfo, "host1.local.", {sAddr1, sAddr2}, "service2", 22222, {});
298*4a64e381SAndroid Build Coastguard Worker     clearLastInstance();
299*4a64e381SAndroid Build Coastguard Worker 
300*4a64e381SAndroid Build Coastguard Worker     pub->PublishHost("host2", Publisher::AddressList{sAddr3}, NoOpCallback());
301*4a64e381SAndroid Build Coastguard Worker     pub->PublishService("host2", "service3", "_test._tcp", {}, 33333, {}, NoOpCallback());
302*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
303*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ("_test._tcp", lastServiceType);
304*4a64e381SAndroid Build Coastguard Worker     CheckServiceInstanceAdded(lastInstanceInfo, "host2.local.", {sAddr3}, "service3", 33333, {});
305*4a64e381SAndroid Build Coastguard Worker     clearLastInstance();
306*4a64e381SAndroid Build Coastguard Worker 
307*4a64e381SAndroid Build Coastguard Worker     pub->UnpublishHost("host2", NoOpCallback());
308*4a64e381SAndroid Build Coastguard Worker     pub->UnpublishService("service3", "_test._tcp", NoOpCallback());
309*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
310*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ("_test._tcp", lastServiceType);
311*4a64e381SAndroid Build Coastguard Worker     CheckServiceInstanceRemoved(lastInstanceInfo, "service3");
312*4a64e381SAndroid Build Coastguard Worker     clearLastInstance();
313*4a64e381SAndroid Build Coastguard Worker 
314*4a64e381SAndroid Build Coastguard Worker     pub->PublishHost("host2", {sAddr3}, NoOpCallback());
315*4a64e381SAndroid Build Coastguard Worker     pub->PublishService("host2", "service3", "_test._tcp", {}, 44444, {}, NoOpCallback());
316*4a64e381SAndroid Build Coastguard Worker     pub->PublishHost("host2", {sAddr3, sAddr4}, NoOpCallback());
317*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
318*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ("_test._tcp", lastServiceType);
319*4a64e381SAndroid Build Coastguard Worker     CheckServiceInstanceAdded(lastInstanceInfo, "host2.local.", {sAddr3, sAddr4}, "service3", 44444, {});
320*4a64e381SAndroid Build Coastguard Worker     clearLastInstance();
321*4a64e381SAndroid Build Coastguard Worker 
322*4a64e381SAndroid Build Coastguard Worker     pub->PublishHost("host2", {sAddr4}, NoOpCallback());
323*4a64e381SAndroid Build Coastguard Worker     RunMainloopUntilTimeout(kTimeoutSeconds);
324*4a64e381SAndroid Build Coastguard Worker     EXPECT_EQ("_test._tcp", lastServiceType);
325*4a64e381SAndroid Build Coastguard Worker     CheckServiceInstanceAdded(lastInstanceInfo, "host2.local.", {sAddr4}, "service3", 44444, {});
326*4a64e381SAndroid Build Coastguard Worker     clearLastInstance();
327*4a64e381SAndroid Build Coastguard Worker }
328