Is a stable, 1.0 release planned
nwalfield opened this issue Β· comments
First, thanks for working on rstest. We're considering using it in sequoia. Looking at rstest's history, it seems that the code and API are relatively stable. The last 10 releases, however, have all been major version bumps. How stable do you consider rstest's API? Are you planning to release 1.0 any time soon?
Looking at the project's statistics, this seems to be a one person project. Do you plan to continue to develop rstest? Do you have any funding? Are you interested in funding?
Thanks for your help!
Yes it is stable. I mean, I'll introduce new features but no breaking change... The only breaking change is that I'll remove the old syntax in the 1.0.0
version.
I'm waiting to create the 1.0 version because there're some things that I would decide before like include rstest_reuse
or introduce a test context.
Anyway I'll answer all your questions one by one:
- How stable do you consider rstest's API? The API are stable and I'll not introduce any breaking change apart remove the deprecated old compact syntax
- Are you planning to release 1.0 any time soon? Hard to say. I would, but I've not planed it yet.
- Do you plan to continue to develop rstest? For sure, I love it. My only concern is that I didn't have too much time to invest (I've a family and 3 child....
rstest
is the fourth but the other 3 come before π - Do you have any funding? No π’ . I ask to my company to give me some days in a month to develop it but for now they don't give me any news.
- Are you interested in funding? : sure π ! Transform a pet project in business would be amazing... Do you have any opportunity?
Thanks for following up. It's important to me that the downstream projects that we depend on want to fulfill my expectations; I don't want to cause undue stress.
Are you interested in funding? : sure smile ! Transform a pet project in business would be amazing... Do you have any opportunity?
We do provide some funding for some of our dependencies, but it's far from enough to quit your job over. I'm sorry if I raised your expectations.
I never thought to quit my job π ... But find some founds can be a motivation to invest more time on rstest
π
I'm waiting to create the 1.0 version because there're some things that I would decide before like include rstest_reuse or introduce a test context.
By that, do you perhaps mean something like the test_context crate? If so, I can offer one use case for it: in my integration tests, I'm calling a helper function that creates a new database and gives it to the Axum server, which is then shuttled off into its own Tokio task. But because that task will never stop (and will have to be terminated by the test runner), the server retains a connection to the test database indefinitely, so Postgres won't let me drop the database. (Manually terminating the Tokio task requires async
, so I can't do it from Drop::drop()
.)
I worked around that by returning a DIY "harness", which looks like this:
pub struct Harness {
server_handle: JoinHandle<Result<(), anyhow::Error>>,
db_name: String,
db_connection_uri: String,
}
impl Harness {
pub async fn test<F>(self, test: F)
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
// Run the test in its own (Tokio) thread and save the output.
let result = tokio::spawn(test).await;
// Stop the server thread.
self.server_handle.abort();
// `abort()` merely schedules termination. The task must be awaited to
// completion.
let _ = self.server_handle.await;
// The server is no longer connected to the database. It's now possible
// to drop it.
drop_database(&self.db_name, &self.db_connection_uri);
// Finally, unwrap the result to propagate any panics within. Without
// this, failing tests will be reported as successful.
result.unwrap();
}
}
Then, I use it like this:
#[tokio::test]
async fn returns_200() {
let (app, harness) = spawn_app().await;
let test = async move {
// Arrange.
let endpoint = format!("{}/health_check", app.address);
let client = reqwest::Client::new();
// Act.
let response = client.get(&endpoint).send().await.unwrap();
// Assert.
assert!(response.status().is_success());
assert_eq!(Some(0), response.content_length());
};
harness.test(test).await;
}
It's a bit clunky, though, and it adds noise and indentation. With the async teardown method of test_context, that could be avoided.
No... I meant what I wrote in #177. I took a rapid look to test_context
and it semams to me quite close to use #[fixture]
from rstest
and implement Drop
trait for your fixture.... the issue to use Drop::drop
in our case is that you cannot call await
in drop π’.
I'm not sure but maybe you can simplify your code using fixture
and implement Drop
for DbServer
that block_on
joining server_handle
. In this case your test become something like:
#[fixture]
fn app() -> App {
// Create your app
}
pub struct DbServer {
server_handle: Option<JoinHandle<Result<(), anyhow::Error>>>,
db_name: String,
db_connection_uri: String,
}
impl Drop for DbServer {
fn test<F>(&mut self)
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
// I should take the ownership of join handle
if let Some(join_handle) = self.server_handle.take() {
// Stop the server thread.
join_handle.abort();
// `abort()` merely schedules termination. The task must be awaited to
// completion.
let task = tokio::task::spawn(join_handle);
futures::executor::block_on(task).unwrap();
// The server is no longer connected to the database. It's now possible
// to drop it.
drop_database(&self.db_name, &self.db_connection_uri);
}
}
}
#[fixture]
fn db_server() -> DbServer {
// Create your db server
}
#[rstest]
#[tokio::test]
async fn returns_200(app: App, harness: Harness) {
// Arrange.
let endpoint = format!("{}/health_check", app.address);
let client = reqwest::Client::new();
// Act.
let response = client.get(&endpoint).send().await.unwrap();
// Assert.
assert!(response.status().is_success());
assert_eq!(Some(0), response.content_length());
}
I'm not sure that this code is correct... but I'm quite sure that's a feasible approach.
Oh, my bad. Thank you for taking the time out of your day to look over my code!
Looking at yours, wouldn't I still need to wrap the test logic in an async
block and pass it as an argument to DbServer::test
? That's my problem. really. My Harness
can indeed be a fixture, and unless I change my approach (e.g. by moving to libtest-mimic), that's exactly what I plan to do.
In contrast, the test_context crate would auto-magically wrap my test without my having to do anything. But if that's not what you were considering, no problem! I think it's more of a test harness problem than anything else.
Ok, my bad. We cannot call async
function in drop implementation. I'll considering to implement a support for teardown async fixtures.