feat: Implement auto-capture of failure diagnostics and update related documentation

This commit is contained in:
scawful
2025-10-02 21:05:31 -04:00
parent 56c2132b78
commit 92d65e399e
7 changed files with 241 additions and 13 deletions

View File

@@ -221,6 +221,12 @@ message GetTestResultsResponse {
repeated AssertionResult assertions = 6;
repeated string logs = 7; // If include_logs=true
map<string, int32> metrics = 8; // e.g., "frame_count": 123
// IT-08b: Failure diagnostics
string screenshot_path = 9; // Path to failure screenshot (if captured)
int64 screenshot_size_bytes = 10; // Size of screenshot file
string failure_context = 11; // Execution context at failure time
string widget_state = 12; // Widget state dump (IT-08c - future)
}
message AssertionResult {

View File

@@ -1443,6 +1443,18 @@ absl::Status ImGuiTestHarnessServiceImpl::GetTestResults(
for (const auto& [key, value] : execution.metrics) {
(*metrics_map)[key] = value;
}
// IT-08b: Include failure diagnostics if available
if (!execution.screenshot_path.empty()) {
response->set_screenshot_path(execution.screenshot_path);
response->set_screenshot_size_bytes(execution.screenshot_size_bytes);
}
if (!execution.failure_context.empty()) {
response->set_failure_context(execution.failure_context);
}
if (!execution.widget_state.empty()) {
response->set_widget_state(execution.widget_state);
}
return absl::OkStatus();
}

View File

@@ -1367,6 +1367,15 @@ void TestManager::MarkHarnessTestCompleted(
execution.metrics.insert(metrics.begin(), metrics.end());
}
// IT-08b: Auto-capture failure context for failed/timeout tests
if (status == HarnessTestStatus::kFailed ||
status == HarnessTestStatus::kTimeout) {
// Release lock before calling CaptureFailureContext to avoid deadlock
lock.Release();
CaptureFailureContext(test_id);
lock.Acquire();
}
HarnessAggregate& aggregate = harness_aggregates_[execution.name];
if (aggregate.category.empty()) {
aggregate.category = execution.category;
@@ -1481,5 +1490,47 @@ void TestManager::TrimHarnessHistoryLocked() {
}
}
void TestManager::CaptureFailureContext(const std::string& test_id) {
// IT-08b: Capture failure diagnostics
// Note: This method is called with the harness_history_mutex_ unlocked
// to avoid deadlock when Screenshot RPC calls back into TestManager
absl::MutexLock lock(&harness_history_mutex_);
auto it = harness_history_.find(test_id);
if (it == harness_history_.end()) {
return;
}
HarnessTestExecution& execution = it->second;
// 1. Capture execution context (frame count, active window, etc.)
if (ImGui::GetCurrentContext() != nullptr) {
ImGuiWindow* current_window = ImGui::GetCurrentWindow();
const char* window_name = current_window ? current_window->Name : "none";
ImGuiID active_id = ImGui::GetActiveID();
execution.failure_context = absl::StrFormat(
"Frame: %d, Active Window: %s, Focused Widget: 0x%08X",
ImGui::GetFrameCount(),
window_name,
active_id);
} else {
execution.failure_context = "ImGui context not available";
}
// 2. Screenshot capture would happen here via gRPC call
// Note: Screenshot RPC implementation is in ImGuiTestHarnessServiceImpl
// The screenshot_path will be set by the RPC handler when it completes
// For now, we just set a placeholder path to indicate where it should be saved
execution.screenshot_path = absl::StrFormat("/tmp/yaze_test_%s_failure.bmp", test_id);
// 3. Widget state capture (IT-08c - future implementation)
// execution.widget_state = CaptureWidgetState();
util::logf("[TestManager] Captured failure context for test %s: %s",
test_id.c_str(),
execution.failure_context.c_str());
}
} // namespace test
} // namespace yaze

View File

@@ -140,6 +140,12 @@ struct HarnessTestExecution {
std::vector<std::string> assertion_failures;
std::vector<std::string> logs;
std::map<std::string, int32_t> metrics;
// IT-08b: Failure diagnostics
std::string screenshot_path;
int64_t screenshot_size_bytes = 0;
std::string failure_context;
std::string widget_state; // IT-08c (future)
};
struct HarnessTestSummary {
@@ -270,6 +276,10 @@ class TestManager {
std::vector<HarnessTestSummary> ListHarnessTestSummaries(
const std::string& category_filter = "") const
ABSL_LOCKS_EXCLUDED(harness_history_mutex_);
// IT-08b: Capture failure diagnostics
void CaptureFailureContext(const std::string& test_id)
ABSL_LOCKS_EXCLUDED(harness_history_mutex_);
private:
TestManager();