From 3df434fd55a197c9cd9f37378a3351f32fcff5be Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 4 Jul 2025 10:41:59 -0500 Subject: [PATCH] improve test --- .../defer_stress_component.cpp | 16 +----- .../defer_stress_component.h | 8 --- tests/integration/test_defer_stress.py | 51 +++++++++++++++---- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/tests/integration/fixtures/external_components/defer_stress_component/defer_stress_component.cpp b/tests/integration/fixtures/external_components/defer_stress_component/defer_stress_component.cpp index c49c7db21a..3a97476067 100644 --- a/tests/integration/fixtures/external_components/defer_stress_component/defer_stress_component.cpp +++ b/tests/integration/fixtures/external_components/defer_stress_component/defer_stress_component.cpp @@ -44,9 +44,9 @@ void DeferStressComponent::run_multi_thread_test() { auto *component = this; // Directly call defer() from this thread - no locking! - this->defer([component, defer_id]() { + this->defer([component, i, j, defer_id]() { component->executed_defers_.fetch_add(1); - ESP_LOGV(TAG, "Executed defer %d", defer_id); + ESP_LOGV(TAG, "Executed defer %d (thread %d, index %d)", defer_id, i, j); }); ESP_LOGV(TAG, "Thread %d called defer for request %d successfully", i, defer_id); @@ -68,19 +68,7 @@ void DeferStressComponent::run_multi_thread_test() { auto end_time = std::chrono::steady_clock::now(); auto thread_time = std::chrono::duration_cast(end_time - start_time).count(); ESP_LOGI(TAG, "All threads finished in %lldms. Created %d defer requests", thread_time, this->total_defers_.load()); - - // Store the final values for checking - this->expected_total_ = NUM_THREADS * DEFERS_PER_THREAD; - this->test_complete_ = true; } -int DeferStressComponent::get_total_defers() { return this->total_defers_.load(); } - -int DeferStressComponent::get_executed_defers() { return this->executed_defers_.load(); } - -bool DeferStressComponent::is_test_complete() { return this->test_complete_; } - -int DeferStressComponent::get_expected_total() { return this->expected_total_; } - } // namespace defer_stress_component } // namespace esphome diff --git a/tests/integration/fixtures/external_components/defer_stress_component/defer_stress_component.h b/tests/integration/fixtures/external_components/defer_stress_component/defer_stress_component.h index 4d60c3b484..59b7565726 100644 --- a/tests/integration/fixtures/external_components/defer_stress_component/defer_stress_component.h +++ b/tests/integration/fixtures/external_components/defer_stress_component/defer_stress_component.h @@ -11,17 +11,9 @@ class DeferStressComponent : public Component { void setup() override; void run_multi_thread_test(); - // Getters for test status - int get_total_defers(); - int get_executed_defers(); - bool is_test_complete(); - int get_expected_total(); - private: std::atomic total_defers_{0}; std::atomic executed_defers_{0}; - bool test_complete_{false}; - int expected_total_{0}; }; } // namespace defer_stress_component diff --git a/tests/integration/test_defer_stress.py b/tests/integration/test_defer_stress.py index 5e061e4651..c11a3aec4a 100644 --- a/tests/integration/test_defer_stress.py +++ b/tests/integration/test_defer_stress.py @@ -32,22 +32,38 @@ async def test_defer_stress( loop = asyncio.get_event_loop() test_complete_future: asyncio.Future[None] = loop.create_future() - # Track executed defers + # Track executed defers and their order executed_defers = set() + thread_executions = {} # thread_id -> list of indices in execution order + fifo_violations = [] def on_log_line(line: str) -> None: - # Track all executed defers - match = re.search(r"Executed defer (\d+)", line) + # Track all executed defers with thread and index info + match = re.search(r"Executed defer (\d+) \(thread (\d+), index (\d+)\)", line) if match: defer_id = int(match.group(1)) + thread_id = int(match.group(2)) + index = int(match.group(3)) + executed_defers.add(defer_id) - # Check if we've executed all 1000 defers (0-999) + # Track execution order per thread + if thread_id not in thread_executions: + thread_executions[thread_id] = [] + + # Check FIFO ordering within thread if ( - defer_id == 999 - and len(executed_defers) == 1000 - and not test_complete_future.done() + thread_executions[thread_id] + and thread_executions[thread_id][-1] >= index ): + fifo_violations.append( + f"Thread {thread_id}: index {index} executed after {thread_executions[thread_id][-1]}" + ) + + thread_executions[thread_id].append(index) + + # Check if we've executed all 1000 defers (0-999) + if len(executed_defers) == 1000 and not test_complete_future.done(): test_complete_future.set_result(None) async with ( @@ -96,5 +112,22 @@ async def test_defer_stress( missing_ids = expected_ids - executed_defers assert not missing_ids, f"Missing defer IDs: {sorted(missing_ids)}" - # If we got here without crashing, the test passed - assert True, "Test completed successfully - all 1000 defers executed in order" + # Verify FIFO ordering was maintained within each thread + assert not fifo_violations, "FIFO ordering violations detected:\n" + "\n".join( + fifo_violations[:10] + ) + + # Verify each thread executed all its defers in order + for thread_id, indices in thread_executions.items(): + assert len(indices) == 100, ( + f"Thread {thread_id} executed {len(indices)} defers, expected 100" + ) + # Indices should be 0-99 in ascending order + assert indices == list(range(100)), ( + f"Thread {thread_id} executed indices out of order: {indices[:10]}..." + ) + + # If we got here without crashing and with proper ordering, the test passed + assert True, ( + "Test completed successfully - all 1000 defers executed with FIFO ordering preserved" + )