[nexus] add support for CLI testing (#13110)

This commit adds support for interacting with nodes via the CLI in the
Nexus simulation framework. This enables writing higher-level
integration tests that verify stack behavior and state through
standard CLI commands.

Key changes:
- Integrated `Cli::Interpreter` into the `Nexus::Node` class.
- Added `Node::InputCli()` to allow sending commands to a node with
  `printf`-style formatting.
- Implemented output capturing logic in `Node::HandleCliOutput()` to
  buffer and parse CLI responses into individual lines, stored in a
  `CliOutputArray`.
- Added helper methods to `CliOutputLine` for matching and validating
  the captured output.
- Added a new `cli_basic` Nexus test to demonstrate and validate the
  CLI interaction functionality.
This commit is contained in:
Abtin Keshavarzian
2026-05-18 13:03:46 -07:00
committed by GitHub
parent 56010e2f65
commit 86b8bf6de4
6 changed files with 339 additions and 0 deletions
+105
View File
@@ -37,10 +37,12 @@ namespace Nexus {
Node::Node(void)
: Platform(static_cast<Instance &>(*this))
, mCliInterpreter(static_cast<Instance *>(this), HandleCliOutput, this)
, mX(0.0f)
, mY(0.0f)
, mLastParentId(0xffff)
{
mCliInterpreter.SetPromptConfig(false);
}
void Node::Reset(void)
@@ -298,6 +300,109 @@ const char *Node::GetExtendedRoleString(void) const
return roleStr;
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Cli
Node::CliOutputLine &Node::CliOutputLine::operator=(const CliOutputLine &aOther)
{
SuccessOrQuit(mLine.Set(aOther.mLine));
return *this;
}
Node::CliOutputLine &Node::CliOutputLine::operator=(CliOutputLine &&aOther)
{
mLine.TakeFrom(aOther.mLine.Move());
return *this;
}
void Node::InputCli(const char *aFormat, ...)
{
static constexpr uint16_t kMaxCommandSize = 256;
va_list args;
char command[kMaxCommandSize];
StringWriter writer(command, kMaxCommandSize);
va_start(args, aFormat);
writer.AppendVarArgs(aFormat, args);
VerifyOrExit(!writer.IsTruncated());
ClearCliOutput();
mCliInterpreter.ProcessLine(command);
exit:
va_end(args);
}
int Node::HandleCliOutput(void *aContext, const char *aFormat, va_list aArguments)
{
return static_cast<Node *>(aContext)->HandleCliOutput(aFormat, aArguments);
}
int Node::HandleCliOutput(const char *aFormat, va_list aArguments)
{
uint16_t length;
// Generate output - determine number of chars written
length = mCliCurOutputLine.GetLength();
mCliCurOutputLine.AppendVarArgs(aFormat, aArguments);
VerifyOrQuit(!mCliCurOutputLine.IsTruncated());
length = mCliCurOutputLine.GetLength() - length;
// Search for `\n` and parse lines one by one
while (true)
{
char lineString[CliOutputLine::kMaxLineSize];
char *end;
CliOutputLine *lineEnrry;
SuccessOrQuit(StringCopy(lineString, mCliCurOutputLine.AsCString()));
end = AsNonConst(StringFind(lineString, '\n'));
VerifyOrExit(end != nullptr);
mCliCurOutputLine.Clear();
mCliCurOutputLine.Append("%s", end + 1);
*end = kNullChar;
if (end > &lineString[0])
{
end--;
if (*end == '\r')
{
*end = kNullChar;
}
}
// Push the full line into the `mCliOutputLines` array
lineEnrry = mCliOutputLines.PushBack();
VerifyOrQuit(lineEnrry != nullptr);
SuccessOrQuit(lineEnrry->mLine.Set(lineString));
}
exit:
return static_cast<int>(length);
}
bool Node::IsCliOutputSuccess(void)
{
bool isSuccess = false;
VerifyOrExit(mCliOutputLines.GetLength() > 0);
VerifyOrExit(mCliOutputLines.Back()->IsDone());
isSuccess = true;
exit:
return isSuccess;
}
//----------------------------------------------------------------------------------------------------------------------
void AllowLinkBetween(Node &aFirstNode, Node &aSecondNode)