1616import hashlib
1717
1818
19- pytestmark = pytest .mark .parametrize ("version" , ["rust" , " cpp" ], scope = "class" )
19+ pytestmark = pytest .mark .parametrize ("version" , ["cpp" ], scope = "class" )
2020
2121# Type tag and value pair.
2222TaggedValue = tuple [str , Any ]
@@ -43,7 +43,7 @@ def create_defaults_file(
4343
4444 """
4545 # Path to expected defaults file.
46- # E.g., `/tmp/xyz/kvs_0_default.json`.
46+
4747 defaults_file_path = dir_path / f"kvs_{ instance_id } _default.json"
4848
4949 # Create JSON string containing default values.
@@ -53,15 +53,25 @@ def create_defaults_file(
5353 with open (defaults_file_path , mode = "w" , encoding = "UTF-8" ) as file :
5454 file .write (json_str )
5555
56- # Hash the actual file contents ( as C++ would)
56+ # TODO : Remove once the issue for C++ is resolved. Create a hash file for the malformed JSON, as C++ expects it to exist
5757 hash_file_path = dir_path / f"kvs_{ instance_id } _default.hash"
5858 with open (defaults_file_path , "rb" ) as f :
5959 file_bytes = f .read ()
60- hash_value = hashlib .sha256 (file_bytes ).hexdigest ()
61- with open (hash_file_path , mode = "w" , encoding = "UTF-8" ) as hash_file :
62- #hash_file.write(hash_value)
63- hash_file .write (hash_value )
64-
60+ # Adler32 implementation
61+ def adler32 (data : bytes ) -> int :
62+ MOD_ADLER = 65521
63+ a = 1
64+ b = 0
65+ for byte in data :
66+ a = (a + byte ) % MOD_ADLER
67+ b = (b + a ) % MOD_ADLER
68+ return (b << 16 ) | a
69+
70+ adler_hash = adler32 (file_bytes )
71+ # Write as 4 bytes, big-endian
72+ with open (hash_file_path , "wb" ) as hash_file :
73+ hash_file .write (adler_hash .to_bytes (4 , byteorder = "big" ))
74+ # Above section to be removed once C++ issue is resolved
6575 return defaults_file_path
6676
6777
@@ -70,8 +80,6 @@ class DefaultValuesScenario(CommonScenario):
7080 """
7181 Common base implementation for default values tests.
7282 """
73-
74-
7583 def instance_id (self ) -> int :
7684 return 1
7785
@@ -113,6 +121,9 @@ def temp_dir(
113121@pytest .mark .DerivationTechnique ("requirements-based" )
114122@pytest .mark .parametrize ("defaults" , ["optional" , "required" , "without" ], scope = "class" )
115123class TestDefaultValues (DefaultValuesScenario ):
124+ # Test Case: TestDefaultValues
125+ # Description: Verifies loading, querying, and override behavior for KVS instances with and without defaults.
126+ # Expected Results: When defaults file is present, values are loaded and overridden correctly. When absent, queries return KeyNotFound.
116127 KEY = "test_number"
117128 VALUE = 111.1
118129
@@ -194,6 +205,9 @@ def test_valid(
194205@pytest .mark .DerivationTechnique ("requirements-based" )
195206@pytest .mark .parametrize ("defaults" , ["optional" , "required" , "without" ], scope = "class" )
196207class TestRemoveKey (DefaultValuesScenario ):
208+ # Test Case: TestRemoveKey
209+ # Description: Tests removal of values in KVS with defaults enabled, ensuring keys revert to their default values.
210+ # Expected Results: After removing a key, its value reverts to the default if defaults file is present; otherwise, KeyNotFound is returned.
197211 KEY = "test_number"
198212 VALUE = 111.1
199213
@@ -220,7 +234,8 @@ def defaults_file(self, temp_dir: Path, defaults: str) -> Path | None:
220234 assert defaults in ("optional" , "required" , "without" )
221235 if defaults == "without" :
222236 return None
223-
237+ # Defensive: ensure temp_dir exists
238+ temp_dir .mkdir (parents = True , exist_ok = True )
224239 return create_defaults_file (
225240 temp_dir , self .instance_id (), {self .KEY : ("f64" , self .VALUE )}
226241 )
@@ -280,6 +295,9 @@ def test_valid(
280295@pytest .mark .DerivationTechnique ("requirements-based" )
281296@pytest .mark .parametrize ("defaults" , ["optional" , "required" ], scope = "class" )
282297class TestMalformedDefaultsFile (DefaultValuesScenario ):
298+ # Test Case: TestMalformedDefaultsFile
299+ # Description: Verifies that KVS fails to open when the defaults file contains invalid (malformed) JSON.
300+ # Expected Results: KVS should panic and return a JsonParserError in stderr; test expects failure and error message.
283301 @pytest .fixture (scope = "class" )
284302 def scenario_name (self ) -> str :
285303 return "cit.default_values.default_values"
@@ -310,6 +328,23 @@ def defaults_file(self, temp_dir: Path, defaults: str) -> Path | None:
310328 with open (defaults_file_path , mode = "w" , encoding = "UTF-8" ) as file :
311329 file .write (json_str )
312330
331+ # TODO : Remove once the issue for C++ is resolved. Create a hash file for the malformed JSON, as C++ expects it to exist
332+ hash_file_path = temp_dir / f"kvs_{ self .instance_id ()} _default.hash"
333+ def adler32 (data : bytes ) -> int :
334+ MOD_ADLER = 65521
335+ a = 1
336+ b = 0
337+ for byte in data :
338+ a = (a + byte ) % MOD_ADLER
339+ b = (b + a ) % MOD_ADLER
340+ return (b << 16 ) | a
341+
342+ with open (defaults_file_path , "rb" ) as f :
343+ file_bytes = f .read ()
344+ adler_hash = adler32 (file_bytes )
345+ with open (hash_file_path , "wb" ) as hash_file :
346+ hash_file .write (adler_hash .to_bytes (4 , byteorder = "big" ))
347+ # Above section to be removed once C++ issue is resolved
313348 return defaults_file_path
314349
315350 def test_invalid (
@@ -339,6 +374,9 @@ def test_invalid(
339374@pytest .mark .DerivationTechnique ("requirements-based" )
340375@pytest .mark .parametrize ("defaults" , ["required" ], scope = "class" )
341376class TestMissingDefaultsFile (DefaultValuesScenario ):
377+ # Test Case: TestMissingDefaultsFile
378+ # Description: Verifies that KVS fails to open when the required defaults file is missing.
379+ # Expected Results: KVS should panic and return a KvsFileReadError in stderr; test expects failure and error message.
342380 @pytest .fixture (scope = "class" )
343381 def scenario_name (self ) -> str :
344382 return "cit.default_values.default_values"
@@ -378,6 +416,9 @@ def test_invalid(self, results: ScenarioResult) -> None:
378416@pytest .mark .DerivationTechnique ("requirements-based" )
379417@pytest .mark .parametrize ("defaults" , ["optional" , "required" ], scope = "class" )
380418class TestResetAllKeys (DefaultValuesScenario ):
419+ # Test Case: TestResetAllKeys
420+ # Description: Checks that resetting KVS restores all keys to their default values as specified in the defaults file.
421+ # Expected Results: After reset, all keys should have their default values restored.
381422 NUM_VALUES = 5
382423
383424 @pytest .fixture (scope = "class" )
@@ -401,7 +442,8 @@ def defaults_file(self, temp_dir: Path, defaults: str) -> Path | None:
401442 values = {}
402443 for i in range (self .NUM_VALUES ):
403444 values [f"test_number_{ i } " ] = ("f64" , 432.1 * i )
404-
445+ # Defensive: ensure temp_dir exists
446+ temp_dir .mkdir (parents = True , exist_ok = True )
405447 return create_defaults_file (temp_dir , self .instance_id (), values )
406448
407449 def test_valid (
@@ -443,6 +485,9 @@ def test_valid(
443485@pytest .mark .DerivationTechnique ("requirements-based" )
444486@pytest .mark .parametrize ("defaults" , ["optional" , "required" ], scope = "class" )
445487class TestResetSingleKey (DefaultValuesScenario ):
488+ # Test Case: TestResetSingleKey
489+ # Description: Checks that resetting a single key restores it to its default value as specified in the defaults file.
490+ # Expected Results: Only the reset key should revert to its default value; other keys retain their current values.
446491 NUM_VALUES = 5
447492 RESET_INDEX = 2
448493
@@ -467,7 +512,8 @@ def defaults_file(self, temp_dir: Path, defaults: str) -> Path | None:
467512 values = {}
468513 for i in range (self .NUM_VALUES ):
469514 values [f"test_number_{ i } " ] = ("f64" , 432.1 * i )
470-
515+ # Defensive: ensure temp_dir exists
516+ temp_dir .mkdir (parents = True , exist_ok = True )
471517 return create_defaults_file (temp_dir , self .instance_id (), values )
472518
473519 def test_valid (
@@ -523,6 +569,9 @@ def test_valid(
523569@pytest .mark .DerivationTechnique ("requirements-based" )
524570@pytest .mark .parametrize ("defaults" , ["optional" , "required" ], scope = "class" )
525571class TestChecksumOnProvidedDefaults (DefaultValuesScenario ):
572+ # Test Case: TestChecksumOnProvidedDefaults
573+ # Description: Ensures that a checksum (hash) file is created when opening KVS with defaults provided.
574+ # Expected Results: Both the defaults JSON and its corresponding hash file should exist after KVS initialization.
526575 KEY = "test_number"
527576 VALUE = 111.1
528577
@@ -545,7 +594,8 @@ def defaults_file(self, temp_dir: Path, defaults: str) -> Path | None:
545594 assert defaults in ("optional" , "required" , "without" )
546595 if defaults == "without" :
547596 return None
548-
597+ # Defensive: ensure temp_dir exists
598+ temp_dir .mkdir (parents = True , exist_ok = True )
549599 return create_defaults_file (
550600 temp_dir , self .instance_id (), {self .KEY : ("f64" , self .VALUE )}
551601 )
0 commit comments