diff options
Diffstat (limited to 'bindings/rust/tests/src')
-rw-r--r-- | bindings/rust/tests/src/bin/cfg-test.rs | 135 | ||||
-rw-r--r-- | bindings/rust/tests/src/bin/cmap-test.rs | 195 | ||||
-rw-r--r-- | bindings/rust/tests/src/bin/cpg-test.rs | 142 | ||||
-rw-r--r-- | bindings/rust/tests/src/bin/quorum-test.rs | 83 | ||||
-rw-r--r-- | bindings/rust/tests/src/bin/votequorum-test.rs | 117 |
5 files changed, 672 insertions, 0 deletions
diff --git a/bindings/rust/tests/src/bin/cfg-test.rs b/bindings/rust/tests/src/bin/cfg-test.rs new file mode 100644 index 0000000..cd70d38 --- /dev/null +++ b/bindings/rust/tests/src/bin/cfg-test.rs @@ -0,0 +1,135 @@ +// 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() { + // 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; + } + }; + + // 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; + } + }; + + 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}"); + } + }; + + 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 + } + } + }; + + // 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})" + ); + } + } + } + + // 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}"); + } + } + } + + // Wait for events + loop { + if cfg::dispatch(handle, corosync::DispatchFlags::One).is_err() { + break; + } + } + println!("ERROR: Corosync quit"); +} diff --git a/bindings/rust/tests/src/bin/cmap-test.rs b/bindings/rust/tests/src/bin/cmap-test.rs new file mode 100644 index 0000000..f435653 --- /dev/null +++ b/bindings/rust/tests/src/bin/cmap-test.rs @@ -0,0 +1,195 @@ +// 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() { + let handle = match cmap::initialize(cmap::Map::Icmap) { + Ok(h) => { + println!("cmap initialized."); + h + } + Err(e) => { + println!("Error in CMAP (Icmap) init: {e}"); + return; + } + }; + + // Test some SETs + if let Err(e) = cmap::set_u32(handle, "test.test_uint32", 456) { + println!("Error in CMAP set_u32: {e}"); + return; + }; + + if let Err(e) = cmap::set_i16(handle, "test.test_int16", -789) { + println!("Error in CMAP set_i16: {e}"); + return; + }; + + if let Err(e) = cmap::set_number(handle, "test.test_num_1", 6809u32) { + println!("Error in CMAP set_number(u32): {e}"); + return; + }; + + // 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; + }; + + if let Err(e) = cmap::set_string(handle, "test.test_string", "Hello from Rust") { + println!("Error in CMAP set_string: {e}"); + return; + }; + + 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; + }; + + // 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; + }; + + // 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; + } + }; + match cmap::get(handle, "test.test_int16") { + Ok(v) => { + println!("GOT uint16 {v}"); + } + + Err(e) => { + println!("Error in CMAP get: {e}"); + return; + } + }; + + match cmap::get(handle, "test.test_num_1") { + Ok(v) => { + println!("GOT num {v}"); + } + + Err(e) => { + println!("Error in CMAP get: {e}"); + return; + } + }; + match cmap::get(handle, "test.test_num_2") { + Ok(v) => { + println!("GOT num {v}"); + } + + Err(e) => { + println!("Error in CMAP get: {e}"); + return; + } + }; + match cmap::get(handle, "test.test_string") { + Ok(v) => { + println!("GOT string {v}"); + } + + Err(e) => { + println!("Error in CMAP get: {e}"); + return; + } + }; + + 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; + } + }; + + // 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; + }; + + // 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; + } + }; + + 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; + } + }; + + // Wait for 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; + } + } +} diff --git a/bindings/rust/tests/src/bin/cpg-test.rs b/bindings/rust/tests/src/bin/cpg-test.rs new file mode 100644 index 0000000..df83c2d --- /dev/null +++ b/bindings/rust/tests/src/bin/cpg-test.rs @@ -0,0 +1,142 @@ +// 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<cpg::Address>, + left_list: Vec<cpg::Address>, + joined_list: Vec<cpg::Address>, +) { + 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<NodeId>) { + println!( + "TEST totem_confchg_fn called for {}/{}", + ring_id.nodeid, ring_id.seq + ); + println!(" members: {member_list:?}"); +} + +fn main() { + // 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; + } + }; + + if let Err(e) = cpg::join(handle, "TEST") { + println!("Error in CPG join: {e}"); + return; + } + + match cpg::local_get(handle) { + Ok(n) => { + println!("Local nodeid is {n}"); + } + Err(e) => { + println!("Error in CPG local_get: {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}"); + } + } + + // 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; + } + + // 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}"); + } + } + + // 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}"); + } + } + + // 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}"); + } + + // Wait for events + loop { + if cpg::dispatch(handle, corosync::DispatchFlags::One).is_err() { + break; + } + } + println!("ERROR: Corosync quit"); +} diff --git a/bindings/rust/tests/src/bin/quorum-test.rs b/bindings/rust/tests/src/bin/quorum-test.rs new file mode 100644 index 0000000..5797b7d --- /dev/null +++ b/bindings/rust/tests/src/bin/quorum-test.rs @@ -0,0 +1,83 @@ +// 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<NodeId>, +) { + 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<NodeId>, + joined_list: Vec<NodeId>, + left_list: Vec<NodeId>, +) { + 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() { + // 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; + } + }; + + // 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; + } + + // 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}"); + } + } + Err(e) => { + println!("Error in QUORUM context_get: {e}"); + } + } + + if let Err(e) = quorum::trackstart(handle, corosync::TrackFlags::Changes) { + println!("Error in QUORUM trackstart: {e}"); + return; + } + + // Wait for events + loop { + if quorum::dispatch(handle, corosync::DispatchFlags::One).is_err() { + break; + } + } + println!("ERROR: Corosync quit"); +} diff --git a/bindings/rust/tests/src/bin/votequorum-test.rs b/bindings/rust/tests/src/bin/votequorum-test.rs new file mode 100644 index 0000000..cf9746b --- /dev/null +++ b/bindings/rust/tests/src/bin/votequorum-test.rs @@ -0,0 +1,117 @@ +// 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<votequorum::Node>, +) { + 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<corosync::NodeId>, +) { + 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() { + // 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; + } + }; + + // 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}"); + } + + // 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}"); + } + } + + const QDEVICE_NAME: &str = "RustQdevice"; + + if let Err(e) = votequorum::qdevice_register(handle, QDEVICE_NAME) { + println!("Error in VOTEQUORUM qdevice_register: {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 + ); + } + } + Err(e) => { + println!("Error in VOTEQUORUM get_info: {e} (check nodeid 1 has been online)"); + } + } + + if let Err(e) = votequorum::qdevice_unregister(handle, QDEVICE_NAME) { + println!("Error in VOTEQUORUM qdevice_unregister: {e}"); + } + + if let Err(e) = votequorum::trackstart(handle, 99_u64, corosync::TrackFlags::Changes) { + println!("Error in VOTEQUORUM trackstart: {e}"); + return; + } + + // Wait for events + loop { + if votequorum::dispatch(handle, corosync::DispatchFlags::One).is_err() { + break; + } + } + println!("ERROR: Corosync quit"); +} |