photoncloud-monorepo/flashdns/crates/flashdns-server/tests/reverse_dns_integration.rs
centra a7ec7e2158 Add T026 practical test + k8shost to flake + workspace files
- Created T026-practical-test task.yaml for MVP smoke testing
- Added k8shost-server to flake.nix (packages, apps, overlays)
- Staged all workspace directories for nix flake build
- Updated flake.nix shellHook to include k8shost

Resolves: T026.S1 blocker (R8 - nix submodule visibility)
2025-12-09 06:07:50 +09:00

165 lines
5.9 KiB
Rust

//! Integration test for reverse DNS pattern-based PTR generation
use std::net::{IpAddr, Ipv4Addr};
use flashdns_types::ReverseZone;
use std::sync::Arc;
use tokio;
#[tokio::test]
#[ignore] // Requires running servers
async fn test_reverse_dns_lifecycle() {
// Test comprehensive reverse DNS lifecycle:
// 1. Create ReverseZone via metadata store
// 2. Query PTR via DNS handler pattern matching
// 3. Verify response with pattern substitution
// 4. Delete zone
// 5. Verify PTR query fails after deletion
// Setup: Create metadata store
let metadata = Arc::new(
flashdns_server::metadata::DnsMetadataStore::new_in_memory()
);
// Step 1: Create reverse zone for 10.0.0.0/8
let zone = ReverseZone {
id: uuid::Uuid::new_v4().to_string(),
org_id: "test-org".to_string(),
project_id: Some("test-project".to_string()),
cidr: "10.0.0.0/8".to_string(),
arpa_zone: "10.in-addr.arpa.".to_string(), // Will be auto-generated
ptr_pattern: "{4}-{3}-{2}-{1}.hosts.cloud.local.".to_string(),
ttl: 3600,
created_at: chrono::Utc::now().timestamp() as u64,
updated_at: chrono::Utc::now().timestamp() as u64,
};
metadata.create_reverse_zone(zone.clone()).await.unwrap();
// Step 2: Simulate PTR query for 10.1.2.3
// Note: This requires DNS handler integration, which we'll test via pattern utilities
use flashdns_server::dns::ptr_patterns::{parse_ptr_query_to_ip, apply_pattern};
let ptr_query = "3.2.1.10.in-addr.arpa.";
let ip = parse_ptr_query_to_ip(ptr_query).unwrap();
assert_eq!(ip, IpAddr::V4(Ipv4Addr::new(10, 1, 2, 3)));
// Step 3: Apply pattern substitution
let result = apply_pattern(&zone.ptr_pattern, ip);
assert_eq!(result, "3-2-1-10.hosts.cloud.local.");
// Step 4: Verify zone can be retrieved
let retrieved = metadata.get_reverse_zone(&zone.id).await.unwrap();
assert!(retrieved.is_some());
let retrieved_zone = retrieved.unwrap();
assert_eq!(retrieved_zone.cidr, "10.0.0.0/8");
assert_eq!(retrieved_zone.ptr_pattern, "{4}-{3}-{2}-{1}.hosts.cloud.local.");
// Step 5: Delete zone
metadata.delete_reverse_zone(&zone).await.unwrap();
// Step 6: Verify zone no longer exists
let deleted_check = metadata.get_reverse_zone(&zone.id).await.unwrap();
assert!(deleted_check.is_none());
println!("✓ Reverse DNS lifecycle test passed");
}
#[tokio::test]
#[ignore]
async fn test_reverse_dns_ipv6() {
// Test IPv6 reverse DNS pattern
use std::net::Ipv6Addr;
use flashdns_server::dns::ptr_patterns::apply_pattern;
let pattern = "v6-{short}.example.com.";
let ip = IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
let result = apply_pattern(pattern, ip);
assert_eq!(result, "v6-2001-db8--1.example.com.");
println!("✓ IPv6 reverse DNS pattern test passed");
}
#[tokio::test]
#[ignore]
async fn test_multiple_reverse_zones_longest_prefix() {
// Test longest prefix matching
let metadata = Arc::new(
flashdns_server::metadata::DnsMetadataStore::new_in_memory()
);
// Create /8 zone
let zone_8 = ReverseZone {
id: uuid::Uuid::new_v4().to_string(),
org_id: "test-org".to_string(),
project_id: Some("test-project".to_string()),
cidr: "192.0.0.0/8".to_string(),
arpa_zone: "192.in-addr.arpa.".to_string(),
ptr_pattern: "host-{ip}-slash8.example.com.".to_string(),
ttl: 3600,
created_at: chrono::Utc::now().timestamp() as u64,
updated_at: chrono::Utc::now().timestamp() as u64,
};
// Create /16 zone (more specific)
let zone_16 = ReverseZone {
id: uuid::Uuid::new_v4().to_string(),
org_id: "test-org".to_string(),
project_id: Some("test-project".to_string()),
cidr: "192.168.0.0/16".to_string(),
arpa_zone: "168.192.in-addr.arpa.".to_string(),
ptr_pattern: "host-{ip}-slash16.example.com.".to_string(),
ttl: 3600,
created_at: chrono::Utc::now().timestamp() as u64,
updated_at: chrono::Utc::now().timestamp() as u64,
};
// Create /24 zone (most specific)
let zone_24 = ReverseZone {
id: uuid::Uuid::new_v4().to_string(),
org_id: "test-org".to_string(),
project_id: Some("test-project".to_string()),
cidr: "192.168.1.0/24".to_string(),
arpa_zone: "1.168.192.in-addr.arpa.".to_string(),
ptr_pattern: "host-{ip}-slash24.example.com.".to_string(),
ttl: 3600,
created_at: chrono::Utc::now().timestamp() as u64,
updated_at: chrono::Utc::now().timestamp() as u64,
};
metadata.create_reverse_zone(zone_8.clone()).await.unwrap();
metadata.create_reverse_zone(zone_16.clone()).await.unwrap();
metadata.create_reverse_zone(zone_24.clone()).await.unwrap();
// Query IP that matches all three zones
// Longest prefix (most specific) should win: /24 > /16 > /8
let _ip = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 5));
// Note: Actual longest-prefix matching is in DNS handler
// Here we verify all zones are stored correctly
let all_zones = metadata.list_reverse_zones("test-org", Some("test-project")).await.unwrap();
assert_eq!(all_zones.len(), 3);
println!("✓ Multiple reverse zones test passed");
}
#[tokio::test]
async fn test_pattern_substitution_variations() {
// Test various pattern substitution formats
use flashdns_server::dns::ptr_patterns::apply_pattern;
let ip = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 5));
// Test individual octets
assert_eq!(apply_pattern("{1}.{2}.{3}.{4}", ip), "192.168.1.5");
// Test reversed octets
assert_eq!(apply_pattern("{4}.{3}.{2}.{1}", ip), "5.1.168.192");
// Test dashed IP
assert_eq!(apply_pattern("{ip}", ip), "192-168-1-5");
// Test combined pattern
assert_eq!(apply_pattern("server-{4}-subnet-{3}.dc.example.com.", ip), "server-5-subnet-1.dc.example.com.");
println!("✓ Pattern substitution variations test passed");
}