|
|
|
@@ -37,8 +37,8 @@ def define(path, name):
|
|
|
|
|
uri_tables = re.findall(r'^static const httpd_uri_t(?: \*const)? \w+\[?\]? = \{.*?^\};',
|
|
|
|
|
source, re.M | re.S)
|
|
|
|
|
# Non-array declarations have no brackets; explicit shape avoids silent omission.
|
|
|
|
|
if len(uri_tables) != 36:
|
|
|
|
|
raise RuntimeError('Review URI extraction: expected 34 descriptors and two tables')
|
|
|
|
|
if len(uri_tables) != 37:
|
|
|
|
|
raise RuntimeError('Review URI extraction: expected 35 descriptors and two tables')
|
|
|
|
|
state = source[source.index('static SemaphoreHandle_t s_server_mutex;'):
|
|
|
|
|
source.index('static esp_err_t ensure_mutex(void)')]
|
|
|
|
|
header = (ROOT / 'src/web_server.h').read_text()
|
|
|
|
@@ -46,6 +46,7 @@ header = '\n'.join(line for line in header.splitlines()
|
|
|
|
|
if not line.startswith(('#include', '#pragma once')))
|
|
|
|
|
constants = define(SOURCE, 'WEB_SERVER_PORT')
|
|
|
|
|
for filename, names in {
|
|
|
|
|
'web_firmware_update.h': ('WEB_FIRMWARE_UPDATE_URI',),
|
|
|
|
|
'web_admin_transport.h': ('WEB_ADMIN_TICKET_URI', 'WEB_ADMIN_WS_URI'),
|
|
|
|
|
'web_serial_transport.h': ('WEB_SERIAL_TRANSPORT_TICKET_URI', 'WEB_SERIAL_TRANSPORT_WS_URI'),
|
|
|
|
|
'web_security.h': ('WEB_SECURITY_CERTIFICATE_DER_CAPACITY', 'WEB_SECURITY_PRIVATE_KEY_DER_CAPACITY'),
|
|
|
|
@@ -104,7 +105,7 @@ static bool unregister_fail;
|
|
|
|
|
static bool settings_fail;
|
|
|
|
|
static unsigned settings_calls;
|
|
|
|
|
static unsigned operation_calls, operation_fail_at;
|
|
|
|
|
static const httpd_uri_t *registered[39];
|
|
|
|
|
static const httpd_uri_t *registered[40];
|
|
|
|
|
static char events[128]; static size_t event_length;
|
|
|
|
|
static void event(char value) { assert(!locked && event_length + 1 < sizeof(events)); events[event_length++] = value; events[event_length] = 0; }
|
|
|
|
|
static SemaphoreHandle_t xSemaphoreCreateMutex(void) { assert(!locked); return mutex_fail ? NULL : &mutex_storage; }
|
|
|
|
@@ -134,6 +135,7 @@ static esp_err_t web_security_replace_reserved(uint32_t token) {
|
|
|
|
|
}
|
|
|
|
|
static void web_security_release_identity(uint32_t token) { assert(!locked); if (token == identity_token) identity_token = 0; }
|
|
|
|
|
#define HANDLER(name) static esp_err_t name(httpd_req_t *r) { (void)r; assert(!"HTTP handler must not run in lifecycle harness"); return ESP_FAIL; }
|
|
|
|
|
HANDLER(web_firmware_update_handler)
|
|
|
|
|
HANDLER(root_handler) HANDLER(status_handler) HANDLER(traced_ticket_handler)
|
|
|
|
|
HANDLER(traced_websocket_handler) HANDLER(asset_handler) HANDLER(web_cookie_auth_handler)
|
|
|
|
|
HANDLER(traced_admin_ticket_handler) HANDLER(traced_admin_upgrade_handler)
|
|
|
|
@@ -277,7 +279,7 @@ static esp_err_t web_security_copy_tls_material(uint8_t *cert, size_t nc, size_t
|
|
|
|
|
static esp_err_t httpd_ssl_start(httpd_handle_t *server, const httpd_ssl_config_t *config) {
|
|
|
|
|
assert(!locked && auth_live && !ssl_live); ++ssl_starts;
|
|
|
|
|
assert(config->httpd.max_open_sockets == 6 && !config->httpd.lru_purge_enable);
|
|
|
|
|
assert(config->httpd.max_uri_handlers == 39 && config->port_secure == 443);
|
|
|
|
|
assert(config->httpd.max_uri_handlers == 40 && config->port_secure == 443);
|
|
|
|
|
assert(config->httpd.recv_wait_timeout == 1 && config->httpd.send_wait_timeout == 1);
|
|
|
|
|
assert(config->tls_handshake_timeout_ms == 5000);
|
|
|
|
|
assert(config->user_cb == tls_session_callback);
|
|
|
|
@@ -293,7 +295,7 @@ static esp_err_t register_one(httpd_handle_t server) {
|
|
|
|
|
}
|
|
|
|
|
static esp_err_t httpd_register_uri_handler(httpd_handle_t s, const httpd_uri_t *uri) {
|
|
|
|
|
if (!strcmp(uri->uri, "/api/settings/serial")) {
|
|
|
|
|
assert(s == SERVER && auth_live && ssl_live && registration_calls >= 17);
|
|
|
|
|
assert(s == SERVER && auth_live && ssl_live && registration_calls >= 18);
|
|
|
|
|
assert(uri->method == HTTP_GET && uri->handler == serial_settings_handler);
|
|
|
|
|
++settings_calls;
|
|
|
|
|
if (settings_fail) return ESP_ERR_NO_MEM;
|
|
|
|
@@ -301,11 +303,11 @@ static esp_err_t httpd_register_uri_handler(httpd_handle_t s, const httpd_uri_t
|
|
|
|
|
return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
if (!strcmp(uri->uri, "/api/admin/ws-ticket") || !strcmp(uri->uri, "/ws/admin")) {
|
|
|
|
|
assert(registration_calls >= 16);
|
|
|
|
|
assert(registration_calls >= 17);
|
|
|
|
|
assert(serial_init_error != ESP_OK || serial_live);
|
|
|
|
|
} else assert(registration_calls < 14);
|
|
|
|
|
} else assert(registration_calls < 15);
|
|
|
|
|
esp_err_t error = register_one(s);
|
|
|
|
|
if (error == ESP_OK) { assert(registered_count < 39); registered[registered_count++] = uri; }
|
|
|
|
|
if (error == ESP_OK) { assert(registered_count < 40); registered[registered_count++] = uri; }
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
static esp_err_t account_register(httpd_handle_t s, const httpd_uri_t *uri) {
|
|
|
|
@@ -355,7 +357,7 @@ static esp_err_t web_httpd_register_optional(httpd_handle_t s, const httpd_uri_t
|
|
|
|
|
}
|
|
|
|
|
static esp_err_t httpd_unregister_uri_handler(httpd_handle_t s, const char *uri, int method) {
|
|
|
|
|
assert(!locked && s == SERVER && ssl_live && auth_live && serial_live);
|
|
|
|
|
assert((registration_calls == 18 && !strcmp(uri, "/api/admin/ws-ticket") && method == HTTP_POST) ||
|
|
|
|
|
assert((registration_calls == 19 && !strcmp(uri, "/api/admin/ws-ticket") && method == HTTP_POST) ||
|
|
|
|
|
((!strcmp(uri, "/api/settings/serial-operation") || !strcmp(uri, "/api/settings/account-operation") || !strcmp(uri, "/api/settings/network-operation") || !strcmp(uri, "/api/settings/display-operation") || !strcmp(uri, "/api/settings/broker-operation") || !strcmp(uri, "/api/settings/ssh-operation") || !strcmp(uri, "/api/settings/lifecycle-operation")) && method == HTTP_GET));
|
|
|
|
|
++unregister_calls;
|
|
|
|
|
for (unsigned i = 0; i < registered_count; ++i) {
|
|
|
|
@@ -372,15 +374,15 @@ static esp_err_t httpd_unregister_uri_handler(httpd_handle_t s, const char *uri,
|
|
|
|
|
}
|
|
|
|
|
static esp_err_t httpd_register_err_handler(httpd_handle_t s, httpd_err_code_t code,
|
|
|
|
|
esp_err_t (*handler)(httpd_req_t *, httpd_err_code_t)) {
|
|
|
|
|
assert(registration_calls == 14 || registration_calls == 15);
|
|
|
|
|
assert(registration_calls == 15 || registration_calls == 16);
|
|
|
|
|
assert((code == 404 || code == 405) && handler == route_error_handler);
|
|
|
|
|
return register_one(s);
|
|
|
|
|
}
|
|
|
|
|
static esp_err_t web_serial_transport_attach_server(httpd_handle_t s) {
|
|
|
|
|
assert(!locked && s == SERVER && ssl_live && auth_live && registration_calls == 16);
|
|
|
|
|
assert(!locked && s == SERVER && ssl_live && auth_live && registration_calls == 17);
|
|
|
|
|
++serial_attaches; serial_live = true; return ESP_OK;
|
|
|
|
|
}
|
|
|
|
|
static esp_err_t web_admin_transport_init(void) { assert(!locked && auth_live && registration_calls == 18); ++admin_inits; return admin_init_error; }
|
|
|
|
|
static esp_err_t web_admin_transport_init(void) { assert(!locked && auth_live && registration_calls == 19); ++admin_inits; return admin_init_error; }
|
|
|
|
|
static esp_err_t web_admin_transport_attach(httpd_handle_t s) {
|
|
|
|
|
assert(!locked && s == SERVER && ssl_live && !admin_owned); ++admin_attaches;
|
|
|
|
|
admin_owned = admin_attach_error == ESP_OK; return admin_attach_error;
|
|
|
|
@@ -531,7 +533,8 @@ int main(void) {
|
|
|
|
|
}
|
|
|
|
|
puts("PASS optional admin init/attach failures do not disable M1 auth or serial attachment");
|
|
|
|
|
|
|
|
|
|
reset(); start(); assert(registered_count == 39 && registration_calls == 18 && settings_calls == 1 && operation_calls == 2);
|
|
|
|
|
reset(); start(); assert(registered_count == 40 && registration_calls == 19 && settings_calls == 1 && operation_calls == 2);
|
|
|
|
|
assert(route("/api/firmware")->method == HTTP_POST && route("/api/firmware")->handler == web_firmware_update_handler);
|
|
|
|
|
assert(generation_calls == 1 && route("/api/settings/accounts/generate-password")->handler == web_account_generate_password_handler);
|
|
|
|
|
assert(route("/api/settings/serial")->handler == serial_settings_handler);
|
|
|
|
|
assert(keys_calls == 1 && route("/api/settings/accounts/keys")->handler == web_account_keys_handler);
|
|
|
|
@@ -569,23 +572,23 @@ int main(void) {
|
|
|
|
|
assert(admin_detaches == 2 && serial_detaches == 1 && admin_stoppeds == 1 && !s_admin_transport_owned);
|
|
|
|
|
puts("PASS failed SSL stop retains admin ownership; stopped runs only after successful retry");
|
|
|
|
|
|
|
|
|
|
for (unsigned failure = 1; failure <= 16; ++failure) {
|
|
|
|
|
for (unsigned failure = 1; failure <= 17; ++failure) {
|
|
|
|
|
reset(); registration_fail_at = failure;
|
|
|
|
|
assert(web_server_start() == ESP_FAIL);
|
|
|
|
|
assert(registration_calls == failure && !admin_inits && !admin_attaches && !serial_attaches);
|
|
|
|
|
assert(!auth_live && !ssl_live && ssl_stops == 1 && !s_server && !s_admin_transport_owned);
|
|
|
|
|
assert(!admin_detaches && !admin_stoppeds && !s_transitioning && s_counters.start_failures == 1);
|
|
|
|
|
}
|
|
|
|
|
puts("PASS required registration positions 1..16 fail fatally before transport attachment");
|
|
|
|
|
puts("PASS required registration positions 1..17 fail fatally before transport attachment");
|
|
|
|
|
|
|
|
|
|
for (unsigned failure = 17; failure <= 18; ++failure) {
|
|
|
|
|
for (unsigned failure = 18; failure <= 19; ++failure) {
|
|
|
|
|
reset(); registration_fail_at = failure;
|
|
|
|
|
assert(web_server_start() == ESP_OK && registration_calls == failure);
|
|
|
|
|
assert(auth_live && ssl_live && serial_live && s_server == SERVER);
|
|
|
|
|
assert(s_serial_transport_attached && !s_admin_transport_owned && !admin_owned);
|
|
|
|
|
assert(!admin_inits && !admin_attaches && !auth_stops && !ssl_stops);
|
|
|
|
|
assert(!s_transitioning && s_last_error == ESP_OK && s_counters.starts == 1 && !s_counters.start_failures);
|
|
|
|
|
assert(registered_count == 37 && unregister_calls == failure - 17);
|
|
|
|
|
assert(registered_count == 38 && unregister_calls == failure - 18);
|
|
|
|
|
for (unsigned i = 0; i < registered_count; ++i)
|
|
|
|
|
assert(strcmp(registered[i]->uri, "/api/admin/ws-ticket") && strcmp(registered[i]->uri, "/ws/admin"));
|
|
|
|
|
assert(route("/ws/serial")->handler == traced_websocket_handler);
|
|
|
|
@@ -594,13 +597,13 @@ int main(void) {
|
|
|
|
|
clear_events(); assert(web_server_stop() == ESP_OK && !strcmp(events, "ASH"));
|
|
|
|
|
assert(!admin_detaches && !admin_stoppeds);
|
|
|
|
|
registration_fail_at = 0; fresh_registration(); start();
|
|
|
|
|
assert(registered_count == 39 && admin_attaches == 1 && s_counters.starts == 2);
|
|
|
|
|
assert(registered_count == 40 && admin_attaches == 1 && s_counters.starts == 2);
|
|
|
|
|
assert(web_server_stop() == ESP_OK && admin_stoppeds == 1);
|
|
|
|
|
}
|
|
|
|
|
puts("PASS optional positions 17..18 preserve M1, roll back ticket when needed and recover after stop/restart");
|
|
|
|
|
puts("PASS optional positions 18..19 preserve M1, roll back ticket when needed and recover after stop/restart");
|
|
|
|
|
|
|
|
|
|
reset(); registration_fail_at = 18; unregister_fail = true;
|
|
|
|
|
assert(web_server_start() == ESP_OK && unregister_calls == 1 && registered_count == 38);
|
|
|
|
|
reset(); registration_fail_at = 19; unregister_fail = true;
|
|
|
|
|
assert(web_server_start() == ESP_OK && unregister_calls == 1 && registered_count == 39);
|
|
|
|
|
assert(auth_live && ssl_live && serial_live && s_serial_transport_attached);
|
|
|
|
|
assert(!admin_inits && !admin_attaches && !admin_owned && !s_admin_transport_owned);
|
|
|
|
|
ticket = route("/api/admin/ws-ticket");
|
|
|
|
@@ -612,7 +615,7 @@ int main(void) {
|
|
|
|
|
clear_events(); assert(web_server_stop() == ESP_OK && !strcmp(events, "ASH"));
|
|
|
|
|
assert(!admin_detaches && !admin_stoppeds);
|
|
|
|
|
unregister_fail = false; registration_fail_at = 0; fresh_registration(); start();
|
|
|
|
|
assert(registered_count == 39 && admin_attaches == 1 && web_server_stop() == ESP_OK);
|
|
|
|
|
assert(registered_count == 40 && admin_attaches == 1 && web_server_stop() == ESP_OK);
|
|
|
|
|
puts("PASS failed unregister retains only original ticket handler, no admin attachment, and permits restart");
|
|
|
|
|
|
|
|
|
|
reset(); registration_fail_at = 6; ssl_stop_error = ESP_FAIL;
|
|
|
|
@@ -634,7 +637,7 @@ int main(void) {
|
|
|
|
|
assert(web_server_stop() == ESP_ERR_INVALID_STATE && !auth_stops);
|
|
|
|
|
puts("PASS auth/start failure gates and invalid/transitioning lifecycle rejection");
|
|
|
|
|
reset(); settings_fail = true; start();
|
|
|
|
|
assert(settings_calls == 1 && registered_count == 38);
|
|
|
|
|
assert(settings_calls == 1 && registered_count == 39);
|
|
|
|
|
assert(auth_live && serial_live && admin_owned && web_server_stop() == ESP_OK);
|
|
|
|
|
settings_fail = false; fresh_registration(); start();
|
|
|
|
|
assert(route("/api/settings/serial")->handler == serial_settings_handler);
|
|
|
|
@@ -642,7 +645,7 @@ int main(void) {
|
|
|
|
|
puts("PASS optional Settings registration failure preserves auth and both transports; restart recovers");
|
|
|
|
|
for (unsigned failure = 1; failure <= 2; ++failure) {
|
|
|
|
|
reset(); operation_fail_at = failure; start();
|
|
|
|
|
assert(registered_count == 37 && operation_calls == failure && unregister_calls == failure - 1);
|
|
|
|
|
assert(registered_count == 38 && operation_calls == failure && unregister_calls == failure - 1);
|
|
|
|
|
assert(auth_live && serial_live && admin_owned);
|
|
|
|
|
for (unsigned i = 0; i < registered_count; ++i) assert(strcmp(registered[i]->uri, "/api/settings/serial-operation"));
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
@@ -650,25 +653,27 @@ int main(void) {
|
|
|
|
|
puts("PASS optional Serial operation GET/POST failure never publishes a mutation-only route or disables transports");
|
|
|
|
|
for (unsigned failure = 1; failure <= 3; ++failure) {
|
|
|
|
|
reset(); account_calls = 0; account_fail_at = failure; start();
|
|
|
|
|
assert(account_calls == failure && registered_count == (failure == 1 ? 36 : 37));
|
|
|
|
|
assert(account_calls == failure && registered_count == (failure == 1 ? 37 : 38));
|
|
|
|
|
assert(keys_calls == 1 && route("/api/settings/accounts/keys")->handler == web_account_keys_handler);
|
|
|
|
|
assert(generation_calls == 1 && route("/api/settings/accounts/generate-password")->handler == web_account_generate_password_handler);
|
|
|
|
|
assert(route("/api/firmware")->method == HTTP_POST && route("/api/firmware")->handler == web_firmware_update_handler);
|
|
|
|
|
assert(generation_calls == 1 && route("/api/settings/accounts/generate-password")->handler == web_account_generate_password_handler);
|
|
|
|
|
assert(auth_live && serial_live && admin_owned);
|
|
|
|
|
for (unsigned i = 0; i < registered_count; ++i)
|
|
|
|
|
assert(strcmp(registered[i]->uri, "/api/settings/account-operation"));
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
account_fail_at = 0; account_calls = 0; fresh_registration(); start();
|
|
|
|
|
assert(registered_count == 39 && account_calls == 3);
|
|
|
|
|
assert(registered_count == 40 && account_calls == 3);
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
}
|
|
|
|
|
reset(); account_calls = 0; account_fail_at = 3; unregister_fail = true; start();
|
|
|
|
|
assert(registered_count == 38 && auth_live && serial_live && admin_owned);
|
|
|
|
|
assert(registered_count == 39 && auth_live && serial_live && admin_owned);
|
|
|
|
|
for (unsigned i = 0; i < registered_count; ++i)
|
|
|
|
|
assert(strcmp(registered[i]->uri, "/api/settings/account-operation") || registered[i]->method == HTTP_GET);
|
|
|
|
|
assert(web_server_stop() == ESP_OK); account_fail_at = 0;
|
|
|
|
|
puts("PASS optional Accounts list/result/mutation allocation failures preserve transports and never expose mutation without reads (including failed unregister)");
|
|
|
|
|
reset(); generation_fail = true; start();
|
|
|
|
|
assert(generation_calls == 1 && registered_count == 38 && account_calls == 3);
|
|
|
|
|
assert(route("/api/firmware")->method == HTTP_POST && route("/api/firmware")->handler == web_firmware_update_handler);
|
|
|
|
|
assert(generation_calls == 1 && registered_count == 39 && account_calls == 3);
|
|
|
|
|
assert(keys_calls == 1 && route("/api/settings/accounts/keys")->handler == web_account_keys_handler);
|
|
|
|
|
assert(!auth_stops && !ssl_stops && !unregister_calls && !s_counters.start_failures);
|
|
|
|
|
assert(route("/api/settings/accounts")->handler == web_account_settings_handler);
|
|
|
|
@@ -680,12 +685,12 @@ int main(void) {
|
|
|
|
|
}
|
|
|
|
|
assert(account_mutations == 1 && web_server_stop() == ESP_OK);
|
|
|
|
|
generation_fail = false; fresh_registration(); start();
|
|
|
|
|
assert(generation_calls == 2 && registered_count == 39);
|
|
|
|
|
assert(generation_calls == 2 && registered_count == 40);
|
|
|
|
|
assert(route("/api/settings/accounts/generate-password")->handler == web_account_generate_password_handler);
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
puts("PASS optional password generation allocation failure preserves account routes/auth/transports; restart recovers");
|
|
|
|
|
reset(); keys_fail = true; start();
|
|
|
|
|
assert(keys_calls == 1 && registered_count == 38 && account_calls == 3 && generation_calls == 1);
|
|
|
|
|
assert(keys_calls == 1 && registered_count == 39 && account_calls == 3 && generation_calls == 1);
|
|
|
|
|
assert(!auth_stops && !ssl_stops && !unregister_calls && !s_counters.start_failures);
|
|
|
|
|
assert(route("/api/settings/accounts")->handler == web_account_settings_handler);
|
|
|
|
|
assert(route("/api/settings/accounts/generate-password")->handler == web_account_generate_password_handler);
|
|
|
|
@@ -700,7 +705,7 @@ int main(void) {
|
|
|
|
|
}
|
|
|
|
|
assert(account_mutations == 1 && web_server_stop() == ESP_OK);
|
|
|
|
|
keys_fail = false; fresh_registration(); start();
|
|
|
|
|
assert(keys_calls == 2 && registered_count == 39);
|
|
|
|
|
assert(keys_calls == 2 && registered_count == 40);
|
|
|
|
|
assert(route("/api/settings/accounts/keys")->handler == web_account_keys_handler);
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
puts("PASS optional account keys allocation failure preserves account/generation/auth/transports; restart recovers");
|
|
|
|
@@ -725,7 +730,7 @@ int main(void) {
|
|
|
|
|
reset(); network_fail_at = failure; start();
|
|
|
|
|
unsigned failed_route = (failure + 1) / 2;
|
|
|
|
|
assert(network_calls == failed_route && network_allocations == failure);
|
|
|
|
|
assert(registered_count == (failed_route == 1 ? 36 : 37));
|
|
|
|
|
assert(registered_count == (failed_route == 1 ? 37 : 38));
|
|
|
|
|
assert(unregister_calls == (failed_route == 3 ? 1 : 0));
|
|
|
|
|
assert(!method_route("/api/settings/network-operation", HTTP_GET));
|
|
|
|
|
assert(!method_route("/api/settings/network-operation", HTTP_POST));
|
|
|
|
@@ -733,13 +738,13 @@ int main(void) {
|
|
|
|
|
other_domains_complete();
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
network_fail_at = 0; fresh_registration(); start();
|
|
|
|
|
assert(registered_count == 39); network_complete();
|
|
|
|
|
assert(registered_count == 40); network_complete();
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
}
|
|
|
|
|
puts("PASS all six Network descriptor/name allocation positions isolate failures and recover after restart");
|
|
|
|
|
for (unsigned failure = 5; failure <= 6; ++failure) {
|
|
|
|
|
reset(); network_fail_at = failure; unregister_fail = true; start();
|
|
|
|
|
assert(registered_count == 38 && unregister_calls == 1);
|
|
|
|
|
assert(registered_count == 39 && unregister_calls == 1);
|
|
|
|
|
assert(route("/api/settings/network")->handler == web_network_snapshot_handler);
|
|
|
|
|
assert(method_route("/api/settings/network-operation", HTTP_GET)->handler == web_network_operation_handler);
|
|
|
|
|
assert(!method_route("/api/settings/network-operation", HTTP_POST));
|
|
|
|
@@ -749,7 +754,7 @@ int main(void) {
|
|
|
|
|
assert(web_server_start() == ESP_ERR_INVALID_STATE && ssl_starts == 1);
|
|
|
|
|
ssl_stop_error = ESP_OK; assert(web_server_stop() == ESP_OK);
|
|
|
|
|
unregister_fail = false; network_fail_at = 0; fresh_registration(); start();
|
|
|
|
|
assert(registered_count == 39); network_complete();
|
|
|
|
|
assert(registered_count == 40); network_complete();
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
}
|
|
|
|
|
puts("PASS failed Network result unregister leaves reads only and preserves stop-failure ownership/restart");
|
|
|
|
@@ -757,7 +762,7 @@ int main(void) {
|
|
|
|
|
reset(); display_fail_at = failure; start();
|
|
|
|
|
unsigned failed_route = (failure + 1) / 2;
|
|
|
|
|
assert(display_calls == failed_route && display_allocations == failure);
|
|
|
|
|
assert(registered_count == (failed_route == 1 ? 36 : 37));
|
|
|
|
|
assert(registered_count == (failed_route == 1 ? 37 : 38));
|
|
|
|
|
assert(unregister_calls == (failed_route == 3 ? 1 : 0));
|
|
|
|
|
assert(!method_route("/api/settings/display-operation", HTTP_GET));
|
|
|
|
|
assert(!method_route("/api/settings/display-operation", HTTP_POST));
|
|
|
|
@@ -765,13 +770,13 @@ int main(void) {
|
|
|
|
|
other_domains_complete(); network_complete();
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
display_fail_at = 0; fresh_registration(); start();
|
|
|
|
|
assert(registered_count == 39); display_complete();
|
|
|
|
|
assert(registered_count == 40); display_complete();
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
}
|
|
|
|
|
puts("PASS all six Display descriptor/name allocation positions isolate failures and recover after restart");
|
|
|
|
|
for (unsigned failure = 5; failure <= 6; ++failure) {
|
|
|
|
|
reset(); display_fail_at = failure; unregister_fail = true; start();
|
|
|
|
|
assert(registered_count == 38 && unregister_calls == 1);
|
|
|
|
|
assert(registered_count == 39 && unregister_calls == 1);
|
|
|
|
|
assert(route("/api/settings/display")->handler == web_display_settings_handler);
|
|
|
|
|
assert(method_route("/api/settings/display-operation", HTTP_GET)->handler == web_display_operation_handler);
|
|
|
|
|
assert(!method_route("/api/settings/display-operation", HTTP_POST));
|
|
|
|
@@ -781,7 +786,7 @@ int main(void) {
|
|
|
|
|
assert(web_server_start() == ESP_ERR_INVALID_STATE && ssl_starts == 1);
|
|
|
|
|
ssl_stop_error = ESP_OK; assert(web_server_stop() == ESP_OK);
|
|
|
|
|
unregister_fail = false; display_fail_at = 0; fresh_registration(); start();
|
|
|
|
|
assert(registered_count == 39); display_complete();
|
|
|
|
|
assert(registered_count == 40); display_complete();
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
}
|
|
|
|
|
puts("PASS failed Display result unregister leaves reads only and preserves stop-failure ownership/restart");
|
|
|
|
@@ -789,7 +794,7 @@ int main(void) {
|
|
|
|
|
reset(); broker_fail_at = failure; start();
|
|
|
|
|
unsigned failed_route = (failure + 1) / 2;
|
|
|
|
|
assert(broker_calls == failed_route && broker_allocations == failure);
|
|
|
|
|
assert(registered_count == (failed_route == 1 ? 36 : 37));
|
|
|
|
|
assert(registered_count == (failed_route == 1 ? 37 : 38));
|
|
|
|
|
assert(unregister_calls == (failed_route == 3 ? 1 : 0));
|
|
|
|
|
assert(!method_route("/api/settings/broker-operation", HTTP_GET));
|
|
|
|
|
assert(!method_route("/api/settings/broker-operation", HTTP_POST));
|
|
|
|
@@ -797,13 +802,13 @@ int main(void) {
|
|
|
|
|
other_domains_complete(); network_complete(); display_complete();
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
broker_fail_at = 0; fresh_registration(); start();
|
|
|
|
|
assert(registered_count == 39); broker_complete();
|
|
|
|
|
assert(registered_count == 40); broker_complete();
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
}
|
|
|
|
|
puts("PASS all six Broker descriptor/name allocation positions isolate failures and recover after restart");
|
|
|
|
|
for (unsigned failure = 5; failure <= 6; ++failure) {
|
|
|
|
|
reset(); broker_fail_at = failure; unregister_fail = true; start();
|
|
|
|
|
assert(registered_count == 38 && unregister_calls == 1);
|
|
|
|
|
assert(registered_count == 39 && unregister_calls == 1);
|
|
|
|
|
assert(route("/api/settings/broker")->handler == web_broker_settings_handler);
|
|
|
|
|
assert(method_route("/api/settings/broker-operation", HTTP_GET)->handler == web_broker_operation_handler);
|
|
|
|
|
assert(!method_route("/api/settings/broker-operation", HTTP_POST));
|
|
|
|
@@ -813,7 +818,7 @@ int main(void) {
|
|
|
|
|
assert(web_server_start() == ESP_ERR_INVALID_STATE && ssl_starts == 1);
|
|
|
|
|
ssl_stop_error = ESP_OK; assert(web_server_stop() == ESP_OK);
|
|
|
|
|
unregister_fail = false; broker_fail_at = 0; fresh_registration(); start();
|
|
|
|
|
assert(registered_count == 39); broker_complete();
|
|
|
|
|
assert(registered_count == 40); broker_complete();
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
}
|
|
|
|
|
puts("PASS failed Broker result unregister leaves reads only and preserves stop-failure ownership/restart");
|
|
|
|
@@ -821,7 +826,7 @@ int main(void) {
|
|
|
|
|
reset(); ssh_fail_at = failure; start();
|
|
|
|
|
unsigned failed_route = (failure + 1) / 2;
|
|
|
|
|
assert(ssh_calls == failed_route && ssh_allocations == failure);
|
|
|
|
|
assert(registered_count == (failed_route == 1 ? 36 : 37));
|
|
|
|
|
assert(registered_count == (failed_route == 1 ? 37 : 38));
|
|
|
|
|
assert(unregister_calls == (failed_route == 3 ? 1 : 0));
|
|
|
|
|
assert(!method_route("/api/settings/ssh-operation", HTTP_GET));
|
|
|
|
|
assert(!method_route("/api/settings/ssh-operation", HTTP_POST));
|
|
|
|
@@ -829,13 +834,13 @@ int main(void) {
|
|
|
|
|
other_domains_complete(); network_complete(); display_complete(); broker_complete();
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
ssh_fail_at = 0; fresh_registration(); start();
|
|
|
|
|
assert(registered_count == 39); ssh_complete();
|
|
|
|
|
assert(registered_count == 40); ssh_complete();
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
}
|
|
|
|
|
puts("PASS all six SSH descriptor/name allocation positions isolate failures and recover after restart");
|
|
|
|
|
for (unsigned failure = 5; failure <= 6; ++failure) {
|
|
|
|
|
reset(); ssh_fail_at = failure; unregister_fail = true; start();
|
|
|
|
|
assert(registered_count == 38 && unregister_calls == 1);
|
|
|
|
|
assert(registered_count == 39 && unregister_calls == 1);
|
|
|
|
|
assert(route("/api/settings/ssh")->handler == web_ssh_settings_handler);
|
|
|
|
|
assert(method_route("/api/settings/ssh-operation", HTTP_GET)->handler == web_ssh_operation_handler);
|
|
|
|
|
assert(!method_route("/api/settings/ssh-operation", HTTP_POST));
|
|
|
|
@@ -845,7 +850,7 @@ int main(void) {
|
|
|
|
|
assert(web_server_start() == ESP_ERR_INVALID_STATE && ssl_starts == 1);
|
|
|
|
|
ssl_stop_error = ESP_OK; assert(web_server_stop() == ESP_OK);
|
|
|
|
|
unregister_fail = false; ssh_fail_at = 0; fresh_registration(); start();
|
|
|
|
|
assert(registered_count == 39); ssh_complete();
|
|
|
|
|
assert(registered_count == 40); ssh_complete();
|
|
|
|
|
assert(web_server_stop() == ESP_OK);
|
|
|
|
|
}
|
|
|
|
|
puts("PASS failed SSH result unregister leaves reads only and preserves stop-failure ownership/restart");
|
|
|
|
@@ -927,7 +932,7 @@ static void management_tests(void) {
|
|
|
|
|
assert(reserved_gaps == 1 && !unlock_hook && !strcmp(events, "ADSHR"));
|
|
|
|
|
assert(s_generation == original + 2 && s_server == SERVER && !s_transitioning);
|
|
|
|
|
assert(auth_live && ssl_live && admin_owned && serial_live && idle_owned);
|
|
|
|
|
assert(ssl_starts == 2 && ssl_stops == 1 && serial_inits == 1 && registered_count == 39);
|
|
|
|
|
assert(ssl_starts == 2 && ssl_stops == 1 && serial_inits == 1 && registered_count == 40);
|
|
|
|
|
assert(web_server_stop_current(original) == ESP_ERR_INVALID_STATE);
|
|
|
|
|
assert(web_server_stop_current(s_generation) == ESP_OK);
|
|
|
|
|
puts("PASS conditional restart reserves stop-to-start gap against canonical and conditional callers");
|
|
|
|
|