Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@ members = [
"http-cache-tower",
"http-cache-tower-server",
"http-cache-ureq"
]
exclude = [
"compat-tests/legacy-writer",
"compat-tests/read-legacy-cache",
]
72 changes: 72 additions & 0 deletions compat-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Compatibility Tests: 0.16 -> 1.0-alpha Migration

These tools validate the real-world upgrade path from http-cache-reqwest 0.16.0
(bincode serialization) to 1.0-alpha.4 (postcard serialization).

## What's being tested

| Scenario | Expected Result |
|---|---|
| Old bincode entries read with new code (postcard only) | Graceful cache miss (`Ok(None)`), no crash |
| Old bincode entries read with compat features enabled | Successful deserialization via bincode fallback |
| New postcard entries written and read | Normal cache hit |

## Prerequisites

- Rust toolchain
- Internet access (for the legacy writer to make HTTP requests)

## Step-by-step manual validation

### 1. Build and run the legacy writer

This uses http-cache-reqwest 0.16.0 from crates.io to populate a cache directory
with bincode-serialized entries.

```bash
cd compat-tests/legacy-writer
cargo run -- /tmp/legacy-cache
```

### 2. Read the cache with the new code (bincode fallback)

This uses the current workspace code with `manager-cacache-bincode` and
`http-headers-compat` features to read back the old entries.

```bash
cd compat-tests/read-legacy-cache
cargo run -- /tmp/legacy-cache
```

Expected output: all entries should be HIT (bincode fallback working).

### 3. Verify graceful degradation without compat features

You can also test by modifying `read-legacy-cache/Cargo.toml` to remove
`manager-cacache-bincode` and `http-headers-compat`, then rebuild and run.
Old entries should return as cache misses without errors.

## Automated CI tests

The equivalent scenarios are also tested in the workspace test suite:

```bash
# Test bincode->postcard migration (with compat features)
cargo test -p http-cache --features manager-cacache,manager-cacache-bincode,http-headers-compat cacache_bincode_to_postcard

# Test graceful degradation (postcard only, no bincode feature)
cargo test -p http-cache --features manager-cacache cacache_bincode_entry_read_without_compat

# Full middleware-level e2e test
cargo test -p http-cache-reqwest --features manager-cacache,manager-cacache-bincode,http-headers-compat migration_from_bincode
```

## Key compatibility facts

| | http-cache-reqwest 0.16.0 | http-cache-reqwest 1.0.0-alpha.4 |
|---|---|---|
| http-cache | 0.21.0 | 1.0.0-alpha.4 |
| Serialization | bincode 1.3.3 | postcard 1.1 (default) |
| cacache | 13.1.0 | 13.1.0 (same!) |
| http-cache-semantics | 2.1.0 | 2.1.0 (same!) |
| Cache key format | `METHOD:URI` | `METHOD:URI` (same!) |
11 changes: 11 additions & 0 deletions compat-tests/legacy-writer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "legacy-writer"
version = "0.1.0"
edition = "2021"

[dependencies]
cacache = { version = "13.1.0", default-features = false }
http-cache-reqwest = { version = "0.16.0", features = ["manager-cacache"] }
reqwest = { version = "0.12", features = ["rustls-tls"] }
reqwest-middleware = "0.4"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
59 changes: 59 additions & 0 deletions compat-tests/legacy-writer/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use http_cache_reqwest::{CACacheManager, Cache, CacheMode, HttpCache, HttpCacheOptions};
use reqwest::Client;
use reqwest_middleware::ClientBuilder;
use std::path::PathBuf;

/// Writes cache entries using http-cache-reqwest 0.16.0 (bincode serialization).
/// Used to validate the upgrade path from 0.16 -> 1.0-alpha.
///
/// Usage: cargo run -- <cache-directory>
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cache_dir = std::env::args()
.nth(1)
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("/tmp/legacy-cache"));

println!("Writing legacy cache entries to: {}", cache_dir.display());

let manager = CACacheManager {
path: cache_dir.clone(),
remove_opts: cacache::RemoveOpts::new().remove_fully(true),
};

let client = ClientBuilder::new(Client::builder().build()?)
.with(Cache(HttpCache {
mode: CacheMode::Default,
manager,
options: HttpCacheOptions::default(),
}))
.build();

let urls = [
"https://httpbin.org/cache/300",
"https://httpbin.org/response-headers?Cache-Control=public%2Cmax-age%3D3600",
"https://jsonplaceholder.typicode.com/posts/1",
];

for url in &urls {
println!("\nRequesting: {}", url);
match client.get(*url).send().await {
Ok(response) => {
println!(" Status: {}", response.status());
println!(
" Cache-Control: {:?}",
response.headers().get("cache-control")
);
let body = response.bytes().await?;
println!(" Body length: {} bytes", body.len());
}
Err(e) => {
eprintln!(" Error: {}", e);
}
}
}

println!("\nCache entries written to: {}", cache_dir.display());
println!("Now run the read-legacy-cache tool to verify migration.");
Ok(())
}
9 changes: 9 additions & 0 deletions compat-tests/read-legacy-cache/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "read-legacy-cache"
version = "0.1.0"
edition = "2021"

[dependencies]
http-cache = { path = "../../http-cache", features = ["manager-cacache", "manager-cacache-bincode", "http-headers-compat"] }
http-cache-semantics = "3.0.0"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
67 changes: 67 additions & 0 deletions compat-tests/read-legacy-cache/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use http_cache::{CACacheManager, CacheManager};
use std::path::PathBuf;

/// Reads cache entries written by the legacy-writer (http-cache-reqwest 0.16.0)
/// using the current code (1.0-alpha with postcard + bincode fallback).
///
/// Usage: cargo run -- <cache-directory>
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cache_dir = std::env::args()
.nth(1)
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("/tmp/legacy-cache"));

println!("Reading legacy cache entries from: {}", cache_dir.display());

let manager = CACacheManager::new(cache_dir.clone(), true);

let urls = [
"https://httpbin.org/cache/300",
"https://httpbin.org/response-headers?Cache-Control=public%2Cmax-age%3D3600",
"https://jsonplaceholder.typicode.com/posts/1",
];

let mut success_count = 0;
let mut miss_count = 0;
let mut total = 0;

for url in &urls {
total += 1;
let cache_key = format!("GET:{}", url);
println!("\nLooking up: {}", cache_key);

match manager.get(&cache_key).await {
Ok(Some((response, policy))) => {
success_count += 1;
println!(" HIT - bincode fallback worked!");
println!(" Status: {}", response.status);
println!(" Body length: {} bytes", response.body.len());
println!(" Headers: {:?}", response.headers);
println!(" Version: {:?}", response.version);
println!(" Policy is_stale: {}", policy.is_stale(std::time::SystemTime::now()));
}
Ok(None) => {
miss_count += 1;
println!(" MISS - entry not found or not deserializable");
}
Err(e) => {
eprintln!(" ERROR: {} (this should NOT happen!)", e);
}
}
}

println!("\n--- Summary ---");
println!("Total: {}, Hits: {}, Misses: {}", total, success_count, miss_count);

if success_count == total {
println!("All legacy entries were successfully read via bincode fallback!");
} else if miss_count > 0 && success_count == 0 {
println!("No entries were readable. This could mean:");
println!(" - The legacy-writer hasn't been run yet");
println!(" - The cache directory is wrong");
println!(" - The bincode fallback isn't working");
}

Ok(())
}
2 changes: 1 addition & 1 deletion http-cache-quickcache/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ rust-version = "1.88.0"
[dependencies]
async-trait = "0.1.85"
postcard = { version = "1.1", default-features = false, features = ["alloc"] }
http-cache-semantics = "2.1.0"
http-cache-semantics = "3.0.0"
serde = { version = "1.0.217", features = ["derive"] }
quick_cache = "0.6.9"
http = "1.2.0"
Expand Down
6 changes: 5 additions & 1 deletion http-cache-reqwest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ bytes = "1.8.0"
http = "1.2.0"
http-body = "1.0.1"
http-body-util = "0.1.2"
http-cache-semantics = "2.1.0"
http-cache-semantics = "3.0.0"
reqwest = { version = "0.13.1", default-features = false, features = [
"stream",
] }
Expand All @@ -38,6 +38,10 @@ version = "1.0.0-alpha.4"
default-features = false

[dev-dependencies]
bincode = "1.3.3"
cacache = { version = "13.1.0", default-features = false, features = ["tokio-runtime"] }
http-cache-semantics = "3.0.0"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread"] }
wiremock = "0.6.0"
tempfile = "3.13.0"
Expand Down
Loading