use ngdp_cache::cached_tact_client::CachedTactClient;
use tact_client::{ProtocolVersion, Region};
use tempfile::TempDir;
mod mock_data {
pub const VERSIONS_RESPONSE: &str = r#"Product!STRING:0|Seqn!DEC:4|Flags!STRING:0
## seqn = 3020098
wow|12.0.5.58238|
wow_classic|11.0.5.58162|
wow_classic_era|1.15.5.58162|"#;
pub const CDNS_RESPONSE: &str = r#"Name!STRING:0|Path!STRING:0|Hosts!STRING:0|Servers!STRING:0|ConfigPath!STRING:0
## seqn = 3020099
us|tpr/wow|level3.blizzard.com edgecast.blizzard.com cdn.blizzard.com|http://level3.blizzard.com/?maxhosts=4 http://edgecast.blizzard.com/?maxhosts=4 https://cdn.blizzard.com/?maxhosts=4|tpr/configs/data"#;
pub const BGDL_RESPONSE: &str = r#"Region!STRING:0|ProductConfig!HEX:32
## seqn = 3020100
us|a9e69b29cce65c8e58cb7c6489df2bf8"#;
}
#[tokio::test]
async fn test_cached_tact_client_mock_workflow() {
let temp_dir = TempDir::new().unwrap();
let cache_dir = temp_dir.path().to_path_buf();
let client =
CachedTactClient::with_cache_dir(Region::US, ProtocolVersion::V1, cache_dir.clone())
.await
.unwrap();
assert!(cache_dir.exists());
let product = "wow";
let versions_path = cache_dir
.join("us")
.join("v1")
.join(product)
.join("versions-3020098.bpsv");
if let Some(parent) = versions_path.parent() {
tokio::fs::create_dir_all(parent).await.unwrap();
}
tokio::fs::write(&versions_path, mock_data::VERSIONS_RESPONSE)
.await
.unwrap();
let meta_path = versions_path.with_extension("meta");
let metadata = serde_json::json!({
"timestamp": std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs(),
"ttl_seconds": 300,
"region": "us",
"protocol": "v1",
"product": product,
"endpoint": "versions",
"sequence": 3020098,
"response_size": mock_data::VERSIONS_RESPONSE.len()
});
tokio::fs::write(&meta_path, serde_json::to_string(&metadata).unwrap())
.await
.unwrap();
let cache_structure = cache_dir.join("us").join("v1").join(product);
assert!(cache_structure.exists());
let mut entries = tokio::fs::read_dir(&cache_structure).await.unwrap();
let mut found_files = Vec::new();
while let Some(entry) = entries.next_entry().await.unwrap() {
found_files.push(entry.file_name().to_string_lossy().to_string());
}
assert!(found_files.contains(&"versions-3020098.bpsv".to_string()));
assert!(found_files.contains(&"versions-3020098.meta".to_string()));
client.clear_cache().await.unwrap();
let mut entries = tokio::fs::read_dir(&cache_structure)
.await
.unwrap_or_else(|_| {
panic!("Cache directory should still exist after clear")
});
let mut remaining_files = Vec::new();
while let Some(entry) = entries.next_entry().await.unwrap() {
remaining_files.push(entry.file_name().to_string_lossy().to_string());
}
assert!(
remaining_files.is_empty(),
"Cache should be empty after clear"
);
}
#[tokio::test]
async fn test_cache_isolation_by_region() {
let temp_dir = TempDir::new().unwrap();
let cache_dir = temp_dir.path().to_path_buf();
let _us_client =
CachedTactClient::with_cache_dir(Region::US, ProtocolVersion::V1, cache_dir.clone())
.await
.unwrap();
let _eu_client =
CachedTactClient::with_cache_dir(Region::EU, ProtocolVersion::V1, cache_dir.clone())
.await
.unwrap();
for region in ["us", "eu"] {
let path = cache_dir
.join(region)
.join("v1")
.join("wow")
.join("versions-1000.bpsv");
if let Some(parent) = path.parent() {
tokio::fs::create_dir_all(parent).await.unwrap();
}
tokio::fs::write(&path, format!("{region} data"))
.await
.unwrap();
}
let us_path = cache_dir.join("us").join("v1").join("wow");
let eu_path = cache_dir.join("eu").join("v1").join("wow");
assert!(us_path.exists());
assert!(eu_path.exists());
let us_content = tokio::fs::read_to_string(us_path.join("versions-1000.bpsv"))
.await
.unwrap();
let eu_content = tokio::fs::read_to_string(eu_path.join("versions-1000.bpsv"))
.await
.unwrap();
assert_eq!(us_content, "us data");
assert_eq!(eu_content, "eu data");
}
#[tokio::test]
async fn test_cache_isolation_by_protocol() {
let temp_dir = TempDir::new().unwrap();
let cache_dir = temp_dir.path().to_path_buf();
let _v1_client =
CachedTactClient::with_cache_dir(Region::US, ProtocolVersion::V1, cache_dir.clone())
.await
.unwrap();
let _v2_client =
CachedTactClient::with_cache_dir(Region::US, ProtocolVersion::V2, cache_dir.clone())
.await
.unwrap();
for protocol in ["v1", "v2"] {
let path = cache_dir
.join("us")
.join(protocol)
.join("wow")
.join("versions-2000.bpsv");
if let Some(parent) = path.parent() {
tokio::fs::create_dir_all(parent).await.unwrap();
}
tokio::fs::write(&path, format!("{protocol} data"))
.await
.unwrap();
}
let v1_content = tokio::fs::read_to_string(
cache_dir
.join("us")
.join("v1")
.join("wow")
.join("versions-2000.bpsv"),
)
.await
.unwrap();
let v2_content = tokio::fs::read_to_string(
cache_dir
.join("us")
.join("v2")
.join("wow")
.join("versions-2000.bpsv"),
)
.await
.unwrap();
assert_eq!(v1_content, "v1 data");
assert_eq!(v2_content, "v2 data");
}
#[tokio::test]
async fn test_sequence_number_handling() {
let temp_dir = TempDir::new().unwrap();
let cache_dir = temp_dir.path().to_path_buf();
let client =
CachedTactClient::with_cache_dir(Region::US, ProtocolVersion::V1, cache_dir.clone())
.await
.unwrap();
let product_dir = cache_dir.join("us").join("v1").join("wow");
tokio::fs::create_dir_all(&product_dir).await.unwrap();
let sequences = [3020098, 3020099, 3020100];
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
for (i, seq) in sequences.iter().enumerate() {
let data_path = product_dir.join(format!("versions-{seq}.bpsv"));
let meta_path = product_dir.join(format!("versions-{seq}.meta"));
tokio::fs::write(&data_path, format!("## seqn = {seq}\ndata"))
.await
.unwrap();
let metadata = serde_json::json!({
"timestamp": now - (60 * i as u64), "ttl_seconds": 300,
"region": "us",
"protocol": "v1",
"product": "wow",
"endpoint": "versions",
"sequence": seq,
"response_size": 20
});
tokio::fs::write(&meta_path, serde_json::to_string(&metadata).unwrap())
.await
.unwrap();
}
for seq in sequences {
let path = product_dir.join(format!("versions-{seq}.bpsv"));
assert!(path.exists(), "Sequence {seq} should exist");
}
client.clear_expired().await.unwrap();
for seq in sequences {
let path = product_dir.join(format!("versions-{seq}.bpsv"));
assert!(
path.exists(),
"Sequence {seq} should still exist after clear_expired"
);
}
}
#[tokio::test]
async fn test_endpoint_differentiation() {
let temp_dir = TempDir::new().unwrap();
let cache_dir = temp_dir.path().to_path_buf();
let _client =
CachedTactClient::with_cache_dir(Region::US, ProtocolVersion::V1, cache_dir.clone())
.await
.unwrap();
let product_dir = cache_dir.join("us").join("v1").join("wow");
tokio::fs::create_dir_all(&product_dir).await.unwrap();
let endpoints = [
("versions", mock_data::VERSIONS_RESPONSE),
("cdns", mock_data::CDNS_RESPONSE), ("bgdl", mock_data::BGDL_RESPONSE),
];
for (endpoint, data) in endpoints {
let path = product_dir.join(format!("{endpoint}-1000.bpsv"));
tokio::fs::write(&path, data).await.unwrap();
}
for (endpoint, _) in endpoints {
let path = product_dir.join(format!("{endpoint}-1000.bpsv"));
assert!(path.exists(), "{endpoint} cache should exist");
}
let versions_content = tokio::fs::read_to_string(product_dir.join("versions-1000.bpsv"))
.await
.unwrap();
assert!(versions_content.contains("wow|12.0.5.58238"));
let cdns_content = tokio::fs::read_to_string(product_dir.join("cdns-1000.bpsv"))
.await
.unwrap();
assert!(cdns_content.contains("level3.blizzard.com"));
assert!(cdns_content.contains("tpr/configs/data"));
let bgdl_content = tokio::fs::read_to_string(product_dir.join("bgdl-1000.bpsv"))
.await
.unwrap();
assert!(bgdl_content.contains("a9e69b29cce65c8e58cb7c6489df2bf8"));
}