Files
ESP32_Serial_Swiss_Army_Knife/tests/ssh_management/runtime.py
T

72 lines
3.8 KiB
Python

#!/usr/bin/env python3
"""Exact production stop/start/process-slot functions with retained-resource doubles."""
from pathlib import Path
import re
import subprocess
import tempfile
root=Path(__file__).resolve().parents[2]
source=(root/'src/ssh_transport.c').read_text()
def function(name):
m=re.search(r'^static [^\n]+\b'+name+r'\([^;]*?\n\{.*?^\}',source,re.M|re.S)
assert m,name
return m.group()+'\n'
fakes=r'''
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#define SSH_TRANSPORT_MAX_SESSIONS 2
#define SSH_TRANSPORT_SESSION_FREE 0
#define SSH_TRANSPORT_SESSION_CLOSING 3
#define SSH_TRANSPORT_SESSION_HANDSHAKE 1
#define SSH_TRANSPORT_SESSION_ACTIVE 2
#define ESP_OK 0
#define ESP_FAIL 1
#define ESP_ERR_TIMEOUT 2
#define ESP_ERR_INVALID_STATE 3
#define pdMS_TO_TICKS(n) (n)
typedef int esp_err_t;
typedef struct { int state; bool close_requested; } ssh_slot_t;
static ssh_slot_t s_slots[2];
static void *s_context;
static int s_listen_fd=-1, s_lock;
static unsigned depth, frees, creates;
static bool s_running, s_cleanup_pending, cleanup_fail, listener_fail;
#define taskENTER_CRITICAL(p) do { (void)(p); assert(!depth++); } while(0)
#define taskEXIT_CRITICAL(p) do { (void)(p); assert(!--depth); } while(0)
static void wolfSSH_CTX_free(void *p) { assert(!depth && p==s_context); for(unsigned i=0;i<2;++i) assert(!s_slots[i].state); ++frees; }
static void close_socket(int *fd) { assert(!depth); *fd=-1; }
static void vTaskDelay(unsigned n) { (void)n; assert(!depth); }
static void request_slot_close(ssh_slot_t *s,bool revoked) { (void)revoked; if(s->state)s->close_requested=true; }
static bool cleanup_slot(ssh_slot_t *s) { if(cleanup_fail)return false; s->state=0;return true; }
static void publish_slot(ssh_slot_t *s,size_t i) { (void)s;(void)i; }
static bool consume_external_close(ssh_slot_t *s,size_t i) { (void)s;(void)i;return false; }
static void process_handshake(ssh_slot_t *s,size_t i) { (void)s;(void)i;assert(0); }
static void process_active(ssh_slot_t *s,size_t i) { (void)s;(void)i;assert(0); }
static esp_err_t create_context(void) { assert(!s_context && !depth); ++creates;s_context=(void *)1;return ESP_OK; }
static esp_err_t create_listener(void) { if(listener_fail)return ESP_FAIL;s_listen_fd=22;return ESP_OK; }
'''
tests=r'''
int main(void) {
assert(start_runtime()==ESP_OK && creates==1);
assert(start_runtime()==ESP_ERR_INVALID_STATE && creates==1 && !frees);
s_slots[0].state=2;cleanup_fail=true;
assert(stop_runtime()==ESP_ERR_TIMEOUT && s_context && !frees && s_listen_fd==-1);
s_cleanup_pending=true;s_running=false;
assert(start_runtime()==ESP_ERR_INVALID_STATE && creates==1);
process_slots();assert(s_context && s_cleanup_pending && !frees);
cleanup_fail=false;process_slots();assert(!s_context && !s_cleanup_pending && frees==1);
process_slots();assert(frees==1);
assert(start_runtime()==ESP_OK && creates==2);assert(stop_runtime()==ESP_OK && frees==2);
listener_fail=true;assert(start_runtime()==ESP_FAIL && !s_context && frees==3 && s_listen_fd==-1);
s_slots[1].state=2;assert(start_runtime()==ESP_ERR_INVALID_STATE && creates==3);s_slots[1].state=0;
s_listen_fd=22;assert(start_runtime()==ESP_ERR_INVALID_STATE && creates==3);
puts("PASS SSH actual runtime stop failure retains context, rejects orphan overwrite, owner retires only after all slots free, failed listener frees context exactly once");
}
'''
with tempfile.TemporaryDirectory(prefix='ssh-runtime-') as directory:
out=Path(directory)
(out/'test.c').write_text(fakes+''.join(function(n) for n in ('start_runtime','stop_runtime','process_slots'))+tests)
subprocess.run(['cc','-std=c11','-Wall','-Wextra','-Werror',str(out/'test.c'),'-o',str(out/'test')],check=True,timeout=30)
subprocess.run([str(out/'test')],check=True,timeout=10)