stress test

This commit is contained in:
J. Nick Koston 2025-07-04 08:49:35 -05:00
parent cd2b50c27f
commit 0665fcea9e
No known key found for this signature in database
3 changed files with 0 additions and 253 deletions

View File

@ -1,35 +0,0 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_ID
CODEOWNERS = ["@test"]
AUTO_LOAD = ["api"]
api_buffer_test_component_ns = cg.esphome_ns.namespace("api_buffer_test_component")
APIBufferTestComponent = api_buffer_test_component_ns.class_(
"APIBufferTestComponent", cg.Component
)
CONF_FILL_SIZE = "fill_size"
CONF_FILL_COUNT = "fill_count"
CONF_AUTO_FILL_DELAY = "auto_fill_delay"
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(APIBufferTestComponent),
cv.Optional(CONF_FILL_SIZE, default=2048): cv.int_range(min=1, max=16384),
cv.Optional(CONF_FILL_COUNT, default=200): cv.int_range(min=1, max=1000),
cv.Optional(
CONF_AUTO_FILL_DELAY, default="2s"
): cv.positive_time_period_milliseconds,
}
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
cg.add(var.set_fill_size(config[CONF_FILL_SIZE]))
cg.add(var.set_fill_count(config[CONF_FILL_COUNT]))
cg.add(var.set_auto_fill_delay(config[CONF_AUTO_FILL_DELAY]))

View File

@ -1,166 +0,0 @@
#include "api_buffer_test_component.h"
#include "esphome/core/application.h"
namespace esphome {
namespace api_buffer_test_component {
APIBufferTestComponent *global_api_buffer_test_component =
nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
void APIBufferTestComponent::setup() {
ESP_LOGD(TAG, "API Buffer Test Component setup");
this->last_fill_time_ = millis();
global_api_buffer_test_component = this;
// For testing, we'll get the API connection through a hack
// In a real implementation, this would be done properly through the API
App.scheduler.set_timeout(this, "get_api_connection", 500, [this]() {
auto *api_server = api::global_api_server;
if (api_server != nullptr) {
// This is a hack - in production code, use proper API subscription
// For testing, we'll assume there's only one connection
ESP_LOGD(TAG, "Looking for API connection to subscribe to");
}
});
}
void APIBufferTestComponent::loop() {
// Check if API server is ready and has connections
auto *api_server = api::global_api_server;
if (api_server == nullptr || !api_server->is_connected()) {
return;
}
// Try to get an API connection if we don't have one
if (this->api_connection_ == nullptr && !this->tried_subscribe_) {
this->tried_subscribe_ = true;
ESP_LOGD(TAG, "API server is connected, buffer test component ready");
// For testing, we'll work with the fact that send_message is available
// through the global API server's connection management
}
uint32_t now = millis();
// Auto-fill buffer after delay if configured
if (this->auto_fill_delay_ > 0 && !this->buffer_filled_ && api_server->is_connected()) {
if (now - this->last_fill_time_ > this->auto_fill_delay_) {
ESP_LOGD(TAG, "Auto-filling buffer after %u ms delay", this->auto_fill_delay_);
// For the test, we'll generate heavy log traffic instead
this->generate_heavy_traffic();
this->buffer_filled_ = true;
// Keep generating traffic for 5 seconds
this->should_keep_full_ = true;
this->keep_full_until_ = now + 5000;
}
}
// Keep buffer full if requested
if (this->should_keep_full_ && now < this->keep_full_until_) {
// Generate more traffic to keep buffer full
this->generate_traffic_burst();
} else if (this->should_keep_full_ && now >= this->keep_full_until_) {
this->should_keep_full_ = false;
ESP_LOGD(TAG, "Stopped keeping buffer full");
}
}
void APIBufferTestComponent::subscribe_api_connection(api::APIConnection *api_connection) {
if (this->api_connection_ != nullptr) {
ESP_LOGE(TAG, "Already subscribed to an API connection");
return;
}
this->api_connection_ = api_connection;
ESP_LOGD(TAG, "Subscribed to API connection");
}
void APIBufferTestComponent::unsubscribe_api_connection(api::APIConnection *api_connection) {
if (this->api_connection_ != api_connection) {
return;
}
this->api_connection_ = nullptr;
ESP_LOGD(TAG, "Unsubscribed from API connection");
}
void APIBufferTestComponent::fill_buffer() {
if (this->api_connection_ == nullptr) {
ESP_LOGW(TAG, "No API connection available to fill buffer");
return;
}
ESP_LOGD(TAG, "Filling transmit buffer with %zu messages of %zu bytes each", this->fill_count_, this->fill_size_);
// Create a large text sensor state response to fill the buffer
api::TextSensorStateResponse resp;
resp.key = 0x12345678; // Dummy key
resp.state = std::string(this->fill_size_, 'X'); // Large payload
resp.missing_state = false;
// Send many messages rapidly to fill the transmit buffer
size_t sent_count = 0;
size_t failed_count = 0;
for (size_t i = 0; i < this->fill_count_; i++) {
// Modify the string slightly each time
resp.state[0] = 'A' + (i % 26);
// Send message directly without batching
bool sent = this->api_connection_->send_message(resp);
if (!sent) {
failed_count++;
ESP_LOGV(TAG, "Message %zu failed to send - buffer likely full", i);
} else {
sent_count++;
}
// Log progress
if (i % 50 == 0) {
ESP_LOGD(TAG, "Progress: %zu/%zu messages, %zu failed", i, this->fill_count_, failed_count);
}
}
ESP_LOGD(TAG, "Buffer fill complete: %zu sent, %zu failed", sent_count, failed_count);
this->last_fill_time_ = millis();
}
void APIBufferTestComponent::generate_heavy_traffic() {
ESP_LOGD(TAG, "Generating heavy traffic to fill transmit buffer");
// Generate many large log messages rapidly
// These will be sent over the API if log subscription is active
std::string large_log(this->fill_size_, 'X');
for (size_t i = 0; i < this->fill_count_; i++) {
// Modify the string to ensure each message is unique
large_log[0] = 'A' + (i % 26);
// Use VERY_VERBOSE level to ensure it's sent when subscribed
ESP_LOGVV(TAG, "Buffer fill #%zu: %s", i, large_log.c_str());
// Progress logging at higher level
if (i % 50 == 0) {
ESP_LOGD(TAG, "Traffic generation progress: %zu/%zu", i, this->fill_count_);
}
}
ESP_LOGD(TAG, "Heavy traffic generation complete");
}
void APIBufferTestComponent::generate_traffic_burst() {
// Generate a burst of medium-sized messages to keep buffer topped up
std::string medium_log(512, 'K');
for (int i = 0; i < 5; i++) {
medium_log[0] = '0' + (i % 10);
ESP_LOGVV(TAG, "Keep-full burst #%d: %s", i, medium_log.c_str());
}
}
void APIBufferTestComponent::keep_buffer_full() {
// Deprecated - use generate_traffic_burst instead
this->generate_traffic_burst();
}
} // namespace api_buffer_test_component
} // namespace esphome

