Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented a test attribute macro #209

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
- uses: actions/checkout@v3
- name: Install Rust
run: rustup update stable
- run: cargo bench --no-run
- run: cargo bench --no-run --all-features

check:
runs-on: ubuntu-latest
Expand All @@ -57,15 +57,15 @@ jobs:
- uses: actions/checkout@v3
- name: Install Rust
run: rustup update stable
- run: cargo test
- run: cargo test --all-features

test-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Rust
run: rustup update stable
- run: cargo test --doc
- run: cargo test --doc --all-features

fmt:
runs-on: ubuntu-latest
Expand Down
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ io-uring support for the Tokio asynchronous runtime.
categories = ["asynchronous", "network-programming"]
keywords = ["async", "fs", "io-uring"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = []
macros = ["tokio-uring-macros"]
full = ["macros"]

[dependencies]
tokio = { version = "1.2", features = ["net", "rt"] }
Expand All @@ -24,6 +27,8 @@ io-uring = { version = "0.5.9", features = ["unstable"] }
socket2 = { version = "0.4.4", features = ["all"] }
bytes = { version = "1.0", optional = true }

tokio-uring-macros = { version = "0.1.0", path = "./tokio-uring-macros", optional = true }

[dev-dependencies]
tempfile = "3.2.0"
tokio-test = "0.4.2"
Expand Down
8 changes: 3 additions & 5 deletions src/io/noop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@ impl Completable for NoOp {
mod test {
use crate as tokio_uring;

#[test]
fn perform_no_op() -> () {
tokio_uring::start(async {
tokio_uring::no_op().await.unwrap();
})
#[tokio_uring::test]
async fn perform_no_op() {
tokio_uring::no_op().await.unwrap();
}
}
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,7 @@ pub async fn no_op() -> std::io::Result<()> {
let op = Op::<io::NoOp>::no_op().unwrap();
op.await
}

#[cfg(feature = "macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
pub use tokio_uring_macros::test;
2 changes: 1 addition & 1 deletion src/runtime/driver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ mod test {
Completion {
result: cqe.result,
flags: cqe.flags,
data: self.clone(),
data: self,
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,13 @@ mod test {
#[test]
fn block_on() {
let rt = Runtime::new(&builder()).unwrap();
rt.block_on(async move { () });
rt.block_on(async move {});
}

#[test]
fn block_on_twice() {
let rt = Runtime::new(&builder()).unwrap();
rt.block_on(async move { () });
rt.block_on(async move { () });
rt.block_on(async move {});
rt.block_on(async move {});
}
}
20 changes: 9 additions & 11 deletions tests/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,19 +75,17 @@ fn complete_ops_on_drop() {
drop(file);
}

#[test]
fn too_many_submissions() {
#[tokio_uring::test]
async fn too_many_submissions() {
let tempfile = tempfile();

tokio_uring::start(async {
let file = File::create(tempfile.path()).await.unwrap();
for _ in 0..600 {
poll_once(async {
file.write_at(b"hello world".to_vec(), 0).await.0.unwrap();
})
.await;
}
});
let file = File::create(tempfile.path()).await.unwrap();
for _ in 0..600 {
poll_once(async {
file.write_at(b"hello world".to_vec(), 0).await.0.unwrap();
})
.await;
}
}

#[test]
Expand Down
216 changes: 105 additions & 111 deletions tests/fixed_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,132 +9,126 @@ use tempfile::NamedTempFile;

const HELLO: &[u8] = b"hello world...";

#[test]
fn fixed_buf_turnaround() {
tokio_uring::start(async {
let mut tempfile = tempfile();
tempfile.write_all(HELLO).unwrap();
#[tokio_uring::test]
async fn fixed_buf_turnaround() {
let mut tempfile = tempfile();
tempfile.write_all(HELLO).unwrap();

let file = File::open(tempfile.path()).await.unwrap();
let file = File::open(tempfile.path()).await.unwrap();

let buffers = FixedBufRegistry::new([30, 20, 10].iter().map(|&n| Vec::with_capacity(n)));
buffers.register().unwrap();
let buffers = FixedBufRegistry::new([30, 20, 10].iter().map(|&n| Vec::with_capacity(n)));
buffers.register().unwrap();

let fixed_buf = buffers.check_out(0).unwrap();
assert_eq!(fixed_buf.bytes_total(), 30);
let fixed_buf = buffers.check_out(0).unwrap();
assert_eq!(fixed_buf.bytes_total(), 30);

// Can't check out the same buffer twice.
assert!(buffers.check_out(0).is_none());
// Can't check out the same buffer twice.
assert!(buffers.check_out(0).is_none());

// Checking out another buffer from the same registry is possible,
// but does not affect the status of the first buffer.
let fixed_buf1 = buffers.check_out(1).unwrap();
assert_eq!(fixed_buf1.bytes_total(), 20);
assert!(buffers.check_out(0).is_none());
mem::drop(fixed_buf1);
assert!(buffers.check_out(0).is_none());
// Checking out another buffer from the same registry is possible,
// but does not affect the status of the first buffer.
let fixed_buf1 = buffers.check_out(1).unwrap();
assert_eq!(fixed_buf1.bytes_total(), 20);
assert!(buffers.check_out(0).is_none());
mem::drop(fixed_buf1);
assert!(buffers.check_out(0).is_none());

let op = file.read_fixed_at(fixed_buf, 0);
let op = file.read_fixed_at(fixed_buf, 0);

// The buffer is used by the pending operation, can't check it out
// for another instance.
assert!(buffers.check_out(0).is_none());
// The buffer is used by the pending operation, can't check it out
// for another instance.
assert!(buffers.check_out(0).is_none());

let (res, buf) = op.await;
let n = res.unwrap();
assert_eq!(n, HELLO.len());
let (res, buf) = op.await;
let n = res.unwrap();
assert_eq!(n, HELLO.len());

// The buffer is owned by `buf`, can't check it out
// for another instance.
assert!(buffers.check_out(0).is_none());
// The buffer is owned by `buf`, can't check it out
// for another instance.
assert!(buffers.check_out(0).is_none());

mem::drop(buf);
mem::drop(buf);

// The buffer has been released, check it out again.
let fixed_buf = buffers.check_out(0).unwrap();
assert_eq!(fixed_buf.bytes_total(), 30);
assert_eq!(fixed_buf.bytes_init(), HELLO.len());
});
// The buffer has been released, check it out again.
let fixed_buf = buffers.check_out(0).unwrap();
assert_eq!(fixed_buf.bytes_total(), 30);
assert_eq!(fixed_buf.bytes_init(), HELLO.len());
}

#[test]
fn unregister_invalidates_checked_out_buffers() {
tokio_uring::start(async {
let mut tempfile = tempfile();
tempfile.write_all(HELLO).unwrap();

let file = File::open(tempfile.path()).await.unwrap();

let buffers = FixedBufRegistry::new([Vec::with_capacity(1024)]);
buffers.register().unwrap();

let fixed_buf = buffers.check_out(0).unwrap();

// The checked out handle keeps the buffer allocation alive.
// Meanwhile, we replace buffer registration in the kernel:
buffers.unregister().unwrap();
let buffers = FixedBufRegistry::new([Vec::with_capacity(1024)]);
buffers.register().unwrap();

// The old buffer's index no longer matches the memory area of the
// currently registered buffer, so the read operation using the old
// buffer's memory should fail.
let (res, _) = file.read_fixed_at(fixed_buf, 0).await;
assert_err!(res);

let fixed_buf = buffers.check_out(0).unwrap();
let (res, buf) = file.read_fixed_at(fixed_buf, 0).await;
let n = res.unwrap();
assert_eq!(n, HELLO.len());
assert_eq!(&buf[..], HELLO);
});
#[tokio_uring::test]
async fn unregister_invalidates_checked_out_buffers() {
let mut tempfile = tempfile();
tempfile.write_all(HELLO).unwrap();

let file = File::open(tempfile.path()).await.unwrap();

let buffers = FixedBufRegistry::new([Vec::with_capacity(1024)]);
buffers.register().unwrap();

let fixed_buf = buffers.check_out(0).unwrap();

// The checked out handle keeps the buffer allocation alive.
// Meanwhile, we replace buffer registration in the kernel:
buffers.unregister().unwrap();
let buffers = FixedBufRegistry::new([Vec::with_capacity(1024)]);
buffers.register().unwrap();

// The old buffer's index no longer matches the memory area of the
// currently registered buffer, so the read operation using the old
// buffer's memory should fail.
let (res, _) = file.read_fixed_at(fixed_buf, 0).await;
assert_err!(res);

let fixed_buf = buffers.check_out(0).unwrap();
let (res, buf) = file.read_fixed_at(fixed_buf, 0).await;
let n = res.unwrap();
assert_eq!(n, HELLO.len());
assert_eq!(&buf[..], HELLO);
}

#[test]
fn slicing() {
tokio_uring::start(async {
let mut tempfile = tempfile();
tempfile.write_all(HELLO).unwrap();

let file = File::from_std(
std::fs::File::options()
.read(true)
.write(true)
.open(tempfile.path())
.unwrap(),
);

let buffers = FixedBufRegistry::new([Vec::with_capacity(1024)]);
buffers.register().unwrap();

let fixed_buf = buffers.check_out(0).unwrap();

// Read no more than 8 bytes into the fixed buffer.
let (res, slice) = file.read_fixed_at(fixed_buf.slice(..8), 3).await;
let n = res.unwrap();
assert_eq!(n, 8);
assert_eq!(slice[..], HELLO[3..11]);
let fixed_buf = slice.into_inner();

// Write from the fixed buffer, starting at offset 1,
// up to the end of the initialized bytes in the buffer.
let (res, slice) = file
.write_fixed_at(fixed_buf.slice(1..), HELLO.len() as u64)
.await;
let n = res.unwrap();
assert_eq!(n, 7);
assert_eq!(slice[..], HELLO[4..11]);
let fixed_buf = slice.into_inner();

// Read into the fixed buffer, overwriting bytes starting from offset 3
// and then extending the initialized part with as many bytes as
// the operation can read.
let (res, slice) = file.read_fixed_at(fixed_buf.slice(3..), 0).await;
let n = res.unwrap();
assert_eq!(n, HELLO.len() + 7);
assert_eq!(slice[..HELLO.len()], HELLO[..]);
assert_eq!(slice[HELLO.len()..], HELLO[4..11]);
})
#[tokio_uring::test]
async fn slicing() {
let mut tempfile = tempfile();
tempfile.write_all(HELLO).unwrap();

let file = File::from_std(
std::fs::File::options()
.read(true)
.write(true)
.open(tempfile.path())
.unwrap(),
);

let buffers = FixedBufRegistry::new([Vec::with_capacity(1024)]);
buffers.register().unwrap();

let fixed_buf = buffers.check_out(0).unwrap();

// Read no more than 8 bytes into the fixed buffer.
let (res, slice) = file.read_fixed_at(fixed_buf.slice(..8), 3).await;
let n = res.unwrap();
assert_eq!(n, 8);
assert_eq!(slice[..], HELLO[3..11]);
let fixed_buf = slice.into_inner();

// Write from the fixed buffer, starting at offset 1,
// up to the end of the initialized bytes in the buffer.
let (res, slice) = file
.write_fixed_at(fixed_buf.slice(1..), HELLO.len() as u64)
.await;
let n = res.unwrap();
assert_eq!(n, 7);
assert_eq!(slice[..], HELLO[4..11]);
let fixed_buf = slice.into_inner();

// Read into the fixed buffer, overwriting bytes starting from offset 3
// and then extending the initialized part with as many bytes as
// the operation can read.
let (res, slice) = file.read_fixed_at(fixed_buf.slice(3..), 0).await;
let n = res.unwrap();
assert_eq!(n, HELLO.len() + 7);
assert_eq!(slice[..HELLO.len()], HELLO[..]);
assert_eq!(slice[HELLO.len()..], HELLO[4..11]);
}

fn tempfile() -> NamedTempFile {
Expand Down
28 changes: 12 additions & 16 deletions tests/fs_directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,20 @@ use tokio_uring::fs;

use tempfile::tempdir;

#[test]
fn basic_create_dir() {
tokio_uring::start(async {
let base_dir = tempdir().unwrap();
let new_dir = base_dir.path().join("foo");
let new_dir_2 = new_dir.clone();
#[tokio_uring::test]
async fn basic_create_dir() {
let base_dir = tempdir().unwrap();
let new_dir = base_dir.path().join("foo");
let new_dir_2 = new_dir.clone();

assert_ok!(fs::create_dir(new_dir).await);
assert_ok!(fs::create_dir(new_dir).await);

assert!(new_dir_2.is_dir());
});
assert!(new_dir_2.is_dir());
}

#[test]
fn basic_remove_dir() {
tokio_uring::start(async {
let temp_dir = tempfile::TempDir::new().unwrap();
tokio_uring::fs::remove_dir(temp_dir.path()).await.unwrap();
assert!(std::fs::metadata(temp_dir.path()).is_err());
});
#[tokio_uring::test]
async fn basic_remove_dir() {
let temp_dir = tempfile::TempDir::new().unwrap();
tokio_uring::fs::remove_dir(temp_dir.path()).await.unwrap();
assert!(std::fs::metadata(temp_dir.path()).is_err());
}
Loading