Skip to content

Commit 2091874

Browse files
arkqbzbarsky-apple
authored andcommitted
DNS-SD mock for checking platform implementations (#26143)
* DNS-SD mock for checking platform implementations * Mark POSIX event loop as ready for run if not-internaly managed * Prevent SEGFAULT in test in case of resolve error * Document mDNS test cases * Apply suggestions from code review Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> --------- Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
1 parent 2688f61 commit 2091874

File tree

3 files changed

+147
-5
lines changed

3 files changed

+147
-5
lines changed

src/include/platform/internal/GenericPlatformManagerImpl_POSIX.ipp

+1
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ void GenericPlatformManagerImpl_POSIX<ImplClass>::_RunEventLoop()
163163
{
164164
mChipTask = pthread_self();
165165
mState.store(State::kRunning, std::memory_order_relaxed);
166+
mShouldRunEventLoop.store(true, std::memory_order_relaxed);
166167
}
167168

168169
pthread_mutex_unlock(&mStateLock);

src/platform/tests/BUILD.gn

+4-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ if (chip_device_platform != "none" && chip_device_platform != "fake") {
4949
if (chip_mdns != "none" && chip_enable_dnssd_tests &&
5050
(chip_device_platform == "linux" || chip_device_platform == "darwin")) {
5151
test_sources += [ "TestDnssd.cpp" ]
52-
public_deps += [ "${chip_root}/src/lib/dnssd" ]
52+
public_deps += [
53+
"${chip_root}/src/lib/dnssd",
54+
"${chip_root}/src/lib/dnssd/minimal_mdns",
55+
]
5356
}
5457

5558
# These tests appear to be broken on Mac.

src/platform/tests/TestDnssd.cpp

+142-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,18 @@
2121

2222
#include "lib/dnssd/platform/Dnssd.h"
2323
#include "platform/CHIPDeviceLayer.h"
24+
#include "platform/ConnectivityManager.h"
2425
#include "platform/PlatformManager.h"
26+
#include <lib/dnssd/minimal_mdns/AddressPolicy.h>
27+
#include <lib/dnssd/minimal_mdns/AddressPolicy_DefaultImpl.h>
28+
#include <lib/dnssd/minimal_mdns/Parser.h>
29+
#include <lib/dnssd/minimal_mdns/RecordData.h>
30+
#include <lib/dnssd/minimal_mdns/ResponseSender.h>
31+
#include <lib/dnssd/minimal_mdns/Server.h>
32+
#include <lib/dnssd/minimal_mdns/responders/IP.h>
33+
#include <lib/dnssd/minimal_mdns/responders/Ptr.h>
34+
#include <lib/dnssd/minimal_mdns/responders/Srv.h>
35+
#include <lib/dnssd/minimal_mdns/responders/Txt.h>
2536
#include <lib/support/CHIPMem.h>
2637
#include <lib/support/UnitTestRegistration.h>
2738

@@ -44,6 +55,35 @@ struct DnssdContext
4455
bool mEndOfInput = false;
4556
};
4657

58+
class TestDnssdResolveServerDelegate : public mdns::Minimal::ServerDelegate, public mdns::Minimal::ParserDelegate
59+
{
60+
public:
61+
TestDnssdResolveServerDelegate(mdns::Minimal::ResponseSender * responder) : mResponder(responder) {}
62+
virtual ~TestDnssdResolveServerDelegate() = default;
63+
64+
// Implementation of mdns::Minimal::ServerDelegate
65+
66+
void OnResponse(const mdns::Minimal::BytesRange & data, const chip::Inet::IPPacketInfo * info) override {}
67+
void OnQuery(const mdns::Minimal::BytesRange & data, const chip::Inet::IPPacketInfo * info) override
68+
{
69+
mCurSrc = info;
70+
mdns::Minimal::ParsePacket(data, this);
71+
mCurSrc = nullptr;
72+
}
73+
74+
// Implementation of mdns::Minimal::ParserDelegate
75+
76+
void OnHeader(mdns::Minimal::ConstHeaderRef & header) override { mMsgId = header.GetMessageId(); }
77+
void OnQuery(const mdns::Minimal::QueryData & data) override { mResponder->Respond(mMsgId, data, mCurSrc, mRespConfig); }
78+
void OnResource(mdns::Minimal::ResourceType type, const mdns::Minimal::ResourceData & data) override {}
79+
80+
private:
81+
mdns::Minimal::ResponseSender * mResponder;
82+
mdns::Minimal::ResponseConfiguration mRespConfig;
83+
const chip::Inet::IPPacketInfo * mCurSrc = nullptr;
84+
uint16_t mMsgId = 0;
85+
};
86+
4787
} // namespace
4888

