Skip to content

[Tests] Add thunder_test_support static library for plugin integration testing#2084

Draft
smanes0213 wants to merge 8 commits intomasterfrom
development/Thunder_Test_Lib
Draft

[Tests] Add thunder_test_support static library for plugin integration testing#2084
smanes0213 wants to merge 8 commits intomasterfrom
development/Thunder_Test_Lib

Conversation

@smanes0213
Copy link
Copy Markdown
Contributor

Adds a static library (libthunder_test_support.a) that embeds the Thunder PluginHost::Server into a linkable archive. Test binaries link against this library to boot a real Thunder runtime without launching the standalone daemon, enabling integration testing of Thunder plugins using GTest/GMock.

Copilot AI review requested due to automatic review settings March 17, 2026 11:04
@smanes0213 smanes0213 marked this pull request as draft March 17, 2026 11:04
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 17, 2026

PR Preview Action v1.1.1-25-g59e77e4
🛫 Deployed preview to https://rdkcentral.github.io/Thunder/pr-preview/pr-2084/
on branch gh-pages at 2026-03-25 05:35 UTC

@rdkcmf-jenkins
Copy link
Copy Markdown
Contributor

b'## Blackduck scan failure details

Summary: 0 violations, 0 files pending approval, 4 files pending identification.

  • Protex Server Path: /home/blackduck/github/Thunder/2084/rdkcentral/Thunder

  • Commit: 47f1530

Report detail: gist'

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new thunder_test_support static library intended to enable in-process integration testing of Thunder plugins by embedding PluginHost::Server into test binaries (optionally built via ENABLE_TEST_RUNTIME).

Changes:

  • Introduces Thunder::TestCore::ThunderTestRuntime API to bootstrap an embedded Thunder server, invoke JSON-RPC in-process, and query COM-RPC interfaces.
  • Adds a new Tests/test_support/ CMake target (thunder_test_support) that statically compiles key Thunder server sources (excluding PluginHost.cpp / main()).
  • Adds end-user documentation describing architecture, build flags, and usage patterns for integration tests.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
Tests/test_support/ThunderTestRuntime.h Public API for starting/stopping an embedded server and calling JSON-RPC / COM-RPC from tests
Tests/test_support/ThunderTestRuntime.cpp Implements temp-dir lifecycle, config generation/parsing, server bootstrap, and invocation helpers
Tests/test_support/Module.cpp Declares module name for tracing/logging for the static library
Tests/test_support/CMakeLists.txt Builds/installs the new thunder_test_support static library and links required Thunder components
Tests/CMakeLists.txt Adds ENABLE_TEST_RUNTIME option and conditionally includes test_support
docs/ThunderTestSupport/ThunderTestSupport.md Adds detailed documentation for the test support library

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

