Skip to main content

TestServer

Struct TestServer 

Source
pub struct TestServer { /* private fields */ }
Expand description

A real HTTP test server that routes requests through the full App pipeline.

Unlike TestClient which operates in-process without network I/O, TestServer creates actual TCP connections and processes requests through the complete HTTP parsing -> App.handle() -> response serialization pipeline.

This enables true end-to-end testing including:

  • HTTP request parsing from raw bytes
  • Full middleware stack execution
  • Route matching and handler dispatch
  • Response serialization to HTTP/1.1
  • Cookie handling over the wire
  • Keep-alive and connection management

§Architecture

Test Code                        TestServer (background thread)
    |                                 |
    |-- TCP connect ----------------> |
    |-- Send HTTP request ----------> |
    |                                 |-- Parse HTTP request
    |                                 |-- Create RequestContext
    |                                 |-- App.handle(ctx, req)
    |                                 |-- Serialize Response
    |<-- Receive HTTP response ------ |
    |                                 |-- Log entry recorded

§Example

use fastapi_core::testing::TestServer;
use fastapi_core::app::App;
use std::io::{Read, Write};
use std::net::TcpStream;

let app = App::builder()
    .get("/health", |_, _| async { Response::ok().body_text("OK") })
    .build();

let server = TestServer::start(app);
println!("Server running on {}", server.url());

// Connect with any HTTP client
let mut stream = TcpStream::connect(server.addr()).unwrap();
stream.write_all(b"GET /health HTTP/1.1\r\nHost: localhost\r\n\r\n").unwrap();

let mut buf = vec![0u8; 4096];
let n = stream.read(&mut buf).unwrap();
let response = String::from_utf8_lossy(&buf[..n]);
assert!(response.contains("200 OK"));

// Check server logs
let logs = server.log_entries();
assert_eq!(logs.len(), 1);
assert_eq!(logs[0].path, "/health");
assert_eq!(logs[0].status, 200);

Implementations§

Source§

impl TestServer

Source

pub fn start(app: App) -> Self

Starts a new test server with the given App on a random available port.

The server begins listening immediately and runs in a background thread. It will process requests through the full App pipeline including all middleware, routing, and error handling.

§Panics

Panics if binding to a local port fails.

Source

pub fn start_with_config(app: App, config: TestServerConfig) -> Self

Starts a test server with custom configuration.

Source

pub fn addr(&self) -> SocketAddr

Returns the socket address the server is listening on.

Source

pub fn port(&self) -> u16

Returns the port the server is listening on.

Source

pub fn url(&self) -> String

Returns the base URL (e.g., “http://127.0.0.1:12345”).

Source

pub fn url_for(&self, path: &str) -> String

Returns a URL for the given path.

Source

pub fn log_entries(&self) -> Vec<TestServerLogEntry>

Returns a snapshot of all log entries recorded so far.

Source

pub fn request_count(&self) -> usize

Returns the number of requests processed.

Source

pub fn clear_logs(&self)

Clears all recorded log entries.

Source

pub fn shutdown_controller(&self) -> &ShutdownController

Returns a reference to the server’s shutdown controller.

Use this to coordinate graceful shutdown in tests, including:

Source

pub fn in_flight_count(&self) -> usize

Returns the number of currently in-flight requests.

Source

pub fn shutdown(&self)

Signals the server to shut down gracefully.

This triggers the shutdown controller (which will cause the server to reject new requests with 503) and stops the accept loop. This is also called automatically on drop.

Source

pub fn is_shutdown(&self) -> bool

Returns true if the server has been signaled to shut down.

Trait Implementations§

Source§

impl Drop for TestServer

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, _span: NoopSpan) -> Self

Instruments this future with a span (no-op when disabled).
Source§

fn in_current_span(self) -> Self

Instruments this future with the current span (no-op when disabled).
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ResponseProduces<T> for T