View File

@ -1,52 +0,0 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/log.h"
#include "esphome/components/api/api_server.h"
#include "esphome/components/api/api_connection.h"
#include "esphome/components/api/api_pb2.h"
namespace esphome {
namespace api_buffer_test_component {
static const char *const TAG = "api_buffer_test";
class APIBufferTestComponent : public Component {
public:
void setup() override;
void loop() override;
float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; }
// Subscribe to API connection (like bluetooth_proxy)
void subscribe_api_connection(api::APIConnection *api_connection);
void unsubscribe_api_connection(api::APIConnection *api_connection);
// Test methods
void fill_buffer();
void keep_buffer_full();
void generate_heavy_traffic();
void generate_traffic_burst();
// Configuration
void set_fill_size(size_t size) { this->fill_size_ = size; }
void set_fill_count(size_t count) { this->fill_count_ = count; }
void set_auto_fill_delay(uint32_t delay) { this->auto_fill_delay_ = delay; }
protected:
api::APIConnection *api_connection_{nullptr};
size_t fill_size_{2048};
size_t fill_count_{200};
uint32_t auto_fill_delay_{2000};
uint32_t last_fill_time_{0};
bool buffer_filled_{false};
bool should_keep_full_{false};
uint32_t keep_full_until_{0};
bool tried_subscribe_{false};
};
extern APIBufferTestComponent
*global_api_buffer_test_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
} // namespace api_buffer_test_component
} // namespace esphome