jeremychone / rust-httpc-test Goto Github PK
View Code? Open in Web Editor NEWMinimalistic HTTP Client Test Utilities
License: Apache License 2.0
Minimalistic HTTP Client Test Utilities
License: Apache License 2.0
If the content type is not precisely application/json
the response is not recognize a json.
This is wrong as encoding can/should be used as well (e.g., application/json; utf8
)
As with text matching, just do a starts_with("application/json")
match.
I want to test redirection from my /login endpoint, but the default client created inside of new_client
automatically follows redirects, so I don't get to inspect it.
pub async fn do_patch(&self, url: &str, content: impl Into<PostContent>) -> Result<Response> {
self.do_push(Method::PUT, url, content.into()).await
}
I am trying to follow this tutorial. I decided to go one tiny inch beyond what is done in the video and implemented a logout route that is supposed to delete the auth cookie. It seems to work OK on the server side, i.e. the server sends a correct empty-valued, expired-last-year set-cookie directive in order to delete the cookie:
->> HANDLER - api_logout
->> RES_MAPPER - main_response_mapper
=== Response for POST http://localhost:8080/api/logout
=> Status : 200 OK
=> Headers :
content-type: "application/json"
content-length: "4"
set-cookie: "auth-token=; Max-Age=0; Expires=Tue, 24 May 2022 23:05:08 GMT"
date: "Wed, 24 May 2023 23:05:08 GMT"
=> Response Cookies:
auth-token:
=> Client Cookies :
auth-token: user-1.exp.sign
=> Response Body :
"Ok"
===
However subsequent requests made with the same client keep sending the old cookie, as if the client didn't apply the directive:
->> HANDLER - handler_hello2 - "Rulatir"
->> RES_MAPPER - main_response_mapper
=== Response for GET http://localhost:8080/hello/Rulatir
=> Status : 200 OK
=> Headers :
content-type: "text/html; charset=utf-8"
content-length: "30"
date: "Wed, 24 May 2023 23:05:08 GMT"
=> Client Cookies :
auth-token: user-1.exp.sign
=> Response Body :
Hello <strong>Rulatir</strong>
===
Hi @jeremychone ,
I am using your valuable tutorial about axume and I enjoyed your httpc-test crate as well.
But when I tried to add some new nested route beside api route in your tutorial I found myself in trouble with request headers without cookie.
I added new nested route similar to your tutorial for api:
let private_files = private_file_routes()
.route_layer(middleware::from_fn(web::mw_auth::mw_require_auth));
let private_files = private_file_routes()
.route_layer(middleware::from_fn(web::mw_auth::mw_require_auth));
let routes_apis = web::routes_tickets::routes(mc.clone())
.route_layer(middleware::from_fn(web::mw_auth::mw_require_auth));
let routes_all = Router::new()
.merge(routes_hello())
.merge(web::routes_login::routes())
.nest("/api", routes_apis)
.nest("/pvf", private_files)
.layer(middleware::map_response(main_response_mapper))
.layer(middleware::from_fn_with_state(mc.clone(), web::mw_auth::mw_ctx_resolver, ))
.layer(CookieManagerLayer::new())
.merge(public_no_auth_routes())
.fallback_service(public_no_auth_routes());
async fn handler_private_file(
ctx: Ctx,
Path(priavate_path): Path<String>,
) -> impl IntoResponse {
println!("->> {:<12} - handler_private_file - {ctx:?} ", "CTX");
println!("->> {:<12} - handler_private_file - {priavate_path:?} ", "HANDLER");
Html(format!("bublic file requested: <strong>{priavate_path}</strong>"))
}
So when I try httpc-test:
let hc = httpc_test::new_client("http://localhost:8080")?;
hc.do_get("/public/lvl_01/lvl_02/public_target_at_several_level").await?.print().await?;
hc.do_get("/public/target_at_public_root").await?.print().await?;
// try to read private data before login:
hc.do_get("/pvf/target_at_private_root_b4_login").await?.print().await?;
let req_login = hc.do_post("/api/login",
json!({
"username": "demo1",
"pwd": "welcome"
}));
req_login.await?.print().await?;
// try to read private data after login:
hc.do_get("/pvf/lvl_01/lvl_02/private_target_at_several_level").await?.print().await?;
hc.do_get("/pvf/private_target_at_root_level").await?.print().await?;
//Check if cookies still working for api route
hc.do_get("/api/tickets").await?.print().await?;
and here is test result:
server side log:
->> LISTENING on 127.0.0.1:8080
->> HANDLER - handler_public_file - "lvl_01/lvl_02/public_target_at_several_level"
->> HANDLER - handler_public_file - "target_at_public_root"
->> MIDDLEWARE - mw_ctx_resolver
mw_ctx_resolver <<-- req.headers {"accept": "*/*", "host": "localhost:8080"}
mw_ctx_resolver <<-- cookies Cookies { inner: Mutex { data: Inner { headers: [], jar: None, changed: false } } }
mw_ctx_resolver -->> auth_token: None -
->> EXTRACTOR - Ctx
->> EXTRACTOR - Ctx
->> MIDDLEWARE - mw_require_auth
->> INTO_RES - AuthFailNoAuthTokenCookie
->> RES_MAPPER - main_response_mapper
->> client_error_body: {"error":{"req_uuid":"018b38f2-29c0-7aaf-9cb4-298d80d1a604","type":"NO_AUTH"}}
->> log_request:
{"client_error_type":"NO_AUTH","error_type":"AuthFailNoAuthTokenCookie","req_method":"GET","req_path":"/pvf/target_at_private_root_b4_login","timestamp":"1697467476416","uuid":"018b38f2-29c0-7aaf-9cb4-298d80d1a604"}
->> server log line - 018b38f2-29c0-7aaf-9cb4-298d80d1a604 - Error: Some(AuthFailNoAuthTokenCookie)
->> MIDDLEWARE - mw_ctx_resolver
mw_ctx_resolver <<-- req.headers {"content-type": "application/json", "accept": "*/*", "host": "localhost:8080", "content-length": "36"}
mw_ctx_resolver <<-- cookies Cookies { inner: Mutex { data: Inner { headers: [], jar: None, changed: false } } }
mw_ctx_resolver -->> auth_token: None -
->> EXTRACTOR - Ctx
->> HANDLER - api_login
->> RES_MAPPER - main_response_mapper
->> log_request:
{"req_method":"POST","req_path":"/api/login","timestamp":"1697467476417","uuid":"018b38f2-29c1-7285-a666-c0decf982c41"}
->> server log line - 018b38f2-29c1-7285-a666-c0decf982c41 - Error: None
->> MIDDLEWARE - mw_ctx_resolver
mw_ctx_resolver <<-- req.headers {"accept": "*/*", "host": "localhost:8080"}
mw_ctx_resolver <<-- cookies Cookies { inner: Mutex { data: Inner { headers: [], jar: None, changed: false } } }
mw_ctx_resolver -->> auth_token: None -
->> EXTRACTOR - Ctx
->> EXTRACTOR - Ctx
->> MIDDLEWARE - mw_require_auth
->> INTO_RES - AuthFailNoAuthTokenCookie
->> RES_MAPPER - main_response_mapper
->> client_error_body: {"error":{"req_uuid":"018b38f2-29c3-78e3-a0e7-98f5a192cee2","type":"NO_AUTH"}}
->> log_request:
{"client_error_type":"NO_AUTH","error_type":"AuthFailNoAuthTokenCookie","req_method":"GET","req_path":"/pvf/lvl_01/lvl_02/private_target_at_several_level","timestamp":"1697467476419","uuid":"018b38f2-29c3-78e3-a0e7-98f5a192cee2"}
->> server log line - 018b38f2-29c3-78e3-a0e7-98f5a192cee2 - Error: Some(AuthFailNoAuthTokenCookie)
->> MIDDLEWARE - mw_ctx_resolver
mw_ctx_resolver <<-- req.headers {"accept": "*/*", "host": "localhost:8080"}
mw_ctx_resolver <<-- cookies Cookies { inner: Mutex { data: Inner { headers: [], jar: None, changed: false } } }
mw_ctx_resolver -->> auth_token: None -
->> EXTRACTOR - Ctx
->> EXTRACTOR - Ctx
->> MIDDLEWARE - mw_require_auth
->> INTO_RES - AuthFailNoAuthTokenCookie
->> RES_MAPPER - main_response_mapper
->> client_error_body: {"error":{"req_uuid":"018b38f2-29c4-71bd-a26c-584b775e198b","type":"NO_AUTH"}}
->> log_request:
{"client_error_type":"NO_AUTH","error_type":"AuthFailNoAuthTokenCookie","req_method":"GET","req_path":"/pvf/private_target_at_root_level","timestamp":"1697467476420","uuid":"018b38f2-29c4-71bd-a26c-584b775e198b"}
->> server log line - 018b38f2-29c4-71bd-a26c-584b775e198b - Error: Some(AuthFailNoAuthTokenCookie)
->> MIDDLEWARE - mw_ctx_resolver
mw_ctx_resolver <<-- req.headers {"accept": "*/*", "cookie": "auth-token=user-1.exp.sign", "host": "localhost:8080"}
mw_ctx_resolver <<-- cookies Cookies { inner: Mutex { data: Inner { headers: ["auth-token=user-1.exp.sign"], jar: None, changed: false } } }
mw_ctx_resolver -->> auth_token: Some("user-1.exp.sign") -
->> EXTRACTOR - Ctx
->> EXTRACTOR - Ctx
->> MIDDLEWARE - mw_require_auth
->> EXTRACTOR - Ctx
->> HANDLER - list_tickets
->> RES_MAPPER - main_response_mapper
->> log_request:
{"req_method":"GET","req_path":"/api/tickets","timestamp":"1697467476424","user_id":1,"uuid":"018b38f2-29c8-7c01-bce9-4985a40472c0"}
->> server log line - 018b38f2-29c8-7c01-bce9-4985a40472c0 - Error: None
client side log:
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 1 test
=== Response for GET http://localhost:8080/public/lvl_01/lvl_02/public_target_at_several_level
=> Status : 200 OK OK
=> Headers :
content-type: text/html; charset=utf-8
content-length: 84
date: Mon, 16 Oct 2023 14:44:36 GMT
=> Response Body :
bublic file requested: <strong>lvl_01/lvl_02/public_target_at_several_level</strong>
===
=== Response for GET http://localhost:8080/public/target_at_public_root
=> Status : 200 OK OK
=> Headers :
content-type: text/html; charset=utf-8
content-length: 61
date: Mon, 16 Oct 2023 14:44:36 GMT
=> Response Body :
bublic file requested: <strong>target_at_public_root</strong>
===
=== Response for GET http://localhost:8080/pvf/target_at_private_root_b4_login
=> Status : 403 Forbidden Forbidden
=> Headers :
content-type: application/json
content-length: 78
date: Mon, 16 Oct 2023 14:44:36 GMT
=> Response Body :
{
"error": {
"req_uuid": "018b38f2-29c0-7aaf-9cb4-298d80d1a604",
"type": "NO_AUTH"
}
}
===
=== Response for POST http://localhost:8080/api/login
=> Status : 200 OK OK
=> Headers :
content-type: application/json
content-length: 27
set-cookie: auth-token=user-1.exp.sign
date: Mon, 16 Oct 2023 14:44:36 GMT
=> Response Cookies:
auth-token: user-1.exp.sign
=> Client Cookies :
auth-token: user-1.exp.sign
=> Response Body :
{
"result": {
"success": true
}
}
===
=== Response for GET http://localhost:8080/pvf/lvl_01/lvl_02/private_target_at_several_level
=> Status : 403 Forbidden Forbidden
=> Headers :
content-type: application/json
content-length: 78
date: Mon, 16 Oct 2023 14:44:36 GMT
=> Client Cookies :
auth-token: user-1.exp.sign
=> Response Body :
{
"error": {
"req_uuid": "018b38f2-29c3-78e3-a0e7-98f5a192cee2",
"type": "NO_AUTH"
}
}
===
=== Response for GET http://localhost:8080/pvf/private_target_at_root_level
=> Status : 403 Forbidden Forbidden
=> Headers :
content-type: application/json
content-length: 78
date: Mon, 16 Oct 2023 14:44:36 GMT
=> Client Cookies :
auth-token: user-1.exp.sign
=> Response Body :
{
"error": {
"req_uuid": "018b38f2-29c4-71bd-a26c-584b775e198b",
"type": "NO_AUTH"
}
}
===
=== Response for GET http://localhost:8080/api/tickets
=> Status : 200 OK OK
=> Headers :
content-type: application/json
content-length: 2
date: Mon, 16 Oct 2023 14:44:36 GMT
=> Client Cookies :
auth-token: user-1.exp.sign
=> Response Body :
[]
===
.
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s
now when I try same url with curl command including cookie I have correct result:
curl -v --cookie "auth-token=user-1.exp.sign" http://localhost:8080/pvf/lvl_01/lvl_02/public_target_at_several_level 17:57:09
* Trying [::1]:8080...
* connect to ::1 port 8080 failed: Connection refused
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080
> GET /pvf/lvl_01/lvl_02/public_target_at_several_level HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.4.0
> Accept: */*
> Cookie: auth-token=user-1.exp.sign
>
< HTTP/1.1 200 OK
< content-type: text/html; charset=utf-8
< content-length: 84
< date: Mon, 16 Oct 2023 14:59:25 GMT
<
* Connection #0 to host localhost left intact
bublic file requested: <strong>lvl_01/lvl_02/public_target_at_several_level</strong>%
So please help me find why there is no cookie in httpc-test requests when I try the other route?
Is there a way to get a request's status code ? Sth that would look like this:
let client = httpc_test::new_client(format!("http://localhost:{}", axum_test::LISTENING_PORT))?;
let status_code = client.do_get("/favicon.svg").await?.status_code().await?;
I can find no status-related info on the Response documentation ๐คท
I love your videos, and I like this tool, but I'm working with HTMX and I need to be able to do post requests with form data.
Currently I'm trying this:
let req_login = hc.do_post(
"/login",
json!({
"username": "demo1",
"pwd": "welcome"
}),
);
req_login.await?.print().await?;
But I'm getting:
=== Response for POST http://localhost:8080/login
=> Status : 415 Unsupported Media Type Unsupported Media Type
=> Headers :
content-type: text/plain; charset=utf-8
content-length: 73
date: Thu, 01 Feb 2024 19:06:56 GMT
=> Response Body :
Form requests must have `Content-Type: application/x-www-form-urlencoded`
===
I don't see any related examples in the docs.
some test need
header
cookie
how about add client builder?
Should be https://github.com/jeremychone/rust-httpc-test
Great little tool - I came across it in your Axum video (which is also amazing).
Using it some scratch integration, I noticed that PUTs would fail with records already existing - poking around, it looks like it calls the request::post method instead of request::put under the hood.
Hello,
I am going through your great Axum course on Youtube and keep running up against this problem while trying to run the tests. It doesn't happen on the first test you go through (so the simple hello get request works as intended) but all the other ones after that have this issue. Using the old school curl
approach to test the server works correctly as well.
I think it might have something to do with this hyper issue: hyperium/hyper#2136 but that's just a guess as you say this library is built on top of reqwest (which uses hyper right?).
Any clue how to overcome this issue? I like this workflow and would like to use it while developing my own projects. My apologies if this is something related to my system and nothing to do with your library.
p.s. Crates.io has the wrong repository link. It tried to take me here: https://github.com/rust-httpc-test
I'm currently working on a Rust backend using Actix Web, where I have implemented a POST route to handle multipart/form-data requests for saving images to disk. However, I'm encountering challenges when testing this functionality using the httpc-test library.
I've created a POST route that handles multipart/form-data requests and saves images to disk, but I'm struggling to find documentation or examples on how to effectively test this route using httpc-test. I've also explored the httpc-test source code but couldn't find any solutions that suit my needs.
I'm looking for guidance or examples on how to test this multipart/form-data request using httpc-test properly. Additionally, I already know how to do this using cURL, and the cURL command I use is as follows:
curl -F [email protected] http://localhost:8080/post --trace-ascii
I want a similar functionality using httpc-test
Thank you for your help in advance!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.