Files
MeshCore/test/test_esp32_contact_writer_batch.py
T

53 lines
3.5 KiB
Python

#!/usr/bin/env python3
"""Execute background502/default251 admission bounds on the real CFT."""
from pathlib import Path
import json,os,subprocess,tempfile,unittest
ROOT=Path(os.environ.get("CONTACT_WRITER_ROOT",Path(__file__).resolve().parents[1]))
HEADER=Path(os.environ.get("CONTACT_WRITER_HEADER",ROOT/"src/helpers/ContactFileTransaction.h"))
DATASTORE=Path(os.environ.get("CONTACT_WRITER_DATASTORE",ROOT/"examples/companion_radio/DataStore.cpp"))
FIXTURE=Path(__file__).resolve().parent/"fixtures/contact_writer_batch/test.cpp"
class WriterBatch(unittest.TestCase):
def run_native(self,mode,negative=None):
source=HEADER.read_text().replace('#include "IdentityStore.h"','// native supplied FILESYSTEM').replace(
'#include "PersistentStoreFormat.h"','#include <helpers/PersistentStoreFormat.h>')
if negative=="default":
anchor='while (serviceBegin() == BeginProgress::Pending) {}'
self.assertEqual(source.count(anchor),1)
source=source.replace(anchor,'while (serviceBegin(true) == BeginProgress::Pending) {}')
if negative=="large":
anchor='ESP_BACKGROUND_WRITE_BUFFER_SIZE = 502;'
self.assertEqual(source.count(anchor),1);source=source.replace(anchor,'ESP_BACKGROUND_WRITE_BUFFER_SIZE = 4096;')
# Reuse the existing immediate-full-newlib stdio model unchanged.
with tempfile.TemporaryDirectory(prefix='mesh-writer-batch-') as directory:
tmp=Path(directory);(tmp/'transaction_under_test.h').write_text(source)
binary=tmp/'fixture'
cmd=['c++','-std=c++17','-O1','-g','-Wall','-Wextra','-fsanitize=address,undefined',
'-fno-omit-frame-pointer','-DESP32_PLATFORM=1','-I',str(tmp),'-I',str(ROOT/'src'),
'-I',str(ROOT/'test/fixtures/contact_cache'),'-I',str(ROOT/'test/fixtures/contact_cache/mocks'),
str(FIXTURE),'-o',str(binary)]
compiled=subprocess.run(cmd,text=True,capture_output=True)
self.assertEqual(compiled.returncode,0,compiled.stderr)
result=subprocess.run([str(binary),mode],text=True,capture_output=True)
if negative:
self.assertNotEqual(result.returncode,0,result.stdout)
self.assertIn('largest_backend_write <= cap',result.stderr)
return
self.assertEqual(result.returncode,0,result.stdout+result.stderr)
return [json.loads(line) for line in result.stdout.splitlines()]
def test_counts_admissions_and_exact_committed_bytes(self):
rows=self.run_native('measure');self.assertEqual(len(rows),6)
for row in rows:
n=row['records'];cap=502 if row['background'] else 251
self.assertEqual(row['logical_writes'],n)
self.assertEqual(row['bytes'],n*152)
self.assertEqual(row['backend_writes'],(n*152+cap-1)//cap)
self.assertEqual(row['largest_backend_write'],cap)
self.assertEqual([(r['backend_writes']) for r in rows],[211,106,212,106,212,106])
def test_synchronous_constructor_keeps_default251(self):self.run_native('default')
def test_configure_time_selection_is_latched(self):self.run_native('configure')
def test_cancellation_tail_and_old_target(self):self.run_native('cancel')
def test_fail_closed_config_short_write_corruption_and_crash(self):self.run_native('faults')
def test_old_default_contract_regression_is_detected(self):self.run_native('default','default')
def test_4096_burst_is_detected(self):self.run_native('measure','large')
if __name__=='__main__':unittest.main()