Skip to content

Commit a99b202

Browse files
arkjedrzSaumya-R
authored andcommitted
impl: use hash file for defaults
- Require hash file for default files. - Make hash parameter non-optional. - Update tests.
1 parent e3509b0 commit a99b202

File tree

5 files changed

+151
-124
lines changed

5 files changed

+151
-124
lines changed

src/rust/rust_kvs/src/json_backend.rs

Lines changed: 102 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,11 @@ impl JsonBackend {
170170
}
171171

172172
impl KvsBackend for JsonBackend {
173-
fn load_kvs(kvs_path: &Path, hash_path: Option<&PathBuf>) -> Result<KvsMap, ErrorCode> {
173+
fn load_kvs(kvs_path: &Path, hash_path: &Path) -> Result<KvsMap, ErrorCode> {
174174
if !Self::check_extension(kvs_path, "json") {
175175
return Err(ErrorCode::KvsFileReadError);
176176
}
177-
if hash_path.is_some_and(|p| !Self::check_extension(p, "hash")) {
177+
if !Self::check_extension(hash_path, "hash") {
178178
return Err(ErrorCode::KvsHashFileReadError);
179179
}
180180

@@ -183,27 +183,25 @@ impl KvsBackend for JsonBackend {
183183
let json_value = Self::parse(&json_str)?;
184184

185185
// Perform hash check.
186-
if let Some(hash_path) = hash_path {
187-
match fs::read(hash_path) {
188-
Ok(hash_bytes) => {
189-
let hash_kvs = adler32::RollingAdler32::from_buffer(json_str.as_bytes()).hash();
190-
if hash_bytes.len() == 4 {
191-
let file_hash = u32::from_be_bytes([
192-
hash_bytes[0],
193-
hash_bytes[1],
194-
hash_bytes[2],
195-
hash_bytes[3],
196-
]);
197-
if hash_kvs != file_hash {
198-
return Err(ErrorCode::ValidationFailed);
199-
}
200-
} else {
186+
match fs::read(hash_path) {
187+
Ok(hash_bytes) => {
188+
let hash_kvs = adler32::RollingAdler32::from_buffer(json_str.as_bytes()).hash();
189+
if hash_bytes.len() == 4 {
190+
let file_hash = u32::from_be_bytes([
191+
hash_bytes[0],
192+
hash_bytes[1],
193+
hash_bytes[2],
194+
hash_bytes[3],
195+
]);
196+
if hash_kvs != file_hash {
201197
return Err(ErrorCode::ValidationFailed);
202198
}
199+
} else {
200+
return Err(ErrorCode::ValidationFailed);
203201
}
204-
Err(_) => return Err(ErrorCode::KvsHashFileReadError),
205-
};
206-
}
202+
}
203+
Err(e) => return Err(e.into()),
204+
};
207205

208206
// Cast from `JsonValue` to `KvsValue`.
209207
let kvs_value = KvsValue::from(json_value);
@@ -214,16 +212,12 @@ impl KvsBackend for JsonBackend {
214212
}
215213
}
216214

217-
fn save_kvs(
218-
kvs_map: &KvsMap,
219-
kvs_path: &Path,
220-
hash_path: Option<&PathBuf>,
221-
) -> Result<(), ErrorCode> {
215+
fn save_kvs(kvs_map: &KvsMap, kvs_path: &Path, hash_path: &Path) -> Result<(), ErrorCode> {
222216
// Validate extensions.
223217
if !Self::check_extension(kvs_path, "json") {
224218
return Err(ErrorCode::KvsFileReadError);
225219
}
226-
if hash_path.is_some_and(|p| !Self::check_extension(p, "hash")) {
220+
if !Self::check_extension(hash_path, "hash") {
227221
return Err(ErrorCode::KvsHashFileReadError);
228222
}
229223

@@ -236,10 +230,8 @@ impl KvsBackend for JsonBackend {
236230
fs::write(kvs_path, &json_str)?;
237231

238232
// Generate hash and save to hash file.
239-
if let Some(hash_path) = hash_path {
240-
let hash = adler32::RollingAdler32::from_buffer(json_str.as_bytes()).hash();
241-
fs::write(hash_path, hash.to_be_bytes())?
242-
}
233+
let hash = adler32::RollingAdler32::from_buffer(json_str.as_bytes()).hash();
234+
fs::write(hash_path, hash.to_be_bytes())?;
243235

244236
Ok(())
245237
}
@@ -278,6 +270,14 @@ impl KvsPathResolver for JsonBackend {
278270
fn defaults_file_path(working_dir: &Path, instance_id: InstanceId) -> PathBuf {
279271
working_dir.join(Self::defaults_file_name(instance_id))
280272
}
273+
274+
fn defaults_hash_file_name(instance_id: InstanceId) -> String {
275+
format!("kvs_{instance_id}_default.hash")
276+
}
277+
278+
fn defaults_hash_file_path(working_dir: &Path, instance_id: InstanceId) -> PathBuf {
279+
working_dir.join(Self::defaults_hash_file_name(instance_id))
280+
}
281281
}
282282

283283
#[cfg(test)]
@@ -736,95 +736,94 @@ mod backend_tests {
736736
]);
737737
let kvs_path = working_dir.join("kvs.json");
738738
let hash_path = working_dir.join("kvs.hash");
739-
JsonBackend::save_kvs(&kvs_map, &kvs_path, Some(&hash_path)).unwrap();
739+
JsonBackend::save_kvs(&kvs_map, &kvs_path, &hash_path).unwrap();
740740
(kvs_path, hash_path)
741741
}
742742

743743
#[test]
744744
fn test_load_kvs_ok() {
745745
let dir = tempdir().unwrap();
746746
let dir_path = dir.path().to_path_buf();
747-
let (kvs_path, _hash_path) = create_kvs_files(&dir_path);
747+
let (kvs_path, hash_path) = create_kvs_files(&dir_path);
748748

749-
let kvs_map = JsonBackend::load_kvs(&kvs_path, None).unwrap();
749+
let kvs_map = JsonBackend::load_kvs(&kvs_path, &hash_path).unwrap();
750750
assert_eq!(kvs_map.len(), 3);
751751
}
752752

753753
#[test]
754-
fn test_load_kvs_not_found() {
754+
fn test_load_kvs_kvs_not_found() {
755755
let dir = tempdir().unwrap();
756756
let dir_path = dir.path().to_path_buf();
757-
let kvs_path = dir_path.join("kvs.json");
757+
let (kvs_path, hash_path) = create_kvs_files(&dir_path);
758+
std::fs::remove_file(&kvs_path).unwrap();
758759

759-
assert!(JsonBackend::load_kvs(&kvs_path, None).is_err_and(|e| e == ErrorCode::FileNotFound));
760+
assert!(JsonBackend::load_kvs(&kvs_path, &hash_path)
761+
.is_err_and(|e| e == ErrorCode::FileNotFound));
760762
}
761763

762764
#[test]
763-
fn test_load_kvs_invalid_extension() {
765+
fn test_load_kvs_kvs_invalid_extension() {
764766
let dir = tempdir().unwrap();
765767
let dir_path = dir.path().to_path_buf();
766768
let kvs_path = dir_path.join("kvs.invalid_ext");
769+
let hash_path = dir_path.join("kvs.hash");
767770

768-
assert!(
769-
JsonBackend::load_kvs(&kvs_path, None).is_err_and(|e| e == ErrorCode::KvsFileReadError)
770-
);
771+
assert!(JsonBackend::load_kvs(&kvs_path, &hash_path)
772+
.is_err_and(|e| e == ErrorCode::KvsFileReadError));
771773
}
772774

773775
#[test]
774-
fn test_load_kvs_malformed_json() {
776+
fn test_load_kvs_hash_not_found() {
775777
let dir = tempdir().unwrap();
776778
let dir_path = dir.path().to_path_buf();
777-
let kvs_path = dir_path.join("kvs.json");
778-
std::fs::write(kvs_path.clone(), "{\"malformed_json\"}").unwrap();
779+
let (kvs_path, hash_path) = create_kvs_files(&dir_path);
780+
std::fs::remove_file(&hash_path).unwrap();
779781

780-
assert!(
781-
JsonBackend::load_kvs(&kvs_path, None).is_err_and(|e| e == ErrorCode::JsonParserError)
782-
);
782+
assert!(JsonBackend::load_kvs(&kvs_path, &hash_path)
783+
.is_err_and(|e| e == ErrorCode::FileNotFound));
783784
}
784785

785786
#[test]
786-
fn test_load_kvs_invalid_data() {
787+
fn test_load_kvs_hash_invalid_extension() {
787788
let dir = tempdir().unwrap();
788789
let dir_path = dir.path().to_path_buf();
789790
let kvs_path = dir_path.join("kvs.json");
790-
std::fs::write(kvs_path.clone(), "[123.4, 567.8]").unwrap();
791+
let hash_path = dir_path.join("kvs.invalid_ext");
791792

792-
assert!(
793-
JsonBackend::load_kvs(&kvs_path, None).is_err_and(|e| e == ErrorCode::JsonParserError)
794-
);
793+
assert!(JsonBackend::load_kvs(&kvs_path, &hash_path)
794+
.is_err_and(|e| e == ErrorCode::KvsHashFileReadError));
795795
}
796796

797797
#[test]
798-
fn test_load_kvs_hash_path_some_ok() {
798+
fn test_load_kvs_malformed_json() {
799799
let dir = tempdir().unwrap();
800800
let dir_path = dir.path().to_path_buf();
801-
let (kvs_path, hash_path) = create_kvs_files(&dir_path);
802-
803-
let kvs_map = JsonBackend::load_kvs(&kvs_path, Some(&hash_path)).unwrap();
804-
assert_eq!(kvs_map.len(), 3);
805-
}
801+
let kvs_path = dir_path.join("kvs.json");
802+
let hash_path = dir_path.join("kvs.hash");
806803

807-
#[test]
808-
fn test_load_kvs_hash_path_some_invalid_extension() {
809-
let dir = tempdir().unwrap();
810-
let dir_path = dir.path().to_path_buf();
811-
let (kvs_path, hash_path) = create_kvs_files(&dir_path);
812-
let new_hash_path = hash_path.with_extension("invalid_ext");
813-
std::fs::rename(hash_path, new_hash_path.clone()).unwrap();
804+
let contents = "{\"malformed_json\"}";
805+
let hash = adler32::RollingAdler32::from_buffer(contents.as_bytes()).hash();
806+
std::fs::write(kvs_path.clone(), contents).unwrap();
807+
std::fs::write(hash_path.clone(), hash.to_be_bytes()).unwrap();
814808

815-
assert!(JsonBackend::load_kvs(&kvs_path, Some(&new_hash_path))
816-
.is_err_and(|e| e == ErrorCode::KvsHashFileReadError));
809+
assert!(JsonBackend::load_kvs(&kvs_path, &hash_path)
810+
.is_err_and(|e| e == ErrorCode::JsonParserError));
817811
}
818812

819813
#[test]
820-
fn test_load_kvs_hash_path_some_not_found() {
814+
fn test_load_kvs_invalid_data() {
821815
let dir = tempdir().unwrap();
822816
let dir_path = dir.path().to_path_buf();
823-
let (kvs_path, hash_path) = create_kvs_files(&dir_path);
824-
std::fs::remove_file(hash_path.clone()).unwrap();
817+
let kvs_path = dir_path.join("kvs.json");
818+
let hash_path = dir_path.join("kvs.hash");
825819

826-
assert!(JsonBackend::load_kvs(&kvs_path, Some(&hash_path))
827-
.is_err_and(|e| e == ErrorCode::KvsHashFileReadError));
820+
let contents = "[123.4, 567.8]";
821+
let hash = adler32::RollingAdler32::from_buffer(contents.as_bytes()).hash();
822+
std::fs::write(kvs_path.clone(), contents).unwrap();
823+
std::fs::write(hash_path.clone(), hash.to_be_bytes()).unwrap();
824+
825+
assert!(JsonBackend::load_kvs(&kvs_path, &hash_path)
826+
.is_err_and(|e| e == ErrorCode::JsonParserError));
828827
}
829828

830829
#[test]
@@ -834,7 +833,7 @@ mod backend_tests {
834833
let (kvs_path, hash_path) = create_kvs_files(&dir_path);
835834
std::fs::write(hash_path.clone(), vec![0x12, 0x34, 0x56, 0x78]).unwrap();
836835

837-
assert!(JsonBackend::load_kvs(&kvs_path, Some(&hash_path))
836+
assert!(JsonBackend::load_kvs(&kvs_path, &hash_path)
838837
.is_err_and(|e| e == ErrorCode::ValidationFailed));
839838
}
840839

@@ -845,7 +844,7 @@ mod backend_tests {
845844
let (kvs_path, hash_path) = create_kvs_files(&dir_path);
846845
std::fs::write(hash_path.clone(), vec![0x12, 0x34, 0x56]).unwrap();
847846

848-
assert!(JsonBackend::load_kvs(&kvs_path, Some(&hash_path))
847+
assert!(JsonBackend::load_kvs(&kvs_path, &hash_path)
849848
.is_err_and(|e| e == ErrorCode::ValidationFailed));
850849
}
851850

@@ -860,49 +859,35 @@ mod backend_tests {
860859
("k3".to_string(), KvsValue::from(123.4)),
861860
]);
862861
let kvs_path = dir_path.join("kvs.json");
863-
JsonBackend::save_kvs(&kvs_map, &kvs_path, None).unwrap();
862+
let hash_path = dir_path.join("kvs.hash");
863+
JsonBackend::save_kvs(&kvs_map, &kvs_path, &hash_path).unwrap();
864864

865865
assert!(kvs_path.exists());
866866
}
867867

868868
#[test]
869-
fn test_save_kvs_invalid_extension() {
869+
fn test_save_kvs_kvs_invalid_extension() {
870870
let dir = tempdir().unwrap();
871871
let dir_path = dir.path().to_path_buf();
872872

873873
let kvs_map = KvsMap::new();
874874
let kvs_path = dir_path.join("kvs.invalid_ext");
875-
assert!(JsonBackend::save_kvs(&kvs_map, &kvs_path, None)
876-
.is_err_and(|e| e == ErrorCode::KvsFileReadError));
877-
}
878-
879-
#[test]
880-
fn test_save_kvs_hash_path_some_ok() {
881-
let dir = tempdir().unwrap();
882-
let dir_path = dir.path().to_path_buf();
883-
884-
let kvs_map = KvsMap::from([
885-
("k1".to_string(), KvsValue::from("v1")),
886-
("k2".to_string(), KvsValue::from(true)),
887-
("k3".to_string(), KvsValue::from(123.4)),
888-
]);
889-
let kvs_path = dir_path.join("kvs.json");
890875
let hash_path = dir_path.join("kvs.hash");
891-
JsonBackend::save_kvs(&kvs_map, &kvs_path, Some(&hash_path)).unwrap();
892876

893-
assert!(kvs_path.exists());
894-
assert!(hash_path.exists());
877+
assert!(JsonBackend::save_kvs(&kvs_map, &kvs_path, &hash_path)
878+
.is_err_and(|e| e == ErrorCode::KvsFileReadError));
895879
}
896880

897881
#[test]
898-
fn test_save_kvs_hash_path_some_invalid_extension() {
882+
fn test_save_kvs_hash_invalid_extension() {
899883
let dir = tempdir().unwrap();
900884
let dir_path = dir.path().to_path_buf();
901885

902886
let kvs_map = KvsMap::new();
903887
let kvs_path = dir_path.join("kvs.json");
904888
let hash_path = dir_path.join("kvs.invalid_ext");
905-
assert!(JsonBackend::save_kvs(&kvs_map, &kvs_path, Some(&hash_path))
889+
890+
assert!(JsonBackend::save_kvs(&kvs_map, &kvs_path, &hash_path)
906891
.is_err_and(|e| e == ErrorCode::KvsHashFileReadError));
907892
}
908893

@@ -913,7 +898,9 @@ mod backend_tests {
913898

914899
let kvs_map = KvsMap::from([("inf".to_string(), KvsValue::from(f64::INFINITY))]);
915900
let kvs_path = dir_path.join("kvs.json");
916-
assert!(JsonBackend::save_kvs(&kvs_map, &kvs_path, None)
901+
let hash_path = dir_path.join("kvs.hash");
902+
903+
assert!(JsonBackend::save_kvs(&kvs_map, &kvs_path, &hash_path)
917904
.is_err_and(|e| e == ErrorCode::JsonGeneratorError));
918905
}
919906
}
@@ -984,4 +971,23 @@ mod path_resolver_tests {
984971
let act_name = JsonBackend::defaults_file_path(dir_path, instance_id);
985972
assert_eq!(exp_name, act_name);
986973
}
974+
975+
#[test]
976+
fn test_defaults_hash_file_name() {
977+
let instance_id = InstanceId(123);
978+
let exp_name = format!("kvs_{instance_id}_default.hash");
979+
let act_name = JsonBackend::defaults_hash_file_name(instance_id);
980+
assert_eq!(exp_name, act_name);
981+
}
982+
983+
#[test]
984+
fn test_defaults_hash_file_path() {
985+
let dir = tempdir().unwrap();
986+
let dir_path = dir.path();
987+
988+
let instance_id = InstanceId(123);
989+
let exp_name = dir_path.join(format!("kvs_{instance_id}_default.hash"));
990+
let act_name = JsonBackend::defaults_hash_file_path(dir_path, instance_id);
991+
assert_eq!(exp_name, act_name);
992+
}
987993
}

0 commit comments

Comments
 (0)