On Wed, Aug 02, 2023 at 12:40:50PM +0000, Tage Johansson wrote: > diff --git a/rust/run-tests.sh b/rust/run-tests.sh > index 7a0bc85..005000e 100755 > --- a/rust/run-tests.sh > +++ b/rust/run-tests.sh > @@ -1,6 +1,6 @@ > #!/bin/bash - > # nbd client library in userspace > -# Copyright Red Hat > +# Copyright Tage Johansson > # > # This library is free software; you can redistribute it and/or > # modify it under the terms of the GNU Lesser General Public > @@ -21,4 +21,6 @@ > set -e > set -x > > -cargo test > +requires nbdkit --version > + > +$CARGO test -- --nocapture
The change to this file should be lifted into patch 1. I'm a bit surprised that $CARGO works (see also my comment on patch 1 about using @CARGO@ here). Is $CARGO set in the Makefile.am? > diff --git a/rust/tests/nbdkit_pattern/mod.rs > b/rust/tests/nbdkit_pattern/mod.rs > new file mode 100644 > index 0000000..5f4069e > --- /dev/null > +++ b/rust/tests/nbdkit_pattern/mod.rs > @@ -0,0 +1,28 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +use once_cell::sync::Lazy; > + > +/// The byte pattern as described in nbdkit-PATTERN-plugin(1). > +pub static PATTERN: Lazy<Vec<u8>> = Lazy::new(|| { > + let mut pattern = Vec::with_capacity(512); > + for i in 0u64..64 { > + pattern.extend_from_slice((i * 8).to_be_bytes().as_slice()); > + } > + assert_eq!(pattern.len(), 512); > + pattern > +}); > diff --git a/rust/tests/test_100_handle.rs b/rust/tests/test_100_handle.rs > new file mode 100644 > index 0000000..85e18aa > --- /dev/null > +++ b/rust/tests/test_100_handle.rs > @@ -0,0 +1,25 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +//! Just check that we can link with libnbd and create a handle. > + > +#![deny(warnings)] > + > +#[test] > +fn test_nbd_handle_new() { > + let _ = libnbd::Handle::new().unwrap(); > +} > diff --git a/rust/tests/test_110_defaults.rs b/rust/tests/test_110_defaults.rs > new file mode 100644 > index 0000000..ac1e29c > --- /dev/null > +++ b/rust/tests/test_110_defaults.rs > @@ -0,0 +1,33 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +#[test] > +fn test_defaults() { > + let nbd = libnbd::Handle::new().unwrap(); > + > + assert!(nbd.get_export_name().unwrap().is_empty()); > + assert!(!nbd.get_full_info().unwrap()); > + assert_eq!(nbd.get_tls(), libnbd::Tls::Disable); > + assert!(nbd.get_request_structured_replies()); > + assert!(nbd.get_request_meta_context().unwrap()); > + assert!(nbd.get_request_block_size().unwrap()); > + assert!(nbd.get_pread_initialize()); > + assert!(nbd.get_handshake_flags().is_all()); > + assert!(!nbd.get_opt_mode()); > +} > diff --git a/rust/tests/test_120_set_non_defaults.rs > b/rust/tests/test_120_set_non_defaults.rs > new file mode 100644 > index 0000000..7f1edab > --- /dev/null > +++ b/rust/tests/test_120_set_non_defaults.rs > @@ -0,0 +1,53 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +#[test] > +fn test_set_non_defaults() { > + let nbd = libnbd::Handle::new().unwrap(); > + > + nbd.set_export_name("name").unwrap(); > + assert_eq!(nbd.get_export_name().unwrap(), b"name"); > + > + nbd.set_full_info(true).unwrap(); > + assert!(nbd.get_full_info().unwrap()); > + > + if nbd.supports_tls() { > + nbd.set_tls(libnbd::Tls::Allow).unwrap(); > + assert_eq!(nbd.get_tls(), libnbd::Tls::Allow); > + } > + > + nbd.set_request_structured_replies(false).unwrap(); > + assert!(!nbd.get_request_structured_replies()); > + > + nbd.set_request_meta_context(false).unwrap(); > + assert!(!nbd.get_request_meta_context().unwrap()); > + > + nbd.set_request_block_size(false).unwrap(); > + assert!(!nbd.get_request_block_size().unwrap()); > + > + nbd.set_pread_initialize(false).unwrap(); > + assert!(!nbd.get_pread_initialize()); > + > + nbd.set_handshake_flags(libnbd::HandshakeFlag::empty()) > + .unwrap(); > + assert!(nbd.get_handshake_flags().is_empty()); > + > + nbd.set_opt_mode(true).unwrap(); > + assert!(nbd.get_opt_mode()); > +} > diff --git a/rust/tests/test_130_private_data.rs > b/rust/tests/test_130_private_data.rs > new file mode 100644 > index 0000000..bb507fb > --- /dev/null > +++ b/rust/tests/test_130_private_data.rs > @@ -0,0 +1,28 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +#[test] > +fn test_private_data() { > + let nbd = libnbd::Handle::new().unwrap(); > + > + assert_eq!(nbd.get_private_data(), 0); > + assert_eq!(nbd.set_private_data(42), 0); > + assert_eq!(nbd.set_private_data(314), 42); > + assert_eq!(nbd.get_private_data(), 314); > +} > diff --git a/rust/tests/test_140_explicit_close.rs > b/rust/tests/test_140_explicit_close.rs > new file mode 100644 > index 0000000..59ab382 > --- /dev/null > +++ b/rust/tests/test_140_explicit_close.rs > @@ -0,0 +1,31 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +mod test_log; > + > +use test_log::DEBUG_LOGGER; > + > +#[test] > +fn test_private_data() { > + DEBUG_LOGGER.init(); > + > + let nbd = libnbd::Handle::new().unwrap(); > + drop(nbd); > + assert!(DEBUG_LOGGER.contains("closing handle")); > +} > diff --git a/rust/tests/test_200_connect_command.rs > b/rust/tests/test_200_connect_command.rs > new file mode 100644 > index 0000000..8338650 > --- /dev/null > +++ b/rust/tests/test_200_connect_command.rs > @@ -0,0 +1,32 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > + > +#[test] > +fn test_connect_command() { > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "null", > + ]) > + .unwrap(); > +} > diff --git a/rust/tests/test_210_opt_abort.rs > b/rust/tests/test_210_opt_abort.rs > new file mode 100644 > index 0000000..c59805f > --- /dev/null > +++ b/rust/tests/test_210_opt_abort.rs > @@ -0,0 +1,31 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +#[test] > +fn test_opt_abort() { > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.set_opt_mode(true).unwrap(); > + nbd.connect_command(&["nbdkit", "-s", "--exit-with-parent", "-v", > "null"]) > + .unwrap(); > + assert_eq!(nbd.get_protocol().unwrap(), b"newstyle-fixed"); > + assert!(nbd.get_structured_replies_negotiated().unwrap()); > + > + nbd.opt_abort().unwrap(); > + assert!(nbd.aio_is_closed()); > +} > diff --git a/rust/tests/test_220_opt_list.rs b/rust/tests/test_220_opt_list.rs > new file mode 100644 > index 0000000..180a95b > --- /dev/null > +++ b/rust/tests/test_220_opt_list.rs > @@ -0,0 +1,86 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +use std::env; > +use std::os::unix::ffi::OsStringExt as _; > +use std::path::Path; > +use std::sync::Arc; > +use std::sync::Mutex; > + > +/// Test different types of connections. > +struct ConnTester { > + script_path: String, > +} > + > +impl ConnTester { > + fn new() -> Self { > + let srcdir = env::var("srcdir").unwrap(); > + let srcdir = Path::new(&srcdir); > + let script_path = srcdir.join("../tests/opt-list.sh"); > + let script_path = > + > String::from_utf8(script_path.into_os_string().into_vec()).unwrap(); > + Self { script_path } > + } > + > + fn connect( > + &self, > + mode: u8, > + expected_exports: &[&str], > + ) -> libnbd::Result<()> { > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.set_opt_mode(true).unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "sh", > + &self.script_path, > + &format!("mode={mode}"), > + ]) > + .unwrap(); > + > + // Collect all exports in this list. > + let exports = Arc::new(Mutex::new(Vec::new())); > + let exports_clone = exports.clone(); > + let count = nbd.opt_list(move |name, _| { > + exports_clone > + .lock() > + .unwrap() > + .push(String::from_utf8(name.to_owned()).unwrap()); > + 0 > + })?; > + let exports = > Arc::into_inner(exports).unwrap().into_inner().unwrap(); > + assert_eq!(exports.len(), count as usize); > + assert_eq!(exports.len(), expected_exports.len()); > + for (export, &expected) in exports.iter().zip(expected_exports) { > + assert_eq!(export, expected); > + } > + Ok(()) > + } > +} > + > +#[test] > +fn test_opt_list() { > + let conn_tester = ConnTester::new(); > + assert!(conn_tester.connect(0, &[]).is_err()); > + assert!(conn_tester.connect(1, &["a", "b"]).is_ok()); > + assert!(conn_tester.connect(2, &[]).is_ok()); > + assert!(conn_tester.connect(3, &["a"]).is_ok()); > +} > diff --git a/rust/tests/test_230_opt_info.rs b/rust/tests/test_230_opt_info.rs > new file mode 100644 > index 0000000..00e5fb0 > --- /dev/null > +++ b/rust/tests/test_230_opt_info.rs > @@ -0,0 +1,120 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +use libnbd::CONTEXT_BASE_ALLOCATION; > +use std::env; > +use std::path::Path; > + > +#[test] > +fn test_opt_info() { > + let srcdir = env::var("srcdir").unwrap(); > + let srcdir = Path::new(&srcdir); > + let script_path = srcdir.join("../tests/opt-info.sh"); > + let script_path = script_path.to_str().unwrap(); > + > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.set_opt_mode(true).unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "sh", > + script_path, > + ]) > + .unwrap(); > + nbd.add_meta_context(CONTEXT_BASE_ALLOCATION).unwrap(); > + > + // No size, flags, or meta-contexts yet > + assert!(nbd.get_size().is_err()); > + assert!(nbd.is_read_only().is_err()); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).is_err()); > + > + // info with no prior name gets info on "" > + assert!(nbd.opt_info().is_ok()); > + assert_eq!(nbd.get_size().unwrap(), 0); > + assert!(nbd.is_read_only().unwrap()); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > + > + // changing export wipes out prior info > + nbd.set_export_name("b").unwrap(); > + assert!(nbd.get_size().is_err()); > + assert!(nbd.is_read_only().is_err()); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).is_err()); > + > + // info on something not present fails > + nbd.set_export_name("a").unwrap(); > + assert!(nbd.opt_info().is_err()); > + > + // info for a different export, with automatic meta_context disabled > + nbd.set_export_name("b").unwrap(); > + nbd.set_request_meta_context(false).unwrap(); > + nbd.opt_info().unwrap(); > + // idempotent name change is no-op > + nbd.set_export_name("b").unwrap(); > + assert_eq!(nbd.get_size().unwrap(), 1); > + assert!(!nbd.is_read_only().unwrap()); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).is_err()); > + nbd.set_request_meta_context(true).unwrap(); > + > + // go on something not present > + nbd.set_export_name("a").unwrap(); > + assert!(nbd.opt_go().is_err()); > + assert!(nbd.get_size().is_err()); > + assert!(nbd.is_read_only().is_err()); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).is_err()); > + > + // go on a valid export > + nbd.set_export_name("good").unwrap(); > + nbd.opt_go().unwrap(); > + assert_eq!(nbd.get_size().unwrap(), 4); > + assert!(nbd.is_read_only().unwrap()); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > + > + // now info is no longer valid, but does not wipe data > + assert!(nbd.set_export_name("a").is_err()); > + assert_eq!(nbd.get_export_name().unwrap(), b"good"); > + assert!(nbd.opt_info().is_err()); > + assert_eq!(nbd.get_size().unwrap(), 4); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > + nbd.shutdown(None).unwrap(); > + > + // Another connection. This time, check that SET_META triggered by > opt_info > + // persists through nbd_opt_go with set_request_meta_context disabled. > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.set_opt_mode(true).unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "sh", > + &script_path, > + ]) > + .unwrap(); > + nbd.add_meta_context("x-unexpected:bogus").unwrap(); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).is_err()); > + nbd.opt_info().unwrap(); > + assert!(!nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > + nbd.set_request_meta_context(false).unwrap(); > + // Adding to the request list now won't matter > + nbd.add_meta_context(CONTEXT_BASE_ALLOCATION).unwrap(); > + nbd.opt_go().unwrap(); > + assert!(!nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > +} > diff --git a/rust/tests/test_240_opt_list_meta.rs > b/rust/tests/test_240_opt_list_meta.rs > new file mode 100644 > index 0000000..5598458 > --- /dev/null > +++ b/rust/tests/test_240_opt_list_meta.rs > @@ -0,0 +1,147 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +use std::sync::Arc; > +use std::sync::Mutex; > + > +/// A struct with information about listed meta contexts. > +#[derive(Debug, Clone, PartialEq, Eq)] > +struct CtxInfo { > + /// Whether the meta context "base:alloc" is listed. > + has_alloc: bool, > + /// The number of listed meta contexts. > + count: u32, > +} > + > +fn list_meta_ctxs(nbd: &libnbd::Handle) -> libnbd::Result<CtxInfo> { > + let info = Arc::new(Mutex::new(CtxInfo { > + has_alloc: false, > + count: 0, > + })); > + let info_clone = info.clone(); > + let replies = nbd.opt_list_meta_context(move |ctx| { > + let mut info = info_clone.lock().unwrap(); > + info.count += 1; > + if ctx == libnbd::CONTEXT_BASE_ALLOCATION { > + info.has_alloc = true; > + } > + 0 > + })?; > + let info = Arc::into_inner(info).unwrap().into_inner().unwrap(); > + assert_eq!(info.count, replies); > + Ok(info) > +} > + > +#[test] > +fn test_opt_list_meta() { > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.set_opt_mode(true).unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "memory", > + "size=1M", > + ]) > + .unwrap(); > + > + // First pass: empty query should give at least "base:allocation". > + let info = list_meta_ctxs(&nbd).unwrap(); > + assert!(info.count >= 1); > + assert!(info.has_alloc); > + let max = info.count; > + > + // Second pass: bogus query has no response. > + nbd.add_meta_context("x-nosuch:").unwrap(); > + assert_eq!( > + list_meta_ctxs(&nbd).unwrap(), > + CtxInfo { > + count: 0, > + has_alloc: false > + } > + ); > + > + // Third pass: specific query should have one match. > + nbd.add_meta_context("base:allocation").unwrap(); > + assert_eq!(nbd.get_nr_meta_contexts().unwrap(), 2); > + assert_eq!(nbd.get_meta_context(1).unwrap(), b"base:allocation"); > + assert_eq!( > + list_meta_ctxs(&nbd).unwrap(), > + CtxInfo { > + count: 1, > + has_alloc: true > + } > + ); > + > + // Fourth pass: opt_list_meta_context is stateless, so it should > + // not wipe status learned during opt_info > + assert!(nbd.can_meta_context("base:allocation").is_err()); > + assert!(nbd.get_size().is_err()); > + nbd.opt_info().unwrap(); > + assert_eq!(nbd.get_size().unwrap(), 1048576); > + assert!(nbd.can_meta_context("base:allocation").unwrap()); > + nbd.clear_meta_contexts().unwrap(); > + nbd.add_meta_context("x-nosuch:").unwrap(); > + assert_eq!( > + list_meta_ctxs(&nbd).unwrap(), > + CtxInfo { > + count: 0, > + has_alloc: false > + } > + ); > + assert_eq!(nbd.get_size().unwrap(), 1048576); > + assert!(nbd.can_meta_context("base:allocation").unwrap()); > + > + // Final pass: "base:" query should get at least "base:allocation" > + nbd.add_meta_context("base:").unwrap(); > + let info = list_meta_ctxs(&nbd).unwrap(); > + assert!(info.count >= 1); > + assert!(info.count <= max); > + assert!(info.has_alloc); > + > + // Repeat but this time without structured replies. Deal gracefully > + // with older servers that don't allow the attempt. > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.set_opt_mode(true).unwrap(); > + nbd.set_request_structured_replies(false).unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "memory", > + "size=1M", > + ]) > + .unwrap(); > + let bytes = nbd.stats_bytes_sent(); > + if let Ok(info) = list_meta_ctxs(&nbd) { > + assert!(info.count >= 1); > + assert!(info.has_alloc) > + } else { > + assert!(nbd.stats_bytes_sent() > bytes); > + // ignoring failure from old server > + } > + > + // Now enable structured replies, and a retry should pass. > + assert!(nbd.opt_structured_reply().unwrap()); > + let info = list_meta_ctxs(&nbd).unwrap(); > + assert!(info.count >= 1); > + assert!(info.has_alloc); > +} > diff --git a/rust/tests/test_245_opt_list_meta_queries.rs > b/rust/tests/test_245_opt_list_meta_queries.rs > new file mode 100644 > index 0000000..da5c674 > --- /dev/null > +++ b/rust/tests/test_245_opt_list_meta_queries.rs > @@ -0,0 +1,93 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +use std::sync::Arc; > +use std::sync::Mutex; > + > +/// A struct with information about listed meta contexts. > +#[derive(Debug, Clone, PartialEq, Eq)] > +struct CtxInfo { > + /// Whether the meta context "base:allocation" is listed. > + has_alloc: bool, > + /// The number of listed meta contexts. > + count: u32, > +} > + > +fn list_meta_ctxs( > + nbd: &libnbd::Handle, > + queries: &[&[u8]], > +) -> libnbd::Result<CtxInfo> { > + let info = Arc::new(Mutex::new(CtxInfo { > + has_alloc: false, > + count: 0, > + })); > + let info_clone = info.clone(); > + let replies = nbd.opt_list_meta_context_queries(queries, move |ctx| { > + let mut info = info_clone.lock().unwrap(); > + info.count += 1; > + if ctx == libnbd::CONTEXT_BASE_ALLOCATION { > + info.has_alloc = true; > + } > + 0 > + })?; > + let info = Arc::into_inner(info).unwrap().into_inner().unwrap(); > + assert_eq!(info.count, replies); > + Ok(info) > +} > + > +#[test] > +fn test_opt_list_meta_queries() { > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.set_opt_mode(true).unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "memory", > + "size=1M", > + ]) > + .unwrap(); > + > + // First pass: empty query should give at least "base:allocation". > + nbd.add_meta_context("x-nosuch:").unwrap(); > + let info = list_meta_ctxs(&nbd, &[]).unwrap(); > + assert!(info.count >= 1); > + assert!(info.has_alloc); > + > + // Second pass: bogus query has no response. > + nbd.clear_meta_contexts().unwrap(); > + assert_eq!( > + list_meta_ctxs(&nbd, &[b"x-nosuch:"]).unwrap(), > + CtxInfo { > + count: 0, > + has_alloc: false > + } > + ); > + > + // Third pass: specific query should have one match. > + assert_eq!( > + list_meta_ctxs(&nbd, &[b"x-nosuch:", > libnbd::CONTEXT_BASE_ALLOCATION]) > + .unwrap(), > + CtxInfo { > + count: 1, > + has_alloc: true > + } > + ); > +} > diff --git a/rust/tests/test_250_opt_set_meta.rs > b/rust/tests/test_250_opt_set_meta.rs > new file mode 100644 > index 0000000..c7a8144 > --- /dev/null > +++ b/rust/tests/test_250_opt_set_meta.rs > @@ -0,0 +1,123 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +use libnbd::CONTEXT_BASE_ALLOCATION; > +use std::sync::Arc; > +use std::sync::Mutex; > + > +/// A struct with information about set meta contexts. > +#[derive(Debug, Clone, PartialEq, Eq)] > +struct CtxInfo { > + /// Whether the meta context "base:allocation" is set. > + has_alloc: bool, > + /// The number of set meta contexts. > + count: u32, > +} > + > +fn set_meta_ctxs(nbd: &libnbd::Handle) -> libnbd::Result<CtxInfo> { > + let info = Arc::new(Mutex::new(CtxInfo { > + has_alloc: false, > + count: 0, > + })); > + let info_clone = info.clone(); > + let replies = nbd.opt_set_meta_context(move |ctx| { > + let mut info = info_clone.lock().unwrap(); > + info.count += 1; > + if ctx == CONTEXT_BASE_ALLOCATION { > + info.has_alloc = true; > + } > + 0 > + })?; > + let info = Arc::into_inner(info).unwrap().into_inner().unwrap(); > + assert_eq!(info.count, replies); > + Ok(info) > +} > + > +#[test] > +fn test_opt_set_meta() { > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.set_opt_mode(true).unwrap(); > + nbd.set_request_structured_replies(false).unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "memory", > + "size=1M", > + ]) > + .unwrap(); > + > + // No contexts negotiated yet; can_meta should be error if any requested > + assert!(!nbd.get_structured_replies_negotiated().unwrap()); > + assert!(!nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > + nbd.add_meta_context(CONTEXT_BASE_ALLOCATION).unwrap(); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).is_err()); > + > + // SET cannot succeed until SR is negotiated. > + assert!(nbd.opt_structured_reply().unwrap()); > + assert!(nbd.get_structured_replies_negotiated().unwrap()); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).is_err()); > + > + // nbdkit does not match wildcard for SET, even though it does for LIST > + nbd.clear_meta_contexts().unwrap(); > + nbd.add_meta_context("base:").unwrap(); > + assert_eq!( > + set_meta_ctxs(&nbd).unwrap(), > + CtxInfo { > + count: 0, > + has_alloc: false > + } > + ); > + assert!(!nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > + > + // Negotiating with no contexts is not an error, but selects nothing > + nbd.clear_meta_contexts().unwrap(); > + assert_eq!( > + set_meta_ctxs(&nbd).unwrap(), > + CtxInfo { > + count: 0, > + has_alloc: false > + } > + ); > + > + // Request 2 with expectation of 1; with set_request_meta_context off > + nbd.add_meta_context("x-nosuch:context").unwrap(); > + nbd.add_meta_context(CONTEXT_BASE_ALLOCATION).unwrap(); > + nbd.set_request_meta_context(false).unwrap(); > + assert_eq!( > + set_meta_ctxs(&nbd).unwrap(), > + CtxInfo { > + count: 1, > + has_alloc: true > + } > + ); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > + > + // Transition to transmission phase; our last set should remain active > + nbd.clear_meta_contexts().unwrap(); > + nbd.add_meta_context("x-nosuch:context").unwrap(); > + nbd.opt_go().unwrap(); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > + > + // Now too late to set; but should not lose earlier state > + assert!(set_meta_ctxs(&nbd).is_err()); > + assert_eq!(nbd.get_size().unwrap(), 1048576); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > +} > diff --git a/rust/tests/test_255_opt_set_meta_queries.rs > b/rust/tests/test_255_opt_set_meta_queries.rs > new file mode 100644 > index 0000000..143a2f1 > --- /dev/null > +++ b/rust/tests/test_255_opt_set_meta_queries.rs > @@ -0,0 +1,109 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +use libnbd::CONTEXT_BASE_ALLOCATION; > +use std::sync::Arc; > +use std::sync::Mutex; > + > +/// A struct with information about set meta contexts. > +#[derive(Debug, Clone, PartialEq, Eq)] > +struct CtxInfo { > + /// Whether the meta context "base:allocation" is set. > + has_alloc: bool, > + /// The number of set meta contexts. > + count: u32, > +} > + > +fn set_meta_ctxs_queries( > + nbd: &libnbd::Handle, > + queries: &[impl AsRef<[u8]>], > +) -> libnbd::Result<CtxInfo> { > + let info = Arc::new(Mutex::new(CtxInfo { > + has_alloc: false, > + count: 0, > + })); > + let info_clone = info.clone(); > + let replies = nbd.opt_set_meta_context_queries(queries, move |ctx| { > + let mut info = info_clone.lock().unwrap(); > + info.count += 1; > + if ctx == CONTEXT_BASE_ALLOCATION { > + info.has_alloc = true; > + } > + 0 > + })?; > + let info = Arc::into_inner(info).unwrap().into_inner().unwrap(); > + assert_eq!(info.count, replies); > + Ok(info) > +} > + > +#[test] > +fn test_opt_set_meta_queries() { > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.set_opt_mode(true).unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "memory", > + "size=1M", > + ]) > + .unwrap(); > + > + // nbdkit does not match wildcard for SET, even though it does for LIST > + assert_eq!( > + set_meta_ctxs_queries(&nbd, &["base:"]).unwrap(), > + CtxInfo { > + count: 0, > + has_alloc: false > + } > + ); > + assert!(!nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > + > + // Negotiating with no contexts is not an error, but selects nothing > + // An explicit empty list overrides a non-empty implicit list. > + nbd.add_meta_context(CONTEXT_BASE_ALLOCATION).unwrap(); > + assert_eq!( > + set_meta_ctxs_queries(&nbd, &[] as &[&str]).unwrap(), > + CtxInfo { > + count: 0, > + has_alloc: false > + } > + ); > + assert!(!nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > + > + // Request 2 with expectation of 1. > + assert_eq!( > + set_meta_ctxs_queries( > + &nbd, > + &[b"x-nosuch:context".as_slice(), CONTEXT_BASE_ALLOCATION] > + ) > + .unwrap(), > + CtxInfo { > + count: 1, > + has_alloc: true > + } > + ); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > + > + // Transition to transmission phase; our last set should remain active > + nbd.set_request_meta_context(false).unwrap(); > + nbd.opt_go().unwrap(); > + assert!(nbd.can_meta_context(CONTEXT_BASE_ALLOCATION).unwrap()); > +} > diff --git a/rust/tests/test_300_get_size.rs b/rust/tests/test_300_get_size.rs > new file mode 100644 > index 0000000..c830164 > --- /dev/null > +++ b/rust/tests/test_300_get_size.rs > @@ -0,0 +1,35 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > + > +#[test] > +fn test_get_size() { > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "null", > + "size=1M", > + ]) > + .unwrap(); > + > + assert_eq!(nbd.get_size().unwrap(), 1048576); > +} > diff --git a/rust/tests/test_400_pread.rs b/rust/tests/test_400_pread.rs > new file mode 100644 > index 0000000..93b826c > --- /dev/null > +++ b/rust/tests/test_400_pread.rs > @@ -0,0 +1,39 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +mod nbdkit_pattern; > +use nbdkit_pattern::PATTERN; > + > +#[test] > +fn test_pread() { > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "pattern", > + "size=1M", > + ]) > + .unwrap(); > + > + let mut buf = [0; 512]; > + nbd.pread(&mut buf, 0, None).unwrap(); > + assert_eq!(buf.as_slice(), PATTERN.as_slice()); > +} > diff --git a/rust/tests/test_405_pread_structured.rs > b/rust/tests/test_405_pread_structured.rs > new file mode 100644 > index 0000000..39a7fd5 > --- /dev/null > +++ b/rust/tests/test_405_pread_structured.rs > @@ -0,0 +1,79 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +mod nbdkit_pattern; > +use nbdkit_pattern::PATTERN; > + > +#[test] > +fn test_pread_structured() { > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "pattern", > + "size=1M", > + ]) > + .unwrap(); > + > + fn f(buf: &[u8], offset: u64, s: u32, err: &mut i32) { > + assert_eq!(*err, 0); > + *err = 42; > + assert_eq!(buf, PATTERN.as_slice()); > + assert_eq!(offset, 0); > + assert_eq!(s, libnbd::READ_DATA); > + } > + > + let mut buf = [0; 512]; > + nbd.pread_structured( > + &mut buf, > + 0, > + |b, o, s, e| { > + f(b, o, s, e); > + 0 > + }, > + None, > + ) > + .unwrap(); > + assert_eq!(buf.as_slice(), PATTERN.as_slice()); > + > + nbd.pread_structured( > + &mut buf, > + 0, > + |b, o, s, e| { > + f(b, o, s, e); > + 0 > + }, > + Some(libnbd::CmdFlag::DF), > + ) > + .unwrap(); > + assert_eq!(buf.as_slice(), PATTERN.as_slice()); > + > + let res = nbd.pread_structured( > + &mut buf, > + 0, > + |b, o, s, e| { > + f(b, o, s, e); > + -1 > + }, > + Some(libnbd::CmdFlag::DF), > + ); > + assert_eq!(res.unwrap_err().errno(), Some(42)); > +} > diff --git a/rust/tests/test_410_pwrite.rs b/rust/tests/test_410_pwrite.rs > new file mode 100644 > index 0000000..d4d6b99 > --- /dev/null > +++ b/rust/tests/test_410_pwrite.rs > @@ -0,0 +1,58 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +use std::fs::{self, File}; > + > +#[test] > +fn test_pwrite() { > + let tmp_dir = tempfile::tempdir().unwrap(); > + let data_file_path = tmp_dir.path().join("pwrite_test.data"); > + let data_file = File::create(&data_file_path).unwrap(); > + data_file.set_len(512).unwrap(); > + drop(data_file); > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "file", > + data_file_path.to_str().unwrap(), > + ]) > + .unwrap(); > + > + let mut buf_1 = [0; 512]; > + buf_1[10] = 0x01; > + buf_1[510] = 0x55; > + buf_1[511] = 0xAA; > + > + let flags = Some(libnbd::CmdFlag::FUA); > + nbd.pwrite(&buf_1, 0, flags).unwrap(); > + > + let mut buf_2 = [0; 512]; > + nbd.pread(&mut buf_2, 0, None).unwrap(); > + > + assert_eq!(buf_1, buf_2); > + > + // Drop nbd before tmp_dir is dropped. > + drop(nbd); > + > + let data_file_content = fs::read(&data_file_path).unwrap(); > + assert_eq!(buf_1.as_slice(), data_file_content.as_slice()); > +} > diff --git a/rust/tests/test_460_block_status.rs > b/rust/tests/test_460_block_status.rs > new file mode 100644 > index 0000000..7cdcb34 > --- /dev/null > +++ b/rust/tests/test_460_block_status.rs > @@ -0,0 +1,92 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > +use std::env; > +use std::path::Path; > +use std::sync::Arc; > +use std::sync::Mutex; > + > +fn block_status_get_entries( > + nbd: &libnbd::Handle, > + count: u64, > + offset: u64, > + flags: Option<libnbd::CmdFlag>, > +) -> Vec<u32> { > + let entries = Arc::new(Mutex::new(None)); > + let entries_clone = entries.clone(); > + nbd.block_status( > + count, > + offset, > + move |metacontext, _, entries, err| { > + assert_eq!(*err, 0); > + if metacontext == libnbd::CONTEXT_BASE_ALLOCATION { > + *entries_clone.lock().unwrap() = Some(entries.to_vec()); > + } > + 0 > + }, > + flags, > + ) > + .unwrap(); > + Arc::into_inner(entries) > + .unwrap() > + .into_inner() > + .unwrap() > + .unwrap() > +} > + > +#[test] > +fn test_block_status() { > + let srcdir = env::var("srcdir").unwrap(); > + let srcdir = Path::new(&srcdir); > + let script_path = srcdir.join("../tests/meta-base-allocation.sh"); > + let script_path = script_path.to_str().unwrap(); > + let nbd = libnbd::Handle::new().unwrap(); > + nbd.add_meta_context(libnbd::CONTEXT_BASE_ALLOCATION) > + .unwrap(); > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "sh", > + script_path, > + ]) > + .unwrap(); > + > + assert_eq!( > + block_status_get_entries(&nbd, 65536, 0, None).as_slice(), > + &[8192, 0, 8192, 1, 16384, 3, 16384, 2, 16384, 0,] > + ); > + > + assert_eq!( > + block_status_get_entries(&nbd, 1024, 32256, None).as_slice(), > + &[512, 3, 16384, 2] > + ); > + > + assert_eq!( > + block_status_get_entries( > + &nbd, > + 1024, > + 32256, > + Some(libnbd::CmdFlag::REQ_ONE) > + ) > + .as_slice(), > + &[512, 3] > + ); > +} > diff --git a/rust/tests/test_620_stats.rs b/rust/tests/test_620_stats.rs > new file mode 100644 > index 0000000..134d59a > --- /dev/null > +++ b/rust/tests/test_620_stats.rs > @@ -0,0 +1,75 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +#![deny(warnings)] > + > + > +#[test] > +fn test_stats() { > + let nbd = libnbd::Handle::new().unwrap(); > + > + // Pre-connection, stats start out at 0 > + assert_eq!(nbd.stats_bytes_sent(), 0); > + assert_eq!(nbd.stats_chunks_sent(), 0); > + assert_eq!(nbd.stats_bytes_received(), 0); > + assert_eq!(nbd.stats_chunks_received(), 0); > + > + // Connection performs handshaking, which increments stats. > + // The number of bytes/chunks here may grow over time as more features > get > + // automatically negotiated, so merely check that they are non-zero. > + nbd.connect_command(&[ > + "nbdkit", > + "-s", > + "--exit-with-parent", > + "-v", > + "null", > + ]) > + .unwrap(); > + > + let bs1 = nbd.stats_bytes_sent(); > + let cs1 = nbd.stats_chunks_sent(); > + let br1 = nbd.stats_bytes_received(); > + let cr1 = nbd.stats_chunks_received(); > + assert!(cs1 > 0); > + assert!(bs1 > cs1); > + assert!(cr1 > 0); > + assert!(br1 > cr1); > + > + // A flush command should be one chunk out, one chunk back (even if > + // structured replies are in use) > + nbd.flush(None).unwrap(); > + let bs2 = nbd.stats_bytes_sent(); > + let cs2 = nbd.stats_chunks_sent(); > + let br2 = nbd.stats_bytes_received(); > + let cr2 = nbd.stats_chunks_received(); > + assert_eq!(bs2, bs1 + 28); > + assert_eq!(cs2, cs1 + 1); > + assert_eq!(br2, br1 + 16); // assumes nbdkit uses simple reply > + assert_eq!(cr2, cr1 + 1); > + > + // Stats are still readable after the connection closes; we don't know if > + // the server sent reply bytes to our NBD_CMD_DISC, so don't insist on > it. > + nbd.shutdown(None).unwrap(); > + let bs3 = nbd.stats_bytes_sent(); > + let cs3 = nbd.stats_chunks_sent(); > + let br3 = nbd.stats_bytes_received(); > + let cr3 = nbd.stats_chunks_received(); > + assert!(bs3 > bs2); > + assert_eq!(cs3, cs2 + 1); > + assert!(br3 >= br2); > + assert!(cr3 == cr2 || cr3 == cr2 + 1); > +} > diff --git a/rust/tests/test_log/mod.rs b/rust/tests/test_log/mod.rs > new file mode 100644 > index 0000000..8dbcd79 > --- /dev/null > +++ b/rust/tests/test_log/mod.rs > @@ -0,0 +1,86 @@ > +// libnbd Rust test case > +// Copyright Tage Johansson > +// > +// This library is free software; you can redistribute it and/or > +// modify it under the terms of the GNU Lesser General Public > +// License as published by the Free Software Foundation; either > +// version 2 of the License, or (at your option) any later version. > +// > +// This library is distributed in the hope that it will be useful, > +// but WITHOUT ANY WARRANTY; without even the implied warranty of > +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > +// Lesser General Public License for more details. > +// > +// You should have received a copy of the GNU Lesser General Public > +// License along with this library; if not, write to the Free Software > +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + > +//! This module provides facilities for capturing log output and asserting > that > +//! it does or does not contain certain messages. The primary use of this > module > +//! is to assert that certain libnbd operations are or are not performed. > + > +#![allow(unused)] > + > +use std::sync::Mutex; > + > +/// Logger that stores all debug messages in a list. > +pub struct DebugLogger { > + /// All targets and messages logged. Wrapped in a mutex so that it can be > + /// updated with an imutable reference to self. > + entries: Mutex<Vec<(String, String)>>, > + is_initialized: Mutex<bool>, > +} > + > +impl DebugLogger { > + const fn new() -> Self { > + Self { > + entries: Mutex::new(Vec::new()), > + is_initialized: Mutex::new(false), > + } > + } > + > + /// Set this logger as the global logger. > + pub fn init(&'static self) { > + let mut is_initialized = self.is_initialized.lock().unwrap(); > + if !*is_initialized { > + log::set_logger(self).unwrap(); > + log::set_max_level(log::LevelFilter::Debug); > + *is_initialized = true; > + } > + } > + > + /// Check wether a specific message has been logged. > + pub fn contains(&self, msg: &str) -> bool { > + self.entries.lock().unwrap().iter().any(|(_, x)| x == msg) > + } > + > + /// Print all logged messages, in no particular order. > + /// > + /// Only for debug purposes. Remember to run cargo test with the `-- > + /// --nocapture` arguments. That is, from the rust directory run: > + /// `./../run cargo test -- --nocapture` > + pub fn print_messages(&self) { > + for (target, msg) in self.entries.lock().unwrap().iter() { > + eprintln!("{target}: {msg}"); > + } > + } > +} > + > +/// A static global `DebugLogger`. Just call `.init()` on this to set it as > the > +/// global logger. > +pub static DEBUG_LOGGER: DebugLogger = DebugLogger::new(); > + > +impl log::Log for DebugLogger { > + fn enabled(&self, metadata: &log::Metadata<'_>) -> bool { > + metadata.level() == log::Level::Debug > + } > + > + fn log(&self, record: &log::Record<'_>) { > + self.entries > + .lock() > + .unwrap() > + .push((record.target().to_string(), record.args().to_string())); > + } > + > + fn flush(&self) {} > +} For the rest of this change: Acked-by: Richard W.M. Jones <rjo...@redhat.com> Can patch 5 be moved so it is the second in the series? As far as I can tell it doesn't seem to depend on either the asynch handle or FnOnce callbacks, therefore shouldn't depend on patches 2, 3 & 4 at all. The advantage of moving it earlier in the series is that we will then be able to fix up the remaining problems with patches 1 & 5 (which will be 1 & 2) and send them upstream sooner than the rest of the change. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com virt-builder quickly builds VMs from scratch http://libguestfs.org/virt-builder.1.html _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://listman.redhat.com/mailman/listinfo/libguestfs