Skip to content

Commit 8e519e0

Browse files
committed
Merge branch 'fix/test_nvs_gen_check_read_only_part_support' into 'master'
fix: test_nvs_gen_check.py support for read-only NVS partitions Closes IDF-12238 See merge request espressif/esp-idf!36829
2 parents de05373 + 0c2cbd1 commit 8e519e0

File tree

2 files changed

+140
-30
lines changed

2 files changed

+140
-30
lines changed

components/nvs_flash/nvs_partition_tool/nvs_check.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python3
2-
# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
2+
# SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
33
# SPDX-License-Identifier: Apache-2.0
44
from typing import Dict
55
from typing import List
@@ -21,10 +21,10 @@
2121
blob_chunks: List[NVS_Entry] = []
2222

2323

24-
def check_partition_size(nvs_partition: NVS_Partition, nvs_log: NVS_Logger) -> bool:
24+
def check_partition_size(nvs_partition: NVS_Partition, nvs_log: NVS_Logger, read_only: bool=False) -> bool:
2525
""" Checks if the partition is large enough and has enough pages
2626
"""
27-
if len(nvs_partition.raw_data) / 0x1000 < 3:
27+
if len(nvs_partition.raw_data) // 0x1000 < 3 and not read_only:
2828
nvs_log.info(
2929
nvs_log.yellow(
3030
'NVS Partition size must be at least 0x3000 (4kiB * 3 pages == 12kiB)!'
@@ -38,7 +38,7 @@ def check_partition_size(nvs_partition: NVS_Partition, nvs_log: NVS_Logger) -> b
3838
)
3939
)
4040
return False
41-
if len(nvs_partition.pages) < 3:
41+
if len(nvs_partition.pages) < 3 and not read_only:
4242
nvs_log.info(
4343
nvs_log.yellow(
4444
'NVS Partition must contain 3 pages (sectors) at least to function properly!'

components/nvs_flash/nvs_partition_tool/test_nvs_gen_check.py

Lines changed: 136 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env python3
2-
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
2+
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
33
# SPDX-License-Identifier: Apache-2.0
4+
from importlib.metadata import version
45
from io import BufferedRandom
56
from io import BytesIO
67
from pathlib import Path
@@ -21,6 +22,18 @@
2122
from nvs_parser import nvs_const
2223
from nvs_parser import NVS_Entry
2324
from nvs_parser import NVS_Partition
25+
from packaging.version import Version
26+
27+
28+
NVS_PART_GEN_VERSION_SKIP = '0.1.8'
29+
30+
31+
# Temporary workaround for pytest skipping tests based on the version of the esp-idf-nvs-partition-gen package
32+
@pytest.fixture(scope='session', autouse=True)
33+
def before() -> None:
34+
ver = version('esp-idf-nvs-partition-gen')
35+
if Version(ver) < Version(NVS_PART_GEN_VERSION_SKIP):
36+
pytest.skip('pass')
2437

2538

2639
class SilentLogger(NVS_Logger):
@@ -101,7 +114,7 @@ def create_entry_data_bytearray(namespace_index: int, entry_type: int, span: int
101114

102115
@pytest.fixture
103116
def generate_nvs() -> Callable:
104-
def _execute_nvs_setup(nvs_setup_func: Callable, size: int = 0x4000, output: Optional[Path] = None) -> NVS_Partition:
117+
def _execute_nvs_setup(nvs_setup_func: Callable, output: Optional[Path] = None) -> NVS_Partition:
105118
nvs_file: Optional[Union[BytesIO, BufferedRandom]] = None
106119
if output is None:
107120
nvs_file = BytesIO()
@@ -110,15 +123,7 @@ def _execute_nvs_setup(nvs_setup_func: Callable, size: int = 0x4000, output: Opt
110123
nvs_file = open(output, 'wb+')
111124
except OSError as e:
112125
raise RuntimeError(f'Cannot open file {output}, error: {e}')
113-
size_fixed = nvs_partition_gen.check_size(str(size))
114-
nvs_obj = nvs_partition_gen.nvs_open(
115-
result_obj=nvs_file,
116-
input_size=size_fixed,
117-
version=nvs_partition_gen.Page.VERSION2,
118-
is_encrypt=False,
119-
key=None
120-
)
121-
nvs_setup_func(nvs_obj)
126+
nvs_obj = nvs_setup_func(nvs_file)
122127
nvs_partition_gen.nvs_close(nvs_obj)
123128
nvs_file.seek(0)
124129
nvs_parsed = NVS_Partition('test', bytearray(nvs_file.read()))
@@ -128,16 +133,36 @@ def _execute_nvs_setup(nvs_setup_func: Callable, size: int = 0x4000, output: Opt
128133

129134

130135
# Setup functions
131-
def setup_ok_primitive(nvs_obj: NVS) -> None:
136+
def setup_ok_primitive(nvs_file: Optional[Union[BytesIO, BufferedRandom]]) -> NVS:
137+
size_fixed, read_only = nvs_partition_gen.check_size(str(0x4000))
138+
nvs_obj = nvs_partition_gen.nvs_open(
139+
result_obj=nvs_file,
140+
input_size=size_fixed,
141+
version=nvs_partition_gen.Page.VERSION2,
142+
is_encrypt=False,
143+
key=None,
144+
read_only=read_only
145+
)
146+
132147
nvs_partition_gen.write_entry(nvs_obj, 'storage', 'namespace', '', '')
133148
nvs_partition_gen.write_entry(nvs_obj, 'int32_test', 'data', 'i32', str(42))
134149
nvs_partition_gen.write_entry(nvs_obj, 'uint32_test', 'data', 'u32', str(42))
135150
nvs_partition_gen.write_entry(nvs_obj, 'int8_test', 'data', 'i8', str(100))
136151

152+
return nvs_obj
153+
154+
155+
def setup_ok_variable_len(nvs_file: Optional[Union[BytesIO, BufferedRandom]]) -> NVS:
156+
size_fixed, read_only = nvs_partition_gen.check_size(str(0x5000))
157+
nvs_obj = nvs_partition_gen.nvs_open(
158+
result_obj=nvs_file,
159+
input_size=size_fixed,
160+
version=nvs_partition_gen.Page.VERSION2,
161+
is_encrypt=False,
162+
key=None,
163+
read_only=read_only
164+
)
137165

138-
def setup_ok_variable_len(nvs_obj: NVS) -> None:
139-
size_fixed = nvs_partition_gen.check_size(str('0x5000'))
140-
nvs_obj.size = size_fixed
141166
nvs_partition_gen.write_entry(nvs_obj, 'storage', 'namespace', '', '')
142167
nvs_partition_gen.write_entry(nvs_obj, 'short_string_key', 'data', 'string', 'Hello world!')
143168
nvs_partition_gen.write_entry(nvs_obj, 'blob_key', 'file', 'binary',
@@ -147,10 +172,20 @@ def setup_ok_variable_len(nvs_obj: NVS) -> None:
147172
nvs_partition_gen.write_entry(nvs_obj, 'multi_blob_key', 'file', 'binary',
148173
'../nvs_partition_generator/testdata/sample_multipage_blob.bin')
149174

175+
return nvs_obj
176+
177+
178+
def setup_ok_mixed(nvs_file: Optional[Union[BytesIO, BufferedRandom]]) -> NVS:
179+
size_fixed, read_only = nvs_partition_gen.check_size(str(0x6000))
180+
nvs_obj = nvs_partition_gen.nvs_open(
181+
result_obj=nvs_file,
182+
input_size=size_fixed,
183+
version=nvs_partition_gen.Page.VERSION2,
184+
is_encrypt=False,
185+
key=None,
186+
read_only=read_only
187+
)
150188

151-
def setup_ok_mixed(nvs_obj: NVS) -> None:
152-
size_fixed = nvs_partition_gen.check_size(str('0x6000'))
153-
nvs_obj.size = size_fixed
154189
prim_types = ['i8', 'u8', 'i16', 'u16', 'i32', 'u32']
155190

156191
nvs_partition_gen.write_entry(nvs_obj, 'storage', 'namespace', '', '')
@@ -173,10 +208,20 @@ def setup_ok_mixed(nvs_obj: NVS) -> None:
173208
nvs_partition_gen.write_entry(nvs_obj, 'blob_key', 'file', 'binary',
174209
'../nvs_partition_generator/testdata/sample_multipage_blob.bin')
175210

211+
return nvs_obj
212+
213+
214+
def setup_bad_mixed_same_key_different_page(nvs_file: Optional[Union[BytesIO, BufferedRandom]]) -> NVS:
215+
size_fixed, read_only = nvs_partition_gen.check_size(str(0x6000))
216+
nvs_obj = nvs_partition_gen.nvs_open(
217+
result_obj=nvs_file,
218+
input_size=size_fixed,
219+
version=nvs_partition_gen.Page.VERSION2,
220+
is_encrypt=False,
221+
key=None,
222+
read_only=read_only
223+
)
176224

177-
def setup_bad_mixed_same_key_different_page(nvs_obj: NVS) -> None:
178-
size_fixed = nvs_partition_gen.check_size(str('0x6000'))
179-
nvs_obj.size = size_fixed
180225
prim_types = ['i8', 'u8', 'i16', 'u16', 'i32', 'u32']
181226

182227
nvs_partition_gen.write_entry(nvs_obj, 'storage', 'namespace', '', '')
@@ -215,8 +260,20 @@ def setup_bad_mixed_same_key_different_page(nvs_obj: NVS) -> None:
215260
# the current used namespace index
216261
nvs_partition_gen.write_entry(nvs_obj, 'storage', 'namespace', '', '')
217262

263+
return nvs_obj
264+
265+
266+
def setup_bad_same_key_primitive(nvs_file: Optional[Union[BytesIO, BufferedRandom]]) -> NVS:
267+
size_fixed, read_only = nvs_partition_gen.check_size(str(0x4000))
268+
nvs_obj = nvs_partition_gen.nvs_open(
269+
result_obj=nvs_file,
270+
input_size=size_fixed,
271+
version=nvs_partition_gen.Page.VERSION2,
272+
is_encrypt=False,
273+
key=None,
274+
read_only=read_only
275+
)
218276

219-
def setup_bad_same_key_primitive(nvs_obj: NVS) -> None:
220277
nvs_partition_gen.write_entry(nvs_obj, 'storage', 'namespace', '', '')
221278
nvs_partition_gen.write_entry(nvs_obj, 'unique_key', 'data', 'i16', str(1234))
222279
nvs_partition_gen.write_entry(nvs_obj, 'same_key', 'data', 'i32', str(42))
@@ -225,17 +282,39 @@ def setup_bad_same_key_primitive(nvs_obj: NVS) -> None:
225282
nvs_partition_gen.write_entry(nvs_obj, 'another_same_key', 'data', 'u16', str(321))
226283
nvs_partition_gen.write_entry(nvs_obj, 'another_same_key', 'data', 'u16', str(456))
227284

285+
return nvs_obj
286+
287+
288+
def setup_bad_same_key_variable_len(nvs_file: Optional[Union[BytesIO, BufferedRandom]]) -> NVS:
289+
size_fixed, read_only = nvs_partition_gen.check_size(str(0x4000))
290+
nvs_obj = nvs_partition_gen.nvs_open(
291+
result_obj=nvs_file,
292+
input_size=size_fixed,
293+
version=nvs_partition_gen.Page.VERSION2,
294+
is_encrypt=False,
295+
key=None,
296+
read_only=read_only
297+
)
228298

229-
def setup_bad_same_key_variable_len(nvs_obj: NVS) -> None:
230299
nvs_partition_gen.write_entry(nvs_obj, 'storage', 'namespace', '', '')
231300
nvs_partition_gen.write_entry(nvs_obj, 'same_string_key', 'data', 'string', 'Hello')
232301
nvs_partition_gen.write_entry(nvs_obj, 'same_string_key', 'data', 'string', 'world!')
233302
nvs_partition_gen.write_entry(nvs_obj, 'unique_string_key', 'data', 'string', 'I am unique!')
234303

304+
return nvs_obj
305+
306+
307+
def setup_bad_same_key_blob_index(nvs_file: Optional[Union[BytesIO, BufferedRandom]]) -> NVS:
308+
size_fixed, read_only = nvs_partition_gen.check_size(str(0x6000))
309+
nvs_obj = nvs_partition_gen.nvs_open(
310+
result_obj=nvs_file,
311+
input_size=size_fixed,
312+
version=nvs_partition_gen.Page.VERSION2,
313+
is_encrypt=False,
314+
key=None,
315+
read_only=read_only
316+
)
235317

236-
def setup_bad_same_key_blob_index(nvs_obj: NVS) -> None:
237-
size_fixed = nvs_partition_gen.check_size(str('0x6000'))
238-
nvs_obj.size = size_fixed
239318
nvs_partition_gen.write_entry(nvs_obj, 'storage', 'namespace', '', '')
240319
nvs_partition_gen.write_entry(nvs_obj, 'blob_key', 'file', 'binary',
241320
'../nvs_partition_generator/testdata/sample_multipage_blob.bin')
@@ -244,6 +323,28 @@ def setup_bad_same_key_blob_index(nvs_obj: NVS) -> None:
244323
nvs_partition_gen.write_entry(nvs_obj, 'blob_key', 'file', 'binary',
245324
'../nvs_partition_generator/testdata/sample_multipage_blob.bin') # Duplicate key
246325

326+
return nvs_obj
327+
328+
329+
def setup_read_only(nvs_file: Optional[Union[BytesIO, BufferedRandom]]) -> NVS:
330+
size_fixed, read_only = nvs_partition_gen.check_size(str(0x1000))
331+
nvs_obj = nvs_partition_gen.nvs_open(
332+
result_obj=nvs_file,
333+
input_size=size_fixed,
334+
version=nvs_partition_gen.Page.VERSION2,
335+
is_encrypt=False,
336+
key=None,
337+
read_only=read_only
338+
)
339+
340+
nvs_partition_gen.write_entry(nvs_obj, 'storage', 'namespace', '', '')
341+
nvs_partition_gen.write_entry(nvs_obj, 'int32_test', 'data', 'i32', str(42))
342+
nvs_partition_gen.write_entry(nvs_obj, 'uint32_test', 'data', 'u32', str(42))
343+
nvs_partition_gen.write_entry(nvs_obj, 'int8_test', 'data', 'i8', str(100))
344+
nvs_partition_gen.write_entry(nvs_obj, 'short_string_key', 'data', 'string', 'Hello world!')
345+
346+
return nvs_obj
347+
247348

248349
# Helper functions
249350
def prepare_duplicate_list(nvs: NVS_Partition) -> Dict[str, List[NVS_Entry]]:
@@ -331,3 +432,12 @@ def test_check_duplicates_bad_same_key_blob_index(generate_nvs: Callable, setup_
331432
# however there are 2 duplicates of each blob_index and blob_data
332433
assert len(list(duplicates.values())[0]) == 6 # 6 entries with the blob_key (2x blob_index, 4x blob_data)
333434
nvs_check.integrity_check(nvs, logger)
435+
436+
437+
@pytest.mark.parametrize('setup_func', [setup_read_only])
438+
def test_check_read_only_partition(generate_nvs: Callable, setup_func: Callable) -> None:
439+
nvs = generate_nvs(setup_func)
440+
assert nvs.raw_data is not None
441+
assert len(nvs.raw_data) == 0x1000
442+
assert nvs_check.check_partition_size(nvs, logger, read_only=True)
443+
assert not nvs_check.check_empty_page_present(nvs, logger)

0 commit comments

Comments
 (0)