diff --git a/bindings/rust/tests/src/bin/cfg-test.rs b/bindings/rust/tests/src/bin/cfg-test.rs index 1b245251..5b6f9ce0 100644 --- a/bindings/rust/tests/src/bin/cfg-test.rs +++ b/bindings/rust/tests/src/bin/cfg-test.rs @@ -1,135 +1,137 @@ // Test the CFG library. Requires that corosync is running and that we are root. extern crate rust_corosync as corosync; use corosync::{cfg, NodeId}; use std::thread::spawn; fn dispatch_thread(handle: &cfg::Handle) { loop { if cfg::dispatch(handle, corosync::DispatchFlags::One).is_err() { return; } } } // Test the shutdown callback fn shutdown_check_fn(handle: &cfg::Handle, _flags: u32) { println!("in shutdown callback"); // DON'T shutdown corosync - we're just testing if let Err(e) = cfg::reply_to_shutdown(handle, cfg::ShutdownReply::No) { println!("Error in CFG replyto_shutdown: {e}"); } } -fn main() { +fn main() -> Result<(), corosync::CsError> { // Initialise the callbacks data let cb = cfg::Callbacks { corosync_cfg_shutdown_callback_fn: Some(shutdown_check_fn), }; let handle = match cfg::initialize(&cb) { Ok(h) => { println!("cfg initialized."); h } Err(e) => { println!("Error in CFG init: {e}"); - return; + return Err(e); } }; // Open two handles to CFG so that the second one can refuse shutdown let handle2 = match cfg::initialize(&cb) { Ok(h) => { println!("cfg2 initialized."); h } Err(e) => { println!("Error in CFG init: {e}"); - return; + return Err(e); } }; match cfg::track_start(&handle2, cfg::TrackFlags::None) { Ok(_) => { // Run handle2 dispatch in its own thread spawn(move || dispatch_thread(&handle2)); } Err(e) => { println!("Error in CFG track_start: {e}"); + return Err(e); } }; let local_nodeid = { match cfg::local_get(&handle) { Ok(n) => { println!("Local nodeid is {n}"); Some(n) } Err(e) => { println!("Error in CFG local_get: {e}"); - None + return Err(e); } } }; // Test node_status_get. // node status for the local node looks odd (cos it's the loopback connection), so // we try for a node ID one less or more than us just to get output that looks // sensible to the user. if let Some(our_nodeid) = local_nodeid { let us_plus1 = NodeId::from(u32::from(our_nodeid) + 1); let us_less1 = NodeId::from(u32::from(our_nodeid) - 1); let mut res = cfg::node_status_get(&handle, us_plus1, cfg::NodeStatusVersion::V1); if let Err(e) = res { println!("Error from node_status_get on nodeid {us_plus1}: {e}"); res = cfg::node_status_get(&handle, us_less1, cfg::NodeStatusVersion::V1); }; match res { Ok(ns) => { println!("Node Status for nodeid {}", ns.nodeid); println!(" reachable: {}", ns.reachable); println!(" remote: {}", ns.remote); println!(" onwire_min: {}", ns.onwire_min); println!(" onwire_max: {}", ns.onwire_max); println!(" onwire_ver: {}", ns.onwire_ver); for (ls_num, ls) in ns.link_status.iter().enumerate() { if ls.enabled { println!(" Link {ls_num}"); println!(" connected: {}", ls.connected); println!(" mtu: {}", ls.mtu); println!(" src: {}", ls.src_ipaddr); println!(" dst: {}", ls.dst_ipaddr); } } } Err(e) => { println!( "Error in CFG node_status get: {e} (tried nodeids {us_plus1} & {us_less1})" ); + return Err(e); } } } // This should not shutdown corosync because the callback on &handle2 will refuse it. match cfg::try_shutdown(&handle, cfg::ShutdownFlags::Request) { Ok(_) => { println!("CFG try_shutdown suceeded, should return busy"); } Err(e) => { if e != corosync::CsError::CsErrBusy { println!("Error in CFG try_shutdown: {e}"); + return Err(e); } } } - // Wait for events - loop { - if cfg::dispatch(&handle, corosync::DispatchFlags::One).is_err() { - break; - } + // Quick test of dispatch + if let Err(e) = cfg::dispatch(&handle, corosync::DispatchFlags::OneNonblocking) { + println!("Error in CFG dispatch"); + return Err(e); } - println!("ERROR: Corosync quit"); + Ok(()) } diff --git a/bindings/rust/tests/src/bin/cmap-test.rs b/bindings/rust/tests/src/bin/cmap-test.rs index 25ec722a..edc0305a 100644 --- a/bindings/rust/tests/src/bin/cmap-test.rs +++ b/bindings/rust/tests/src/bin/cmap-test.rs @@ -1,195 +1,196 @@ // Test the CMAP library. Requires that corosync is running and that we are root. extern crate rust_corosync as corosync; use corosync::cmap; fn track_notify_fn( _handle: &cmap::Handle, _track_handle: &cmap::TrackHandle, event: cmap::TrackType, key_name: &str, old_value: &cmap::Data, new_value: &cmap::Data, user_data: u64, ) { println!("Track notify callback"); println!("Key: {key_name}, event: {event}, user_data: {user_data}"); println!(" Old value: {old_value}"); println!(" New value: {new_value}"); } -fn main() { +fn main() -> Result<(), corosync::CsError> { let handle = match cmap::initialize(cmap::Map::Icmap) { Ok(h) => { println!("cmap initialized."); h } Err(e) => { println!("Error in CMAP (Icmap) init: {e}"); - return; + return Err(e); } }; // Test some SETs if let Err(e) = cmap::set_u32(&handle, "test.test_uint32", 456) { println!("Error in CMAP set_u32: {e}"); - return; + return Err(e); }; if let Err(e) = cmap::set_i16(&handle, "test.test_int16", -789) { println!("Error in CMAP set_i16: {e}"); - return; + return Err(e); }; if let Err(e) = cmap::set_number(&handle, "test.test_num_1", 6809u32) { println!("Error in CMAP set_number(u32): {e}"); - return; + return Err(e); }; // NOT PI (just to avoid clippy whingeing) if let Err(e) = cmap::set_number(&handle, "test.test_num_2", 3.24159265) { println!("Error in CMAP set_number(f32): {e}"); - return; + return Err(e); }; if let Err(e) = cmap::set_string(&handle, "test.test_string", "Hello from Rust") { println!("Error in CMAP set_string: {e}"); - return; + return Err(e); }; let test_d = cmap::Data::UInt64(0xdeadbeefbacecafe); if let Err(e) = cmap::set(&handle, "test.test_data", &test_d) { println!("Error in CMAP set_data: {e}"); - return; + return Err(e); }; // let test_d2 = cmap::Data::UInt32(6809); let test_d2 = cmap::Data::String("Test string in data 12345".to_string()); if let Err(e) = cmap::set(&handle, "test.test_again", &test_d2) { println!("Error in CMAP set_data2: {e}"); - return; + return Err(e); }; // get them back again match cmap::get(&handle, "test.test_uint32") { Ok(v) => { println!("GOT uint32 {v}"); } Err(e) => { println!("Error in CMAP get: {e}"); - return; + return Err(e); } }; match cmap::get(&handle, "test.test_int16") { Ok(v) => { println!("GOT uint16 {v}"); } Err(e) => { println!("Error in CMAP get: {e}"); - return; + return Err(e); } }; match cmap::get(&handle, "test.test_num_1") { Ok(v) => { println!("GOT num {v}"); } Err(e) => { println!("Error in CMAP get: {e}"); - return; + return Err(e); } }; match cmap::get(&handle, "test.test_num_2") { Ok(v) => { println!("GOT num {v}"); } Err(e) => { println!("Error in CMAP get: {e}"); - return; + return Err(e); } }; match cmap::get(&handle, "test.test_string") { Ok(v) => { println!("GOT string {v}"); } Err(e) => { println!("Error in CMAP get: {e}"); - return; + return Err(e); } }; match cmap::get(&handle, "test.test_data") { Ok(v) => match v { cmap::Data::UInt64(u) => println!("GOT data value {u:x}"), _ => println!("ERROR type was not UInt64, got {v}"), }, Err(e) => { println!("Error in CMAP get: {e}"); - return; + return Err(e); } }; // Test an iterator match cmap::CmapIterStart::new(&handle, "totem.") { Ok(cmap_iter) => { for i in cmap_iter { println!("ITER: {i:?}"); } println!(); } Err(e) => { println!("Error in CMAP iter start: {e}"); } } // Close this handle if let Err(e) = cmap::finalize(&handle) { println!("Error in CMAP get: {e}"); - return; + return Err(e); }; // Test notifications on the stats map let handle = match cmap::initialize(cmap::Map::Stats) { Ok(h) => h, Err(e) => { println!("Error in CMAP (Stats) init: {e}"); - return; + return Err(e); } }; let cb = cmap::NotifyCallback { notify_fn: Some(track_notify_fn), }; let _track_handle = match cmap::track_add( &handle, "stats.srp.memb_merge_detect_tx", cmap::TrackType::MODIFY | cmap::TrackType::ADD | cmap::TrackType::DELETE, &cb, 997u64, ) { Ok(th) => th, Err(e) => { println!("Error in CMAP track_add {e}"); - return; + return Err(e); } }; - // Wait for events + // Wait for some events let mut event_num = 0; loop { if let Err(e) = cmap::dispatch(&handle, corosync::DispatchFlags::One) { println!("Error from CMAP dispatch: {e}"); } // Just do 5 event_num += 1; if event_num > 5 { break; } } + Ok(()) } diff --git a/bindings/rust/tests/src/bin/cpg-test.rs b/bindings/rust/tests/src/bin/cpg-test.rs index c5a58edc..dd574940 100644 --- a/bindings/rust/tests/src/bin/cpg-test.rs +++ b/bindings/rust/tests/src/bin/cpg-test.rs @@ -1,142 +1,146 @@ // Test the CPG library. Requires that corosync is running and that we are root. extern crate rust_corosync as corosync; use corosync::{cpg, NodeId}; use std::str; fn deliver_fn( _handle: &cpg::Handle, group_name: String, nodeid: NodeId, pid: u32, msg: &[u8], msg_len: usize, ) { println!( "TEST deliver_fn called for {group_name}, from nodeid/pid {nodeid}/{pid}. len={msg_len}" ); // Print as text if it's valid UTF8 match str::from_utf8(msg) { Ok(s) => println!(" {s}"), Err(_) => { for i in msg { print!("{i:02x} "); } println!(); } } } fn confchg_fn( _handle: &cpg::Handle, group_name: &str, member_list: Vec, left_list: Vec, joined_list: Vec, ) { println!("TEST confchg_fn called for {group_name}"); println!(" members: {member_list:?}"); println!(" left: {left_list:?}"); println!(" joined: {joined_list:?}"); } fn totem_confchg_fn(_handle: &cpg::Handle, ring_id: cpg::RingId, member_list: Vec) { println!( "TEST totem_confchg_fn called for {}/{}", ring_id.nodeid, ring_id.seq ); println!(" members: {member_list:?}"); } -fn main() { +fn main() -> Result<(), corosync::CsError> { // Initialise the model data let md = cpg::ModelData::ModelV1(cpg::Model1Data { flags: cpg::Model1Flags::None, deliver_fn: Some(deliver_fn), confchg_fn: Some(confchg_fn), totem_confchg_fn: Some(totem_confchg_fn), }); let handle = match cpg::initialize(&md, 99_u64) { Ok(h) => h, Err(e) => { println!("Error in CPG init: {e}"); - return; + return Err(e); } }; if let Err(e) = cpg::join(&handle, "TEST") { println!("Error in CPG join: {e}"); - return; + return Err(e); } match cpg::local_get(&handle) { Ok(n) => { println!("Local nodeid is {n}"); } Err(e) => { println!("Error in CPG local_get: {e}"); + return Err(e); } } // Test membership_get() match cpg::membership_get(&handle, "TEST") { Ok(m) => { println!(" members: {m:?}"); println!(); } Err(e) => { println!("Error in CPG membership_get: {e}"); + return Err(e); } } // Test context APIs let set_context: u64 = 0xabcdbeefcafe; if let Err(e) = cpg::context_set(&handle, set_context) { println!("Error in CPG context_set: {e}"); - return; + return Err(e); } // NOTE This will fail on 32 bit systems because void* is not u64 match cpg::context_get(&handle) { Ok(c) => { if c != set_context { println!("Error: context_get() returned {c:x}, context should be {set_context:x}"); } } Err(e) => { println!("Error in CPG context_get: {e}"); + return Err(e); } } // Test iterator match cpg::CpgIterStart::new(&handle, "", cpg::CpgIterType::All) { Ok(cpg_iter) => { for i in cpg_iter { println!("ITER: {i:?}"); } println!(); } Err(e) => { println!("Error in CPG iter start: {e}"); + return Err(e); } } // We should receive our own message (at least) in the event loop if let Err(e) = cpg::mcast_joined( &handle, cpg::Guarantee::TypeAgreed, &"This is a test".to_string().into_bytes(), ) { println!("Error in CPG mcast_joined: {e}"); + return Err(e); } - // Wait for events - loop { - if cpg::dispatch(&handle, corosync::DispatchFlags::One).is_err() { - break; - } + // Quick test of dispatch + if let Err(e) = cpg::dispatch(&handle, corosync::DispatchFlags::OneNonblocking) { + println!("Error in CPG dispatch: {e}"); + return Err(e); } - println!("ERROR: Corosync quit"); + Ok(()) } diff --git a/bindings/rust/tests/src/bin/quorum-test.rs b/bindings/rust/tests/src/bin/quorum-test.rs index 9436b392..ae7404ec 100644 --- a/bindings/rust/tests/src/bin/quorum-test.rs +++ b/bindings/rust/tests/src/bin/quorum-test.rs @@ -1,83 +1,84 @@ // Test the QUORUM library. Requires that corosync is running and that we are root. extern crate rust_corosync as corosync; use corosync::{quorum, NodeId}; fn quorum_fn( _handle: &quorum::Handle, quorate: bool, ring_id: quorum::RingId, member_list: Vec, ) { println!("TEST quorum_fn called. quorate = {quorate}"); println!(" ring_id: {}/{}", ring_id.nodeid, ring_id.seq); println!(" members: {member_list:?}"); } fn nodelist_fn( _handle: &quorum::Handle, ring_id: quorum::RingId, member_list: Vec, joined_list: Vec, left_list: Vec, ) { println!( "TEST nodelist_fn called for {}/{}", ring_id.nodeid, ring_id.seq ); println!(" members: {member_list:?}"); println!(" joined: {joined_list:?}"); println!(" left: {left_list:?}"); } -fn main() { +fn main() -> Result<(), corosync::CsError> { // Initialise the model data let md = quorum::ModelData::ModelV1(quorum::Model1Data { flags: quorum::Model1Flags::None, quorum_notification_fn: Some(quorum_fn), nodelist_notification_fn: Some(nodelist_fn), }); let handle = match quorum::initialize(&md, 99_u64) { Ok((h, t)) => { println!("Quorum initialized; type = {}", t as u32); h } Err(e) => { println!("Error in QUORUM init: {e}"); - return; + return Err(e); } }; // Test context APIs let set_context: u64 = 0xabcdbeefcafe; if let Err(e) = quorum::context_set(&handle, set_context) { println!("Error in QUORUM context_set: {e}"); - return; + return Err(e); } // NOTE This will fail on 32 bit systems because void* is not u64 match quorum::context_get(&handle) { Ok(c) => { if c != set_context { println!("Error: context_get() returned {c:x}, context should be {set_context:x}"); + return Err(corosync::CsError::CsErrRustCompat); } } Err(e) => { println!("Error in QUORUM context_get: {e}"); + return Err(e); } } if let Err(e) = quorum::trackstart(&handle, corosync::TrackFlags::Changes) { println!("Error in QUORUM trackstart: {e}"); - return; + return Err(e); } - // Wait for events - loop { - if quorum::dispatch(&handle, corosync::DispatchFlags::One).is_err() { - break; - } + // Quick test of dispatch + if let Err(e) = quorum::dispatch(&handle, corosync::DispatchFlags::OneNonblocking) { + println!("Error in QUORUM dispatch: {e}"); + return Err(e); } - println!("ERROR: Corosync quit"); + Ok(()) } diff --git a/bindings/rust/tests/src/bin/votequorum-test.rs b/bindings/rust/tests/src/bin/votequorum-test.rs index eebc9f0d..d37100a4 100644 --- a/bindings/rust/tests/src/bin/votequorum-test.rs +++ b/bindings/rust/tests/src/bin/votequorum-test.rs @@ -1,117 +1,122 @@ // Test the VOTEQUORUM library. Requires that corosync is running and that we are root. extern crate rust_corosync as corosync; use corosync::votequorum; fn quorum_fn( _handle: &votequorum::Handle, _context: u64, quorate: bool, member_list: Vec, ) { println!("TEST votequorum_quorum_fn called. quorate = {quorate}"); println!(" members: {member_list:?}"); } fn nodelist_fn( _handle: &votequorum::Handle, _context: u64, ring_id: votequorum::RingId, member_list: Vec, ) { println!( "TEST nodelist_fn called for {}/{}", ring_id.nodeid, ring_id.seq ); println!(" members: {member_list:?}"); } fn expectedvotes_fn(_handle: &votequorum::Handle, _context: u64, expected_votes: u32) { println!("TEST expected_votes_fn called: value is {expected_votes}"); } -fn main() { +fn main() -> Result<(), corosync::CsError> { // Initialise the model data let cb = votequorum::Callbacks { quorum_notification_fn: Some(quorum_fn), nodelist_notification_fn: Some(nodelist_fn), expectedvotes_notification_fn: Some(expectedvotes_fn), }; let handle = match votequorum::initialize(&cb) { Ok(h) => { println!("Votequorum initialized."); h } Err(e) => { println!("Error in VOTEQUORUM init: {e}"); - return; + return Err(e); } }; // Test context APIs let set_context: u64 = 0xabcdbeefcafe; if let Err(e) = votequorum::context_set(&handle, set_context) { println!("Error in VOTEQUORUM context_set: {e}"); + return Err(e); } // NOTE This will fail on 32 bit systems because void* is not u64 match votequorum::context_get(&handle) { Ok(c) => { if c != set_context { println!("Error: context_get() returned {c:x}, context should be {set_context:x}"); } } Err(e) => { println!("Error in VOTEQUORUM context_get: {e}"); + return Err(e); } } const QDEVICE_NAME: &str = "RustQdevice"; if let Err(e) = votequorum::qdevice_register(&handle, QDEVICE_NAME) { println!("Error in VOTEQUORUM qdevice_register: {e}"); + return Err(e); } match votequorum::get_info(&handle, corosync::NodeId::from(1u32)) { Ok(i) => { println!("Node info for nodeid 1"); println!(" nodeid: {}", i.node_id); println!(" node_state: {:?}", i.node_state); println!(" node_votes: {}", i.node_votes); println!(" node_expected: {}", i.node_expected_votes); println!(" highest_expected: {}", i.highest_expected); println!(" quorum: {}", i.quorum); println!(" flags: {:x}", i.flags); println!(" qdevice_votes: {}", i.qdevice_votes); println!(" qdevice_name: {}", i.qdevice_name); if i.qdevice_name != QDEVICE_NAME { println!( "qdevice names do not match: s/b: \"{}\" is: \"{}\"", QDEVICE_NAME, i.qdevice_name ); + return Err(corosync::CsError::CsErrRustCompat); } } Err(e) => { println!("Error in VOTEQUORUM get_info: {e} (check nodeid 1 has been online)"); + return Err(e); } } if let Err(e) = votequorum::qdevice_unregister(&handle, QDEVICE_NAME) { println!("Error in VOTEQUORUM qdevice_unregister: {e}"); + return Err(e); } if let Err(e) = votequorum::trackstart(&handle, 99_u64, corosync::TrackFlags::Changes) { println!("Error in VOTEQUORUM trackstart: {e}"); - return; + return Err(e); } - // Wait for events - loop { - if votequorum::dispatch(&handle, corosync::DispatchFlags::One).is_err() { - break; - } + // Quick test of dispatch + if let Err(e) = votequorum::dispatch(&handle, corosync::DispatchFlags::OneNonblocking) { + println!("Error in VOTEUORUM dispatch: {e}"); + return Err(e); } - println!("ERROR: Corosync quit"); + Ok(()) }