xref: /aosp_15_r20/external/bazelbuild-rules_rust/examples/crate_universe/no_cargo_manifests/src/main.rs (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
1 //! Copied from https://github.com/tokio-rs/axum/blob/v0.2.5/examples/testing/src/main.rs
2 
3 use axum::{
4     routing::{get, post},
5     Json, Router,
6 };
7 use tower_http::trace::TraceLayer;
8 
9 #[tokio::main]
main()10 async fn main() {
11     // Set the RUST_LOG, if it hasn't been explicitly defined
12     if std::env::var_os("RUST_LOG").is_none() {
13         std::env::set_var("RUST_LOG", "example_testing=debug,tower_http=debug")
14     }
15     tracing_subscriber::fmt::init();
16 
17     let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 3000));
18 
19     tracing::debug!("listening on {}", addr);
20 
21     axum::Server::bind(&addr)
22         .serve(app().into_make_service())
23         .await
24         .unwrap();
25 }
26 
27 /// Having a function that produces our app makes it easy to call it from tests
28 /// without having to create an HTTP server.
29 #[allow(dead_code)]
app() -> Router30 fn app() -> Router {
31     Router::new()
32         .route("/", get(|| async { "Hello, World!" }))
33         .route(
34             "/json",
35             post(|payload: Json<serde_json::Value>| async move {
36                 Json(serde_json::json!({ "data": payload.0 }))
37             }),
38         )
39         // We can still add middleware
40         .layer(TraceLayer::new_for_http())
41 }
42 
43 #[cfg(test)]
44 mod tests {
45     use super::*;
46 
47     #[cfg(not(target_os = "windows"))]
48     use std::net::{SocketAddr, TcpListener};
49 
50     use axum::{
51         body::Body,
52         http::{self, Request, StatusCode},
53     };
54     use serde_json::{json, Value};
55     use tower::ServiceExt; // for `app.oneshot()`
56 
57     #[tokio::test]
hello_world()58     async fn hello_world() {
59         let app = app();
60 
61         // `Router` implements `tower::Service<Request<Body>>` so we can
62         // call it like any tower service, no need to run an HTTP server.
63         let response = app
64             .oneshot(Request::builder().uri("/").body(Body::empty()).unwrap())
65             .await
66             .unwrap();
67 
68         assert_eq!(response.status(), StatusCode::OK);
69 
70         let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
71         assert_eq!(&body[..], b"Hello, World!");
72     }
73 
74     #[tokio::test]
json()75     async fn json() {
76         let app = app();
77 
78         let response = app
79             .oneshot(
80                 Request::builder()
81                     .method(http::Method::POST)
82                     .uri("/json")
83                     .header(http::header::CONTENT_TYPE, mime::APPLICATION_JSON.as_ref())
84                     .body(Body::from(
85                         serde_json::to_vec(&json!([1_i8, 2_i8, 3_i8, 4_i8])).unwrap(),
86                     ))
87                     .unwrap(),
88             )
89             .await
90             .unwrap();
91 
92         assert_eq!(response.status(), StatusCode::OK);
93 
94         let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
95         let body: Value = serde_json::from_slice(&body).unwrap();
96         assert_eq!(body, json!({ "data": [1_i8, 2_i8, 3_i8, 4_i8] }));
97     }
98 
99     #[tokio::test]
not_found()100     async fn not_found() {
101         let app = app();
102 
103         let response = app
104             .oneshot(
105                 Request::builder()
106                     .uri("/does-not-exist")
107                     .body(Body::empty())
108                     .unwrap(),
109             )
110             .await
111             .unwrap();
112 
113         assert_eq!(response.status(), StatusCode::NOT_FOUND);
114         let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
115         assert!(body.is_empty());
116     }
117 
118     // TODO: This test fails on Windows, it shouldn't but it's unclear to me
119     // if this is an issue on the host or with the test.
120     #[cfg(not(target_os = "windows"))]
121     // You can also spawn a server and talk to it like any other HTTP server:
122     #[tokio::test]
the_real_deal()123     async fn the_real_deal() {
124         let listener = TcpListener::bind("0.0.0.0:0".parse::<SocketAddr>().unwrap()).unwrap();
125         let addr = listener.local_addr().unwrap();
126 
127         tokio::spawn(async move {
128             axum::Server::from_tcp(listener)
129                 .unwrap()
130                 .serve(app().into_make_service())
131                 .await
132                 .unwrap();
133         });
134 
135         let client = hyper::Client::new();
136 
137         let response = client
138             .request(
139                 Request::builder()
140                     .uri(format!("http://{addr}"))
141                     .body(Body::empty())
142                     .unwrap(),
143             )
144             .await
145             .unwrap();
146 
147         let body = hyper::body::to_bytes(response.into_body()).await.unwrap();
148         assert_eq!(&body[..], b"Hello, World!");
149     }
150 }
151