mirror of
https://github.com/esphome/esphome.git
synced 2025-08-06 18:37:47 +00:00
stress
This commit is contained in:
parent
0665fcea9e
commit
f7ca26eef8
@ -1,65 +1,36 @@
|
||||
esphome:
|
||||
name: defer-stress-test
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: EXTERNAL_COMPONENT_PATH
|
||||
components: [defer_stress_component]
|
||||
|
||||
host:
|
||||
|
||||
logger:
|
||||
level: DEBUG
|
||||
|
||||
defer_stress_component:
|
||||
id: defer_stress
|
||||
|
||||
api:
|
||||
services:
|
||||
- service: run_stress_test
|
||||
then:
|
||||
- lambda: |-
|
||||
static int total_defers = 0;
|
||||
static int executed_defers = 0;
|
||||
|
||||
ESP_LOGI("stress", "Starting defer stress test - rapid sequential defers");
|
||||
|
||||
// Reset counters
|
||||
total_defers = 0;
|
||||
executed_defers = 0;
|
||||
|
||||
// Create a temporary component to access defer()
|
||||
class TestComponent : public Component {
|
||||
public:
|
||||
void run_test() {
|
||||
// Rapidly defer many callbacks to stress the defer mechanism
|
||||
for (int batch = 0; batch < 10; batch++) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
int expected_id = total_defers;
|
||||
this->defer([expected_id]() {
|
||||
executed_defers++;
|
||||
ESP_LOGV("stress", "Defer %d executed", expected_id);
|
||||
});
|
||||
total_defers++;
|
||||
}
|
||||
// Brief yield to let other work happen
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TestComponent test_comp;
|
||||
test_comp.run_test();
|
||||
|
||||
ESP_LOGI("stress", "Scheduled %d defers", total_defers);
|
||||
|
||||
// Give the main loop time to process all defers
|
||||
App.scheduler.set_timeout((Component*)nullptr, nullptr, 500, []() {
|
||||
ESP_LOGI("stress", "Test complete. Defers scheduled: %d, executed: %d", total_defers, executed_defers);
|
||||
|
||||
// We should have executed all defers without crashing
|
||||
if (executed_defers == total_defers && total_defers == 1000) {
|
||||
ESP_LOGI("stress", "✓ Stress test PASSED - All %d defers executed", total_defers);
|
||||
id(test_result)->trigger("passed");
|
||||
} else {
|
||||
ESP_LOGE("stress", "✗ Stress test FAILED - Expected 1000 executed, got %d", executed_defers);
|
||||
id(test_result)->trigger("failed");
|
||||
}
|
||||
|
||||
id(test_complete)->trigger("test_finished");
|
||||
});
|
||||
id(defer_stress)->run_multi_thread_test();
|
||||
- wait_until:
|
||||
lambda: |-
|
||||
return id(defer_stress)->is_test_complete();
|
||||
- lambda: |-
|
||||
if (id(defer_stress)->is_test_passed()) {
|
||||
id(test_result)->trigger("passed");
|
||||
} else {
|
||||
id(test_result)->trigger("failed");
|
||||
}
|
||||
id(test_complete)->trigger("test_finished");
|
||||
|
||||
event:
|
||||
- platform: template
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""Stress test for defer() thread safety with multiple threads."""
|
||||
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
from aioesphomeapi import EntityState, Event, EventInfo, UserService
|
||||
import pytest
|
||||
@ -16,6 +17,16 @@ async def test_defer_stress(
|
||||
) -> None:
|
||||
"""Test that defer() doesn't crash when called rapidly from multiple threads."""
|
||||
|
||||
# Get the absolute path to the external components directory
|
||||
external_components_path = str(
|
||||
Path(__file__).parent / "fixtures" / "external_components"
|
||||
)
|
||||
|
||||
# Replace the placeholder in the YAML config with the actual path
|
||||
yaml_config = yaml_config.replace(
|
||||
"EXTERNAL_COMPONENT_PATH", external_components_path
|
||||
)
|
||||
|
||||
async with run_compiled(yaml_config), api_client_connected() as client:
|
||||
# Verify we can connect
|
||||
device_info = await client.device_info()
|
||||
@ -79,10 +90,10 @@ async def test_defer_stress(
|
||||
|
||||
# Wait for test completion with a longer timeout (threads run for 100ms + processing time)
|
||||
try:
|
||||
await asyncio.wait_for(test_complete_future, timeout=10.0)
|
||||
await asyncio.wait_for(test_complete_future, timeout=15.0)
|
||||
test_passed = await asyncio.wait_for(test_result_future, timeout=1.0)
|
||||
except asyncio.TimeoutError:
|
||||
pytest.fail("Stress test did not complete within 10 seconds")
|
||||
pytest.fail("Stress test did not complete within 15 seconds")
|
||||
|
||||
# Verify the test passed
|
||||
assert test_passed is True, (
|
||||
|
Loading…
x
Reference in New Issue
Block a user