use std::time::Duration;
use tokio::time::timeout;
struct HttpClient {
base_url: String,
timeout: Duration,
}
impl HttpClient {
fn new(base_url: String, timeout: Duration) -> Self {
Self { base_url, timeout }
}
async fn get(&self, path: &str) -> Result<String, Box<dyn std::error::Error>> {
let url = format!("{}{}", self.base_url, path);
let client = reqwest::Client::new();
let response = timeout(self.timeout, client.get(&url).send()).await??;
let text = response.text().await?;
Ok(text)
}
async fn get_with_status(
&self,
path: &str,
) -> Result<(u16, String), Box<dyn std::error::Error>> {
let url = format!("{}{}", self.base_url, path);
let client = reqwest::Client::new();
let response = timeout(self.timeout, client.get(&url).send()).await??;
let status = response.status().as_u16();
let text = response.text().await?;
Ok((status, text))
}
async fn get_with_headers(
&self,
path: &str,
headers: &[(&str, &str)],
) -> Result<String, Box<dyn std::error::Error>> {
let url = format!("{}{}", self.base_url, path);
let client = reqwest::Client::new();
let mut request = client.get(&url);
for (key, value) in headers {
request = request.header(*key, *value);
}
let response = timeout(self.timeout, request.send()).await??;
let text = response.text().await?;
Ok(text)
}
}
async fn run_integration_tests() -> Result<(), Box<dyn std::error::Error>> {
println!("๐งช Running HTTPCan client testing examples...\n");
println!("Test 1: Testing slow response timeout...");
let client = HttpClient::new("http://127.0.0.1:8080".to_string(), Duration::from_secs(1));
match client.get("/delay/10").await {
Err(e) => {
if e.to_string().contains("timeout") || e.to_string().contains("elapsed") {
println!("โ
Test passed: Got expected timeout error");
} else {
println!("โ Test failed: Got unexpected error: {}", e);
}
}
Ok(_) => {
println!("โ Test failed: Expected timeout but request succeeded");
}
}
println!("\nTest 2: Testing successful request...");
let client = HttpClient::new("http://127.0.0.1:8080".to_string(), Duration::from_secs(5));
match client.get("/delay/1").await {
Ok(response) => {
println!("โ
Test passed: Got successful response");
println!("Response preview: {}", &response[..response.len().min(100)]);
}
Err(e) => {
println!("โ Test failed: Expected success but got error: {}", e);
}
}
println!("\nTest 3: Testing JSON endpoint...");
match client.get("/json").await {
Ok(response) => {
if response.contains("slideshow") {
println!("โ
Test passed: Got expected JSON response");
} else {
println!("โ Test failed: JSON response doesn't contain expected content");
}
}
Err(e) => {
println!("โ Test failed: JSON request failed: {}", e);
}
}
println!("\nTest 4: Testing status codes...");
match client.get_with_status("/status/404").await {
Ok((status, _)) => {
if status == 404 {
println!("โ
Test passed: Got expected 404 status");
} else {
println!("โ Test failed: Expected 404 but got {}", status);
}
}
Err(e) => {
println!("โ Test failed: Status request failed: {}", e);
}
}
println!("\nTest 5: Testing headers endpoint...");
let headers = &[
("X-Test-Header", "test-value"),
("X-Custom", "custom-value"),
];
match client.get_with_headers("/headers", headers).await {
Ok(response) => {
if response.contains("X-Test-Header") && response.contains("test-value") {
println!("โ
Test passed: Headers are correctly echoed");
} else {
println!("โ Test failed: Headers not found in response");
}
}
Err(e) => {
println!("โ Test failed: Headers request failed: {}", e);
}
}
println!("\nTest 6: Testing GET endpoint...");
match client.get("/get?param1=value1¶m2=value2").await {
Ok(response) => {
if response.contains("param1") && response.contains("value1") {
println!("โ
Test passed: Query parameters are correctly handled");
} else {
println!("โ Test failed: Query parameters not found in response");
}
}
Err(e) => {
println!("โ Test failed: GET request failed: {}", e);
}
}
println!("\n๐ All integration tests completed!");
println!(
"๐ก This demonstrates how HTTPCan can be used as a test server for HTTP client testing"
);
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
httpcan::logging::init();
println!("Starting HTTPCan test server on http://127.0.0.1:8080");
println!("This example demonstrates testing HTTP clients against HTTPCan");
println!("๐ Note: To run these tests, start the HTTPCan server first:");
println!(" cargo run --example basic");
println!(" # Then in another terminal:");
println!(" cargo run --example client_testing --features examples");
println!();
let client = HttpClient::new("http://127.0.0.1:8080".to_string(), Duration::from_secs(2));
match client.get("/get").await {
Ok(_) => {
println!("๐ HTTPCan server detected! Running integration tests...\n");
run_integration_tests().await?;
}
Err(_) => {
println!("โ ๏ธ HTTPCan server not running on port 8080");
println!(" Start the server first with: cargo run --example basic");
println!(" Then run this example again.");
println!();
println!("๐ Here's what the tests would do:");
println!(" 1. Test timeout behavior with /delay/10 endpoint");
println!(" 2. Test successful requests with /delay/1 endpoint");
println!(" 3. Validate JSON responses from /json endpoint");
println!(" 4. Check status code handling with /status/404");
println!(" 5. Verify header echoing with /headers endpoint");
println!(" 6. Test query parameter handling with /get endpoint");
}
}
Ok(())
}