diff --git a/Cargo.toml b/Cargo.toml index d5a119d..7b3e68a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,5 +42,9 @@ fs_extra = "1.3" [dev-dependencies] anyhow = "1.0.67" +futures = "0.3.30" pretty_assertions = "1.4.0" +rand = "0.8.5" tempfile = "3.2" +tokio = { version = "1.39", features = ["full"] } +tokio-macros = "2.4" diff --git a/src/tests/fixtures/image2.jpg b/src/tests/fixtures/image2.jpg new file mode 100755 index 0000000..17862cc Binary files /dev/null and b/src/tests/fixtures/image2.jpg differ diff --git a/src/tests/issues/issue_230.rs b/src/tests/issues/issue_230.rs new file mode 100644 index 0000000..ddd4f8e --- /dev/null +++ b/src/tests/issues/issue_230.rs @@ -0,0 +1,101 @@ +// Copyright 2024 Adobe. All rights reserved. +// This file is licensed to you under the Apache License, +// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +// or the MIT license (http://opensource.org/licenses/MIT), +// at your option. + +// Unless required by applicable law or agreed to in writing, +// this software is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or +// implied. See the LICENSE-MIT and LICENSE-APACHE files for the +// specific language governing permissions and limitations under +// each license. + +// Test case for https://github.com/adobe/xmp-toolkit-rs/issues/230: +// Updating the XMP data of same image concurrently aborts the entire process. + +use std::thread::sleep; + +use futures::stream::StreamExt; +use rand::{thread_rng, Rng}; +use tempfile::tempdir; +use tokio::task::spawn_blocking; +use tokio_macros::test; + +use crate::{ + tests::fixtures::temp_copy_of_fixture, xmp_ns::TIFF, OpenFileOptions, XmpFile, XmpMeta, + XmpValue, +}; + +#[test(flavor = "multi_thread")] +async fn main() { + let tempdir: tempfile::TempDir = tempdir().unwrap(); + let image2 = temp_copy_of_fixture(tempdir.path(), "image2.jpg"); + + let mut handles = Vec::new(); + + for _ in 0..2 { + let image2 = image2.clone(); + + let handle = spawn_blocking(move || { + let flip = thread_rng().gen_range(1..=8); + + let (mut xmp_file, mut meta) = open_file(&image2); + + sleep(std::time::Duration::from_secs(3)); + update(&mut meta, flip); + + sleep(std::time::Duration::from_secs(3)); + write_to_file(&mut xmp_file, &meta); + }); + + handles.push(handle); + } + + futures::stream::iter(handles) + .buffer_unordered(4) + .collect::>() + .await + .into_iter() + .collect::, _>>() + .unwrap(); +} + +fn open_file(path: impl AsRef) -> (XmpFile, XmpMeta) { + let path = path.as_ref(); + + let mut xmp_file = XmpFile::new().unwrap(); + + xmp_file + .open_file( + &path, + OpenFileOptions::default() + .only_xmp() + .for_update() + .use_smart_handler(), + ) + .or_else(|_| { + xmp_file.open_file( + &path, + OpenFileOptions::default() + .only_xmp() + .for_update() + .use_packet_scanning(), + ) + }) + .unwrap(); + + let xmp = xmp_file.xmp().unwrap_or(XmpMeta::new().unwrap()); + + (xmp_file, xmp) +} + +fn update(meta: &mut XmpMeta, flip: u8) { + meta.set_property(TIFF, "Orientation", &XmpValue::new(flip.to_string())) + .unwrap(); +} + +fn write_to_file(xmp_file: &mut XmpFile, meta: &XmpMeta) { + xmp_file.put_xmp(meta).unwrap(); + xmp_file.close(); +} diff --git a/src/tests/issues/mod.rs b/src/tests/issues/mod.rs new file mode 100644 index 0000000..3f1b8a0 --- /dev/null +++ b/src/tests/issues/mod.rs @@ -0,0 +1,16 @@ +// Copyright 2024 Adobe. All rights reserved. +// This file is licensed to you under the Apache License, +// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +// or the MIT license (http://opensource.org/licenses/MIT), +// at your option. + +// Unless required by applicable law or agreed to in writing, +// this software is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or +// implied. See the LICENSE-MIT and LICENSE-APACHE files for the +// specific language governing permissions and limitations under +// each license. + +// Test cases for specific GitHub issues will be added here. + +mod issue_230; diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 65dea8d..e90b702 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -19,6 +19,7 @@ #![allow(clippy::unwrap_used)] mod fixtures; +mod issues; mod xmp_core_coverage; mod xmp_date_time; #[cfg(feature = "chrono")]