summaryrefslogtreecommitdiffstats
path: root/bindings/rust/tests/src
diff options
context:
space:
mode:
Diffstat (limited to 'bindings/rust/tests/src')
-rw-r--r--bindings/rust/tests/src/bin/cfg-test.rs135
-rw-r--r--bindings/rust/tests/src/bin/cmap-test.rs195
-rw-r--r--bindings/rust/tests/src/bin/cpg-test.rs142
-rw-r--r--bindings/rust/tests/src/bin/quorum-test.rs83
-rw-r--r--bindings/rust/tests/src/bin/votequorum-test.rs117
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");
+}