| /* |
| * |
| * Copyright (c) 2021 Project CHIP Authors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include <lib/dnssd/Advertiser.h> |
| |
| #include <string> |
| #include <utility> |
| |
| #include <lib/dnssd/Advertiser.h> |
| #include <lib/dnssd/MinimalMdnsServer.h> |
| #include <lib/dnssd/minimal_mdns/Query.h> |
| #include <lib/dnssd/minimal_mdns/QueryBuilder.h> |
| #include <lib/dnssd/minimal_mdns/core/QName.h> |
| #include <lib/dnssd/minimal_mdns/records/Ptr.h> |
| #include <lib/dnssd/minimal_mdns/records/Srv.h> |
| #include <lib/dnssd/minimal_mdns/records/Txt.h> |
| #include <lib/dnssd/minimal_mdns/tests/CheckOnlyServer.h> |
| #include <lib/support/UnitTestContext.h> |
| #include <lib/support/UnitTestRegistration.h> |
| #include <system/SystemPacketBuffer.h> |
| #include <transport/raw/tests/NetworkTestHelpers.h> |
| |
| #include <nlunit-test.h> |
| |
| namespace { |
| |
| using namespace std; |
| using namespace chip; |
| using namespace chip::Dnssd; |
| using namespace mdns::Minimal; |
| using namespace mdns::Minimal::test; |
| |
| // Used for everything. |
| const QNamePart kDnsSdQueryParts[] = { "_services", "_dns-sd", "_udp", "local" }; |
| const FullQName kDnsSdQueryName = FullQName(kDnsSdQueryParts); |
| constexpr size_t kMdnsMaxPacketSize = 512; |
| const uint8_t kMac[kMaxMacSize] = { 1, 2, 3, 4, 5, 6, 7, 8 }; |
| const QNamePart kHostnameParts[] = { "0102030405060708", "local" }; |
| const FullQName kHostnameName = FullQName(kHostnameParts); |
| |
| // Operational records and queries. |
| const QNamePart kMatterOperationalQueryParts[3] = { "_matter", "_tcp", "local" }; |
| const FullQName kMatterOperationalQueryName = FullQName(kMatterOperationalQueryParts); |
| const PeerId kPeerId1 = PeerId().SetCompressedFabricId(0xBEEFBEEFF00DF00D).SetNodeId(0x1111222233334444); |
| const PeerId kPeerId2 = PeerId().SetCompressedFabricId(0x5555666677778888).SetNodeId(0x1212343456567878); |
| const PeerId kPeerId3 = PeerId().SetCompressedFabricId(0x3333333333333333).SetNodeId(0x3333333333333333); |
| const PeerId kPeerId4 = PeerId().SetCompressedFabricId(0x4444444444444444).SetNodeId(0x4444444444444444); |
| const PeerId kPeerId5 = PeerId().SetCompressedFabricId(0x5555555555555555).SetNodeId(0x5555555555555555); |
| const PeerId kPeerId6 = PeerId().SetCompressedFabricId(0x6666666666666666).SetNodeId(0x6666666666666666); |
| const QNamePart kInstanceNameParts1[] = { "BEEFBEEFF00DF00D-1111222233334444", "_matter", "_tcp", "local" }; |
| const FullQName kInstanceName1 = FullQName(kInstanceNameParts1); |
| const QNamePart kInstanceNameParts2[] = { "5555666677778888-1212343456567878", "_matter", "_tcp", "local" }; |
| const FullQName kInstanceName2 = FullQName(kInstanceNameParts2); |
| const QNamePart kTxtRecordEmptyParts[] = { "=" }; |
| const FullQName kTxtRecordEmptyName = FullQName(kTxtRecordEmptyParts); |
| const QNamePart kCompressedIdSubParts1[] = { "_IBEEFBEEFF00DF00D", "_sub", "_matter", "_tcp", "local" }; |
| FullQName kCompressedIdSubName1 = FullQName(kCompressedIdSubParts1); |
| const QNamePart kCompressedIdSubParts2[] = { "_I5555666677778888", "_sub", "_matter", "_tcp", "local" }; |
| FullQName kCompressedIdSubName2 = FullQName(kCompressedIdSubParts2); |
| PtrResourceRecord ptrServiceSubCompressedId1 = PtrResourceRecord(kDnsSdQueryName, kCompressedIdSubName1); |
| PtrResourceRecord ptrServiceSubCompressedId2 = PtrResourceRecord(kDnsSdQueryName, kCompressedIdSubName2); |
| |
| OperationalAdvertisingParameters operationalParams1 = |
| OperationalAdvertisingParameters() |
| .SetPeerId(kPeerId1) |
| .SetMac(ByteSpan(kMac)) |
| .SetPort(CHIP_PORT) |
| .EnableIpV4(true) |
| .SetTcpSupported(chip::Optional<bool>(false)) |
| .SetLocalMRPConfig(Optional<ReliableMessageProtocolConfig>::Value(32_ms32, 30_ms32)); // Match SII, SAI below |
| OperationalAdvertisingParameters operationalParams2 = |
| OperationalAdvertisingParameters().SetPeerId(kPeerId2).SetMac(ByteSpan(kMac)).SetPort(CHIP_PORT).EnableIpV4(true); |
| OperationalAdvertisingParameters operationalParams3 = |
| OperationalAdvertisingParameters().SetPeerId(kPeerId3).SetMac(ByteSpan(kMac)).SetPort(CHIP_PORT).EnableIpV4(true); |
| OperationalAdvertisingParameters operationalParams4 = |
| OperationalAdvertisingParameters().SetPeerId(kPeerId4).SetMac(ByteSpan(kMac)).SetPort(CHIP_PORT).EnableIpV4(true); |
| OperationalAdvertisingParameters operationalParams5 = |
| OperationalAdvertisingParameters().SetPeerId(kPeerId5).SetMac(ByteSpan(kMac)).SetPort(CHIP_PORT).EnableIpV4(true); |
| OperationalAdvertisingParameters operationalParams6 = |
| OperationalAdvertisingParameters().SetPeerId(kPeerId6).SetMac(ByteSpan(kMac)).SetPort(CHIP_PORT).EnableIpV4(true); |
| const QNamePart txtOperational1Parts[] = { "SII=32", "SAI=30", "T=0" }; |
| PtrResourceRecord ptrOperationalService = PtrResourceRecord(kDnsSdQueryName, kMatterOperationalQueryName); |
| PtrResourceRecord ptrOperational1 = PtrResourceRecord(kMatterOperationalQueryName, kInstanceName1); |
| SrvResourceRecord srvOperational1 = SrvResourceRecord(kInstanceName1, kHostnameName, CHIP_PORT); |
| TxtResourceRecord txtOperational1 = TxtResourceRecord(kInstanceName1, txtOperational1Parts); |
| PtrResourceRecord ptrOperational2 = PtrResourceRecord(kMatterOperationalQueryName, kInstanceName2); |
| SrvResourceRecord srvOperational2 = SrvResourceRecord(kInstanceName2, kHostnameName, CHIP_PORT); |
| TxtResourceRecord txtOperational2 = TxtResourceRecord(kInstanceName2, kTxtRecordEmptyName); |
| |
| // Commissionable node records and queries. |
| const QNamePart kMatterCommissionableNodeQueryParts[3] = { "_matterc", "_udp", "local" }; |
| const QNamePart kLongSubPartsFullLen[] = { "_L4094", "_sub", "_matterc", "_udp", "local" }; |
| const QNamePart kShortSubPartsFullLen[] = { "_S15", "_sub", "_matterc", "_udp", "local" }; |
| const QNamePart kCmSubParts[] = { "_CM", "_sub", "_matterc", "_udp", "local" }; |
| const QNamePart kLongSubParts[] = { "_L22", "_sub", "_matterc", "_udp", "local" }; |
| const QNamePart kShortSubParts[] = { "_S2", "_sub", "_matterc", "_udp", "local" }; |
| const QNamePart kVendorSubParts[] = { "_V555", "_sub", "_matterc", "_udp", "local" }; |
| const QNamePart kDeviceTypeSubParts[] = { "_T70000", "_sub", "_matterc", "_udp", "local" }; |
| const FullQName kMatterCommissionableNodeQueryName = FullQName(kMatterCommissionableNodeQueryParts); |
| FullQName kLongSubFullLenName = FullQName(kLongSubPartsFullLen); |
| FullQName kShortSubFullLenName = FullQName(kShortSubPartsFullLen); |
| FullQName kCmSubName = FullQName(kCmSubParts); |
| FullQName kLongSubName = FullQName(kLongSubParts); |
| FullQName kShortSubName = FullQName(kShortSubParts); |
| FullQName kVendorSubName = FullQName(kVendorSubParts); |
| FullQName kDeviceTypeSubName = FullQName(kDeviceTypeSubParts); |
| PtrResourceRecord ptrCommissionableNodeService = PtrResourceRecord(kDnsSdQueryName, kMatterCommissionableNodeQueryName); |
| PtrResourceRecord ptrServiceSubLFullLen = PtrResourceRecord(kDnsSdQueryName, kLongSubFullLenName); |
| PtrResourceRecord ptrServiceSubSFullLen = PtrResourceRecord(kDnsSdQueryName, kShortSubFullLenName); |
| PtrResourceRecord ptrServiceSubCM = PtrResourceRecord(kDnsSdQueryName, kCmSubName); |
| PtrResourceRecord ptrServiceSubLong = PtrResourceRecord(kDnsSdQueryName, kLongSubName); |
| PtrResourceRecord ptrServiceSubShort = PtrResourceRecord(kDnsSdQueryName, kShortSubName); |
| PtrResourceRecord ptrServiceSubVendor = PtrResourceRecord(kDnsSdQueryName, kVendorSubName); |
| PtrResourceRecord ptrServiceSubDeviceType = PtrResourceRecord(kDnsSdQueryName, kDeviceTypeSubName); |
| |
| // For commissioning, the instance name is chosen randomly by the advertiser, so we have to get this value from it. We can, however, |
| // pre-populate the records with the ptr. |
| char instanceNamePrefix[17]; |
| QNamePart instanceNameParts[] = { instanceNamePrefix, "_matterc", "_udp", "local" }; |
| FullQName instanceName = FullQName(instanceNameParts); |
| PtrResourceRecord ptrCommissionableNode = PtrResourceRecord(kMatterCommissionableNodeQueryName, instanceName); |
| SrvResourceRecord srvCommissionableNode = SrvResourceRecord(instanceName, kHostnameName, CHIP_PORT); |
| |
| CommissionAdvertisingParameters commissionableNodeParamsSmall = |
| CommissionAdvertisingParameters() |
| .SetCommissionAdvertiseMode(CommssionAdvertiseMode::kCommissionableNode) |
| .SetMac(ByteSpan(kMac)) |
| .SetLongDiscriminator(0xFFE) |
| .SetShortDiscriminator(0xF) |
| .SetCommissioningMode(CommissioningMode::kDisabled); |
| const QNamePart txtCommissionableNodeParamsSmallParts[] = { "CM=0", "D=4094" }; |
| FullQName txtCommissionableNodeParamsSmallName = FullQName(txtCommissionableNodeParamsSmallParts); |
| TxtResourceRecord txtCommissionableNodeParamsSmall = TxtResourceRecord(instanceName, txtCommissionableNodeParamsSmallName); |
| |
| CommissionAdvertisingParameters commissionableNodeParamsLargeBasic = |
| CommissionAdvertisingParameters() |
| .SetCommissionAdvertiseMode(CommssionAdvertiseMode::kCommissionableNode) |
| .SetMac(ByteSpan(kMac, sizeof(kMac))) |
| .SetLongDiscriminator(22) |
| .SetShortDiscriminator(2) |
| .SetVendorId(chip::Optional<uint16_t>(555)) |
| .SetDeviceType(chip::Optional<uint32_t>(70000)) |
| .SetCommissioningMode(CommissioningMode::kEnabledBasic) |
| .SetDeviceName(chip::Optional<const char *>("testy-test")) |
| .SetPairingHint(chip::Optional<uint16_t>(3)) |
| .SetPairingInstruction(chip::Optional<const char *>("Pair me")) |
| .SetProductId(chip::Optional<uint16_t>(897)) |
| .SetRotatingDeviceId(chip::Optional<const char *>("id_that_spins")); |
| QNamePart txtCommissionableNodeParamsLargeBasicParts[] = { "D=22", "VP=555+897", "CM=1", "DT=70000", |
| "DN=testy-test", "RI=id_that_spins", "PI=Pair me", "PH=3" }; |
| FullQName txtCommissionableNodeParamsLargeBasicName = FullQName(txtCommissionableNodeParamsLargeBasicParts); |
| TxtResourceRecord txtCommissionableNodeParamsLargeBasic = |
| TxtResourceRecord(instanceName, txtCommissionableNodeParamsLargeBasicName); |
| |
| CommissionAdvertisingParameters commissionableNodeParamsLargeEnhanced = |
| CommissionAdvertisingParameters() |
| .SetCommissionAdvertiseMode(CommssionAdvertiseMode::kCommissionableNode) |
| .SetMac(ByteSpan(kMac, sizeof(kMac))) |
| .SetLongDiscriminator(22) |
| .SetShortDiscriminator(2) |
| .SetVendorId(chip::Optional<uint16_t>(555)) |
| .SetDeviceType(chip::Optional<uint32_t>(70000)) |
| .SetCommissioningMode(CommissioningMode::kEnabledEnhanced) |
| .SetDeviceName(chip::Optional<const char *>("testy-test")) |
| .SetPairingHint(chip::Optional<uint16_t>(3)) |
| .SetPairingInstruction(chip::Optional<const char *>("Pair me")) |
| .SetProductId(chip::Optional<uint16_t>(897)) |
| .SetRotatingDeviceId(chip::Optional<const char *>("id_that_spins")) |
| .SetTcpSupported(chip::Optional<bool>(true)) |
| // 3600005 is more than the max so should be adjusted down |
| .SetLocalMRPConfig(Optional<ReliableMessageProtocolConfig>::Value(3600000_ms32, 3600005_ms32)); |
| QNamePart txtCommissionableNodeParamsLargeEnhancedParts[] = { "D=22", "VP=555+897", "CM=2", "DT=70000", |
| "DN=testy-test", "RI=id_that_spins", "PI=Pair me", "PH=3", |
| "SAI=3600000", "SII=3600000", "T=1" }; |
| FullQName txtCommissionableNodeParamsLargeEnhancedName = FullQName(txtCommissionableNodeParamsLargeEnhancedParts); |
| TxtResourceRecord txtCommissionableNodeParamsLargeEnhanced = |
| TxtResourceRecord(instanceName, txtCommissionableNodeParamsLargeEnhancedName); |
| |
| // Our server doesn't do anything with this, blank is fine. |
| Inet::IPPacketInfo packetInfo; |
| |
| CHIP_ERROR SendQuery(FullQName qname) |
| { |
| System::PacketBufferHandle queryBuffer = System::PacketBufferHandle::New(kMdnsMaxPacketSize); |
| if (queryBuffer.IsNull()) |
| { |
| return CHIP_ERROR_NO_MEMORY; |
| } |
| QueryBuilder queryBuilder(std::move(queryBuffer)); |
| queryBuilder.Header().SetMessageId(0); |
| Query query = Query(qname).SetClass(QClass::IN).SetType(QType::ANY); |
| queryBuilder.AddQuery(query); |
| queryBuffer = queryBuilder.ReleasePacket(); |
| |
| // Send the query to the advertiser directly. |
| BytesRange range = BytesRange(queryBuffer->Start(), queryBuffer->Start() + queryBuffer->DataLength()); |
| GlobalMinimalMdnsServer::Instance().OnQuery(range, &packetInfo); |
| return CHIP_NO_ERROR; |
| } |
| |
| void OperationalAdverts(nlTestSuite * inSuite, void * inContext) |
| { |
| auto & mdnsAdvertiser = chip::Dnssd::ServiceAdvertiser::Instance(); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.RemoveServices() == CHIP_NO_ERROR); |
| |
| auto & server = static_cast<CheckOnlyServer &>(GlobalMinimalMdnsServer::Server()); |
| server.SetTestSuite(inSuite); |
| server.Reset(); |
| |
| // Start a single operational advertiser |
| ChipLogProgress(Discovery, "Testing single operational advertiser"); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.Advertise(operationalParams1) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.FinalizeServiceUpdate() == CHIP_NO_ERROR); |
| |
| // Test for PTR response to _services request. |
| ChipLogProgress(Discovery, "Checking response to _services._dns-sd._udp.local"); |
| server.AddExpectedRecord(&ptrOperationalService); |
| server.AddExpectedRecord(&ptrServiceSubCompressedId1); |
| NL_TEST_ASSERT(inSuite, SendQuery(kDnsSdQueryName) == CHIP_NO_ERROR); |
| |
| // These check that the requested records added are sent out correctly. |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| // Want PTR response to _matter.tcp. We will also get the SRV and TXT as additionals. |
| // We won't get any A/AAAA because this is a test and we don't have addresses. |
| ChipLogProgress(Discovery, "Testing response to _matter._tcp.local"); |
| server.Reset(); |
| // For now, we don't check TXT records content, just that they exist. Operational currently |
| // sends a TXT record regardless of content being present or not. |
| server.AddExpectedRecord(&ptrOperational1); |
| server.AddExpectedRecord(&srvOperational1); |
| server.AddExpectedRecord(&txtOperational1); |
| |
| NL_TEST_ASSERT(inSuite, SendQuery(kMatterOperationalQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| ChipLogProgress(Discovery, "Testing response to instance name"); |
| server.Reset(); |
| // Just the SRV and TXT should return |
| server.AddExpectedRecord(&srvOperational1); |
| server.AddExpectedRecord(&txtOperational1); |
| NL_TEST_ASSERT(inSuite, SendQuery(kInstanceName1) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| // If we try to re-advertise with the same operational parameters, we should not get duplicates |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.Advertise(operationalParams1) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.FinalizeServiceUpdate() == CHIP_NO_ERROR); |
| ChipLogProgress(Discovery, "Testing single operational advertiser with Advertise called twice"); |
| // We should get a single PTR back for _services |
| ChipLogProgress(Discovery, "Checking response to _services._dns-sd._udp.local"); |
| server.Reset(); |
| server.AddExpectedRecord(&ptrOperationalService); |
| server.AddExpectedRecord(&ptrServiceSubCompressedId1); |
| NL_TEST_ASSERT(inSuite, SendQuery(kDnsSdQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| // Same records should come back for _matter._tcp.local queries. |
| ChipLogProgress(Discovery, "Testing response to _matter._tcp.local"); |
| server.Reset(); |
| server.AddExpectedRecord(&ptrOperational1); |
| server.AddExpectedRecord(&srvOperational1); |
| server.AddExpectedRecord(&txtOperational1); |
| NL_TEST_ASSERT(inSuite, SendQuery(kMatterOperationalQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| // Adding a second operational advertiser. |
| ChipLogProgress(Discovery, "Adding a second operational Advertiser"); |
| server.Reset(); |
| // Mac is the same, peer id is different |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.Advertise(operationalParams2) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.FinalizeServiceUpdate() == CHIP_NO_ERROR); |
| |
| // For now, we'll get back two copies of the PTR. Not sure if that's totally correct, but for now, that's expected. |
| ChipLogProgress(Discovery, "Checking response to _services._dns-sd._udp.local"); |
| server.AddExpectedRecord(&ptrOperationalService); |
| server.AddExpectedRecord(&ptrOperationalService); |
| server.AddExpectedRecord(&ptrServiceSubCompressedId1); |
| server.AddExpectedRecord(&ptrServiceSubCompressedId2); |
| NL_TEST_ASSERT(inSuite, SendQuery(kDnsSdQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| // Requests for _matter._tcp.local will respond with all records from both parameter sets |
| ChipLogProgress(Discovery, "Testing response to _matter._tcp.local"); |
| server.Reset(); |
| server.AddExpectedRecord(&ptrOperational1); |
| server.AddExpectedRecord(&srvOperational1); |
| server.AddExpectedRecord(&txtOperational1); |
| server.AddExpectedRecord(&ptrOperational2); |
| server.AddExpectedRecord(&srvOperational2); |
| server.AddExpectedRecord(&txtOperational2); |
| NL_TEST_ASSERT(inSuite, SendQuery(kMatterOperationalQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| // Requests for each SRV record should give only records specific to that fabric. |
| ChipLogProgress(Discovery, "Testing response to instance name for fabric 1"); |
| server.Reset(); |
| // Just the SRV and TXT should return |
| server.AddExpectedRecord(&srvOperational1); |
| server.AddExpectedRecord(&txtOperational1); |
| NL_TEST_ASSERT(inSuite, SendQuery(kInstanceName1) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| ChipLogProgress(Discovery, "Testing response to instance name for fabric 2"); |
| server.Reset(); |
| // Just the SRV and TXT should return |
| server.AddExpectedRecord(&srvOperational2); |
| server.AddExpectedRecord(&txtOperational2); |
| NL_TEST_ASSERT(inSuite, SendQuery(kInstanceName2) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| // All devices should support at least 5 operational network additions (spec min) |
| // however larger devices may support more. |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.Advertise(operationalParams3) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.Advertise(operationalParams4) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.Advertise(operationalParams5) == CHIP_NO_ERROR); |
| } |
| |
| void CommissionableAdverts(nlTestSuite * inSuite, void * inContext) |
| { |
| auto & mdnsAdvertiser = chip::Dnssd::ServiceAdvertiser::Instance(); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.RemoveServices() == CHIP_NO_ERROR); |
| |
| auto & server = static_cast<CheckOnlyServer &>(GlobalMinimalMdnsServer::Server()); |
| server.SetTestSuite(inSuite); |
| server.Reset(); |
| |
| // Start a single operational advertiser |
| ChipLogProgress(Discovery, "Testing commissionable advertiser"); |
| // Start very basic - only the mandatory values (short and long discriminator and commissioning modes) |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.Advertise(commissionableNodeParamsSmall) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.FinalizeServiceUpdate() == CHIP_NO_ERROR); |
| |
| // Test for PTR response to _services request. |
| ChipLogProgress(Discovery, "Checking response to _services._dns-sd._udp.local for small parameters"); |
| server.AddExpectedRecord(&ptrCommissionableNodeService); |
| server.AddExpectedRecord(&ptrServiceSubLFullLen); |
| server.AddExpectedRecord(&ptrServiceSubSFullLen); |
| NL_TEST_ASSERT(inSuite, SendQuery(kDnsSdQueryName) == CHIP_NO_ERROR); |
| // These check that the requested records added are sent out correctly. |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| // Want PTR response to _matterc._udp. We will also get the SRV and TXT as additionals. |
| // We won't get any A/AAAA because this is a test and we don't have addresses. |
| // First fill in the instance name - FullQNames already have this space included. |
| NL_TEST_ASSERT(inSuite, |
| mdnsAdvertiser.GetCommissionableInstanceName(instanceNamePrefix, sizeof(instanceNamePrefix)) == CHIP_NO_ERROR); |
| |
| ChipLogProgress(Discovery, "Testing response to _matterc._udp.local for small parameters"); |
| server.Reset(); |
| server.AddExpectedRecord(&ptrCommissionableNode); |
| server.AddExpectedRecord(&srvCommissionableNode); |
| server.AddExpectedRecord(&txtCommissionableNodeParamsSmall); |
| NL_TEST_ASSERT(inSuite, SendQuery(kMatterCommissionableNodeQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| ChipLogProgress(Discovery, "Testing response to instance name for small parameters"); |
| server.Reset(); |
| // Just the SRV and TXT should return |
| server.AddExpectedRecord(&srvCommissionableNode); |
| server.AddExpectedRecord(&txtCommissionableNodeParamsSmall); |
| NL_TEST_ASSERT(inSuite, SendQuery(instanceName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| // Add more parameters, check that the subtypes and TXT values get set correctly. |
| // Also check that we get proper values when the discriminators are small (no leading 0's) |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.Advertise(commissionableNodeParamsLargeBasic) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.FinalizeServiceUpdate() == CHIP_NO_ERROR); |
| ChipLogProgress(Discovery, "Checking response to _services._dns-sd._udp.local for large basic parameters"); |
| server.Reset(); |
| server.AddExpectedRecord(&ptrCommissionableNodeService); |
| server.AddExpectedRecord(&ptrServiceSubLong); |
| server.AddExpectedRecord(&ptrServiceSubShort); |
| server.AddExpectedRecord(&ptrServiceSubCM); |
| server.AddExpectedRecord(&ptrServiceSubVendor); |
| server.AddExpectedRecord(&ptrServiceSubDeviceType); |
| NL_TEST_ASSERT(inSuite, SendQuery(kDnsSdQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| ChipLogProgress(Discovery, "Testing response to _matterc._udp.local for large basic parameters"); |
| server.Reset(); |
| server.AddExpectedRecord(&ptrCommissionableNode); |
| server.AddExpectedRecord(&srvCommissionableNode); |
| server.AddExpectedRecord(&txtCommissionableNodeParamsLargeBasic); |
| NL_TEST_ASSERT(inSuite, SendQuery(kMatterCommissionableNodeQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| ChipLogProgress(Discovery, "Testing response to instance name for large basic parameters"); |
| server.Reset(); |
| // Just the SRV and TXT should return |
| server.AddExpectedRecord(&srvCommissionableNode); |
| server.AddExpectedRecord(&txtCommissionableNodeParamsLargeBasic); |
| NL_TEST_ASSERT(inSuite, SendQuery(instanceName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.Advertise(commissionableNodeParamsLargeEnhanced) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.FinalizeServiceUpdate() == CHIP_NO_ERROR); |
| ChipLogProgress(Discovery, "Checking response to _services._dns-sd._udp.local for large enhanced parameters"); |
| server.Reset(); |
| server.AddExpectedRecord(&ptrCommissionableNodeService); |
| server.AddExpectedRecord(&ptrServiceSubLong); |
| server.AddExpectedRecord(&ptrServiceSubShort); |
| server.AddExpectedRecord(&ptrServiceSubCM); |
| server.AddExpectedRecord(&ptrServiceSubVendor); |
| server.AddExpectedRecord(&ptrServiceSubDeviceType); |
| NL_TEST_ASSERT(inSuite, SendQuery(kDnsSdQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| ChipLogProgress(Discovery, "Testing response to _matterc._udp.local for large enhanced parameters"); |
| server.Reset(); |
| server.AddExpectedRecord(&ptrCommissionableNode); |
| server.AddExpectedRecord(&srvCommissionableNode); |
| server.AddExpectedRecord(&txtCommissionableNodeParamsLargeEnhanced); |
| NL_TEST_ASSERT(inSuite, SendQuery(kMatterCommissionableNodeQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| ChipLogProgress(Discovery, "Testing response to instance name for large enhanced parameters"); |
| server.Reset(); |
| // Just the SRV and TXT should return |
| server.AddExpectedRecord(&srvCommissionableNode); |
| server.AddExpectedRecord(&txtCommissionableNodeParamsLargeEnhanced); |
| NL_TEST_ASSERT(inSuite, SendQuery(instanceName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| } |
| |
| void CommissionableAndOperationalAdverts(nlTestSuite * inSuite, void * inContext) |
| { |
| auto & mdnsAdvertiser = chip::Dnssd::ServiceAdvertiser::Instance(); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.RemoveServices() == CHIP_NO_ERROR); |
| |
| auto & server = static_cast<CheckOnlyServer &>(GlobalMinimalMdnsServer::Server()); |
| server.SetTestSuite(inSuite); |
| server.Reset(); |
| |
| // Add two operational and a commissionable and test that we get the correct values back. |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.Advertise(operationalParams1) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.Advertise(operationalParams2) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.Advertise(commissionableNodeParamsLargeEnhanced) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, mdnsAdvertiser.FinalizeServiceUpdate() == CHIP_NO_ERROR); |
| |
| // Services listing should have two operational ptrs, the base commissionable node ptr and the various _sub ptrs |
| ChipLogProgress(Discovery, "Checking response to _services._dns-sd._udp.local"); |
| server.Reset(); |
| server.AddExpectedRecord(&ptrOperationalService); |
| server.AddExpectedRecord(&ptrOperationalService); |
| server.AddExpectedRecord(&ptrCommissionableNodeService); |
| server.AddExpectedRecord(&ptrServiceSubLong); |
| server.AddExpectedRecord(&ptrServiceSubShort); |
| server.AddExpectedRecord(&ptrServiceSubCM); |
| server.AddExpectedRecord(&ptrServiceSubVendor); |
| server.AddExpectedRecord(&ptrServiceSubDeviceType); |
| server.AddExpectedRecord(&ptrServiceSubCompressedId1); |
| server.AddExpectedRecord(&ptrServiceSubCompressedId2); |
| NL_TEST_ASSERT(inSuite, SendQuery(kDnsSdQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| // Requests for _matter._tcp.local will respond with all records from both operational records, but no commissionable. |
| ChipLogProgress(Discovery, "Testing response to _matter._tcp.local"); |
| server.Reset(); |
| server.AddExpectedRecord(&ptrOperational1); |
| server.AddExpectedRecord(&srvOperational1); |
| server.AddExpectedRecord(&txtOperational1); |
| server.AddExpectedRecord(&ptrOperational2); |
| server.AddExpectedRecord(&srvOperational2); |
| server.AddExpectedRecord(&txtOperational2); |
| NL_TEST_ASSERT(inSuite, SendQuery(kMatterOperationalQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| // Responses to _matterc query should return commissionable node, but no operational. |
| ChipLogProgress(Discovery, "Testing response to _matterc._udp.local"); |
| server.Reset(); |
| server.AddExpectedRecord(&ptrCommissionableNode); |
| server.AddExpectedRecord(&srvCommissionableNode); |
| server.AddExpectedRecord(&txtCommissionableNodeParamsLargeEnhanced); |
| NL_TEST_ASSERT(inSuite, SendQuery(kMatterCommissionableNodeQueryName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| // Requests for each SRV record should give only records specific to that fabric. |
| ChipLogProgress(Discovery, "Testing response to operational instance name for fabric 1"); |
| server.Reset(); |
| // Just the SRV and TXT should return |
| server.AddExpectedRecord(&srvOperational1); |
| server.AddExpectedRecord(&txtOperational1); |
| NL_TEST_ASSERT(inSuite, SendQuery(kInstanceName1) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| ChipLogProgress(Discovery, "Testing response to operational instance name for fabric 2"); |
| server.Reset(); |
| // Just the SRV and TXT should return |
| server.AddExpectedRecord(&srvOperational2); |
| server.AddExpectedRecord(&txtOperational2); |
| NL_TEST_ASSERT(inSuite, SendQuery(kInstanceName2) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| |
| ChipLogProgress(Discovery, "Testing response to commissionable instance name"); |
| server.Reset(); |
| // Just the SRV and TXT should return |
| server.AddExpectedRecord(&srvCommissionableNode); |
| server.AddExpectedRecord(&txtCommissionableNodeParamsLargeEnhanced); |
| NL_TEST_ASSERT(inSuite, SendQuery(instanceName) == CHIP_NO_ERROR); |
| NL_TEST_ASSERT(inSuite, server.GetSendCalled()); |
| NL_TEST_ASSERT(inSuite, server.GetHeaderFound()); |
| } |
| |
| const nlTest sTests[] = { |
| NL_TEST_DEF("OperationalAdverts", OperationalAdverts), // |
| NL_TEST_DEF("CommissionableNodeAdverts", CommissionableAdverts), // |
| NL_TEST_DEF("CommissionableAndOperationalAdverts", CommissionableAndOperationalAdverts), // |
| NL_TEST_SENTINEL() // |
| }; |
| |
| } // namespace |
| |
| int TestAdvertiser() |
| { |
| chip::Platform::MemoryInit(); |
| chip::Test::IOContext context; |
| context.Init(); |
| nlTestSuite theSuite = { "AdvertiserImplMinimal", sTests, nullptr, nullptr }; |
| CheckOnlyServer server(&theSuite); |
| test::ServerSwapper swapper(&server); |
| auto & mdnsAdvertiser = chip::Dnssd::ServiceAdvertiser::Instance(); |
| mdnsAdvertiser.Init(context.GetUDPEndPointManager()); |
| nlTestRunner(&theSuite, &server); |
| server.Shutdown(); |
| context.Shutdown(); |
| mdnsAdvertiser.RemoveServices(); |
| mdnsAdvertiser.Shutdown(); |
| chip::Platform::MemoryShutdown(); |
| |
| return nlTestRunnerStats(&theSuite); |
| } |
| |
| CHIP_REGISTER_TEST_SUITE(TestAdvertiser) |