1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-02 03:12:20 +01:00
Files
esphome/tests/integration/fixtures/scheduler_removed_item_race.yaml
J. Nick Koston e06dbffe9f fix
2025-08-17 16:12:53 -04:00

119 lines
4.1 KiB
YAML

esphome:
name: scheduler-removed-item-race
host:
api:
services:
- service: run_test
then:
- script.execute: run_test_script
logger:
level: DEBUG
globals:
- id: test_passed
type: bool
initial_value: 'true'
- id: removed_item_executed
type: int
initial_value: '0'
- id: normal_item_executed
type: int
initial_value: '0'
sensor:
- platform: template
id: test_sensor
name: "Test Sensor"
update_interval: never
lambda: return 0.0;
script:
- id: run_test_script
then:
- logger.log: "=== Starting Removed Item Race Test ==="
# This test creates a scenario where:
# 1. Multiple timeouts are scheduled to execute at nearly the same time
# 2. One timeout in the middle of the heap gets cancelled
# 3. Without the fix, the cancelled timeout would still execute
- lambda: |-
// Schedule multiple timeouts that will all be ready at the same time
// This ensures they're all in the heap together
// First timeout - executes at 10ms
App.scheduler.set_timeout(id(test_sensor), "timeout1", 10, []() {
ESP_LOGD("test", "Timeout 1 executed (expected)");
id(normal_item_executed)++;
});
// Second timeout - executes at 10ms (will be cancelled)
App.scheduler.set_timeout(id(test_sensor), "timeout2", 10, []() {
ESP_LOGE("test", "RACE: Timeout 2 executed after being cancelled!");
id(removed_item_executed)++;
id(test_passed) = false;
});
// Third timeout - executes at 10ms
App.scheduler.set_timeout(id(test_sensor), "timeout3", 10, []() {
ESP_LOGD("test", "Timeout 3 executed (expected)");
id(normal_item_executed)++;
});
// Fourth timeout - executes at 10ms
App.scheduler.set_timeout(id(test_sensor), "timeout4", 10, []() {
ESP_LOGD("test", "Timeout 4 executed (expected)");
id(normal_item_executed)++;
});
// Now cancel timeout2
// Since all timeouts have the same execution time, they're all in the heap
// timeout2 might not be at the front, so cleanup_() won't remove it
bool cancelled = App.scheduler.cancel_timeout(id(test_sensor), "timeout2");
ESP_LOGD("test", "Cancelled timeout2: %s", cancelled ? "true" : "false");
// Also test with items at slightly different times
App.scheduler.set_timeout(id(test_sensor), "timeout5", 11, []() {
ESP_LOGD("test", "Timeout 5 executed (expected)");
id(normal_item_executed)++;
});
App.scheduler.set_timeout(id(test_sensor), "timeout6", 12, []() {
ESP_LOGE("test", "RACE: Timeout 6 executed after being cancelled!");
id(removed_item_executed)++;
id(test_passed) = false;
});
App.scheduler.set_timeout(id(test_sensor), "timeout7", 13, []() {
ESP_LOGD("test", "Timeout 7 executed (expected)");
id(normal_item_executed)++;
});
// Cancel timeout6
cancelled = App.scheduler.cancel_timeout(id(test_sensor), "timeout6");
ESP_LOGD("test", "Cancelled timeout6: %s", cancelled ? "true" : "false");
# Wait for all timeouts to execute (or not)
- delay: 50ms
# Check results
- lambda: |-
ESP_LOGI("test", "=== Test Results ===");
ESP_LOGI("test", "Normal items executed: %d (expected 5)", id(normal_item_executed));
ESP_LOGI("test", "Removed items executed: %d (expected 0)", id(removed_item_executed));
if (id(removed_item_executed) > 0) {
ESP_LOGE("test", "TEST FAILED: %d cancelled items were executed!", id(removed_item_executed));
id(test_passed) = false;
} else if (id(normal_item_executed) != 5) {
ESP_LOGE("test", "TEST FAILED: Expected 5 normal items, got %d", id(normal_item_executed));
id(test_passed) = false;
} else {
ESP_LOGI("test", "TEST PASSED: No cancelled items were executed");
}
ESP_LOGI("test", "=== Test Complete ===");