LukeMathWalker / zero-to-production

Code for "Zero To Production In Rust", a book on API development using Rust.
https://www.zero2prod.com
Apache License 2.0
5.73k stars 491 forks source link

Chapter 3 Test Health Check ConnectionRefused #242

Closed JonnyWaffles closed 8 months ago

JonnyWaffles commented 8 months ago

Hi friends, picked up the book and working through the examples. I have this strange scenario in Chapter 3, where my app works if I build and run, but not when the test executes.

Here's a link to my progress thus far https://github.com/JonnyWaffles/zero2prod/tree/b17dc67098881ed38b05fee89100858752b13946.

When I run the test kit

#[tokio::test]
async fn health_check_works() {
    spawn_app();
    // We need to bring in `reqwest`
    // to perform HTTP requests against our application.
    let client = reqwest::Client::new();
    // Act
    let response = client
        .get("http://127.0.0.1:8000/health_check")
        .send()
        .await
        .expect("Failed to execute request.");
    // Assert
    assert!(response.status().is_success());
    assert_eq!(Some(0), response.content_length());
}

async fn spawn_app() {
    let server = zero2prod::run().expect("Failed to bind address");
    let _ = tokio::spawn(server);
}

I see

thread 'health_check_works' panicked at tests\health_check.rs:12:10:
Failed to execute request.: reqwest::Error { kind: Request, url: Url { scheme: "http", cannot_be_a_base: false, username: "", password: None, host:
 Some(Ipv4(127.0.0.1)), port: Some(8000), path: "/health_check", query: None, fragment: None }, source: hyper::Error(Connect, ConnectError("tcp con
nect error", Os { code: 10061, kind: ConnectionRefused, message: "No connection could be made because the target machine actively refused it." })) 
}
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

The strange part is if I build and run without testing, I can curl the app, and it works in Chrome. Just not when testing. It's like the tokio::spawn(server) isn't ready to go when I make the request above.

JonnyWaffles commented 8 months ago

When I skip ahead and use the TcpListener everything works, but I don't understand why the simpler hard coded port 8000 test fails when I know I can curl it when I do a build.

JonnyWaffles commented 8 months ago

Never mind I got owned by the extra async in my spawn app function! Damn my Python habits.

The fix is

fn spawn_app() {
    let server = zero2prod::run().expect("Failed to bind address");
    let _ = tokio::spawn(server);
}

Removing the async. Yikes.