Skip to content

Commit 7b17bcb

Browse files
committed
tests: added more tests
1 parent 16b4e34 commit 7b17bcb

2 files changed

Lines changed: 128 additions & 22 deletions

File tree

examples/basic.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ fn main() -> Result<()> {
4141

4242
// Compile the artifact into a manifest and chunks and store it
4343
build(
44-
input_dir.as_path(),
45-
repo_dir.as_path(),
44+
&input_dir.to_path_buf(),
45+
&repo_dir.to_path_buf(),
4646
&"generic".to_string(),
4747
)?;
4848

src/lib.rs

Lines changed: 126 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,14 @@ pub struct Store {
5555
/// Any errors returned by `fs::create_dir_all` are ignored.
5656
#[cfg(feature = "encoding")]
5757
pub fn create_repo(repo_dir: &Path) -> Result<()> {
58-
if !repo_dir.exists() {
59-
let _ = fs::create_dir_all(repo_dir.join("chunks"));
60-
let _ = fs::create_dir_all(repo_dir.join("manifests"));
61-
}
62-
Ok(())
58+
return if !repo_dir.exists() {
59+
let _ = fs::create_dir_all(repo_dir.join("chunks"))?;
60+
let _ = fs::create_dir_all(repo_dir.join("manifests"))?;
61+
62+
Ok(())
63+
} else {
64+
bail!("Already exists! {}", repo_dir.display())
65+
};
6366
}
6467

6568
/// Attempts to create the Store and it's associated directories.
@@ -95,7 +98,7 @@ pub fn create_store(store: &Store) -> Result<()> {
9598

9699
/// Creates a manifest and it's associated chunks from a dir structure, and saves it into the list of artifacts
97100
#[cfg(feature = "encoding")]
98-
pub fn build(input_dir: &Path, repo_dir: &Path, artifact_name: &String) -> Result<String> {
101+
pub fn build(input_dir: &PathBuf, repo_dir: &PathBuf, artifact_name: &String) -> Result<String> {
99102
use std::os::unix::fs::PermissionsExt;
100103
use walkdir::WalkDir;
101104

@@ -256,15 +259,38 @@ fn resolve_repo_path(store: &Store, path: &String) -> Result<PathBuf> {
256259
}
257260

258261
#[cfg(feature = "decoding")]
259-
fn get_temp_file(potential: Option<u8>, dir: &Path) -> String {
262+
fn get_temp_file(potential: Option<u8>, dir: &Path) -> PathBuf {
260263
let potential = potential.unwrap_or_default();
261264

262265
let file_name = format!(".tmp_{potential}");
263266

267+
// Overflow protection, if the potential number is too high, we clear the oldest old temp file and replace it.
268+
if potential > u8::MAX - 1 {
269+
// Find the most recently modified temp file and remove it to prevent overflow
270+
if let Ok(entries) = std::fs::read_dir(dir) {
271+
let oldest_temp = entries
272+
.flatten()
273+
.filter(|f| {
274+
f.file_type().map(|ft| ft.is_file()).unwrap_or(false)
275+
&& f.file_name().to_string_lossy().starts_with(".tmp_")
276+
})
277+
.min_by_key(|f| f.metadata().and_then(|m| m.modified()).ok())
278+
.map(|f| f.path())
279+
.unwrap();
280+
281+
fs::remove_file(&oldest_temp).unwrap_or_else(|x| {
282+
panic!("Failed to remove old temp symlink: {x}");
283+
});
284+
285+
return oldest_temp;
286+
}
287+
}
288+
289+
// Check if the file already exists, if it does, increment the potential number
264290
if dir.join(&file_name).exists() {
265291
get_temp_file(Some(potential + 1), dir)
266292
} else {
267-
file_name
293+
dir.join(&file_name)
268294
}
269295
}
270296

@@ -319,11 +345,17 @@ mod tests {
319345
#[cfg(feature = "decoding")]
320346
use crate::{RepoType, Store, create_store, resolve_repo_path};
321347

348+
#[test]
349+
#[cfg(all(feature = "encoding", feature = "decoding"))]
350+
fn test_create_store() {
351+
let _ = create_test_store("basic");
352+
}
353+
322354
#[cfg(all(feature = "encoding", feature = "decoding"))]
323-
fn create_test_store() -> Store {
324-
let repo = temp_dir().join("lcas_testing_repo");
325-
let cache = temp_dir().join("lcas_testing_cache");
326-
let store_path = temp_dir().join("lcas_testing_store");
355+
fn create_test_store(test_name: &str) -> Store {
356+
let repo = temp_dir().join(format!("lcas_testing_repo_{}", test_name));
357+
let cache = temp_dir().join(format!("lcas_testing_cache_{}", test_name));
358+
let store_path = temp_dir().join(format!("lcas_testing_store_{}", test_name));
327359

328360
let _ = remove_dir_all(&repo);
329361
let _ = remove_dir_all(&cache);
@@ -343,24 +375,24 @@ mod tests {
343375

344376
#[test]
345377
#[cfg(all(feature = "encoding", feature = "decoding"))]
346-
fn store_to_cache_empty() {
347-
let store = create_test_store();
378+
fn test_store_to_cache_empty() {
379+
let store = create_test_store("store_to_cache_empty");
348380

349381
assert!(resolve_repo_path(&store, &"manifests/undefined".to_string()).is_err());
350382
}
351383

352384
#[test]
353385
#[cfg(all(feature = "encoding", feature = "decoding"))]
354-
fn create_store_when_exists_should_fail() {
355-
let store = create_test_store();
386+
fn test_create_store_when_exists_should_fail() {
387+
let store = create_test_store("create_store_when_exists_should_fail");
356388
// Try to create the store again, should error
357389
let result = create_store(&store);
358390
assert!(result.is_err());
359391
}
360392

361393
#[test]
362394
#[cfg(feature = "encoding")]
363-
fn create_repo_creates_directories() {
395+
fn test_create_repo_creates_directories() {
364396
let repo = temp_dir().join("lcas_testing_repo_dirs");
365397
let _ = remove_dir_all(&repo);
366398

@@ -370,10 +402,48 @@ mod tests {
370402
assert!(repo.join("manifests").exists());
371403
}
372404

405+
#[test]
406+
#[cfg(feature = "encoding")]
407+
fn test_create_repo_on_file() {
408+
let repo = temp_dir().join("lcas_testing_repo_file");
409+
let _ = remove_dir_all(&repo);
410+
411+
fs::write(&repo, "Testing data.").unwrap();
412+
413+
let err = create_repo(&repo).unwrap_err();
414+
assert!(err.to_string().contains("Already exists!"));
415+
}
416+
417+
#[test]
418+
#[cfg(feature = "encoding")]
419+
fn test_create_repo_on_dir() {
420+
let repo = temp_dir().join("lcas_testing_repo_dir");
421+
let _ = remove_dir_all(&repo);
422+
423+
fs::create_dir(&repo).unwrap();
424+
425+
let err = create_repo(&repo).unwrap_err();
426+
assert!(err.to_string().contains("Already exists!"));
427+
}
428+
373429
#[test]
374430
#[cfg(feature = "decoding")]
375-
fn get_temp_file_returns_unique_names() {
376-
let dir = temp_dir().join("lcas_temp_file_test");
431+
fn test_create_temp_file_overflow_test() {
432+
let dir = temp_dir().join("lcas_temp_file_overflow_test");
433+
let _ = std::fs::remove_dir_all(&dir);
434+
std::fs::create_dir_all(&dir).unwrap();
435+
436+
for _i in 0..1000 {
437+
let file_name = super::get_temp_file(None, &dir);
438+
File::create_new(&file_name).unwrap();
439+
assert!(file_name.exists());
440+
}
441+
}
442+
443+
#[test]
444+
#[cfg(feature = "decoding")]
445+
fn test_get_temp_file_returns_unique_names() {
446+
let dir = temp_dir().join("lcas_temp_file_unique_test");
377447
let _ = std::fs::create_dir_all(&dir);
378448
let file1 = super::get_temp_file(None, &dir);
379449
std::fs::File::create(dir.join(&file1)).unwrap();
@@ -384,7 +454,7 @@ mod tests {
384454

385455
#[test]
386456
#[cfg(feature = "decoding")]
387-
fn make_chunk_executable_sets_permissions() {
457+
fn test_make_chunk_executable_sets_permissions() {
388458
let dir = temp_dir().join("lcas_executable_test");
389459
let _ = fs::create_dir_all(dir.join("chunks"));
390460
let chunk_hash = "testchunk".to_string();
@@ -398,4 +468,40 @@ mod tests {
398468

399469
let _ = remove_dir_all(&dir);
400470
}
471+
472+
#[test]
473+
#[cfg(all(feature = "encoding", feature = "decoding"))]
474+
fn test_create_and_load_artifact() {
475+
use std::path::PathBuf;
476+
477+
use crate::{build, install_artifact};
478+
479+
let store = create_test_store("artifact");
480+
let input_dir = temp_dir().join("lcas_artifact_test");
481+
482+
let _ = fs::remove_dir_all(&input_dir);
483+
fs::create_dir_all(&input_dir).unwrap();
484+
fs::write(input_dir.join("file1.txt"), b"Hello, world!").unwrap();
485+
fs::write(input_dir.join("file2.txt"), b"Another file.").unwrap();
486+
487+
// Create a nested directory and files inside it
488+
let nested_dir = input_dir.join("nested");
489+
fs::create_dir(&nested_dir).unwrap();
490+
fs::write(nested_dir.join("nested1.txt"), b"Nested file 1.").unwrap();
491+
fs::write(nested_dir.join("nested2.txt"), b"Nested file 2.").unwrap();
492+
493+
// Create a deeper nested directory
494+
let deeper_nested_dir = nested_dir.join("deeper");
495+
fs::create_dir(&deeper_nested_dir).unwrap();
496+
fs::write(deeper_nested_dir.join("deepfile.txt"), b"Deep nested file.").unwrap();
497+
498+
build(
499+
&input_dir,
500+
&PathBuf::from(&store.repo_path),
501+
&"test_artifact".to_string(),
502+
)
503+
.unwrap();
504+
505+
install_artifact(&"test_artifact".to_string(), &store).unwrap();
506+
}
401507
}

0 commit comments

Comments
 (0)