Skip to content

Commit

Permalink
Refactor mDNS test runner to allow adding new tests
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
arkq committed Apr 21, 2023
1 parent cbf5e3e commit b3fa580
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 110 deletions.
2 changes: 1 addition & 1 deletion src/platform/tests/TestConfigurationMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion src/platform/tests/TestConnectivityMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
219 changes: 114 additions & 105 deletions src/platform/tests/TestDnssd.cpp
Original file line number Diff line number Diff line change
@@ -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 <condition_variable>
#include <mutex>
#include <thread>
Expand All @@ -14,47 +37,75 @@ 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<std::mutex> lock(mDoneMutex);
mDone = true;
mDoneCondition.notify_all();
}

CHIP_ERROR Wait(chip::System::Clock::Timeout aDelay)
{
std::unique_lock<std::mutex> 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<chip::Inet::IPAddress> & addresses,
CHIP_ERROR error)
{
auto * browseContext = static_cast<DnssdBrowseContext *>(context);
auto * suite = browseContext->mTestSuite;
char addrBuf[100];
nlTestSuite * suite = static_cast<nlTestSuite *>(context);

NL_TEST_ASSERT(suite, result != nullptr);
NL_TEST_ASSERT(suite, error == CHIP_NO_ERROR);

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<const char *>(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<nlTestSuite *>(context);
auto * browseContext = static_cast<DnssdBrowseContext *>(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)
{
Expand All @@ -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<nlTestSuite *>(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<nlTestSuite *>(context);
DnssdBrowseContext browseContext;
browseContext.mTestSuite = inSuite;

NL_TEST_ASSERT(suite, error == CHIP_NO_ERROR);
DnssdService service{};
TextEntry entry{ "key", reinterpret_cast<const uint8_t *>("val"), 3 };

service.mInterface = chip::Inet::InterfaceId::Null();
service.mPort = 80;
Expand All @@ -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<const uint8_t *>(val);
entry.mDataSize = strlen(reinterpret_cast<const char *>(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<std::mutex> 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<std::mutex> lock(mtx);
done = true;
doneCondition.notify_all();
}
});

{
std::unique_lock<std::mutex> 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);
2 changes: 1 addition & 1 deletion src/platform/tests/TestKeyValueStoreMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion src/platform/tests/TestPlatformMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion src/platform/tests/TestPlatformTime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down

0 comments on commit b3fa580

Please sign in to comment.