#[cfg(feature = "grid_fs")]
#[cfg(test)]
mod tests {
use crate::{grid_fs::GridFs, test_db::test_error::TestError, test_error, tests::test_util::*};
use futures_util::{io::Cursor, AsyncReadExt, AsyncWriteExt};
use mongodb::{bson::doc, options::GridFsUploadOptions};
use tokio::fs::{read, File};
use tokio_util::compat::*;
async fn load_file_data(path: &str) -> Result<(File, Vec<u8>), Box<dyn std::error::Error>> {
Ok((File::open(path).await?, read(path).await?))
}
async fn upload_revised_shark_data(
grid_fs: &GridFs,
) -> Result<(usize, Vec<u8>, Vec<u8>, Vec<u8>, Vec<u8>), Box<dyn std::error::Error>> {
let (file_revision_0, file_revision_0_data) =
load_file_data("./test_data/shark-0.png").await?;
let (file_revision_1, file_revision_1_data) =
load_file_data("./test_data/shark-1.jpg").await?;
let (file_revision_2, file_revision_2_data) =
load_file_data("./test_data/shark-2.jpg").await?;
let (file_revision_3, file_revision_3_data) =
load_file_data("./test_data/shark-3.jpg").await?;
let expected_total_bytes = file_revision_0_data.len()
+ file_revision_1_data.len()
+ file_revision_2_data.len()
+ file_revision_3_data.len();
grid_fs
.upload(
"shark",
file_revision_0.compat(),
Some(
GridFsUploadOptions::builder()
.metadata(Some(doc! { "id": 1 }))
.build(),
),
)
.await?;
grid_fs
.upload(
"shark",
file_revision_1.compat(),
Some(
GridFsUploadOptions::builder()
.metadata(Some(doc! { "id": 2 }))
.build(),
),
)
.await?;
grid_fs
.upload(
"shark",
file_revision_2.compat(),
Some(
GridFsUploadOptions::builder()
.metadata(Some(doc! { "id": 3 }))
.build(),
),
)
.await?;
grid_fs
.upload(
"shark",
file_revision_3.compat(),
Some(
GridFsUploadOptions::builder()
.metadata(Some(doc! { "id": 4 }))
.build(),
),
)
.await?;
Ok((
expected_total_bytes,
file_revision_0_data,
file_revision_1_data,
file_revision_2_data,
file_revision_3_data,
))
}
fn assert_upload_download_data(
uploaded: &[u8],
downloaded: &[u8],
) -> Result<(), Box<dyn std::error::Error>> {
if uploaded != downloaded {
test_error!(
"Uploaded data did not match downloaded data \n\
Uploaded Data length: {} \n\
Downloaded Data length: {}
",
uploaded.len(),
downloaded.len()
);
}
Ok(())
}
async fn assert_size(
grid_fs: &GridFs,
expected_bytes: usize,
expected_files: usize,
) -> Result<(), Box<dyn std::error::Error>> {
let (total_bytes, total_files) = grid_fs.size().await?;
if total_bytes != expected_bytes {
test_error!(
"size() did not return the correct amount of bytes, {} != {}",
total_bytes,
expected_bytes
);
}
if total_files != expected_files {
test_error!(
"size() did not return the correct amount of files, {} != {}",
total_files,
expected_files
);
}
Ok(())
}
async fn assert_exists(
grid_fs: &GridFs,
filename: &str,
) -> Result<(), Box<dyn std::error::Error>> {
if !grid_fs.exists(filename).await? {
test_error!("Could not find filename: {}", filename);
}
Ok(())
}
async fn assert_does_not_exists(
grid_fs: &GridFs,
filename: &str,
) -> Result<(), Box<dyn std::error::Error>> {
if grid_fs.exists(filename).await? {
test_error!("Found filename: {}", filename);
}
Ok(())
}
#[tokio::test]
async fn test_upload_download() {
let (_, test_db, _) = setup().await;
let grid_fs = GridFs::new(&test_db.db, None);
test_db
.run_test(
|| async {
let (file, file_data) = load_file_data("./test_data/shark-0.png").await?;
let file_stream = file.compat();
grid_fs.upload("shark", file_stream, None).await?;
let mut writer = Cursor::new(vec![]);
grid_fs.download("shark", &mut writer, None).await?;
let downloaded_data = writer.into_inner();
assert_upload_download_data(&file_data, &downloaded_data)?;
assert_size(&grid_fs, downloaded_data.len(), 1).await?;
Ok(())
},
None,
)
.await
.unwrap();
}
#[tokio::test]
async fn test_upload_download_streams() {
let (_, test_db, _) = setup().await;
let grid_fs = GridFs::new(&test_db.db, None);
test_db
.run_test(
|| async {
let file_data = read("./test_data/shark-0.png").await?;
let mut upload_stream = grid_fs.open_upload_stream("shark", None).await?;
upload_stream.write_all(&file_data).await?;
upload_stream.close().await?;
let mut download_stream = grid_fs.open_download_stream("shark", None).await?;
let mut buffer = vec![0; 1337];
let mut downloaded_data = vec![];
loop {
let bytes_read = match download_stream.read(&mut buffer[..]).await? {
0 => break,
size => size,
};
downloaded_data.extend_from_slice(&buffer[..bytes_read]);
}
assert_upload_download_data(&file_data, &downloaded_data)?;
assert_size(&grid_fs, downloaded_data.len(), 1).await?;
Ok(())
},
None,
)
.await
.unwrap();
}
#[tokio::test]
async fn test_rename() {
let (_, test_db, _) = setup().await;
let grid_fs = GridFs::new(&test_db.db, None);
test_db
.run_test(
|| async {
let (expected_total_bytes, _, _, _, _) =
upload_revised_shark_data(&grid_fs).await?;
grid_fs
.rename_by_filename("shark", "new_shark", None)
.await?;
assert_exists(&grid_fs, "new_shark").await?;
assert_does_not_exists(&grid_fs, "shark").await?;
assert_size(&grid_fs, expected_total_bytes, 4).await?;
Ok(())
},
None,
)
.await
.unwrap();
}
#[tokio::test]
async fn test_delete() {
let (_, test_db, _) = setup().await;
let grid_fs = GridFs::new(&test_db.db, None);
test_db
.run_test(
|| async {
upload_revised_shark_data(&grid_fs).await?;
grid_fs.delete_by_filename("shark", None).await?;
assert_does_not_exists(&grid_fs, "shark").await?;
assert_size(&grid_fs, 0, 0).await?;
Ok(())
},
None,
)
.await
.unwrap();
}
#[tokio::test]
async fn test_delete_many() {
let (_, test_db, _) = setup().await;
let grid_fs = GridFs::new(&test_db.db, None);
test_db
.run_test(
|| async {
upload_revised_shark_data(&grid_fs).await?;
grid_fs.delete_many(doc! {}, None).await?;
assert_does_not_exists(&grid_fs, "shark").await?;
assert_size(&grid_fs, 0, 0).await?;
Ok(())
},
None,
)
.await
.unwrap();
}
#[tokio::test]
async fn test_download_by_revision() {
let (_, test_db, _) = setup().await;
let grid_fs = GridFs::new(&test_db.db, None);
test_db
.run_test(
|| async {
let (expected_total_bytes, _, _, file_revision_2_data, _) =
upload_revised_shark_data(&grid_fs).await?;
let mut writer = Cursor::new(vec![]);
grid_fs.download("shark", &mut writer, Some(-2)).await?;
let downloaded_data = writer.into_inner();
if downloaded_data != file_revision_2_data {
test_error!("Downloaded data did not match revision -2 file data");
}
assert_size(&grid_fs, expected_total_bytes, 4).await?;
Ok(())
},
None,
)
.await
.unwrap();
}
#[tokio::test]
async fn test_delete_by_revision() {
let (_, test_db, _) = setup().await;
let grid_fs = GridFs::new(&test_db.db, None);
test_db
.run_test(
|| async {
let (expected_total_bytes, _, _, file_revision_2_data, _) =
upload_revised_shark_data(&grid_fs).await?;
let deleted_files = grid_fs.delete_by_filename("shark", Some(-2)).await?;
if deleted_files != 1 {
test_error!("deleted files should of been 1, got {}", deleted_files);
}
let deleted_document_option = grid_fs
.find_one(
doc! {
"metadata.id": 3,
},
None,
)
.await?;
if deleted_document_option.is_some() {
test_error!("Document with revision of -2 was not deleted");
}
assert_size(
&grid_fs,
expected_total_bytes - file_revision_2_data.len(),
3,
)
.await?;
Ok(())
},
None,
)
.await
.unwrap();
}
#[tokio::test]
async fn test_rename_by_revision() {
let (_, test_db, _) = setup().await;
let grid_fs = GridFs::new(&test_db.db, None);
test_db
.run_test(
|| async {
let (expected_total_bytes, _, _, _, _) =
upload_revised_shark_data(&grid_fs).await?;
let renamed_files = grid_fs
.rename_by_filename("shark", "new_shark", Some(2))
.await?;
if renamed_files != 1 {
test_error!("renamed files should of been 1, got {}", renamed_files);
}
let renamed_file = grid_fs
.find_one(
doc! {
"metadata.id": 3,
},
None,
)
.await?
.unwrap();
if renamed_file.filename.as_ref().unwrap() != "new_shark" {
test_error!("File with revision id 2 did not get renamed");
}
assert_exists(&grid_fs, "shark").await?;
assert_exists(&grid_fs, "new_shark").await?;
assert_size(&grid_fs, expected_total_bytes, 4).await?;
Ok(())
},
None,
)
.await
.unwrap();
}
}