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

Is a stable, 1.0 release planned #197

Open
nwalfield opened this issue May 30, 2023 · 7 comments
Open

Is a stable, 1.0 release planned #197

nwalfield opened this issue May 30, 2023 · 7 comments

Comments

@nwalfield
Copy link

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!

@la10736
Copy link
Owner

la10736 commented May 30, 2023

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?

@nwalfield
Copy link
Author

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.

@la10736
Copy link
Owner

la10736 commented May 31, 2023

I never thought to quit my job 😄 ... But find some founds can be a motivation to invest more time on rstest 😄

@dsaghliani
Copy link

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.

@la10736
Copy link
Owner

la10736 commented Jun 25, 2023

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.

@dsaghliani
Copy link

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.

@la10736
Copy link
Owner

la10736 commented Jun 28, 2023

Ok, my bad. We cannot call async function in drop implementation. I'll considering to implement a support for teardown async fixtures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants