mirror of
https://github.com/espressif/openthread.git
synced 2026-10-07 08:17:40 +00:00
This commit migrates the test_srp_register_500_services.py test from the thread-cert test suite to the Nexus platform. The new C++ test (tests/nexus/test_srp_scale.cpp) implements the same functionality: it verifies that 25 SRP clients (13 routers and 12 FEDs) can successfully register a total of 500 services (20 services per client) with a single SRP server (the leader). The commit includes: - Removal of the original Python test file. - Addition of the new Nexus C++ test file. - Integration of the new test into CMakeLists.txt and run_nexus_tests.sh.
244 lines
7.2 KiB
C++
244 lines
7.2 KiB
C++
/*
|
|
* Copyright (c) 2026, The OpenThread Authors.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the copyright holder nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "platform/nexus_core.hpp"
|
|
#include "platform/nexus_node.hpp"
|
|
|
|
namespace ot {
|
|
namespace Nexus {
|
|
|
|
namespace {
|
|
|
|
const uint16_t kNumSrpClients = 25;
|
|
const uint16_t kInstanceNumPerClient = 20;
|
|
const uint16_t kServicePort = 12345;
|
|
const char *kServiceName = "_srpclient._tcp";
|
|
|
|
struct ClientInfo
|
|
{
|
|
Srp::Client::Service mServices[kInstanceNumPerClient];
|
|
String<32> mInstanceNames[kInstanceNumPerClient];
|
|
};
|
|
|
|
static ClientInfo sClientInfo[kNumSrpClients + 1];
|
|
|
|
/**
|
|
* This function registers SRP services from a given node.
|
|
*
|
|
* @param[in] aNode The node from which to register services.
|
|
* @param[in] aClientId The client ID to use for host and instance names.
|
|
*
|
|
*/
|
|
void RegisterServices(Node &aNode, uint16_t aClientId)
|
|
{
|
|
String<32> hostName;
|
|
|
|
hostName.Append("client%u", aClientId);
|
|
|
|
aNode.Get<Srp::Client>().EnableAutoStartMode(nullptr, nullptr);
|
|
SuccessOrQuit(aNode.Get<Srp::Client>().SetHostName(hostName.AsCString()));
|
|
SuccessOrQuit(aNode.Get<Srp::Client>().EnableAutoHostAddress());
|
|
|
|
for (uint16_t j = 1; j <= kInstanceNumPerClient; j++)
|
|
{
|
|
String<32> &instanceName = sClientInfo[aClientId].mInstanceNames[j - 1];
|
|
|
|
instanceName.Clear().Append("client%u_%u", aClientId, j);
|
|
|
|
Srp::Client::Service &service = sClientInfo[aClientId].mServices[j - 1];
|
|
|
|
// We use `memset` to zero-initialize the service object. This is
|
|
// safer than `ClearAllBytes` as it correctly handles the
|
|
// `LinkedListEntry` base class part.
|
|
memset(&service, 0, sizeof(service));
|
|
|
|
service.mName = kServiceName;
|
|
service.mInstanceName = instanceName.AsCString();
|
|
service.mPort = kServicePort;
|
|
|
|
SuccessOrQuit(service.Init());
|
|
|
|
Error error = aNode.Get<Srp::Client>().AddService(service);
|
|
if (error != kErrorNone)
|
|
{
|
|
Log("AddService failed with error %s (%d) for client %u, instance %u", ErrorToString(error), error,
|
|
aClientId, j);
|
|
}
|
|
SuccessOrQuit(error);
|
|
|
|
if (j % 10 == 0 || j == kInstanceNumPerClient)
|
|
{
|
|
Core::Get().AdvanceTime(5 * 1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function verifies registered services on a given SRP client node.
|
|
*
|
|
* @param[in] aNode The node to verify.
|
|
*
|
|
*/
|
|
void VerifyClient(Node &aNode)
|
|
{
|
|
const Srp::Client::Service *service = aNode.Get<Srp::Client>().GetServices().GetHead();
|
|
uint16_t count = 0;
|
|
|
|
while (service != nullptr)
|
|
{
|
|
VerifyOrQuit(service->GetState() == Srp::Client::kRegistered);
|
|
count++;
|
|
service = service->GetNext();
|
|
}
|
|
|
|
VerifyOrQuit(count == kInstanceNumPerClient);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
/**
|
|
* This test verifies SRP function that SRP clients can register up to 500 services to one SRP server.
|
|
*
|
|
* Topology:
|
|
* LEADER (SRP server)
|
|
* |
|
|
* |
|
|
* ROUTER1 ... ROUTER13 (SRP clients)
|
|
* | |
|
|
* FED14 ... FED25 (SRP clients)
|
|
*
|
|
*/
|
|
void TestSrpScale(void)
|
|
{
|
|
const uint16_t kNumRouters = (kNumSrpClients / 2) + (kNumSrpClients % 2);
|
|
const uint16_t kNumFeds = kNumSrpClients - kNumRouters;
|
|
|
|
Core nexus;
|
|
Node &leader = nexus.CreateNode();
|
|
Node *routers[kNumRouters];
|
|
Node *feds[kNumFeds];
|
|
|
|
Log("Test SRP Scale: 500 services");
|
|
|
|
leader.Form();
|
|
nexus.AdvanceTime(15 * 1000);
|
|
VerifyOrQuit(leader.Get<Mle::Mle>().IsLeader());
|
|
|
|
leader.Get<Srp::Server>().SetEnabled(true);
|
|
nexus.AdvanceTime(1000);
|
|
|
|
for (uint16_t i = 0; i < kNumRouters; i++)
|
|
{
|
|
routers[i] = &nexus.CreateNode();
|
|
routers[i]->SetName("router", i + 1);
|
|
routers[i]->Get<Mle::Mle>().SetRouterSelectionJitter(1);
|
|
routers[i]->Join(leader);
|
|
}
|
|
|
|
// Wait for routers to become routers
|
|
nexus.AdvanceTime(20 * 1000);
|
|
|
|
for (uint16_t i = 0; i < kNumRouters; i++)
|
|
{
|
|
VerifyOrQuit(routers[i]->Get<Mle::Mle>().IsRouter());
|
|
}
|
|
|
|
for (uint16_t i = 0; i < kNumFeds; i++)
|
|
{
|
|
feds[i] = &nexus.CreateNode();
|
|
feds[i]->SetName("fed", i + kNumRouters + 1);
|
|
feds[i]->Join(*routers[i], Node::kAsFed);
|
|
}
|
|
|
|
nexus.AdvanceTime(10 * 1000);
|
|
|
|
for (uint16_t i = 0; i < kNumFeds; i++)
|
|
{
|
|
VerifyOrQuit(feds[i]->Get<Mle::Mle>().IsChild());
|
|
}
|
|
|
|
Log("Registering services from routers...");
|
|
for (uint16_t i = 0; i < kNumRouters; i++)
|
|
{
|
|
RegisterServices(*routers[i], i + 1);
|
|
}
|
|
|
|
Log("Registering services from FEDs...");
|
|
for (uint16_t i = 0; i < kNumFeds; i++)
|
|
{
|
|
RegisterServices(*feds[i], i + kNumRouters + 1);
|
|
}
|
|
|
|
// Give it some more time to settle
|
|
nexus.AdvanceTime(20 * 1000);
|
|
|
|
Log("Verifying registrations...");
|
|
|
|
for (uint16_t i = 0; i < kNumRouters; i++)
|
|
{
|
|
VerifyClient(*routers[i]);
|
|
}
|
|
|
|
for (uint16_t i = 0; i < kNumFeds; i++)
|
|
{
|
|
VerifyClient(*feds[i]);
|
|
}
|
|
|
|
uint32_t totalServices = 0;
|
|
const Srp::Server::Host *host = nullptr;
|
|
while ((host = leader.Get<Srp::Server>().GetNextHost(host)) != nullptr)
|
|
{
|
|
const Srp::Server::Service *service = nullptr;
|
|
while ((service = host->GetNextService(service)) != nullptr)
|
|
{
|
|
if (!service->IsDeleted())
|
|
{
|
|
totalServices++;
|
|
}
|
|
}
|
|
}
|
|
|
|
Log("Total services registered on server: %u", totalServices);
|
|
VerifyOrQuit(totalServices == kNumSrpClients * kInstanceNumPerClient);
|
|
|
|
Log("Test passed!");
|
|
}
|
|
|
|
} // namespace Nexus
|
|
} // namespace ot
|
|
|
|
int main(void)
|
|
{
|
|
ot::Nexus::TestSrpScale();
|
|
printf("All tests passed\n");
|
|
return 0;
|
|
}
|