Skip to content

Fix timed out Camera FPS config test#1845

Merged
aljazdu merged 4 commits into
developfrom
fix/rvc2_tests
Jun 24, 2026
Merged

Fix timed out Camera FPS config test#1845
aljazdu merged 4 commits into
developfrom
fix/rvc2_tests

Conversation

@aljazdu

@aljazdu aljazdu commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Purpose

Camera FPS config test often timed out for RVC2 POE devices. This fix adds early stopping when enough frames are collected.

Specification

None / not applicable

Dependencies & Potential Impact

None / not applicable

Deployment Plan

None / not applicable

Testing & Validation

None / not applicable

AI Usage

Assisted-by: /

Submitted code was reviewed by a human: YES

The author is taking the responsibility for the contribution: YES

Summary by CodeRabbit

  • Tests
    • Added a new on-device camera FPS/config validation test (camera_fps_config_part_2_test) to verify camera output queue/frame pool limits across platforms.
    • Updated platform-specific expectations for RVC4 queue size overrides and ensured behavior adapts when DEPTHAI_AUTOCALIBRATION=OFF.
  • Bug Fixes
    • Improved crash-dump state handling after reconnects by correctly preparing the “handled” tracking based on whether a pending crash dump exists.

@aljazdu aljazdu requested a review from moratom June 11, 2026 08:36
@aljazdu aljazdu self-assigned this Jun 11, 2026
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Camera pool size test coverage is split into two on-device tests with updated CMake registration, and reconnect monitoring now changes how crash-dump handled state is reset after success.

Changes

Camera pool sizes test coverage

Layer / File(s) Summary
Test target registration
tests/CMakeLists.txt
A new on-device test target, camera_fps_config_part_2_test, is added with labels matching the existing camera FPS config test and DEPTHAI_AUTOCALIBRATION=OFF in its environment.
Test case split and queue-size list
tests/src/ondevice_tests/pipeline/node/camera_fps_config_test.cpp, tests/src/ondevice_tests/pipeline/node/camera_fps_config_test_part_2.cpp
The existing Camera pool sizes test trims the RVC4 overrideQueueSize list, and a new companion Catch2 test adds the camera/script buffering checks for platform-specific queue limits.

Device reconnection crash-dump handling

Layer / File(s) Summary
Crash-dump availability and state reset
src/device/DeviceBase.cpp
After successful reconnect, crash-dump handling reads hasPendingCrashDump, assigns crashed from it, and clears crashDumpHandled only when no pending crash dump remains.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

testable

Suggested reviewers

  • moratom

Poem

