From b3fa580f563029b15c819be97cdced9f33512737 Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Fri, 21 Apr 2023 21:32:58 +0200 Subject: [PATCH] Refactor mDNS test runner to allow adding new tests Now, all tests will share initialized matter stack and event loop. Instead of stopping event loop (in order to trigger test end) we will use dedicated browse context with its own condition variable. --- src/platform/tests/TestConfigurationMgr.cpp | 2 +- src/platform/tests/TestConnectivityMgr.cpp | 2 +- src/platform/tests/TestDnssd.cpp | 219 ++++++++++---------- src/platform/tests/TestKeyValueStoreMgr.cpp | 2 +- src/platform/tests/TestPlatformMgr.cpp | 2 +- src/platform/tests/TestPlatformTime.cpp | 2 +- 6 files changed, 119 insertions(+), 110 deletions(-) diff --git a/src/platform/tests/TestConfigurationMgr.cpp b/src/platform/tests/TestConfigurationMgr.cpp index aafdf4a63cfa31..91dabe222f28fd 100644 --- a/src/platform/tests/TestConfigurationMgr.cpp +++ b/src/platform/tests/TestConfigurationMgr.cpp @@ -499,7 +499,7 @@ int TestConfigurationMgr() { nlTestSuite theSuite = { "ConfigurationMgr tests", &sTests[0], TestConfigurationMgr_Setup, TestConfigurationMgr_Teardown }; - // Run test suit againt one context. + // Run test suit against one context. nlTestRunner(&theSuite, nullptr); return nlTestRunnerStats(&theSuite); } diff --git a/src/platform/tests/TestConnectivityMgr.cpp b/src/platform/tests/TestConnectivityMgr.cpp index 932be3dcfc5b1a..6cf205737a330a 100644 --- a/src/platform/tests/TestConnectivityMgr.cpp +++ b/src/platform/tests/TestConnectivityMgr.cpp @@ -99,7 +99,7 @@ int TestConnectivityMgr() { nlTestSuite theSuite = { "ConfigurationMgr tests", &sTests[0], TestConnectivityMgr_Setup, TestConnectivityMgr_Teardown }; - // Run test suit againt one context. + // Run test suit against one context. nlTestRunner(&theSuite, nullptr); return nlTestRunnerStats(&theSuite); } diff --git a/src/platform/tests/TestDnssd.cpp b/src/platform/tests/TestDnssd.cpp index 71540355d32355..6a9048698381e1 100644 --- a/src/platform/tests/TestDnssd.cpp +++ b/src/platform/tests/TestDnssd.cpp @@ -1,3 +1,26 @@ +/* + * + * 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. + */ + +/** + * @file + * This file implements a unit test suite for the mDNS code functionality. + * + */ + #include #include #include @@ -14,15 +37,44 @@ using chip::Dnssd::DnssdService; using chip::Dnssd::DnssdServiceProtocol; using chip::Dnssd::TextEntry; -static unsigned int gBrowsedServicesCount = 0; -static unsigned int gResolvedServicesCount = 0; -static bool gEndOfInput = false; +namespace { + +struct DnssdBrowseContext +{ + nlTestSuite * mTestSuite; + + unsigned int mBrowsedServicesCount = 0; + unsigned int mResolvedServicesCount = 0; + bool mEndOfInput = false; + + void Done() + { + std::lock_guard lock(mDoneMutex); + mDone = true; + mDoneCondition.notify_all(); + } + + CHIP_ERROR Wait(chip::System::Clock::Timeout aDelay) + { + std::unique_lock lock(mDoneMutex); + bool ok = mDoneCondition.wait_for(lock, aDelay, [this]() { return mDone; }); + return ok ? CHIP_NO_ERROR : CHIP_ERROR_TIMEOUT; + } + +private: + std::mutex mDoneMutex; + std::condition_variable mDoneCondition; + bool mDone = false; +}; + +} // namespace static void HandleResolve(void * context, DnssdService * result, const chip::Span & addresses, CHIP_ERROR error) { + auto * browseContext = static_cast(context); + auto * suite = browseContext->mTestSuite; char addrBuf[100]; - nlTestSuite * suite = static_cast(context); NL_TEST_ASSERT(suite, result != nullptr); NL_TEST_ASSERT(suite, error == CHIP_NO_ERROR); @@ -30,31 +82,30 @@ static void HandleResolve(void * context, DnssdService * result, const chip::Spa if (!addresses.empty()) { addresses.data()[0].ToString(addrBuf, sizeof(addrBuf)); - printf("Service[%u] at [%s]:%u\n", gResolvedServicesCount, addrBuf, result->mPort); + printf("Service[%u] at [%s]:%u\n", browseContext->mResolvedServicesCount, addrBuf, result->mPort); } NL_TEST_ASSERT(suite, result->mTextEntrySize == 1); NL_TEST_ASSERT(suite, strcmp(result->mTextEntries[0].mKey, "key") == 0); NL_TEST_ASSERT(suite, strcmp(reinterpret_cast(result->mTextEntries[0].mData), "val") == 0); - if (gBrowsedServicesCount == ++gResolvedServicesCount) + if (browseContext->mBrowsedServicesCount == ++browseContext->mResolvedServicesCount) { - // After last service is resolved, stop the event loop, - // so the test case can gracefully exit. - chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); + browseContext->Done(); } } static void HandleBrowse(void * context, DnssdService * services, size_t servicesSize, bool finalBrowse, CHIP_ERROR error) { - nlTestSuite * suite = static_cast(context); + auto * browseContext = static_cast(context); + auto * suite = browseContext->mTestSuite; // Make sure that we will not be called again after end-of-input is set - NL_TEST_ASSERT(suite, gEndOfInput == false); + NL_TEST_ASSERT(suite, browseContext->mEndOfInput == false); NL_TEST_ASSERT(suite, error == CHIP_NO_ERROR); - gBrowsedServicesCount += servicesSize; - gEndOfInput = finalBrowse; + browseContext->mBrowsedServicesCount += servicesSize; + browseContext->mEndOfInput = finalBrowse; if (servicesSize > 0) { @@ -63,22 +114,31 @@ static void HandleBrowse(void * context, DnssdService * services, size_t service { printf("Service[%u] name %s\n", i, services[i].mName); printf("Service[%u] type %s\n", i, services[i].mType); - NL_TEST_ASSERT(suite, ChipDnssdResolve(&services[i], services[i].mInterface, HandleResolve, suite) == CHIP_NO_ERROR); + NL_TEST_ASSERT(suite, ChipDnssdResolve(&services[i], services[i].mInterface, HandleResolve, context) == CHIP_NO_ERROR); } } } +static void DnssdInitCallback(void * context, CHIP_ERROR error) +{ + VerifyOrReturn(error == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "mDNS init error: %" CHIP_ERROR_FORMAT, error.Format())); + NL_TEST_ASSERT(static_cast(context), error == CHIP_NO_ERROR); +} + +static void DnssdErrorCallback(void * context, CHIP_ERROR error) +{ + VerifyOrDieWithMsg(error == CHIP_NO_ERROR, DeviceLayer, "mDNS error: %" CHIP_ERROR_FORMAT, error.Format()); +} + static void HandlePublish(void * context, const char * type, const char * instanceName, CHIP_ERROR error) {} -static void InitCallback(void * context, CHIP_ERROR error) +void TestDnssdPubSub(nlTestSuite * inSuite, void * inContext) { - DnssdService service; - TextEntry entry; - char key[] = "key"; - char val[] = "val"; - nlTestSuite * suite = static_cast(context); + DnssdBrowseContext browseContext; + browseContext.mTestSuite = inSuite; - NL_TEST_ASSERT(suite, error == CHIP_NO_ERROR); + DnssdService service{}; + TextEntry entry{ "key", reinterpret_cast("val"), 3 }; service.mInterface = chip::Inet::InterfaceId::Null(); service.mPort = 80; @@ -87,107 +147,56 @@ static void InitCallback(void * context, CHIP_ERROR error) strcpy(service.mType, "_mock"); service.mAddressType = chip::Inet::IPAddressType::kAny; service.mProtocol = DnssdServiceProtocol::kDnssdProtocolTcp; - entry.mKey = key; - entry.mData = reinterpret_cast(val); - entry.mDataSize = strlen(reinterpret_cast(entry.mData)); service.mTextEntries = &entry; service.mTextEntrySize = 1; service.mSubTypes = nullptr; service.mSubTypeSize = 0; - NL_TEST_ASSERT(suite, ChipDnssdPublishService(&service, HandlePublish) == CHIP_NO_ERROR); + chip::DeviceLayer::PlatformMgr().LockChipStack(); + + NL_TEST_ASSERT(inSuite, chip::Dnssd::ChipDnssdInit(DnssdInitCallback, DnssdErrorCallback, inSuite) == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, ChipDnssdPublishService(&service, HandlePublish) == CHIP_NO_ERROR); + intptr_t browseIdentifier; - ChipDnssdBrowse("_mock", DnssdServiceProtocol::kDnssdProtocolTcp, chip::Inet::IPAddressType::kAny, - chip::Inet::InterfaceId::Null(), HandleBrowse, suite, &browseIdentifier); -} + NL_TEST_ASSERT(inSuite, + ChipDnssdBrowse("_mock", DnssdServiceProtocol::kDnssdProtocolTcp, chip::Inet::IPAddressType::kAny, + chip::Inet::InterfaceId::Null(), HandleBrowse, &browseContext, + &browseIdentifier) == CHIP_NO_ERROR); -static void ErrorCallback(void * context, CHIP_ERROR error) -{ - VerifyOrDieWithMsg(error == CHIP_NO_ERROR, DeviceLayer, "Mdns error: %" CHIP_ERROR_FORMAT "\n", error.Format()); -} + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); -void TestDnssdPubSub(nlTestSuite * inSuite, void * inContext) -{ - chip::Platform::MemoryInit(); - chip::DeviceLayer::PlatformMgr().InitChipStack(); - NL_TEST_ASSERT(inSuite, chip::Dnssd::ChipDnssdInit(InitCallback, ErrorCallback, inSuite) == CHIP_NO_ERROR); + NL_TEST_ASSERT(inSuite, browseContext.Wait(chip::System::Clock::Seconds32(5)) == CHIP_NO_ERROR); - ChipLogProgress(DeviceLayer, "Start EventLoop"); - chip::DeviceLayer::PlatformMgr().RunEventLoop(); - ChipLogProgress(DeviceLayer, "End EventLoop"); + chip::DeviceLayer::PlatformMgr().LockChipStack(); + chip::Dnssd::ChipDnssdShutdown(); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); } static const nlTest sTests[] = { NL_TEST_DEF("Test Dnssd::PubSub", TestDnssdPubSub), NL_TEST_SENTINEL() }; -int TestDnssd() +int TestDnssd_Setup(void * inContext) { - std::mutex mtx; - - std::condition_variable readyCondition; - bool ready = false; - - std::condition_variable doneCondition; - bool done = false; - bool shutdown = false; - - int retVal = EXIT_FAILURE; - - std::thread t([&]() { - { - std::lock_guard lock(mtx); - ready = true; - readyCondition.notify_one(); - } - - nlTestSuite theSuite = { "CHIP DeviceLayer mdns tests", &sTests[0], nullptr, nullptr }; - - nlTestRunner(&theSuite, nullptr); - retVal = nlTestRunnerStats(&theSuite); - - { - std::lock_guard lock(mtx); - done = true; - doneCondition.notify_all(); - } - }); - - { - std::unique_lock lock(mtx); - readyCondition.wait(lock, [&] { return ready; }); - - doneCondition.wait_for(lock, std::chrono::seconds(5)); - if (!done) - { - fprintf(stderr, "mDNS test timeout, is avahi daemon running?\n"); - - // - // This will stop the event loop above, and wait till it has actually stopped - // (i.e exited RunEventLoop()). - // - chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); - chip::Dnssd::ChipDnssdShutdown(); - chip::DeviceLayer::PlatformMgr().Shutdown(); - shutdown = true; - - doneCondition.wait_for(lock, std::chrono::seconds(1)); - if (!done) - { - fprintf(stderr, "Orderly shutdown of the platform main loop failed as well.\n"); - } - retVal = EXIT_FAILURE; - } - } - t.join(); + VerifyOrReturnError(chip::Platform::MemoryInit() == CHIP_NO_ERROR, FAILURE); + VerifyOrReturnError(chip::DeviceLayer::PlatformMgr().InitChipStack() == CHIP_NO_ERROR, FAILURE); + VerifyOrReturnError(chip::DeviceLayer::PlatformMgr().StartEventLoopTask() == CHIP_NO_ERROR, FAILURE); + return SUCCESS; +} - if (!shutdown) - { - chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); - chip::Dnssd::ChipDnssdShutdown(); - chip::DeviceLayer::PlatformMgr().Shutdown(); - } +int TestDnssd_Teardown(void * inContext) +{ + VerifyOrReturnError(chip::DeviceLayer::PlatformMgr().StopEventLoopTask() == CHIP_NO_ERROR, FAILURE); + chip::DeviceLayer::PlatformMgr().Shutdown(); chip::Platform::MemoryShutdown(); + return SUCCESS; +} + +int TestDnssd() +{ + nlTestSuite theSuite = { "CHIP DeviceLayer mDNS tests", &sTests[0], TestDnssd_Setup, TestDnssd_Teardown }; - return retVal; + // Run test suit against one context. + nlTestRunner(&theSuite, nullptr); + return nlTestRunnerStats(&theSuite); } CHIP_REGISTER_TEST_SUITE(TestDnssd); diff --git a/src/platform/tests/TestKeyValueStoreMgr.cpp b/src/platform/tests/TestKeyValueStoreMgr.cpp index fad7e490078069..f189493afe6956 100644 --- a/src/platform/tests/TestKeyValueStoreMgr.cpp +++ b/src/platform/tests/TestKeyValueStoreMgr.cpp @@ -353,7 +353,7 @@ int TestKeyValueStoreMgr() { nlTestSuite theSuite = { "KeyValueStoreMgr tests", &sTests[0], TestKeyValueStoreMgr_Setup, TestKeyValueStoreMgr_Teardown }; - // Run test suit againt one context. + // Run test suit against one context. nlTestRunner(&theSuite, nullptr); return nlTestRunnerStats(&theSuite); } diff --git a/src/platform/tests/TestPlatformMgr.cpp b/src/platform/tests/TestPlatformMgr.cpp index cd2caab4b96eb9..1e8b5741c70369 100644 --- a/src/platform/tests/TestPlatformMgr.cpp +++ b/src/platform/tests/TestPlatformMgr.cpp @@ -247,7 +247,7 @@ int TestPlatformMgr() { nlTestSuite theSuite = { "PlatformMgr tests", &sTests[0], TestPlatformMgr_Setup, TestPlatformMgr_Teardown }; - // Run test suit againt one context. + // Run test suit against one context. nlTestRunner(&theSuite, nullptr); return nlTestRunnerStats(&theSuite); } diff --git a/src/platform/tests/TestPlatformTime.cpp b/src/platform/tests/TestPlatformTime.cpp index 95698f0d696f15..cca7db7e69c691 100644 --- a/src/platform/tests/TestPlatformTime.cpp +++ b/src/platform/tests/TestPlatformTime.cpp @@ -125,7 +125,7 @@ int TestPlatformTime() { nlTestSuite theSuite = { "PlatformTime tests", &sTests[0], nullptr, nullptr }; - // Run test suit againt one context. + // Run test suit against one context. nlTestRunner(&theSuite, nullptr); return nlTestRunnerStats(&theSuite); }