Files
story/firmware/echoear-platform-agent/tests/device-receipt-host.cjs
T
Codex Local bf1233d5df
ci / verify (push) Canceled after 0s
feat: expand companion platform, device controls, and memoir workflows
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
2026-10-08 10:06:44 +08:00

64 lines
4.4 KiB
JavaScript

// 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;
}
`);