mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-20 15:01:58 +00:00
Align host fixtures with ESP32 metadata and OTA ownership
This commit is contained in:
@@ -9,6 +9,7 @@ import unittest
|
||||
|
||||
from test_companion_preferences_transaction import HARNESS as PREFERENCES_HARNESS
|
||||
from test_companion_preferences_transaction import esp_recovery_helpers
|
||||
from test_radio_profile_spiffs_missing import STAT_HEADER
|
||||
from test_replay_reset_integration import extract_braced
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
@@ -17,8 +18,22 @@ HARNESS = r'''
|
||||
#include <helpers/RadioProfileCLI.h>
|
||||
#include <helpers/TxtDataHelpers.h>
|
||||
#include <helpers/radiolib/RXPowerSaving.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits>
|
||||
#define constrain(value,low,high) ((value)<(low)?(low):((value)>(high)?(high):(value)))
|
||||
// The production SPIFFS metadata syscall sees the same mounted filesystem as
|
||||
// the File peripheral. The standalone header keeps this fake away from libc.
|
||||
static MemoryFS* profile_metadata_fs = nullptr;
|
||||
static bool profile_metadata_error = false;
|
||||
static unsigned profile_metadata_probes = 0;
|
||||
int stat(const char* path, struct stat* info) {
|
||||
assert(profile_metadata_fs && !strncmp(path, "/spiffs/radio_profiles", 22));
|
||||
++profile_metadata_probes;
|
||||
if (profile_metadata_error) { errno = EIO; return -1; }
|
||||
if (!profile_metadata_fs->exists(path + 7)) { errno = ENOENT; return -1; }
|
||||
info->st_mode = 0100000;
|
||||
return 0;
|
||||
}
|
||||
struct Clock : mesh::RTCClock {
|
||||
uint32_t getCurrentTime() override { return 1700000000; }
|
||||
void setCurrentTime(uint32_t) override {}
|
||||
@@ -55,6 +70,7 @@ struct MyMesh {
|
||||
_prefs.freq=909.5f; _prefs.bw=62.5f; _prefs.sf=7; _prefs.cr=5;
|
||||
_prefs.airtime_factor=1; _prefs.rx_ps_level=1; _prefs.rx_ps_preamble=16;
|
||||
_prefs.rx_ps_rx_us=3000; _prefs.rx_ps_sleep_us=4000;
|
||||
profile_metadata_fs=&profile_fs;
|
||||
_radio_profiles.begin(&profile_fs,&radio,&clock);
|
||||
assert(_radio_profiles.savePrimaryPreamble(48));
|
||||
assert(savePrefs());
|
||||
@@ -63,6 +79,7 @@ struct MyMesh {
|
||||
void bootSanitize() { @COMPANION_SANITIZE@ }
|
||||
bool handleCommand(const char*,uint32_t,char*);
|
||||
const char* command(const char* value,uint32_t timestamp=0) {
|
||||
profile_metadata_fs=&profile_fs;
|
||||
memset(reply,0,sizeof(reply));
|
||||
assert(handleCommand(value,timestamp,reply));
|
||||
assert(memchr(reply,0,sizeof(reply)));
|
||||
@@ -73,6 +90,7 @@ struct MyMesh {
|
||||
assert(store.loadPrefs(loaded,lat,lon));
|
||||
}
|
||||
uint16_t rebootPreamble() {
|
||||
profile_metadata_fs=&profile_fs;
|
||||
Radio reboot_radio;mesh::RadioProfileCLI reboot_cli;
|
||||
reboot_cli.begin(&profile_fs,&reboot_radio,&clock);
|
||||
return reboot_cli.primaryPreamble();
|
||||
@@ -181,6 +199,18 @@ int main() {
|
||||
assert(error(m.command(command)));assert(m.store.fs.files["/new_prefs"]==prefs);
|
||||
assert(m._prefs.airtime_factor==1);++checks;
|
||||
}
|
||||
{ // Unreadable metadata must protect the existing committed profile image.
|
||||
MyMesh m;
|
||||
const auto files=m.profile_fs.files;
|
||||
Radio reboot_radio;mesh::RadioProfileCLI reboot_cli;
|
||||
profile_metadata_error=true;
|
||||
reboot_cli.begin(&m.profile_fs,&reboot_radio,&m.clock);
|
||||
assert(!reboot_cli.savePrimaryPreamble(32));
|
||||
assert(m.profile_fs.files==files);
|
||||
profile_metadata_error=false;
|
||||
m.expectOriginal();++checks;
|
||||
}
|
||||
assert(profile_metadata_probes>0);
|
||||
printf("%u production primary-radio persistence scenarios passed\n",checks);
|
||||
}
|
||||
'''
|
||||
@@ -228,6 +258,13 @@ def production_primary_radio_harness():
|
||||
return harness
|
||||
|
||||
|
||||
def prepare_profile_metadata_boundary(work):
|
||||
"""Supply only the SPIFFS syscall declaration, shared with the app test."""
|
||||
work = Path(work)
|
||||
(work / 'sys').mkdir(exist_ok=True)
|
||||
(work / 'sys/stat.h').write_text(STAT_HEADER, encoding='ascii')
|
||||
|
||||
|
||||
class CompanionPrimaryRadioPersistenceTests(unittest.TestCase):
|
||||
def test_production_validation_rollback_and_dutycycle_boot(self):
|
||||
harness = production_primary_radio_harness()
|
||||
@@ -235,6 +272,7 @@ class CompanionPrimaryRadioPersistenceTests(unittest.TestCase):
|
||||
self.assertIsNotNone(compiler)
|
||||
with tempfile.TemporaryDirectory(prefix='companion-primary-radio-') as directory:
|
||||
work = Path(directory)
|
||||
prepare_profile_metadata_boundary(work)
|
||||
# Reuse the profile fixture's identity/crypto mocks and add only
|
||||
# unused JSON conversion links required by real NodePrefs adapters.
|
||||
utils = (ROOT/'test/mocks/Utils.h').read_text()
|
||||
|
||||
@@ -343,7 +343,11 @@ class CompanionUsbDefaultTest(unittest.TestCase):
|
||||
self.assertLess(loop.index("serviceUsbLoggingReplyBarrier();"), loop.index("the_mesh.loop();"))
|
||||
self.assertLess(loop.index("serviceUsbLoggingOwnership(mesh::isUsbLoggingEnabled());"), loop.index("the_mesh.loop();"))
|
||||
self.assertLess(loop.index("expireUsbBinaryStartupProbeBeforeDispatch();"), loop.index("the_mesh.loop();"))
|
||||
self.assertNotIn("COMPANION_RADIO_FULL", MAIN)
|
||||
# USB defaults apply to ordinary and Full builds. Unrelated WiFi OTA
|
||||
# ownership may legitimately use the Full profile elsewhere in main.
|
||||
for name in ("beginUsbDefaultSession", "resetUsbTerminalHostSession",
|
||||
"serviceUsbTerminalHostSessionReset", "serviceUsbAsciiSessionDefault"):
|
||||
self.assertNotIn("COMPANION_RADIO_FULL", function("static void " + name + "() {"))
|
||||
source = (ROOT / "examples/companion_radio/MyMesh.cpp").read_text()
|
||||
self.assertNotIn("mesh::setUsbLoggingEnabled(", source)
|
||||
logging_reply = source[source.index('if (strncmp(command, "set logging.output ", 19)'):
|
||||
|
||||
@@ -19,7 +19,8 @@ import unittest
|
||||
import urllib.request
|
||||
|
||||
from test_client_acl_response import production_acl_methods
|
||||
from test_companion_primary_radio_persistence import production_primary_radio_harness
|
||||
from test_companion_primary_radio_persistence import (
|
||||
prepare_profile_metadata_boundary, production_primary_radio_harness)
|
||||
from test_companion_delayed_reply_delivery import production_delayed_reply_inputs
|
||||
from test_replay_reset_integration import extract_braced
|
||||
|
||||
@@ -244,6 +245,7 @@ public:
|
||||
transaction = (ROOT / "src/helpers/ContactFileTransaction.h").read_text()
|
||||
(work / "ContactFileTransaction.h").write_text(transaction.replace(
|
||||
'#include "IdentityStore.h"', '#include <helpers/IdentityStore.h>'), encoding="ascii")
|
||||
prepare_profile_metadata_boundary(work)
|
||||
(work / "radio.cpp").write_text(harness, encoding="ascii")
|
||||
binary = work / "radio.exe"
|
||||
checked([compiler, "-std=c++17", "-Wall", "-Wextra", "-Wno-unused-function",
|
||||
|
||||
Reference in New Issue
Block a user