🐰 Two camera tests hop side by side,
One trims the list, one checks the stride.
A crash-dump flag now calmly waits,
Until reconnect resets the gates.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: reducing Camera FPS config test timeouts.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/rvc2_tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/src/ondevice_tests/pipeline/node/camera_fps_config_test.cpp`:
- Line 184: The condition using a magic number (200) in the check
if(outQueuesCounter[idx] <= queueSize + 200) should be documented or replaced
with a named constant; either add a short inline comment explaining that 200
represents ~6.67 seconds at 30fps as the recovery verification window, or
refactor to a descriptive constant like kRecoveryFrameThreshold (used as
queueSize + kRecoveryFrameThreshold) so the intent of outQueuesCounter, idx and
queueSize is clear.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2c76d27f-84eb-4804-9695-c0e39b43ed89

📥 Commits

Reviewing files that changed from the base of the PR and between a713be1 and 9767050.

📒 Files selected for processing (1)
  • tests/src/ondevice_tests/pipeline/node/camera_fps_config_test.cpp
📜 Review details
🔇 Additional comments (1)
tests/src/ondevice_tests/pipeline/node/camera_fps_config_test.cpp (1)

177-191: LGTM!

Comment thread tests/src/ondevice_tests/pipeline/node/camera_fps_config_test.cpp Outdated
@moratom moratom requested a review from jakgra June 16, 2026 10:45
Comment on lines 184 to 190
if(outQueuesCounter[idx] <= queueSize + 200) {
gotEnoughFrames = false;
}
}
if(gotEnoughFrames) {
break;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think this might defeat the purpuse of the test CC: @jakgra

I would rather reduce the time to block for 30s if total runtime is a problem

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The current test implementation asserts only that 200 frames were successfully sent, not asserting sustained streaming for the full 30s window (while those 30s of streaming do happen). The early break preserves that assertion and removes dead wait on the success path, not influencing the test checks in any way.

I would rather reduce the time to block for 30s if total runtime is a problem

Can go with this, but would have to update the current assertion as well to actually achieve the mentioned purpose of the test.

Comment thread src/device/DeviceBase.cpp
@aljazkonec1 aljazkonec1 self-requested a review June 23, 2026 12:10

@aljazkonec1 aljazkonec1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

w.r.t. the 200 frame limit: the code does not reflect the spirit of the test. Instead of validating running for 30 seconds, it just checks for >200 recieved frames so I agree with what @aljazdu proposed to adapt.

IMO the entire test would need to be rewritten but lets make that a separate PR just because of higher prio items.
Before merge, just test out splitting the test into two files, one with the first TEST_CASE and half of the queue sizes form second TEST_CASE and another test file with the other half of the queue sizes. This should stop the timeout from hitting without the 200 frame limit.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/src/ondevice_tests/pipeline/node/camera_fps_config_test_part_2.cpp`:
- Around line 18-129: The Camera pool sizes test logic is duplicated here and
has already drifted from the original test body, so consolidate the shared
behavior into one helper used by both `camera_fps_config_test_part_2.cpp` and
`camera_fps_config_test.cpp`. Refactor the main body around `TEST_CASE("Camera
pool sizes")` into a reusable function or header-level helper that accepts the
override queue list and any target-specific parameters, then have each test file
call that shared helper so future changes stay in sync.
- Around line 45-56: The queue-size fallback logic in this companion camera FPS
test is unreachable because the local override list never uses the sentinel
value that would select the default path. Simplify the test by removing the dead
`autoCalibrationOnStartup`/`defaultQueueSize` computation and the
`overrideQueueSize != -1` branch in the `Camera` setup, and keep only the direct
`overrideQueueSize` assignment used by this split test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4fcd5cc5-84bf-4c62-af46-654a5fb32fd2

📥 Commits

Reviewing files that changed from the base of the PR and between 03f7e46 and 0c6d8ad.

📒 Files selected for processing (4)
  • src/device/DeviceBase.cpp
  • tests/CMakeLists.txt
  • tests/src/ondevice_tests/pipeline/node/camera_fps_config_test.cpp
  • tests/src/ondevice_tests/pipeline/node/camera_fps_config_test_part_2.cpp
📜 Review details
🧰 Additional context used
🪛 Cppcheck (2.21.0)
tests/src/ondevice_tests/pipeline/node/camera_fps_config_test_part_2.cpp

[error] 33-33: There is an unknown macro here somewhere. Configuration is required. If DEPTHAI_NLOHMANN_DEFINE_TYPE_INTRUSIVE is a macro then please configure it.

(unknownMacro)

🔇 Additional comments (3)
tests/src/ondevice_tests/pipeline/node/camera_fps_config_test.cpp (1)

81-81: LGTM!

tests/CMakeLists.txt (1)

849-851: 📐 Maintainability & Code Quality

No label drift. camera_fps_config_part_2_test uses the same labels and DEPTHAI_AUTOCALIBRATION=OFF environment as camera_fps_config_test.

src/device/DeviceBase.cpp (1)

1529-1530: 🎯 Functional Correctness

Keep the buffered crash flag aligned with pending dump state
hasCrashed() tracks the current crash-dump state, so clearing crashed here when no dump is pending avoids leaving a stale crash indicator after recovery.

			> Likely an incorrect or invalid review comment.