void ThunderTestRuntime::CleanupDirectories() const
{
if (!_tempDir.empty()) {
Core::Directory(_tempDir.c_str()).Destroy();
Comment on lines +66 to +90
std::ostringstream json;
json << "{"
<< "\"port\":0,"
<< "\"binding\":\"127.0.0.1\","
<< "\"idletime\":180,"
<< "\"persistentpath\":\"" << _tempDir << "persistent/\","
<< "\"volatilepath\":\"" << _tempDir << "volatile/\","
<< "\"datapath\":\"" << _tempDir << "data/\","
<< "\"systempath\":\"" << systemPath << "\","
<< "\"proxystubpath\":\"" << proxyStubPath << "\","
<< "\"communicator\":\"" << _tempDir << "communicator\","
<< "\"plugins\":[";

for (size_t i = 0; i < plugins.size(); ++i) {
const auto& p = plugins[i];
if (i > 0) json << ",";
json << "{"
<< "\"callsign\":\"" << p.callsign << "\","
<< "\"locator\":\"" << p.locator << "\","
<< "\"classname\":\"" << p.classname << "\","
<< "\"startuporder\":" << p.startuporder << ","
<< "\"autostart\":" << (p.autostart ? "true" : "false");

if (!p.configuration.empty()) {
json << ",\"configuration\":" << p.configuration;
Comment on lines +47 to +50
Core::Directory(_tempDir.c_str()).Create();
Core::Directory((_tempDir + "persistent/").c_str()).Create();
Core::Directory((_tempDir + "volatile/").c_str()).Create();
Core::Directory((_tempDir + "data/").c_str()).Create();
Comment on lines +49 to +52
#ifndef MODULE_NAME
#define MODULE_NAME Application
#endif

//
// TEST_F(MyTest, JsonRpc) {
// string resp;
// _runtime.InvokeJSONRPC("Callsign", "Method", params, resp);
Comment on lines +34 to +42
│ │ ├── PluginServer │ │ │ │ │ ├── Controller │ │
│ │ ├── SystemInfo │ │ │ │ │ ├── PluginServer │ │
│ │ └── HTTP/WS Listener │ │ │ │ │ ├── SystemInfo │ │
│ │ ↓ │ │ │ │ │ └── (no HTTP listener) │ │
│ │ Plugin .so (dynamic load) │ │ │ │ └── Plugin .so (dynamic load) │ │
│ └───────────────────────────────┘ │ │ └─────────────────────────────────┘ │
│ │ │ │
│ Communication: HTTP/WS/COMRPC │ │ Communication: Direct in-process calls │
└─────────────────────────────────────┘ └─────────────────────────────────────────┘
@mhughesacn
Copy link
Copy Markdown

Hi @smanes0213 : This is draft so not looking closely, but if you append:

Copyright 2024 RDK Management
Licensed under the Apache License, Version 2.0

to the end of NOTICE in top level, I will clear off blackduck. Thank you.

@smanes0213
Copy link
Copy Markdown
Contributor Author

Hi @smanes0213 : This is draft so not looking closely, but if you append:

Copyright 2024 RDK Management
Licensed under the Apache License, Version 2.0

to the end of NOTICE in top level, I will clear off blackduck. Thank you.

Hi @mhughesacn: The changes are not finalised yet, I have removed the license header for now. Will add the header once everything is confirmed.

Copy link
Copy Markdown
Contributor

@bramoosterhuis bramoosterhuis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we want a minimal main.cpp example that boots the runtime and exercises a basic JSON-RPC call against the built-in Controller — no external plugin .so needed. This would serve as a smoke test to verify the library links and initialises correctly end-to-end.


// Invoke a JSON-RPC method on a loaded plugin.
// Method format: "Callsign.Version.method" (e.g. "Counter.1.increment")
uint32_t InvokeJSONRPC(const string& callsign, const string& method,
Copy link
Copy Markdown
Contributor

@bramoosterhuis bramoosterhuis Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there a specific reason for having both callsign and method as separate parameters here?

As it stands, the callsign is already embedded in the fully-qualified method string ("Counter.1.increment"), so the caller ends up saying the same thing twice — and there's nothing stopping them from passing mismatched values, which would produce a confusing failure.

Would it make sense to drop the callsign parameter and derive it from method in the implementation instead?

see Core::JSONRPC::Message , const string callsign = Core::JSONRPC::Message::Callsign(method);

string CommunicatorPath() const;

// Stop the server, release config, and clean up temp directories.
void Shutdown();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there a reason for pairing Initialize() with Shutdown() rather than following one of Thunder's own naming conventions?

Thunder is consistent elsewhere — IPlugin uses Initialize()/Deinitialize(), and PluginHost::Server uses Open()/Close(). Using Shutdown() introduces a third scheme that fits neither, which feels slightly off for a library that lives inside the Thunder repo and targets Thunder plugin developers who are already familiar with those conventions.

Would Initialize()/Deinitialize() or Open()/Close() be a better fit here?


#include <core/core.h>

MODULE_NAME_DECLARATION(BUILD_REFERENCE)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thunder has a macro for static archives — MODULE_NAME_ARCHIVE_DECLARATION. Using it in Module.cpp instead of MODULE_NAME_DECLARATION(BUILD_REFERENCE) avoids conflicting definitions of ModuleBuildRef(), GetModuleServices() and SetModuleServices() with the consumer's own MODULE_NAME_DECLARATION. It also removes the need for the #ifndef guard here.

#define MODULE_NAME ThunderTestRuntime
#include <core/core.h>
MODULE_NAME_ARCHIVE_DECLARATION

#define MODULE_NAME Application
#endif

#include <plugins/plugins.h>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: <plugins/plugins.h> can be replaced with <core/core.h> and <plugins/IShell.h> — the header only needs IShell and Core this avoids pulling in the entire plugins umbrella header into every consumer TU.

  original -Wno-psabi only setting
set CXX_STANDARD on thunder_test_support target so it respects the
  ENABLE_CXX17 flag like all other Thunder targets
Pass -DENABLE_CXX17=OFF in the smoke test CI workflow to avoid the
  SocketServer.h IteratorType move constructor bug
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants