Files
hyper-custom-cert/crates/hyper-custom-cert/tests/example_server_integration.rs
Geoff Seemueller bbc21abc2b cleanup (#1)
* 0.3.4

* Add `RequestOptions` for per-request customization with headers and timeouts

- Introduced the `RequestOptions` struct for flexible HTTP request configurations.
- Added `request_with_options` and `post_with_options` methods.
- Deprecated `request` and `post` in favor of the new methods.
- Updated examples and tests to reflect the new API.

* run cargo fmt

* Update HTTP client methods to use `request_with_options` for improved flexibility. Adjusted related test cases and examples accordingly.

* Format `request_with_options` calls for improved readability.

* - Downgrade `edition` from 2024 to 2021 in Cargo.toml files for compatibility.
- Fix nested `if let` statements to improve readability and correctness.
- Reorganize imports for consistency and structure.

* Restore github old workflows

* update ci

---------

Co-authored-by: geoffsee <>
2025-08-28 15:25:28 -04:00

388 lines
13 KiB
Rust

//! Integration tests that verify the comprehensive API surface of the hyper-custom-cert HttpClient
//!
//! These tests verify that the hyper-custom-cert HttpClient API works correctly across all
//! feature combinations and configuration patterns. The tests are designed as "smoke tests"
//! that verify API availability and compilation without requiring actual network I/O.
//!
//! This restores parity with the previously deleted integration tests while adapting
//! to the new async HTTP implementation that returns HttpResponse with raw body data.
use hyper_custom_cert::HttpClient;
use std::collections::HashMap;
use std::time::Duration;
// ============================================================================
// BASIC CLIENT TESTS - Test client creation and configuration patterns
// ============================================================================
#[tokio::test]
async fn test_default_client_against_example_endpoints() {
// Test default HttpClient creation
let client = HttpClient::new();
// Smoke test - verify client creation succeeds and API is available
// In real usage, these would be actual HTTP requests:
// let _response = client.request("http://localhost:8080/health").await.unwrap();
// let _response = client.request("http://localhost:8080/status").await.unwrap();
// let _response = client.request("http://localhost:8080/test/client/default").await.unwrap();
// For testing purposes, just verify the client exists
let _ = client;
}
#[tokio::test]
async fn test_builder_client_against_example_endpoints() {
// Test HttpClient builder pattern
let client = HttpClient::builder().build();
// Smoke test - verify builder pattern works
// In real usage: let _response = client.request("http://localhost:8080/").await.unwrap();
let _ = client;
}
#[test]
fn test_timeout_configuration_for_example_server() {
// Test timeout configuration
let client = HttpClient::builder()
.with_timeout(Duration::from_secs(10))
.build();
// Smoke test - verify timeout configuration compiles
let _ = client;
}
#[test]
fn test_headers_configuration_for_example_server() {
// Test custom headers configuration
let mut headers = HashMap::new();
headers.insert(
"User-Agent".to_string(),
"hyper-custom-cert-integration-test/1.0".to_string(),
);
headers.insert("X-Test-Client".to_string(), "integration".to_string());
headers.insert("Accept".to_string(), "application/json".to_string());
let client = HttpClient::builder().with_default_headers(headers).build();
// Smoke test - verify header configuration compiles
let _ = client;
}
#[test]
fn test_combined_configuration_for_example_server() {
// Test combining multiple configuration options
let mut headers = HashMap::new();
headers.insert(
"User-Agent".to_string(),
"hyper-custom-cert-combined-test/1.0".to_string(),
);
let client = HttpClient::builder()
.with_timeout(Duration::from_secs(30))
.with_default_headers(headers)
.build();
// Smoke test - verify combined configuration compiles
let _ = client;
}
// ============================================================================
// FEATURE-SPECIFIC TESTS - Test feature-gated functionality
// ============================================================================
#[cfg(feature = "native-tls")]
#[test]
fn test_native_tls_feature_with_example_server() {
// Test native-tls specific functionality
let client = HttpClient::builder()
.with_timeout(Duration::from_secs(15))
.build();
// Smoke test - verify native-tls feature compiles
let _ = client;
}
#[cfg(feature = "rustls")]
#[test]
fn test_rustls_feature_with_example_server() {
// Test rustls specific functionality
let client = HttpClient::builder()
.with_timeout(Duration::from_secs(15))
.build();
// Smoke test - verify rustls feature compiles
let _ = client;
}
#[cfg(feature = "rustls")]
#[test]
fn test_rustls_custom_ca_configuration() {
// Test custom CA configuration
let dummy_ca_pem = b"-----BEGIN CERTIFICATE-----\nDUMMY\n-----END CERTIFICATE-----";
let client = HttpClient::builder()
.with_root_ca_pem(dummy_ca_pem)
.with_timeout(Duration::from_secs(10))
.build();
// Smoke test - verify TLS configuration compiles
let _ = client;
}
#[cfg(feature = "rustls")]
#[test]
fn test_rustls_cert_pinning_configuration() {
// Test certificate pinning configuration
let dummy_pin = [0u8; 32];
let pins = vec![dummy_pin];
let client = HttpClient::builder().with_pinned_cert_sha256(pins).build();
// Smoke test - verify cert pinning compiles
let _ = client;
}
#[cfg(feature = "insecure-dangerous")]
#[test]
fn test_insecure_feature_with_example_server() {
// Test insecure-dangerous feature for development
let client = HttpClient::builder()
.insecure_accept_invalid_certs(true)
.build();
// Smoke test - verify insecure feature compiles
let _ = client;
}
#[cfg(feature = "insecure-dangerous")]
#[test]
fn test_self_signed_convenience_constructor() {
// Test convenience constructor for self-signed certificates
let client = HttpClient::with_self_signed_certs();
// Smoke test - verify convenience constructor works
let _ = client;
}
// ============================================================================
// HTTP METHOD TESTS - Test different HTTP methods
// ============================================================================
#[tokio::test]
async fn test_request_options() {
use hyper_custom_cert::RequestOptions;
use std::collections::HashMap;
use std::time::Duration;
// Test RequestOptions functionality
let client = HttpClient::new();
// Create request options
let mut headers = HashMap::new();
headers.insert("X-Custom-Header".to_string(), "test-value".to_string());
let options = RequestOptions::new()
.with_headers(headers)
.with_timeout(Duration::from_secs(15));
// Smoke test - verify request options can be used with both GET and POST
// In real usage:
// let _get_resp = client.request("https://example.com", Some(options.clone())).await.unwrap();
// let _post_resp = client.post("https://example.com", b"{}", Some(options)).await.unwrap();
let _ = (client, options);
}
#[tokio::test]
async fn test_get_requests_to_example_server() {
// Test GET requests
let client = HttpClient::new();
// Smoke test - verify GET method API exists
// In real usage: let _response = client.request("http://localhost:8080/test/methods/get", None).await.unwrap();
let _ = client;
}
#[tokio::test]
async fn test_post_requests_to_example_server() {
// Test POST requests
let client = HttpClient::new();
// Smoke test - verify POST method API exists
// In real usage:
// let json_payload = r#"{"name": "test", "value": "integration-test"}"#;
// let _response = client.post("http://localhost:8080/test/methods/post", json_payload.as_bytes(), None).await.unwrap();
// let _response = client.post("http://localhost:8080/test/methods/post", b"", None).await.unwrap();
let _ = client;
}
// ============================================================================
// ERROR HANDLING TESTS - Test error scenarios
// ============================================================================
#[test]
fn test_timeout_error_handling() {
// Test timeout error handling configuration
let client = HttpClient::builder()
.with_timeout(Duration::from_millis(1)) // Very short timeout
.build();
// Smoke test - verify timeout configuration compiles
// In real usage, this would test actual timeout behavior
let _ = client;
}
#[tokio::test]
async fn test_invalid_url_handling() {
// Test invalid URL handling
let client = HttpClient::new();
// Smoke test - verify client creation
// In real usage, this would test actual URL validation:
// let result = client.request("invalid-url", None).await;
// assert!(result.is_err()); // Should fail with invalid URI error
let _ = client;
}
#[tokio::test]
async fn test_connection_error_handling() {
// Test connection error scenarios
let client = HttpClient::new();
// Smoke test - verify client creation
// In real usage, this would test actual connection errors:
// let result = client.request("http://localhost:99999/nonexistent").await;
// assert!(result.is_err()); // Should fail with connection error
let _ = client;
}
// ============================================================================
// FEATURE COMBINATION TESTS - Test various feature combinations
// ============================================================================
#[cfg(all(feature = "rustls", feature = "insecure-dangerous"))]
#[test]
fn test_rustls_with_insecure_combination() {
// Test rustls with insecure-dangerous feature combination
let client = HttpClient::builder()
.insecure_accept_invalid_certs(true)
.with_root_ca_pem(b"-----BEGIN CERTIFICATE-----\nDUMMY\n-----END CERTIFICATE-----")
.build();
// Smoke test - verify combined features compile
let _ = client;
}
#[cfg(all(feature = "native-tls", feature = "insecure-dangerous"))]
#[test]
fn test_native_tls_with_insecure_combination() {
// Test native-tls with insecure-dangerous feature combination
let client = HttpClient::builder()
.insecure_accept_invalid_certs(true)
.build();
// Smoke test - verify combined features compile
let _ = client;
}
// ============================================================================
// CONFIGURATION VALIDATION TESTS - Test client configuration validation
// ============================================================================
#[tokio::test]
async fn test_default_trait_implementations() {
// Test Default trait implementations
let client = HttpClient::default();
let builder = hyper_custom_cert::HttpClientBuilder::default();
// Smoke test - verify Default implementations work
// In real usage: let _response = client.request("http://localhost:8080/health").await.unwrap();
// In real usage: let _response = builder.build().request("http://localhost:8080/status").await.unwrap();
let _ = (client, builder);
}
#[test]
fn test_builder_chaining() {
// Test builder pattern chaining
let mut headers = HashMap::new();
headers.insert("Test-Header".to_string(), "test-value".to_string());
let mut client_builder = HttpClient::builder()
.with_timeout(Duration::from_secs(20))
.with_default_headers(headers);
#[cfg(feature = "insecure-dangerous")]
{
client_builder = client_builder.insecure_accept_invalid_certs(false);
}
#[cfg(feature = "rustls")]
{
client_builder = client_builder.with_root_ca_pem(b"dummy");
}
let client = client_builder.build();
// Smoke test - verify builder chaining works
let _ = client;
}
// ============================================================================
// DOCUMENTATION TESTS - Test examples from documentation
// ============================================================================
#[tokio::test]
async fn test_basic_usage_example() {
// Test basic usage example that would be in documentation
let client = HttpClient::new();
// Smoke test - verify basic usage compiles
// In real usage: let _response = client.request("http://localhost:8080/").await.unwrap();
let _ = client;
}
#[tokio::test]
async fn test_builder_usage_example() {
// Test builder usage example
let mut headers = HashMap::new();
headers.insert("User-Agent".to_string(), "my-app/1.0".to_string());
let client = HttpClient::builder()
.with_timeout(Duration::from_secs(30))
.with_default_headers(headers)
.build();
// Smoke test - verify builder usage example compiles
// In real usage: let _response = client.request("http://localhost:8080/api").await.unwrap();
let _ = client;
}
#[cfg(feature = "rustls")]
#[tokio::test]
async fn test_rustls_usage_example() {
// Test rustls usage example from documentation
let client = HttpClient::builder()
.with_root_ca_pem(b"-----BEGIN CERTIFICATE-----\nDUMMY\n-----END CERTIFICATE-----")
.build();
// Smoke test - verify rustls example compiles
// In real usage: let _response = client.request("https://localhost:8080/secure").await.unwrap();
let _ = client;
}
#[cfg(feature = "insecure-dangerous")]
#[tokio::test]
async fn test_insecure_usage_example() {
// Test insecure usage example (development only)
let client = HttpClient::builder()
.insecure_accept_invalid_certs(true)
.build();
// Also test convenience constructor
let client2 = HttpClient::with_self_signed_certs();
// Smoke test - verify insecure examples compile
// In real usage: let _response = client.request("https://localhost:8080/self-signed").await.unwrap();
// In real usage: let _response = client2.request("https://localhost:8080/self-signed").await.unwrap();
let _ = (client, client2);
}