Comment on lines +18 to +129
TEST_CASE("Camera pool sizes") {
auto firstDevice = dai::Device::getFirstAvailableDevice();
auto isRvc4 = std::get<1>(firstDevice).platform == X_LINK_RVC4;
for(const int overrideQueueSize : (isRvc4 ? std::vector<int>{50, 4, 5} : std::vector<int>{3, 4, 5})) {
std::cout << "Testing num frames = " << overrideQueueSize << "\n" << std::flush;
dai::Pipeline pipeline;
std::map<dai::CameraBoardSocket, std::vector<std::tuple<int, int, float>>> streamsRvc4{
// Has to be (for now):
// - without FpsRegulator (different fps per same sensor)(different fps on different sensors also doesn't work right now)
// - without ManipResizer so size should be supported by ISP directly
{dai::CameraBoardSocket::CAM_A, {{640, 480, 30.0f}, {1920, 1440, 30.0f}}},
{dai::CameraBoardSocket::CAM_B, {{640, 400, 30.0f}, {1280, 800, 30.0f}}},
{dai::CameraBoardSocket::CAM_C, {{640, 400, 30.0f}, {1280, 800, 30.0f}}},
};
// RVC2 is more RAM bound so use smaller sizes for the test
std::map<dai::CameraBoardSocket, std::vector<std::tuple<int, int, float>>> streamsRvc2{
// Has to be (for now):
// - not a size supported directly by ISP as then isp is passed trough and the isp pool size value is used not the outputs pool size
{dai::CameraBoardSocket::CAM_A, {{300, 300, 30.0f}}},
{dai::CameraBoardSocket::CAM_B, {{300, 300, 30.0f}, {200, 200, 30.0f}}},
{dai::CameraBoardSocket::CAM_C, {{200, 200, 30.0f}}},
};
auto streams = isRvc4 ? streamsRvc4 : streamsRvc2;
std::vector<std::shared_ptr<dai::MessageQueue>> outQueues;
std::vector<int> outQueuesCounter;
std::vector<std::shared_ptr<dai::node::Camera>> cameras;
auto script = pipeline.create<dai::node::Script>();
// If startup AutoCalibration is enabled globally, default pool count is increased by 3.
const char* autoCalibrationEnv = std::getenv("DEPTHAI_AUTOCALIBRATION");
const bool autoCalibrationOnStartup =
autoCalibrationEnv != nullptr && (std::string(autoCalibrationEnv) == "ON_START" || std::string(autoCalibrationEnv) == "CONTINUOUS");
const int defaultQueueSizeBase = isRvc4 ? 7 : 3;
const int defaultQueueSize = defaultQueueSizeBase + (autoCalibrationOnStartup ? 3 : 0);
int queueSize = overrideQueueSize == -1 ? defaultQueueSize : overrideQueueSize;
for(const auto& [socket, resolutions] : streams) {
auto camera = pipeline.create<dai::node::Camera>()->build(socket);
camera->properties.maxSizePoolOutputs = 1 * 1024 * 1024 * 1024; // 1G size limit to only test num frames limitation
if(overrideQueueSize != -1) {
camera->properties.numFramesPoolOutputs = overrideQueueSize;
}
for(const auto& resolution : resolutions) {
std::string theKey = std::to_string(outQueues.size());
std::string inputName = "in" + theKey;
std::string outputName = "out" + theKey;
camera->requestOutput({std::get<0>(resolution), std::get<1>(resolution)}, std::nullopt, dai::ImgResizeMode::CROP, std::get<2>(resolution))
->link(script->inputs[inputName]);
script->inputs[inputName].setBlocking(false);
script->inputs[inputName].setMaxSize(1000);
outQueues.push_back(script->outputs[outputName].createOutputQueue());
outQueuesCounter.push_back(0);
}
cameras.push_back(camera);
}
int timeToBlock = 20;
std::string scriptContent = isRvc4 ? R"(
from depthai import BenchmarkReport)"
: "";
scriptContent += R"(
import time

all_frames=[]
max_id = )" + std::to_string(outQueues.size() - 1)
+ R"(
start_time = time.time()
while time.time() - start_time < )"
+ std::to_string(timeToBlock) + R"(:
for idx in range(max_id + 1):
the_key = str(idx)
frame = node.inputs["in" + the_key].tryGet()
if frame is not None:
all_frames.append(frame)
out = BenchmarkReport()
node.outputs["out" + the_key].send(out)
all_frames = []
while True:
for idx in range(max_id + 1):
the_key = str(idx)
frame = node.inputs["in" + the_key].tryGet()
if frame is not None:
out = BenchmarkReport()
node.outputs["out" + the_key].send(out)
)";
script->setScript(scriptContent);
pipeline.start();
auto startTime = std::chrono::steady_clock::now();
// Keep frames in script node and check Camera node stops sending frames after buffer limit is hit
while(std::chrono::duration<double>(std::chrono::steady_clock::now() - startTime).count() < timeToBlock - 5) {
for(int idx = 0; idx < outQueues.size(); ++idx) {
auto frame = outQueues[idx]->tryGet();
if(frame) {
++outQueuesCounter[idx];
}
}
}
std::cout << "Got the first part frames\n" << std::flush;
for(const auto& count : outQueuesCounter) {
REQUIRE(count == queueSize);
}
// Check stream still works after script node unblocks the Camera node
while(std::chrono::duration<double>(std::chrono::steady_clock::now() - startTime).count() < timeToBlock + 30) {
for(int idx = 0; idx < outQueues.size(); ++idx) {
auto frame = outQueues[idx]->tryGet();
if(frame) {
++outQueuesCounter[idx];
}
}
}
for(const auto& count : outQueuesCounter) {
REQUIRE(count > queueSize + 200);
}
}
}

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.

📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Near-total duplication with the original Camera pool sizes test.

This file is a copy of the Camera pool sizes body in camera_fps_config_test.cpp with only the override-list parameters differing. They are already diverging (the original dropped the early-break/gotEnoughFrames logic while this copy retains the queueSize + 200 tail check), which is exactly the drift duplication invites. Consider extracting the shared body into a common helper (e.g. a header taking the override-list as an argument) so both targets exercise identical logic.

🧰 Tools
🪛 Cppcheck (2.21.0)

[error] 33-33: There is an unknown macro here somewhere. Configuration is required. If DEPTHAI_NLOHMANN_DEFINE_TYPE_INTRUSIVE is a macro then please configure it.

(unknownMacro)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/src/ondevice_tests/pipeline/node/camera_fps_config_test_part_2.cpp`
around lines 18 - 129, The Camera pool sizes test logic is duplicated here and
has already drifted from the original test body, so consolidate the shared
behavior into one helper used by both `camera_fps_config_test_part_2.cpp` and
`camera_fps_config_test.cpp`. Refactor the main body around `TEST_CASE("Camera
pool sizes")` into a reusable function or header-level helper that accepts the
override queue list and any target-specific parameters, then have each test file
call that shared helper so future changes stay in sync.

Comment on lines +45 to +56
// If startup AutoCalibration is enabled globally, default pool count is increased by 3.
const char* autoCalibrationEnv = std::getenv("DEPTHAI_AUTOCALIBRATION");
const bool autoCalibrationOnStartup =
autoCalibrationEnv != nullptr && (std::string(autoCalibrationEnv) == "ON_START" || std::string(autoCalibrationEnv) == "CONTINUOUS");
const int defaultQueueSizeBase = isRvc4 ? 7 : 3;
const int defaultQueueSize = defaultQueueSizeBase + (autoCalibrationOnStartup ? 3 : 0);
int queueSize = overrideQueueSize == -1 ? defaultQueueSize : overrideQueueSize;
for(const auto& [socket, resolutions] : streams) {
auto camera = pipeline.create<dai::node::Camera>()->build(socket);
camera->properties.maxSizePoolOutputs = 1 * 1024 * 1024 * 1024; // 1G size limit to only test num frames limitation
if(overrideQueueSize != -1) {
camera->properties.numFramesPoolOutputs = overrideQueueSize;

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.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Dead default-queue-size / autocalibration logic in this split.

In this companion test the override list (line 21) never contains -1, so queueSize always equals overrideQueueSize and the defaultQueueSize/autoCalibrationOnStartup computation plus the overrideQueueSize != -1 guard are unreachable. This was carried over verbatim from the original test where -1 exercised the default path. Consider dropping it here to avoid confusion (the CMake DEPTHAI_AUTOCALIBRATION=OFF already makes the env read moot).

♻️ Proposed simplification
-        auto script = pipeline.create<dai::node::Script>();
-        // If startup AutoCalibration is enabled globally, default pool count is increased by 3.
-        const char* autoCalibrationEnv = std::getenv("DEPTHAI_AUTOCALIBRATION");
-        const bool autoCalibrationOnStartup =
-            autoCalibrationEnv != nullptr && (std::string(autoCalibrationEnv) == "ON_START" || std::string(autoCalibrationEnv) == "CONTINUOUS");
-        const int defaultQueueSizeBase = isRvc4 ? 7 : 3;
-        const int defaultQueueSize = defaultQueueSizeBase + (autoCalibrationOnStartup ? 3 : 0);
-        int queueSize = overrideQueueSize == -1 ? defaultQueueSize : overrideQueueSize;
+        auto script = pipeline.create<dai::node::Script>();
+        int queueSize = overrideQueueSize;
         for(const auto& [socket, resolutions] : streams) {
             auto camera = pipeline.create<dai::node::Camera>()->build(socket);
             camera->properties.maxSizePoolOutputs = 1 * 1024 * 1024 * 1024;  // 1G size limit to only test num frames limitation
-            if(overrideQueueSize != -1) {
-                camera->properties.numFramesPoolOutputs = overrideQueueSize;
-            }
+            camera->properties.numFramesPoolOutputs = overrideQueueSize;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// If startup AutoCalibration is enabled globally, default pool count is increased by 3.
const char* autoCalibrationEnv = std::getenv("DEPTHAI_AUTOCALIBRATION");
const bool autoCalibrationOnStartup =
autoCalibrationEnv != nullptr && (std::string(autoCalibrationEnv) == "ON_START" || std::string(autoCalibrationEnv) == "CONTINUOUS");
const int defaultQueueSizeBase = isRvc4 ? 7 : 3;
const int defaultQueueSize = defaultQueueSizeBase + (autoCalibrationOnStartup ? 3 : 0);
int queueSize = overrideQueueSize == -1 ? defaultQueueSize : overrideQueueSize;
for(const auto& [socket, resolutions] : streams) {
auto camera = pipeline.create<dai::node::Camera>()->build(socket);
camera->properties.maxSizePoolOutputs = 1 * 1024 * 1024 * 1024; // 1G size limit to only test num frames limitation
if(overrideQueueSize != -1) {
camera->properties.numFramesPoolOutputs = overrideQueueSize;
int queueSize = overrideQueueSize;
for(const auto& [socket, resolutions] : streams) {
auto camera = pipeline.create<dai::node::Camera>()->build(socket);
camera->properties.maxSizePoolOutputs = 1 * 1024 * 1024 * 1024; // 1G size limit to only test num frames limitation
camera->properties.numFramesPoolOutputs = overrideQueueSize;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/src/ondevice_tests/pipeline/node/camera_fps_config_test_part_2.cpp`
around lines 45 - 56, The queue-size fallback logic in this companion camera FPS
test is unreachable because the local override list never uses the sentinel
value that would select the default path. Simplify the test by removing the dead
`autoCalibrationOnStartup`/`defaultQueueSize` computation and the
`overrideQueueSize != -1` branch in the `Camera` setup, and keep only the direct
`overrideQueueSize` assignment used by this split test.

@aljazkonec1 aljazkonec1 self-requested a review June 24, 2026 07:00
@aljazkonec1 aljazkonec1 requested a review from moratom June 24, 2026 07:00
@aljazkonec1 aljazkonec1 dismissed moratom’s stale review June 24, 2026 07:01

Assigned to me after the fact

@aljazkonec1 aljazkonec1 added the testable PR is ready to be tested - run vanilla tests label Jun 24, 2026
@aljazkonec1

Copy link
Copy Markdown
Collaborator

Can merge once POE and Crashdump tests pass

@aljazdu aljazdu merged commit 7db734c into develop Jun 24, 2026
64 of 71 checks passed
@aljazdu aljazdu deleted the fix/rvc2_tests branch June 24, 2026 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

testable PR is ready to be tested - run vanilla tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants