2026-06-13 18:50:31 -04:00
|
|
|
#include <boostAsioLinkageFix.h>
|
|
|
|
|
|
|
|
|
|
#include <catalogHelpers.h>
|
|
|
|
|
#include <lcameraDev.h>
|
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
#include <support/bakedDeviceCatalog.h>
|
|
|
|
|
#include <support/probeComponentThread.h>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <functional>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
namespace lcamera_dev {
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
constexpr const char *hilEnvVar = "LCAMERADEV_HIL";
|
|
|
|
|
constexpr const char *machineEnvVar = "LCAMERADEV_MACHINE";
|
|
|
|
|
constexpr const char *defaultMachineTag = "dell-laptop";
|
|
|
|
|
|
|
|
|
|
bool hilTestsEnabled()
|
|
|
|
|
{
|
|
|
|
|
const char *value = std::getenv(hilEnvVar);
|
|
|
|
|
return value != nullptr && std::string(value) == "1";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string machineTagFromEnvironment()
|
|
|
|
|
{
|
|
|
|
|
const char *value = std::getenv(machineEnvVar);
|
|
|
|
|
if (value != nullptr && std::string(value).size() > 0) {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return defaultMachineTag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sscl::co::NonViralNonPostingInvoker enumerateCamerasCInd(
|
|
|
|
|
std::exception_ptr& exceptionStorage,
|
|
|
|
|
std::function<void()> callerLambda,
|
|
|
|
|
std::vector<lcamera_dev::LcameraDevCameraInfo>& enumeratedCameras)
|
|
|
|
|
{
|
|
|
|
|
(void)exceptionStorage;
|
|
|
|
|
(void)callerLambda;
|
|
|
|
|
|
|
|
|
|
enumeratedCameras = co_await lcameraDev_enumerateCamerasCReq();
|
|
|
|
|
co_return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sscl::co::NonViralNonPostingInvoker getOrCreateCInd(
|
|
|
|
|
std::exception_ptr& exceptionStorage,
|
|
|
|
|
std::function<void()> callerLambda,
|
|
|
|
|
const char *deviceSelector,
|
|
|
|
|
lcamera_dev::LcameraDevGetOrCreateResult& createResult)
|
|
|
|
|
{
|
|
|
|
|
(void)exceptionStorage;
|
|
|
|
|
(void)callerLambda;
|
|
|
|
|
|
|
|
|
|
createResult = co_await lcameraDev_getOrCreateDeviceCReq(deviceSelector);
|
|
|
|
|
co_return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sscl::co::NonViralNonPostingInvoker releaseCInd(
|
|
|
|
|
std::exception_ptr& exceptionStorage,
|
|
|
|
|
std::function<void()> callerLambda,
|
|
|
|
|
const std::shared_ptr<lcamera_dev::CameraSession>& deviceSession)
|
|
|
|
|
{
|
|
|
|
|
(void)exceptionStorage;
|
|
|
|
|
(void)callerLambda;
|
|
|
|
|
|
|
|
|
|
co_await lcameraDev_releaseDeviceCReq(deviceSession);
|
|
|
|
|
co_return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-14 11:02:11 -04:00
|
|
|
sscl::co::NonViralNonPostingInvoker resolveSelectorCInd(
|
|
|
|
|
std::exception_ptr &, std::function<void()>,
|
|
|
|
|
const char *deviceSelector,
|
|
|
|
|
lcamera_dev::CameraIdentityRecord& resolvedIdentity)
|
|
|
|
|
{
|
|
|
|
|
resolvedIdentity =
|
|
|
|
|
co_await lcameraDev_resolveDeviceSelectorCReq(deviceSelector);
|
|
|
|
|
co_return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-13 18:50:31 -04:00
|
|
|
void runLcameraDevMainAndNurseryTask(
|
|
|
|
|
const std::function<void(
|
|
|
|
|
const std::shared_ptr<sscl::ComponentThread>&)>& work)
|
|
|
|
|
{
|
|
|
|
|
sscl::tests::ProbeComponentThreadHarness harness("lcameraDev-hil");
|
|
|
|
|
harness.runSync(
|
|
|
|
|
[&work](const std::shared_ptr<sscl::ComponentThread>& componentThread)
|
|
|
|
|
{
|
|
|
|
|
lcameraDev_main(componentThread);
|
|
|
|
|
work(componentThread);
|
|
|
|
|
lcameraDev_exit();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class LcameraDevHilTest : public ::testing::Test
|
|
|
|
|
{
|
|
|
|
|
protected:
|
|
|
|
|
void SetUp() override
|
|
|
|
|
{
|
|
|
|
|
if (!hilTestsEnabled()) {
|
|
|
|
|
GTEST_SKIP() << "Set " << hilEnvVar << "=1 to run hardware tests";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
machineTag = machineTagFromEnvironment();
|
|
|
|
|
requiredProfiles =
|
|
|
|
|
sscl::tests::requiredProfilesForMachine(machineTag.c_str());
|
|
|
|
|
|
|
|
|
|
if (requiredProfiles.empty()) {
|
|
|
|
|
GTEST_SKIP() << "No baked profiles for machine tag "
|
|
|
|
|
<< machineTag;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string machineTag;
|
|
|
|
|
std::vector<const test_fixtures::BakedCameraProfile *> requiredProfiles;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TEST_F(LcameraDevHilTest, EnumerateMatchesBakedCatalog)
|
|
|
|
|
{
|
|
|
|
|
std::vector<lcamera_dev::LcameraDevCameraInfo> enumeratedCameras;
|
|
|
|
|
|
|
|
|
|
runLcameraDevMainAndNurseryTask(
|
|
|
|
|
[&enumeratedCameras](
|
|
|
|
|
const std::shared_ptr<sscl::ComponentThread>& componentThread)
|
|
|
|
|
{
|
|
|
|
|
sscl::tests::runNonViralNurseryOnComponentThread(
|
|
|
|
|
componentThread,
|
|
|
|
|
[&enumeratedCameras](
|
|
|
|
|
sscl::co::NonViralTaskNursery::Slot::Lease& lease)
|
|
|
|
|
{
|
|
|
|
|
return enumerateCamerasCInd(
|
|
|
|
|
lease.getExceptionStorage(),
|
|
|
|
|
lease.getCallerLambda(),
|
|
|
|
|
enumeratedCameras);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
EXPECT_GE(enumeratedCameras.size(), requiredProfiles.size());
|
|
|
|
|
|
|
|
|
|
for (const test_fixtures::BakedCameraProfile *profile : requiredProfiles)
|
|
|
|
|
{
|
|
|
|
|
bool found = false;
|
|
|
|
|
for (const lcamera_dev::LcameraDevCameraInfo& camera : enumeratedCameras)
|
|
|
|
|
{
|
|
|
|
|
if (camera.id == profile->libcameraId) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(found)
|
|
|
|
|
<< "Missing baked profile camera id=" << profile->libcameraId;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(LcameraDevHilTest, GetOrCreateByBakedSelector)
|
|
|
|
|
{
|
|
|
|
|
runLcameraDevMainAndNurseryTask(
|
|
|
|
|
[this](const std::shared_ptr<sscl::ComponentThread>& componentThread)
|
|
|
|
|
{
|
|
|
|
|
for (const test_fixtures::BakedCameraProfile *profile :
|
|
|
|
|
requiredProfiles)
|
|
|
|
|
{
|
|
|
|
|
lcamera_dev::LcameraDevGetOrCreateResult createResult;
|
|
|
|
|
|
|
|
|
|
sscl::tests::runNonViralNurseryOnComponentThread(
|
|
|
|
|
componentThread,
|
|
|
|
|
[profile, &createResult](
|
|
|
|
|
sscl::co::NonViralTaskNursery::Slot::Lease& lease)
|
|
|
|
|
{
|
|
|
|
|
return getOrCreateCInd(
|
|
|
|
|
lease.getExceptionStorage(),
|
|
|
|
|
lease.getCallerLambda(),
|
|
|
|
|
profile->exampleSelector,
|
|
|
|
|
createResult);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
EXPECT_TRUE(createResult.deviceSession != nullptr)
|
|
|
|
|
<< profile->profileTag;
|
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
createResult.resolvedIdentity.id,
|
|
|
|
|
profile->libcameraId)
|
|
|
|
|
<< profile->profileTag;
|
|
|
|
|
|
|
|
|
|
sscl::tests::runNonViralNurseryOnComponentThread(
|
|
|
|
|
componentThread,
|
|
|
|
|
[&createResult](
|
|
|
|
|
sscl::co::NonViralTaskNursery::Slot::Lease& lease)
|
|
|
|
|
{
|
|
|
|
|
return releaseCInd(
|
|
|
|
|
lease.getExceptionStorage(),
|
|
|
|
|
lease.getCallerLambda(),
|
|
|
|
|
createResult.deviceSession);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-14 11:02:11 -04:00
|
|
|
TEST_F(LcameraDevHilTest, ResolveDeviceSelectorMatchesGetOrCreateIdentity)
|
|
|
|
|
{
|
|
|
|
|
runLcameraDevMainAndNurseryTask(
|
|
|
|
|
[this](const std::shared_ptr<sscl::ComponentThread>& componentThread)
|
|
|
|
|
{
|
|
|
|
|
for (const test_fixtures::BakedCameraProfile *profile :
|
|
|
|
|
requiredProfiles)
|
|
|
|
|
{
|
|
|
|
|
lcamera_dev::CameraIdentityRecord resolvedIdentity;
|
|
|
|
|
lcamera_dev::LcameraDevGetOrCreateResult createResult;
|
|
|
|
|
|
|
|
|
|
sscl::tests::runNonViralNurseryOnComponentThread(
|
|
|
|
|
componentThread,
|
|
|
|
|
[profile, &resolvedIdentity](
|
|
|
|
|
sscl::co::NonViralTaskNursery::Slot::Lease& lease)
|
|
|
|
|
{
|
|
|
|
|
return resolveSelectorCInd(
|
|
|
|
|
lease.getExceptionStorage(),
|
|
|
|
|
lease.getCallerLambda(),
|
|
|
|
|
profile->exampleSelector,
|
|
|
|
|
resolvedIdentity);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(resolvedIdentity.id, profile->libcameraId)
|
|
|
|
|
<< profile->profileTag;
|
|
|
|
|
|
|
|
|
|
sscl::tests::runNonViralNurseryOnComponentThread(
|
|
|
|
|
componentThread,
|
|
|
|
|
[profile, &createResult](
|
|
|
|
|
sscl::co::NonViralTaskNursery::Slot::Lease& lease)
|
|
|
|
|
{
|
|
|
|
|
return getOrCreateCInd(
|
|
|
|
|
lease.getExceptionStorage(),
|
|
|
|
|
lease.getCallerLambda(),
|
|
|
|
|
profile->exampleSelector,
|
|
|
|
|
createResult);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
createResult.resolvedIdentity.id,
|
|
|
|
|
resolvedIdentity.id)
|
|
|
|
|
<< profile->profileTag;
|
|
|
|
|
|
|
|
|
|
sscl::tests::runNonViralNurseryOnComponentThread(
|
|
|
|
|
componentThread,
|
|
|
|
|
[&createResult](
|
|
|
|
|
sscl::co::NonViralTaskNursery::Slot::Lease& lease)
|
|
|
|
|
{
|
|
|
|
|
return releaseCInd(
|
|
|
|
|
lease.getExceptionStorage(),
|
|
|
|
|
lease.getCallerLambda(),
|
|
|
|
|
createResult.deviceSession);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-13 18:50:31 -04:00
|
|
|
} // namespace
|
|
|
|
|
} // namespace lcamera_dev
|