mirror of
https://github.com/latentPrion/libspinscale.git
synced 2026-06-23 19:48:32 +00:00
New test support harness primitives for testing stimbuffapis
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
add_library(spinscale_test_support STATIC
|
add_library(spinscale_test_support STATIC
|
||||||
support/threadHarness.cpp
|
support/threadHarness.cpp
|
||||||
|
support/probeComponentThread.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(spinscale_test_support PUBLIC
|
target_include_directories(spinscale_test_support PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_SOURCE_DIR}/tests/fixtures
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(spinscale_test_support PUBLIC
|
target_link_libraries(spinscale_test_support PUBLIC
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#ifndef SPINSCALE_TEST_SUPPORT_BAKED_DEVICE_CATALOG_H
|
||||||
|
#define SPINSCALE_TEST_SUPPORT_BAKED_DEVICE_CATALOG_H
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <bakedCameraProfiles.h>
|
||||||
|
|
||||||
|
namespace sscl::tests {
|
||||||
|
|
||||||
|
inline std::vector<const test_fixtures::BakedCameraProfile *>
|
||||||
|
profilesForMachine(const char *machineTag)
|
||||||
|
{
|
||||||
|
std::vector<const test_fixtures::BakedCameraProfile *> matches;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < test_fixtures::bakedCameraProfileCount; ++i)
|
||||||
|
{
|
||||||
|
const test_fixtures::BakedCameraProfile& profile =
|
||||||
|
test_fixtures::bakedCameraProfiles[i];
|
||||||
|
|
||||||
|
if (std::string(profile.machineTag) == machineTag) {
|
||||||
|
matches.push_back(&profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::optional<const test_fixtures::BakedCameraProfile *>
|
||||||
|
findProfileByTag(const char *machineTag, const char *profileTag)
|
||||||
|
{
|
||||||
|
for (std::size_t i = 0; i < test_fixtures::bakedCameraProfileCount; ++i)
|
||||||
|
{
|
||||||
|
const test_fixtures::BakedCameraProfile& profile =
|
||||||
|
test_fixtures::bakedCameraProfiles[i];
|
||||||
|
|
||||||
|
if (std::string(profile.machineTag) == machineTag
|
||||||
|
&& std::string(profile.profileTag) == profileTag)
|
||||||
|
{
|
||||||
|
return &profile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::vector<const test_fixtures::BakedCameraProfile *>
|
||||||
|
requiredProfilesForMachine(const char *machineTag)
|
||||||
|
{
|
||||||
|
std::vector<const test_fixtures::BakedCameraProfile *> matches;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < test_fixtures::bakedCameraProfileCount; ++i)
|
||||||
|
{
|
||||||
|
const test_fixtures::BakedCameraProfile& profile =
|
||||||
|
test_fixtures::bakedCameraProfiles[i];
|
||||||
|
|
||||||
|
if (std::string(profile.machineTag) == machineTag
|
||||||
|
&& profile.requiredOnMachine)
|
||||||
|
{
|
||||||
|
matches.push_back(&profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sscl::tests
|
||||||
|
|
||||||
|
#endif // SPINSCALE_TEST_SUPPORT_BAKED_DEVICE_CATALOG_H
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef SPINSCALE_TEST_SUPPORT_EXCEPTION_ASSERTIONS_H
|
||||||
|
#define SPINSCALE_TEST_SUPPORT_EXCEPTION_ASSERTIONS_H
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace sscl::tests {
|
||||||
|
|
||||||
|
inline void requireExceptionMessageContains(
|
||||||
|
const std::exception &exception,
|
||||||
|
const std::string &expectedSubstring)
|
||||||
|
{
|
||||||
|
const std::string message = exception.what();
|
||||||
|
if (message.find(expectedSubstring) == std::string::npos) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Expected exception message to contain \""
|
||||||
|
+ expectedSubstring
|
||||||
|
+ "\", got \""
|
||||||
|
+ message
|
||||||
|
+ "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void expectExceptionMessageContains(
|
||||||
|
const std::exception &exception,
|
||||||
|
const std::string &expectedSubstring)
|
||||||
|
{
|
||||||
|
EXPECT_NO_THROW(
|
||||||
|
requireExceptionMessageContains(exception, expectedSubstring));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void requireExceptionPtrMessageContains(
|
||||||
|
const std::exception_ptr &exceptionPtr,
|
||||||
|
const std::string &expectedSubstring)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
std::rethrow_exception(exceptionPtr);
|
||||||
|
}
|
||||||
|
catch (const std::exception &exception) {
|
||||||
|
requireExceptionMessageContains(exception, expectedSubstring);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
throw std::runtime_error("Expected std::exception in exception_ptr");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void expectExceptionPtrMessageContains(
|
||||||
|
const std::exception_ptr &exceptionPtr,
|
||||||
|
const std::string &expectedSubstring)
|
||||||
|
{
|
||||||
|
EXPECT_NO_THROW(
|
||||||
|
requireExceptionPtrMessageContains(
|
||||||
|
exceptionPtr,
|
||||||
|
expectedSubstring));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sscl::tests
|
||||||
|
|
||||||
|
#endif // SPINSCALE_TEST_SUPPORT_EXCEPTION_ASSERTIONS_H
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
#include <support/probeComponentThread.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <spinscale/component.h>
|
||||||
|
|
||||||
|
namespace sscl::tests {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr sscl::ThreadId PROBE_PUPPETEER_THREAD_ID = 2;
|
||||||
|
|
||||||
|
class ProbeDummyPuppeteerComponent
|
||||||
|
: public sscl::pptr::PuppeteerComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ProbeDummyPuppeteerComponent(
|
||||||
|
const std::shared_ptr<sscl::PuppeteerThread>& componentThreadIn)
|
||||||
|
: sscl::pptr::PuppeteerComponent(componentThreadIn)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void handleLoopExceptionHook() override
|
||||||
|
{
|
||||||
|
std::cerr << "ProbeComponentThreadHarness: puppeteer loop exception\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void probePuppeteerMain(
|
||||||
|
const sscl::PuppeteerThread::EntryFnArguments& args,
|
||||||
|
const std::function<void(
|
||||||
|
const std::shared_ptr<sscl::ComponentThread>&)>& work,
|
||||||
|
std::promise<std::exception_ptr>& donePromise)
|
||||||
|
{
|
||||||
|
sscl::PuppeteerThread& thr = args.usableBeforeJolt;
|
||||||
|
thr.initializeTls();
|
||||||
|
sscl::ComponentThread::setPuppeteerThreadId(PROBE_PUPPETEER_THREAD_ID);
|
||||||
|
|
||||||
|
std::shared_ptr<sscl::PuppeteerThread> thrPtr =
|
||||||
|
std::static_pointer_cast<sscl::PuppeteerThread>(thr.shared_from_this());
|
||||||
|
sscl::ComponentThread::setPuppeteerThread(thrPtr);
|
||||||
|
|
||||||
|
try {
|
||||||
|
work(thrPtr);
|
||||||
|
donePromise.set_value(nullptr);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
donePromise.set_value(std::current_exception());
|
||||||
|
}
|
||||||
|
|
||||||
|
thr.getIoContext().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
ProbeComponentThreadHarness::ProbeComponentThreadHarness(
|
||||||
|
const char *threadName)
|
||||||
|
: threadName(threadName),
|
||||||
|
dummyComponent(std::make_shared<ProbeDummyPuppeteerComponent>(
|
||||||
|
std::shared_ptr<sscl::PuppeteerThread>()))
|
||||||
|
{}
|
||||||
|
|
||||||
|
ProbeComponentThreadHarness::~ProbeComponentThreadHarness() = default;
|
||||||
|
|
||||||
|
std::shared_ptr<sscl::ComponentThread>
|
||||||
|
ProbeComponentThreadHarness::componentThread() const
|
||||||
|
{
|
||||||
|
return lastComponentThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProbeComponentThreadHarness::runSync(
|
||||||
|
const std::function<void(
|
||||||
|
const std::shared_ptr<sscl::ComponentThread>&)>& work)
|
||||||
|
{
|
||||||
|
std::promise<std::exception_ptr> donePromise;
|
||||||
|
std::future<std::exception_ptr> doneFuture = donePromise.get_future();
|
||||||
|
|
||||||
|
std::shared_ptr<sscl::PuppeteerThread> runThread =
|
||||||
|
std::make_shared<sscl::PuppeteerThread>(
|
||||||
|
PROBE_PUPPETEER_THREAD_ID,
|
||||||
|
threadName,
|
||||||
|
[&work, &donePromise](
|
||||||
|
const sscl::PuppeteerThread::EntryFnArguments& args)
|
||||||
|
{
|
||||||
|
probePuppeteerMain(args, work, donePromise);
|
||||||
|
},
|
||||||
|
*dummyComponent,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
dummyComponent->thread = runThread;
|
||||||
|
lastComponentThread = runThread;
|
||||||
|
runThread->thread.join();
|
||||||
|
|
||||||
|
std::exception_ptr probeException = doneFuture.get();
|
||||||
|
if (probeException) {
|
||||||
|
std::rethrow_exception(probeException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void runNonViralNurseryOnComponentThread(
|
||||||
|
const std::shared_ptr<sscl::ComponentThread>& componentThread,
|
||||||
|
std::function<sscl::co::NonViralNonPostingInvoker(
|
||||||
|
sscl::co::NonViralTaskNursery::Slot::Lease&)> invokerFactory,
|
||||||
|
std::chrono::milliseconds timeout)
|
||||||
|
{
|
||||||
|
(void)timeout;
|
||||||
|
|
||||||
|
sscl::co::NonViralTaskNursery nursery;
|
||||||
|
nursery.openAdmission();
|
||||||
|
nursery.launch(
|
||||||
|
[&invokerFactory](sscl::co::NonViralTaskNursery::Slot::Lease& lease)
|
||||||
|
{
|
||||||
|
return invokerFactory(lease);
|
||||||
|
});
|
||||||
|
nursery.closeAdmission();
|
||||||
|
nursery.syncAwaitAllSettlements(componentThread->getIoContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sscl::tests
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#ifndef SPINSCALE_TEST_SUPPORT_PROBE_COMPONENT_THREAD_H
|
||||||
|
#define SPINSCALE_TEST_SUPPORT_PROBE_COMPONENT_THREAD_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <exception>
|
||||||
|
#include <functional>
|
||||||
|
#include <future>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <spinscale/componentThread.h>
|
||||||
|
#include <spinscale/co/invokers.h>
|
||||||
|
#include <spinscale/co/nonViralTaskNursery.h>
|
||||||
|
|
||||||
|
namespace sscl::tests {
|
||||||
|
|
||||||
|
constexpr std::chrono::milliseconds defaultProbeTaskTimeout{10000};
|
||||||
|
|
||||||
|
void runNonViralNurseryOnComponentThread(
|
||||||
|
const std::shared_ptr<sscl::ComponentThread>& componentThread,
|
||||||
|
std::function<sscl::co::NonViralNonPostingInvoker(
|
||||||
|
sscl::co::NonViralTaskNursery::Slot::Lease&)> invokerFactory,
|
||||||
|
std::chrono::milliseconds timeout = defaultProbeTaskTimeout);
|
||||||
|
|
||||||
|
class ProbeComponentThreadHarness
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ProbeComponentThreadHarness(
|
||||||
|
const char *threadName = "spinscale-probe");
|
||||||
|
~ProbeComponentThreadHarness();
|
||||||
|
|
||||||
|
ProbeComponentThreadHarness(const ProbeComponentThreadHarness &) = delete;
|
||||||
|
ProbeComponentThreadHarness &operator=(
|
||||||
|
const ProbeComponentThreadHarness &) = delete;
|
||||||
|
|
||||||
|
std::shared_ptr<sscl::ComponentThread> componentThread() const;
|
||||||
|
|
||||||
|
void runSync(
|
||||||
|
const std::function<void(
|
||||||
|
const std::shared_ptr<sscl::ComponentThread>&)>& work);
|
||||||
|
|
||||||
|
template <typename InvokerFactory>
|
||||||
|
void runNonViralNurseryTask(
|
||||||
|
InvokerFactory &&invokerFactory,
|
||||||
|
std::chrono::milliseconds timeout = defaultProbeTaskTimeout)
|
||||||
|
{
|
||||||
|
runSync(
|
||||||
|
[this, &invokerFactory, timeout](
|
||||||
|
const std::shared_ptr<sscl::ComponentThread>& componentThread)
|
||||||
|
{
|
||||||
|
sscl::tests::runNonViralNurseryOnComponentThread(
|
||||||
|
componentThread,
|
||||||
|
std::forward<InvokerFactory>(invokerFactory),
|
||||||
|
timeout);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string threadName;
|
||||||
|
std::shared_ptr<sscl::pptr::PuppeteerComponent> dummyComponent;
|
||||||
|
std::shared_ptr<sscl::ComponentThread> lastComponentThread;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sscl::tests
|
||||||
|
|
||||||
|
#endif // SPINSCALE_TEST_SUPPORT_PROBE_COMPONENT_THREAD_H
|
||||||
Reference in New Issue
Block a user