Resolve device selector on detach and add YuvStimProducer state tests.
Detach finds the shared producer via lcameraDev_resolveDeviceSelectorCReq then removes buffers by attach identity; unit tests cover quale guards. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,244 @@
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <cameraIdentity.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <hilSmoCallbacksStub.h>
|
||||
#include <lcameraBuffInternal.h>
|
||||
#include <support/exceptionAssertions.h>
|
||||
#include <yuvChannelStimulusBuffer.h>
|
||||
#include <yuvStimProducer.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace smo {
|
||||
namespace stim_buff {
|
||||
namespace lcamera_buff {
|
||||
namespace {
|
||||
|
||||
constexpr const char *usbExternalSelector =
|
||||
"model-substr:USB;location:external";
|
||||
constexpr const char *usbAliasSelector =
|
||||
"model-substr:USB Video Device;location:external";
|
||||
|
||||
std::shared_ptr<device::DeviceAttachmentSpec> makeLcameraAttachSpec(
|
||||
const std::string& deviceSelector,
|
||||
const std::string& qualeIfaceApi,
|
||||
const std::string& deviceIdentifier = "cam0")
|
||||
{
|
||||
auto spec = std::make_shared<device::DeviceAttachmentSpec>();
|
||||
spec->deviceIdentifier = deviceIdentifier;
|
||||
spec->sensorType = 'e';
|
||||
spec->qualeIfaceApi = qualeIfaceApi;
|
||||
spec->stimBuffApi = "lcameraBuff";
|
||||
spec->provider = "lcameraDev";
|
||||
spec->deviceSelector = deviceSelector;
|
||||
spec->stimBuffApiParams = {
|
||||
{"v-res", "480p"},
|
||||
{"colour-space", "yuv"},
|
||||
{"opt-planar", ""},
|
||||
};
|
||||
return spec;
|
||||
}
|
||||
|
||||
LcameraBuffParsedParams makeDefaultParsedParams()
|
||||
{
|
||||
LcameraBuffParsedParams parsedParams;
|
||||
parsedParams.width = 640;
|
||||
parsedParams.height = 480;
|
||||
parsedParams.colourSpace = lcamera_dev::LcameraDevColourSpace::Yuv;
|
||||
parsedParams.fullPlanarIsOptional = true;
|
||||
return parsedParams;
|
||||
}
|
||||
|
||||
lcamera_dev::LcameraDevConfiguredCameraMode makeYuyv480ConfiguredMode()
|
||||
{
|
||||
lcamera_dev::LcameraDevConfiguredCameraMode configuredMode;
|
||||
configuredMode.width = 640;
|
||||
configuredMode.height = 480;
|
||||
configuredMode.colourSpace = lcamera_dev::LcameraDevColourSpace::Yuv;
|
||||
configuredMode.pixelFormatName = "YUYV";
|
||||
configuredMode.isFullyPlanar = false;
|
||||
configuredMode.planeCount = 1;
|
||||
return configuredMode;
|
||||
}
|
||||
|
||||
lcamera_dev::CameraIdentityRecord makeTestCameraIdentity()
|
||||
{
|
||||
lcamera_dev::CameraIdentityRecord identity;
|
||||
identity.id = "unit-test-camera-1";
|
||||
identity.model = "UnitTestCam";
|
||||
return identity;
|
||||
}
|
||||
|
||||
class YuvStimProducerQualeIfaceTest
|
||||
: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
lcameraBuffSmoHooksPtr = &lcamera_buff_tests::hilSmoCallbacksStub();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
lcameraBuffSmoHooksPtr = nullptr;
|
||||
}
|
||||
|
||||
boost::asio::io_context ioContext;
|
||||
const LcameraBuffParsedParams parsedParams = makeDefaultParsedParams();
|
||||
const lcamera_dev::LcameraDevConfiguredCameraMode configuredMode =
|
||||
makeYuyv480ConfiguredMode();
|
||||
const lcamera_dev::CameraIdentityRecord cameraIdentity =
|
||||
makeTestCameraIdentity();
|
||||
|
||||
YuvStimProducer makeProducer(
|
||||
const std::shared_ptr<device::DeviceAttachmentSpec>& producerSpec)
|
||||
{
|
||||
return YuvStimProducer(
|
||||
producerSpec,
|
||||
ioContext,
|
||||
nullptr,
|
||||
cameraIdentity,
|
||||
parsedParams,
|
||||
configuredMode);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(YuvStimProducerQualeIfaceTest, GetOrCreateSameSpecReturnsExistingBuffer)
|
||||
{
|
||||
auto producerSpec = makeLcameraAttachSpec(
|
||||
usbExternalSelector, "colour-yuv-y");
|
||||
YuvStimProducer producer = makeProducer(producerSpec);
|
||||
|
||||
const auto firstBuffer =
|
||||
producer.getOrCreateAttachedStimulusBuffer(producerSpec);
|
||||
ASSERT_NE(firstBuffer, nullptr);
|
||||
|
||||
const auto secondBuffer =
|
||||
producer.getOrCreateAttachedStimulusBuffer(producerSpec);
|
||||
|
||||
EXPECT_EQ(firstBuffer, secondBuffer);
|
||||
EXPECT_EQ(producer.attachedStimulusBuffers.size(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(YuvStimProducerQualeIfaceTest,
|
||||
RejectDuplicateQualeWhenAlternateSelectorResolvesToSameSession)
|
||||
{
|
||||
/* One YuvStimProducer == one resolved libcamera camera id / session.
|
||||
* A second DAP line may spell a different deviceSelector yet resolve to
|
||||
* that same session via attachToExistingProducer; it must not attach the
|
||||
* same qualeIface API twice.
|
||||
*/
|
||||
auto producerSpec = makeLcameraAttachSpec(
|
||||
usbExternalSelector, "colour-yuv-y");
|
||||
YuvStimProducer producer = makeProducer(producerSpec);
|
||||
|
||||
const auto firstSpec = makeLcameraAttachSpec(
|
||||
usbExternalSelector, "colour-yuv-y", "cam-y-line0");
|
||||
ASSERT_NE(producer.getOrCreateAttachedStimulusBuffer(firstSpec), nullptr);
|
||||
|
||||
const auto duplicateQualeAlternateSelectorSpec = makeLcameraAttachSpec(
|
||||
usbAliasSelector, "colour-yuv-y", "cam-y-line1");
|
||||
|
||||
try {
|
||||
producer.getOrCreateAttachedStimulusBuffer(
|
||||
duplicateQualeAlternateSelectorSpec);
|
||||
FAIL() << "Expected std::runtime_error";
|
||||
}
|
||||
catch (const std::runtime_error& exception)
|
||||
{
|
||||
sscl::tests::expectExceptionMessageContains(
|
||||
exception,
|
||||
"already attached for camera session");
|
||||
sscl::tests::expectExceptionMessageContains(
|
||||
exception,
|
||||
"colour-yuv-y");
|
||||
}
|
||||
|
||||
EXPECT_EQ(producer.attachedStimulusBuffers.size(), 1u);
|
||||
EXPECT_NE(
|
||||
firstSpec->deviceSelector,
|
||||
duplicateQualeAlternateSelectorSpec->deviceSelector);
|
||||
}
|
||||
|
||||
TEST_F(YuvStimProducerQualeIfaceTest,
|
||||
AllowDistinctQualeIfacesForAlternateSelectorsOnSameSession)
|
||||
{
|
||||
auto producerSpec = makeLcameraAttachSpec(
|
||||
usbExternalSelector, "colour-yuv-y");
|
||||
YuvStimProducer producer = makeProducer(producerSpec);
|
||||
|
||||
const auto ySpec = makeLcameraAttachSpec(
|
||||
usbExternalSelector, "colour-yuv-y", "cam-y");
|
||||
const auto uSpec = makeLcameraAttachSpec(
|
||||
usbAliasSelector, "colour-yuv-u", "cam-u");
|
||||
const auto vSpec = makeLcameraAttachSpec(
|
||||
usbExternalSelector, "colour-yuv-v", "cam-v");
|
||||
|
||||
ASSERT_NE(producer.getOrCreateAttachedStimulusBuffer(ySpec), nullptr);
|
||||
ASSERT_NE(producer.getOrCreateAttachedStimulusBuffer(uSpec), nullptr);
|
||||
ASSERT_NE(producer.getOrCreateAttachedStimulusBuffer(vSpec), nullptr);
|
||||
|
||||
EXPECT_EQ(producer.attachedStimulusBuffers.size(), 3u);
|
||||
EXPECT_TRUE(producer.hasBufferWithQualeIfaceApi("colour-yuv-y"));
|
||||
EXPECT_TRUE(producer.hasBufferWithQualeIfaceApi("colour-yuv-u"));
|
||||
EXPECT_TRUE(producer.hasBufferWithQualeIfaceApi("colour-yuv-v"));
|
||||
}
|
||||
|
||||
TEST_F(YuvStimProducerQualeIfaceTest,
|
||||
RejectDuplicateQualeAfterYViaSelectorAAndUViaSelectorB)
|
||||
{
|
||||
auto producerSpec = makeLcameraAttachSpec(
|
||||
usbExternalSelector, "colour-yuv-y");
|
||||
YuvStimProducer producer = makeProducer(producerSpec);
|
||||
|
||||
ASSERT_NE(producer.getOrCreateAttachedStimulusBuffer(
|
||||
makeLcameraAttachSpec(usbExternalSelector, "colour-yuv-y", "cam-y")),
|
||||
nullptr);
|
||||
ASSERT_NE(producer.getOrCreateAttachedStimulusBuffer(
|
||||
makeLcameraAttachSpec(usbAliasSelector, "colour-yuv-u", "cam-u")),
|
||||
nullptr);
|
||||
|
||||
const auto duplicateYViaAlternateSelector = makeLcameraAttachSpec(
|
||||
usbAliasSelector, "colour-yuv-y", "cam-y-second-dap-line");
|
||||
|
||||
EXPECT_THROW(
|
||||
producer.getOrCreateAttachedStimulusBuffer(
|
||||
duplicateYViaAlternateSelector),
|
||||
std::runtime_error);
|
||||
EXPECT_EQ(producer.attachedStimulusBuffers.size(), 2u);
|
||||
}
|
||||
|
||||
TEST_F(YuvStimProducerQualeIfaceTest,
|
||||
FindAttachedBufferByAttachIdentityWithAlternateSelector)
|
||||
{
|
||||
auto producerSpec = makeLcameraAttachSpec(
|
||||
usbExternalSelector, "colour-yuv-y");
|
||||
YuvStimProducer producer = makeProducer(producerSpec);
|
||||
|
||||
const auto uSpec = makeLcameraAttachSpec(
|
||||
usbExternalSelector, "colour-yuv-u", "cam-u");
|
||||
ASSERT_NE(producer.getOrCreateAttachedStimulusBuffer(uSpec), nullptr);
|
||||
|
||||
const auto foundBuffer =
|
||||
producer.getAttachedStimulusBufferByAttachIdentity(
|
||||
"cam-u", "colour-yuv-u");
|
||||
ASSERT_NE(foundBuffer, nullptr);
|
||||
EXPECT_EQ(
|
||||
foundBuffer->deviceAttachmentSpec->deviceSelector,
|
||||
usbExternalSelector);
|
||||
|
||||
EXPECT_EQ(
|
||||
producer.getAttachedStimulusBuffer(
|
||||
makeLcameraAttachSpec(
|
||||
usbAliasSelector, "colour-yuv-u", "cam-u")),
|
||||
nullptr);
|
||||
EXPECT_NE(
|
||||
producer.getAttachedStimulusBufferByAttachIdentity(
|
||||
"cam-u", "colour-yuv-u"),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace lcamera_buff
|
||||
} // namespace stim_buff
|
||||
} // namespace smo
|
||||
Reference in New Issue
Block a user