Files

64 lines
4.4 KiB
JavaScript
Raw Permalink Normal View History

// Production durable command receipts with NVS and lost-response injection.
const fs=require('fs'),path=require('path');
const source=fs.readFileSync(path.join(__dirname,'../main/device_control.c'),'utf8');
const json=path.join(process.env.IDF_PATH||'E:/Codex/toolchains/esp-idf-v5.5.1','components/json/cJSON');
const receipts=source.slice(source.indexOf('static esp_err_t save_result('),source.indexOf('static esp_err_t apply_config('));
process.stdout.write(fs.readFileSync(path.join(json,'cJSON.h'),'utf8')+'\n'+fs.readFileSync(path.join(json,'cJSON.c'),'utf8').replace('#include "cJSON.h"','')+`
#include <assert.h>
#include <stdbool.h>
typedef int esp_err_t;
typedef int nvs_handle_t;
#define ESP_OK 0
#define ESP_FAIL -1
#define ESP_ERR_NO_MEM -2
#define ESP_ERR_NVS_NOT_FOUND 1
#define NVS_READONLY 0
#define NVS_READWRITE 1
static bool namespace_exists;
static char durable[4096],staged[4096];
static int open_error,size_error,read_error,commit_error,write_error,posts,network_error;
static const char *boot_id="boot-A",*error_code="";
static const char *id="40000000-0000-4000-8000-000000000001";
static int nvs_open(const char *ns,int mode,nvs_handle_t *n){
assert(!strcmp(ns,"control"));if(open_error)return ESP_FAIL;
if(!namespace_exists&&mode==NVS_READONLY)return ESP_ERR_NVS_NOT_FOUND;
namespace_exists=true;strcpy(staged,durable);*n=1;return ESP_OK;
}
static int nvs_set_str(int n,const char *key,const char *value){assert(!strcmp(key,"result"));if(write_error)return ESP_FAIL;assert(strlen(value)<sizeof(staged));strcpy(staged,value);return ESP_OK;}
static int nvs_erase_key(int n,const char *key){assert(!strcmp(key,"result"));if(write_error)return ESP_FAIL;staged[0]=0;return ESP_OK;}
static int nvs_commit(int n){if(commit_error)return ESP_FAIL;strcpy(durable,staged);return ESP_OK;}
static int nvs_get_str(int n,const char *key,char *out,size_t *size){
assert(!strcmp(key,"result"));if(!durable[0])return ESP_ERR_NVS_NOT_FOUND;
if(!out){if(size_error)return ESP_FAIL;*size=strlen(durable)+1;return ESP_OK;}
if(read_error)return ESP_FAIL;assert(*size>=strlen(durable)+1);strcpy(out,durable);*size=strlen(durable)+1;return ESP_OK;
}
static void nvs_close(int n){}
static const char *ble_cloud_boot_id(void){return boot_id;}
static const char *platform_last_error_code(void){return error_code;}
static const char *text(const cJSON *j,const char *k){const cJSON *v=cJSON_GetObjectItemCaseSensitive(j,k);return cJSON_IsString(v)?v->valuestring:"";}
static int post(const char *path,cJSON *j,cJSON **out){
assert(!strcmp(path,"/api/v1/device/control/ack"));assert(!strcmp(text(j,"command_id"),id));
assert(!cJSON_GetObjectItemCaseSensitive(j,"_reboot_from"));posts++;return network_error?ESP_FAIL:ESP_OK;
}
`+receipts+`
static void reset(void){namespace_exists=false;durable[0]=staged[0]=0;open_error=size_error=read_error=commit_error=write_error=posts=network_error=0;boot_id="boot-A";error_code="";}
static void pending(void){assert(ack(id,"SUCCEEDED",NULL,true)==ESP_OK);assert(durable[0]&&posts==0);}
int main(int argc,char **argv){
reset();assert(flush_result());
// Unknown storage state must block command fetching, never mean no receipt.
if(argc>1&&!strcmp(argv[1],"open-error")){open_error=1;assert(!flush_result());puts("PASS NVS read failure blocks commands");return 0;}
reset();pending();assert(!flush_result()&&posts==0);
boot_id="boot-B";network_error=1;assert(!flush_result()&&durable[0]&&posts==1);
// A lost ACK response and a failed local erase both retain the same receipt.
network_error=0;commit_error=1;assert(!flush_result()&&durable[0]&&posts==2);
commit_error=0;assert(flush_result()&&!durable[0]&&posts==3);assert(flush_result()&&posts==3);
for(int fault=0;fault<3;fault++){reset();pending();boot_id="boot-B";if(fault==0)open_error=1;if(fault==1)size_error=1;if(fault==2)read_error=1;assert(!flush_result()&&posts==0&&durable[0]);}
reset();namespace_exists=true;strcpy(durable,"not JSON");assert(!flush_result()&&posts==0);
reset();write_error=1;assert(ack(id,"SUCCEEDED",NULL,true)!=ESP_OK&&posts==0&&!durable[0]);
reset();commit_error=1;assert(ack(id,"SUCCEEDED",NULL,true)!=ESP_OK&&posts==0&&!durable[0]);
reset();pending();boot_id="boot-B";network_error=1;error_code="DEVICE_COMMAND_STATE_CONFLICT";assert(flush_result()&&!durable[0]);
reset();network_error=1;assert(ack(id,"SUCCEEDED",NULL,false)==ESP_OK&&durable[0]);network_error=0;assert(flush_result()&&!durable[0]);
puts("PASS production receipts: boot guard, lost responses, durable retries and NVS failures");return 0;
}
`);