Tests: add tests for lcameraDev, fix qutex tests
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#include <spinscale/cps/qutex.h>
|
||||
#include <spinscale/cps/lockerAndInvokerBase.h>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
@@ -15,19 +16,48 @@ public:
|
||||
: sscl::cps::LockerAndInvokerBase(addr), awakened(false) {}
|
||||
|
||||
bool awakened;
|
||||
sscl::cps::Qutex* registeredQutex = nullptr;
|
||||
sscl::cps::LockerAndInvokerBase::List::iterator queueIterator;
|
||||
mutable sscl::cps::Qutex* registeredQutex = nullptr;
|
||||
mutable sscl::cps::LockerAndInvokerBase::List::iterator queueIterator;
|
||||
|
||||
sscl::cps::LockerAndInvokerBase::List::iterator getLockvokerIteratorForQutex(sscl::cps::Qutex& qutex) override {
|
||||
sscl::cps::LockerAndInvokerBase::List::iterator
|
||||
getLockvokerIteratorForQutex(sscl::cps::Qutex& qutex) const override
|
||||
{
|
||||
registeredQutex = &qutex;
|
||||
queueIterator = qutex.registerInQueue(std::shared_ptr<sscl::cps::LockerAndInvokerBase>(this));
|
||||
return queueIterator;
|
||||
|
||||
for (auto it = qutex.queue.begin(); it != qutex.queue.end(); ++it)
|
||||
{
|
||||
if ((**it) == *this)
|
||||
{
|
||||
queueIterator = it;
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
"MockLockerAndInvoker: not registered in qutex queue");
|
||||
}
|
||||
|
||||
void awaken(bool forceAwaken = false) override {
|
||||
void awaken(bool forceAwaken = false) override
|
||||
{
|
||||
(void)forceAwaken;
|
||||
awakened = true;
|
||||
}
|
||||
|
||||
size_t getLockSetSize() const override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
sscl::cps::Qutex& getLockAt(size_t index) const override
|
||||
{
|
||||
if (index != 0 || registeredQutex == nullptr)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"MockLockerAndInvoker: invalid lock index or no registered qutex");
|
||||
}
|
||||
|
||||
return *registeredQutex;
|
||||
}
|
||||
};
|
||||
|
||||
class QutexTest : public ::testing::Test {
|
||||
@@ -45,7 +75,7 @@ protected:
|
||||
// Clean up
|
||||
}
|
||||
|
||||
sscl::cps::Qutex qutex;
|
||||
sscl::cps::Qutex qutex{"test-qutex"};
|
||||
std::shared_ptr<MockLockerAndInvoker> mock1, mock2, mock3, mock4, mock5;
|
||||
|
||||
// Unique addresses for testing
|
||||
@@ -79,7 +109,7 @@ TEST_F(QutexTest, QueueRegistrationAndUnregistration) {
|
||||
// Test single lock acquisition when queue is empty
|
||||
TEST_F(QutexTest, SingleLockAcquisitionEmptyQueue) {
|
||||
// Register mock1
|
||||
auto it1 = qutex.registerInQueue(mock1);
|
||||
(void)qutex.registerInQueue(mock1);
|
||||
|
||||
// Try to acquire with nRequiredLocks = 1
|
||||
bool acquired = qutex.tryAcquire(*mock1, 1);
|
||||
@@ -90,9 +120,9 @@ TEST_F(QutexTest, SingleLockAcquisitionEmptyQueue) {
|
||||
// Test single lock acquisition when at front of queue
|
||||
TEST_F(QutexTest, SingleLockAcquisitionAtFront) {
|
||||
// Register multiple lockvokers
|
||||
auto it1 = qutex.registerInQueue(mock1);
|
||||
auto it2 = qutex.registerInQueue(mock2);
|
||||
auto it3 = qutex.registerInQueue(mock3);
|
||||
(void)qutex.registerInQueue(mock1);
|
||||
(void)qutex.registerInQueue(mock2);
|
||||
(void)qutex.registerInQueue(mock3);
|
||||
|
||||
// mock1 should be at front, mock3 at back
|
||||
EXPECT_EQ(qutex.queue.front().get(), mock1.get());
|
||||
@@ -112,8 +142,8 @@ TEST_F(QutexTest, SingleLockAcquisitionAtFront) {
|
||||
// Test single lock acquisition failure when not at front
|
||||
TEST_F(QutexTest, SingleLockAcquisitionNotAtFront) {
|
||||
// Register multiple lockvokers
|
||||
auto it1 = qutex.registerInQueue(mock1);
|
||||
auto it2 = qutex.registerInQueue(mock2);
|
||||
(void)qutex.registerInQueue(mock1);
|
||||
(void)qutex.registerInQueue(mock2);
|
||||
|
||||
// mock2 (not at front) should fail
|
||||
bool acquired = qutex.tryAcquire(*mock2, 1);
|
||||
@@ -124,10 +154,10 @@ TEST_F(QutexTest, SingleLockAcquisitionNotAtFront) {
|
||||
// Test multi-lock acquisition (nRequiredLocks > 1)
|
||||
TEST_F(QutexTest, MultiLockAcquisition) {
|
||||
// Register 4 lockvokers
|
||||
auto it1 = qutex.registerInQueue(mock1);
|
||||
auto it2 = qutex.registerInQueue(mock2);
|
||||
auto it3 = qutex.registerInQueue(mock3);
|
||||
auto it4 = qutex.registerInQueue(mock4);
|
||||
(void)qutex.registerInQueue(mock1);
|
||||
(void)qutex.registerInQueue(mock2);
|
||||
(void)qutex.registerInQueue(mock3);
|
||||
(void)qutex.registerInQueue(mock4);
|
||||
|
||||
// For nRequiredLocks = 2, need to be in top 50% (top 2 out of 4)
|
||||
// mock1 (position 1) should succeed
|
||||
@@ -159,16 +189,16 @@ TEST_F(QutexTest, MultiLockAcquisition) {
|
||||
// Test multi-lock acquisition with 3 required locks
|
||||
TEST_F(QutexTest, MultiLockAcquisitionThreeLocks) {
|
||||
// Register 6 lockvokers
|
||||
auto it1 = qutex.registerInQueue(mock1);
|
||||
auto it2 = qutex.registerInQueue(mock2);
|
||||
auto it3 = qutex.registerInQueue(mock3);
|
||||
auto it4 = qutex.registerInQueue(mock4);
|
||||
auto it5 = qutex.registerInQueue(mock5);
|
||||
(void)qutex.registerInQueue(mock1);
|
||||
(void)qutex.registerInQueue(mock2);
|
||||
(void)qutex.registerInQueue(mock3);
|
||||
(void)qutex.registerInQueue(mock4);
|
||||
(void)qutex.registerInQueue(mock5);
|
||||
|
||||
// Create one more mock
|
||||
int addr6 = 6;
|
||||
auto mock6 = std::make_shared<MockLockerAndInvoker>(&addr6);
|
||||
auto it6 = qutex.registerInQueue(mock6);
|
||||
(void)qutex.registerInQueue(mock6);
|
||||
|
||||
// For nRequiredLocks = 3, need to be in top 66% (top 4 out of 6)
|
||||
// Positions 1, 2, 3, 4 should succeed
|
||||
@@ -201,7 +231,7 @@ TEST_F(QutexTest, MultiLockAcquisitionThreeLocks) {
|
||||
// Test acquisition failure when already owned
|
||||
TEST_F(QutexTest, AcquisitionFailureWhenOwned) {
|
||||
// Register mock1
|
||||
auto it1 = qutex.registerInQueue(mock1);
|
||||
(void)qutex.registerInQueue(mock1);
|
||||
|
||||
// Manually set as owned
|
||||
qutex.isOwned = true;
|
||||
@@ -214,28 +244,28 @@ TEST_F(QutexTest, AcquisitionFailureWhenOwned) {
|
||||
|
||||
// Test backoff with single item (should not rotate)
|
||||
TEST_F(QutexTest, BackoffSingleItem) {
|
||||
// Register only one lockvoker
|
||||
auto it1 = qutex.registerInQueue(mock1);
|
||||
// Register only one lockvoker
|
||||
(void)qutex.registerInQueue(mock1);
|
||||
|
||||
// Set as owned first
|
||||
qutex.isOwned = true;
|
||||
// Set as owned first
|
||||
qutex.isOwned = true;
|
||||
|
||||
// Backoff should not rotate and should awaken the front item
|
||||
mock1->awakened = false;
|
||||
qutex.backoff(*mock1, 1);
|
||||
// nRequiredLocks > 1 avoids the "front item with nRequiredLocks==1" guard
|
||||
mock1->awakened = false;
|
||||
qutex.backoff(*mock1, 2);
|
||||
|
||||
EXPECT_FALSE(qutex.isOwned);
|
||||
EXPECT_EQ(qutex.queue.size(), 1);
|
||||
// Should not awaken since there's only one item
|
||||
EXPECT_FALSE(mock1->awakened);
|
||||
EXPECT_FALSE(qutex.isOwned);
|
||||
EXPECT_EQ(qutex.queue.size(), 1u);
|
||||
// Should not awaken since there's only one item
|
||||
EXPECT_FALSE(mock1->awakened);
|
||||
}
|
||||
|
||||
// Test backoff with multiple items and rotation
|
||||
TEST_F(QutexTest, BackoffWithRotation) {
|
||||
// Register multiple lockvokers
|
||||
auto it1 = qutex.registerInQueue(mock1);
|
||||
auto it2 = qutex.registerInQueue(mock2);
|
||||
auto it3 = qutex.registerInQueue(mock3);
|
||||
(void)qutex.registerInQueue(mock1);
|
||||
(void)qutex.registerInQueue(mock2);
|
||||
(void)qutex.registerInQueue(mock3);
|
||||
|
||||
// Set as owned first
|
||||
qutex.isOwned = true;
|
||||
@@ -259,8 +289,8 @@ TEST_F(QutexTest, BackoffWithRotation) {
|
||||
// Test backoff with rotation to back when queue smaller than nRequiredLocks
|
||||
TEST_F(QutexTest, BackoffRotationToBack) {
|
||||
// Register only 2 lockvokers
|
||||
auto it1 = qutex.registerInQueue(mock1);
|
||||
auto it2 = qutex.registerInQueue(mock2);
|
||||
(void)qutex.registerInQueue(mock1);
|
||||
(void)qutex.registerInQueue(mock2);
|
||||
|
||||
// Set as owned first
|
||||
qutex.isOwned = true;
|
||||
@@ -284,31 +314,26 @@ TEST_F(QutexTest, BackoffRotationToBack) {
|
||||
|
||||
// Test release functionality
|
||||
TEST_F(QutexTest, Release) {
|
||||
// Register multiple lockvokers
|
||||
auto it1 = qutex.registerInQueue(mock1);
|
||||
auto it2 = qutex.registerInQueue(mock2);
|
||||
// Register multiple lockvokers
|
||||
(void)qutex.registerInQueue(mock1);
|
||||
(void)qutex.registerInQueue(mock2);
|
||||
|
||||
// Set as owned
|
||||
qutex.isOwned = true;
|
||||
ASSERT_TRUE(qutex.tryAcquire(*mock1, 1));
|
||||
|
||||
// Release should set isOwned to false and awaken front item
|
||||
mock1->awakened = false;
|
||||
qutex.release();
|
||||
// Release should set isOwned to false and awaken front item
|
||||
mock1->awakened = false;
|
||||
qutex.release();
|
||||
|
||||
EXPECT_FALSE(qutex.isOwned);
|
||||
EXPECT_TRUE(mock1->awakened);
|
||||
EXPECT_FALSE(qutex.isOwned);
|
||||
EXPECT_TRUE(mock1->awakened);
|
||||
}
|
||||
|
||||
// Test release with empty queue
|
||||
TEST_F(QutexTest, ReleaseEmptyQueue) {
|
||||
// Set as owned
|
||||
qutex.isOwned = true;
|
||||
// Test release without a prior acquire is rejected
|
||||
TEST_F(QutexTest, ReleaseWithoutAcquireThrows) {
|
||||
qutex.isOwned = true;
|
||||
|
||||
// Release with empty queue should just set isOwned to false
|
||||
qutex.release();
|
||||
|
||||
EXPECT_FALSE(qutex.isOwned);
|
||||
EXPECT_TRUE(qutex.queue.empty());
|
||||
EXPECT_THROW(qutex.release(), std::runtime_error);
|
||||
EXPECT_TRUE(qutex.queue.empty());
|
||||
}
|
||||
|
||||
// Test exception when trying to acquire from empty queue
|
||||
@@ -326,7 +351,7 @@ TEST_F(QutexTest, ExceptionOnEmptyQueueBackoff) {
|
||||
// Test edge case: single lockvoker with multiple required locks
|
||||
TEST_F(QutexTest, SingleLockvokerMultipleRequiredLocks) {
|
||||
// Register only one lockvoker
|
||||
auto it1 = qutex.registerInQueue(mock1);
|
||||
(void)qutex.registerInQueue(mock1);
|
||||
|
||||
// Should succeed regardless of nRequiredLocks when only one item
|
||||
bool acquired = qutex.tryAcquire(*mock1, 5);
|
||||
|
||||
Reference in New Issue
Block a user