3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2013-2017 Nest Labs, Inc.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 * This file tests DNS resolution using the CHIP Inet Layer APIs.
26 #ifndef __STDC_LIMIT_MACROS
27 #define __STDC_LIMIT_MACROS
35 #include <nlunit-test.h>
37 #include <CHIPVersion.h>
39 #include <inet/InetLayer.h>
40 #include <support/CodeUtils.h>
41 #include <support/UnitTestRegistration.h>
43 #include <system/SystemClock.h>
44 #include <system/SystemTimer.h>
46 #include "TestInetCommon.h"
47 #include "TestSetupSignalling.h"
50 using namespace chip::Inet;
52 #if INET_CONFIG_ENABLE_DNS_RESOLVER
54 #define TOOL_NAME "TestInetLayerDNS"
56 #define DISABLE_BROKEN_DNS_TESTS 1 // https://github.com/project-chip/connectedhomeip/issues/4670
58 #define DEFAULT_TEST_DURATION_MILLISECS (20000)
59 #define DEFAULT_CANCEL_TEST_DURATION_MILLISECS (2000)
61 static uint32_t sNumResInProgress = 0;
62 constexpr uint8_t kMaxResults = 20;
64 struct DNSResolutionTestCase
66 const char * hostName;
74 struct DNSResolutionTestContext
76 nlTestSuite * testSuite;
77 DNSResolutionTestCase testCase;
79 IPAddress resultsBuf[kMaxResults];
82 static void RunTestCase(nlTestSuite * testSuite, const DNSResolutionTestCase & testCase);
83 static void StartTestCase(DNSResolutionTestContext & testContext);
84 static void HandleResolutionComplete(void * appState, INET_ERROR err, uint8_t addrCount, IPAddress * addrArray);
85 static void ServiceNetworkUntilDone(uint32_t timeoutMS);
86 static void HandleSIGUSR1(int sig);
89 * Test basic name resolution functionality.
91 static void TestDNSResolution_Basic(nlTestSuite * testSuite, void * testContext)
95 #ifndef DISABLE_BROKEN_DNS_TESTS
96 // Test resolving a name with only IPv4 addresses.
97 RunTestCase(testSuite,
109 // Test resolving a name with only IPv6 addresses.
110 RunTestCase(testSuite,
111 DNSResolutionTestCase
122 // Test resolving a name with IPv4 and IPv6 addresses.
123 RunTestCase(testSuite,
124 DNSResolutionTestCase
139 * Test resolving a name using various address type options.
141 static void TestDNSResolution_AddressTypeOption(nlTestSuite * testSuite, void * testContext)
144 #ifndef DISABLE_BROKEN_DNS_TESTS
146 // Test requesting IPv4 addresses only.
147 #if INET_CONFIG_ENABLE_IPV4
148 RunTestCase(testSuite,
149 DNSResolutionTestCase
152 kDNSOption_AddrFamily_IPv4Only,
159 #endif // INET_CONFIG_ENABLE_IPV4
161 // Test requesting IPv6 addresses only.
162 RunTestCase(testSuite,
163 DNSResolutionTestCase
166 kDNSOption_AddrFamily_IPv6Only,
174 // Test requesting IPv4 address preferentially.
175 #if INET_CONFIG_ENABLE_IPV4
176 RunTestCase(testSuite,
177 DNSResolutionTestCase
180 kDNSOption_AddrFamily_IPv4Preferred,
187 #endif // INET_CONFIG_ENABLE_IPV4
189 // Test requesting IPv6 address preferentially.
190 RunTestCase(testSuite,
191 DNSResolutionTestCase
194 kDNSOption_AddrFamily_IPv6Preferred,
207 * Test resolving a name with a limited number of results.
209 static void TestDNSResolution_RestrictedResults(nlTestSuite * testSuite, void * testContext)
213 // Test requesting 2 IPv4 addresses. This should result in, at most, 2 IPv4 addresses.
214 #if INET_CONFIG_ENABLE_IPV4
215 RunTestCase(testSuite,
216 DNSResolutionTestCase
219 kDNSOption_AddrFamily_IPv4Only,
226 #endif // INET_CONFIG_ENABLE_IPV4
228 // Test requesting 2 IPv6 addresses. This should result in, at most, 2 IPv6 addresses.
229 RunTestCase(testSuite,
230 DNSResolutionTestCase
233 kDNSOption_AddrFamily_IPv6Only,
241 // Test requesting 2 addresses, preferring IPv4. This should result in 1 IPv4 address
242 // followed by 1 IPv6 address.
243 #if INET_CONFIG_ENABLE_IPV4
244 RunTestCase(testSuite,
245 DNSResolutionTestCase
248 kDNSOption_AddrFamily_IPv4Preferred,
255 #endif // INET_CONFIG_ENABLE_IPV4
257 // Test requesting 2 addresses, preferring IPv6. This should result in 1 IPv6 address
258 // followed by 1 IPv4 address.
259 RunTestCase(testSuite,
260 DNSResolutionTestCase
263 kDNSOption_AddrFamily_IPv6Preferred,
274 * Test resolving a non-existant name.
276 static void TestDNSResolution_NoRecord(nlTestSuite * testSuite, void * testContext)
279 #ifndef DISABLE_BROKEN_DNS_TESTS
280 RunTestCase(testSuite,
281 DNSResolutionTestCase
283 "www.google.invalid.",
284 kDNSOption_AddrFamily_Any,
286 INET_ERROR_HOST_NOT_FOUND,
296 * Test resolving a name where the resultant DNS entry lacks an A or AAAA record.
298 static void TestDNSResolution_NoHostRecord(nlTestSuite * testSuite, void * testContext)
302 // Test resolving a name that has no host records (A or AAAA).
303 RunTestCase(testSuite,
304 DNSResolutionTestCase
307 kDNSOption_AddrFamily_Any,
309 INET_ERROR_HOST_NOT_FOUND,
315 // Test resolving a name that has only AAAA records, while requesting IPv4 addresses only.
316 #if INET_CONFIG_ENABLE_IPV4
317 RunTestCase(testSuite,
318 DNSResolutionTestCase
321 kDNSOption_AddrFamily_IPv4Only,
323 INET_ERROR_HOST_NOT_FOUND,
328 #endif // INET_CONFIG_ENABLE_IPV4
330 // Test resolving a name that has only A records, while requesting IPv6 addresses only.
331 RunTestCase(testSuite,
332 DNSResolutionTestCase
335 kDNSOption_AddrFamily_IPv6Only,
337 INET_ERROR_HOST_NOT_FOUND,
346 * Test resolving text form IP addresses.
348 static void TestDNSResolution_TextForm(nlTestSuite * testSuite, void * testContext)
351 RunTestCase(testSuite,
352 DNSResolutionTestCase
355 kDNSOption_AddrFamily_Any,
363 RunTestCase(testSuite,
364 DNSResolutionTestCase
366 "2607:f8b0:4005:804::200e",
367 kDNSOption_AddrFamily_Any,
375 // Test resolving text form IPv4 and IPv6 addresses while requesting an
376 // incompatible address type.
378 RunTestCase(testSuite,
379 DNSResolutionTestCase
382 kDNSOption_AddrFamily_IPv6Only,
384 INET_ERROR_INCOMPATIBLE_IP_ADDRESS_TYPE,
390 RunTestCase(testSuite,
391 DNSResolutionTestCase
393 "2607:f8b0:4005:804::200e",
394 kDNSOption_AddrFamily_IPv4Only,
396 INET_ERROR_INCOMPATIBLE_IP_ADDRESS_TYPE,
404 static void TestDNSResolution_Cancel(nlTestSuite * testSuite, void * inContext)
406 DNSResolutionTestContext testContext{
407 testSuite, DNSResolutionTestCase{ "www.google.com", kDNSOption_Default, kMaxResults, INET_NO_ERROR, true, false }
410 // Start DNS resolution.
411 StartTestCase(testContext);
413 // If address resolution did NOT complete synchronously...
414 // (NOTE: If address resolution completes synchronously then this test is effectively
415 // void, as there's no opportunity to cancel the request).
416 if (!testContext.callbackCalled)
418 // Cancel the resolution before it completes.
419 gInet.CancelResolveHostAddress(HandleResolutionComplete, &testContext);
421 // Service the network for awhile to see what happens (should timeout).
422 ServiceNetworkUntilDone(DEFAULT_CANCEL_TEST_DURATION_MILLISECS);
424 // Verify that the completion function was NOT called.
425 NL_TEST_ASSERT(testSuite, testContext.callbackCalled == false);
429 sNumResInProgress = 0;
432 static void TestDNSResolution_Simultaneous(nlTestSuite * testSuite, void * inContext)
435 DNSResolutionTestContext tests[] =
439 DNSResolutionTestCase
451 DNSResolutionTestCase
463 DNSResolutionTestCase
475 DNSResolutionTestCase
488 // Start multiple DNS resolutions simultaneously.
489 for (DNSResolutionTestContext & testContext : tests)
491 StartTestCase(testContext);
494 // Service the network until each completes, or a timeout occurs.
495 ServiceNetworkUntilDone(DEFAULT_TEST_DURATION_MILLISECS);
497 // Verify no timeout occurred.
498 NL_TEST_ASSERT(testSuite, gDone == true);
500 // Sanity check test logic.
501 NL_TEST_ASSERT(testSuite, sNumResInProgress == 0);
504 static void RunTestCase(nlTestSuite * testSuite, const DNSResolutionTestCase & testCase)
506 DNSResolutionTestContext testContext{ testSuite, testCase };
508 // Start DNS resolution.
509 StartTestCase(testContext);
511 // Service the network until the completion callback is called.
512 ServiceNetworkUntilDone(DEFAULT_TEST_DURATION_MILLISECS);
514 // Verify no timeout occurred.
515 NL_TEST_ASSERT(testSuite, gDone == true);
517 // Sanity check test logic.
518 NL_TEST_ASSERT(testSuite, sNumResInProgress == 0);
521 static void StartTestCase(DNSResolutionTestContext & testContext)
523 INET_ERROR err = INET_NO_ERROR;
524 DNSResolutionTestCase & testCase = testContext.testCase;
525 nlTestSuite * testSuite = testContext.testSuite;
530 printf("Resolving hostname %s\n", testCase.hostName);
531 err = gInet.ResolveHostAddress(testCase.hostName, strlen(testCase.hostName), testCase.dnsOptions, testCase.maxResults,
532 testContext.resultsBuf, HandleResolutionComplete, &testContext);
534 if (err != INET_NO_ERROR)
536 printf("ResolveHostAddress failed for %s: %s\n", testCase.hostName, ::chip::ErrorStr(err));
538 // Verify the expected error
539 NL_TEST_ASSERT(testSuite, err == testCase.expectErr);
541 // Verify the callback WASN'T called
542 NL_TEST_ASSERT(testSuite, testContext.callbackCalled == false); //
545 if (sNumResInProgress == 0)
552 static void HandleResolutionComplete(void * appState, INET_ERROR err, uint8_t addrCount, IPAddress * addrArray)
554 DNSResolutionTestContext & testContext = *static_cast<DNSResolutionTestContext *>(appState);
555 DNSResolutionTestCase & testCase = testContext.testCase;
556 nlTestSuite * testSuite = testContext.testSuite;
558 if (err == INET_NO_ERROR)
560 printf("DNS resolution complete for %s: %" PRIu8 " result%s returned\n", testCase.hostName, addrCount,
561 (addrCount != 1) ? "s" : "");
562 for (uint8_t i = 0; i < addrCount; i++)
564 char ipAddrStr[INET6_ADDRSTRLEN];
566 printf(" %s\n", addrArray[i].ToString(ipAddrStr, sizeof(ipAddrStr)));
571 printf("DNS resolution complete for %s: %s\n", testCase.hostName, ::chip::ErrorStr(err));
574 // Verify the expected result.
575 NL_TEST_ASSERT(testSuite, err == testCase.expectErr);
577 if (err == INET_NO_ERROR)
579 // Make sure the number of addresses is within the max expected.
580 NL_TEST_ASSERT(testSuite, addrCount <= testCase.maxResults);
582 // Determine the types of addresses in the response and their relative ordering.
583 bool respContainsIPv4Addrs = false;
584 bool respContainsIPv6Addrs = false;
586 for (uint8_t i = 0; i < addrCount; i++)
588 respContainsIPv4Addrs = respContainsIPv4Addrs || (addrArray[i].Type() == kIPAddressType_IPv4);
589 respContainsIPv6Addrs = respContainsIPv6Addrs || (addrArray[i].Type() == kIPAddressType_IPv6);
592 // Verify the expected address types were returned.
593 // The current LwIP DNS implementation returns at most one address. So if the test expects
594 // both IPv4 and IPv6 addresses, relax this to accept either.
595 #if CHIP_SYSTEM_CONFIG_USE_LWIP
596 if (testCase.expectIPv4Addrs && testCase.expectIPv6Addrs)
598 NL_TEST_ASSERT(testSuite, respContainsIPv4Addrs || respContainsIPv6Addrs);
601 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
603 if (testCase.expectIPv4Addrs)
605 NL_TEST_ASSERT(testSuite, respContainsIPv4Addrs);
607 if (testCase.expectIPv6Addrs)
609 NL_TEST_ASSERT(testSuite, respContainsIPv6Addrs);
613 // Verify that only the requested address types were returned, and that the
614 // addresses were returned in the correct order.
615 switch (testCase.dnsOptions & kDNSOption_AddrFamily_Mask)
617 case kDNSOption_AddrFamily_Any:
619 case kDNSOption_AddrFamily_IPv4Only:
620 NL_TEST_ASSERT(testSuite, !respContainsIPv6Addrs);
622 case kDNSOption_AddrFamily_IPv4Preferred:
623 if (respContainsIPv4Addrs)
625 NL_TEST_ASSERT(testSuite, addrArray[0].Type() == kIPAddressType_IPv4);
628 case kDNSOption_AddrFamily_IPv6Only:
629 NL_TEST_ASSERT(testSuite, !respContainsIPv4Addrs);
631 case kDNSOption_AddrFamily_IPv6Preferred:
632 if (respContainsIPv6Addrs)
634 NL_TEST_ASSERT(testSuite, addrArray[0].Type() == kIPAddressType_IPv6);
638 constexpr bool UnexpectedAddressTypeValue = true;
639 NL_TEST_ASSERT(testSuite, !UnexpectedAddressTypeValue);
643 testContext.callbackCalled = true;
646 if (sNumResInProgress == 0)
652 static void ServiceNetworkUntilDone(uint32_t timeoutMS)
654 uint64_t timeoutTimeMS = System::Layer::GetClock_MonotonicMS() + timeoutMS;
655 struct timeval sleepTime;
656 sleepTime.tv_sec = 0;
657 sleepTime.tv_usec = 10000;
661 ServiceNetwork(sleepTime);
663 if (System::Layer::GetClock_MonotonicMS() >= timeoutTimeMS)
670 static void HandleSIGUSR1(int sig)
677 int TestInetLayerDNSInternal()
680 const nlTest DNSTests[] =
682 NL_TEST_DEF("TestDNSResolution:Basic", TestDNSResolution_Basic),
683 NL_TEST_DEF("TestDNSResolution:AddressTypeOption", TestDNSResolution_AddressTypeOption),
684 NL_TEST_DEF("TestDNSResolution:RestrictedResults", TestDNSResolution_RestrictedResults),
685 NL_TEST_DEF("TestDNSResolution:TextForm", TestDNSResolution_TextForm),
686 NL_TEST_DEF("TestDNSResolution:NoRecord", TestDNSResolution_NoRecord),
687 NL_TEST_DEF("TestDNSResolution:NoHostRecord", TestDNSResolution_NoHostRecord),
688 NL_TEST_DEF("TestDNSResolution:Cancel", TestDNSResolution_Cancel),
689 NL_TEST_DEF("TestDNSResolution:Simultaneous", TestDNSResolution_Simultaneous),
690 NL_TEST_SENTINEL() };
692 nlTestSuite DNSTestSuite =
701 InitTestInetCommon();
706 // Run all tests in Suite
708 nlTestRunner(&DNSTestSuite, nullptr);
711 ShutdownSystemLayer();
713 return nlTestRunnerStats(&DNSTestSuite);
716 CHIP_REGISTER_TEST_SUITE(TestInetLayerDNSInternal)
717 #else // !INET_CONFIG_ENABLE_DNS_RESOLVER
719 int TestInetLayerDNSInternal(void)
721 fprintf(stderr, "Please assert INET_CONFIG_ENABLE_DNS_RESOLVER to use this test.\n");
723 return (EXIT_SUCCESS);
726 #endif // !INET_CONFIG_ENABLE_DNS_RESOLVER
728 int TestInetLayerDNS()
730 SetSignalHandler(HandleSIGUSR1);
732 nlTestSetOutputStyle(OUTPUT_CSV);
734 return (TestInetLayerDNSInternal());