Skip to content

Commit

Permalink
Add a few basic integration tests
Browse files Browse the repository at this point in the history
I created a few basic integration tests to complement the bindgen auto-generated test suite.
  • Loading branch information
Daniel Noland authored and Daniel Noland committed Jun 5, 2021
1 parent a6a2a46 commit 914dcc2
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 0 deletions.
34 changes: 34 additions & 0 deletions scripts/make-rdma-loopback.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env bash

set -euxETo pipefail

declare -r RXE_INTERFACE_NAME="rust_ibverbs"

# Print an error message
log_err() {
>&2 echo "${*}"
}

# Determine if netns state of rdma devices is shared or exclusive
get_rdma_netns_state() {
# Note: for some reason rdma system does not seem to support json output at the moment.
# Thus we need to parse the output, can't use jq
rdma system show | grep netns | awk '{print $NF}'
}

# Check that our rdma devices are available across network namespaces
confirm_rdma_netns_shared() {
declare access
access="$(get_rdma_netns_state)"
declare -r access
if [[ "${access}" != "shared" ]]; then
log_err "rdma netns state is not shared: current state ${access}"
return 1
fi
}

confirm_rdma_netns_shared
ip link add root type dummy
ip link add link root name "${RXE_INTERFACE_NAME}" type macvlan mode bridge
rdma link add "${RXE_INTERFACE_NAME}" type rxe netdev "${RXE_INTERFACE_NAME}"
ip link set group default up
7 changes: 7 additions & 0 deletions scripts/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash

set -euxETo pipefail

sudo ./scripts/make-rdma-loopback.sh

cargo test
132 changes: 132 additions & 0 deletions tests/integration/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#[test]
fn can_list_rdma_devices() {
ibverbs::devices().expect("Could not fetch list of rdma devices");
}

#[test]
fn list_of_rdma_devices_contains_test_device() {
let device_list = ibverbs::devices().expect("Could not fetch list of rdma devices");
helper::test_device(&device_list).expect("Could not find RDMA test device");
}

#[test]
fn can_open_test_device() {
let device_list = ibverbs::devices().expect("Could not fetch list of rdma devices");
let test_device = helper::test_device(&device_list).expect("Could not find RDMA test device");
test_device.open().expect("Could not open test device");
}

#[test]
fn test_device_can_open_then_close_then_open() {
let device_list = ibverbs::devices().expect("Could not fetch list of rdma devices");
{
let test_device = helper::test_device(&device_list).expect("Could not find RDMA test device");
test_device.open().expect("Could not open test device");
}
{
let test_device = helper::test_device(&device_list).expect("Could not find RDMA test device");
test_device.open().expect("Could not open test device");
}
}

#[test]
fn can_send_rdma_loopback_traffic_on_test_device() {
const MINIMUM_COMPLETION_QUEUE_SIZE: i32 = 128;
let completion_queue_id = 129;

let device_list = ibverbs::devices().expect("Could not fetch list of rdma devices");
let test_device = helper::test_device(&device_list).expect("Could not find RDMA test device");
let context = test_device.open().expect("Could not open test device");
let completion_queue = context
.create_cq(MINIMUM_COMPLETION_QUEUE_SIZE, completion_queue_id)
.expect("Could not create completion queue");
let protection_domain = context
.alloc_pd()
.expect("Could not allocate protection domain");

let prepared_queue_pair = protection_domain
.create_qp(
&completion_queue,
&completion_queue,
ibverbs::ibv_qp_type::IBV_QPT_RC,
)
.build()
.expect("Could not create prepared queue pair");

let endpoint = prepared_queue_pair.endpoint();
let mut queue_pair = prepared_queue_pair
.handshake(endpoint)
.expect("Could not create queue pair");

let mut memory_region = protection_domain
.allocate::<u64>(2)
.expect("Could not allocate memory region");

let message = 0x42;
memory_region[1] = message;

let send_work_request_id = 1;
let receive_work_request_id = 2;

unsafe {
queue_pair
.post_receive(&mut memory_region, ..1, receive_work_request_id)
.expect("failed to post receive request on queue pair");
queue_pair
.post_send(&mut memory_region, 1.., send_work_request_id)
.expect("failed to post send request on queue pair");
}

let mut sent = false;
let mut received = false;

let mut completions = [ibverbs::ibv_wc::default(); MINIMUM_COMPLETION_QUEUE_SIZE as usize];

while !(sent && received) {
let completed = completion_queue
.poll(&mut completions[..])
.expect("failed to poll completion queue");
if completed.is_empty() {
continue;
}
assert!(completed.len() <= 2);
for completion in completed {
match completion.wr_id() {
1 => {
assert!(!sent);
sent = true;
}
2 => {
assert!(!received);
received = true;
assert_eq!(memory_region[0], message);
}
_ => unreachable!()
}
}
}
}

mod helper {
use ibverbs::{Device, DeviceList};

pub fn test_device(device_list: &DeviceList) -> Option<Device> {
device_list.iter().find_map(|rdma_device| {
if let Some(device_name_cstr) = rdma_device.name() {
match device_name_cstr.to_str() {
Ok(device_name) => {
if device_name == "rust_ibverbs" {
Some(rdma_device)
} else {
None
}
},
Err(_) => None
}
} else {
None
}
})
}
}

0 comments on commit 914dcc2

Please sign in to comment.