4989
static void Timeout(chip::System::Layer * systemLayer, void * context)
@@ -64,6 +104,10 @@ static void HandleResolve(void * context, DnssdService * result, const chip::Spa
64104
NL_TEST_ASSERT(suite, result != nullptr);
65105
NL_TEST_ASSERT(suite, error == CHIP_NO_ERROR);
66106

107+
// The NL_TEST_ASSERT above will not abort the test, so we need to
108+
// explicitly abort it here to avoid dereferencing a null pointer.
109+
VerifyOrReturn(result != nullptr, );
110+
67111
if (!addresses.empty())
68112
{
69113
addresses.data()[0].ToString(addrBuf, sizeof(addrBuf));
@@ -122,13 +166,96 @@ static void DnssdErrorCallback(void * context, CHIP_ERROR error)
122166
NL_TEST_ASSERT(ctx->mTestSuite, error == CHIP_NO_ERROR);
123167
}
124168

169+
void TestDnssdBrowse_DnssdInitCallback(void * context, CHIP_ERROR error)
170+
{
171+
auto * ctx = static_cast<DnssdContext *>(context);
172+
NL_TEST_ASSERT(ctx->mTestSuite, error == CHIP_NO_ERROR);
173+
auto * suite = ctx->mTestSuite;
174+
175+
NL_TEST_ASSERT(suite,
176+
ChipDnssdBrowse("_mock", DnssdServiceProtocol::kDnssdProtocolUdp, chip::Inet::IPAddressType::kAny,
177+
chip::Inet::InterfaceId::Null(), HandleBrowse, context,
178+
&ctx->mBrowseIdentifier) == CHIP_NO_ERROR);
179+
}
180+
181+
// Verify that platform DNS-SD implementation can browse and resolve services.
182+
//
183+
// This test case uses platform-independent mDNS server implementation based on
184+
// minimal mdns library. The server is configured to respond to PTR, SRV, TXT,
185+
// A and AAAA queries without additional records. In order to pass this test,
186+
// the platform DNS-SD client implementation must be able to browse and resolve
187+
// services by querying for all of these records separately.
188+
void TestDnssdBrowse(nlTestSuite * inSuite, void * inContext)
189+
{
190+
DnssdContext context;
191+
context.mTestSuite = inSuite;
192+
193+
mdns::Minimal::SetDefaultAddressPolicy();
194+
195+
mdns::Minimal::Server<10> server;
196+
mdns::Minimal::QNamePart serverName[] = { "resolve-tester", "_mock", chip::Dnssd::kCommissionProtocol,
197+
chip::Dnssd::kLocalDomain };
198+
mdns::Minimal::ResponseSender responseSender(&server);
199+
200+
mdns::Minimal::QueryResponder<16> queryResponder;
201+
responseSender.AddQueryResponder(&queryResponder);
202+
203+
// Respond to PTR queries for _mock._udp.local
204+
mdns::Minimal::QNamePart serviceName[] = { "_mock", chip::Dnssd::kCommissionProtocol, chip::Dnssd::kLocalDomain };
205+
mdns::Minimal::QNamePart serverServiceName[] = { "INSTANCE", chip::Dnssd::kCommissionableServiceName,
206+
chip::Dnssd::kCommissionProtocol, chip::Dnssd::kLocalDomain };
207+
mdns::Minimal::PtrResponder ptrUdpResponder(serviceName, serverServiceName);
208+
queryResponder.AddResponder(&ptrUdpResponder);
209+
210+
// Respond to SRV queries for INSTANCE._matterc._udp.local
211+
mdns::Minimal::SrvResponder srvResponder(mdns::Minimal::SrvResourceRecord(serverServiceName, serverName, CHIP_PORT));
212+
queryResponder.AddResponder(&srvResponder);
213+
214+
// Respond to TXT queries for INSTANCE._matterc._udp.local
215+
const char * txtEntries[] = { "key=val" };
216+
mdns::Minimal::TxtResponder txtResponder(mdns::Minimal::TxtResourceRecord(serverServiceName, txtEntries));
217+
queryResponder.AddResponder(&txtResponder);
218+
219+
// Respond to A queries
220+
mdns::Minimal::IPv4Responder ipv4Responder(serverName);
221+
queryResponder.AddResponder(&ipv4Responder);
222+
223+
// Respond to AAAA queries
224+
mdns::Minimal::IPv6Responder ipv6Responder(serverName);
225+
queryResponder.AddResponder(&ipv6Responder);
226+
227+
TestDnssdResolveServerDelegate delegate(&responseSender);
228+
server.SetDelegate(&delegate);
229+
230+
auto endpoints = mdns::Minimal::GetAddressPolicy()->GetListenEndpoints();
231+
NL_TEST_ASSERT(inSuite, server.Listen(chip::DeviceLayer::UDPEndPointManager(), endpoints.get(), 5353) == CHIP_NO_ERROR);
232+
233+
NL_TEST_ASSERT(inSuite,
234+
chip::Dnssd::ChipDnssdInit(TestDnssdBrowse_DnssdInitCallback, DnssdErrorCallback, &context) == CHIP_NO_ERROR);
235+
NL_TEST_ASSERT(inSuite,
236+
chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(5), Timeout, &context) ==
237+
CHIP_NO_ERROR);
238+
239+
ChipLogProgress(DeviceLayer, "Start EventLoop");
240+
chip::DeviceLayer::PlatformMgr().RunEventLoop();
241+
ChipLogProgress(DeviceLayer, "End EventLoop");
242+
243+
NL_TEST_ASSERT(inSuite, context.mResolvedServicesCount > 0);
244+
NL_TEST_ASSERT(inSuite, !context.mTimeoutExpired);
245+
246+
// Stop browsing so we can safely shutdown DNS-SD
247+
chip::Dnssd::ChipDnssdStopBrowse(context.mBrowseIdentifier);
248+
249+
chip::Dnssd::ChipDnssdShutdown();
250+
}
251+
125252
static void HandlePublish(void * context, const char * type, const char * instanceName, CHIP_ERROR error)
126253
{
127254
auto * ctx = static_cast<DnssdContext *>(context);
128255
NL_TEST_ASSERT(ctx->mTestSuite, error == CHIP_NO_ERROR);
129256
}
130257

131-
static void TestDnssdPubSub_DnssdInitCallback(void * context, CHIP_ERROR error)
258+
static void TestDnssdPublishService_DnssdInitCallback(void * context, CHIP_ERROR error)
132259
{
133260
auto * ctx = static_cast<DnssdContext *>(context);
134261
NL_TEST_ASSERT(ctx->mTestSuite, error == CHIP_NO_ERROR);
@@ -157,13 +284,19 @@ static void TestDnssdPubSub_DnssdInitCallback(void * context, CHIP_ERROR error)
157284
&ctx->mBrowseIdentifier) == CHIP_NO_ERROR);
158285
}
159286

160-
void TestDnssdPubSub(nlTestSuite * inSuite, void * inContext)
287+
// Verify that the platform DNS-SD implementation can publish services.
288+
//
289+
// This test uses platform implementation of DNS-SD server and client. Since
290+
// client implementation should be verified by the TestDnssdBrowse test case,
291+
// here we only verify that the server implementation can publish services.
292+
void TestDnssdPublishService(nlTestSuite * inSuite, void * inContext)
161293
{
162294
DnssdContext context;
163295
context.mTestSuite = inSuite;
164296

165297
NL_TEST_ASSERT(inSuite,
166-
chip::Dnssd::ChipDnssdInit(TestDnssdPubSub_DnssdInitCallback, DnssdErrorCallback, &context) == CHIP_NO_ERROR);
298+
chip::Dnssd::ChipDnssdInit(TestDnssdPublishService_DnssdInitCallback, DnssdErrorCallback, &context) ==
299+
CHIP_NO_ERROR);
167300
NL_TEST_ASSERT(inSuite,
168301
chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(5), Timeout, &context) ==
169302
CHIP_NO_ERROR);
@@ -172,6 +305,7 @@ void TestDnssdPubSub(nlTestSuite * inSuite, void * inContext)
172305
chip::DeviceLayer::PlatformMgr().RunEventLoop();
173306
ChipLogProgress(DeviceLayer, "End EventLoop");
174307

308+
NL_TEST_ASSERT(inSuite, context.mResolvedServicesCount > 0);
175309
NL_TEST_ASSERT(inSuite, !context.mTimeoutExpired);
176310

177311
// Stop browsing so we can safely shutdown DNS-SD
@@ -180,7 +314,11 @@ void TestDnssdPubSub(nlTestSuite * inSuite, void * inContext)
180314
chip::Dnssd::ChipDnssdShutdown();
181315
}
182316

183-
static const nlTest sTests[] = { NL_TEST_DEF("Test Dnssd::PubSub", TestDnssdPubSub), NL_TEST_SENTINEL() };
317+
static const nlTest sTests[] = {
318+
NL_TEST_DEF("Test ChipDnssdBrowse", TestDnssdBrowse),
319+
NL_TEST_DEF("Test ChipDnssdPublishService", TestDnssdPublishService),
320+
NL_TEST_SENTINEL(),
321+
};
184322

185323
int TestDnssd_Setup(void * inContext)
186324
{

0 commit comments

Comments
 (0)