ContainerConfig

Struct ContainerConfig 

Source
pub struct ContainerConfig {
    pub image: String,
    pub ports: Vec<(u16, u16)>,
    pub auto_ports: Vec<u16>,
    pub env: Vec<(String, String)>,
    pub name: Option<String>,
    pub ready_timeout: Duration,
    pub auto_cleanup: bool,
}

Fields§

§image: String§ports: Vec<(u16, u16)>§auto_ports: Vec<u16>§env: Vec<(String, String)>§name: Option<String>§ready_timeout: Duration§auto_cleanup: bool

Implementations§

Source§

impl ContainerConfig

Source

pub fn new(image: &str) -> Self

Examples found in repository?
examples/user_specified_ports.rs (line 18)
12fn main() {
13    println!("🔧 User-Specified Ports Example");
14    println!("==============================");
15    println!();
16    
17    // Example 1: PostgreSQL on standard port 5432
18    let postgres_container = ContainerConfig::new("postgres:13-alpine")
19        .port(5432, 5432)     // Map host port 5432 to container port 5432
20        .env("POSTGRES_PASSWORD", "testpass")
21        .env("POSTGRES_DB", "testdb")
22        .name("postgres_test")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Web service on port 8080
26    let web_container = ContainerConfig::new("nginx:alpine")
27        .port(8080, 80)       // Map host port 8080 to container port 80
28        .name("nginx_test")
29        .ready_timeout(Duration::from_secs(10));
30    
31    // Example 3: Mixed configuration - some fixed, some auto
32    let api_container = ContainerConfig::new("httpd:alpine")
33        .port(3000, 80)       // Fixed port for main API
34        .auto_port(443)       // Auto-assign for HTTPS
35        .auto_port(9090)      // Auto-assign for metrics
36        .name("api_test")
37        .ready_timeout(Duration::from_secs(10));
38    
39    println!("📋 Container Configurations:");
40    println!("1. PostgreSQL: Fixed on localhost:5432 (standard PostgreSQL port)");
41    println!("2. Web Service: Fixed on localhost:8080");
42    println!("3. API Service: Fixed localhost:3000, auto-assigned for 443 and 9090");
43    println!();
44    
45    // Clone containers for hooks
46    let postgres_before = postgres_container.clone();
47    let web_before = web_container.clone();
48    let api_before = api_container.clone();
49    
50    // Start containers in before_each
51    before_each(move |ctx| {
52        println!("🚀 before_each: Starting containers with specified ports...");
53        
54        // Start PostgreSQL container
55        let postgres_info = postgres_before.start()
56            .map_err(|e| format!("Failed to start PostgreSQL container: {}", e))?;
57        ctx.set_data("postgres_container_info", postgres_info.clone());
58        
59        println!("✅ PostgreSQL started: {}", postgres_info.container_id);
60        println!("   📍 Port mappings: {}", postgres_info.ports_summary());
61        println!("   🗄️ Database URL: postgresql://postgres:testpass@localhost:5432/testdb");
62        
63        // Start web container
64        let web_info = web_before.start()
65            .map_err(|e| format!("Failed to start web container: {}", e))?;
66        ctx.set_data("web_container_info", web_info.clone());
67        
68        println!("✅ Web service started: {}", web_info.container_id);
69        println!("   📍 Port mappings: {}", web_info.ports_summary());
70        println!("   🌐 Web accessible at: http://localhost:8080");
71        
72        // Start API container
73        let api_info = api_before.start()
74            .map_err(|e| format!("Failed to start API container: {}", e))?;
75        ctx.set_data("api_container_info", api_info.clone());
76        
77        println!("✅ API service started: {}", api_info.container_id);
78        println!("   📍 Port mappings: {}", api_info.ports_summary());
79        println!("   🔗 API accessible at: http://localhost:3000");
80        if let Some(https_port) = api_info.host_port_for(443) {
81            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
82        }
83        if let Some(metrics_port) = api_info.host_port_for(9090) {
84            println!("   📊 Metrics accessible at: http://localhost:{}/metrics", metrics_port);
85        }
86        
87        Ok(())
88    });
89    
90    // Cleanup containers in after_each
91    let postgres_after = postgres_container.clone();
92    let web_after = web_container.clone();
93    let api_after = api_container.clone();
94    
95    after_each(move |ctx| {
96        println!("🧹 after_each: Cleaning up containers...");
97        
98        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
99            let _ = postgres_after.stop(&postgres_info.container_id);
100            println!("🛑 Stopped PostgreSQL container");
101        }
102        
103        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
104            let _ = web_after.stop(&web_info.container_id);
105            println!("🛑 Stopped web container");
106        }
107        
108        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
109            let _ = api_after.stop(&api_info.container_id);
110            println!("🛑 Stopped API container");
111        }
112        
113        println!("✅ All containers cleaned up!");
114        Ok(())
115    });
116    
117    // Test 1: Database connection test
118    test("test_database_connection", |ctx| {
119        println!("🧪 Testing database connection on fixed port 5432...");
120        
121        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
122            assert_eq!(postgres_info.host_port_for(5432), Some(5432));
123            assert_eq!(postgres_info.url_for_port(5432), Some("localhost:5432".to_string()));
124            println!("✅ Database is accessible on the expected port 5432");
125        } else {
126            return Err("PostgreSQL container info not found".into());
127        }
128        
129        Ok(())
130    });
131    
132    // Test 2: Web service test
133    test("test_web_service_fixed_port", |ctx| {
134        println!("🧪 Testing web service on fixed port 8080...");
135        
136        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
137            assert_eq!(web_info.host_port_for(80), Some(8080));
138            assert_eq!(web_info.url_for_port(80), Some("localhost:8080".to_string()));
139            println!("✅ Web service is accessible on the expected port 8080");
140        } else {
141            return Err("Web container info not found".into());
142        }
143        
144        Ok(())
145    });
146    
147    // Test 3: Mixed configuration test
148    test("test_mixed_port_configuration", |ctx| {
149        println!("🧪 Testing mixed port configuration (fixed + auto)...");
150        
151        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
152            // Test fixed port
153            assert_eq!(api_info.host_port_for(80), Some(3000));
154            assert_eq!(api_info.url_for_port(80), Some("localhost:3000".to_string()));
155            println!("✅ Fixed port 3000 -> 80 is working");
156            
157            // Test auto-assigned ports
158            if let Some(https_port) = api_info.host_port_for(443) {
159                assert!(https_port > 1024); // Should be a high port
160                println!("✅ Auto-assigned HTTPS port: {}", https_port);
161            }
162            
163            if let Some(metrics_port) = api_info.host_port_for(9090) {
164                assert!(metrics_port > 1024); // Should be a high port
165                println!("✅ Auto-assigned metrics port: {}", metrics_port);
166            }
167            
168            println!("✅ Mixed configuration is working correctly");
169        } else {
170            return Err("API container info not found".into());
171        }
172        
173        Ok(())
174    });
175    
176    println!("🚀 Running user-specified ports tests...");
177    
178    let config = TestConfig {
179        html_report: Some("user-specified-ports-report.html".to_string()),
180        ..Default::default()
181    };
182    
183    let exit_code = run_tests_with_config(config);
184    
185    println!();
186    println!("🎉 Tests completed!");
187    println!("📊 Check the HTML report for detailed results.");
188    println!();
189    println!("💡 Key Takeaways:");
190    println!("   • Use .port(host_port, container_port) for fixed port mappings");
191    println!("   • Use .auto_port(container_port) for automatic port assignment");
192    println!("   • Mix both approaches for maximum flexibility");
193    println!("   • Fixed ports are great for services with standard ports (5432, 3306, etc.)");
194    println!("   • Auto-ports prevent conflicts in parallel test environments");
195    
196    std::process::exit(exit_code);
197}
More examples
Hide additional examples
examples/mongodb_integration.rs (line 74)
68fn main() {
69    println!("🐳 MongoDB Integration Example with Container Hooks");
70    println!("==================================================");
71    println!();
72    
73    // Define container configuration with auto-port for MongoDB
74    let mongo_container = ContainerConfig::new("mongo:5.0")
75        .auto_port(27017) // Automatically assign available host port for MongoDB
76        .env("MONGO_INITDB_ROOT_USERNAME", "admin")
77        .env("MONGO_INITDB_ROOT_PASSWORD", "password")
78        .name("test_mongodb")
79        .ready_timeout(Duration::from_secs(30));
80    
81    println!("📋 Container Configuration:");
82    println!("  Image: {}", mongo_container.image);
83    println!("  Auto-ports: {:?}", mongo_container.auto_ports);
84    println!("  Environment: {:?}", mongo_container.env);
85    println!("  Name: {:?}", mongo_container.name);
86    println!("  Ready Timeout: {:?}", mongo_container.ready_timeout);
87    println!("  Auto-cleanup: {}", mongo_container.auto_cleanup);
88    println!();
89    
90    // Clone for before_each hook
91    let mongo_container_before = mongo_container.clone();
92    
93    // Register before_each hook to start container
94    before_each(move |ctx| {
95        println!("🔄 before_each: Starting MongoDB container...");
96        
97        // Start the container and get ContainerInfo
98        let container_info = mongo_container_before.start()
99            .map_err(|e| format!("Failed to start container: {}", e))?;
100        
101        // Store container info in context for tests to access
102        ctx.set_data("mongo_container_info", container_info.clone());
103        
104        // Log container details including auto-assigned ports
105        println!("✅ before_each: MongoDB container {} started", container_info.container_id);
106        println!("🌐 Container exposed on: {}", container_info.ports_summary());
107        if let Some(primary_url) = container_info.primary_url() {
108            println!("🔗 Primary URL: {}", primary_url);
109        }
110        
111        Ok(())
112    });
113    
114    // Register after_each hook to stop container
115    let mongo_container_after = mongo_container.clone();
116    rust_test_harness::after_each(move |ctx| {
117        println!("🔄 after_each: Stopping MongoDB container...");
118        
119        // Get container info from context
120        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
121            .expect("Container info should be available");
122        
123        // Stop the container
124        mongo_container_after.stop(&container_info.container_id)
125            .map_err(|e| format!("Failed to stop container: {}", e))?;
126        
127        println!("✅ after_each: MongoDB container {} stopped", container_info.container_id);
128        Ok(())
129    });
130    
131    // Test 1: Basic MongoDB operations
132    test("test_mongodb_basic_operations", |ctx| {
133        println!("🧪 Running test: test_mongodb_basic_operations");
134        
135        // Get container info from context
136        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
137            .expect("Container info should be available");
138        
139        // Show how to access port information
140        println!("🌐 Container {} is running on:", container_info.container_id);
141        println!("   Ports: {}", container_info.ports_summary());
142        if let Some(primary_url) = container_info.primary_url() {
143            println!("   Primary URL: {}", primary_url);
144        }
145        
146        // Get the MongoDB port (27017) and show the actual host port
147        if let Some(host_port) = container_info.host_port_for(27017) {
148            println!("   MongoDB accessible at: localhost:{}", host_port);
149        }
150        
151        // Create MongoDB client
152        let mut client = MongoClient::new(container_info.container_id.clone());
153        
154        // Connect to MongoDB
155        client.connect()?;
156        
157        // Insert a document
158        client.insert_document("users", r#"{"name": "John Doe", "email": "john@example.com"}"#)?;
159        
160        // Find documents
161        let documents = client.find_documents("users", r#"{"name": "John Doe"}"#)?;
162        assert_eq!(documents.len(), 2);
163        
164        // Disconnect
165        client.disconnect()?;
166        
167        println!("✅ test_mongodb_basic_operations passed");
168        Ok(())
169    });
170    
171    // Test 2: Multiple operations
172    test("test_mongodb_multiple_operations", |ctx| {
173        println!("🧪 Running test: test_mongodb_multiple_operations");
174        
175        // Get container info from context
176        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
177            .expect("Container info should be available");
178        
179        // Show container status
180        println!("🌐 Container {} status:", container_info.container_id);
181        println!("   Active ports: {}", container_info.ports_summary());
182        
183        // Create MongoDB client
184        let mut client = MongoClient::new(container_info.container_id.clone());
185        
186        // Connect to MongoDB
187        client.connect()?;
188        
189        // Insert multiple documents
190        client.insert_document("products", r#"{"name": "Laptop", "price": 999.99}"#)?;
191        client.insert_document("products", r#"{"name": "Mouse", "price": 29.99}"#)?;
192        client.insert_document("products", r#"{"name": "Keyboard", "price": 79.99}"#)?;
193        
194        // Find documents
195        let documents = client.find_documents("products", r#"{"price": {"$gt": 50}}"#)?;
196        assert_eq!(documents.len(), 2); // Laptop and Keyboard
197        
198        // Disconnect
199        client.disconnect()?;
200        
201        println!("✅ test_mongodb_multiple_operations passed");
202        Ok(())
203    });
204    
205    // Test 3: Error handling
206    test("test_mongodb_error_handling", |ctx| {
207        println!("🧪 Running test: test_mongodb_error_handling");
208        
209        // Get container ID from context
210        let container_id = ctx.get_data::<String>("mongo_container_id")
211            .expect("Container ID should be available")
212            .to_string();
213        
214        // Create MongoDB client
215        let client = MongoClient::new(container_id);
216        
217        // Try to insert without connecting (should fail)
218        let result = client.insert_document("users", r#"{"name": "Test"}"#);
219        assert!(result.is_err());
220        assert_eq!(result.unwrap_err(), "Not connected to MongoDB");
221        
222        println!("✅ test_mongodb_error_handling passed");
223        Ok(())
224    });
225    
226    // Test 4: Performance testing
227    test("test_mongodb_performance", |ctx| {
228        println!("🧪 Running test: test_mongodb_performance");
229        
230        // Get container ID from context
231        let container_id = ctx.get_data::<String>("mongo_container_id")
232            .expect("Container ID should be available")
233            .to_string();
234        
235        // Create MongoDB client
236        let mut client = MongoClient::new(container_id);
237        
238        // Connect to MongoDB
239        client.connect()?;
240        
241        // Simulate bulk operations
242        for i in 0..100 {
243            client.insert_document("bulk_data", &format!(r#"{{"index": {}, "data": "bulk_item_{}"}}"#, i, i))?;
244        }
245        
246        // Simulate bulk retrieval
247        let documents = client.find_documents("bulk_data", r#"{"index": {"$lt": 50}}"#)?;
248        assert_eq!(documents.len(), 2); // Mock always returns 2
249        
250        // Disconnect
251        client.disconnect()?;
252        
253        println!("✅ test_mongodb_performance passed");
254        Ok(())
255    });
256    
257    println!("\n🚀 Running MongoDB integration tests...");
258    println!("   Each test will get a fresh MongoDB container via before_each");
259    println!("   Each test will clean up its container via after_each");
260    println!();
261    
262    // Run tests with container hooks enabled
263    let config = TestConfig {
264        skip_hooks: Some(false),
265        ..Default::default()
266    };
267    
268    let result = run_tests_with_config(config);
269    
270    println!("\n📊 Test Results:");
271    if result == 0 {
272        println!("✅ All MongoDB integration tests passed!");
273        println!("🎯 Container lifecycle management working correctly");
274        println!("🐳 Each test got its own MongoDB container");
275        println!("🧹 Each test cleaned up its container properly");
276    } else {
277        println!("❌ Some tests failed");
278    }
279    
280    println!("\n💡 Key Benefits of this approach:");
281    println!("   • Clean separation of concerns");
282    println!("   • Each test gets a fresh container");
283    println!("   • Automatic cleanup via after_each");
284    println!("   • Easy to configure containers");
285    println!("   • No complex global state management");
286}
examples/auto_port_demo.rs (line 18)
12fn main() {
13    println!("🚀 Auto-Port and Container Management Demo");
14    println!("==========================================");
15    println!();
16    
17    // Example 1: Web service with auto-port
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80) // Automatically assign host port for container port 80
20        .env("NGINX_HOST", "localhost")
21        .name("web_service")
22        .ready_timeout(Duration::from_secs(15));
23    
24    // Example 2: Database with auto-port
25    let db_container = ContainerConfig::new("postgres:13-alpine")
26        .auto_port(5432) // Automatically assign host port for container port 5432
27        .env("POSTGRES_PASSWORD", "testpass")
28        .env("POSTGRES_DB", "testdb")
29        .name("test_database")
30        .ready_timeout(Duration::from_secs(20));
31    
32    // Example 3: Redis with auto-port
33    let redis_container = ContainerConfig::new("redis:6-alpine")
34        .auto_port(6379) // Automatically assign host port for container port 6379
35        .name("test_redis")
36        .ready_timeout(Duration::from_secs(10));
37    
38    // Example 4: Mixed configuration (manual + auto ports)
39    let mixed_container = ContainerConfig::new("httpd:alpine")
40        .port(8080, 80) // Manual port mapping
41        .auto_port(443) // Auto port for HTTPS
42        .env("APACHE_DOCUMENT_ROOT", "/var/www/html")
43        .name("mixed_ports")
44        .ready_timeout(Duration::from_secs(15));
45    
46    println!("📋 Container Configurations:");
47    println!("1. Web Service (nginx):");
48    println!("   - Image: {}", web_container.image);
49    println!("   - Auto-ports: {:?}", web_container.auto_ports);
50    println!("   - Auto-cleanup: {}", web_container.auto_cleanup);
51    
52    println!("2. Database (postgres):");
53    println!("   - Image: {}", db_container.image);
54    println!("   - Auto-ports: {:?}", db_container.auto_ports);
55    println!("   - Auto-cleanup: {}", db_container.auto_cleanup);
56    
57    println!("3. Cache (redis):");
58    println!("   - Image: {}", redis_container.image);
59    println!("   - Auto-ports: {:?}", redis_container.auto_ports);
60    println!("   - Auto-cleanup: {}", redis_container.auto_cleanup);
61    
62    println!("4. Mixed (httpd):");
63    println!("   - Image: {}", mixed_container.image);
64    println!("   - Manual ports: {:?}", mixed_container.ports);
65    println!("   - Auto-ports: {:?}", mixed_container.auto_ports);
66    println!("   - Auto-cleanup: {}", mixed_container.auto_cleanup);
67    println!();
68    
69    // Clone containers for hooks
70    let web_before = web_container.clone();
71    let db_before = db_container.clone();
72    let redis_before = redis_container.clone();
73    let mixed_before = mixed_container.clone();
74    
75    // Start all containers in before_each for each test
76    before_each(move |ctx| {
77        println!("🚀 before_each: Starting all containers...");
78        
79        // Start web container
80        let web_info = web_before.start()
81            .map_err(|e| format!("Failed to start web container: {}", e))?;
82        ctx.set_data("web_container_info", web_info.clone());
83        println!("✅ Web container started: {}", web_info.container_id);
84        println!("   Ports: {}", web_info.ports_summary());
85        if let Some(url) = web_info.primary_url() {
86            println!("   URL: {}", url);
87        }
88        
89        // Start database container
90        let db_info = db_before.start()
91            .map_err(|e| format!("Failed to start db container: {}", e))?;
92        ctx.set_data("db_container_info", db_info.clone());
93        println!("✅ Database container started: {}", db_info.container_id);
94        println!("   Ports: {}", db_info.ports_summary());
95        if let Some(host_port) = db_info.host_port_for(5432) {
96            println!("   PostgreSQL accessible at: localhost:{}", host_port);
97        }
98        
99        // Start redis container
100        let redis_info = redis_before.start()
101            .map_err(|e| format!("Failed to start redis container: {}", e))?;
102        ctx.set_data("redis_container_info", redis_info.clone());
103        println!("✅ Redis container started: {}", redis_info.container_id);
104        println!("   Ports: {}", redis_info.ports_summary());
105        if let Some(host_port) = redis_info.host_port_for(6379) {
106            println!("   Redis accessible at: localhost:{}", host_port);
107        }
108        
109        // Start mixed container
110        let mixed_info = mixed_before.start()
111            .map_err(|e| format!("Failed to start mixed container: {}", e))?;
112        ctx.set_data("mixed_container_info", mixed_info.clone());
113        println!("✅ Mixed container started: {}", mixed_info.container_id);
114        println!("   Ports: {}", mixed_info.ports_summary());
115        if let Some(host_port) = mixed_info.host_port_for(443) {
116            println!("   HTTPS accessible at: localhost:{}", host_port);
117        }
118        
119        println!("🎉 All containers started successfully!");
120        Ok(())
121    });
122    
123    // Cleanup all containers in after_each for each test
124    let web_after = web_container.clone();
125    let db_after = db_container.clone();
126    let redis_after = redis_container.clone();
127    let mixed_after = mixed_container.clone();
128    
129    after_each(move |ctx| {
130        println!("🧹 after_each: Cleaning up all containers...");
131        
132        // Get all container info and stop them
133        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
134            let _ = web_after.stop(&web_info.container_id);
135            println!("🛑 Stopped web container: {}", web_info.container_id);
136        }
137        
138        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
139            let _ = db_after.stop(&db_info.container_id);
140            println!("🛑 Stopped database container: {}", db_info.container_id);
141        }
142        
143        if let Some(redis_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info") {
144            let _ = redis_after.stop(&redis_info.container_id);
145            println!("🛑 Stopped redis container: {}", redis_info.container_id);
146        }
147        
148        if let Some(mixed_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info") {
149            let _ = mixed_after.stop(&mixed_info.container_id);
150            println!("🛑 Stopped mixed container: {}", mixed_info.container_id);
151        }
152        
153        println!("✅ All containers cleaned up!");
154        Ok(())
155    });
156    
157    // Test 1: Access web service
158    test("test_web_service_access", |ctx| {
159        println!("🧪 Testing web service access...");
160        
161        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
162            .expect("Web container info should be available");
163        
164        println!("🌐 Web service container: {}", web_info.container_id);
165        println!("   Ports: {}", web_info.ports_summary());
166        println!("   Primary URL: {}", web_info.primary_url().unwrap_or("None"));
167        
168        // In a real test, you would make HTTP requests to the container
169        // For demo purposes, just verify the port information
170        assert!(web_info.host_port_for(80).is_some(), "Web service should have port 80 exposed");
171        
172        println!("✅ Web service test passed");
173        Ok(())
174    });
175    
176    // Test 2: Access database
177    test("test_database_access", |ctx| {
178        println!("🧪 Testing database access...");
179        
180        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
181            .expect("Database container info should be available");
182        
183        println!("🗄️ Database container: {}", db_info.container_id);
184        println!("   Ports: {}", db_info.ports_summary());
185        
186        // Verify PostgreSQL port is exposed
187        let postgres_port = db_info.host_port_for(5432)
188            .expect("PostgreSQL port 5432 should be exposed");
189        println!("   PostgreSQL accessible at: localhost:{}", postgres_port);
190        
191        // In a real test, you would connect to the database
192        // For demo purposes, just verify the port information
193        assert!(postgres_port > 0, "PostgreSQL port should be valid");
194        
195        println!("✅ Database test passed");
196        Ok(())
197    });
198    
199    // Test 3: Access redis
200    test("test_redis_access", |ctx| {
201        println!("🧪 Testing redis access...");
202        
203        let redis_info = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info")
204            .expect("Redis container info should be available");
205        
206        println!("🔴 Redis container: {}", redis_info.container_id);
207        println!("   Ports: {}", redis_info.ports_summary());
208        
209        // Verify Redis port is exposed
210        let redis_port = redis_info.host_port_for(6379)
211            .expect("Redis port 6379 should be exposed");
212        println!("   Redis accessible at: localhost:{}", redis_port);
213        
214        // In a real test, you would connect to Redis
215        // For demo purposes, just verify the port information
216        assert!(redis_port > 0, "Redis port should be valid");
217        
218        println!("✅ Redis test passed");
219        Ok(())
220    });
221    
222    // Test 4: Mixed port configuration
223    test("test_mixed_port_config", |ctx| {
224        println!("🧪 Testing mixed port configuration...");
225        
226        let mixed_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info")
227            .expect("Mixed container info should be available");
228        
229        println!("🔀 Mixed container: {}", mixed_info.container_id);
230        println!("   Ports: {}", mixed_info.ports_summary());
231        
232        // Verify both manual and auto ports
233        let http_port = mixed_info.host_port_for(80)
234            .expect("HTTP port 80 should be exposed");
235        let https_port = mixed_info.host_port_for(443)
236            .expect("HTTPS port 443 should be exposed");
237        
238        println!("   HTTP accessible at: localhost:{}", http_port);
239        println!("   HTTPS accessible at: localhost:{}", https_port);
240        
241        // Verify the manual port mapping (8080 -> 80)
242        assert_eq!(http_port, 8080, "Manual port mapping should work");
243        
244        // Verify auto port is different from manual port
245        assert_ne!(https_port, 8080, "Auto port should be different from manual port");
246        
247        println!("✅ Mixed port configuration test passed");
248        Ok(())
249    });
250    
251    // Test 5: Container info methods
252    test("test_container_info_methods", |ctx| {
253        println!("🧪 Testing container info methods...");
254        
255        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
256            .expect("Web container info should be available");
257        
258        // Test all the convenience methods
259        println!("🔍 Testing container info methods for: {}", web_info.container_id);
260        
261        // Test primary_url
262        if let Some(url) = web_info.primary_url() {
263            println!("   Primary URL: {}", url);
264            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
265        }
266        
267        // Test url_for_port
268        if let Some(url) = web_info.url_for_port(80) {
269            println!("   URL for port 80: {}", url);
270            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
271        }
272        
273        // Test host_port_for
274        if let Some(host_port) = web_info.host_port_for(80) {
275            println!("   Host port for container port 80: {}", host_port);
276            assert!(host_port > 0, "Host port should be valid");
277        }
278        
279        // Test ports_summary
280        let summary = web_info.ports_summary();
281        println!("   Ports summary: {}", summary);
282        assert!(!summary.is_empty(), "Ports summary should not be empty");
283        
284        println!("✅ Container info methods test passed");
285        Ok(())
286    });
287    
288    println!("🚀 Running tests with auto-port functionality...");
289    println!();
290    
291    // Run the tests
292    let config = TestConfig {
293        html_report: Some("auto-port-demo-report.html".to_string()),
294        ..Default::default()
295    };
296    
297    let exit_code = run_tests_with_config(config);
298    
299    println!();
300    if exit_code == 0 {
301        println!("🎉 All tests passed! Auto-port functionality is working correctly.");
302        println!("📊 Check the HTML report for detailed results.");
303    } else {
304        println!("❌ Some tests failed. Check the output above for details.");
305    }
306    
307    std::process::exit(exit_code);
308}
examples/container_port_access.rs (line 18)
12fn main() {
13    println!("🌐 Container Port and URL Access Example");
14    println!("========================================");
15    println!();
16    
17    // Example 1: Web service with multiple auto-ports
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80)      // Auto-assign port for HTTP
20        .auto_port(443)     // Auto-assign port for HTTPS
21        .env("NGINX_HOST", "localhost")
22        .name("web_service")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Database with auto-port
26    let db_container = ContainerConfig::new("postgres:13-alpine")
27        .auto_port(5432)    // Auto-assign port for PostgreSQL
28        .env("POSTGRES_PASSWORD", "testpass")
29        .env("POSTGRES_DB", "testdb")
30        .name("test_database")
31        .ready_timeout(Duration::from_secs(20));
32    
33    // Example 3: Mixed configuration (manual + auto ports)
34    let api_container = ContainerConfig::new("httpd:alpine")
35        .port(8080, 80)     // Manual port mapping
36        .auto_port(9090)    // Auto-assign port for API
37        .auto_port(9091)    // Auto-assign port for metrics
38        .env("API_VERSION", "v1")
39        .name("api_service")
40        .ready_timeout(Duration::from_secs(15));
41    
42    println!("📋 Container Configurations:");
43    println!("1. Web Service:");
44    println!("   - Image: {}", web_container.image);
45    println!("   - Auto-ports: {:?}", web_container.auto_ports);
46    println!("   - Will auto-assign host ports for container ports 80 and 443");
47    
48    println!("2. Database:");
49    println!("   - Image: {}", db_container.image);
50    println!("   - Auto-ports: {:?}", db_container.auto_ports);
51    println!("   - Will auto-assign host port for container port 5432");
52    
53    println!("3. API Service:");
54    println!("   - Image: {}", api_container.image);
55    println!("   - Manual ports: {:?}", api_container.ports);
56    println!("   - Auto-ports: {:?}", api_container.auto_ports);
57    println!("   - Manual mapping: 8080 -> 80, Auto-assign: 9090, 9091");
58    println!();
59    
60    // Clone containers for hooks
61    let web_before = web_container.clone();
62    let db_before = db_container.clone();
63    let api_before = api_container.clone();
64    
65    // Start containers in before_each
66    before_each(move |ctx| {
67        println!("🚀 before_each: Starting containers and capturing port info...");
68        
69        // Start web container
70        let web_info = web_before.start()
71            .map_err(|e| format!("Failed to start web container: {}", e))?;
72        ctx.set_data("web_container_info", web_info.clone());
73        
74        println!("✅ Web container started: {}", web_info.container_id);
75        println!("   📍 Port mappings: {}", web_info.ports_summary());
76        println!("   🔗 Primary URL: {}", web_info.primary_url().unwrap_or("None"));
77        
78        // Show specific port access
79        if let Some(http_port) = web_info.host_port_for(80) {
80            println!("   🌐 HTTP accessible at: http://localhost:{}", http_port);
81        }
82        if let Some(https_port) = web_info.host_port_for(443) {
83            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
84        }
85        
86        // Start database container
87        let db_info = db_before.start()
88            .map_err(|e| format!("Failed to start db container: {}", e))?;
89        ctx.set_data("db_container_info", db_info.clone());
90        
91        println!("✅ Database container started: {}", db_info.container_id);
92        println!("   📍 Port mappings: {}", db_info.ports_summary());
93        if let Some(db_port) = db_info.host_port_for(5432) {
94            println!("   🗄️ PostgreSQL accessible at: localhost:{}", db_port);
95            println!("   📝 Connection string: postgresql://user:pass@localhost:{}/testdb", db_port);
96        }
97        
98        // Start API container
99        let api_info = api_before.start()
100            .map_err(|e| format!("Failed to start api container: {}", e))?;
101        ctx.set_data("api_container_info", api_info.clone());
102        
103        println!("✅ API container started: {}", api_info.container_id);
104        println!("   📍 Port mappings: {}", api_info.ports_summary());
105        
106        // Show both manual and auto ports
107        if let Some(http_port) = api_info.host_port_for(80) {
108            println!("   🌐 HTTP API at: http://localhost:{} (manual mapping)", http_port);
109        }
110        if let Some(api_port) = api_info.host_port_for(9090) {
111            println!("   🔧 API endpoint at: http://localhost:{} (auto-assigned)", api_port);
112        }
113        if let Some(metrics_port) = api_info.host_port_for(9091) {
114            println!("   📊 Metrics at: http://localhost:{} (auto-assigned)", metrics_port);
115        }
116        
117        println!("🎉 All containers started with auto-assigned ports!");
118        Ok(())
119    });
120    
121    // Cleanup containers in after_each
122    let web_after = web_container.clone();
123    let db_after = db_container.clone();
124    let api_after = api_container.clone();
125    
126    after_each(move |ctx| {
127        println!("🧹 after_each: Cleaning up containers...");
128        
129        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
130            let _ = web_after.stop(&web_info.container_id);
131            println!("🛑 Stopped web container: {}", web_info.container_id);
132        }
133        
134        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
135            let _ = db_after.stop(&db_info.container_id);
136            println!("🛑 Stopped database container: {}", db_info.container_id);
137        }
138        
139        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
140            let _ = api_after.stop(&api_info.container_id);
141            println!("🛑 Stopped API container: {}", api_info.container_id);
142        }
143        
144        println!("✅ All containers cleaned up!");
145        Ok(())
146    });
147    
148    // Test 1: Web service port access
149    test("test_web_service_port_access", |ctx| {
150        println!("🧪 Testing web service port access...");
151        
152        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
153            .expect("Web container info should be available");
154        
155        println!("🔍 Demonstrating port access methods:");
156        
157        // Method 1: Get specific host port for container port
158        if let Some(http_port) = web_info.host_port_for(80) {
159            println!("   ✅ HTTP port 80 is mapped to host port: {}", http_port);
160            println!("      💡 Use this for HTTP client connections");
161        }
162        
163        if let Some(https_port) = web_info.host_port_for(443) {
164            println!("   ✅ HTTPS port 443 is mapped to host port: {}", https_port);
165            println!("      💡 Use this for HTTPS client connections");
166        }
167        
168        // Method 2: Get ready-to-use URLs
169        if let Some(http_url) = web_info.url_for_port(80) {
170            println!("   🔗 HTTP URL: {}", http_url);
171            println!("      💡 Ready to use in HTTP requests");
172        }
173        
174        if let Some(https_url) = web_info.url_for_port(443) {
175            println!("   🔗 HTTPS URL: {}", https_url);
176            println!("      💡 Ready to use in HTTPS requests (change http:// to https://)");
177        }
178        
179        // Method 3: Get all URLs
180        println!("   📋 All service URLs:");
181        for (i, url) in web_info.urls.iter().enumerate() {
182            println!("      {}. {}", i + 1, url);
183        }
184        
185        // Method 4: Get all port mappings
186        println!("   📊 All port mappings:");
187        for (host_port, container_port) in &web_info.port_mappings {
188            println!("      Host {} -> Container {}", host_port, container_port);
189        }
190        
191        // Verify ports are different (auto-assigned)
192        assert!(web_info.host_port_for(80).unwrap() != web_info.host_port_for(443).unwrap(), 
193                "Auto-assigned ports should be different");
194        
195        println!("✅ Web service port access test passed");
196        Ok(())
197    });
198    
199    // Test 2: Database connection string generation
200    test("test_database_connection_info", |ctx| {
201        println!("🧪 Testing database connection info generation...");
202        
203        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
204            .expect("Database container info should be available");
205        
206        println!("🗄️ Database connection information:");
207        
208        // Get the auto-assigned port for PostgreSQL
209        let db_port = db_info.host_port_for(5432)
210            .expect("PostgreSQL port should be exposed");
211        
212        println!("   📍 PostgreSQL running on: localhost:{}", db_port);
213        
214        // Generate connection strings using the auto-assigned port
215        let connection_string = format!("postgresql://admin:testpass@localhost:{}/testdb", db_port);
216        let jdbc_url = format!("jdbc:postgresql://localhost:{}/testdb", db_port);
217        let docker_internal = format!("postgresql://admin:testpass@{}:5432/testdb", db_info.container_id);
218        
219        println!("   🔗 Connection strings:");
220        println!("      Standard: {}", connection_string);
221        println!("      JDBC: {}", jdbc_url);
222        println!("      Docker internal: {}", docker_internal);
223        
224        // Show how to use this in real applications
225        println!("   💡 Usage examples:");
226        println!("      - Set DATABASE_URL={}", connection_string);
227        println!("      - Use in tests: connect to localhost:{}", db_port);
228        println!("      - Container-to-container: use port 5432");
229        
230        // Verify port is valid
231        assert!(db_port > 0, "Database port should be valid");
232        println!("✅ Database connection info test passed");
233        
234        Ok(())
235    });
236    
237    // Test 3: Mixed port configuration
238    test("test_mixed_port_configuration", |ctx| {
239        println!("🧪 Testing mixed port configuration (manual + auto)...");
240        
241        let api_info = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info")
242            .expect("API container info should be available");
243        
244        println!("🔀 Mixed port configuration analysis:");
245        
246        // Manual port mapping
247        let http_port = api_info.host_port_for(80)
248            .expect("HTTP port should be mapped");
249        println!("   📌 Manual mapping - HTTP port 80 -> host port: {}", http_port);
250        assert_eq!(http_port, 8080, "Manual port should be exactly as specified");
251        
252        // Auto-assigned ports
253        let api_port = api_info.host_port_for(9090)
254            .expect("API port should be auto-assigned");
255        let metrics_port = api_info.host_port_for(9091)
256            .expect("Metrics port should be auto-assigned");
257        
258        println!("   🎲 Auto-assigned - API port 9090 -> host port: {}", api_port);
259        println!("   🎲 Auto-assigned - Metrics port 9091 -> host port: {}", metrics_port);
260        
261        // Verify auto-assigned ports are different from manual port
262        assert_ne!(api_port, 8080, "Auto-assigned port should be different from manual port");
263        assert_ne!(metrics_port, 8080, "Auto-assigned port should be different from manual port");
264        assert_ne!(api_port, metrics_port, "Auto-assigned ports should be different from each other");
265        
266        println!("   🌐 Service endpoints:");
267        println!("      Main API: http://localhost:{}/", http_port);
268        println!("      API v2: http://localhost:{}/", api_port);
269        println!("      Metrics: http://localhost:{}/metrics", metrics_port);
270        
271        // Show complete port summary
272        println!("   📋 Complete port summary: {}", api_info.ports_summary());
273        
274        println!("✅ Mixed port configuration test passed");
275        Ok(())
276    });
277    
278    // Test 4: Container info convenience methods
279    test("test_container_info_convenience_methods", |ctx| {
280        println!("🧪 Testing ContainerInfo convenience methods...");
281        
282        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
283            .expect("Web container info should be available");
284        
285        println!("🔧 Testing all ContainerInfo methods:");
286        
287        // Test primary_url()
288        if let Some(primary_url) = web_info.primary_url() {
289            println!("   ✅ primary_url(): {}", primary_url);
290            assert!(primary_url.starts_with("http://localhost:"), "Primary URL should be valid");
291        }
292        
293        // Test url_for_port()
294        if let Some(url_80) = web_info.url_for_port(80) {
295            println!("   ✅ url_for_port(80): {}", url_80);
296            assert!(url_80.contains("localhost:"), "URL should contain localhost");
297        }
298        
299        // Test host_port_for()
300        if let Some(port_80) = web_info.host_port_for(80) {
301            println!("   ✅ host_port_for(80): {}", port_80);
302            assert!(port_80 > 0, "Port should be positive");
303        }
304        
305        // Test ports_summary()
306        let summary = web_info.ports_summary();
307        println!("   ✅ ports_summary(): {}", summary);
308        assert!(summary.contains("->"), "Summary should contain port mappings");
309        
310        // Test direct field access
311        println!("   ✅ container_id: {}", web_info.container_id);
312        println!("   ✅ image: {}", web_info.image);
313        println!("   ✅ auto_cleanup: {}", web_info.auto_cleanup);
314        
315        println!("   📊 All URLs:");
316        for (i, url) in web_info.urls.iter().enumerate() {
317            println!("      {}. {}", i + 1, url);
318        }
319        
320        println!("   📊 All port mappings:");
321        for (host_port, container_port) in &web_info.port_mappings {
322            println!("      {} -> {}", host_port, container_port);
323        }
324        
325        println!("✅ Container info convenience methods test passed");
326        Ok(())
327    });
328    
329    // Test 5: Real-world usage patterns
330    test("test_real_world_usage_patterns", |ctx| {
331        println!("🧪 Testing real-world usage patterns...");
332        
333        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
334            .expect("Web container info should be available");
335        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
336            .expect("Database container info should be available");
337        
338        println!("🌍 Real-world usage examples:");
339        
340        // Pattern 1: HTTP client testing
341        if let Some(web_url) = web_info.primary_url() {
342            println!("   🌐 HTTP Client Testing:");
343            println!("      Base URL: {}", web_url);
344            println!("      GET {}/health", web_url);
345            println!("      POST {}/api/users", web_url);
346            println!("      Code: let response = reqwest::get(\"{}/health\").await?;", web_url);
347        }
348        
349        // Pattern 2: Database testing
350        if let Some(db_port) = db_info.host_port_for(5432) {
351            println!("   🗄️ Database Testing:");
352            println!("      Connection: localhost:{}", db_port);
353            println!("      Code: let conn = PgConnection::establish(\"postgresql://user:pass@localhost:{}/db\")?;", db_port);
354        }
355        
356        // Pattern 3: Environment variable setup
357        println!("   🔧 Environment Variables:");
358        if let Some(web_port) = web_info.host_port_for(80) {
359            println!("      export WEB_SERVICE_URL=http://localhost:{}", web_port);
360        }
361        if let Some(db_port) = db_info.host_port_for(5432) {
362            println!("      export DATABASE_URL=postgresql://localhost:{}/testdb", db_port);
363        }
364        
365        // Pattern 4: Docker-compose style networking
366        println!("   🐳 Container Networking:");
367        println!("      External: Use auto-assigned host ports");
368        println!("      Internal: Use original container ports");
369        println!("      Web -> DB: {}:5432 (container-to-container)", db_info.container_id);
370        
371        // Pattern 5: Health checks
372        println!("   ❤️ Health Checks:");
373        if let Some(web_url) = web_info.primary_url() {
374            println!("      Health endpoint: {}/health", web_url);
375            println!("      Ready endpoint: {}/ready", web_url);
376        }
377        
378        println!("✅ Real-world usage patterns test passed");
379        Ok(())
380    });
381    
382    println!("🚀 Running container port access tests...");
383    println!();
384    
385    // Run the tests
386    let config = TestConfig {
387        html_report: Some("container-port-access-report.html".to_string()),
388        ..Default::default()
389    };
390    
391    let exit_code = run_tests_with_config(config);
392    
393    println!();
394    if exit_code == 0 {
395        println!("🎉 All tests passed! Port access functionality is working correctly.");
396        println!("📊 Check the HTML report for detailed results.");
397        println!();
398        println!("💡 Key Takeaways:");
399        println!("   • Use auto_port() to avoid port conflicts");
400        println!("   • Access host ports with host_port_for(container_port)");
401        println!("   • Get ready-to-use URLs with url_for_port(container_port)");
402        println!("   • Use ports_summary() for human-readable port info");
403        println!("   • ContainerInfo provides complete access to all port information");
404    } else {
405        println!("❌ Some tests failed. Check the output above for details.");
406    }
407    
408    std::process::exit(exit_code);
409}
Source

pub fn port(self, host_port: u16, container_port: u16) -> Self

Examples found in repository?
examples/user_specified_ports.rs (line 19)
12fn main() {
13    println!("🔧 User-Specified Ports Example");
14    println!("==============================");
15    println!();
16    
17    // Example 1: PostgreSQL on standard port 5432
18    let postgres_container = ContainerConfig::new("postgres:13-alpine")
19        .port(5432, 5432)     // Map host port 5432 to container port 5432
20        .env("POSTGRES_PASSWORD", "testpass")
21        .env("POSTGRES_DB", "testdb")
22        .name("postgres_test")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Web service on port 8080
26    let web_container = ContainerConfig::new("nginx:alpine")
27        .port(8080, 80)       // Map host port 8080 to container port 80
28        .name("nginx_test")
29        .ready_timeout(Duration::from_secs(10));
30    
31    // Example 3: Mixed configuration - some fixed, some auto
32    let api_container = ContainerConfig::new("httpd:alpine")
33        .port(3000, 80)       // Fixed port for main API
34        .auto_port(443)       // Auto-assign for HTTPS
35        .auto_port(9090)      // Auto-assign for metrics
36        .name("api_test")
37        .ready_timeout(Duration::from_secs(10));
38    
39    println!("📋 Container Configurations:");
40    println!("1. PostgreSQL: Fixed on localhost:5432 (standard PostgreSQL port)");
41    println!("2. Web Service: Fixed on localhost:8080");
42    println!("3. API Service: Fixed localhost:3000, auto-assigned for 443 and 9090");
43    println!();
44    
45    // Clone containers for hooks
46    let postgres_before = postgres_container.clone();
47    let web_before = web_container.clone();
48    let api_before = api_container.clone();
49    
50    // Start containers in before_each
51    before_each(move |ctx| {
52        println!("🚀 before_each: Starting containers with specified ports...");
53        
54        // Start PostgreSQL container
55        let postgres_info = postgres_before.start()
56            .map_err(|e| format!("Failed to start PostgreSQL container: {}", e))?;
57        ctx.set_data("postgres_container_info", postgres_info.clone());
58        
59        println!("✅ PostgreSQL started: {}", postgres_info.container_id);
60        println!("   📍 Port mappings: {}", postgres_info.ports_summary());
61        println!("   🗄️ Database URL: postgresql://postgres:testpass@localhost:5432/testdb");
62        
63        // Start web container
64        let web_info = web_before.start()
65            .map_err(|e| format!("Failed to start web container: {}", e))?;
66        ctx.set_data("web_container_info", web_info.clone());
67        
68        println!("✅ Web service started: {}", web_info.container_id);
69        println!("   📍 Port mappings: {}", web_info.ports_summary());
70        println!("   🌐 Web accessible at: http://localhost:8080");
71        
72        // Start API container
73        let api_info = api_before.start()
74            .map_err(|e| format!("Failed to start API container: {}", e))?;
75        ctx.set_data("api_container_info", api_info.clone());
76        
77        println!("✅ API service started: {}", api_info.container_id);
78        println!("   📍 Port mappings: {}", api_info.ports_summary());
79        println!("   🔗 API accessible at: http://localhost:3000");
80        if let Some(https_port) = api_info.host_port_for(443) {
81            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
82        }
83        if let Some(metrics_port) = api_info.host_port_for(9090) {
84            println!("   📊 Metrics accessible at: http://localhost:{}/metrics", metrics_port);
85        }
86        
87        Ok(())
88    });
89    
90    // Cleanup containers in after_each
91    let postgres_after = postgres_container.clone();
92    let web_after = web_container.clone();
93    let api_after = api_container.clone();
94    
95    after_each(move |ctx| {
96        println!("🧹 after_each: Cleaning up containers...");
97        
98        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
99            let _ = postgres_after.stop(&postgres_info.container_id);
100            println!("🛑 Stopped PostgreSQL container");
101        }
102        
103        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
104            let _ = web_after.stop(&web_info.container_id);
105            println!("🛑 Stopped web container");
106        }
107        
108        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
109            let _ = api_after.stop(&api_info.container_id);
110            println!("🛑 Stopped API container");
111        }
112        
113        println!("✅ All containers cleaned up!");
114        Ok(())
115    });
116    
117    // Test 1: Database connection test
118    test("test_database_connection", |ctx| {
119        println!("🧪 Testing database connection on fixed port 5432...");
120        
121        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
122            assert_eq!(postgres_info.host_port_for(5432), Some(5432));
123            assert_eq!(postgres_info.url_for_port(5432), Some("localhost:5432".to_string()));
124            println!("✅ Database is accessible on the expected port 5432");
125        } else {
126            return Err("PostgreSQL container info not found".into());
127        }
128        
129        Ok(())
130    });
131    
132    // Test 2: Web service test
133    test("test_web_service_fixed_port", |ctx| {
134        println!("🧪 Testing web service on fixed port 8080...");
135        
136        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
137            assert_eq!(web_info.host_port_for(80), Some(8080));
138            assert_eq!(web_info.url_for_port(80), Some("localhost:8080".to_string()));
139            println!("✅ Web service is accessible on the expected port 8080");
140        } else {
141            return Err("Web container info not found".into());
142        }
143        
144        Ok(())
145    });
146    
147    // Test 3: Mixed configuration test
148    test("test_mixed_port_configuration", |ctx| {
149        println!("🧪 Testing mixed port configuration (fixed + auto)...");
150        
151        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
152            // Test fixed port
153            assert_eq!(api_info.host_port_for(80), Some(3000));
154            assert_eq!(api_info.url_for_port(80), Some("localhost:3000".to_string()));
155            println!("✅ Fixed port 3000 -> 80 is working");
156            
157            // Test auto-assigned ports
158            if let Some(https_port) = api_info.host_port_for(443) {
159                assert!(https_port > 1024); // Should be a high port
160                println!("✅ Auto-assigned HTTPS port: {}", https_port);
161            }
162            
163            if let Some(metrics_port) = api_info.host_port_for(9090) {
164                assert!(metrics_port > 1024); // Should be a high port
165                println!("✅ Auto-assigned metrics port: {}", metrics_port);
166            }
167            
168            println!("✅ Mixed configuration is working correctly");
169        } else {
170            return Err("API container info not found".into());
171        }
172        
173        Ok(())
174    });
175    
176    println!("🚀 Running user-specified ports tests...");
177    
178    let config = TestConfig {
179        html_report: Some("user-specified-ports-report.html".to_string()),
180        ..Default::default()
181    };
182    
183    let exit_code = run_tests_with_config(config);
184    
185    println!();
186    println!("🎉 Tests completed!");
187    println!("📊 Check the HTML report for detailed results.");
188    println!();
189    println!("💡 Key Takeaways:");
190    println!("   • Use .port(host_port, container_port) for fixed port mappings");
191    println!("   • Use .auto_port(container_port) for automatic port assignment");
192    println!("   • Mix both approaches for maximum flexibility");
193    println!("   • Fixed ports are great for services with standard ports (5432, 3306, etc.)");
194    println!("   • Auto-ports prevent conflicts in parallel test environments");
195    
196    std::process::exit(exit_code);
197}
More examples
Hide additional examples
examples/auto_port_demo.rs (line 40)
12fn main() {
13    println!("🚀 Auto-Port and Container Management Demo");
14    println!("==========================================");
15    println!();
16    
17    // Example 1: Web service with auto-port
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80) // Automatically assign host port for container port 80
20        .env("NGINX_HOST", "localhost")
21        .name("web_service")
22        .ready_timeout(Duration::from_secs(15));
23    
24    // Example 2: Database with auto-port
25    let db_container = ContainerConfig::new("postgres:13-alpine")
26        .auto_port(5432) // Automatically assign host port for container port 5432
27        .env("POSTGRES_PASSWORD", "testpass")
28        .env("POSTGRES_DB", "testdb")
29        .name("test_database")
30        .ready_timeout(Duration::from_secs(20));
31    
32    // Example 3: Redis with auto-port
33    let redis_container = ContainerConfig::new("redis:6-alpine")
34        .auto_port(6379) // Automatically assign host port for container port 6379
35        .name("test_redis")
36        .ready_timeout(Duration::from_secs(10));
37    
38    // Example 4: Mixed configuration (manual + auto ports)
39    let mixed_container = ContainerConfig::new("httpd:alpine")
40        .port(8080, 80) // Manual port mapping
41        .auto_port(443) // Auto port for HTTPS
42        .env("APACHE_DOCUMENT_ROOT", "/var/www/html")
43        .name("mixed_ports")
44        .ready_timeout(Duration::from_secs(15));
45    
46    println!("📋 Container Configurations:");
47    println!("1. Web Service (nginx):");
48    println!("   - Image: {}", web_container.image);
49    println!("   - Auto-ports: {:?}", web_container.auto_ports);
50    println!("   - Auto-cleanup: {}", web_container.auto_cleanup);
51    
52    println!("2. Database (postgres):");
53    println!("   - Image: {}", db_container.image);
54    println!("   - Auto-ports: {:?}", db_container.auto_ports);
55    println!("   - Auto-cleanup: {}", db_container.auto_cleanup);
56    
57    println!("3. Cache (redis):");
58    println!("   - Image: {}", redis_container.image);
59    println!("   - Auto-ports: {:?}", redis_container.auto_ports);
60    println!("   - Auto-cleanup: {}", redis_container.auto_cleanup);
61    
62    println!("4. Mixed (httpd):");
63    println!("   - Image: {}", mixed_container.image);
64    println!("   - Manual ports: {:?}", mixed_container.ports);
65    println!("   - Auto-ports: {:?}", mixed_container.auto_ports);
66    println!("   - Auto-cleanup: {}", mixed_container.auto_cleanup);
67    println!();
68    
69    // Clone containers for hooks
70    let web_before = web_container.clone();
71    let db_before = db_container.clone();
72    let redis_before = redis_container.clone();
73    let mixed_before = mixed_container.clone();
74    
75    // Start all containers in before_each for each test
76    before_each(move |ctx| {
77        println!("🚀 before_each: Starting all containers...");
78        
79        // Start web container
80        let web_info = web_before.start()
81            .map_err(|e| format!("Failed to start web container: {}", e))?;
82        ctx.set_data("web_container_info", web_info.clone());
83        println!("✅ Web container started: {}", web_info.container_id);
84        println!("   Ports: {}", web_info.ports_summary());
85        if let Some(url) = web_info.primary_url() {
86            println!("   URL: {}", url);
87        }
88        
89        // Start database container
90        let db_info = db_before.start()
91            .map_err(|e| format!("Failed to start db container: {}", e))?;
92        ctx.set_data("db_container_info", db_info.clone());
93        println!("✅ Database container started: {}", db_info.container_id);
94        println!("   Ports: {}", db_info.ports_summary());
95        if let Some(host_port) = db_info.host_port_for(5432) {
96            println!("   PostgreSQL accessible at: localhost:{}", host_port);
97        }
98        
99        // Start redis container
100        let redis_info = redis_before.start()
101            .map_err(|e| format!("Failed to start redis container: {}", e))?;
102        ctx.set_data("redis_container_info", redis_info.clone());
103        println!("✅ Redis container started: {}", redis_info.container_id);
104        println!("   Ports: {}", redis_info.ports_summary());
105        if let Some(host_port) = redis_info.host_port_for(6379) {
106            println!("   Redis accessible at: localhost:{}", host_port);
107        }
108        
109        // Start mixed container
110        let mixed_info = mixed_before.start()
111            .map_err(|e| format!("Failed to start mixed container: {}", e))?;
112        ctx.set_data("mixed_container_info", mixed_info.clone());
113        println!("✅ Mixed container started: {}", mixed_info.container_id);
114        println!("   Ports: {}", mixed_info.ports_summary());
115        if let Some(host_port) = mixed_info.host_port_for(443) {
116            println!("   HTTPS accessible at: localhost:{}", host_port);
117        }
118        
119        println!("🎉 All containers started successfully!");
120        Ok(())
121    });
122    
123    // Cleanup all containers in after_each for each test
124    let web_after = web_container.clone();
125    let db_after = db_container.clone();
126    let redis_after = redis_container.clone();
127    let mixed_after = mixed_container.clone();
128    
129    after_each(move |ctx| {
130        println!("🧹 after_each: Cleaning up all containers...");
131        
132        // Get all container info and stop them
133        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
134            let _ = web_after.stop(&web_info.container_id);
135            println!("🛑 Stopped web container: {}", web_info.container_id);
136        }
137        
138        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
139            let _ = db_after.stop(&db_info.container_id);
140            println!("🛑 Stopped database container: {}", db_info.container_id);
141        }
142        
143        if let Some(redis_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info") {
144            let _ = redis_after.stop(&redis_info.container_id);
145            println!("🛑 Stopped redis container: {}", redis_info.container_id);
146        }
147        
148        if let Some(mixed_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info") {
149            let _ = mixed_after.stop(&mixed_info.container_id);
150            println!("🛑 Stopped mixed container: {}", mixed_info.container_id);
151        }
152        
153        println!("✅ All containers cleaned up!");
154        Ok(())
155    });
156    
157    // Test 1: Access web service
158    test("test_web_service_access", |ctx| {
159        println!("🧪 Testing web service access...");
160        
161        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
162            .expect("Web container info should be available");
163        
164        println!("🌐 Web service container: {}", web_info.container_id);
165        println!("   Ports: {}", web_info.ports_summary());
166        println!("   Primary URL: {}", web_info.primary_url().unwrap_or("None"));
167        
168        // In a real test, you would make HTTP requests to the container
169        // For demo purposes, just verify the port information
170        assert!(web_info.host_port_for(80).is_some(), "Web service should have port 80 exposed");
171        
172        println!("✅ Web service test passed");
173        Ok(())
174    });
175    
176    // Test 2: Access database
177    test("test_database_access", |ctx| {
178        println!("🧪 Testing database access...");
179        
180        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
181            .expect("Database container info should be available");
182        
183        println!("🗄️ Database container: {}", db_info.container_id);
184        println!("   Ports: {}", db_info.ports_summary());
185        
186        // Verify PostgreSQL port is exposed
187        let postgres_port = db_info.host_port_for(5432)
188            .expect("PostgreSQL port 5432 should be exposed");
189        println!("   PostgreSQL accessible at: localhost:{}", postgres_port);
190        
191        // In a real test, you would connect to the database
192        // For demo purposes, just verify the port information
193        assert!(postgres_port > 0, "PostgreSQL port should be valid");
194        
195        println!("✅ Database test passed");
196        Ok(())
197    });
198    
199    // Test 3: Access redis
200    test("test_redis_access", |ctx| {
201        println!("🧪 Testing redis access...");
202        
203        let redis_info = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info")
204            .expect("Redis container info should be available");
205        
206        println!("🔴 Redis container: {}", redis_info.container_id);
207        println!("   Ports: {}", redis_info.ports_summary());
208        
209        // Verify Redis port is exposed
210        let redis_port = redis_info.host_port_for(6379)
211            .expect("Redis port 6379 should be exposed");
212        println!("   Redis accessible at: localhost:{}", redis_port);
213        
214        // In a real test, you would connect to Redis
215        // For demo purposes, just verify the port information
216        assert!(redis_port > 0, "Redis port should be valid");
217        
218        println!("✅ Redis test passed");
219        Ok(())
220    });
221    
222    // Test 4: Mixed port configuration
223    test("test_mixed_port_config", |ctx| {
224        println!("🧪 Testing mixed port configuration...");
225        
226        let mixed_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info")
227            .expect("Mixed container info should be available");
228        
229        println!("🔀 Mixed container: {}", mixed_info.container_id);
230        println!("   Ports: {}", mixed_info.ports_summary());
231        
232        // Verify both manual and auto ports
233        let http_port = mixed_info.host_port_for(80)
234            .expect("HTTP port 80 should be exposed");
235        let https_port = mixed_info.host_port_for(443)
236            .expect("HTTPS port 443 should be exposed");
237        
238        println!("   HTTP accessible at: localhost:{}", http_port);
239        println!("   HTTPS accessible at: localhost:{}", https_port);
240        
241        // Verify the manual port mapping (8080 -> 80)
242        assert_eq!(http_port, 8080, "Manual port mapping should work");
243        
244        // Verify auto port is different from manual port
245        assert_ne!(https_port, 8080, "Auto port should be different from manual port");
246        
247        println!("✅ Mixed port configuration test passed");
248        Ok(())
249    });
250    
251    // Test 5: Container info methods
252    test("test_container_info_methods", |ctx| {
253        println!("🧪 Testing container info methods...");
254        
255        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
256            .expect("Web container info should be available");
257        
258        // Test all the convenience methods
259        println!("🔍 Testing container info methods for: {}", web_info.container_id);
260        
261        // Test primary_url
262        if let Some(url) = web_info.primary_url() {
263            println!("   Primary URL: {}", url);
264            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
265        }
266        
267        // Test url_for_port
268        if let Some(url) = web_info.url_for_port(80) {
269            println!("   URL for port 80: {}", url);
270            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
271        }
272        
273        // Test host_port_for
274        if let Some(host_port) = web_info.host_port_for(80) {
275            println!("   Host port for container port 80: {}", host_port);
276            assert!(host_port > 0, "Host port should be valid");
277        }
278        
279        // Test ports_summary
280        let summary = web_info.ports_summary();
281        println!("   Ports summary: {}", summary);
282        assert!(!summary.is_empty(), "Ports summary should not be empty");
283        
284        println!("✅ Container info methods test passed");
285        Ok(())
286    });
287    
288    println!("🚀 Running tests with auto-port functionality...");
289    println!();
290    
291    // Run the tests
292    let config = TestConfig {
293        html_report: Some("auto-port-demo-report.html".to_string()),
294        ..Default::default()
295    };
296    
297    let exit_code = run_tests_with_config(config);
298    
299    println!();
300    if exit_code == 0 {
301        println!("🎉 All tests passed! Auto-port functionality is working correctly.");
302        println!("📊 Check the HTML report for detailed results.");
303    } else {
304        println!("❌ Some tests failed. Check the output above for details.");
305    }
306    
307    std::process::exit(exit_code);
308}
examples/container_port_access.rs (line 35)
12fn main() {
13    println!("🌐 Container Port and URL Access Example");
14    println!("========================================");
15    println!();
16    
17    // Example 1: Web service with multiple auto-ports
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80)      // Auto-assign port for HTTP
20        .auto_port(443)     // Auto-assign port for HTTPS
21        .env("NGINX_HOST", "localhost")
22        .name("web_service")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Database with auto-port
26    let db_container = ContainerConfig::new("postgres:13-alpine")
27        .auto_port(5432)    // Auto-assign port for PostgreSQL
28        .env("POSTGRES_PASSWORD", "testpass")
29        .env("POSTGRES_DB", "testdb")
30        .name("test_database")
31        .ready_timeout(Duration::from_secs(20));
32    
33    // Example 3: Mixed configuration (manual + auto ports)
34    let api_container = ContainerConfig::new("httpd:alpine")
35        .port(8080, 80)     // Manual port mapping
36        .auto_port(9090)    // Auto-assign port for API
37        .auto_port(9091)    // Auto-assign port for metrics
38        .env("API_VERSION", "v1")
39        .name("api_service")
40        .ready_timeout(Duration::from_secs(15));
41    
42    println!("📋 Container Configurations:");
43    println!("1. Web Service:");
44    println!("   - Image: {}", web_container.image);
45    println!("   - Auto-ports: {:?}", web_container.auto_ports);
46    println!("   - Will auto-assign host ports for container ports 80 and 443");
47    
48    println!("2. Database:");
49    println!("   - Image: {}", db_container.image);
50    println!("   - Auto-ports: {:?}", db_container.auto_ports);
51    println!("   - Will auto-assign host port for container port 5432");
52    
53    println!("3. API Service:");
54    println!("   - Image: {}", api_container.image);
55    println!("   - Manual ports: {:?}", api_container.ports);
56    println!("   - Auto-ports: {:?}", api_container.auto_ports);
57    println!("   - Manual mapping: 8080 -> 80, Auto-assign: 9090, 9091");
58    println!();
59    
60    // Clone containers for hooks
61    let web_before = web_container.clone();
62    let db_before = db_container.clone();
63    let api_before = api_container.clone();
64    
65    // Start containers in before_each
66    before_each(move |ctx| {
67        println!("🚀 before_each: Starting containers and capturing port info...");
68        
69        // Start web container
70        let web_info = web_before.start()
71            .map_err(|e| format!("Failed to start web container: {}", e))?;
72        ctx.set_data("web_container_info", web_info.clone());
73        
74        println!("✅ Web container started: {}", web_info.container_id);
75        println!("   📍 Port mappings: {}", web_info.ports_summary());
76        println!("   🔗 Primary URL: {}", web_info.primary_url().unwrap_or("None"));
77        
78        // Show specific port access
79        if let Some(http_port) = web_info.host_port_for(80) {
80            println!("   🌐 HTTP accessible at: http://localhost:{}", http_port);
81        }
82        if let Some(https_port) = web_info.host_port_for(443) {
83            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
84        }
85        
86        // Start database container
87        let db_info = db_before.start()
88            .map_err(|e| format!("Failed to start db container: {}", e))?;
89        ctx.set_data("db_container_info", db_info.clone());
90        
91        println!("✅ Database container started: {}", db_info.container_id);
92        println!("   📍 Port mappings: {}", db_info.ports_summary());
93        if let Some(db_port) = db_info.host_port_for(5432) {
94            println!("   🗄️ PostgreSQL accessible at: localhost:{}", db_port);
95            println!("   📝 Connection string: postgresql://user:pass@localhost:{}/testdb", db_port);
96        }
97        
98        // Start API container
99        let api_info = api_before.start()
100            .map_err(|e| format!("Failed to start api container: {}", e))?;
101        ctx.set_data("api_container_info", api_info.clone());
102        
103        println!("✅ API container started: {}", api_info.container_id);
104        println!("   📍 Port mappings: {}", api_info.ports_summary());
105        
106        // Show both manual and auto ports
107        if let Some(http_port) = api_info.host_port_for(80) {
108            println!("   🌐 HTTP API at: http://localhost:{} (manual mapping)", http_port);
109        }
110        if let Some(api_port) = api_info.host_port_for(9090) {
111            println!("   🔧 API endpoint at: http://localhost:{} (auto-assigned)", api_port);
112        }
113        if let Some(metrics_port) = api_info.host_port_for(9091) {
114            println!("   📊 Metrics at: http://localhost:{} (auto-assigned)", metrics_port);
115        }
116        
117        println!("🎉 All containers started with auto-assigned ports!");
118        Ok(())
119    });
120    
121    // Cleanup containers in after_each
122    let web_after = web_container.clone();
123    let db_after = db_container.clone();
124    let api_after = api_container.clone();
125    
126    after_each(move |ctx| {
127        println!("🧹 after_each: Cleaning up containers...");
128        
129        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
130            let _ = web_after.stop(&web_info.container_id);
131            println!("🛑 Stopped web container: {}", web_info.container_id);
132        }
133        
134        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
135            let _ = db_after.stop(&db_info.container_id);
136            println!("🛑 Stopped database container: {}", db_info.container_id);
137        }
138        
139        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
140            let _ = api_after.stop(&api_info.container_id);
141            println!("🛑 Stopped API container: {}", api_info.container_id);
142        }
143        
144        println!("✅ All containers cleaned up!");
145        Ok(())
146    });
147    
148    // Test 1: Web service port access
149    test("test_web_service_port_access", |ctx| {
150        println!("🧪 Testing web service port access...");
151        
152        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
153            .expect("Web container info should be available");
154        
155        println!("🔍 Demonstrating port access methods:");
156        
157        // Method 1: Get specific host port for container port
158        if let Some(http_port) = web_info.host_port_for(80) {
159            println!("   ✅ HTTP port 80 is mapped to host port: {}", http_port);
160            println!("      💡 Use this for HTTP client connections");
161        }
162        
163        if let Some(https_port) = web_info.host_port_for(443) {
164            println!("   ✅ HTTPS port 443 is mapped to host port: {}", https_port);
165            println!("      💡 Use this for HTTPS client connections");
166        }
167        
168        // Method 2: Get ready-to-use URLs
169        if let Some(http_url) = web_info.url_for_port(80) {
170            println!("   🔗 HTTP URL: {}", http_url);
171            println!("      💡 Ready to use in HTTP requests");
172        }
173        
174        if let Some(https_url) = web_info.url_for_port(443) {
175            println!("   🔗 HTTPS URL: {}", https_url);
176            println!("      💡 Ready to use in HTTPS requests (change http:// to https://)");
177        }
178        
179        // Method 3: Get all URLs
180        println!("   📋 All service URLs:");
181        for (i, url) in web_info.urls.iter().enumerate() {
182            println!("      {}. {}", i + 1, url);
183        }
184        
185        // Method 4: Get all port mappings
186        println!("   📊 All port mappings:");
187        for (host_port, container_port) in &web_info.port_mappings {
188            println!("      Host {} -> Container {}", host_port, container_port);
189        }
190        
191        // Verify ports are different (auto-assigned)
192        assert!(web_info.host_port_for(80).unwrap() != web_info.host_port_for(443).unwrap(), 
193                "Auto-assigned ports should be different");
194        
195        println!("✅ Web service port access test passed");
196        Ok(())
197    });
198    
199    // Test 2: Database connection string generation
200    test("test_database_connection_info", |ctx| {
201        println!("🧪 Testing database connection info generation...");
202        
203        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
204            .expect("Database container info should be available");
205        
206        println!("🗄️ Database connection information:");
207        
208        // Get the auto-assigned port for PostgreSQL
209        let db_port = db_info.host_port_for(5432)
210            .expect("PostgreSQL port should be exposed");
211        
212        println!("   📍 PostgreSQL running on: localhost:{}", db_port);
213        
214        // Generate connection strings using the auto-assigned port
215        let connection_string = format!("postgresql://admin:testpass@localhost:{}/testdb", db_port);
216        let jdbc_url = format!("jdbc:postgresql://localhost:{}/testdb", db_port);
217        let docker_internal = format!("postgresql://admin:testpass@{}:5432/testdb", db_info.container_id);
218        
219        println!("   🔗 Connection strings:");
220        println!("      Standard: {}", connection_string);
221        println!("      JDBC: {}", jdbc_url);
222        println!("      Docker internal: {}", docker_internal);
223        
224        // Show how to use this in real applications
225        println!("   💡 Usage examples:");
226        println!("      - Set DATABASE_URL={}", connection_string);
227        println!("      - Use in tests: connect to localhost:{}", db_port);
228        println!("      - Container-to-container: use port 5432");
229        
230        // Verify port is valid
231        assert!(db_port > 0, "Database port should be valid");
232        println!("✅ Database connection info test passed");
233        
234        Ok(())
235    });
236    
237    // Test 3: Mixed port configuration
238    test("test_mixed_port_configuration", |ctx| {
239        println!("🧪 Testing mixed port configuration (manual + auto)...");
240        
241        let api_info = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info")
242            .expect("API container info should be available");
243        
244        println!("🔀 Mixed port configuration analysis:");
245        
246        // Manual port mapping
247        let http_port = api_info.host_port_for(80)
248            .expect("HTTP port should be mapped");
249        println!("   📌 Manual mapping - HTTP port 80 -> host port: {}", http_port);
250        assert_eq!(http_port, 8080, "Manual port should be exactly as specified");
251        
252        // Auto-assigned ports
253        let api_port = api_info.host_port_for(9090)
254            .expect("API port should be auto-assigned");
255        let metrics_port = api_info.host_port_for(9091)
256            .expect("Metrics port should be auto-assigned");
257        
258        println!("   🎲 Auto-assigned - API port 9090 -> host port: {}", api_port);
259        println!("   🎲 Auto-assigned - Metrics port 9091 -> host port: {}", metrics_port);
260        
261        // Verify auto-assigned ports are different from manual port
262        assert_ne!(api_port, 8080, "Auto-assigned port should be different from manual port");
263        assert_ne!(metrics_port, 8080, "Auto-assigned port should be different from manual port");
264        assert_ne!(api_port, metrics_port, "Auto-assigned ports should be different from each other");
265        
266        println!("   🌐 Service endpoints:");
267        println!("      Main API: http://localhost:{}/", http_port);
268        println!("      API v2: http://localhost:{}/", api_port);
269        println!("      Metrics: http://localhost:{}/metrics", metrics_port);
270        
271        // Show complete port summary
272        println!("   📋 Complete port summary: {}", api_info.ports_summary());
273        
274        println!("✅ Mixed port configuration test passed");
275        Ok(())
276    });
277    
278    // Test 4: Container info convenience methods
279    test("test_container_info_convenience_methods", |ctx| {
280        println!("🧪 Testing ContainerInfo convenience methods...");
281        
282        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
283            .expect("Web container info should be available");
284        
285        println!("🔧 Testing all ContainerInfo methods:");
286        
287        // Test primary_url()
288        if let Some(primary_url) = web_info.primary_url() {
289            println!("   ✅ primary_url(): {}", primary_url);
290            assert!(primary_url.starts_with("http://localhost:"), "Primary URL should be valid");
291        }
292        
293        // Test url_for_port()
294        if let Some(url_80) = web_info.url_for_port(80) {
295            println!("   ✅ url_for_port(80): {}", url_80);
296            assert!(url_80.contains("localhost:"), "URL should contain localhost");
297        }
298        
299        // Test host_port_for()
300        if let Some(port_80) = web_info.host_port_for(80) {
301            println!("   ✅ host_port_for(80): {}", port_80);
302            assert!(port_80 > 0, "Port should be positive");
303        }
304        
305        // Test ports_summary()
306        let summary = web_info.ports_summary();
307        println!("   ✅ ports_summary(): {}", summary);
308        assert!(summary.contains("->"), "Summary should contain port mappings");
309        
310        // Test direct field access
311        println!("   ✅ container_id: {}", web_info.container_id);
312        println!("   ✅ image: {}", web_info.image);
313        println!("   ✅ auto_cleanup: {}", web_info.auto_cleanup);
314        
315        println!("   📊 All URLs:");
316        for (i, url) in web_info.urls.iter().enumerate() {
317            println!("      {}. {}", i + 1, url);
318        }
319        
320        println!("   📊 All port mappings:");
321        for (host_port, container_port) in &web_info.port_mappings {
322            println!("      {} -> {}", host_port, container_port);
323        }
324        
325        println!("✅ Container info convenience methods test passed");
326        Ok(())
327    });
328    
329    // Test 5: Real-world usage patterns
330    test("test_real_world_usage_patterns", |ctx| {
331        println!("🧪 Testing real-world usage patterns...");
332        
333        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
334            .expect("Web container info should be available");
335        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
336            .expect("Database container info should be available");
337        
338        println!("🌍 Real-world usage examples:");
339        
340        // Pattern 1: HTTP client testing
341        if let Some(web_url) = web_info.primary_url() {
342            println!("   🌐 HTTP Client Testing:");
343            println!("      Base URL: {}", web_url);
344            println!("      GET {}/health", web_url);
345            println!("      POST {}/api/users", web_url);
346            println!("      Code: let response = reqwest::get(\"{}/health\").await?;", web_url);
347        }
348        
349        // Pattern 2: Database testing
350        if let Some(db_port) = db_info.host_port_for(5432) {
351            println!("   🗄️ Database Testing:");
352            println!("      Connection: localhost:{}", db_port);
353            println!("      Code: let conn = PgConnection::establish(\"postgresql://user:pass@localhost:{}/db\")?;", db_port);
354        }
355        
356        // Pattern 3: Environment variable setup
357        println!("   🔧 Environment Variables:");
358        if let Some(web_port) = web_info.host_port_for(80) {
359            println!("      export WEB_SERVICE_URL=http://localhost:{}", web_port);
360        }
361        if let Some(db_port) = db_info.host_port_for(5432) {
362            println!("      export DATABASE_URL=postgresql://localhost:{}/testdb", db_port);
363        }
364        
365        // Pattern 4: Docker-compose style networking
366        println!("   🐳 Container Networking:");
367        println!("      External: Use auto-assigned host ports");
368        println!("      Internal: Use original container ports");
369        println!("      Web -> DB: {}:5432 (container-to-container)", db_info.container_id);
370        
371        // Pattern 5: Health checks
372        println!("   ❤️ Health Checks:");
373        if let Some(web_url) = web_info.primary_url() {
374            println!("      Health endpoint: {}/health", web_url);
375            println!("      Ready endpoint: {}/ready", web_url);
376        }
377        
378        println!("✅ Real-world usage patterns test passed");
379        Ok(())
380    });
381    
382    println!("🚀 Running container port access tests...");
383    println!();
384    
385    // Run the tests
386    let config = TestConfig {
387        html_report: Some("container-port-access-report.html".to_string()),
388        ..Default::default()
389    };
390    
391    let exit_code = run_tests_with_config(config);
392    
393    println!();
394    if exit_code == 0 {
395        println!("🎉 All tests passed! Port access functionality is working correctly.");
396        println!("📊 Check the HTML report for detailed results.");
397        println!();
398        println!("💡 Key Takeaways:");
399        println!("   • Use auto_port() to avoid port conflicts");
400        println!("   • Access host ports with host_port_for(container_port)");
401        println!("   • Get ready-to-use URLs with url_for_port(container_port)");
402        println!("   • Use ports_summary() for human-readable port info");
403        println!("   • ContainerInfo provides complete access to all port information");
404    } else {
405        println!("❌ Some tests failed. Check the output above for details.");
406    }
407    
408    std::process::exit(exit_code);
409}
Source

pub fn env(self, key: &str, value: &str) -> Self

Examples found in repository?
examples/user_specified_ports.rs (line 20)
12fn main() {
13    println!("🔧 User-Specified Ports Example");
14    println!("==============================");
15    println!();
16    
17    // Example 1: PostgreSQL on standard port 5432
18    let postgres_container = ContainerConfig::new("postgres:13-alpine")
19        .port(5432, 5432)     // Map host port 5432 to container port 5432
20        .env("POSTGRES_PASSWORD", "testpass")
21        .env("POSTGRES_DB", "testdb")
22        .name("postgres_test")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Web service on port 8080
26    let web_container = ContainerConfig::new("nginx:alpine")
27        .port(8080, 80)       // Map host port 8080 to container port 80
28        .name("nginx_test")
29        .ready_timeout(Duration::from_secs(10));
30    
31    // Example 3: Mixed configuration - some fixed, some auto
32    let api_container = ContainerConfig::new("httpd:alpine")
33        .port(3000, 80)       // Fixed port for main API
34        .auto_port(443)       // Auto-assign for HTTPS
35        .auto_port(9090)      // Auto-assign for metrics
36        .name("api_test")
37        .ready_timeout(Duration::from_secs(10));
38    
39    println!("📋 Container Configurations:");
40    println!("1. PostgreSQL: Fixed on localhost:5432 (standard PostgreSQL port)");
41    println!("2. Web Service: Fixed on localhost:8080");
42    println!("3. API Service: Fixed localhost:3000, auto-assigned for 443 and 9090");
43    println!();
44    
45    // Clone containers for hooks
46    let postgres_before = postgres_container.clone();
47    let web_before = web_container.clone();
48    let api_before = api_container.clone();
49    
50    // Start containers in before_each
51    before_each(move |ctx| {
52        println!("🚀 before_each: Starting containers with specified ports...");
53        
54        // Start PostgreSQL container
55        let postgres_info = postgres_before.start()
56            .map_err(|e| format!("Failed to start PostgreSQL container: {}", e))?;
57        ctx.set_data("postgres_container_info", postgres_info.clone());
58        
59        println!("✅ PostgreSQL started: {}", postgres_info.container_id);
60        println!("   📍 Port mappings: {}", postgres_info.ports_summary());
61        println!("   🗄️ Database URL: postgresql://postgres:testpass@localhost:5432/testdb");
62        
63        // Start web container
64        let web_info = web_before.start()
65            .map_err(|e| format!("Failed to start web container: {}", e))?;
66        ctx.set_data("web_container_info", web_info.clone());
67        
68        println!("✅ Web service started: {}", web_info.container_id);
69        println!("   📍 Port mappings: {}", web_info.ports_summary());
70        println!("   🌐 Web accessible at: http://localhost:8080");
71        
72        // Start API container
73        let api_info = api_before.start()
74            .map_err(|e| format!("Failed to start API container: {}", e))?;
75        ctx.set_data("api_container_info", api_info.clone());
76        
77        println!("✅ API service started: {}", api_info.container_id);
78        println!("   📍 Port mappings: {}", api_info.ports_summary());
79        println!("   🔗 API accessible at: http://localhost:3000");
80        if let Some(https_port) = api_info.host_port_for(443) {
81            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
82        }
83        if let Some(metrics_port) = api_info.host_port_for(9090) {
84            println!("   📊 Metrics accessible at: http://localhost:{}/metrics", metrics_port);
85        }
86        
87        Ok(())
88    });
89    
90    // Cleanup containers in after_each
91    let postgres_after = postgres_container.clone();
92    let web_after = web_container.clone();
93    let api_after = api_container.clone();
94    
95    after_each(move |ctx| {
96        println!("🧹 after_each: Cleaning up containers...");
97        
98        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
99            let _ = postgres_after.stop(&postgres_info.container_id);
100            println!("🛑 Stopped PostgreSQL container");
101        }
102        
103        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
104            let _ = web_after.stop(&web_info.container_id);
105            println!("🛑 Stopped web container");
106        }
107        
108        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
109            let _ = api_after.stop(&api_info.container_id);
110            println!("🛑 Stopped API container");
111        }
112        
113        println!("✅ All containers cleaned up!");
114        Ok(())
115    });
116    
117    // Test 1: Database connection test
118    test("test_database_connection", |ctx| {
119        println!("🧪 Testing database connection on fixed port 5432...");
120        
121        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
122            assert_eq!(postgres_info.host_port_for(5432), Some(5432));
123            assert_eq!(postgres_info.url_for_port(5432), Some("localhost:5432".to_string()));
124            println!("✅ Database is accessible on the expected port 5432");
125        } else {
126            return Err("PostgreSQL container info not found".into());
127        }
128        
129        Ok(())
130    });
131    
132    // Test 2: Web service test
133    test("test_web_service_fixed_port", |ctx| {
134        println!("🧪 Testing web service on fixed port 8080...");
135        
136        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
137            assert_eq!(web_info.host_port_for(80), Some(8080));
138            assert_eq!(web_info.url_for_port(80), Some("localhost:8080".to_string()));
139            println!("✅ Web service is accessible on the expected port 8080");
140        } else {
141            return Err("Web container info not found".into());
142        }
143        
144        Ok(())
145    });
146    
147    // Test 3: Mixed configuration test
148    test("test_mixed_port_configuration", |ctx| {
149        println!("🧪 Testing mixed port configuration (fixed + auto)...");
150        
151        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
152            // Test fixed port
153            assert_eq!(api_info.host_port_for(80), Some(3000));
154            assert_eq!(api_info.url_for_port(80), Some("localhost:3000".to_string()));
155            println!("✅ Fixed port 3000 -> 80 is working");
156            
157            // Test auto-assigned ports
158            if let Some(https_port) = api_info.host_port_for(443) {
159                assert!(https_port > 1024); // Should be a high port
160                println!("✅ Auto-assigned HTTPS port: {}", https_port);
161            }
162            
163            if let Some(metrics_port) = api_info.host_port_for(9090) {
164                assert!(metrics_port > 1024); // Should be a high port
165                println!("✅ Auto-assigned metrics port: {}", metrics_port);
166            }
167            
168            println!("✅ Mixed configuration is working correctly");
169        } else {
170            return Err("API container info not found".into());
171        }
172        
173        Ok(())
174    });
175    
176    println!("🚀 Running user-specified ports tests...");
177    
178    let config = TestConfig {
179        html_report: Some("user-specified-ports-report.html".to_string()),
180        ..Default::default()
181    };
182    
183    let exit_code = run_tests_with_config(config);
184    
185    println!();
186    println!("🎉 Tests completed!");
187    println!("📊 Check the HTML report for detailed results.");
188    println!();
189    println!("💡 Key Takeaways:");
190    println!("   • Use .port(host_port, container_port) for fixed port mappings");
191    println!("   • Use .auto_port(container_port) for automatic port assignment");
192    println!("   • Mix both approaches for maximum flexibility");
193    println!("   • Fixed ports are great for services with standard ports (5432, 3306, etc.)");
194    println!("   • Auto-ports prevent conflicts in parallel test environments");
195    
196    std::process::exit(exit_code);
197}
More examples
Hide additional examples
examples/mongodb_integration.rs (line 76)
68fn main() {
69    println!("🐳 MongoDB Integration Example with Container Hooks");
70    println!("==================================================");
71    println!();
72    
73    // Define container configuration with auto-port for MongoDB
74    let mongo_container = ContainerConfig::new("mongo:5.0")
75        .auto_port(27017) // Automatically assign available host port for MongoDB
76        .env("MONGO_INITDB_ROOT_USERNAME", "admin")
77        .env("MONGO_INITDB_ROOT_PASSWORD", "password")
78        .name("test_mongodb")
79        .ready_timeout(Duration::from_secs(30));
80    
81    println!("📋 Container Configuration:");
82    println!("  Image: {}", mongo_container.image);
83    println!("  Auto-ports: {:?}", mongo_container.auto_ports);
84    println!("  Environment: {:?}", mongo_container.env);
85    println!("  Name: {:?}", mongo_container.name);
86    println!("  Ready Timeout: {:?}", mongo_container.ready_timeout);
87    println!("  Auto-cleanup: {}", mongo_container.auto_cleanup);
88    println!();
89    
90    // Clone for before_each hook
91    let mongo_container_before = mongo_container.clone();
92    
93    // Register before_each hook to start container
94    before_each(move |ctx| {
95        println!("🔄 before_each: Starting MongoDB container...");
96        
97        // Start the container and get ContainerInfo
98        let container_info = mongo_container_before.start()
99            .map_err(|e| format!("Failed to start container: {}", e))?;
100        
101        // Store container info in context for tests to access
102        ctx.set_data("mongo_container_info", container_info.clone());
103        
104        // Log container details including auto-assigned ports
105        println!("✅ before_each: MongoDB container {} started", container_info.container_id);
106        println!("🌐 Container exposed on: {}", container_info.ports_summary());
107        if let Some(primary_url) = container_info.primary_url() {
108            println!("🔗 Primary URL: {}", primary_url);
109        }
110        
111        Ok(())
112    });
113    
114    // Register after_each hook to stop container
115    let mongo_container_after = mongo_container.clone();
116    rust_test_harness::after_each(move |ctx| {
117        println!("🔄 after_each: Stopping MongoDB container...");
118        
119        // Get container info from context
120        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
121            .expect("Container info should be available");
122        
123        // Stop the container
124        mongo_container_after.stop(&container_info.container_id)
125            .map_err(|e| format!("Failed to stop container: {}", e))?;
126        
127        println!("✅ after_each: MongoDB container {} stopped", container_info.container_id);
128        Ok(())
129    });
130    
131    // Test 1: Basic MongoDB operations
132    test("test_mongodb_basic_operations", |ctx| {
133        println!("🧪 Running test: test_mongodb_basic_operations");
134        
135        // Get container info from context
136        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
137            .expect("Container info should be available");
138        
139        // Show how to access port information
140        println!("🌐 Container {} is running on:", container_info.container_id);
141        println!("   Ports: {}", container_info.ports_summary());
142        if let Some(primary_url) = container_info.primary_url() {
143            println!("   Primary URL: {}", primary_url);
144        }
145        
146        // Get the MongoDB port (27017) and show the actual host port
147        if let Some(host_port) = container_info.host_port_for(27017) {
148            println!("   MongoDB accessible at: localhost:{}", host_port);
149        }
150        
151        // Create MongoDB client
152        let mut client = MongoClient::new(container_info.container_id.clone());
153        
154        // Connect to MongoDB
155        client.connect()?;
156        
157        // Insert a document
158        client.insert_document("users", r#"{"name": "John Doe", "email": "john@example.com"}"#)?;
159        
160        // Find documents
161        let documents = client.find_documents("users", r#"{"name": "John Doe"}"#)?;
162        assert_eq!(documents.len(), 2);
163        
164        // Disconnect
165        client.disconnect()?;
166        
167        println!("✅ test_mongodb_basic_operations passed");
168        Ok(())
169    });
170    
171    // Test 2: Multiple operations
172    test("test_mongodb_multiple_operations", |ctx| {
173        println!("🧪 Running test: test_mongodb_multiple_operations");
174        
175        // Get container info from context
176        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
177            .expect("Container info should be available");
178        
179        // Show container status
180        println!("🌐 Container {} status:", container_info.container_id);
181        println!("   Active ports: {}", container_info.ports_summary());
182        
183        // Create MongoDB client
184        let mut client = MongoClient::new(container_info.container_id.clone());
185        
186        // Connect to MongoDB
187        client.connect()?;
188        
189        // Insert multiple documents
190        client.insert_document("products", r#"{"name": "Laptop", "price": 999.99}"#)?;
191        client.insert_document("products", r#"{"name": "Mouse", "price": 29.99}"#)?;
192        client.insert_document("products", r#"{"name": "Keyboard", "price": 79.99}"#)?;
193        
194        // Find documents
195        let documents = client.find_documents("products", r#"{"price": {"$gt": 50}}"#)?;
196        assert_eq!(documents.len(), 2); // Laptop and Keyboard
197        
198        // Disconnect
199        client.disconnect()?;
200        
201        println!("✅ test_mongodb_multiple_operations passed");
202        Ok(())
203    });
204    
205    // Test 3: Error handling
206    test("test_mongodb_error_handling", |ctx| {
207        println!("🧪 Running test: test_mongodb_error_handling");
208        
209        // Get container ID from context
210        let container_id = ctx.get_data::<String>("mongo_container_id")
211            .expect("Container ID should be available")
212            .to_string();
213        
214        // Create MongoDB client
215        let client = MongoClient::new(container_id);
216        
217        // Try to insert without connecting (should fail)
218        let result = client.insert_document("users", r#"{"name": "Test"}"#);
219        assert!(result.is_err());
220        assert_eq!(result.unwrap_err(), "Not connected to MongoDB");
221        
222        println!("✅ test_mongodb_error_handling passed");
223        Ok(())
224    });
225    
226    // Test 4: Performance testing
227    test("test_mongodb_performance", |ctx| {
228        println!("🧪 Running test: test_mongodb_performance");
229        
230        // Get container ID from context
231        let container_id = ctx.get_data::<String>("mongo_container_id")
232            .expect("Container ID should be available")
233            .to_string();
234        
235        // Create MongoDB client
236        let mut client = MongoClient::new(container_id);
237        
238        // Connect to MongoDB
239        client.connect()?;
240        
241        // Simulate bulk operations
242        for i in 0..100 {
243            client.insert_document("bulk_data", &format!(r#"{{"index": {}, "data": "bulk_item_{}"}}"#, i, i))?;
244        }
245        
246        // Simulate bulk retrieval
247        let documents = client.find_documents("bulk_data", r#"{"index": {"$lt": 50}}"#)?;
248        assert_eq!(documents.len(), 2); // Mock always returns 2
249        
250        // Disconnect
251        client.disconnect()?;
252        
253        println!("✅ test_mongodb_performance passed");
254        Ok(())
255    });
256    
257    println!("\n🚀 Running MongoDB integration tests...");
258    println!("   Each test will get a fresh MongoDB container via before_each");
259    println!("   Each test will clean up its container via after_each");
260    println!();
261    
262    // Run tests with container hooks enabled
263    let config = TestConfig {
264        skip_hooks: Some(false),
265        ..Default::default()
266    };
267    
268    let result = run_tests_with_config(config);
269    
270    println!("\n📊 Test Results:");
271    if result == 0 {
272        println!("✅ All MongoDB integration tests passed!");
273        println!("🎯 Container lifecycle management working correctly");
274        println!("🐳 Each test got its own MongoDB container");
275        println!("🧹 Each test cleaned up its container properly");
276    } else {
277        println!("❌ Some tests failed");
278    }
279    
280    println!("\n💡 Key Benefits of this approach:");
281    println!("   • Clean separation of concerns");
282    println!("   • Each test gets a fresh container");
283    println!("   • Automatic cleanup via after_each");
284    println!("   • Easy to configure containers");
285    println!("   • No complex global state management");
286}
examples/auto_port_demo.rs (line 20)
12fn main() {
13    println!("🚀 Auto-Port and Container Management Demo");
14    println!("==========================================");
15    println!();
16    
17    // Example 1: Web service with auto-port
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80) // Automatically assign host port for container port 80
20        .env("NGINX_HOST", "localhost")
21        .name("web_service")
22        .ready_timeout(Duration::from_secs(15));
23    
24    // Example 2: Database with auto-port
25    let db_container = ContainerConfig::new("postgres:13-alpine")
26        .auto_port(5432) // Automatically assign host port for container port 5432
27        .env("POSTGRES_PASSWORD", "testpass")
28        .env("POSTGRES_DB", "testdb")
29        .name("test_database")
30        .ready_timeout(Duration::from_secs(20));
31    
32    // Example 3: Redis with auto-port
33    let redis_container = ContainerConfig::new("redis:6-alpine")
34        .auto_port(6379) // Automatically assign host port for container port 6379
35        .name("test_redis")
36        .ready_timeout(Duration::from_secs(10));
37    
38    // Example 4: Mixed configuration (manual + auto ports)
39    let mixed_container = ContainerConfig::new("httpd:alpine")
40        .port(8080, 80) // Manual port mapping
41        .auto_port(443) // Auto port for HTTPS
42        .env("APACHE_DOCUMENT_ROOT", "/var/www/html")
43        .name("mixed_ports")
44        .ready_timeout(Duration::from_secs(15));
45    
46    println!("📋 Container Configurations:");
47    println!("1. Web Service (nginx):");
48    println!("   - Image: {}", web_container.image);
49    println!("   - Auto-ports: {:?}", web_container.auto_ports);
50    println!("   - Auto-cleanup: {}", web_container.auto_cleanup);
51    
52    println!("2. Database (postgres):");
53    println!("   - Image: {}", db_container.image);
54    println!("   - Auto-ports: {:?}", db_container.auto_ports);
55    println!("   - Auto-cleanup: {}", db_container.auto_cleanup);
56    
57    println!("3. Cache (redis):");
58    println!("   - Image: {}", redis_container.image);
59    println!("   - Auto-ports: {:?}", redis_container.auto_ports);
60    println!("   - Auto-cleanup: {}", redis_container.auto_cleanup);
61    
62    println!("4. Mixed (httpd):");
63    println!("   - Image: {}", mixed_container.image);
64    println!("   - Manual ports: {:?}", mixed_container.ports);
65    println!("   - Auto-ports: {:?}", mixed_container.auto_ports);
66    println!("   - Auto-cleanup: {}", mixed_container.auto_cleanup);
67    println!();
68    
69    // Clone containers for hooks
70    let web_before = web_container.clone();
71    let db_before = db_container.clone();
72    let redis_before = redis_container.clone();
73    let mixed_before = mixed_container.clone();
74    
75    // Start all containers in before_each for each test
76    before_each(move |ctx| {
77        println!("🚀 before_each: Starting all containers...");
78        
79        // Start web container
80        let web_info = web_before.start()
81            .map_err(|e| format!("Failed to start web container: {}", e))?;
82        ctx.set_data("web_container_info", web_info.clone());
83        println!("✅ Web container started: {}", web_info.container_id);
84        println!("   Ports: {}", web_info.ports_summary());
85        if let Some(url) = web_info.primary_url() {
86            println!("   URL: {}", url);
87        }
88        
89        // Start database container
90        let db_info = db_before.start()
91            .map_err(|e| format!("Failed to start db container: {}", e))?;
92        ctx.set_data("db_container_info", db_info.clone());
93        println!("✅ Database container started: {}", db_info.container_id);
94        println!("   Ports: {}", db_info.ports_summary());
95        if let Some(host_port) = db_info.host_port_for(5432) {
96            println!("   PostgreSQL accessible at: localhost:{}", host_port);
97        }
98        
99        // Start redis container
100        let redis_info = redis_before.start()
101            .map_err(|e| format!("Failed to start redis container: {}", e))?;
102        ctx.set_data("redis_container_info", redis_info.clone());
103        println!("✅ Redis container started: {}", redis_info.container_id);
104        println!("   Ports: {}", redis_info.ports_summary());
105        if let Some(host_port) = redis_info.host_port_for(6379) {
106            println!("   Redis accessible at: localhost:{}", host_port);
107        }
108        
109        // Start mixed container
110        let mixed_info = mixed_before.start()
111            .map_err(|e| format!("Failed to start mixed container: {}", e))?;
112        ctx.set_data("mixed_container_info", mixed_info.clone());
113        println!("✅ Mixed container started: {}", mixed_info.container_id);
114        println!("   Ports: {}", mixed_info.ports_summary());
115        if let Some(host_port) = mixed_info.host_port_for(443) {
116            println!("   HTTPS accessible at: localhost:{}", host_port);
117        }
118        
119        println!("🎉 All containers started successfully!");
120        Ok(())
121    });
122    
123    // Cleanup all containers in after_each for each test
124    let web_after = web_container.clone();
125    let db_after = db_container.clone();
126    let redis_after = redis_container.clone();
127    let mixed_after = mixed_container.clone();
128    
129    after_each(move |ctx| {
130        println!("🧹 after_each: Cleaning up all containers...");
131        
132        // Get all container info and stop them
133        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
134            let _ = web_after.stop(&web_info.container_id);
135            println!("🛑 Stopped web container: {}", web_info.container_id);
136        }
137        
138        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
139            let _ = db_after.stop(&db_info.container_id);
140            println!("🛑 Stopped database container: {}", db_info.container_id);
141        }
142        
143        if let Some(redis_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info") {
144            let _ = redis_after.stop(&redis_info.container_id);
145            println!("🛑 Stopped redis container: {}", redis_info.container_id);
146        }
147        
148        if let Some(mixed_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info") {
149            let _ = mixed_after.stop(&mixed_info.container_id);
150            println!("🛑 Stopped mixed container: {}", mixed_info.container_id);
151        }
152        
153        println!("✅ All containers cleaned up!");
154        Ok(())
155    });
156    
157    // Test 1: Access web service
158    test("test_web_service_access", |ctx| {
159        println!("🧪 Testing web service access...");
160        
161        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
162            .expect("Web container info should be available");
163        
164        println!("🌐 Web service container: {}", web_info.container_id);
165        println!("   Ports: {}", web_info.ports_summary());
166        println!("   Primary URL: {}", web_info.primary_url().unwrap_or("None"));
167        
168        // In a real test, you would make HTTP requests to the container
169        // For demo purposes, just verify the port information
170        assert!(web_info.host_port_for(80).is_some(), "Web service should have port 80 exposed");
171        
172        println!("✅ Web service test passed");
173        Ok(())
174    });
175    
176    // Test 2: Access database
177    test("test_database_access", |ctx| {
178        println!("🧪 Testing database access...");
179        
180        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
181            .expect("Database container info should be available");
182        
183        println!("🗄️ Database container: {}", db_info.container_id);
184        println!("   Ports: {}", db_info.ports_summary());
185        
186        // Verify PostgreSQL port is exposed
187        let postgres_port = db_info.host_port_for(5432)
188            .expect("PostgreSQL port 5432 should be exposed");
189        println!("   PostgreSQL accessible at: localhost:{}", postgres_port);
190        
191        // In a real test, you would connect to the database
192        // For demo purposes, just verify the port information
193        assert!(postgres_port > 0, "PostgreSQL port should be valid");
194        
195        println!("✅ Database test passed");
196        Ok(())
197    });
198    
199    // Test 3: Access redis
200    test("test_redis_access", |ctx| {
201        println!("🧪 Testing redis access...");
202        
203        let redis_info = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info")
204            .expect("Redis container info should be available");
205        
206        println!("🔴 Redis container: {}", redis_info.container_id);
207        println!("   Ports: {}", redis_info.ports_summary());
208        
209        // Verify Redis port is exposed
210        let redis_port = redis_info.host_port_for(6379)
211            .expect("Redis port 6379 should be exposed");
212        println!("   Redis accessible at: localhost:{}", redis_port);
213        
214        // In a real test, you would connect to Redis
215        // For demo purposes, just verify the port information
216        assert!(redis_port > 0, "Redis port should be valid");
217        
218        println!("✅ Redis test passed");
219        Ok(())
220    });
221    
222    // Test 4: Mixed port configuration
223    test("test_mixed_port_config", |ctx| {
224        println!("🧪 Testing mixed port configuration...");
225        
226        let mixed_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info")
227            .expect("Mixed container info should be available");
228        
229        println!("🔀 Mixed container: {}", mixed_info.container_id);
230        println!("   Ports: {}", mixed_info.ports_summary());
231        
232        // Verify both manual and auto ports
233        let http_port = mixed_info.host_port_for(80)
234            .expect("HTTP port 80 should be exposed");
235        let https_port = mixed_info.host_port_for(443)
236            .expect("HTTPS port 443 should be exposed");
237        
238        println!("   HTTP accessible at: localhost:{}", http_port);
239        println!("   HTTPS accessible at: localhost:{}", https_port);
240        
241        // Verify the manual port mapping (8080 -> 80)
242        assert_eq!(http_port, 8080, "Manual port mapping should work");
243        
244        // Verify auto port is different from manual port
245        assert_ne!(https_port, 8080, "Auto port should be different from manual port");
246        
247        println!("✅ Mixed port configuration test passed");
248        Ok(())
249    });
250    
251    // Test 5: Container info methods
252    test("test_container_info_methods", |ctx| {
253        println!("🧪 Testing container info methods...");
254        
255        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
256            .expect("Web container info should be available");
257        
258        // Test all the convenience methods
259        println!("🔍 Testing container info methods for: {}", web_info.container_id);
260        
261        // Test primary_url
262        if let Some(url) = web_info.primary_url() {
263            println!("   Primary URL: {}", url);
264            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
265        }
266        
267        // Test url_for_port
268        if let Some(url) = web_info.url_for_port(80) {
269            println!("   URL for port 80: {}", url);
270            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
271        }
272        
273        // Test host_port_for
274        if let Some(host_port) = web_info.host_port_for(80) {
275            println!("   Host port for container port 80: {}", host_port);
276            assert!(host_port > 0, "Host port should be valid");
277        }
278        
279        // Test ports_summary
280        let summary = web_info.ports_summary();
281        println!("   Ports summary: {}", summary);
282        assert!(!summary.is_empty(), "Ports summary should not be empty");
283        
284        println!("✅ Container info methods test passed");
285        Ok(())
286    });
287    
288    println!("🚀 Running tests with auto-port functionality...");
289    println!();
290    
291    // Run the tests
292    let config = TestConfig {
293        html_report: Some("auto-port-demo-report.html".to_string()),
294        ..Default::default()
295    };
296    
297    let exit_code = run_tests_with_config(config);
298    
299    println!();
300    if exit_code == 0 {
301        println!("🎉 All tests passed! Auto-port functionality is working correctly.");
302        println!("📊 Check the HTML report for detailed results.");
303    } else {
304        println!("❌ Some tests failed. Check the output above for details.");
305    }
306    
307    std::process::exit(exit_code);
308}
examples/container_port_access.rs (line 21)
12fn main() {
13    println!("🌐 Container Port and URL Access Example");
14    println!("========================================");
15    println!();
16    
17    // Example 1: Web service with multiple auto-ports
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80)      // Auto-assign port for HTTP
20        .auto_port(443)     // Auto-assign port for HTTPS
21        .env("NGINX_HOST", "localhost")
22        .name("web_service")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Database with auto-port
26    let db_container = ContainerConfig::new("postgres:13-alpine")
27        .auto_port(5432)    // Auto-assign port for PostgreSQL
28        .env("POSTGRES_PASSWORD", "testpass")
29        .env("POSTGRES_DB", "testdb")
30        .name("test_database")
31        .ready_timeout(Duration::from_secs(20));
32    
33    // Example 3: Mixed configuration (manual + auto ports)
34    let api_container = ContainerConfig::new("httpd:alpine")
35        .port(8080, 80)     // Manual port mapping
36        .auto_port(9090)    // Auto-assign port for API
37        .auto_port(9091)    // Auto-assign port for metrics
38        .env("API_VERSION", "v1")
39        .name("api_service")
40        .ready_timeout(Duration::from_secs(15));
41    
42    println!("📋 Container Configurations:");
43    println!("1. Web Service:");
44    println!("   - Image: {}", web_container.image);
45    println!("   - Auto-ports: {:?}", web_container.auto_ports);
46    println!("   - Will auto-assign host ports for container ports 80 and 443");
47    
48    println!("2. Database:");
49    println!("   - Image: {}", db_container.image);
50    println!("   - Auto-ports: {:?}", db_container.auto_ports);
51    println!("   - Will auto-assign host port for container port 5432");
52    
53    println!("3. API Service:");
54    println!("   - Image: {}", api_container.image);
55    println!("   - Manual ports: {:?}", api_container.ports);
56    println!("   - Auto-ports: {:?}", api_container.auto_ports);
57    println!("   - Manual mapping: 8080 -> 80, Auto-assign: 9090, 9091");
58    println!();
59    
60    // Clone containers for hooks
61    let web_before = web_container.clone();
62    let db_before = db_container.clone();
63    let api_before = api_container.clone();
64    
65    // Start containers in before_each
66    before_each(move |ctx| {
67        println!("🚀 before_each: Starting containers and capturing port info...");
68        
69        // Start web container
70        let web_info = web_before.start()
71            .map_err(|e| format!("Failed to start web container: {}", e))?;
72        ctx.set_data("web_container_info", web_info.clone());
73        
74        println!("✅ Web container started: {}", web_info.container_id);
75        println!("   📍 Port mappings: {}", web_info.ports_summary());
76        println!("   🔗 Primary URL: {}", web_info.primary_url().unwrap_or("None"));
77        
78        // Show specific port access
79        if let Some(http_port) = web_info.host_port_for(80) {
80            println!("   🌐 HTTP accessible at: http://localhost:{}", http_port);
81        }
82        if let Some(https_port) = web_info.host_port_for(443) {
83            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
84        }
85        
86        // Start database container
87        let db_info = db_before.start()
88            .map_err(|e| format!("Failed to start db container: {}", e))?;
89        ctx.set_data("db_container_info", db_info.clone());
90        
91        println!("✅ Database container started: {}", db_info.container_id);
92        println!("   📍 Port mappings: {}", db_info.ports_summary());
93        if let Some(db_port) = db_info.host_port_for(5432) {
94            println!("   🗄️ PostgreSQL accessible at: localhost:{}", db_port);
95            println!("   📝 Connection string: postgresql://user:pass@localhost:{}/testdb", db_port);
96        }
97        
98        // Start API container
99        let api_info = api_before.start()
100            .map_err(|e| format!("Failed to start api container: {}", e))?;
101        ctx.set_data("api_container_info", api_info.clone());
102        
103        println!("✅ API container started: {}", api_info.container_id);
104        println!("   📍 Port mappings: {}", api_info.ports_summary());
105        
106        // Show both manual and auto ports
107        if let Some(http_port) = api_info.host_port_for(80) {
108            println!("   🌐 HTTP API at: http://localhost:{} (manual mapping)", http_port);
109        }
110        if let Some(api_port) = api_info.host_port_for(9090) {
111            println!("   🔧 API endpoint at: http://localhost:{} (auto-assigned)", api_port);
112        }
113        if let Some(metrics_port) = api_info.host_port_for(9091) {
114            println!("   📊 Metrics at: http://localhost:{} (auto-assigned)", metrics_port);
115        }
116        
117        println!("🎉 All containers started with auto-assigned ports!");
118        Ok(())
119    });
120    
121    // Cleanup containers in after_each
122    let web_after = web_container.clone();
123    let db_after = db_container.clone();
124    let api_after = api_container.clone();
125    
126    after_each(move |ctx| {
127        println!("🧹 after_each: Cleaning up containers...");
128        
129        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
130            let _ = web_after.stop(&web_info.container_id);
131            println!("🛑 Stopped web container: {}", web_info.container_id);
132        }
133        
134        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
135            let _ = db_after.stop(&db_info.container_id);
136            println!("🛑 Stopped database container: {}", db_info.container_id);
137        }
138        
139        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
140            let _ = api_after.stop(&api_info.container_id);
141            println!("🛑 Stopped API container: {}", api_info.container_id);
142        }
143        
144        println!("✅ All containers cleaned up!");
145        Ok(())
146    });
147    
148    // Test 1: Web service port access
149    test("test_web_service_port_access", |ctx| {
150        println!("🧪 Testing web service port access...");
151        
152        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
153            .expect("Web container info should be available");
154        
155        println!("🔍 Demonstrating port access methods:");
156        
157        // Method 1: Get specific host port for container port
158        if let Some(http_port) = web_info.host_port_for(80) {
159            println!("   ✅ HTTP port 80 is mapped to host port: {}", http_port);
160            println!("      💡 Use this for HTTP client connections");
161        }
162        
163        if let Some(https_port) = web_info.host_port_for(443) {
164            println!("   ✅ HTTPS port 443 is mapped to host port: {}", https_port);
165            println!("      💡 Use this for HTTPS client connections");
166        }
167        
168        // Method 2: Get ready-to-use URLs
169        if let Some(http_url) = web_info.url_for_port(80) {
170            println!("   🔗 HTTP URL: {}", http_url);
171            println!("      💡 Ready to use in HTTP requests");
172        }
173        
174        if let Some(https_url) = web_info.url_for_port(443) {
175            println!("   🔗 HTTPS URL: {}", https_url);
176            println!("      💡 Ready to use in HTTPS requests (change http:// to https://)");
177        }
178        
179        // Method 3: Get all URLs
180        println!("   📋 All service URLs:");
181        for (i, url) in web_info.urls.iter().enumerate() {
182            println!("      {}. {}", i + 1, url);
183        }
184        
185        // Method 4: Get all port mappings
186        println!("   📊 All port mappings:");
187        for (host_port, container_port) in &web_info.port_mappings {
188            println!("      Host {} -> Container {}", host_port, container_port);
189        }
190        
191        // Verify ports are different (auto-assigned)
192        assert!(web_info.host_port_for(80).unwrap() != web_info.host_port_for(443).unwrap(), 
193                "Auto-assigned ports should be different");
194        
195        println!("✅ Web service port access test passed");
196        Ok(())
197    });
198    
199    // Test 2: Database connection string generation
200    test("test_database_connection_info", |ctx| {
201        println!("🧪 Testing database connection info generation...");
202        
203        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
204            .expect("Database container info should be available");
205        
206        println!("🗄️ Database connection information:");
207        
208        // Get the auto-assigned port for PostgreSQL
209        let db_port = db_info.host_port_for(5432)
210            .expect("PostgreSQL port should be exposed");
211        
212        println!("   📍 PostgreSQL running on: localhost:{}", db_port);
213        
214        // Generate connection strings using the auto-assigned port
215        let connection_string = format!("postgresql://admin:testpass@localhost:{}/testdb", db_port);
216        let jdbc_url = format!("jdbc:postgresql://localhost:{}/testdb", db_port);
217        let docker_internal = format!("postgresql://admin:testpass@{}:5432/testdb", db_info.container_id);
218        
219        println!("   🔗 Connection strings:");
220        println!("      Standard: {}", connection_string);
221        println!("      JDBC: {}", jdbc_url);
222        println!("      Docker internal: {}", docker_internal);
223        
224        // Show how to use this in real applications
225        println!("   💡 Usage examples:");
226        println!("      - Set DATABASE_URL={}", connection_string);
227        println!("      - Use in tests: connect to localhost:{}", db_port);
228        println!("      - Container-to-container: use port 5432");
229        
230        // Verify port is valid
231        assert!(db_port > 0, "Database port should be valid");
232        println!("✅ Database connection info test passed");
233        
234        Ok(())
235    });
236    
237    // Test 3: Mixed port configuration
238    test("test_mixed_port_configuration", |ctx| {
239        println!("🧪 Testing mixed port configuration (manual + auto)...");
240        
241        let api_info = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info")
242            .expect("API container info should be available");
243        
244        println!("🔀 Mixed port configuration analysis:");
245        
246        // Manual port mapping
247        let http_port = api_info.host_port_for(80)
248            .expect("HTTP port should be mapped");
249        println!("   📌 Manual mapping - HTTP port 80 -> host port: {}", http_port);
250        assert_eq!(http_port, 8080, "Manual port should be exactly as specified");
251        
252        // Auto-assigned ports
253        let api_port = api_info.host_port_for(9090)
254            .expect("API port should be auto-assigned");
255        let metrics_port = api_info.host_port_for(9091)
256            .expect("Metrics port should be auto-assigned");
257        
258        println!("   🎲 Auto-assigned - API port 9090 -> host port: {}", api_port);
259        println!("   🎲 Auto-assigned - Metrics port 9091 -> host port: {}", metrics_port);
260        
261        // Verify auto-assigned ports are different from manual port
262        assert_ne!(api_port, 8080, "Auto-assigned port should be different from manual port");
263        assert_ne!(metrics_port, 8080, "Auto-assigned port should be different from manual port");
264        assert_ne!(api_port, metrics_port, "Auto-assigned ports should be different from each other");
265        
266        println!("   🌐 Service endpoints:");
267        println!("      Main API: http://localhost:{}/", http_port);
268        println!("      API v2: http://localhost:{}/", api_port);
269        println!("      Metrics: http://localhost:{}/metrics", metrics_port);
270        
271        // Show complete port summary
272        println!("   📋 Complete port summary: {}", api_info.ports_summary());
273        
274        println!("✅ Mixed port configuration test passed");
275        Ok(())
276    });
277    
278    // Test 4: Container info convenience methods
279    test("test_container_info_convenience_methods", |ctx| {
280        println!("🧪 Testing ContainerInfo convenience methods...");
281        
282        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
283            .expect("Web container info should be available");
284        
285        println!("🔧 Testing all ContainerInfo methods:");
286        
287        // Test primary_url()
288        if let Some(primary_url) = web_info.primary_url() {
289            println!("   ✅ primary_url(): {}", primary_url);
290            assert!(primary_url.starts_with("http://localhost:"), "Primary URL should be valid");
291        }
292        
293        // Test url_for_port()
294        if let Some(url_80) = web_info.url_for_port(80) {
295            println!("   ✅ url_for_port(80): {}", url_80);
296            assert!(url_80.contains("localhost:"), "URL should contain localhost");
297        }
298        
299        // Test host_port_for()
300        if let Some(port_80) = web_info.host_port_for(80) {
301            println!("   ✅ host_port_for(80): {}", port_80);
302            assert!(port_80 > 0, "Port should be positive");
303        }
304        
305        // Test ports_summary()
306        let summary = web_info.ports_summary();
307        println!("   ✅ ports_summary(): {}", summary);
308        assert!(summary.contains("->"), "Summary should contain port mappings");
309        
310        // Test direct field access
311        println!("   ✅ container_id: {}", web_info.container_id);
312        println!("   ✅ image: {}", web_info.image);
313        println!("   ✅ auto_cleanup: {}", web_info.auto_cleanup);
314        
315        println!("   📊 All URLs:");
316        for (i, url) in web_info.urls.iter().enumerate() {
317            println!("      {}. {}", i + 1, url);
318        }
319        
320        println!("   📊 All port mappings:");
321        for (host_port, container_port) in &web_info.port_mappings {
322            println!("      {} -> {}", host_port, container_port);
323        }
324        
325        println!("✅ Container info convenience methods test passed");
326        Ok(())
327    });
328    
329    // Test 5: Real-world usage patterns
330    test("test_real_world_usage_patterns", |ctx| {
331        println!("🧪 Testing real-world usage patterns...");
332        
333        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
334            .expect("Web container info should be available");
335        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
336            .expect("Database container info should be available");
337        
338        println!("🌍 Real-world usage examples:");
339        
340        // Pattern 1: HTTP client testing
341        if let Some(web_url) = web_info.primary_url() {
342            println!("   🌐 HTTP Client Testing:");
343            println!("      Base URL: {}", web_url);
344            println!("      GET {}/health", web_url);
345            println!("      POST {}/api/users", web_url);
346            println!("      Code: let response = reqwest::get(\"{}/health\").await?;", web_url);
347        }
348        
349        // Pattern 2: Database testing
350        if let Some(db_port) = db_info.host_port_for(5432) {
351            println!("   🗄️ Database Testing:");
352            println!("      Connection: localhost:{}", db_port);
353            println!("      Code: let conn = PgConnection::establish(\"postgresql://user:pass@localhost:{}/db\")?;", db_port);
354        }
355        
356        // Pattern 3: Environment variable setup
357        println!("   🔧 Environment Variables:");
358        if let Some(web_port) = web_info.host_port_for(80) {
359            println!("      export WEB_SERVICE_URL=http://localhost:{}", web_port);
360        }
361        if let Some(db_port) = db_info.host_port_for(5432) {
362            println!("      export DATABASE_URL=postgresql://localhost:{}/testdb", db_port);
363        }
364        
365        // Pattern 4: Docker-compose style networking
366        println!("   🐳 Container Networking:");
367        println!("      External: Use auto-assigned host ports");
368        println!("      Internal: Use original container ports");
369        println!("      Web -> DB: {}:5432 (container-to-container)", db_info.container_id);
370        
371        // Pattern 5: Health checks
372        println!("   ❤️ Health Checks:");
373        if let Some(web_url) = web_info.primary_url() {
374            println!("      Health endpoint: {}/health", web_url);
375            println!("      Ready endpoint: {}/ready", web_url);
376        }
377        
378        println!("✅ Real-world usage patterns test passed");
379        Ok(())
380    });
381    
382    println!("🚀 Running container port access tests...");
383    println!();
384    
385    // Run the tests
386    let config = TestConfig {
387        html_report: Some("container-port-access-report.html".to_string()),
388        ..Default::default()
389    };
390    
391    let exit_code = run_tests_with_config(config);
392    
393    println!();
394    if exit_code == 0 {
395        println!("🎉 All tests passed! Port access functionality is working correctly.");
396        println!("📊 Check the HTML report for detailed results.");
397        println!();
398        println!("💡 Key Takeaways:");
399        println!("   • Use auto_port() to avoid port conflicts");
400        println!("   • Access host ports with host_port_for(container_port)");
401        println!("   • Get ready-to-use URLs with url_for_port(container_port)");
402        println!("   • Use ports_summary() for human-readable port info");
403        println!("   • ContainerInfo provides complete access to all port information");
404    } else {
405        println!("❌ Some tests failed. Check the output above for details.");
406    }
407    
408    std::process::exit(exit_code);
409}
Source

pub fn name(self, name: &str) -> Self

Examples found in repository?
examples/user_specified_ports.rs (line 22)
12fn main() {
13    println!("🔧 User-Specified Ports Example");
14    println!("==============================");
15    println!();
16    
17    // Example 1: PostgreSQL on standard port 5432
18    let postgres_container = ContainerConfig::new("postgres:13-alpine")
19        .port(5432, 5432)     // Map host port 5432 to container port 5432
20        .env("POSTGRES_PASSWORD", "testpass")
21        .env("POSTGRES_DB", "testdb")
22        .name("postgres_test")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Web service on port 8080
26    let web_container = ContainerConfig::new("nginx:alpine")
27        .port(8080, 80)       // Map host port 8080 to container port 80
28        .name("nginx_test")
29        .ready_timeout(Duration::from_secs(10));
30    
31    // Example 3: Mixed configuration - some fixed, some auto
32    let api_container = ContainerConfig::new("httpd:alpine")
33        .port(3000, 80)       // Fixed port for main API
34        .auto_port(443)       // Auto-assign for HTTPS
35        .auto_port(9090)      // Auto-assign for metrics
36        .name("api_test")
37        .ready_timeout(Duration::from_secs(10));
38    
39    println!("📋 Container Configurations:");
40    println!("1. PostgreSQL: Fixed on localhost:5432 (standard PostgreSQL port)");
41    println!("2. Web Service: Fixed on localhost:8080");
42    println!("3. API Service: Fixed localhost:3000, auto-assigned for 443 and 9090");
43    println!();
44    
45    // Clone containers for hooks
46    let postgres_before = postgres_container.clone();
47    let web_before = web_container.clone();
48    let api_before = api_container.clone();
49    
50    // Start containers in before_each
51    before_each(move |ctx| {
52        println!("🚀 before_each: Starting containers with specified ports...");
53        
54        // Start PostgreSQL container
55        let postgres_info = postgres_before.start()
56            .map_err(|e| format!("Failed to start PostgreSQL container: {}", e))?;
57        ctx.set_data("postgres_container_info", postgres_info.clone());
58        
59        println!("✅ PostgreSQL started: {}", postgres_info.container_id);
60        println!("   📍 Port mappings: {}", postgres_info.ports_summary());
61        println!("   🗄️ Database URL: postgresql://postgres:testpass@localhost:5432/testdb");
62        
63        // Start web container
64        let web_info = web_before.start()
65            .map_err(|e| format!("Failed to start web container: {}", e))?;
66        ctx.set_data("web_container_info", web_info.clone());
67        
68        println!("✅ Web service started: {}", web_info.container_id);
69        println!("   📍 Port mappings: {}", web_info.ports_summary());
70        println!("   🌐 Web accessible at: http://localhost:8080");
71        
72        // Start API container
73        let api_info = api_before.start()
74            .map_err(|e| format!("Failed to start API container: {}", e))?;
75        ctx.set_data("api_container_info", api_info.clone());
76        
77        println!("✅ API service started: {}", api_info.container_id);
78        println!("   📍 Port mappings: {}", api_info.ports_summary());
79        println!("   🔗 API accessible at: http://localhost:3000");
80        if let Some(https_port) = api_info.host_port_for(443) {
81            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
82        }
83        if let Some(metrics_port) = api_info.host_port_for(9090) {
84            println!("   📊 Metrics accessible at: http://localhost:{}/metrics", metrics_port);
85        }
86        
87        Ok(())
88    });
89    
90    // Cleanup containers in after_each
91    let postgres_after = postgres_container.clone();
92    let web_after = web_container.clone();
93    let api_after = api_container.clone();
94    
95    after_each(move |ctx| {
96        println!("🧹 after_each: Cleaning up containers...");
97        
98        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
99            let _ = postgres_after.stop(&postgres_info.container_id);
100            println!("🛑 Stopped PostgreSQL container");
101        }
102        
103        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
104            let _ = web_after.stop(&web_info.container_id);
105            println!("🛑 Stopped web container");
106        }
107        
108        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
109            let _ = api_after.stop(&api_info.container_id);
110            println!("🛑 Stopped API container");
111        }
112        
113        println!("✅ All containers cleaned up!");
114        Ok(())
115    });
116    
117    // Test 1: Database connection test
118    test("test_database_connection", |ctx| {
119        println!("🧪 Testing database connection on fixed port 5432...");
120        
121        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
122            assert_eq!(postgres_info.host_port_for(5432), Some(5432));
123            assert_eq!(postgres_info.url_for_port(5432), Some("localhost:5432".to_string()));
124            println!("✅ Database is accessible on the expected port 5432");
125        } else {
126            return Err("PostgreSQL container info not found".into());
127        }
128        
129        Ok(())
130    });
131    
132    // Test 2: Web service test
133    test("test_web_service_fixed_port", |ctx| {
134        println!("🧪 Testing web service on fixed port 8080...");
135        
136        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
137            assert_eq!(web_info.host_port_for(80), Some(8080));
138            assert_eq!(web_info.url_for_port(80), Some("localhost:8080".to_string()));
139            println!("✅ Web service is accessible on the expected port 8080");
140        } else {
141            return Err("Web container info not found".into());
142        }
143        
144        Ok(())
145    });
146    
147    // Test 3: Mixed configuration test
148    test("test_mixed_port_configuration", |ctx| {
149        println!("🧪 Testing mixed port configuration (fixed + auto)...");
150        
151        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
152            // Test fixed port
153            assert_eq!(api_info.host_port_for(80), Some(3000));
154            assert_eq!(api_info.url_for_port(80), Some("localhost:3000".to_string()));
155            println!("✅ Fixed port 3000 -> 80 is working");
156            
157            // Test auto-assigned ports
158            if let Some(https_port) = api_info.host_port_for(443) {
159                assert!(https_port > 1024); // Should be a high port
160                println!("✅ Auto-assigned HTTPS port: {}", https_port);
161            }
162            
163            if let Some(metrics_port) = api_info.host_port_for(9090) {
164                assert!(metrics_port > 1024); // Should be a high port
165                println!("✅ Auto-assigned metrics port: {}", metrics_port);
166            }
167            
168            println!("✅ Mixed configuration is working correctly");
169        } else {
170            return Err("API container info not found".into());
171        }
172        
173        Ok(())
174    });
175    
176    println!("🚀 Running user-specified ports tests...");
177    
178    let config = TestConfig {
179        html_report: Some("user-specified-ports-report.html".to_string()),
180        ..Default::default()
181    };
182    
183    let exit_code = run_tests_with_config(config);
184    
185    println!();
186    println!("🎉 Tests completed!");
187    println!("📊 Check the HTML report for detailed results.");
188    println!();
189    println!("💡 Key Takeaways:");
190    println!("   • Use .port(host_port, container_port) for fixed port mappings");
191    println!("   • Use .auto_port(container_port) for automatic port assignment");
192    println!("   • Mix both approaches for maximum flexibility");
193    println!("   • Fixed ports are great for services with standard ports (5432, 3306, etc.)");
194    println!("   • Auto-ports prevent conflicts in parallel test environments");
195    
196    std::process::exit(exit_code);
197}
More examples
Hide additional examples
examples/mongodb_integration.rs (line 78)
68fn main() {
69    println!("🐳 MongoDB Integration Example with Container Hooks");
70    println!("==================================================");
71    println!();
72    
73    // Define container configuration with auto-port for MongoDB
74    let mongo_container = ContainerConfig::new("mongo:5.0")
75        .auto_port(27017) // Automatically assign available host port for MongoDB
76        .env("MONGO_INITDB_ROOT_USERNAME", "admin")
77        .env("MONGO_INITDB_ROOT_PASSWORD", "password")
78        .name("test_mongodb")
79        .ready_timeout(Duration::from_secs(30));
80    
81    println!("📋 Container Configuration:");
82    println!("  Image: {}", mongo_container.image);
83    println!("  Auto-ports: {:?}", mongo_container.auto_ports);
84    println!("  Environment: {:?}", mongo_container.env);
85    println!("  Name: {:?}", mongo_container.name);
86    println!("  Ready Timeout: {:?}", mongo_container.ready_timeout);
87    println!("  Auto-cleanup: {}", mongo_container.auto_cleanup);
88    println!();
89    
90    // Clone for before_each hook
91    let mongo_container_before = mongo_container.clone();
92    
93    // Register before_each hook to start container
94    before_each(move |ctx| {
95        println!("🔄 before_each: Starting MongoDB container...");
96        
97        // Start the container and get ContainerInfo
98        let container_info = mongo_container_before.start()
99            .map_err(|e| format!("Failed to start container: {}", e))?;
100        
101        // Store container info in context for tests to access
102        ctx.set_data("mongo_container_info", container_info.clone());
103        
104        // Log container details including auto-assigned ports
105        println!("✅ before_each: MongoDB container {} started", container_info.container_id);
106        println!("🌐 Container exposed on: {}", container_info.ports_summary());
107        if let Some(primary_url) = container_info.primary_url() {
108            println!("🔗 Primary URL: {}", primary_url);
109        }
110        
111        Ok(())
112    });
113    
114    // Register after_each hook to stop container
115    let mongo_container_after = mongo_container.clone();
116    rust_test_harness::after_each(move |ctx| {
117        println!("🔄 after_each: Stopping MongoDB container...");
118        
119        // Get container info from context
120        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
121            .expect("Container info should be available");
122        
123        // Stop the container
124        mongo_container_after.stop(&container_info.container_id)
125            .map_err(|e| format!("Failed to stop container: {}", e))?;
126        
127        println!("✅ after_each: MongoDB container {} stopped", container_info.container_id);
128        Ok(())
129    });
130    
131    // Test 1: Basic MongoDB operations
132    test("test_mongodb_basic_operations", |ctx| {
133        println!("🧪 Running test: test_mongodb_basic_operations");
134        
135        // Get container info from context
136        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
137            .expect("Container info should be available");
138        
139        // Show how to access port information
140        println!("🌐 Container {} is running on:", container_info.container_id);
141        println!("   Ports: {}", container_info.ports_summary());
142        if let Some(primary_url) = container_info.primary_url() {
143            println!("   Primary URL: {}", primary_url);
144        }
145        
146        // Get the MongoDB port (27017) and show the actual host port
147        if let Some(host_port) = container_info.host_port_for(27017) {
148            println!("   MongoDB accessible at: localhost:{}", host_port);
149        }
150        
151        // Create MongoDB client
152        let mut client = MongoClient::new(container_info.container_id.clone());
153        
154        // Connect to MongoDB
155        client.connect()?;
156        
157        // Insert a document
158        client.insert_document("users", r#"{"name": "John Doe", "email": "john@example.com"}"#)?;
159        
160        // Find documents
161        let documents = client.find_documents("users", r#"{"name": "John Doe"}"#)?;
162        assert_eq!(documents.len(), 2);
163        
164        // Disconnect
165        client.disconnect()?;
166        
167        println!("✅ test_mongodb_basic_operations passed");
168        Ok(())
169    });
170    
171    // Test 2: Multiple operations
172    test("test_mongodb_multiple_operations", |ctx| {
173        println!("🧪 Running test: test_mongodb_multiple_operations");
174        
175        // Get container info from context
176        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
177            .expect("Container info should be available");
178        
179        // Show container status
180        println!("🌐 Container {} status:", container_info.container_id);
181        println!("   Active ports: {}", container_info.ports_summary());
182        
183        // Create MongoDB client
184        let mut client = MongoClient::new(container_info.container_id.clone());
185        
186        // Connect to MongoDB
187        client.connect()?;
188        
189        // Insert multiple documents
190        client.insert_document("products", r#"{"name": "Laptop", "price": 999.99}"#)?;
191        client.insert_document("products", r#"{"name": "Mouse", "price": 29.99}"#)?;
192        client.insert_document("products", r#"{"name": "Keyboard", "price": 79.99}"#)?;
193        
194        // Find documents
195        let documents = client.find_documents("products", r#"{"price": {"$gt": 50}}"#)?;
196        assert_eq!(documents.len(), 2); // Laptop and Keyboard
197        
198        // Disconnect
199        client.disconnect()?;
200        
201        println!("✅ test_mongodb_multiple_operations passed");
202        Ok(())
203    });
204    
205    // Test 3: Error handling
206    test("test_mongodb_error_handling", |ctx| {
207        println!("🧪 Running test: test_mongodb_error_handling");
208        
209        // Get container ID from context
210        let container_id = ctx.get_data::<String>("mongo_container_id")
211            .expect("Container ID should be available")
212            .to_string();
213        
214        // Create MongoDB client
215        let client = MongoClient::new(container_id);
216        
217        // Try to insert without connecting (should fail)
218        let result = client.insert_document("users", r#"{"name": "Test"}"#);
219        assert!(result.is_err());
220        assert_eq!(result.unwrap_err(), "Not connected to MongoDB");
221        
222        println!("✅ test_mongodb_error_handling passed");
223        Ok(())
224    });
225    
226    // Test 4: Performance testing
227    test("test_mongodb_performance", |ctx| {
228        println!("🧪 Running test: test_mongodb_performance");
229        
230        // Get container ID from context
231        let container_id = ctx.get_data::<String>("mongo_container_id")
232            .expect("Container ID should be available")
233            .to_string();
234        
235        // Create MongoDB client
236        let mut client = MongoClient::new(container_id);
237        
238        // Connect to MongoDB
239        client.connect()?;
240        
241        // Simulate bulk operations
242        for i in 0..100 {
243            client.insert_document("bulk_data", &format!(r#"{{"index": {}, "data": "bulk_item_{}"}}"#, i, i))?;
244        }
245        
246        // Simulate bulk retrieval
247        let documents = client.find_documents("bulk_data", r#"{"index": {"$lt": 50}}"#)?;
248        assert_eq!(documents.len(), 2); // Mock always returns 2
249        
250        // Disconnect
251        client.disconnect()?;
252        
253        println!("✅ test_mongodb_performance passed");
254        Ok(())
255    });
256    
257    println!("\n🚀 Running MongoDB integration tests...");
258    println!("   Each test will get a fresh MongoDB container via before_each");
259    println!("   Each test will clean up its container via after_each");
260    println!();
261    
262    // Run tests with container hooks enabled
263    let config = TestConfig {
264        skip_hooks: Some(false),
265        ..Default::default()
266    };
267    
268    let result = run_tests_with_config(config);
269    
270    println!("\n📊 Test Results:");
271    if result == 0 {
272        println!("✅ All MongoDB integration tests passed!");
273        println!("🎯 Container lifecycle management working correctly");
274        println!("🐳 Each test got its own MongoDB container");
275        println!("🧹 Each test cleaned up its container properly");
276    } else {
277        println!("❌ Some tests failed");
278    }
279    
280    println!("\n💡 Key Benefits of this approach:");
281    println!("   • Clean separation of concerns");
282    println!("   • Each test gets a fresh container");
283    println!("   • Automatic cleanup via after_each");
284    println!("   • Easy to configure containers");
285    println!("   • No complex global state management");
286}
examples/auto_port_demo.rs (line 21)
12fn main() {
13    println!("🚀 Auto-Port and Container Management Demo");
14    println!("==========================================");
15    println!();
16    
17    // Example 1: Web service with auto-port
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80) // Automatically assign host port for container port 80
20        .env("NGINX_HOST", "localhost")
21        .name("web_service")
22        .ready_timeout(Duration::from_secs(15));
23    
24    // Example 2: Database with auto-port
25    let db_container = ContainerConfig::new("postgres:13-alpine")
26        .auto_port(5432) // Automatically assign host port for container port 5432
27        .env("POSTGRES_PASSWORD", "testpass")
28        .env("POSTGRES_DB", "testdb")
29        .name("test_database")
30        .ready_timeout(Duration::from_secs(20));
31    
32    // Example 3: Redis with auto-port
33    let redis_container = ContainerConfig::new("redis:6-alpine")
34        .auto_port(6379) // Automatically assign host port for container port 6379
35        .name("test_redis")
36        .ready_timeout(Duration::from_secs(10));
37    
38    // Example 4: Mixed configuration (manual + auto ports)
39    let mixed_container = ContainerConfig::new("httpd:alpine")
40        .port(8080, 80) // Manual port mapping
41        .auto_port(443) // Auto port for HTTPS
42        .env("APACHE_DOCUMENT_ROOT", "/var/www/html")
43        .name("mixed_ports")
44        .ready_timeout(Duration::from_secs(15));
45    
46    println!("📋 Container Configurations:");
47    println!("1. Web Service (nginx):");
48    println!("   - Image: {}", web_container.image);
49    println!("   - Auto-ports: {:?}", web_container.auto_ports);
50    println!("   - Auto-cleanup: {}", web_container.auto_cleanup);
51    
52    println!("2. Database (postgres):");
53    println!("   - Image: {}", db_container.image);
54    println!("   - Auto-ports: {:?}", db_container.auto_ports);
55    println!("   - Auto-cleanup: {}", db_container.auto_cleanup);
56    
57    println!("3. Cache (redis):");
58    println!("   - Image: {}", redis_container.image);
59    println!("   - Auto-ports: {:?}", redis_container.auto_ports);
60    println!("   - Auto-cleanup: {}", redis_container.auto_cleanup);
61    
62    println!("4. Mixed (httpd):");
63    println!("   - Image: {}", mixed_container.image);
64    println!("   - Manual ports: {:?}", mixed_container.ports);
65    println!("   - Auto-ports: {:?}", mixed_container.auto_ports);
66    println!("   - Auto-cleanup: {}", mixed_container.auto_cleanup);
67    println!();
68    
69    // Clone containers for hooks
70    let web_before = web_container.clone();
71    let db_before = db_container.clone();
72    let redis_before = redis_container.clone();
73    let mixed_before = mixed_container.clone();
74    
75    // Start all containers in before_each for each test
76    before_each(move |ctx| {
77        println!("🚀 before_each: Starting all containers...");
78        
79        // Start web container
80        let web_info = web_before.start()
81            .map_err(|e| format!("Failed to start web container: {}", e))?;
82        ctx.set_data("web_container_info", web_info.clone());
83        println!("✅ Web container started: {}", web_info.container_id);
84        println!("   Ports: {}", web_info.ports_summary());
85        if let Some(url) = web_info.primary_url() {
86            println!("   URL: {}", url);
87        }
88        
89        // Start database container
90        let db_info = db_before.start()
91            .map_err(|e| format!("Failed to start db container: {}", e))?;
92        ctx.set_data("db_container_info", db_info.clone());
93        println!("✅ Database container started: {}", db_info.container_id);
94        println!("   Ports: {}", db_info.ports_summary());
95        if let Some(host_port) = db_info.host_port_for(5432) {
96            println!("   PostgreSQL accessible at: localhost:{}", host_port);
97        }
98        
99        // Start redis container
100        let redis_info = redis_before.start()
101            .map_err(|e| format!("Failed to start redis container: {}", e))?;
102        ctx.set_data("redis_container_info", redis_info.clone());
103        println!("✅ Redis container started: {}", redis_info.container_id);
104        println!("   Ports: {}", redis_info.ports_summary());
105        if let Some(host_port) = redis_info.host_port_for(6379) {
106            println!("   Redis accessible at: localhost:{}", host_port);
107        }
108        
109        // Start mixed container
110        let mixed_info = mixed_before.start()
111            .map_err(|e| format!("Failed to start mixed container: {}", e))?;
112        ctx.set_data("mixed_container_info", mixed_info.clone());
113        println!("✅ Mixed container started: {}", mixed_info.container_id);
114        println!("   Ports: {}", mixed_info.ports_summary());
115        if let Some(host_port) = mixed_info.host_port_for(443) {
116            println!("   HTTPS accessible at: localhost:{}", host_port);
117        }
118        
119        println!("🎉 All containers started successfully!");
120        Ok(())
121    });
122    
123    // Cleanup all containers in after_each for each test
124    let web_after = web_container.clone();
125    let db_after = db_container.clone();
126    let redis_after = redis_container.clone();
127    let mixed_after = mixed_container.clone();
128    
129    after_each(move |ctx| {
130        println!("🧹 after_each: Cleaning up all containers...");
131        
132        // Get all container info and stop them
133        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
134            let _ = web_after.stop(&web_info.container_id);
135            println!("🛑 Stopped web container: {}", web_info.container_id);
136        }
137        
138        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
139            let _ = db_after.stop(&db_info.container_id);
140            println!("🛑 Stopped database container: {}", db_info.container_id);
141        }
142        
143        if let Some(redis_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info") {
144            let _ = redis_after.stop(&redis_info.container_id);
145            println!("🛑 Stopped redis container: {}", redis_info.container_id);
146        }
147        
148        if let Some(mixed_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info") {
149            let _ = mixed_after.stop(&mixed_info.container_id);
150            println!("🛑 Stopped mixed container: {}", mixed_info.container_id);
151        }
152        
153        println!("✅ All containers cleaned up!");
154        Ok(())
155    });
156    
157    // Test 1: Access web service
158    test("test_web_service_access", |ctx| {
159        println!("🧪 Testing web service access...");
160        
161        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
162            .expect("Web container info should be available");
163        
164        println!("🌐 Web service container: {}", web_info.container_id);
165        println!("   Ports: {}", web_info.ports_summary());
166        println!("   Primary URL: {}", web_info.primary_url().unwrap_or("None"));
167        
168        // In a real test, you would make HTTP requests to the container
169        // For demo purposes, just verify the port information
170        assert!(web_info.host_port_for(80).is_some(), "Web service should have port 80 exposed");
171        
172        println!("✅ Web service test passed");
173        Ok(())
174    });
175    
176    // Test 2: Access database
177    test("test_database_access", |ctx| {
178        println!("🧪 Testing database access...");
179        
180        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
181            .expect("Database container info should be available");
182        
183        println!("🗄️ Database container: {}", db_info.container_id);
184        println!("   Ports: {}", db_info.ports_summary());
185        
186        // Verify PostgreSQL port is exposed
187        let postgres_port = db_info.host_port_for(5432)
188            .expect("PostgreSQL port 5432 should be exposed");
189        println!("   PostgreSQL accessible at: localhost:{}", postgres_port);
190        
191        // In a real test, you would connect to the database
192        // For demo purposes, just verify the port information
193        assert!(postgres_port > 0, "PostgreSQL port should be valid");
194        
195        println!("✅ Database test passed");
196        Ok(())
197    });
198    
199    // Test 3: Access redis
200    test("test_redis_access", |ctx| {
201        println!("🧪 Testing redis access...");
202        
203        let redis_info = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info")
204            .expect("Redis container info should be available");
205        
206        println!("🔴 Redis container: {}", redis_info.container_id);
207        println!("   Ports: {}", redis_info.ports_summary());
208        
209        // Verify Redis port is exposed
210        let redis_port = redis_info.host_port_for(6379)
211            .expect("Redis port 6379 should be exposed");
212        println!("   Redis accessible at: localhost:{}", redis_port);
213        
214        // In a real test, you would connect to Redis
215        // For demo purposes, just verify the port information
216        assert!(redis_port > 0, "Redis port should be valid");
217        
218        println!("✅ Redis test passed");
219        Ok(())
220    });
221    
222    // Test 4: Mixed port configuration
223    test("test_mixed_port_config", |ctx| {
224        println!("🧪 Testing mixed port configuration...");
225        
226        let mixed_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info")
227            .expect("Mixed container info should be available");
228        
229        println!("🔀 Mixed container: {}", mixed_info.container_id);
230        println!("   Ports: {}", mixed_info.ports_summary());
231        
232        // Verify both manual and auto ports
233        let http_port = mixed_info.host_port_for(80)
234            .expect("HTTP port 80 should be exposed");
235        let https_port = mixed_info.host_port_for(443)
236            .expect("HTTPS port 443 should be exposed");
237        
238        println!("   HTTP accessible at: localhost:{}", http_port);
239        println!("   HTTPS accessible at: localhost:{}", https_port);
240        
241        // Verify the manual port mapping (8080 -> 80)
242        assert_eq!(http_port, 8080, "Manual port mapping should work");
243        
244        // Verify auto port is different from manual port
245        assert_ne!(https_port, 8080, "Auto port should be different from manual port");
246        
247        println!("✅ Mixed port configuration test passed");
248        Ok(())
249    });
250    
251    // Test 5: Container info methods
252    test("test_container_info_methods", |ctx| {
253        println!("🧪 Testing container info methods...");
254        
255        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
256            .expect("Web container info should be available");
257        
258        // Test all the convenience methods
259        println!("🔍 Testing container info methods for: {}", web_info.container_id);
260        
261        // Test primary_url
262        if let Some(url) = web_info.primary_url() {
263            println!("   Primary URL: {}", url);
264            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
265        }
266        
267        // Test url_for_port
268        if let Some(url) = web_info.url_for_port(80) {
269            println!("   URL for port 80: {}", url);
270            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
271        }
272        
273        // Test host_port_for
274        if let Some(host_port) = web_info.host_port_for(80) {
275            println!("   Host port for container port 80: {}", host_port);
276            assert!(host_port > 0, "Host port should be valid");
277        }
278        
279        // Test ports_summary
280        let summary = web_info.ports_summary();
281        println!("   Ports summary: {}", summary);
282        assert!(!summary.is_empty(), "Ports summary should not be empty");
283        
284        println!("✅ Container info methods test passed");
285        Ok(())
286    });
287    
288    println!("🚀 Running tests with auto-port functionality...");
289    println!();
290    
291    // Run the tests
292    let config = TestConfig {
293        html_report: Some("auto-port-demo-report.html".to_string()),
294        ..Default::default()
295    };
296    
297    let exit_code = run_tests_with_config(config);
298    
299    println!();
300    if exit_code == 0 {
301        println!("🎉 All tests passed! Auto-port functionality is working correctly.");
302        println!("📊 Check the HTML report for detailed results.");
303    } else {
304        println!("❌ Some tests failed. Check the output above for details.");
305    }
306    
307    std::process::exit(exit_code);
308}
examples/container_port_access.rs (line 22)
12fn main() {
13    println!("🌐 Container Port and URL Access Example");
14    println!("========================================");
15    println!();
16    
17    // Example 1: Web service with multiple auto-ports
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80)      // Auto-assign port for HTTP
20        .auto_port(443)     // Auto-assign port for HTTPS
21        .env("NGINX_HOST", "localhost")
22        .name("web_service")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Database with auto-port
26    let db_container = ContainerConfig::new("postgres:13-alpine")
27        .auto_port(5432)    // Auto-assign port for PostgreSQL
28        .env("POSTGRES_PASSWORD", "testpass")
29        .env("POSTGRES_DB", "testdb")
30        .name("test_database")
31        .ready_timeout(Duration::from_secs(20));
32    
33    // Example 3: Mixed configuration (manual + auto ports)
34    let api_container = ContainerConfig::new("httpd:alpine")
35        .port(8080, 80)     // Manual port mapping
36        .auto_port(9090)    // Auto-assign port for API
37        .auto_port(9091)    // Auto-assign port for metrics
38        .env("API_VERSION", "v1")
39        .name("api_service")
40        .ready_timeout(Duration::from_secs(15));
41    
42    println!("📋 Container Configurations:");
43    println!("1. Web Service:");
44    println!("   - Image: {}", web_container.image);
45    println!("   - Auto-ports: {:?}", web_container.auto_ports);
46    println!("   - Will auto-assign host ports for container ports 80 and 443");
47    
48    println!("2. Database:");
49    println!("   - Image: {}", db_container.image);
50    println!("   - Auto-ports: {:?}", db_container.auto_ports);
51    println!("   - Will auto-assign host port for container port 5432");
52    
53    println!("3. API Service:");
54    println!("   - Image: {}", api_container.image);
55    println!("   - Manual ports: {:?}", api_container.ports);
56    println!("   - Auto-ports: {:?}", api_container.auto_ports);
57    println!("   - Manual mapping: 8080 -> 80, Auto-assign: 9090, 9091");
58    println!();
59    
60    // Clone containers for hooks
61    let web_before = web_container.clone();
62    let db_before = db_container.clone();
63    let api_before = api_container.clone();
64    
65    // Start containers in before_each
66    before_each(move |ctx| {
67        println!("🚀 before_each: Starting containers and capturing port info...");
68        
69        // Start web container
70        let web_info = web_before.start()
71            .map_err(|e| format!("Failed to start web container: {}", e))?;
72        ctx.set_data("web_container_info", web_info.clone());
73        
74        println!("✅ Web container started: {}", web_info.container_id);
75        println!("   📍 Port mappings: {}", web_info.ports_summary());
76        println!("   🔗 Primary URL: {}", web_info.primary_url().unwrap_or("None"));
77        
78        // Show specific port access
79        if let Some(http_port) = web_info.host_port_for(80) {
80            println!("   🌐 HTTP accessible at: http://localhost:{}", http_port);
81        }
82        if let Some(https_port) = web_info.host_port_for(443) {
83            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
84        }
85        
86        // Start database container
87        let db_info = db_before.start()
88            .map_err(|e| format!("Failed to start db container: {}", e))?;
89        ctx.set_data("db_container_info", db_info.clone());
90        
91        println!("✅ Database container started: {}", db_info.container_id);
92        println!("   📍 Port mappings: {}", db_info.ports_summary());
93        if let Some(db_port) = db_info.host_port_for(5432) {
94            println!("   🗄️ PostgreSQL accessible at: localhost:{}", db_port);
95            println!("   📝 Connection string: postgresql://user:pass@localhost:{}/testdb", db_port);
96        }
97        
98        // Start API container
99        let api_info = api_before.start()
100            .map_err(|e| format!("Failed to start api container: {}", e))?;
101        ctx.set_data("api_container_info", api_info.clone());
102        
103        println!("✅ API container started: {}", api_info.container_id);
104        println!("   📍 Port mappings: {}", api_info.ports_summary());
105        
106        // Show both manual and auto ports
107        if let Some(http_port) = api_info.host_port_for(80) {
108            println!("   🌐 HTTP API at: http://localhost:{} (manual mapping)", http_port);
109        }
110        if let Some(api_port) = api_info.host_port_for(9090) {
111            println!("   🔧 API endpoint at: http://localhost:{} (auto-assigned)", api_port);
112        }
113        if let Some(metrics_port) = api_info.host_port_for(9091) {
114            println!("   📊 Metrics at: http://localhost:{} (auto-assigned)", metrics_port);
115        }
116        
117        println!("🎉 All containers started with auto-assigned ports!");
118        Ok(())
119    });
120    
121    // Cleanup containers in after_each
122    let web_after = web_container.clone();
123    let db_after = db_container.clone();
124    let api_after = api_container.clone();
125    
126    after_each(move |ctx| {
127        println!("🧹 after_each: Cleaning up containers...");
128        
129        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
130            let _ = web_after.stop(&web_info.container_id);
131            println!("🛑 Stopped web container: {}", web_info.container_id);
132        }
133        
134        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
135            let _ = db_after.stop(&db_info.container_id);
136            println!("🛑 Stopped database container: {}", db_info.container_id);
137        }
138        
139        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
140            let _ = api_after.stop(&api_info.container_id);
141            println!("🛑 Stopped API container: {}", api_info.container_id);
142        }
143        
144        println!("✅ All containers cleaned up!");
145        Ok(())
146    });
147    
148    // Test 1: Web service port access
149    test("test_web_service_port_access", |ctx| {
150        println!("🧪 Testing web service port access...");
151        
152        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
153            .expect("Web container info should be available");
154        
155        println!("🔍 Demonstrating port access methods:");
156        
157        // Method 1: Get specific host port for container port
158        if let Some(http_port) = web_info.host_port_for(80) {
159            println!("   ✅ HTTP port 80 is mapped to host port: {}", http_port);
160            println!("      💡 Use this for HTTP client connections");
161        }
162        
163        if let Some(https_port) = web_info.host_port_for(443) {
164            println!("   ✅ HTTPS port 443 is mapped to host port: {}", https_port);
165            println!("      💡 Use this for HTTPS client connections");
166        }
167        
168        // Method 2: Get ready-to-use URLs
169        if let Some(http_url) = web_info.url_for_port(80) {
170            println!("   🔗 HTTP URL: {}", http_url);
171            println!("      💡 Ready to use in HTTP requests");
172        }
173        
174        if let Some(https_url) = web_info.url_for_port(443) {
175            println!("   🔗 HTTPS URL: {}", https_url);
176            println!("      💡 Ready to use in HTTPS requests (change http:// to https://)");
177        }
178        
179        // Method 3: Get all URLs
180        println!("   📋 All service URLs:");
181        for (i, url) in web_info.urls.iter().enumerate() {
182            println!("      {}. {}", i + 1, url);
183        }
184        
185        // Method 4: Get all port mappings
186        println!("   📊 All port mappings:");
187        for (host_port, container_port) in &web_info.port_mappings {
188            println!("      Host {} -> Container {}", host_port, container_port);
189        }
190        
191        // Verify ports are different (auto-assigned)
192        assert!(web_info.host_port_for(80).unwrap() != web_info.host_port_for(443).unwrap(), 
193                "Auto-assigned ports should be different");
194        
195        println!("✅ Web service port access test passed");
196        Ok(())
197    });
198    
199    // Test 2: Database connection string generation
200    test("test_database_connection_info", |ctx| {
201        println!("🧪 Testing database connection info generation...");
202        
203        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
204            .expect("Database container info should be available");
205        
206        println!("🗄️ Database connection information:");
207        
208        // Get the auto-assigned port for PostgreSQL
209        let db_port = db_info.host_port_for(5432)
210            .expect("PostgreSQL port should be exposed");
211        
212        println!("   📍 PostgreSQL running on: localhost:{}", db_port);
213        
214        // Generate connection strings using the auto-assigned port
215        let connection_string = format!("postgresql://admin:testpass@localhost:{}/testdb", db_port);
216        let jdbc_url = format!("jdbc:postgresql://localhost:{}/testdb", db_port);
217        let docker_internal = format!("postgresql://admin:testpass@{}:5432/testdb", db_info.container_id);
218        
219        println!("   🔗 Connection strings:");
220        println!("      Standard: {}", connection_string);
221        println!("      JDBC: {}", jdbc_url);
222        println!("      Docker internal: {}", docker_internal);
223        
224        // Show how to use this in real applications
225        println!("   💡 Usage examples:");
226        println!("      - Set DATABASE_URL={}", connection_string);
227        println!("      - Use in tests: connect to localhost:{}", db_port);
228        println!("      - Container-to-container: use port 5432");
229        
230        // Verify port is valid
231        assert!(db_port > 0, "Database port should be valid");
232        println!("✅ Database connection info test passed");
233        
234        Ok(())
235    });
236    
237    // Test 3: Mixed port configuration
238    test("test_mixed_port_configuration", |ctx| {
239        println!("🧪 Testing mixed port configuration (manual + auto)...");
240        
241        let api_info = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info")
242            .expect("API container info should be available");
243        
244        println!("🔀 Mixed port configuration analysis:");
245        
246        // Manual port mapping
247        let http_port = api_info.host_port_for(80)
248            .expect("HTTP port should be mapped");
249        println!("   📌 Manual mapping - HTTP port 80 -> host port: {}", http_port);
250        assert_eq!(http_port, 8080, "Manual port should be exactly as specified");
251        
252        // Auto-assigned ports
253        let api_port = api_info.host_port_for(9090)
254            .expect("API port should be auto-assigned");
255        let metrics_port = api_info.host_port_for(9091)
256            .expect("Metrics port should be auto-assigned");
257        
258        println!("   🎲 Auto-assigned - API port 9090 -> host port: {}", api_port);
259        println!("   🎲 Auto-assigned - Metrics port 9091 -> host port: {}", metrics_port);
260        
261        // Verify auto-assigned ports are different from manual port
262        assert_ne!(api_port, 8080, "Auto-assigned port should be different from manual port");
263        assert_ne!(metrics_port, 8080, "Auto-assigned port should be different from manual port");
264        assert_ne!(api_port, metrics_port, "Auto-assigned ports should be different from each other");
265        
266        println!("   🌐 Service endpoints:");
267        println!("      Main API: http://localhost:{}/", http_port);
268        println!("      API v2: http://localhost:{}/", api_port);
269        println!("      Metrics: http://localhost:{}/metrics", metrics_port);
270        
271        // Show complete port summary
272        println!("   📋 Complete port summary: {}", api_info.ports_summary());
273        
274        println!("✅ Mixed port configuration test passed");
275        Ok(())
276    });
277    
278    // Test 4: Container info convenience methods
279    test("test_container_info_convenience_methods", |ctx| {
280        println!("🧪 Testing ContainerInfo convenience methods...");
281        
282        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
283            .expect("Web container info should be available");
284        
285        println!("🔧 Testing all ContainerInfo methods:");
286        
287        // Test primary_url()
288        if let Some(primary_url) = web_info.primary_url() {
289            println!("   ✅ primary_url(): {}", primary_url);
290            assert!(primary_url.starts_with("http://localhost:"), "Primary URL should be valid");
291        }
292        
293        // Test url_for_port()
294        if let Some(url_80) = web_info.url_for_port(80) {
295            println!("   ✅ url_for_port(80): {}", url_80);
296            assert!(url_80.contains("localhost:"), "URL should contain localhost");
297        }
298        
299        // Test host_port_for()
300        if let Some(port_80) = web_info.host_port_for(80) {
301            println!("   ✅ host_port_for(80): {}", port_80);
302            assert!(port_80 > 0, "Port should be positive");
303        }
304        
305        // Test ports_summary()
306        let summary = web_info.ports_summary();
307        println!("   ✅ ports_summary(): {}", summary);
308        assert!(summary.contains("->"), "Summary should contain port mappings");
309        
310        // Test direct field access
311        println!("   ✅ container_id: {}", web_info.container_id);
312        println!("   ✅ image: {}", web_info.image);
313        println!("   ✅ auto_cleanup: {}", web_info.auto_cleanup);
314        
315        println!("   📊 All URLs:");
316        for (i, url) in web_info.urls.iter().enumerate() {
317            println!("      {}. {}", i + 1, url);
318        }
319        
320        println!("   📊 All port mappings:");
321        for (host_port, container_port) in &web_info.port_mappings {
322            println!("      {} -> {}", host_port, container_port);
323        }
324        
325        println!("✅ Container info convenience methods test passed");
326        Ok(())
327    });
328    
329    // Test 5: Real-world usage patterns
330    test("test_real_world_usage_patterns", |ctx| {
331        println!("🧪 Testing real-world usage patterns...");
332        
333        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
334            .expect("Web container info should be available");
335        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
336            .expect("Database container info should be available");
337        
338        println!("🌍 Real-world usage examples:");
339        
340        // Pattern 1: HTTP client testing
341        if let Some(web_url) = web_info.primary_url() {
342            println!("   🌐 HTTP Client Testing:");
343            println!("      Base URL: {}", web_url);
344            println!("      GET {}/health", web_url);
345            println!("      POST {}/api/users", web_url);
346            println!("      Code: let response = reqwest::get(\"{}/health\").await?;", web_url);
347        }
348        
349        // Pattern 2: Database testing
350        if let Some(db_port) = db_info.host_port_for(5432) {
351            println!("   🗄️ Database Testing:");
352            println!("      Connection: localhost:{}", db_port);
353            println!("      Code: let conn = PgConnection::establish(\"postgresql://user:pass@localhost:{}/db\")?;", db_port);
354        }
355        
356        // Pattern 3: Environment variable setup
357        println!("   🔧 Environment Variables:");
358        if let Some(web_port) = web_info.host_port_for(80) {
359            println!("      export WEB_SERVICE_URL=http://localhost:{}", web_port);
360        }
361        if let Some(db_port) = db_info.host_port_for(5432) {
362            println!("      export DATABASE_URL=postgresql://localhost:{}/testdb", db_port);
363        }
364        
365        // Pattern 4: Docker-compose style networking
366        println!("   🐳 Container Networking:");
367        println!("      External: Use auto-assigned host ports");
368        println!("      Internal: Use original container ports");
369        println!("      Web -> DB: {}:5432 (container-to-container)", db_info.container_id);
370        
371        // Pattern 5: Health checks
372        println!("   ❤️ Health Checks:");
373        if let Some(web_url) = web_info.primary_url() {
374            println!("      Health endpoint: {}/health", web_url);
375            println!("      Ready endpoint: {}/ready", web_url);
376        }
377        
378        println!("✅ Real-world usage patterns test passed");
379        Ok(())
380    });
381    
382    println!("🚀 Running container port access tests...");
383    println!();
384    
385    // Run the tests
386    let config = TestConfig {
387        html_report: Some("container-port-access-report.html".to_string()),
388        ..Default::default()
389    };
390    
391    let exit_code = run_tests_with_config(config);
392    
393    println!();
394    if exit_code == 0 {
395        println!("🎉 All tests passed! Port access functionality is working correctly.");
396        println!("📊 Check the HTML report for detailed results.");
397        println!();
398        println!("💡 Key Takeaways:");
399        println!("   • Use auto_port() to avoid port conflicts");
400        println!("   • Access host ports with host_port_for(container_port)");
401        println!("   • Get ready-to-use URLs with url_for_port(container_port)");
402        println!("   • Use ports_summary() for human-readable port info");
403        println!("   • ContainerInfo provides complete access to all port information");
404    } else {
405        println!("❌ Some tests failed. Check the output above for details.");
406    }
407    
408    std::process::exit(exit_code);
409}
Source

pub fn ready_timeout(self, timeout: Duration) -> Self

Examples found in repository?
examples/user_specified_ports.rs (line 23)
12fn main() {
13    println!("🔧 User-Specified Ports Example");
14    println!("==============================");
15    println!();
16    
17    // Example 1: PostgreSQL on standard port 5432
18    let postgres_container = ContainerConfig::new("postgres:13-alpine")
19        .port(5432, 5432)     // Map host port 5432 to container port 5432
20        .env("POSTGRES_PASSWORD", "testpass")
21        .env("POSTGRES_DB", "testdb")
22        .name("postgres_test")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Web service on port 8080
26    let web_container = ContainerConfig::new("nginx:alpine")
27        .port(8080, 80)       // Map host port 8080 to container port 80
28        .name("nginx_test")
29        .ready_timeout(Duration::from_secs(10));
30    
31    // Example 3: Mixed configuration - some fixed, some auto
32    let api_container = ContainerConfig::new("httpd:alpine")
33        .port(3000, 80)       // Fixed port for main API
34        .auto_port(443)       // Auto-assign for HTTPS
35        .auto_port(9090)      // Auto-assign for metrics
36        .name("api_test")
37        .ready_timeout(Duration::from_secs(10));
38    
39    println!("📋 Container Configurations:");
40    println!("1. PostgreSQL: Fixed on localhost:5432 (standard PostgreSQL port)");
41    println!("2. Web Service: Fixed on localhost:8080");
42    println!("3. API Service: Fixed localhost:3000, auto-assigned for 443 and 9090");
43    println!();
44    
45    // Clone containers for hooks
46    let postgres_before = postgres_container.clone();
47    let web_before = web_container.clone();
48    let api_before = api_container.clone();
49    
50    // Start containers in before_each
51    before_each(move |ctx| {
52        println!("🚀 before_each: Starting containers with specified ports...");
53        
54        // Start PostgreSQL container
55        let postgres_info = postgres_before.start()
56            .map_err(|e| format!("Failed to start PostgreSQL container: {}", e))?;
57        ctx.set_data("postgres_container_info", postgres_info.clone());
58        
59        println!("✅ PostgreSQL started: {}", postgres_info.container_id);
60        println!("   📍 Port mappings: {}", postgres_info.ports_summary());
61        println!("   🗄️ Database URL: postgresql://postgres:testpass@localhost:5432/testdb");
62        
63        // Start web container
64        let web_info = web_before.start()
65            .map_err(|e| format!("Failed to start web container: {}", e))?;
66        ctx.set_data("web_container_info", web_info.clone());
67        
68        println!("✅ Web service started: {}", web_info.container_id);
69        println!("   📍 Port mappings: {}", web_info.ports_summary());
70        println!("   🌐 Web accessible at: http://localhost:8080");
71        
72        // Start API container
73        let api_info = api_before.start()
74            .map_err(|e| format!("Failed to start API container: {}", e))?;
75        ctx.set_data("api_container_info", api_info.clone());
76        
77        println!("✅ API service started: {}", api_info.container_id);
78        println!("   📍 Port mappings: {}", api_info.ports_summary());
79        println!("   🔗 API accessible at: http://localhost:3000");
80        if let Some(https_port) = api_info.host_port_for(443) {
81            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
82        }
83        if let Some(metrics_port) = api_info.host_port_for(9090) {
84            println!("   📊 Metrics accessible at: http://localhost:{}/metrics", metrics_port);
85        }
86        
87        Ok(())
88    });
89    
90    // Cleanup containers in after_each
91    let postgres_after = postgres_container.clone();
92    let web_after = web_container.clone();
93    let api_after = api_container.clone();
94    
95    after_each(move |ctx| {
96        println!("🧹 after_each: Cleaning up containers...");
97        
98        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
99            let _ = postgres_after.stop(&postgres_info.container_id);
100            println!("🛑 Stopped PostgreSQL container");
101        }
102        
103        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
104            let _ = web_after.stop(&web_info.container_id);
105            println!("🛑 Stopped web container");
106        }
107        
108        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
109            let _ = api_after.stop(&api_info.container_id);
110            println!("🛑 Stopped API container");
111        }
112        
113        println!("✅ All containers cleaned up!");
114        Ok(())
115    });
116    
117    // Test 1: Database connection test
118    test("test_database_connection", |ctx| {
119        println!("🧪 Testing database connection on fixed port 5432...");
120        
121        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
122            assert_eq!(postgres_info.host_port_for(5432), Some(5432));
123            assert_eq!(postgres_info.url_for_port(5432), Some("localhost:5432".to_string()));
124            println!("✅ Database is accessible on the expected port 5432");
125        } else {
126            return Err("PostgreSQL container info not found".into());
127        }
128        
129        Ok(())
130    });
131    
132    // Test 2: Web service test
133    test("test_web_service_fixed_port", |ctx| {
134        println!("🧪 Testing web service on fixed port 8080...");
135        
136        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
137            assert_eq!(web_info.host_port_for(80), Some(8080));
138            assert_eq!(web_info.url_for_port(80), Some("localhost:8080".to_string()));
139            println!("✅ Web service is accessible on the expected port 8080");
140        } else {
141            return Err("Web container info not found".into());
142        }
143        
144        Ok(())
145    });
146    
147    // Test 3: Mixed configuration test
148    test("test_mixed_port_configuration", |ctx| {
149        println!("🧪 Testing mixed port configuration (fixed + auto)...");
150        
151        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
152            // Test fixed port
153            assert_eq!(api_info.host_port_for(80), Some(3000));
154            assert_eq!(api_info.url_for_port(80), Some("localhost:3000".to_string()));
155            println!("✅ Fixed port 3000 -> 80 is working");
156            
157            // Test auto-assigned ports
158            if let Some(https_port) = api_info.host_port_for(443) {
159                assert!(https_port > 1024); // Should be a high port
160                println!("✅ Auto-assigned HTTPS port: {}", https_port);
161            }
162            
163            if let Some(metrics_port) = api_info.host_port_for(9090) {
164                assert!(metrics_port > 1024); // Should be a high port
165                println!("✅ Auto-assigned metrics port: {}", metrics_port);
166            }
167            
168            println!("✅ Mixed configuration is working correctly");
169        } else {
170            return Err("API container info not found".into());
171        }
172        
173        Ok(())
174    });
175    
176    println!("🚀 Running user-specified ports tests...");
177    
178    let config = TestConfig {
179        html_report: Some("user-specified-ports-report.html".to_string()),
180        ..Default::default()
181    };
182    
183    let exit_code = run_tests_with_config(config);
184    
185    println!();
186    println!("🎉 Tests completed!");
187    println!("📊 Check the HTML report for detailed results.");
188    println!();
189    println!("💡 Key Takeaways:");
190    println!("   • Use .port(host_port, container_port) for fixed port mappings");
191    println!("   • Use .auto_port(container_port) for automatic port assignment");
192    println!("   • Mix both approaches for maximum flexibility");
193    println!("   • Fixed ports are great for services with standard ports (5432, 3306, etc.)");
194    println!("   • Auto-ports prevent conflicts in parallel test environments");
195    
196    std::process::exit(exit_code);
197}
More examples
Hide additional examples
examples/mongodb_integration.rs (line 79)
68fn main() {
69    println!("🐳 MongoDB Integration Example with Container Hooks");
70    println!("==================================================");
71    println!();
72    
73    // Define container configuration with auto-port for MongoDB
74    let mongo_container = ContainerConfig::new("mongo:5.0")
75        .auto_port(27017) // Automatically assign available host port for MongoDB
76        .env("MONGO_INITDB_ROOT_USERNAME", "admin")
77        .env("MONGO_INITDB_ROOT_PASSWORD", "password")
78        .name("test_mongodb")
79        .ready_timeout(Duration::from_secs(30));
80    
81    println!("📋 Container Configuration:");
82    println!("  Image: {}", mongo_container.image);
83    println!("  Auto-ports: {:?}", mongo_container.auto_ports);
84    println!("  Environment: {:?}", mongo_container.env);
85    println!("  Name: {:?}", mongo_container.name);
86    println!("  Ready Timeout: {:?}", mongo_container.ready_timeout);
87    println!("  Auto-cleanup: {}", mongo_container.auto_cleanup);
88    println!();
89    
90    // Clone for before_each hook
91    let mongo_container_before = mongo_container.clone();
92    
93    // Register before_each hook to start container
94    before_each(move |ctx| {
95        println!("🔄 before_each: Starting MongoDB container...");
96        
97        // Start the container and get ContainerInfo
98        let container_info = mongo_container_before.start()
99            .map_err(|e| format!("Failed to start container: {}", e))?;
100        
101        // Store container info in context for tests to access
102        ctx.set_data("mongo_container_info", container_info.clone());
103        
104        // Log container details including auto-assigned ports
105        println!("✅ before_each: MongoDB container {} started", container_info.container_id);
106        println!("🌐 Container exposed on: {}", container_info.ports_summary());
107        if let Some(primary_url) = container_info.primary_url() {
108            println!("🔗 Primary URL: {}", primary_url);
109        }
110        
111        Ok(())
112    });
113    
114    // Register after_each hook to stop container
115    let mongo_container_after = mongo_container.clone();
116    rust_test_harness::after_each(move |ctx| {
117        println!("🔄 after_each: Stopping MongoDB container...");
118        
119        // Get container info from context
120        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
121            .expect("Container info should be available");
122        
123        // Stop the container
124        mongo_container_after.stop(&container_info.container_id)
125            .map_err(|e| format!("Failed to stop container: {}", e))?;
126        
127        println!("✅ after_each: MongoDB container {} stopped", container_info.container_id);
128        Ok(())
129    });
130    
131    // Test 1: Basic MongoDB operations
132    test("test_mongodb_basic_operations", |ctx| {
133        println!("🧪 Running test: test_mongodb_basic_operations");
134        
135        // Get container info from context
136        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
137            .expect("Container info should be available");
138        
139        // Show how to access port information
140        println!("🌐 Container {} is running on:", container_info.container_id);
141        println!("   Ports: {}", container_info.ports_summary());
142        if let Some(primary_url) = container_info.primary_url() {
143            println!("   Primary URL: {}", primary_url);
144        }
145        
146        // Get the MongoDB port (27017) and show the actual host port
147        if let Some(host_port) = container_info.host_port_for(27017) {
148            println!("   MongoDB accessible at: localhost:{}", host_port);
149        }
150        
151        // Create MongoDB client
152        let mut client = MongoClient::new(container_info.container_id.clone());
153        
154        // Connect to MongoDB
155        client.connect()?;
156        
157        // Insert a document
158        client.insert_document("users", r#"{"name": "John Doe", "email": "john@example.com"}"#)?;
159        
160        // Find documents
161        let documents = client.find_documents("users", r#"{"name": "John Doe"}"#)?;
162        assert_eq!(documents.len(), 2);
163        
164        // Disconnect
165        client.disconnect()?;
166        
167        println!("✅ test_mongodb_basic_operations passed");
168        Ok(())
169    });
170    
171    // Test 2: Multiple operations
172    test("test_mongodb_multiple_operations", |ctx| {
173        println!("🧪 Running test: test_mongodb_multiple_operations");
174        
175        // Get container info from context
176        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
177            .expect("Container info should be available");
178        
179        // Show container status
180        println!("🌐 Container {} status:", container_info.container_id);
181        println!("   Active ports: {}", container_info.ports_summary());
182        
183        // Create MongoDB client
184        let mut client = MongoClient::new(container_info.container_id.clone());
185        
186        // Connect to MongoDB
187        client.connect()?;
188        
189        // Insert multiple documents
190        client.insert_document("products", r#"{"name": "Laptop", "price": 999.99}"#)?;
191        client.insert_document("products", r#"{"name": "Mouse", "price": 29.99}"#)?;
192        client.insert_document("products", r#"{"name": "Keyboard", "price": 79.99}"#)?;
193        
194        // Find documents
195        let documents = client.find_documents("products", r#"{"price": {"$gt": 50}}"#)?;
196        assert_eq!(documents.len(), 2); // Laptop and Keyboard
197        
198        // Disconnect
199        client.disconnect()?;
200        
201        println!("✅ test_mongodb_multiple_operations passed");
202        Ok(())
203    });
204    
205    // Test 3: Error handling
206    test("test_mongodb_error_handling", |ctx| {
207        println!("🧪 Running test: test_mongodb_error_handling");
208        
209        // Get container ID from context
210        let container_id = ctx.get_data::<String>("mongo_container_id")
211            .expect("Container ID should be available")
212            .to_string();
213        
214        // Create MongoDB client
215        let client = MongoClient::new(container_id);
216        
217        // Try to insert without connecting (should fail)
218        let result = client.insert_document("users", r#"{"name": "Test"}"#);
219        assert!(result.is_err());
220        assert_eq!(result.unwrap_err(), "Not connected to MongoDB");
221        
222        println!("✅ test_mongodb_error_handling passed");
223        Ok(())
224    });
225    
226    // Test 4: Performance testing
227    test("test_mongodb_performance", |ctx| {
228        println!("🧪 Running test: test_mongodb_performance");
229        
230        // Get container ID from context
231        let container_id = ctx.get_data::<String>("mongo_container_id")
232            .expect("Container ID should be available")
233            .to_string();
234        
235        // Create MongoDB client
236        let mut client = MongoClient::new(container_id);
237        
238        // Connect to MongoDB
239        client.connect()?;
240        
241        // Simulate bulk operations
242        for i in 0..100 {
243            client.insert_document("bulk_data", &format!(r#"{{"index": {}, "data": "bulk_item_{}"}}"#, i, i))?;
244        }
245        
246        // Simulate bulk retrieval
247        let documents = client.find_documents("bulk_data", r#"{"index": {"$lt": 50}}"#)?;
248        assert_eq!(documents.len(), 2); // Mock always returns 2
249        
250        // Disconnect
251        client.disconnect()?;
252        
253        println!("✅ test_mongodb_performance passed");
254        Ok(())
255    });
256    
257    println!("\n🚀 Running MongoDB integration tests...");
258    println!("   Each test will get a fresh MongoDB container via before_each");
259    println!("   Each test will clean up its container via after_each");
260    println!();
261    
262    // Run tests with container hooks enabled
263    let config = TestConfig {
264        skip_hooks: Some(false),
265        ..Default::default()
266    };
267    
268    let result = run_tests_with_config(config);
269    
270    println!("\n📊 Test Results:");
271    if result == 0 {
272        println!("✅ All MongoDB integration tests passed!");
273        println!("🎯 Container lifecycle management working correctly");
274        println!("🐳 Each test got its own MongoDB container");
275        println!("🧹 Each test cleaned up its container properly");
276    } else {
277        println!("❌ Some tests failed");
278    }
279    
280    println!("\n💡 Key Benefits of this approach:");
281    println!("   • Clean separation of concerns");
282    println!("   • Each test gets a fresh container");
283    println!("   • Automatic cleanup via after_each");
284    println!("   • Easy to configure containers");
285    println!("   • No complex global state management");
286}
examples/auto_port_demo.rs (line 22)
12fn main() {
13    println!("🚀 Auto-Port and Container Management Demo");
14    println!("==========================================");
15    println!();
16    
17    // Example 1: Web service with auto-port
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80) // Automatically assign host port for container port 80
20        .env("NGINX_HOST", "localhost")
21        .name("web_service")
22        .ready_timeout(Duration::from_secs(15));
23    
24    // Example 2: Database with auto-port
25    let db_container = ContainerConfig::new("postgres:13-alpine")
26        .auto_port(5432) // Automatically assign host port for container port 5432
27        .env("POSTGRES_PASSWORD", "testpass")
28        .env("POSTGRES_DB", "testdb")
29        .name("test_database")
30        .ready_timeout(Duration::from_secs(20));
31    
32    // Example 3: Redis with auto-port
33    let redis_container = ContainerConfig::new("redis:6-alpine")
34        .auto_port(6379) // Automatically assign host port for container port 6379
35        .name("test_redis")
36        .ready_timeout(Duration::from_secs(10));
37    
38    // Example 4: Mixed configuration (manual + auto ports)
39    let mixed_container = ContainerConfig::new("httpd:alpine")
40        .port(8080, 80) // Manual port mapping
41        .auto_port(443) // Auto port for HTTPS
42        .env("APACHE_DOCUMENT_ROOT", "/var/www/html")
43        .name("mixed_ports")
44        .ready_timeout(Duration::from_secs(15));
45    
46    println!("📋 Container Configurations:");
47    println!("1. Web Service (nginx):");
48    println!("   - Image: {}", web_container.image);
49    println!("   - Auto-ports: {:?}", web_container.auto_ports);
50    println!("   - Auto-cleanup: {}", web_container.auto_cleanup);
51    
52    println!("2. Database (postgres):");
53    println!("   - Image: {}", db_container.image);
54    println!("   - Auto-ports: {:?}", db_container.auto_ports);
55    println!("   - Auto-cleanup: {}", db_container.auto_cleanup);
56    
57    println!("3. Cache (redis):");
58    println!("   - Image: {}", redis_container.image);
59    println!("   - Auto-ports: {:?}", redis_container.auto_ports);
60    println!("   - Auto-cleanup: {}", redis_container.auto_cleanup);
61    
62    println!("4. Mixed (httpd):");
63    println!("   - Image: {}", mixed_container.image);
64    println!("   - Manual ports: {:?}", mixed_container.ports);
65    println!("   - Auto-ports: {:?}", mixed_container.auto_ports);
66    println!("   - Auto-cleanup: {}", mixed_container.auto_cleanup);
67    println!();
68    
69    // Clone containers for hooks
70    let web_before = web_container.clone();
71    let db_before = db_container.clone();
72    let redis_before = redis_container.clone();
73    let mixed_before = mixed_container.clone();
74    
75    // Start all containers in before_each for each test
76    before_each(move |ctx| {
77        println!("🚀 before_each: Starting all containers...");
78        
79        // Start web container
80        let web_info = web_before.start()
81            .map_err(|e| format!("Failed to start web container: {}", e))?;
82        ctx.set_data("web_container_info", web_info.clone());
83        println!("✅ Web container started: {}", web_info.container_id);
84        println!("   Ports: {}", web_info.ports_summary());
85        if let Some(url) = web_info.primary_url() {
86            println!("   URL: {}", url);
87        }
88        
89        // Start database container
90        let db_info = db_before.start()
91            .map_err(|e| format!("Failed to start db container: {}", e))?;
92        ctx.set_data("db_container_info", db_info.clone());
93        println!("✅ Database container started: {}", db_info.container_id);
94        println!("   Ports: {}", db_info.ports_summary());
95        if let Some(host_port) = db_info.host_port_for(5432) {
96            println!("   PostgreSQL accessible at: localhost:{}", host_port);
97        }
98        
99        // Start redis container
100        let redis_info = redis_before.start()
101            .map_err(|e| format!("Failed to start redis container: {}", e))?;
102        ctx.set_data("redis_container_info", redis_info.clone());
103        println!("✅ Redis container started: {}", redis_info.container_id);
104        println!("   Ports: {}", redis_info.ports_summary());
105        if let Some(host_port) = redis_info.host_port_for(6379) {
106            println!("   Redis accessible at: localhost:{}", host_port);
107        }
108        
109        // Start mixed container
110        let mixed_info = mixed_before.start()
111            .map_err(|e| format!("Failed to start mixed container: {}", e))?;
112        ctx.set_data("mixed_container_info", mixed_info.clone());
113        println!("✅ Mixed container started: {}", mixed_info.container_id);
114        println!("   Ports: {}", mixed_info.ports_summary());
115        if let Some(host_port) = mixed_info.host_port_for(443) {
116            println!("   HTTPS accessible at: localhost:{}", host_port);
117        }
118        
119        println!("🎉 All containers started successfully!");
120        Ok(())
121    });
122    
123    // Cleanup all containers in after_each for each test
124    let web_after = web_container.clone();
125    let db_after = db_container.clone();
126    let redis_after = redis_container.clone();
127    let mixed_after = mixed_container.clone();
128    
129    after_each(move |ctx| {
130        println!("🧹 after_each: Cleaning up all containers...");
131        
132        // Get all container info and stop them
133        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
134            let _ = web_after.stop(&web_info.container_id);
135            println!("🛑 Stopped web container: {}", web_info.container_id);
136        }
137        
138        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
139            let _ = db_after.stop(&db_info.container_id);
140            println!("🛑 Stopped database container: {}", db_info.container_id);
141        }
142        
143        if let Some(redis_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info") {
144            let _ = redis_after.stop(&redis_info.container_id);
145            println!("🛑 Stopped redis container: {}", redis_info.container_id);
146        }
147        
148        if let Some(mixed_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info") {
149            let _ = mixed_after.stop(&mixed_info.container_id);
150            println!("🛑 Stopped mixed container: {}", mixed_info.container_id);
151        }
152        
153        println!("✅ All containers cleaned up!");
154        Ok(())
155    });
156    
157    // Test 1: Access web service
158    test("test_web_service_access", |ctx| {
159        println!("🧪 Testing web service access...");
160        
161        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
162            .expect("Web container info should be available");
163        
164        println!("🌐 Web service container: {}", web_info.container_id);
165        println!("   Ports: {}", web_info.ports_summary());
166        println!("   Primary URL: {}", web_info.primary_url().unwrap_or("None"));
167        
168        // In a real test, you would make HTTP requests to the container
169        // For demo purposes, just verify the port information
170        assert!(web_info.host_port_for(80).is_some(), "Web service should have port 80 exposed");
171        
172        println!("✅ Web service test passed");
173        Ok(())
174    });
175    
176    // Test 2: Access database
177    test("test_database_access", |ctx| {
178        println!("🧪 Testing database access...");
179        
180        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
181            .expect("Database container info should be available");
182        
183        println!("🗄️ Database container: {}", db_info.container_id);
184        println!("   Ports: {}", db_info.ports_summary());
185        
186        // Verify PostgreSQL port is exposed
187        let postgres_port = db_info.host_port_for(5432)
188            .expect("PostgreSQL port 5432 should be exposed");
189        println!("   PostgreSQL accessible at: localhost:{}", postgres_port);
190        
191        // In a real test, you would connect to the database
192        // For demo purposes, just verify the port information
193        assert!(postgres_port > 0, "PostgreSQL port should be valid");
194        
195        println!("✅ Database test passed");
196        Ok(())
197    });
198    
199    // Test 3: Access redis
200    test("test_redis_access", |ctx| {
201        println!("🧪 Testing redis access...");
202        
203        let redis_info = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info")
204            .expect("Redis container info should be available");
205        
206        println!("🔴 Redis container: {}", redis_info.container_id);
207        println!("   Ports: {}", redis_info.ports_summary());
208        
209        // Verify Redis port is exposed
210        let redis_port = redis_info.host_port_for(6379)
211            .expect("Redis port 6379 should be exposed");
212        println!("   Redis accessible at: localhost:{}", redis_port);
213        
214        // In a real test, you would connect to Redis
215        // For demo purposes, just verify the port information
216        assert!(redis_port > 0, "Redis port should be valid");
217        
218        println!("✅ Redis test passed");
219        Ok(())
220    });
221    
222    // Test 4: Mixed port configuration
223    test("test_mixed_port_config", |ctx| {
224        println!("🧪 Testing mixed port configuration...");
225        
226        let mixed_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info")
227            .expect("Mixed container info should be available");
228        
229        println!("🔀 Mixed container: {}", mixed_info.container_id);
230        println!("   Ports: {}", mixed_info.ports_summary());
231        
232        // Verify both manual and auto ports
233        let http_port = mixed_info.host_port_for(80)
234            .expect("HTTP port 80 should be exposed");
235        let https_port = mixed_info.host_port_for(443)
236            .expect("HTTPS port 443 should be exposed");
237        
238        println!("   HTTP accessible at: localhost:{}", http_port);
239        println!("   HTTPS accessible at: localhost:{}", https_port);
240        
241        // Verify the manual port mapping (8080 -> 80)
242        assert_eq!(http_port, 8080, "Manual port mapping should work");
243        
244        // Verify auto port is different from manual port
245        assert_ne!(https_port, 8080, "Auto port should be different from manual port");
246        
247        println!("✅ Mixed port configuration test passed");
248        Ok(())
249    });
250    
251    // Test 5: Container info methods
252    test("test_container_info_methods", |ctx| {
253        println!("🧪 Testing container info methods...");
254        
255        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
256            .expect("Web container info should be available");
257        
258        // Test all the convenience methods
259        println!("🔍 Testing container info methods for: {}", web_info.container_id);
260        
261        // Test primary_url
262        if let Some(url) = web_info.primary_url() {
263            println!("   Primary URL: {}", url);
264            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
265        }
266        
267        // Test url_for_port
268        if let Some(url) = web_info.url_for_port(80) {
269            println!("   URL for port 80: {}", url);
270            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
271        }
272        
273        // Test host_port_for
274        if let Some(host_port) = web_info.host_port_for(80) {
275            println!("   Host port for container port 80: {}", host_port);
276            assert!(host_port > 0, "Host port should be valid");
277        }
278        
279        // Test ports_summary
280        let summary = web_info.ports_summary();
281        println!("   Ports summary: {}", summary);
282        assert!(!summary.is_empty(), "Ports summary should not be empty");
283        
284        println!("✅ Container info methods test passed");
285        Ok(())
286    });
287    
288    println!("🚀 Running tests with auto-port functionality...");
289    println!();
290    
291    // Run the tests
292    let config = TestConfig {
293        html_report: Some("auto-port-demo-report.html".to_string()),
294        ..Default::default()
295    };
296    
297    let exit_code = run_tests_with_config(config);
298    
299    println!();
300    if exit_code == 0 {
301        println!("🎉 All tests passed! Auto-port functionality is working correctly.");
302        println!("📊 Check the HTML report for detailed results.");
303    } else {
304        println!("❌ Some tests failed. Check the output above for details.");
305    }
306    
307    std::process::exit(exit_code);
308}
examples/container_port_access.rs (line 23)
12fn main() {
13    println!("🌐 Container Port and URL Access Example");
14    println!("========================================");
15    println!();
16    
17    // Example 1: Web service with multiple auto-ports
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80)      // Auto-assign port for HTTP
20        .auto_port(443)     // Auto-assign port for HTTPS
21        .env("NGINX_HOST", "localhost")
22        .name("web_service")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Database with auto-port
26    let db_container = ContainerConfig::new("postgres:13-alpine")
27        .auto_port(5432)    // Auto-assign port for PostgreSQL
28        .env("POSTGRES_PASSWORD", "testpass")
29        .env("POSTGRES_DB", "testdb")
30        .name("test_database")
31        .ready_timeout(Duration::from_secs(20));
32    
33    // Example 3: Mixed configuration (manual + auto ports)
34    let api_container = ContainerConfig::new("httpd:alpine")
35        .port(8080, 80)     // Manual port mapping
36        .auto_port(9090)    // Auto-assign port for API
37        .auto_port(9091)    // Auto-assign port for metrics
38        .env("API_VERSION", "v1")
39        .name("api_service")
40        .ready_timeout(Duration::from_secs(15));
41    
42    println!("📋 Container Configurations:");
43    println!("1. Web Service:");
44    println!("   - Image: {}", web_container.image);
45    println!("   - Auto-ports: {:?}", web_container.auto_ports);
46    println!("   - Will auto-assign host ports for container ports 80 and 443");
47    
48    println!("2. Database:");
49    println!("   - Image: {}", db_container.image);
50    println!("   - Auto-ports: {:?}", db_container.auto_ports);
51    println!("   - Will auto-assign host port for container port 5432");
52    
53    println!("3. API Service:");
54    println!("   - Image: {}", api_container.image);
55    println!("   - Manual ports: {:?}", api_container.ports);
56    println!("   - Auto-ports: {:?}", api_container.auto_ports);
57    println!("   - Manual mapping: 8080 -> 80, Auto-assign: 9090, 9091");
58    println!();
59    
60    // Clone containers for hooks
61    let web_before = web_container.clone();
62    let db_before = db_container.clone();
63    let api_before = api_container.clone();
64    
65    // Start containers in before_each
66    before_each(move |ctx| {
67        println!("🚀 before_each: Starting containers and capturing port info...");
68        
69        // Start web container
70        let web_info = web_before.start()
71            .map_err(|e| format!("Failed to start web container: {}", e))?;
72        ctx.set_data("web_container_info", web_info.clone());
73        
74        println!("✅ Web container started: {}", web_info.container_id);
75        println!("   📍 Port mappings: {}", web_info.ports_summary());
76        println!("   🔗 Primary URL: {}", web_info.primary_url().unwrap_or("None"));
77        
78        // Show specific port access
79        if let Some(http_port) = web_info.host_port_for(80) {
80            println!("   🌐 HTTP accessible at: http://localhost:{}", http_port);
81        }
82        if let Some(https_port) = web_info.host_port_for(443) {
83            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
84        }
85        
86        // Start database container
87        let db_info = db_before.start()
88            .map_err(|e| format!("Failed to start db container: {}", e))?;
89        ctx.set_data("db_container_info", db_info.clone());
90        
91        println!("✅ Database container started: {}", db_info.container_id);
92        println!("   📍 Port mappings: {}", db_info.ports_summary());
93        if let Some(db_port) = db_info.host_port_for(5432) {
94            println!("   🗄️ PostgreSQL accessible at: localhost:{}", db_port);
95            println!("   📝 Connection string: postgresql://user:pass@localhost:{}/testdb", db_port);
96        }
97        
98        // Start API container
99        let api_info = api_before.start()
100            .map_err(|e| format!("Failed to start api container: {}", e))?;
101        ctx.set_data("api_container_info", api_info.clone());
102        
103        println!("✅ API container started: {}", api_info.container_id);
104        println!("   📍 Port mappings: {}", api_info.ports_summary());
105        
106        // Show both manual and auto ports
107        if let Some(http_port) = api_info.host_port_for(80) {
108            println!("   🌐 HTTP API at: http://localhost:{} (manual mapping)", http_port);
109        }
110        if let Some(api_port) = api_info.host_port_for(9090) {
111            println!("   🔧 API endpoint at: http://localhost:{} (auto-assigned)", api_port);
112        }
113        if let Some(metrics_port) = api_info.host_port_for(9091) {
114            println!("   📊 Metrics at: http://localhost:{} (auto-assigned)", metrics_port);
115        }
116        
117        println!("🎉 All containers started with auto-assigned ports!");
118        Ok(())
119    });
120    
121    // Cleanup containers in after_each
122    let web_after = web_container.clone();
123    let db_after = db_container.clone();
124    let api_after = api_container.clone();
125    
126    after_each(move |ctx| {
127        println!("🧹 after_each: Cleaning up containers...");
128        
129        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
130            let _ = web_after.stop(&web_info.container_id);
131            println!("🛑 Stopped web container: {}", web_info.container_id);
132        }
133        
134        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
135            let _ = db_after.stop(&db_info.container_id);
136            println!("🛑 Stopped database container: {}", db_info.container_id);
137        }
138        
139        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
140            let _ = api_after.stop(&api_info.container_id);
141            println!("🛑 Stopped API container: {}", api_info.container_id);
142        }
143        
144        println!("✅ All containers cleaned up!");
145        Ok(())
146    });
147    
148    // Test 1: Web service port access
149    test("test_web_service_port_access", |ctx| {
150        println!("🧪 Testing web service port access...");
151        
152        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
153            .expect("Web container info should be available");
154        
155        println!("🔍 Demonstrating port access methods:");
156        
157        // Method 1: Get specific host port for container port
158        if let Some(http_port) = web_info.host_port_for(80) {
159            println!("   ✅ HTTP port 80 is mapped to host port: {}", http_port);
160            println!("      💡 Use this for HTTP client connections");
161        }
162        
163        if let Some(https_port) = web_info.host_port_for(443) {
164            println!("   ✅ HTTPS port 443 is mapped to host port: {}", https_port);
165            println!("      💡 Use this for HTTPS client connections");
166        }
167        
168        // Method 2: Get ready-to-use URLs
169        if let Some(http_url) = web_info.url_for_port(80) {
170            println!("   🔗 HTTP URL: {}", http_url);
171            println!("      💡 Ready to use in HTTP requests");
172        }
173        
174        if let Some(https_url) = web_info.url_for_port(443) {
175            println!("   🔗 HTTPS URL: {}", https_url);
176            println!("      💡 Ready to use in HTTPS requests (change http:// to https://)");
177        }
178        
179        // Method 3: Get all URLs
180        println!("   📋 All service URLs:");
181        for (i, url) in web_info.urls.iter().enumerate() {
182            println!("      {}. {}", i + 1, url);
183        }
184        
185        // Method 4: Get all port mappings
186        println!("   📊 All port mappings:");
187        for (host_port, container_port) in &web_info.port_mappings {
188            println!("      Host {} -> Container {}", host_port, container_port);
189        }
190        
191        // Verify ports are different (auto-assigned)
192        assert!(web_info.host_port_for(80).unwrap() != web_info.host_port_for(443).unwrap(), 
193                "Auto-assigned ports should be different");
194        
195        println!("✅ Web service port access test passed");
196        Ok(())
197    });
198    
199    // Test 2: Database connection string generation
200    test("test_database_connection_info", |ctx| {
201        println!("🧪 Testing database connection info generation...");
202        
203        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
204            .expect("Database container info should be available");
205        
206        println!("🗄️ Database connection information:");
207        
208        // Get the auto-assigned port for PostgreSQL
209        let db_port = db_info.host_port_for(5432)
210            .expect("PostgreSQL port should be exposed");
211        
212        println!("   📍 PostgreSQL running on: localhost:{}", db_port);
213        
214        // Generate connection strings using the auto-assigned port
215        let connection_string = format!("postgresql://admin:testpass@localhost:{}/testdb", db_port);
216        let jdbc_url = format!("jdbc:postgresql://localhost:{}/testdb", db_port);
217        let docker_internal = format!("postgresql://admin:testpass@{}:5432/testdb", db_info.container_id);
218        
219        println!("   🔗 Connection strings:");
220        println!("      Standard: {}", connection_string);
221        println!("      JDBC: {}", jdbc_url);
222        println!("      Docker internal: {}", docker_internal);
223        
224        // Show how to use this in real applications
225        println!("   💡 Usage examples:");
226        println!("      - Set DATABASE_URL={}", connection_string);
227        println!("      - Use in tests: connect to localhost:{}", db_port);
228        println!("      - Container-to-container: use port 5432");
229        
230        // Verify port is valid
231        assert!(db_port > 0, "Database port should be valid");
232        println!("✅ Database connection info test passed");
233        
234        Ok(())
235    });
236    
237    // Test 3: Mixed port configuration
238    test("test_mixed_port_configuration", |ctx| {
239        println!("🧪 Testing mixed port configuration (manual + auto)...");
240        
241        let api_info = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info")
242            .expect("API container info should be available");
243        
244        println!("🔀 Mixed port configuration analysis:");
245        
246        // Manual port mapping
247        let http_port = api_info.host_port_for(80)
248            .expect("HTTP port should be mapped");
249        println!("   📌 Manual mapping - HTTP port 80 -> host port: {}", http_port);
250        assert_eq!(http_port, 8080, "Manual port should be exactly as specified");
251        
252        // Auto-assigned ports
253        let api_port = api_info.host_port_for(9090)
254            .expect("API port should be auto-assigned");
255        let metrics_port = api_info.host_port_for(9091)
256            .expect("Metrics port should be auto-assigned");
257        
258        println!("   🎲 Auto-assigned - API port 9090 -> host port: {}", api_port);
259        println!("   🎲 Auto-assigned - Metrics port 9091 -> host port: {}", metrics_port);
260        
261        // Verify auto-assigned ports are different from manual port
262        assert_ne!(api_port, 8080, "Auto-assigned port should be different from manual port");
263        assert_ne!(metrics_port, 8080, "Auto-assigned port should be different from manual port");
264        assert_ne!(api_port, metrics_port, "Auto-assigned ports should be different from each other");
265        
266        println!("   🌐 Service endpoints:");
267        println!("      Main API: http://localhost:{}/", http_port);
268        println!("      API v2: http://localhost:{}/", api_port);
269        println!("      Metrics: http://localhost:{}/metrics", metrics_port);
270        
271        // Show complete port summary
272        println!("   📋 Complete port summary: {}", api_info.ports_summary());
273        
274        println!("✅ Mixed port configuration test passed");
275        Ok(())
276    });
277    
278    // Test 4: Container info convenience methods
279    test("test_container_info_convenience_methods", |ctx| {
280        println!("🧪 Testing ContainerInfo convenience methods...");
281        
282        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
283            .expect("Web container info should be available");
284        
285        println!("🔧 Testing all ContainerInfo methods:");
286        
287        // Test primary_url()
288        if let Some(primary_url) = web_info.primary_url() {
289            println!("   ✅ primary_url(): {}", primary_url);
290            assert!(primary_url.starts_with("http://localhost:"), "Primary URL should be valid");
291        }
292        
293        // Test url_for_port()
294        if let Some(url_80) = web_info.url_for_port(80) {
295            println!("   ✅ url_for_port(80): {}", url_80);
296            assert!(url_80.contains("localhost:"), "URL should contain localhost");
297        }
298        
299        // Test host_port_for()
300        if let Some(port_80) = web_info.host_port_for(80) {
301            println!("   ✅ host_port_for(80): {}", port_80);
302            assert!(port_80 > 0, "Port should be positive");
303        }
304        
305        // Test ports_summary()
306        let summary = web_info.ports_summary();
307        println!("   ✅ ports_summary(): {}", summary);
308        assert!(summary.contains("->"), "Summary should contain port mappings");
309        
310        // Test direct field access
311        println!("   ✅ container_id: {}", web_info.container_id);
312        println!("   ✅ image: {}", web_info.image);
313        println!("   ✅ auto_cleanup: {}", web_info.auto_cleanup);
314        
315        println!("   📊 All URLs:");
316        for (i, url) in web_info.urls.iter().enumerate() {
317            println!("      {}. {}", i + 1, url);
318        }
319        
320        println!("   📊 All port mappings:");
321        for (host_port, container_port) in &web_info.port_mappings {
322            println!("      {} -> {}", host_port, container_port);
323        }
324        
325        println!("✅ Container info convenience methods test passed");
326        Ok(())
327    });
328    
329    // Test 5: Real-world usage patterns
330    test("test_real_world_usage_patterns", |ctx| {
331        println!("🧪 Testing real-world usage patterns...");
332        
333        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
334            .expect("Web container info should be available");
335        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
336            .expect("Database container info should be available");
337        
338        println!("🌍 Real-world usage examples:");
339        
340        // Pattern 1: HTTP client testing
341        if let Some(web_url) = web_info.primary_url() {
342            println!("   🌐 HTTP Client Testing:");
343            println!("      Base URL: {}", web_url);
344            println!("      GET {}/health", web_url);
345            println!("      POST {}/api/users", web_url);
346            println!("      Code: let response = reqwest::get(\"{}/health\").await?;", web_url);
347        }
348        
349        // Pattern 2: Database testing
350        if let Some(db_port) = db_info.host_port_for(5432) {
351            println!("   🗄️ Database Testing:");
352            println!("      Connection: localhost:{}", db_port);
353            println!("      Code: let conn = PgConnection::establish(\"postgresql://user:pass@localhost:{}/db\")?;", db_port);
354        }
355        
356        // Pattern 3: Environment variable setup
357        println!("   🔧 Environment Variables:");
358        if let Some(web_port) = web_info.host_port_for(80) {
359            println!("      export WEB_SERVICE_URL=http://localhost:{}", web_port);
360        }
361        if let Some(db_port) = db_info.host_port_for(5432) {
362            println!("      export DATABASE_URL=postgresql://localhost:{}/testdb", db_port);
363        }
364        
365        // Pattern 4: Docker-compose style networking
366        println!("   🐳 Container Networking:");
367        println!("      External: Use auto-assigned host ports");
368        println!("      Internal: Use original container ports");
369        println!("      Web -> DB: {}:5432 (container-to-container)", db_info.container_id);
370        
371        // Pattern 5: Health checks
372        println!("   ❤️ Health Checks:");
373        if let Some(web_url) = web_info.primary_url() {
374            println!("      Health endpoint: {}/health", web_url);
375            println!("      Ready endpoint: {}/ready", web_url);
376        }
377        
378        println!("✅ Real-world usage patterns test passed");
379        Ok(())
380    });
381    
382    println!("🚀 Running container port access tests...");
383    println!();
384    
385    // Run the tests
386    let config = TestConfig {
387        html_report: Some("container-port-access-report.html".to_string()),
388        ..Default::default()
389    };
390    
391    let exit_code = run_tests_with_config(config);
392    
393    println!();
394    if exit_code == 0 {
395        println!("🎉 All tests passed! Port access functionality is working correctly.");
396        println!("📊 Check the HTML report for detailed results.");
397        println!();
398        println!("💡 Key Takeaways:");
399        println!("   • Use auto_port() to avoid port conflicts");
400        println!("   • Access host ports with host_port_for(container_port)");
401        println!("   • Get ready-to-use URLs with url_for_port(container_port)");
402        println!("   • Use ports_summary() for human-readable port info");
403        println!("   • ContainerInfo provides complete access to all port information");
404    } else {
405        println!("❌ Some tests failed. Check the output above for details.");
406    }
407    
408    std::process::exit(exit_code);
409}
Source

pub fn auto_port(self, container_port: u16) -> Self

Add a port that should be automatically assigned an available host port

Examples found in repository?
examples/user_specified_ports.rs (line 34)
12fn main() {
13    println!("🔧 User-Specified Ports Example");
14    println!("==============================");
15    println!();
16    
17    // Example 1: PostgreSQL on standard port 5432
18    let postgres_container = ContainerConfig::new("postgres:13-alpine")
19        .port(5432, 5432)     // Map host port 5432 to container port 5432
20        .env("POSTGRES_PASSWORD", "testpass")
21        .env("POSTGRES_DB", "testdb")
22        .name("postgres_test")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Web service on port 8080
26    let web_container = ContainerConfig::new("nginx:alpine")
27        .port(8080, 80)       // Map host port 8080 to container port 80
28        .name("nginx_test")
29        .ready_timeout(Duration::from_secs(10));
30    
31    // Example 3: Mixed configuration - some fixed, some auto
32    let api_container = ContainerConfig::new("httpd:alpine")
33        .port(3000, 80)       // Fixed port for main API
34        .auto_port(443)       // Auto-assign for HTTPS
35        .auto_port(9090)      // Auto-assign for metrics
36        .name("api_test")
37        .ready_timeout(Duration::from_secs(10));
38    
39    println!("📋 Container Configurations:");
40    println!("1. PostgreSQL: Fixed on localhost:5432 (standard PostgreSQL port)");
41    println!("2. Web Service: Fixed on localhost:8080");
42    println!("3. API Service: Fixed localhost:3000, auto-assigned for 443 and 9090");
43    println!();
44    
45    // Clone containers for hooks
46    let postgres_before = postgres_container.clone();
47    let web_before = web_container.clone();
48    let api_before = api_container.clone();
49    
50    // Start containers in before_each
51    before_each(move |ctx| {
52        println!("🚀 before_each: Starting containers with specified ports...");
53        
54        // Start PostgreSQL container
55        let postgres_info = postgres_before.start()
56            .map_err(|e| format!("Failed to start PostgreSQL container: {}", e))?;
57        ctx.set_data("postgres_container_info", postgres_info.clone());
58        
59        println!("✅ PostgreSQL started: {}", postgres_info.container_id);
60        println!("   📍 Port mappings: {}", postgres_info.ports_summary());
61        println!("   🗄️ Database URL: postgresql://postgres:testpass@localhost:5432/testdb");
62        
63        // Start web container
64        let web_info = web_before.start()
65            .map_err(|e| format!("Failed to start web container: {}", e))?;
66        ctx.set_data("web_container_info", web_info.clone());
67        
68        println!("✅ Web service started: {}", web_info.container_id);
69        println!("   📍 Port mappings: {}", web_info.ports_summary());
70        println!("   🌐 Web accessible at: http://localhost:8080");
71        
72        // Start API container
73        let api_info = api_before.start()
74            .map_err(|e| format!("Failed to start API container: {}", e))?;
75        ctx.set_data("api_container_info", api_info.clone());
76        
77        println!("✅ API service started: {}", api_info.container_id);
78        println!("   📍 Port mappings: {}", api_info.ports_summary());
79        println!("   🔗 API accessible at: http://localhost:3000");
80        if let Some(https_port) = api_info.host_port_for(443) {
81            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
82        }
83        if let Some(metrics_port) = api_info.host_port_for(9090) {
84            println!("   📊 Metrics accessible at: http://localhost:{}/metrics", metrics_port);
85        }
86        
87        Ok(())
88    });
89    
90    // Cleanup containers in after_each
91    let postgres_after = postgres_container.clone();
92    let web_after = web_container.clone();
93    let api_after = api_container.clone();
94    
95    after_each(move |ctx| {
96        println!("🧹 after_each: Cleaning up containers...");
97        
98        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
99            let _ = postgres_after.stop(&postgres_info.container_id);
100            println!("🛑 Stopped PostgreSQL container");
101        }
102        
103        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
104            let _ = web_after.stop(&web_info.container_id);
105            println!("🛑 Stopped web container");
106        }
107        
108        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
109            let _ = api_after.stop(&api_info.container_id);
110            println!("🛑 Stopped API container");
111        }
112        
113        println!("✅ All containers cleaned up!");
114        Ok(())
115    });
116    
117    // Test 1: Database connection test
118    test("test_database_connection", |ctx| {
119        println!("🧪 Testing database connection on fixed port 5432...");
120        
121        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
122            assert_eq!(postgres_info.host_port_for(5432), Some(5432));
123            assert_eq!(postgres_info.url_for_port(5432), Some("localhost:5432".to_string()));
124            println!("✅ Database is accessible on the expected port 5432");
125        } else {
126            return Err("PostgreSQL container info not found".into());
127        }
128        
129        Ok(())
130    });
131    
132    // Test 2: Web service test
133    test("test_web_service_fixed_port", |ctx| {
134        println!("🧪 Testing web service on fixed port 8080...");
135        
136        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
137            assert_eq!(web_info.host_port_for(80), Some(8080));
138            assert_eq!(web_info.url_for_port(80), Some("localhost:8080".to_string()));
139            println!("✅ Web service is accessible on the expected port 8080");
140        } else {
141            return Err("Web container info not found".into());
142        }
143        
144        Ok(())
145    });
146    
147    // Test 3: Mixed configuration test
148    test("test_mixed_port_configuration", |ctx| {
149        println!("🧪 Testing mixed port configuration (fixed + auto)...");
150        
151        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
152            // Test fixed port
153            assert_eq!(api_info.host_port_for(80), Some(3000));
154            assert_eq!(api_info.url_for_port(80), Some("localhost:3000".to_string()));
155            println!("✅ Fixed port 3000 -> 80 is working");
156            
157            // Test auto-assigned ports
158            if let Some(https_port) = api_info.host_port_for(443) {
159                assert!(https_port > 1024); // Should be a high port
160                println!("✅ Auto-assigned HTTPS port: {}", https_port);
161            }
162            
163            if let Some(metrics_port) = api_info.host_port_for(9090) {
164                assert!(metrics_port > 1024); // Should be a high port
165                println!("✅ Auto-assigned metrics port: {}", metrics_port);
166            }
167            
168            println!("✅ Mixed configuration is working correctly");
169        } else {
170            return Err("API container info not found".into());
171        }
172        
173        Ok(())
174    });
175    
176    println!("🚀 Running user-specified ports tests...");
177    
178    let config = TestConfig {
179        html_report: Some("user-specified-ports-report.html".to_string()),
180        ..Default::default()
181    };
182    
183    let exit_code = run_tests_with_config(config);
184    
185    println!();
186    println!("🎉 Tests completed!");
187    println!("📊 Check the HTML report for detailed results.");
188    println!();
189    println!("💡 Key Takeaways:");
190    println!("   • Use .port(host_port, container_port) for fixed port mappings");
191    println!("   • Use .auto_port(container_port) for automatic port assignment");
192    println!("   • Mix both approaches for maximum flexibility");
193    println!("   • Fixed ports are great for services with standard ports (5432, 3306, etc.)");
194    println!("   • Auto-ports prevent conflicts in parallel test environments");
195    
196    std::process::exit(exit_code);
197}
More examples
Hide additional examples
examples/mongodb_integration.rs (line 75)
68fn main() {
69    println!("🐳 MongoDB Integration Example with Container Hooks");
70    println!("==================================================");
71    println!();
72    
73    // Define container configuration with auto-port for MongoDB
74    let mongo_container = ContainerConfig::new("mongo:5.0")
75        .auto_port(27017) // Automatically assign available host port for MongoDB
76        .env("MONGO_INITDB_ROOT_USERNAME", "admin")
77        .env("MONGO_INITDB_ROOT_PASSWORD", "password")
78        .name("test_mongodb")
79        .ready_timeout(Duration::from_secs(30));
80    
81    println!("📋 Container Configuration:");
82    println!("  Image: {}", mongo_container.image);
83    println!("  Auto-ports: {:?}", mongo_container.auto_ports);
84    println!("  Environment: {:?}", mongo_container.env);
85    println!("  Name: {:?}", mongo_container.name);
86    println!("  Ready Timeout: {:?}", mongo_container.ready_timeout);
87    println!("  Auto-cleanup: {}", mongo_container.auto_cleanup);
88    println!();
89    
90    // Clone for before_each hook
91    let mongo_container_before = mongo_container.clone();
92    
93    // Register before_each hook to start container
94    before_each(move |ctx| {
95        println!("🔄 before_each: Starting MongoDB container...");
96        
97        // Start the container and get ContainerInfo
98        let container_info = mongo_container_before.start()
99            .map_err(|e| format!("Failed to start container: {}", e))?;
100        
101        // Store container info in context for tests to access
102        ctx.set_data("mongo_container_info", container_info.clone());
103        
104        // Log container details including auto-assigned ports
105        println!("✅ before_each: MongoDB container {} started", container_info.container_id);
106        println!("🌐 Container exposed on: {}", container_info.ports_summary());
107        if let Some(primary_url) = container_info.primary_url() {
108            println!("🔗 Primary URL: {}", primary_url);
109        }
110        
111        Ok(())
112    });
113    
114    // Register after_each hook to stop container
115    let mongo_container_after = mongo_container.clone();
116    rust_test_harness::after_each(move |ctx| {
117        println!("🔄 after_each: Stopping MongoDB container...");
118        
119        // Get container info from context
120        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
121            .expect("Container info should be available");
122        
123        // Stop the container
124        mongo_container_after.stop(&container_info.container_id)
125            .map_err(|e| format!("Failed to stop container: {}", e))?;
126        
127        println!("✅ after_each: MongoDB container {} stopped", container_info.container_id);
128        Ok(())
129    });
130    
131    // Test 1: Basic MongoDB operations
132    test("test_mongodb_basic_operations", |ctx| {
133        println!("🧪 Running test: test_mongodb_basic_operations");
134        
135        // Get container info from context
136        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
137            .expect("Container info should be available");
138        
139        // Show how to access port information
140        println!("🌐 Container {} is running on:", container_info.container_id);
141        println!("   Ports: {}", container_info.ports_summary());
142        if let Some(primary_url) = container_info.primary_url() {
143            println!("   Primary URL: {}", primary_url);
144        }
145        
146        // Get the MongoDB port (27017) and show the actual host port
147        if let Some(host_port) = container_info.host_port_for(27017) {
148            println!("   MongoDB accessible at: localhost:{}", host_port);
149        }
150        
151        // Create MongoDB client
152        let mut client = MongoClient::new(container_info.container_id.clone());
153        
154        // Connect to MongoDB
155        client.connect()?;
156        
157        // Insert a document
158        client.insert_document("users", r#"{"name": "John Doe", "email": "john@example.com"}"#)?;
159        
160        // Find documents
161        let documents = client.find_documents("users", r#"{"name": "John Doe"}"#)?;
162        assert_eq!(documents.len(), 2);
163        
164        // Disconnect
165        client.disconnect()?;
166        
167        println!("✅ test_mongodb_basic_operations passed");
168        Ok(())
169    });
170    
171    // Test 2: Multiple operations
172    test("test_mongodb_multiple_operations", |ctx| {
173        println!("🧪 Running test: test_mongodb_multiple_operations");
174        
175        // Get container info from context
176        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
177            .expect("Container info should be available");
178        
179        // Show container status
180        println!("🌐 Container {} status:", container_info.container_id);
181        println!("   Active ports: {}", container_info.ports_summary());
182        
183        // Create MongoDB client
184        let mut client = MongoClient::new(container_info.container_id.clone());
185        
186        // Connect to MongoDB
187        client.connect()?;
188        
189        // Insert multiple documents
190        client.insert_document("products", r#"{"name": "Laptop", "price": 999.99}"#)?;
191        client.insert_document("products", r#"{"name": "Mouse", "price": 29.99}"#)?;
192        client.insert_document("products", r#"{"name": "Keyboard", "price": 79.99}"#)?;
193        
194        // Find documents
195        let documents = client.find_documents("products", r#"{"price": {"$gt": 50}}"#)?;
196        assert_eq!(documents.len(), 2); // Laptop and Keyboard
197        
198        // Disconnect
199        client.disconnect()?;
200        
201        println!("✅ test_mongodb_multiple_operations passed");
202        Ok(())
203    });
204    
205    // Test 3: Error handling
206    test("test_mongodb_error_handling", |ctx| {
207        println!("🧪 Running test: test_mongodb_error_handling");
208        
209        // Get container ID from context
210        let container_id = ctx.get_data::<String>("mongo_container_id")
211            .expect("Container ID should be available")
212            .to_string();
213        
214        // Create MongoDB client
215        let client = MongoClient::new(container_id);
216        
217        // Try to insert without connecting (should fail)
218        let result = client.insert_document("users", r#"{"name": "Test"}"#);
219        assert!(result.is_err());
220        assert_eq!(result.unwrap_err(), "Not connected to MongoDB");
221        
222        println!("✅ test_mongodb_error_handling passed");
223        Ok(())
224    });
225    
226    // Test 4: Performance testing
227    test("test_mongodb_performance", |ctx| {
228        println!("🧪 Running test: test_mongodb_performance");
229        
230        // Get container ID from context
231        let container_id = ctx.get_data::<String>("mongo_container_id")
232            .expect("Container ID should be available")
233            .to_string();
234        
235        // Create MongoDB client
236        let mut client = MongoClient::new(container_id);
237        
238        // Connect to MongoDB
239        client.connect()?;
240        
241        // Simulate bulk operations
242        for i in 0..100 {
243            client.insert_document("bulk_data", &format!(r#"{{"index": {}, "data": "bulk_item_{}"}}"#, i, i))?;
244        }
245        
246        // Simulate bulk retrieval
247        let documents = client.find_documents("bulk_data", r#"{"index": {"$lt": 50}}"#)?;
248        assert_eq!(documents.len(), 2); // Mock always returns 2
249        
250        // Disconnect
251        client.disconnect()?;
252        
253        println!("✅ test_mongodb_performance passed");
254        Ok(())
255    });
256    
257    println!("\n🚀 Running MongoDB integration tests...");
258    println!("   Each test will get a fresh MongoDB container via before_each");
259    println!("   Each test will clean up its container via after_each");
260    println!();
261    
262    // Run tests with container hooks enabled
263    let config = TestConfig {
264        skip_hooks: Some(false),
265        ..Default::default()
266    };
267    
268    let result = run_tests_with_config(config);
269    
270    println!("\n📊 Test Results:");
271    if result == 0 {
272        println!("✅ All MongoDB integration tests passed!");
273        println!("🎯 Container lifecycle management working correctly");
274        println!("🐳 Each test got its own MongoDB container");
275        println!("🧹 Each test cleaned up its container properly");
276    } else {
277        println!("❌ Some tests failed");
278    }
279    
280    println!("\n💡 Key Benefits of this approach:");
281    println!("   • Clean separation of concerns");
282    println!("   • Each test gets a fresh container");
283    println!("   • Automatic cleanup via after_each");
284    println!("   • Easy to configure containers");
285    println!("   • No complex global state management");
286}
examples/auto_port_demo.rs (line 19)
12fn main() {
13    println!("🚀 Auto-Port and Container Management Demo");
14    println!("==========================================");
15    println!();
16    
17    // Example 1: Web service with auto-port
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80) // Automatically assign host port for container port 80
20        .env("NGINX_HOST", "localhost")
21        .name("web_service")
22        .ready_timeout(Duration::from_secs(15));
23    
24    // Example 2: Database with auto-port
25    let db_container = ContainerConfig::new("postgres:13-alpine")
26        .auto_port(5432) // Automatically assign host port for container port 5432
27        .env("POSTGRES_PASSWORD", "testpass")
28        .env("POSTGRES_DB", "testdb")
29        .name("test_database")
30        .ready_timeout(Duration::from_secs(20));
31    
32    // Example 3: Redis with auto-port
33    let redis_container = ContainerConfig::new("redis:6-alpine")
34        .auto_port(6379) // Automatically assign host port for container port 6379
35        .name("test_redis")
36        .ready_timeout(Duration::from_secs(10));
37    
38    // Example 4: Mixed configuration (manual + auto ports)
39    let mixed_container = ContainerConfig::new("httpd:alpine")
40        .port(8080, 80) // Manual port mapping
41        .auto_port(443) // Auto port for HTTPS
42        .env("APACHE_DOCUMENT_ROOT", "/var/www/html")
43        .name("mixed_ports")
44        .ready_timeout(Duration::from_secs(15));
45    
46    println!("📋 Container Configurations:");
47    println!("1. Web Service (nginx):");
48    println!("   - Image: {}", web_container.image);
49    println!("   - Auto-ports: {:?}", web_container.auto_ports);
50    println!("   - Auto-cleanup: {}", web_container.auto_cleanup);
51    
52    println!("2. Database (postgres):");
53    println!("   - Image: {}", db_container.image);
54    println!("   - Auto-ports: {:?}", db_container.auto_ports);
55    println!("   - Auto-cleanup: {}", db_container.auto_cleanup);
56    
57    println!("3. Cache (redis):");
58    println!("   - Image: {}", redis_container.image);
59    println!("   - Auto-ports: {:?}", redis_container.auto_ports);
60    println!("   - Auto-cleanup: {}", redis_container.auto_cleanup);
61    
62    println!("4. Mixed (httpd):");
63    println!("   - Image: {}", mixed_container.image);
64    println!("   - Manual ports: {:?}", mixed_container.ports);
65    println!("   - Auto-ports: {:?}", mixed_container.auto_ports);
66    println!("   - Auto-cleanup: {}", mixed_container.auto_cleanup);
67    println!();
68    
69    // Clone containers for hooks
70    let web_before = web_container.clone();
71    let db_before = db_container.clone();
72    let redis_before = redis_container.clone();
73    let mixed_before = mixed_container.clone();
74    
75    // Start all containers in before_each for each test
76    before_each(move |ctx| {
77        println!("🚀 before_each: Starting all containers...");
78        
79        // Start web container
80        let web_info = web_before.start()
81            .map_err(|e| format!("Failed to start web container: {}", e))?;
82        ctx.set_data("web_container_info", web_info.clone());
83        println!("✅ Web container started: {}", web_info.container_id);
84        println!("   Ports: {}", web_info.ports_summary());
85        if let Some(url) = web_info.primary_url() {
86            println!("   URL: {}", url);
87        }
88        
89        // Start database container
90        let db_info = db_before.start()
91            .map_err(|e| format!("Failed to start db container: {}", e))?;
92        ctx.set_data("db_container_info", db_info.clone());
93        println!("✅ Database container started: {}", db_info.container_id);
94        println!("   Ports: {}", db_info.ports_summary());
95        if let Some(host_port) = db_info.host_port_for(5432) {
96            println!("   PostgreSQL accessible at: localhost:{}", host_port);
97        }
98        
99        // Start redis container
100        let redis_info = redis_before.start()
101            .map_err(|e| format!("Failed to start redis container: {}", e))?;
102        ctx.set_data("redis_container_info", redis_info.clone());
103        println!("✅ Redis container started: {}", redis_info.container_id);
104        println!("   Ports: {}", redis_info.ports_summary());
105        if let Some(host_port) = redis_info.host_port_for(6379) {
106            println!("   Redis accessible at: localhost:{}", host_port);
107        }
108        
109        // Start mixed container
110        let mixed_info = mixed_before.start()
111            .map_err(|e| format!("Failed to start mixed container: {}", e))?;
112        ctx.set_data("mixed_container_info", mixed_info.clone());
113        println!("✅ Mixed container started: {}", mixed_info.container_id);
114        println!("   Ports: {}", mixed_info.ports_summary());
115        if let Some(host_port) = mixed_info.host_port_for(443) {
116            println!("   HTTPS accessible at: localhost:{}", host_port);
117        }
118        
119        println!("🎉 All containers started successfully!");
120        Ok(())
121    });
122    
123    // Cleanup all containers in after_each for each test
124    let web_after = web_container.clone();
125    let db_after = db_container.clone();
126    let redis_after = redis_container.clone();
127    let mixed_after = mixed_container.clone();
128    
129    after_each(move |ctx| {
130        println!("🧹 after_each: Cleaning up all containers...");
131        
132        // Get all container info and stop them
133        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
134            let _ = web_after.stop(&web_info.container_id);
135            println!("🛑 Stopped web container: {}", web_info.container_id);
136        }
137        
138        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
139            let _ = db_after.stop(&db_info.container_id);
140            println!("🛑 Stopped database container: {}", db_info.container_id);
141        }
142        
143        if let Some(redis_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info") {
144            let _ = redis_after.stop(&redis_info.container_id);
145            println!("🛑 Stopped redis container: {}", redis_info.container_id);
146        }
147        
148        if let Some(mixed_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info") {
149            let _ = mixed_after.stop(&mixed_info.container_id);
150            println!("🛑 Stopped mixed container: {}", mixed_info.container_id);
151        }
152        
153        println!("✅ All containers cleaned up!");
154        Ok(())
155    });
156    
157    // Test 1: Access web service
158    test("test_web_service_access", |ctx| {
159        println!("🧪 Testing web service access...");
160        
161        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
162            .expect("Web container info should be available");
163        
164        println!("🌐 Web service container: {}", web_info.container_id);
165        println!("   Ports: {}", web_info.ports_summary());
166        println!("   Primary URL: {}", web_info.primary_url().unwrap_or("None"));
167        
168        // In a real test, you would make HTTP requests to the container
169        // For demo purposes, just verify the port information
170        assert!(web_info.host_port_for(80).is_some(), "Web service should have port 80 exposed");
171        
172        println!("✅ Web service test passed");
173        Ok(())
174    });
175    
176    // Test 2: Access database
177    test("test_database_access", |ctx| {
178        println!("🧪 Testing database access...");
179        
180        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
181            .expect("Database container info should be available");
182        
183        println!("🗄️ Database container: {}", db_info.container_id);
184        println!("   Ports: {}", db_info.ports_summary());
185        
186        // Verify PostgreSQL port is exposed
187        let postgres_port = db_info.host_port_for(5432)
188            .expect("PostgreSQL port 5432 should be exposed");
189        println!("   PostgreSQL accessible at: localhost:{}", postgres_port);
190        
191        // In a real test, you would connect to the database
192        // For demo purposes, just verify the port information
193        assert!(postgres_port > 0, "PostgreSQL port should be valid");
194        
195        println!("✅ Database test passed");
196        Ok(())
197    });
198    
199    // Test 3: Access redis
200    test("test_redis_access", |ctx| {
201        println!("🧪 Testing redis access...");
202        
203        let redis_info = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info")
204            .expect("Redis container info should be available");
205        
206        println!("🔴 Redis container: {}", redis_info.container_id);
207        println!("   Ports: {}", redis_info.ports_summary());
208        
209        // Verify Redis port is exposed
210        let redis_port = redis_info.host_port_for(6379)
211            .expect("Redis port 6379 should be exposed");
212        println!("   Redis accessible at: localhost:{}", redis_port);
213        
214        // In a real test, you would connect to Redis
215        // For demo purposes, just verify the port information
216        assert!(redis_port > 0, "Redis port should be valid");
217        
218        println!("✅ Redis test passed");
219        Ok(())
220    });
221    
222    // Test 4: Mixed port configuration
223    test("test_mixed_port_config", |ctx| {
224        println!("🧪 Testing mixed port configuration...");
225        
226        let mixed_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info")
227            .expect("Mixed container info should be available");
228        
229        println!("🔀 Mixed container: {}", mixed_info.container_id);
230        println!("   Ports: {}", mixed_info.ports_summary());
231        
232        // Verify both manual and auto ports
233        let http_port = mixed_info.host_port_for(80)
234            .expect("HTTP port 80 should be exposed");
235        let https_port = mixed_info.host_port_for(443)
236            .expect("HTTPS port 443 should be exposed");
237        
238        println!("   HTTP accessible at: localhost:{}", http_port);
239        println!("   HTTPS accessible at: localhost:{}", https_port);
240        
241        // Verify the manual port mapping (8080 -> 80)
242        assert_eq!(http_port, 8080, "Manual port mapping should work");
243        
244        // Verify auto port is different from manual port
245        assert_ne!(https_port, 8080, "Auto port should be different from manual port");
246        
247        println!("✅ Mixed port configuration test passed");
248        Ok(())
249    });
250    
251    // Test 5: Container info methods
252    test("test_container_info_methods", |ctx| {
253        println!("🧪 Testing container info methods...");
254        
255        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
256            .expect("Web container info should be available");
257        
258        // Test all the convenience methods
259        println!("🔍 Testing container info methods for: {}", web_info.container_id);
260        
261        // Test primary_url
262        if let Some(url) = web_info.primary_url() {
263            println!("   Primary URL: {}", url);
264            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
265        }
266        
267        // Test url_for_port
268        if let Some(url) = web_info.url_for_port(80) {
269            println!("   URL for port 80: {}", url);
270            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
271        }
272        
273        // Test host_port_for
274        if let Some(host_port) = web_info.host_port_for(80) {
275            println!("   Host port for container port 80: {}", host_port);
276            assert!(host_port > 0, "Host port should be valid");
277        }
278        
279        // Test ports_summary
280        let summary = web_info.ports_summary();
281        println!("   Ports summary: {}", summary);
282        assert!(!summary.is_empty(), "Ports summary should not be empty");
283        
284        println!("✅ Container info methods test passed");
285        Ok(())
286    });
287    
288    println!("🚀 Running tests with auto-port functionality...");
289    println!();
290    
291    // Run the tests
292    let config = TestConfig {
293        html_report: Some("auto-port-demo-report.html".to_string()),
294        ..Default::default()
295    };
296    
297    let exit_code = run_tests_with_config(config);
298    
299    println!();
300    if exit_code == 0 {
301        println!("🎉 All tests passed! Auto-port functionality is working correctly.");
302        println!("📊 Check the HTML report for detailed results.");
303    } else {
304        println!("❌ Some tests failed. Check the output above for details.");
305    }
306    
307    std::process::exit(exit_code);
308}
examples/container_port_access.rs (line 19)
12fn main() {
13    println!("🌐 Container Port and URL Access Example");
14    println!("========================================");
15    println!();
16    
17    // Example 1: Web service with multiple auto-ports
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80)      // Auto-assign port for HTTP
20        .auto_port(443)     // Auto-assign port for HTTPS
21        .env("NGINX_HOST", "localhost")
22        .name("web_service")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Database with auto-port
26    let db_container = ContainerConfig::new("postgres:13-alpine")
27        .auto_port(5432)    // Auto-assign port for PostgreSQL
28        .env("POSTGRES_PASSWORD", "testpass")
29        .env("POSTGRES_DB", "testdb")
30        .name("test_database")
31        .ready_timeout(Duration::from_secs(20));
32    
33    // Example 3: Mixed configuration (manual + auto ports)
34    let api_container = ContainerConfig::new("httpd:alpine")
35        .port(8080, 80)     // Manual port mapping
36        .auto_port(9090)    // Auto-assign port for API
37        .auto_port(9091)    // Auto-assign port for metrics
38        .env("API_VERSION", "v1")
39        .name("api_service")
40        .ready_timeout(Duration::from_secs(15));
41    
42    println!("📋 Container Configurations:");
43    println!("1. Web Service:");
44    println!("   - Image: {}", web_container.image);
45    println!("   - Auto-ports: {:?}", web_container.auto_ports);
46    println!("   - Will auto-assign host ports for container ports 80 and 443");
47    
48    println!("2. Database:");
49    println!("   - Image: {}", db_container.image);
50    println!("   - Auto-ports: {:?}", db_container.auto_ports);
51    println!("   - Will auto-assign host port for container port 5432");
52    
53    println!("3. API Service:");
54    println!("   - Image: {}", api_container.image);
55    println!("   - Manual ports: {:?}", api_container.ports);
56    println!("   - Auto-ports: {:?}", api_container.auto_ports);
57    println!("   - Manual mapping: 8080 -> 80, Auto-assign: 9090, 9091");
58    println!();
59    
60    // Clone containers for hooks
61    let web_before = web_container.clone();
62    let db_before = db_container.clone();
63    let api_before = api_container.clone();
64    
65    // Start containers in before_each
66    before_each(move |ctx| {
67        println!("🚀 before_each: Starting containers and capturing port info...");
68        
69        // Start web container
70        let web_info = web_before.start()
71            .map_err(|e| format!("Failed to start web container: {}", e))?;
72        ctx.set_data("web_container_info", web_info.clone());
73        
74        println!("✅ Web container started: {}", web_info.container_id);
75        println!("   📍 Port mappings: {}", web_info.ports_summary());
76        println!("   🔗 Primary URL: {}", web_info.primary_url().unwrap_or("None"));
77        
78        // Show specific port access
79        if let Some(http_port) = web_info.host_port_for(80) {
80            println!("   🌐 HTTP accessible at: http://localhost:{}", http_port);
81        }
82        if let Some(https_port) = web_info.host_port_for(443) {
83            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
84        }
85        
86        // Start database container
87        let db_info = db_before.start()
88            .map_err(|e| format!("Failed to start db container: {}", e))?;
89        ctx.set_data("db_container_info", db_info.clone());
90        
91        println!("✅ Database container started: {}", db_info.container_id);
92        println!("   📍 Port mappings: {}", db_info.ports_summary());
93        if let Some(db_port) = db_info.host_port_for(5432) {
94            println!("   🗄️ PostgreSQL accessible at: localhost:{}", db_port);
95            println!("   📝 Connection string: postgresql://user:pass@localhost:{}/testdb", db_port);
96        }
97        
98        // Start API container
99        let api_info = api_before.start()
100            .map_err(|e| format!("Failed to start api container: {}", e))?;
101        ctx.set_data("api_container_info", api_info.clone());
102        
103        println!("✅ API container started: {}", api_info.container_id);
104        println!("   📍 Port mappings: {}", api_info.ports_summary());
105        
106        // Show both manual and auto ports
107        if let Some(http_port) = api_info.host_port_for(80) {
108            println!("   🌐 HTTP API at: http://localhost:{} (manual mapping)", http_port);
109        }
110        if let Some(api_port) = api_info.host_port_for(9090) {
111            println!("   🔧 API endpoint at: http://localhost:{} (auto-assigned)", api_port);
112        }
113        if let Some(metrics_port) = api_info.host_port_for(9091) {
114            println!("   📊 Metrics at: http://localhost:{} (auto-assigned)", metrics_port);
115        }
116        
117        println!("🎉 All containers started with auto-assigned ports!");
118        Ok(())
119    });
120    
121    // Cleanup containers in after_each
122    let web_after = web_container.clone();
123    let db_after = db_container.clone();
124    let api_after = api_container.clone();
125    
126    after_each(move |ctx| {
127        println!("🧹 after_each: Cleaning up containers...");
128        
129        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
130            let _ = web_after.stop(&web_info.container_id);
131            println!("🛑 Stopped web container: {}", web_info.container_id);
132        }
133        
134        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
135            let _ = db_after.stop(&db_info.container_id);
136            println!("🛑 Stopped database container: {}", db_info.container_id);
137        }
138        
139        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
140            let _ = api_after.stop(&api_info.container_id);
141            println!("🛑 Stopped API container: {}", api_info.container_id);
142        }
143        
144        println!("✅ All containers cleaned up!");
145        Ok(())
146    });
147    
148    // Test 1: Web service port access
149    test("test_web_service_port_access", |ctx| {
150        println!("🧪 Testing web service port access...");
151        
152        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
153            .expect("Web container info should be available");
154        
155        println!("🔍 Demonstrating port access methods:");
156        
157        // Method 1: Get specific host port for container port
158        if let Some(http_port) = web_info.host_port_for(80) {
159            println!("   ✅ HTTP port 80 is mapped to host port: {}", http_port);
160            println!("      💡 Use this for HTTP client connections");
161        }
162        
163        if let Some(https_port) = web_info.host_port_for(443) {
164            println!("   ✅ HTTPS port 443 is mapped to host port: {}", https_port);
165            println!("      💡 Use this for HTTPS client connections");
166        }
167        
168        // Method 2: Get ready-to-use URLs
169        if let Some(http_url) = web_info.url_for_port(80) {
170            println!("   🔗 HTTP URL: {}", http_url);
171            println!("      💡 Ready to use in HTTP requests");
172        }
173        
174        if let Some(https_url) = web_info.url_for_port(443) {
175            println!("   🔗 HTTPS URL: {}", https_url);
176            println!("      💡 Ready to use in HTTPS requests (change http:// to https://)");
177        }
178        
179        // Method 3: Get all URLs
180        println!("   📋 All service URLs:");
181        for (i, url) in web_info.urls.iter().enumerate() {
182            println!("      {}. {}", i + 1, url);
183        }
184        
185        // Method 4: Get all port mappings
186        println!("   📊 All port mappings:");
187        for (host_port, container_port) in &web_info.port_mappings {
188            println!("      Host {} -> Container {}", host_port, container_port);
189        }
190        
191        // Verify ports are different (auto-assigned)
192        assert!(web_info.host_port_for(80).unwrap() != web_info.host_port_for(443).unwrap(), 
193                "Auto-assigned ports should be different");
194        
195        println!("✅ Web service port access test passed");
196        Ok(())
197    });
198    
199    // Test 2: Database connection string generation
200    test("test_database_connection_info", |ctx| {
201        println!("🧪 Testing database connection info generation...");
202        
203        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
204            .expect("Database container info should be available");
205        
206        println!("🗄️ Database connection information:");
207        
208        // Get the auto-assigned port for PostgreSQL
209        let db_port = db_info.host_port_for(5432)
210            .expect("PostgreSQL port should be exposed");
211        
212        println!("   📍 PostgreSQL running on: localhost:{}", db_port);
213        
214        // Generate connection strings using the auto-assigned port
215        let connection_string = format!("postgresql://admin:testpass@localhost:{}/testdb", db_port);
216        let jdbc_url = format!("jdbc:postgresql://localhost:{}/testdb", db_port);
217        let docker_internal = format!("postgresql://admin:testpass@{}:5432/testdb", db_info.container_id);
218        
219        println!("   🔗 Connection strings:");
220        println!("      Standard: {}", connection_string);
221        println!("      JDBC: {}", jdbc_url);
222        println!("      Docker internal: {}", docker_internal);
223        
224        // Show how to use this in real applications
225        println!("   💡 Usage examples:");
226        println!("      - Set DATABASE_URL={}", connection_string);
227        println!("      - Use in tests: connect to localhost:{}", db_port);
228        println!("      - Container-to-container: use port 5432");
229        
230        // Verify port is valid
231        assert!(db_port > 0, "Database port should be valid");
232        println!("✅ Database connection info test passed");
233        
234        Ok(())
235    });
236    
237    // Test 3: Mixed port configuration
238    test("test_mixed_port_configuration", |ctx| {
239        println!("🧪 Testing mixed port configuration (manual + auto)...");
240        
241        let api_info = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info")
242            .expect("API container info should be available");
243        
244        println!("🔀 Mixed port configuration analysis:");
245        
246        // Manual port mapping
247        let http_port = api_info.host_port_for(80)
248            .expect("HTTP port should be mapped");
249        println!("   📌 Manual mapping - HTTP port 80 -> host port: {}", http_port);
250        assert_eq!(http_port, 8080, "Manual port should be exactly as specified");
251        
252        // Auto-assigned ports
253        let api_port = api_info.host_port_for(9090)
254            .expect("API port should be auto-assigned");
255        let metrics_port = api_info.host_port_for(9091)
256            .expect("Metrics port should be auto-assigned");
257        
258        println!("   🎲 Auto-assigned - API port 9090 -> host port: {}", api_port);
259        println!("   🎲 Auto-assigned - Metrics port 9091 -> host port: {}", metrics_port);
260        
261        // Verify auto-assigned ports are different from manual port
262        assert_ne!(api_port, 8080, "Auto-assigned port should be different from manual port");
263        assert_ne!(metrics_port, 8080, "Auto-assigned port should be different from manual port");
264        assert_ne!(api_port, metrics_port, "Auto-assigned ports should be different from each other");
265        
266        println!("   🌐 Service endpoints:");
267        println!("      Main API: http://localhost:{}/", http_port);
268        println!("      API v2: http://localhost:{}/", api_port);
269        println!("      Metrics: http://localhost:{}/metrics", metrics_port);
270        
271        // Show complete port summary
272        println!("   📋 Complete port summary: {}", api_info.ports_summary());
273        
274        println!("✅ Mixed port configuration test passed");
275        Ok(())
276    });
277    
278    // Test 4: Container info convenience methods
279    test("test_container_info_convenience_methods", |ctx| {
280        println!("🧪 Testing ContainerInfo convenience methods...");
281        
282        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
283            .expect("Web container info should be available");
284        
285        println!("🔧 Testing all ContainerInfo methods:");
286        
287        // Test primary_url()
288        if let Some(primary_url) = web_info.primary_url() {
289            println!("   ✅ primary_url(): {}", primary_url);
290            assert!(primary_url.starts_with("http://localhost:"), "Primary URL should be valid");
291        }
292        
293        // Test url_for_port()
294        if let Some(url_80) = web_info.url_for_port(80) {
295            println!("   ✅ url_for_port(80): {}", url_80);
296            assert!(url_80.contains("localhost:"), "URL should contain localhost");
297        }
298        
299        // Test host_port_for()
300        if let Some(port_80) = web_info.host_port_for(80) {
301            println!("   ✅ host_port_for(80): {}", port_80);
302            assert!(port_80 > 0, "Port should be positive");
303        }
304        
305        // Test ports_summary()
306        let summary = web_info.ports_summary();
307        println!("   ✅ ports_summary(): {}", summary);
308        assert!(summary.contains("->"), "Summary should contain port mappings");
309        
310        // Test direct field access
311        println!("   ✅ container_id: {}", web_info.container_id);
312        println!("   ✅ image: {}", web_info.image);
313        println!("   ✅ auto_cleanup: {}", web_info.auto_cleanup);
314        
315        println!("   📊 All URLs:");
316        for (i, url) in web_info.urls.iter().enumerate() {
317            println!("      {}. {}", i + 1, url);
318        }
319        
320        println!("   📊 All port mappings:");
321        for (host_port, container_port) in &web_info.port_mappings {
322            println!("      {} -> {}", host_port, container_port);
323        }
324        
325        println!("✅ Container info convenience methods test passed");
326        Ok(())
327    });
328    
329    // Test 5: Real-world usage patterns
330    test("test_real_world_usage_patterns", |ctx| {
331        println!("🧪 Testing real-world usage patterns...");
332        
333        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
334            .expect("Web container info should be available");
335        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
336            .expect("Database container info should be available");
337        
338        println!("🌍 Real-world usage examples:");
339        
340        // Pattern 1: HTTP client testing
341        if let Some(web_url) = web_info.primary_url() {
342            println!("   🌐 HTTP Client Testing:");
343            println!("      Base URL: {}", web_url);
344            println!("      GET {}/health", web_url);
345            println!("      POST {}/api/users", web_url);
346            println!("      Code: let response = reqwest::get(\"{}/health\").await?;", web_url);
347        }
348        
349        // Pattern 2: Database testing
350        if let Some(db_port) = db_info.host_port_for(5432) {
351            println!("   🗄️ Database Testing:");
352            println!("      Connection: localhost:{}", db_port);
353            println!("      Code: let conn = PgConnection::establish(\"postgresql://user:pass@localhost:{}/db\")?;", db_port);
354        }
355        
356        // Pattern 3: Environment variable setup
357        println!("   🔧 Environment Variables:");
358        if let Some(web_port) = web_info.host_port_for(80) {
359            println!("      export WEB_SERVICE_URL=http://localhost:{}", web_port);
360        }
361        if let Some(db_port) = db_info.host_port_for(5432) {
362            println!("      export DATABASE_URL=postgresql://localhost:{}/testdb", db_port);
363        }
364        
365        // Pattern 4: Docker-compose style networking
366        println!("   🐳 Container Networking:");
367        println!("      External: Use auto-assigned host ports");
368        println!("      Internal: Use original container ports");
369        println!("      Web -> DB: {}:5432 (container-to-container)", db_info.container_id);
370        
371        // Pattern 5: Health checks
372        println!("   ❤️ Health Checks:");
373        if let Some(web_url) = web_info.primary_url() {
374            println!("      Health endpoint: {}/health", web_url);
375            println!("      Ready endpoint: {}/ready", web_url);
376        }
377        
378        println!("✅ Real-world usage patterns test passed");
379        Ok(())
380    });
381    
382    println!("🚀 Running container port access tests...");
383    println!();
384    
385    // Run the tests
386    let config = TestConfig {
387        html_report: Some("container-port-access-report.html".to_string()),
388        ..Default::default()
389    };
390    
391    let exit_code = run_tests_with_config(config);
392    
393    println!();
394    if exit_code == 0 {
395        println!("🎉 All tests passed! Port access functionality is working correctly.");
396        println!("📊 Check the HTML report for detailed results.");
397        println!();
398        println!("💡 Key Takeaways:");
399        println!("   • Use auto_port() to avoid port conflicts");
400        println!("   • Access host ports with host_port_for(container_port)");
401        println!("   • Get ready-to-use URLs with url_for_port(container_port)");
402        println!("   • Use ports_summary() for human-readable port info");
403        println!("   • ContainerInfo provides complete access to all port information");
404    } else {
405        println!("❌ Some tests failed. Check the output above for details.");
406    }
407    
408    std::process::exit(exit_code);
409}
Source

pub fn no_auto_cleanup(self) -> Self

Disable automatic cleanup (containers will persist after tests)

Source

pub fn start(&self) -> Result<ContainerInfo, Box<dyn Error + Send + Sync>>

Start a container with this configuration using Docker API

Examples found in repository?
examples/user_specified_ports.rs (line 55)
12fn main() {
13    println!("🔧 User-Specified Ports Example");
14    println!("==============================");
15    println!();
16    
17    // Example 1: PostgreSQL on standard port 5432
18    let postgres_container = ContainerConfig::new("postgres:13-alpine")
19        .port(5432, 5432)     // Map host port 5432 to container port 5432
20        .env("POSTGRES_PASSWORD", "testpass")
21        .env("POSTGRES_DB", "testdb")
22        .name("postgres_test")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Web service on port 8080
26    let web_container = ContainerConfig::new("nginx:alpine")
27        .port(8080, 80)       // Map host port 8080 to container port 80
28        .name("nginx_test")
29        .ready_timeout(Duration::from_secs(10));
30    
31    // Example 3: Mixed configuration - some fixed, some auto
32    let api_container = ContainerConfig::new("httpd:alpine")
33        .port(3000, 80)       // Fixed port for main API
34        .auto_port(443)       // Auto-assign for HTTPS
35        .auto_port(9090)      // Auto-assign for metrics
36        .name("api_test")
37        .ready_timeout(Duration::from_secs(10));
38    
39    println!("📋 Container Configurations:");
40    println!("1. PostgreSQL: Fixed on localhost:5432 (standard PostgreSQL port)");
41    println!("2. Web Service: Fixed on localhost:8080");
42    println!("3. API Service: Fixed localhost:3000, auto-assigned for 443 and 9090");
43    println!();
44    
45    // Clone containers for hooks
46    let postgres_before = postgres_container.clone();
47    let web_before = web_container.clone();
48    let api_before = api_container.clone();
49    
50    // Start containers in before_each
51    before_each(move |ctx| {
52        println!("🚀 before_each: Starting containers with specified ports...");
53        
54        // Start PostgreSQL container
55        let postgres_info = postgres_before.start()
56            .map_err(|e| format!("Failed to start PostgreSQL container: {}", e))?;
57        ctx.set_data("postgres_container_info", postgres_info.clone());
58        
59        println!("✅ PostgreSQL started: {}", postgres_info.container_id);
60        println!("   📍 Port mappings: {}", postgres_info.ports_summary());
61        println!("   🗄️ Database URL: postgresql://postgres:testpass@localhost:5432/testdb");
62        
63        // Start web container
64        let web_info = web_before.start()
65            .map_err(|e| format!("Failed to start web container: {}", e))?;
66        ctx.set_data("web_container_info", web_info.clone());
67        
68        println!("✅ Web service started: {}", web_info.container_id);
69        println!("   📍 Port mappings: {}", web_info.ports_summary());
70        println!("   🌐 Web accessible at: http://localhost:8080");
71        
72        // Start API container
73        let api_info = api_before.start()
74            .map_err(|e| format!("Failed to start API container: {}", e))?;
75        ctx.set_data("api_container_info", api_info.clone());
76        
77        println!("✅ API service started: {}", api_info.container_id);
78        println!("   📍 Port mappings: {}", api_info.ports_summary());
79        println!("   🔗 API accessible at: http://localhost:3000");
80        if let Some(https_port) = api_info.host_port_for(443) {
81            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
82        }
83        if let Some(metrics_port) = api_info.host_port_for(9090) {
84            println!("   📊 Metrics accessible at: http://localhost:{}/metrics", metrics_port);
85        }
86        
87        Ok(())
88    });
89    
90    // Cleanup containers in after_each
91    let postgres_after = postgres_container.clone();
92    let web_after = web_container.clone();
93    let api_after = api_container.clone();
94    
95    after_each(move |ctx| {
96        println!("🧹 after_each: Cleaning up containers...");
97        
98        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
99            let _ = postgres_after.stop(&postgres_info.container_id);
100            println!("🛑 Stopped PostgreSQL container");
101        }
102        
103        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
104            let _ = web_after.stop(&web_info.container_id);
105            println!("🛑 Stopped web container");
106        }
107        
108        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
109            let _ = api_after.stop(&api_info.container_id);
110            println!("🛑 Stopped API container");
111        }
112        
113        println!("✅ All containers cleaned up!");
114        Ok(())
115    });
116    
117    // Test 1: Database connection test
118    test("test_database_connection", |ctx| {
119        println!("🧪 Testing database connection on fixed port 5432...");
120        
121        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
122            assert_eq!(postgres_info.host_port_for(5432), Some(5432));
123            assert_eq!(postgres_info.url_for_port(5432), Some("localhost:5432".to_string()));
124            println!("✅ Database is accessible on the expected port 5432");
125        } else {
126            return Err("PostgreSQL container info not found".into());
127        }
128        
129        Ok(())
130    });
131    
132    // Test 2: Web service test
133    test("test_web_service_fixed_port", |ctx| {
134        println!("🧪 Testing web service on fixed port 8080...");
135        
136        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
137            assert_eq!(web_info.host_port_for(80), Some(8080));
138            assert_eq!(web_info.url_for_port(80), Some("localhost:8080".to_string()));
139            println!("✅ Web service is accessible on the expected port 8080");
140        } else {
141            return Err("Web container info not found".into());
142        }
143        
144        Ok(())
145    });
146    
147    // Test 3: Mixed configuration test
148    test("test_mixed_port_configuration", |ctx| {
149        println!("🧪 Testing mixed port configuration (fixed + auto)...");
150        
151        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
152            // Test fixed port
153            assert_eq!(api_info.host_port_for(80), Some(3000));
154            assert_eq!(api_info.url_for_port(80), Some("localhost:3000".to_string()));
155            println!("✅ Fixed port 3000 -> 80 is working");
156            
157            // Test auto-assigned ports
158            if let Some(https_port) = api_info.host_port_for(443) {
159                assert!(https_port > 1024); // Should be a high port
160                println!("✅ Auto-assigned HTTPS port: {}", https_port);
161            }
162            
163            if let Some(metrics_port) = api_info.host_port_for(9090) {
164                assert!(metrics_port > 1024); // Should be a high port
165                println!("✅ Auto-assigned metrics port: {}", metrics_port);
166            }
167            
168            println!("✅ Mixed configuration is working correctly");
169        } else {
170            return Err("API container info not found".into());
171        }
172        
173        Ok(())
174    });
175    
176    println!("🚀 Running user-specified ports tests...");
177    
178    let config = TestConfig {
179        html_report: Some("user-specified-ports-report.html".to_string()),
180        ..Default::default()
181    };
182    
183    let exit_code = run_tests_with_config(config);
184    
185    println!();
186    println!("🎉 Tests completed!");
187    println!("📊 Check the HTML report for detailed results.");
188    println!();
189    println!("💡 Key Takeaways:");
190    println!("   • Use .port(host_port, container_port) for fixed port mappings");
191    println!("   • Use .auto_port(container_port) for automatic port assignment");
192    println!("   • Mix both approaches for maximum flexibility");
193    println!("   • Fixed ports are great for services with standard ports (5432, 3306, etc.)");
194    println!("   • Auto-ports prevent conflicts in parallel test environments");
195    
196    std::process::exit(exit_code);
197}
More examples
Hide additional examples
examples/mongodb_integration.rs (line 98)
68fn main() {
69    println!("🐳 MongoDB Integration Example with Container Hooks");
70    println!("==================================================");
71    println!();
72    
73    // Define container configuration with auto-port for MongoDB
74    let mongo_container = ContainerConfig::new("mongo:5.0")
75        .auto_port(27017) // Automatically assign available host port for MongoDB
76        .env("MONGO_INITDB_ROOT_USERNAME", "admin")
77        .env("MONGO_INITDB_ROOT_PASSWORD", "password")
78        .name("test_mongodb")
79        .ready_timeout(Duration::from_secs(30));
80    
81    println!("📋 Container Configuration:");
82    println!("  Image: {}", mongo_container.image);
83    println!("  Auto-ports: {:?}", mongo_container.auto_ports);
84    println!("  Environment: {:?}", mongo_container.env);
85    println!("  Name: {:?}", mongo_container.name);
86    println!("  Ready Timeout: {:?}", mongo_container.ready_timeout);
87    println!("  Auto-cleanup: {}", mongo_container.auto_cleanup);
88    println!();
89    
90    // Clone for before_each hook
91    let mongo_container_before = mongo_container.clone();
92    
93    // Register before_each hook to start container
94    before_each(move |ctx| {
95        println!("🔄 before_each: Starting MongoDB container...");
96        
97        // Start the container and get ContainerInfo
98        let container_info = mongo_container_before.start()
99            .map_err(|e| format!("Failed to start container: {}", e))?;
100        
101        // Store container info in context for tests to access
102        ctx.set_data("mongo_container_info", container_info.clone());
103        
104        // Log container details including auto-assigned ports
105        println!("✅ before_each: MongoDB container {} started", container_info.container_id);
106        println!("🌐 Container exposed on: {}", container_info.ports_summary());
107        if let Some(primary_url) = container_info.primary_url() {
108            println!("🔗 Primary URL: {}", primary_url);
109        }
110        
111        Ok(())
112    });
113    
114    // Register after_each hook to stop container
115    let mongo_container_after = mongo_container.clone();
116    rust_test_harness::after_each(move |ctx| {
117        println!("🔄 after_each: Stopping MongoDB container...");
118        
119        // Get container info from context
120        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
121            .expect("Container info should be available");
122        
123        // Stop the container
124        mongo_container_after.stop(&container_info.container_id)
125            .map_err(|e| format!("Failed to stop container: {}", e))?;
126        
127        println!("✅ after_each: MongoDB container {} stopped", container_info.container_id);
128        Ok(())
129    });
130    
131    // Test 1: Basic MongoDB operations
132    test("test_mongodb_basic_operations", |ctx| {
133        println!("🧪 Running test: test_mongodb_basic_operations");
134        
135        // Get container info from context
136        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
137            .expect("Container info should be available");
138        
139        // Show how to access port information
140        println!("🌐 Container {} is running on:", container_info.container_id);
141        println!("   Ports: {}", container_info.ports_summary());
142        if let Some(primary_url) = container_info.primary_url() {
143            println!("   Primary URL: {}", primary_url);
144        }
145        
146        // Get the MongoDB port (27017) and show the actual host port
147        if let Some(host_port) = container_info.host_port_for(27017) {
148            println!("   MongoDB accessible at: localhost:{}", host_port);
149        }
150        
151        // Create MongoDB client
152        let mut client = MongoClient::new(container_info.container_id.clone());
153        
154        // Connect to MongoDB
155        client.connect()?;
156        
157        // Insert a document
158        client.insert_document("users", r#"{"name": "John Doe", "email": "john@example.com"}"#)?;
159        
160        // Find documents
161        let documents = client.find_documents("users", r#"{"name": "John Doe"}"#)?;
162        assert_eq!(documents.len(), 2);
163        
164        // Disconnect
165        client.disconnect()?;
166        
167        println!("✅ test_mongodb_basic_operations passed");
168        Ok(())
169    });
170    
171    // Test 2: Multiple operations
172    test("test_mongodb_multiple_operations", |ctx| {
173        println!("🧪 Running test: test_mongodb_multiple_operations");
174        
175        // Get container info from context
176        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
177            .expect("Container info should be available");
178        
179        // Show container status
180        println!("🌐 Container {} status:", container_info.container_id);
181        println!("   Active ports: {}", container_info.ports_summary());
182        
183        // Create MongoDB client
184        let mut client = MongoClient::new(container_info.container_id.clone());
185        
186        // Connect to MongoDB
187        client.connect()?;
188        
189        // Insert multiple documents
190        client.insert_document("products", r#"{"name": "Laptop", "price": 999.99}"#)?;
191        client.insert_document("products", r#"{"name": "Mouse", "price": 29.99}"#)?;
192        client.insert_document("products", r#"{"name": "Keyboard", "price": 79.99}"#)?;
193        
194        // Find documents
195        let documents = client.find_documents("products", r#"{"price": {"$gt": 50}}"#)?;
196        assert_eq!(documents.len(), 2); // Laptop and Keyboard
197        
198        // Disconnect
199        client.disconnect()?;
200        
201        println!("✅ test_mongodb_multiple_operations passed");
202        Ok(())
203    });
204    
205    // Test 3: Error handling
206    test("test_mongodb_error_handling", |ctx| {
207        println!("🧪 Running test: test_mongodb_error_handling");
208        
209        // Get container ID from context
210        let container_id = ctx.get_data::<String>("mongo_container_id")
211            .expect("Container ID should be available")
212            .to_string();
213        
214        // Create MongoDB client
215        let client = MongoClient::new(container_id);
216        
217        // Try to insert without connecting (should fail)
218        let result = client.insert_document("users", r#"{"name": "Test"}"#);
219        assert!(result.is_err());
220        assert_eq!(result.unwrap_err(), "Not connected to MongoDB");
221        
222        println!("✅ test_mongodb_error_handling passed");
223        Ok(())
224    });
225    
226    // Test 4: Performance testing
227    test("test_mongodb_performance", |ctx| {
228        println!("🧪 Running test: test_mongodb_performance");
229        
230        // Get container ID from context
231        let container_id = ctx.get_data::<String>("mongo_container_id")
232            .expect("Container ID should be available")
233            .to_string();
234        
235        // Create MongoDB client
236        let mut client = MongoClient::new(container_id);
237        
238        // Connect to MongoDB
239        client.connect()?;
240        
241        // Simulate bulk operations
242        for i in 0..100 {
243            client.insert_document("bulk_data", &format!(r#"{{"index": {}, "data": "bulk_item_{}"}}"#, i, i))?;
244        }
245        
246        // Simulate bulk retrieval
247        let documents = client.find_documents("bulk_data", r#"{"index": {"$lt": 50}}"#)?;
248        assert_eq!(documents.len(), 2); // Mock always returns 2
249        
250        // Disconnect
251        client.disconnect()?;
252        
253        println!("✅ test_mongodb_performance passed");
254        Ok(())
255    });
256    
257    println!("\n🚀 Running MongoDB integration tests...");
258    println!("   Each test will get a fresh MongoDB container via before_each");
259    println!("   Each test will clean up its container via after_each");
260    println!();
261    
262    // Run tests with container hooks enabled
263    let config = TestConfig {
264        skip_hooks: Some(false),
265        ..Default::default()
266    };
267    
268    let result = run_tests_with_config(config);
269    
270    println!("\n📊 Test Results:");
271    if result == 0 {
272        println!("✅ All MongoDB integration tests passed!");
273        println!("🎯 Container lifecycle management working correctly");
274        println!("🐳 Each test got its own MongoDB container");
275        println!("🧹 Each test cleaned up its container properly");
276    } else {
277        println!("❌ Some tests failed");
278    }
279    
280    println!("\n💡 Key Benefits of this approach:");
281    println!("   • Clean separation of concerns");
282    println!("   • Each test gets a fresh container");
283    println!("   • Automatic cleanup via after_each");
284    println!("   • Easy to configure containers");
285    println!("   • No complex global state management");
286}
examples/auto_port_demo.rs (line 80)
12fn main() {
13    println!("🚀 Auto-Port and Container Management Demo");
14    println!("==========================================");
15    println!();
16    
17    // Example 1: Web service with auto-port
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80) // Automatically assign host port for container port 80
20        .env("NGINX_HOST", "localhost")
21        .name("web_service")
22        .ready_timeout(Duration::from_secs(15));
23    
24    // Example 2: Database with auto-port
25    let db_container = ContainerConfig::new("postgres:13-alpine")
26        .auto_port(5432) // Automatically assign host port for container port 5432
27        .env("POSTGRES_PASSWORD", "testpass")
28        .env("POSTGRES_DB", "testdb")
29        .name("test_database")
30        .ready_timeout(Duration::from_secs(20));
31    
32    // Example 3: Redis with auto-port
33    let redis_container = ContainerConfig::new("redis:6-alpine")
34        .auto_port(6379) // Automatically assign host port for container port 6379
35        .name("test_redis")
36        .ready_timeout(Duration::from_secs(10));
37    
38    // Example 4: Mixed configuration (manual + auto ports)
39    let mixed_container = ContainerConfig::new("httpd:alpine")
40        .port(8080, 80) // Manual port mapping
41        .auto_port(443) // Auto port for HTTPS
42        .env("APACHE_DOCUMENT_ROOT", "/var/www/html")
43        .name("mixed_ports")
44        .ready_timeout(Duration::from_secs(15));
45    
46    println!("📋 Container Configurations:");
47    println!("1. Web Service (nginx):");
48    println!("   - Image: {}", web_container.image);
49    println!("   - Auto-ports: {:?}", web_container.auto_ports);
50    println!("   - Auto-cleanup: {}", web_container.auto_cleanup);
51    
52    println!("2. Database (postgres):");
53    println!("   - Image: {}", db_container.image);
54    println!("   - Auto-ports: {:?}", db_container.auto_ports);
55    println!("   - Auto-cleanup: {}", db_container.auto_cleanup);
56    
57    println!("3. Cache (redis):");
58    println!("   - Image: {}", redis_container.image);
59    println!("   - Auto-ports: {:?}", redis_container.auto_ports);
60    println!("   - Auto-cleanup: {}", redis_container.auto_cleanup);
61    
62    println!("4. Mixed (httpd):");
63    println!("   - Image: {}", mixed_container.image);
64    println!("   - Manual ports: {:?}", mixed_container.ports);
65    println!("   - Auto-ports: {:?}", mixed_container.auto_ports);
66    println!("   - Auto-cleanup: {}", mixed_container.auto_cleanup);
67    println!();
68    
69    // Clone containers for hooks
70    let web_before = web_container.clone();
71    let db_before = db_container.clone();
72    let redis_before = redis_container.clone();
73    let mixed_before = mixed_container.clone();
74    
75    // Start all containers in before_each for each test
76    before_each(move |ctx| {
77        println!("🚀 before_each: Starting all containers...");
78        
79        // Start web container
80        let web_info = web_before.start()
81            .map_err(|e| format!("Failed to start web container: {}", e))?;
82        ctx.set_data("web_container_info", web_info.clone());
83        println!("✅ Web container started: {}", web_info.container_id);
84        println!("   Ports: {}", web_info.ports_summary());
85        if let Some(url) = web_info.primary_url() {
86            println!("   URL: {}", url);
87        }
88        
89        // Start database container
90        let db_info = db_before.start()
91            .map_err(|e| format!("Failed to start db container: {}", e))?;
92        ctx.set_data("db_container_info", db_info.clone());
93        println!("✅ Database container started: {}", db_info.container_id);
94        println!("   Ports: {}", db_info.ports_summary());
95        if let Some(host_port) = db_info.host_port_for(5432) {
96            println!("   PostgreSQL accessible at: localhost:{}", host_port);
97        }
98        
99        // Start redis container
100        let redis_info = redis_before.start()
101            .map_err(|e| format!("Failed to start redis container: {}", e))?;
102        ctx.set_data("redis_container_info", redis_info.clone());
103        println!("✅ Redis container started: {}", redis_info.container_id);
104        println!("   Ports: {}", redis_info.ports_summary());
105        if let Some(host_port) = redis_info.host_port_for(6379) {
106            println!("   Redis accessible at: localhost:{}", host_port);
107        }
108        
109        // Start mixed container
110        let mixed_info = mixed_before.start()
111            .map_err(|e| format!("Failed to start mixed container: {}", e))?;
112        ctx.set_data("mixed_container_info", mixed_info.clone());
113        println!("✅ Mixed container started: {}", mixed_info.container_id);
114        println!("   Ports: {}", mixed_info.ports_summary());
115        if let Some(host_port) = mixed_info.host_port_for(443) {
116            println!("   HTTPS accessible at: localhost:{}", host_port);
117        }
118        
119        println!("🎉 All containers started successfully!");
120        Ok(())
121    });
122    
123    // Cleanup all containers in after_each for each test
124    let web_after = web_container.clone();
125    let db_after = db_container.clone();
126    let redis_after = redis_container.clone();
127    let mixed_after = mixed_container.clone();
128    
129    after_each(move |ctx| {
130        println!("🧹 after_each: Cleaning up all containers...");
131        
132        // Get all container info and stop them
133        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
134            let _ = web_after.stop(&web_info.container_id);
135            println!("🛑 Stopped web container: {}", web_info.container_id);
136        }
137        
138        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
139            let _ = db_after.stop(&db_info.container_id);
140            println!("🛑 Stopped database container: {}", db_info.container_id);
141        }
142        
143        if let Some(redis_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info") {
144            let _ = redis_after.stop(&redis_info.container_id);
145            println!("🛑 Stopped redis container: {}", redis_info.container_id);
146        }
147        
148        if let Some(mixed_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info") {
149            let _ = mixed_after.stop(&mixed_info.container_id);
150            println!("🛑 Stopped mixed container: {}", mixed_info.container_id);
151        }
152        
153        println!("✅ All containers cleaned up!");
154        Ok(())
155    });
156    
157    // Test 1: Access web service
158    test("test_web_service_access", |ctx| {
159        println!("🧪 Testing web service access...");
160        
161        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
162            .expect("Web container info should be available");
163        
164        println!("🌐 Web service container: {}", web_info.container_id);
165        println!("   Ports: {}", web_info.ports_summary());
166        println!("   Primary URL: {}", web_info.primary_url().unwrap_or("None"));
167        
168        // In a real test, you would make HTTP requests to the container
169        // For demo purposes, just verify the port information
170        assert!(web_info.host_port_for(80).is_some(), "Web service should have port 80 exposed");
171        
172        println!("✅ Web service test passed");
173        Ok(())
174    });
175    
176    // Test 2: Access database
177    test("test_database_access", |ctx| {
178        println!("🧪 Testing database access...");
179        
180        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
181            .expect("Database container info should be available");
182        
183        println!("🗄️ Database container: {}", db_info.container_id);
184        println!("   Ports: {}", db_info.ports_summary());
185        
186        // Verify PostgreSQL port is exposed
187        let postgres_port = db_info.host_port_for(5432)
188            .expect("PostgreSQL port 5432 should be exposed");
189        println!("   PostgreSQL accessible at: localhost:{}", postgres_port);
190        
191        // In a real test, you would connect to the database
192        // For demo purposes, just verify the port information
193        assert!(postgres_port > 0, "PostgreSQL port should be valid");
194        
195        println!("✅ Database test passed");
196        Ok(())
197    });
198    
199    // Test 3: Access redis
200    test("test_redis_access", |ctx| {
201        println!("🧪 Testing redis access...");
202        
203        let redis_info = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info")
204            .expect("Redis container info should be available");
205        
206        println!("🔴 Redis container: {}", redis_info.container_id);
207        println!("   Ports: {}", redis_info.ports_summary());
208        
209        // Verify Redis port is exposed
210        let redis_port = redis_info.host_port_for(6379)
211            .expect("Redis port 6379 should be exposed");
212        println!("   Redis accessible at: localhost:{}", redis_port);
213        
214        // In a real test, you would connect to Redis
215        // For demo purposes, just verify the port information
216        assert!(redis_port > 0, "Redis port should be valid");
217        
218        println!("✅ Redis test passed");
219        Ok(())
220    });
221    
222    // Test 4: Mixed port configuration
223    test("test_mixed_port_config", |ctx| {
224        println!("🧪 Testing mixed port configuration...");
225        
226        let mixed_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info")
227            .expect("Mixed container info should be available");
228        
229        println!("🔀 Mixed container: {}", mixed_info.container_id);
230        println!("   Ports: {}", mixed_info.ports_summary());
231        
232        // Verify both manual and auto ports
233        let http_port = mixed_info.host_port_for(80)
234            .expect("HTTP port 80 should be exposed");
235        let https_port = mixed_info.host_port_for(443)
236            .expect("HTTPS port 443 should be exposed");
237        
238        println!("   HTTP accessible at: localhost:{}", http_port);
239        println!("   HTTPS accessible at: localhost:{}", https_port);
240        
241        // Verify the manual port mapping (8080 -> 80)
242        assert_eq!(http_port, 8080, "Manual port mapping should work");
243        
244        // Verify auto port is different from manual port
245        assert_ne!(https_port, 8080, "Auto port should be different from manual port");
246        
247        println!("✅ Mixed port configuration test passed");
248        Ok(())
249    });
250    
251    // Test 5: Container info methods
252    test("test_container_info_methods", |ctx| {
253        println!("🧪 Testing container info methods...");
254        
255        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
256            .expect("Web container info should be available");
257        
258        // Test all the convenience methods
259        println!("🔍 Testing container info methods for: {}", web_info.container_id);
260        
261        // Test primary_url
262        if let Some(url) = web_info.primary_url() {
263            println!("   Primary URL: {}", url);
264            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
265        }
266        
267        // Test url_for_port
268        if let Some(url) = web_info.url_for_port(80) {
269            println!("   URL for port 80: {}", url);
270            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
271        }
272        
273        // Test host_port_for
274        if let Some(host_port) = web_info.host_port_for(80) {
275            println!("   Host port for container port 80: {}", host_port);
276            assert!(host_port > 0, "Host port should be valid");
277        }
278        
279        // Test ports_summary
280        let summary = web_info.ports_summary();
281        println!("   Ports summary: {}", summary);
282        assert!(!summary.is_empty(), "Ports summary should not be empty");
283        
284        println!("✅ Container info methods test passed");
285        Ok(())
286    });
287    
288    println!("🚀 Running tests with auto-port functionality...");
289    println!();
290    
291    // Run the tests
292    let config = TestConfig {
293        html_report: Some("auto-port-demo-report.html".to_string()),
294        ..Default::default()
295    };
296    
297    let exit_code = run_tests_with_config(config);
298    
299    println!();
300    if exit_code == 0 {
301        println!("🎉 All tests passed! Auto-port functionality is working correctly.");
302        println!("📊 Check the HTML report for detailed results.");
303    } else {
304        println!("❌ Some tests failed. Check the output above for details.");
305    }
306    
307    std::process::exit(exit_code);
308}
examples/container_port_access.rs (line 70)
12fn main() {
13    println!("🌐 Container Port and URL Access Example");
14    println!("========================================");
15    println!();
16    
17    // Example 1: Web service with multiple auto-ports
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80)      // Auto-assign port for HTTP
20        .auto_port(443)     // Auto-assign port for HTTPS
21        .env("NGINX_HOST", "localhost")
22        .name("web_service")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Database with auto-port
26    let db_container = ContainerConfig::new("postgres:13-alpine")
27        .auto_port(5432)    // Auto-assign port for PostgreSQL
28        .env("POSTGRES_PASSWORD", "testpass")
29        .env("POSTGRES_DB", "testdb")
30        .name("test_database")
31        .ready_timeout(Duration::from_secs(20));
32    
33    // Example 3: Mixed configuration (manual + auto ports)
34    let api_container = ContainerConfig::new("httpd:alpine")
35        .port(8080, 80)     // Manual port mapping
36        .auto_port(9090)    // Auto-assign port for API
37        .auto_port(9091)    // Auto-assign port for metrics
38        .env("API_VERSION", "v1")
39        .name("api_service")
40        .ready_timeout(Duration::from_secs(15));
41    
42    println!("📋 Container Configurations:");
43    println!("1. Web Service:");
44    println!("   - Image: {}", web_container.image);
45    println!("   - Auto-ports: {:?}", web_container.auto_ports);
46    println!("   - Will auto-assign host ports for container ports 80 and 443");
47    
48    println!("2. Database:");
49    println!("   - Image: {}", db_container.image);
50    println!("   - Auto-ports: {:?}", db_container.auto_ports);
51    println!("   - Will auto-assign host port for container port 5432");
52    
53    println!("3. API Service:");
54    println!("   - Image: {}", api_container.image);
55    println!("   - Manual ports: {:?}", api_container.ports);
56    println!("   - Auto-ports: {:?}", api_container.auto_ports);
57    println!("   - Manual mapping: 8080 -> 80, Auto-assign: 9090, 9091");
58    println!();
59    
60    // Clone containers for hooks
61    let web_before = web_container.clone();
62    let db_before = db_container.clone();
63    let api_before = api_container.clone();
64    
65    // Start containers in before_each
66    before_each(move |ctx| {
67        println!("🚀 before_each: Starting containers and capturing port info...");
68        
69        // Start web container
70        let web_info = web_before.start()
71            .map_err(|e| format!("Failed to start web container: {}", e))?;
72        ctx.set_data("web_container_info", web_info.clone());
73        
74        println!("✅ Web container started: {}", web_info.container_id);
75        println!("   📍 Port mappings: {}", web_info.ports_summary());
76        println!("   🔗 Primary URL: {}", web_info.primary_url().unwrap_or("None"));
77        
78        // Show specific port access
79        if let Some(http_port) = web_info.host_port_for(80) {
80            println!("   🌐 HTTP accessible at: http://localhost:{}", http_port);
81        }
82        if let Some(https_port) = web_info.host_port_for(443) {
83            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
84        }
85        
86        // Start database container
87        let db_info = db_before.start()
88            .map_err(|e| format!("Failed to start db container: {}", e))?;
89        ctx.set_data("db_container_info", db_info.clone());
90        
91        println!("✅ Database container started: {}", db_info.container_id);
92        println!("   📍 Port mappings: {}", db_info.ports_summary());
93        if let Some(db_port) = db_info.host_port_for(5432) {
94            println!("   🗄️ PostgreSQL accessible at: localhost:{}", db_port);
95            println!("   📝 Connection string: postgresql://user:pass@localhost:{}/testdb", db_port);
96        }
97        
98        // Start API container
99        let api_info = api_before.start()
100            .map_err(|e| format!("Failed to start api container: {}", e))?;
101        ctx.set_data("api_container_info", api_info.clone());
102        
103        println!("✅ API container started: {}", api_info.container_id);
104        println!("   📍 Port mappings: {}", api_info.ports_summary());
105        
106        // Show both manual and auto ports
107        if let Some(http_port) = api_info.host_port_for(80) {
108            println!("   🌐 HTTP API at: http://localhost:{} (manual mapping)", http_port);
109        }
110        if let Some(api_port) = api_info.host_port_for(9090) {
111            println!("   🔧 API endpoint at: http://localhost:{} (auto-assigned)", api_port);
112        }
113        if let Some(metrics_port) = api_info.host_port_for(9091) {
114            println!("   📊 Metrics at: http://localhost:{} (auto-assigned)", metrics_port);
115        }
116        
117        println!("🎉 All containers started with auto-assigned ports!");
118        Ok(())
119    });
120    
121    // Cleanup containers in after_each
122    let web_after = web_container.clone();
123    let db_after = db_container.clone();
124    let api_after = api_container.clone();
125    
126    after_each(move |ctx| {
127        println!("🧹 after_each: Cleaning up containers...");
128        
129        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
130            let _ = web_after.stop(&web_info.container_id);
131            println!("🛑 Stopped web container: {}", web_info.container_id);
132        }
133        
134        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
135            let _ = db_after.stop(&db_info.container_id);
136            println!("🛑 Stopped database container: {}", db_info.container_id);
137        }
138        
139        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
140            let _ = api_after.stop(&api_info.container_id);
141            println!("🛑 Stopped API container: {}", api_info.container_id);
142        }
143        
144        println!("✅ All containers cleaned up!");
145        Ok(())
146    });
147    
148    // Test 1: Web service port access
149    test("test_web_service_port_access", |ctx| {
150        println!("🧪 Testing web service port access...");
151        
152        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
153            .expect("Web container info should be available");
154        
155        println!("🔍 Demonstrating port access methods:");
156        
157        // Method 1: Get specific host port for container port
158        if let Some(http_port) = web_info.host_port_for(80) {
159            println!("   ✅ HTTP port 80 is mapped to host port: {}", http_port);
160            println!("      💡 Use this for HTTP client connections");
161        }
162        
163        if let Some(https_port) = web_info.host_port_for(443) {
164            println!("   ✅ HTTPS port 443 is mapped to host port: {}", https_port);
165            println!("      💡 Use this for HTTPS client connections");
166        }
167        
168        // Method 2: Get ready-to-use URLs
169        if let Some(http_url) = web_info.url_for_port(80) {
170            println!("   🔗 HTTP URL: {}", http_url);
171            println!("      💡 Ready to use in HTTP requests");
172        }
173        
174        if let Some(https_url) = web_info.url_for_port(443) {
175            println!("   🔗 HTTPS URL: {}", https_url);
176            println!("      💡 Ready to use in HTTPS requests (change http:// to https://)");
177        }
178        
179        // Method 3: Get all URLs
180        println!("   📋 All service URLs:");
181        for (i, url) in web_info.urls.iter().enumerate() {
182            println!("      {}. {}", i + 1, url);
183        }
184        
185        // Method 4: Get all port mappings
186        println!("   📊 All port mappings:");
187        for (host_port, container_port) in &web_info.port_mappings {
188            println!("      Host {} -> Container {}", host_port, container_port);
189        }
190        
191        // Verify ports are different (auto-assigned)
192        assert!(web_info.host_port_for(80).unwrap() != web_info.host_port_for(443).unwrap(), 
193                "Auto-assigned ports should be different");
194        
195        println!("✅ Web service port access test passed");
196        Ok(())
197    });
198    
199    // Test 2: Database connection string generation
200    test("test_database_connection_info", |ctx| {
201        println!("🧪 Testing database connection info generation...");
202        
203        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
204            .expect("Database container info should be available");
205        
206        println!("🗄️ Database connection information:");
207        
208        // Get the auto-assigned port for PostgreSQL
209        let db_port = db_info.host_port_for(5432)
210            .expect("PostgreSQL port should be exposed");
211        
212        println!("   📍 PostgreSQL running on: localhost:{}", db_port);
213        
214        // Generate connection strings using the auto-assigned port
215        let connection_string = format!("postgresql://admin:testpass@localhost:{}/testdb", db_port);
216        let jdbc_url = format!("jdbc:postgresql://localhost:{}/testdb", db_port);
217        let docker_internal = format!("postgresql://admin:testpass@{}:5432/testdb", db_info.container_id);
218        
219        println!("   🔗 Connection strings:");
220        println!("      Standard: {}", connection_string);
221        println!("      JDBC: {}", jdbc_url);
222        println!("      Docker internal: {}", docker_internal);
223        
224        // Show how to use this in real applications
225        println!("   💡 Usage examples:");
226        println!("      - Set DATABASE_URL={}", connection_string);
227        println!("      - Use in tests: connect to localhost:{}", db_port);
228        println!("      - Container-to-container: use port 5432");
229        
230        // Verify port is valid
231        assert!(db_port > 0, "Database port should be valid");
232        println!("✅ Database connection info test passed");
233        
234        Ok(())
235    });
236    
237    // Test 3: Mixed port configuration
238    test("test_mixed_port_configuration", |ctx| {
239        println!("🧪 Testing mixed port configuration (manual + auto)...");
240        
241        let api_info = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info")
242            .expect("API container info should be available");
243        
244        println!("🔀 Mixed port configuration analysis:");
245        
246        // Manual port mapping
247        let http_port = api_info.host_port_for(80)
248            .expect("HTTP port should be mapped");
249        println!("   📌 Manual mapping - HTTP port 80 -> host port: {}", http_port);
250        assert_eq!(http_port, 8080, "Manual port should be exactly as specified");
251        
252        // Auto-assigned ports
253        let api_port = api_info.host_port_for(9090)
254            .expect("API port should be auto-assigned");
255        let metrics_port = api_info.host_port_for(9091)
256            .expect("Metrics port should be auto-assigned");
257        
258        println!("   🎲 Auto-assigned - API port 9090 -> host port: {}", api_port);
259        println!("   🎲 Auto-assigned - Metrics port 9091 -> host port: {}", metrics_port);
260        
261        // Verify auto-assigned ports are different from manual port
262        assert_ne!(api_port, 8080, "Auto-assigned port should be different from manual port");
263        assert_ne!(metrics_port, 8080, "Auto-assigned port should be different from manual port");
264        assert_ne!(api_port, metrics_port, "Auto-assigned ports should be different from each other");
265        
266        println!("   🌐 Service endpoints:");
267        println!("      Main API: http://localhost:{}/", http_port);
268        println!("      API v2: http://localhost:{}/", api_port);
269        println!("      Metrics: http://localhost:{}/metrics", metrics_port);
270        
271        // Show complete port summary
272        println!("   📋 Complete port summary: {}", api_info.ports_summary());
273        
274        println!("✅ Mixed port configuration test passed");
275        Ok(())
276    });
277    
278    // Test 4: Container info convenience methods
279    test("test_container_info_convenience_methods", |ctx| {
280        println!("🧪 Testing ContainerInfo convenience methods...");
281        
282        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
283            .expect("Web container info should be available");
284        
285        println!("🔧 Testing all ContainerInfo methods:");
286        
287        // Test primary_url()
288        if let Some(primary_url) = web_info.primary_url() {
289            println!("   ✅ primary_url(): {}", primary_url);
290            assert!(primary_url.starts_with("http://localhost:"), "Primary URL should be valid");
291        }
292        
293        // Test url_for_port()
294        if let Some(url_80) = web_info.url_for_port(80) {
295            println!("   ✅ url_for_port(80): {}", url_80);
296            assert!(url_80.contains("localhost:"), "URL should contain localhost");
297        }
298        
299        // Test host_port_for()
300        if let Some(port_80) = web_info.host_port_for(80) {
301            println!("   ✅ host_port_for(80): {}", port_80);
302            assert!(port_80 > 0, "Port should be positive");
303        }
304        
305        // Test ports_summary()
306        let summary = web_info.ports_summary();
307        println!("   ✅ ports_summary(): {}", summary);
308        assert!(summary.contains("->"), "Summary should contain port mappings");
309        
310        // Test direct field access
311        println!("   ✅ container_id: {}", web_info.container_id);
312        println!("   ✅ image: {}", web_info.image);
313        println!("   ✅ auto_cleanup: {}", web_info.auto_cleanup);
314        
315        println!("   📊 All URLs:");
316        for (i, url) in web_info.urls.iter().enumerate() {
317            println!("      {}. {}", i + 1, url);
318        }
319        
320        println!("   📊 All port mappings:");
321        for (host_port, container_port) in &web_info.port_mappings {
322            println!("      {} -> {}", host_port, container_port);
323        }
324        
325        println!("✅ Container info convenience methods test passed");
326        Ok(())
327    });
328    
329    // Test 5: Real-world usage patterns
330    test("test_real_world_usage_patterns", |ctx| {
331        println!("🧪 Testing real-world usage patterns...");
332        
333        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
334            .expect("Web container info should be available");
335        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
336            .expect("Database container info should be available");
337        
338        println!("🌍 Real-world usage examples:");
339        
340        // Pattern 1: HTTP client testing
341        if let Some(web_url) = web_info.primary_url() {
342            println!("   🌐 HTTP Client Testing:");
343            println!("      Base URL: {}", web_url);
344            println!("      GET {}/health", web_url);
345            println!("      POST {}/api/users", web_url);
346            println!("      Code: let response = reqwest::get(\"{}/health\").await?;", web_url);
347        }
348        
349        // Pattern 2: Database testing
350        if let Some(db_port) = db_info.host_port_for(5432) {
351            println!("   🗄️ Database Testing:");
352            println!("      Connection: localhost:{}", db_port);
353            println!("      Code: let conn = PgConnection::establish(\"postgresql://user:pass@localhost:{}/db\")?;", db_port);
354        }
355        
356        // Pattern 3: Environment variable setup
357        println!("   🔧 Environment Variables:");
358        if let Some(web_port) = web_info.host_port_for(80) {
359            println!("      export WEB_SERVICE_URL=http://localhost:{}", web_port);
360        }
361        if let Some(db_port) = db_info.host_port_for(5432) {
362            println!("      export DATABASE_URL=postgresql://localhost:{}/testdb", db_port);
363        }
364        
365        // Pattern 4: Docker-compose style networking
366        println!("   🐳 Container Networking:");
367        println!("      External: Use auto-assigned host ports");
368        println!("      Internal: Use original container ports");
369        println!("      Web -> DB: {}:5432 (container-to-container)", db_info.container_id);
370        
371        // Pattern 5: Health checks
372        println!("   ❤️ Health Checks:");
373        if let Some(web_url) = web_info.primary_url() {
374            println!("      Health endpoint: {}/health", web_url);
375            println!("      Ready endpoint: {}/ready", web_url);
376        }
377        
378        println!("✅ Real-world usage patterns test passed");
379        Ok(())
380    });
381    
382    println!("🚀 Running container port access tests...");
383    println!();
384    
385    // Run the tests
386    let config = TestConfig {
387        html_report: Some("container-port-access-report.html".to_string()),
388        ..Default::default()
389    };
390    
391    let exit_code = run_tests_with_config(config);
392    
393    println!();
394    if exit_code == 0 {
395        println!("🎉 All tests passed! Port access functionality is working correctly.");
396        println!("📊 Check the HTML report for detailed results.");
397        println!();
398        println!("💡 Key Takeaways:");
399        println!("   • Use auto_port() to avoid port conflicts");
400        println!("   • Access host ports with host_port_for(container_port)");
401        println!("   • Get ready-to-use URLs with url_for_port(container_port)");
402        println!("   • Use ports_summary() for human-readable port info");
403        println!("   • ContainerInfo provides complete access to all port information");
404    } else {
405        println!("❌ Some tests failed. Check the output above for details.");
406    }
407    
408    std::process::exit(exit_code);
409}
Source

pub fn stop( &self, container_id: &str, ) -> Result<(), Box<dyn Error + Send + Sync>>

Stop a container by ID using Docker API

Examples found in repository?
examples/user_specified_ports.rs (line 99)
12fn main() {
13    println!("🔧 User-Specified Ports Example");
14    println!("==============================");
15    println!();
16    
17    // Example 1: PostgreSQL on standard port 5432
18    let postgres_container = ContainerConfig::new("postgres:13-alpine")
19        .port(5432, 5432)     // Map host port 5432 to container port 5432
20        .env("POSTGRES_PASSWORD", "testpass")
21        .env("POSTGRES_DB", "testdb")
22        .name("postgres_test")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Web service on port 8080
26    let web_container = ContainerConfig::new("nginx:alpine")
27        .port(8080, 80)       // Map host port 8080 to container port 80
28        .name("nginx_test")
29        .ready_timeout(Duration::from_secs(10));
30    
31    // Example 3: Mixed configuration - some fixed, some auto
32    let api_container = ContainerConfig::new("httpd:alpine")
33        .port(3000, 80)       // Fixed port for main API
34        .auto_port(443)       // Auto-assign for HTTPS
35        .auto_port(9090)      // Auto-assign for metrics
36        .name("api_test")
37        .ready_timeout(Duration::from_secs(10));
38    
39    println!("📋 Container Configurations:");
40    println!("1. PostgreSQL: Fixed on localhost:5432 (standard PostgreSQL port)");
41    println!("2. Web Service: Fixed on localhost:8080");
42    println!("3. API Service: Fixed localhost:3000, auto-assigned for 443 and 9090");
43    println!();
44    
45    // Clone containers for hooks
46    let postgres_before = postgres_container.clone();
47    let web_before = web_container.clone();
48    let api_before = api_container.clone();
49    
50    // Start containers in before_each
51    before_each(move |ctx| {
52        println!("🚀 before_each: Starting containers with specified ports...");
53        
54        // Start PostgreSQL container
55        let postgres_info = postgres_before.start()
56            .map_err(|e| format!("Failed to start PostgreSQL container: {}", e))?;
57        ctx.set_data("postgres_container_info", postgres_info.clone());
58        
59        println!("✅ PostgreSQL started: {}", postgres_info.container_id);
60        println!("   📍 Port mappings: {}", postgres_info.ports_summary());
61        println!("   🗄️ Database URL: postgresql://postgres:testpass@localhost:5432/testdb");
62        
63        // Start web container
64        let web_info = web_before.start()
65            .map_err(|e| format!("Failed to start web container: {}", e))?;
66        ctx.set_data("web_container_info", web_info.clone());
67        
68        println!("✅ Web service started: {}", web_info.container_id);
69        println!("   📍 Port mappings: {}", web_info.ports_summary());
70        println!("   🌐 Web accessible at: http://localhost:8080");
71        
72        // Start API container
73        let api_info = api_before.start()
74            .map_err(|e| format!("Failed to start API container: {}", e))?;
75        ctx.set_data("api_container_info", api_info.clone());
76        
77        println!("✅ API service started: {}", api_info.container_id);
78        println!("   📍 Port mappings: {}", api_info.ports_summary());
79        println!("   🔗 API accessible at: http://localhost:3000");
80        if let Some(https_port) = api_info.host_port_for(443) {
81            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
82        }
83        if let Some(metrics_port) = api_info.host_port_for(9090) {
84            println!("   📊 Metrics accessible at: http://localhost:{}/metrics", metrics_port);
85        }
86        
87        Ok(())
88    });
89    
90    // Cleanup containers in after_each
91    let postgres_after = postgres_container.clone();
92    let web_after = web_container.clone();
93    let api_after = api_container.clone();
94    
95    after_each(move |ctx| {
96        println!("🧹 after_each: Cleaning up containers...");
97        
98        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
99            let _ = postgres_after.stop(&postgres_info.container_id);
100            println!("🛑 Stopped PostgreSQL container");
101        }
102        
103        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
104            let _ = web_after.stop(&web_info.container_id);
105            println!("🛑 Stopped web container");
106        }
107        
108        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
109            let _ = api_after.stop(&api_info.container_id);
110            println!("🛑 Stopped API container");
111        }
112        
113        println!("✅ All containers cleaned up!");
114        Ok(())
115    });
116    
117    // Test 1: Database connection test
118    test("test_database_connection", |ctx| {
119        println!("🧪 Testing database connection on fixed port 5432...");
120        
121        if let Some(postgres_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("postgres_container_info") {
122            assert_eq!(postgres_info.host_port_for(5432), Some(5432));
123            assert_eq!(postgres_info.url_for_port(5432), Some("localhost:5432".to_string()));
124            println!("✅ Database is accessible on the expected port 5432");
125        } else {
126            return Err("PostgreSQL container info not found".into());
127        }
128        
129        Ok(())
130    });
131    
132    // Test 2: Web service test
133    test("test_web_service_fixed_port", |ctx| {
134        println!("🧪 Testing web service on fixed port 8080...");
135        
136        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
137            assert_eq!(web_info.host_port_for(80), Some(8080));
138            assert_eq!(web_info.url_for_port(80), Some("localhost:8080".to_string()));
139            println!("✅ Web service is accessible on the expected port 8080");
140        } else {
141            return Err("Web container info not found".into());
142        }
143        
144        Ok(())
145    });
146    
147    // Test 3: Mixed configuration test
148    test("test_mixed_port_configuration", |ctx| {
149        println!("🧪 Testing mixed port configuration (fixed + auto)...");
150        
151        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
152            // Test fixed port
153            assert_eq!(api_info.host_port_for(80), Some(3000));
154            assert_eq!(api_info.url_for_port(80), Some("localhost:3000".to_string()));
155            println!("✅ Fixed port 3000 -> 80 is working");
156            
157            // Test auto-assigned ports
158            if let Some(https_port) = api_info.host_port_for(443) {
159                assert!(https_port > 1024); // Should be a high port
160                println!("✅ Auto-assigned HTTPS port: {}", https_port);
161            }
162            
163            if let Some(metrics_port) = api_info.host_port_for(9090) {
164                assert!(metrics_port > 1024); // Should be a high port
165                println!("✅ Auto-assigned metrics port: {}", metrics_port);
166            }
167            
168            println!("✅ Mixed configuration is working correctly");
169        } else {
170            return Err("API container info not found".into());
171        }
172        
173        Ok(())
174    });
175    
176    println!("🚀 Running user-specified ports tests...");
177    
178    let config = TestConfig {
179        html_report: Some("user-specified-ports-report.html".to_string()),
180        ..Default::default()
181    };
182    
183    let exit_code = run_tests_with_config(config);
184    
185    println!();
186    println!("🎉 Tests completed!");
187    println!("📊 Check the HTML report for detailed results.");
188    println!();
189    println!("💡 Key Takeaways:");
190    println!("   • Use .port(host_port, container_port) for fixed port mappings");
191    println!("   • Use .auto_port(container_port) for automatic port assignment");
192    println!("   • Mix both approaches for maximum flexibility");
193    println!("   • Fixed ports are great for services with standard ports (5432, 3306, etc.)");
194    println!("   • Auto-ports prevent conflicts in parallel test environments");
195    
196    std::process::exit(exit_code);
197}
More examples
Hide additional examples
examples/mongodb_integration.rs (line 124)
68fn main() {
69    println!("🐳 MongoDB Integration Example with Container Hooks");
70    println!("==================================================");
71    println!();
72    
73    // Define container configuration with auto-port for MongoDB
74    let mongo_container = ContainerConfig::new("mongo:5.0")
75        .auto_port(27017) // Automatically assign available host port for MongoDB
76        .env("MONGO_INITDB_ROOT_USERNAME", "admin")
77        .env("MONGO_INITDB_ROOT_PASSWORD", "password")
78        .name("test_mongodb")
79        .ready_timeout(Duration::from_secs(30));
80    
81    println!("📋 Container Configuration:");
82    println!("  Image: {}", mongo_container.image);
83    println!("  Auto-ports: {:?}", mongo_container.auto_ports);
84    println!("  Environment: {:?}", mongo_container.env);
85    println!("  Name: {:?}", mongo_container.name);
86    println!("  Ready Timeout: {:?}", mongo_container.ready_timeout);
87    println!("  Auto-cleanup: {}", mongo_container.auto_cleanup);
88    println!();
89    
90    // Clone for before_each hook
91    let mongo_container_before = mongo_container.clone();
92    
93    // Register before_each hook to start container
94    before_each(move |ctx| {
95        println!("🔄 before_each: Starting MongoDB container...");
96        
97        // Start the container and get ContainerInfo
98        let container_info = mongo_container_before.start()
99            .map_err(|e| format!("Failed to start container: {}", e))?;
100        
101        // Store container info in context for tests to access
102        ctx.set_data("mongo_container_info", container_info.clone());
103        
104        // Log container details including auto-assigned ports
105        println!("✅ before_each: MongoDB container {} started", container_info.container_id);
106        println!("🌐 Container exposed on: {}", container_info.ports_summary());
107        if let Some(primary_url) = container_info.primary_url() {
108            println!("🔗 Primary URL: {}", primary_url);
109        }
110        
111        Ok(())
112    });
113    
114    // Register after_each hook to stop container
115    let mongo_container_after = mongo_container.clone();
116    rust_test_harness::after_each(move |ctx| {
117        println!("🔄 after_each: Stopping MongoDB container...");
118        
119        // Get container info from context
120        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
121            .expect("Container info should be available");
122        
123        // Stop the container
124        mongo_container_after.stop(&container_info.container_id)
125            .map_err(|e| format!("Failed to stop container: {}", e))?;
126        
127        println!("✅ after_each: MongoDB container {} stopped", container_info.container_id);
128        Ok(())
129    });
130    
131    // Test 1: Basic MongoDB operations
132    test("test_mongodb_basic_operations", |ctx| {
133        println!("🧪 Running test: test_mongodb_basic_operations");
134        
135        // Get container info from context
136        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
137            .expect("Container info should be available");
138        
139        // Show how to access port information
140        println!("🌐 Container {} is running on:", container_info.container_id);
141        println!("   Ports: {}", container_info.ports_summary());
142        if let Some(primary_url) = container_info.primary_url() {
143            println!("   Primary URL: {}", primary_url);
144        }
145        
146        // Get the MongoDB port (27017) and show the actual host port
147        if let Some(host_port) = container_info.host_port_for(27017) {
148            println!("   MongoDB accessible at: localhost:{}", host_port);
149        }
150        
151        // Create MongoDB client
152        let mut client = MongoClient::new(container_info.container_id.clone());
153        
154        // Connect to MongoDB
155        client.connect()?;
156        
157        // Insert a document
158        client.insert_document("users", r#"{"name": "John Doe", "email": "john@example.com"}"#)?;
159        
160        // Find documents
161        let documents = client.find_documents("users", r#"{"name": "John Doe"}"#)?;
162        assert_eq!(documents.len(), 2);
163        
164        // Disconnect
165        client.disconnect()?;
166        
167        println!("✅ test_mongodb_basic_operations passed");
168        Ok(())
169    });
170    
171    // Test 2: Multiple operations
172    test("test_mongodb_multiple_operations", |ctx| {
173        println!("🧪 Running test: test_mongodb_multiple_operations");
174        
175        // Get container info from context
176        let container_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mongo_container_info")
177            .expect("Container info should be available");
178        
179        // Show container status
180        println!("🌐 Container {} status:", container_info.container_id);
181        println!("   Active ports: {}", container_info.ports_summary());
182        
183        // Create MongoDB client
184        let mut client = MongoClient::new(container_info.container_id.clone());
185        
186        // Connect to MongoDB
187        client.connect()?;
188        
189        // Insert multiple documents
190        client.insert_document("products", r#"{"name": "Laptop", "price": 999.99}"#)?;
191        client.insert_document("products", r#"{"name": "Mouse", "price": 29.99}"#)?;
192        client.insert_document("products", r#"{"name": "Keyboard", "price": 79.99}"#)?;
193        
194        // Find documents
195        let documents = client.find_documents("products", r#"{"price": {"$gt": 50}}"#)?;
196        assert_eq!(documents.len(), 2); // Laptop and Keyboard
197        
198        // Disconnect
199        client.disconnect()?;
200        
201        println!("✅ test_mongodb_multiple_operations passed");
202        Ok(())
203    });
204    
205    // Test 3: Error handling
206    test("test_mongodb_error_handling", |ctx| {
207        println!("🧪 Running test: test_mongodb_error_handling");
208        
209        // Get container ID from context
210        let container_id = ctx.get_data::<String>("mongo_container_id")
211            .expect("Container ID should be available")
212            .to_string();
213        
214        // Create MongoDB client
215        let client = MongoClient::new(container_id);
216        
217        // Try to insert without connecting (should fail)
218        let result = client.insert_document("users", r#"{"name": "Test"}"#);
219        assert!(result.is_err());
220        assert_eq!(result.unwrap_err(), "Not connected to MongoDB");
221        
222        println!("✅ test_mongodb_error_handling passed");
223        Ok(())
224    });
225    
226    // Test 4: Performance testing
227    test("test_mongodb_performance", |ctx| {
228        println!("🧪 Running test: test_mongodb_performance");
229        
230        // Get container ID from context
231        let container_id = ctx.get_data::<String>("mongo_container_id")
232            .expect("Container ID should be available")
233            .to_string();
234        
235        // Create MongoDB client
236        let mut client = MongoClient::new(container_id);
237        
238        // Connect to MongoDB
239        client.connect()?;
240        
241        // Simulate bulk operations
242        for i in 0..100 {
243            client.insert_document("bulk_data", &format!(r#"{{"index": {}, "data": "bulk_item_{}"}}"#, i, i))?;
244        }
245        
246        // Simulate bulk retrieval
247        let documents = client.find_documents("bulk_data", r#"{"index": {"$lt": 50}}"#)?;
248        assert_eq!(documents.len(), 2); // Mock always returns 2
249        
250        // Disconnect
251        client.disconnect()?;
252        
253        println!("✅ test_mongodb_performance passed");
254        Ok(())
255    });
256    
257    println!("\n🚀 Running MongoDB integration tests...");
258    println!("   Each test will get a fresh MongoDB container via before_each");
259    println!("   Each test will clean up its container via after_each");
260    println!();
261    
262    // Run tests with container hooks enabled
263    let config = TestConfig {
264        skip_hooks: Some(false),
265        ..Default::default()
266    };
267    
268    let result = run_tests_with_config(config);
269    
270    println!("\n📊 Test Results:");
271    if result == 0 {
272        println!("✅ All MongoDB integration tests passed!");
273        println!("🎯 Container lifecycle management working correctly");
274        println!("🐳 Each test got its own MongoDB container");
275        println!("🧹 Each test cleaned up its container properly");
276    } else {
277        println!("❌ Some tests failed");
278    }
279    
280    println!("\n💡 Key Benefits of this approach:");
281    println!("   • Clean separation of concerns");
282    println!("   • Each test gets a fresh container");
283    println!("   • Automatic cleanup via after_each");
284    println!("   • Easy to configure containers");
285    println!("   • No complex global state management");
286}
examples/auto_port_demo.rs (line 134)
12fn main() {
13    println!("🚀 Auto-Port and Container Management Demo");
14    println!("==========================================");
15    println!();
16    
17    // Example 1: Web service with auto-port
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80) // Automatically assign host port for container port 80
20        .env("NGINX_HOST", "localhost")
21        .name("web_service")
22        .ready_timeout(Duration::from_secs(15));
23    
24    // Example 2: Database with auto-port
25    let db_container = ContainerConfig::new("postgres:13-alpine")
26        .auto_port(5432) // Automatically assign host port for container port 5432
27        .env("POSTGRES_PASSWORD", "testpass")
28        .env("POSTGRES_DB", "testdb")
29        .name("test_database")
30        .ready_timeout(Duration::from_secs(20));
31    
32    // Example 3: Redis with auto-port
33    let redis_container = ContainerConfig::new("redis:6-alpine")
34        .auto_port(6379) // Automatically assign host port for container port 6379
35        .name("test_redis")
36        .ready_timeout(Duration::from_secs(10));
37    
38    // Example 4: Mixed configuration (manual + auto ports)
39    let mixed_container = ContainerConfig::new("httpd:alpine")
40        .port(8080, 80) // Manual port mapping
41        .auto_port(443) // Auto port for HTTPS
42        .env("APACHE_DOCUMENT_ROOT", "/var/www/html")
43        .name("mixed_ports")
44        .ready_timeout(Duration::from_secs(15));
45    
46    println!("📋 Container Configurations:");
47    println!("1. Web Service (nginx):");
48    println!("   - Image: {}", web_container.image);
49    println!("   - Auto-ports: {:?}", web_container.auto_ports);
50    println!("   - Auto-cleanup: {}", web_container.auto_cleanup);
51    
52    println!("2. Database (postgres):");
53    println!("   - Image: {}", db_container.image);
54    println!("   - Auto-ports: {:?}", db_container.auto_ports);
55    println!("   - Auto-cleanup: {}", db_container.auto_cleanup);
56    
57    println!("3. Cache (redis):");
58    println!("   - Image: {}", redis_container.image);
59    println!("   - Auto-ports: {:?}", redis_container.auto_ports);
60    println!("   - Auto-cleanup: {}", redis_container.auto_cleanup);
61    
62    println!("4. Mixed (httpd):");
63    println!("   - Image: {}", mixed_container.image);
64    println!("   - Manual ports: {:?}", mixed_container.ports);
65    println!("   - Auto-ports: {:?}", mixed_container.auto_ports);
66    println!("   - Auto-cleanup: {}", mixed_container.auto_cleanup);
67    println!();
68    
69    // Clone containers for hooks
70    let web_before = web_container.clone();
71    let db_before = db_container.clone();
72    let redis_before = redis_container.clone();
73    let mixed_before = mixed_container.clone();
74    
75    // Start all containers in before_each for each test
76    before_each(move |ctx| {
77        println!("🚀 before_each: Starting all containers...");
78        
79        // Start web container
80        let web_info = web_before.start()
81            .map_err(|e| format!("Failed to start web container: {}", e))?;
82        ctx.set_data("web_container_info", web_info.clone());
83        println!("✅ Web container started: {}", web_info.container_id);
84        println!("   Ports: {}", web_info.ports_summary());
85        if let Some(url) = web_info.primary_url() {
86            println!("   URL: {}", url);
87        }
88        
89        // Start database container
90        let db_info = db_before.start()
91            .map_err(|e| format!("Failed to start db container: {}", e))?;
92        ctx.set_data("db_container_info", db_info.clone());
93        println!("✅ Database container started: {}", db_info.container_id);
94        println!("   Ports: {}", db_info.ports_summary());
95        if let Some(host_port) = db_info.host_port_for(5432) {
96            println!("   PostgreSQL accessible at: localhost:{}", host_port);
97        }
98        
99        // Start redis container
100        let redis_info = redis_before.start()
101            .map_err(|e| format!("Failed to start redis container: {}", e))?;
102        ctx.set_data("redis_container_info", redis_info.clone());
103        println!("✅ Redis container started: {}", redis_info.container_id);
104        println!("   Ports: {}", redis_info.ports_summary());
105        if let Some(host_port) = redis_info.host_port_for(6379) {
106            println!("   Redis accessible at: localhost:{}", host_port);
107        }
108        
109        // Start mixed container
110        let mixed_info = mixed_before.start()
111            .map_err(|e| format!("Failed to start mixed container: {}", e))?;
112        ctx.set_data("mixed_container_info", mixed_info.clone());
113        println!("✅ Mixed container started: {}", mixed_info.container_id);
114        println!("   Ports: {}", mixed_info.ports_summary());
115        if let Some(host_port) = mixed_info.host_port_for(443) {
116            println!("   HTTPS accessible at: localhost:{}", host_port);
117        }
118        
119        println!("🎉 All containers started successfully!");
120        Ok(())
121    });
122    
123    // Cleanup all containers in after_each for each test
124    let web_after = web_container.clone();
125    let db_after = db_container.clone();
126    let redis_after = redis_container.clone();
127    let mixed_after = mixed_container.clone();
128    
129    after_each(move |ctx| {
130        println!("🧹 after_each: Cleaning up all containers...");
131        
132        // Get all container info and stop them
133        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
134            let _ = web_after.stop(&web_info.container_id);
135            println!("🛑 Stopped web container: {}", web_info.container_id);
136        }
137        
138        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
139            let _ = db_after.stop(&db_info.container_id);
140            println!("🛑 Stopped database container: {}", db_info.container_id);
141        }
142        
143        if let Some(redis_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info") {
144            let _ = redis_after.stop(&redis_info.container_id);
145            println!("🛑 Stopped redis container: {}", redis_info.container_id);
146        }
147        
148        if let Some(mixed_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info") {
149            let _ = mixed_after.stop(&mixed_info.container_id);
150            println!("🛑 Stopped mixed container: {}", mixed_info.container_id);
151        }
152        
153        println!("✅ All containers cleaned up!");
154        Ok(())
155    });
156    
157    // Test 1: Access web service
158    test("test_web_service_access", |ctx| {
159        println!("🧪 Testing web service access...");
160        
161        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
162            .expect("Web container info should be available");
163        
164        println!("🌐 Web service container: {}", web_info.container_id);
165        println!("   Ports: {}", web_info.ports_summary());
166        println!("   Primary URL: {}", web_info.primary_url().unwrap_or("None"));
167        
168        // In a real test, you would make HTTP requests to the container
169        // For demo purposes, just verify the port information
170        assert!(web_info.host_port_for(80).is_some(), "Web service should have port 80 exposed");
171        
172        println!("✅ Web service test passed");
173        Ok(())
174    });
175    
176    // Test 2: Access database
177    test("test_database_access", |ctx| {
178        println!("🧪 Testing database access...");
179        
180        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
181            .expect("Database container info should be available");
182        
183        println!("🗄️ Database container: {}", db_info.container_id);
184        println!("   Ports: {}", db_info.ports_summary());
185        
186        // Verify PostgreSQL port is exposed
187        let postgres_port = db_info.host_port_for(5432)
188            .expect("PostgreSQL port 5432 should be exposed");
189        println!("   PostgreSQL accessible at: localhost:{}", postgres_port);
190        
191        // In a real test, you would connect to the database
192        // For demo purposes, just verify the port information
193        assert!(postgres_port > 0, "PostgreSQL port should be valid");
194        
195        println!("✅ Database test passed");
196        Ok(())
197    });
198    
199    // Test 3: Access redis
200    test("test_redis_access", |ctx| {
201        println!("🧪 Testing redis access...");
202        
203        let redis_info = ctx.get_data::<rust_test_harness::ContainerInfo>("redis_container_info")
204            .expect("Redis container info should be available");
205        
206        println!("🔴 Redis container: {}", redis_info.container_id);
207        println!("   Ports: {}", redis_info.ports_summary());
208        
209        // Verify Redis port is exposed
210        let redis_port = redis_info.host_port_for(6379)
211            .expect("Redis port 6379 should be exposed");
212        println!("   Redis accessible at: localhost:{}", redis_port);
213        
214        // In a real test, you would connect to Redis
215        // For demo purposes, just verify the port information
216        assert!(redis_port > 0, "Redis port should be valid");
217        
218        println!("✅ Redis test passed");
219        Ok(())
220    });
221    
222    // Test 4: Mixed port configuration
223    test("test_mixed_port_config", |ctx| {
224        println!("🧪 Testing mixed port configuration...");
225        
226        let mixed_info = ctx.get_data::<rust_test_harness::ContainerInfo>("mixed_container_info")
227            .expect("Mixed container info should be available");
228        
229        println!("🔀 Mixed container: {}", mixed_info.container_id);
230        println!("   Ports: {}", mixed_info.ports_summary());
231        
232        // Verify both manual and auto ports
233        let http_port = mixed_info.host_port_for(80)
234            .expect("HTTP port 80 should be exposed");
235        let https_port = mixed_info.host_port_for(443)
236            .expect("HTTPS port 443 should be exposed");
237        
238        println!("   HTTP accessible at: localhost:{}", http_port);
239        println!("   HTTPS accessible at: localhost:{}", https_port);
240        
241        // Verify the manual port mapping (8080 -> 80)
242        assert_eq!(http_port, 8080, "Manual port mapping should work");
243        
244        // Verify auto port is different from manual port
245        assert_ne!(https_port, 8080, "Auto port should be different from manual port");
246        
247        println!("✅ Mixed port configuration test passed");
248        Ok(())
249    });
250    
251    // Test 5: Container info methods
252    test("test_container_info_methods", |ctx| {
253        println!("🧪 Testing container info methods...");
254        
255        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
256            .expect("Web container info should be available");
257        
258        // Test all the convenience methods
259        println!("🔍 Testing container info methods for: {}", web_info.container_id);
260        
261        // Test primary_url
262        if let Some(url) = web_info.primary_url() {
263            println!("   Primary URL: {}", url);
264            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
265        }
266        
267        // Test url_for_port
268        if let Some(url) = web_info.url_for_port(80) {
269            println!("   URL for port 80: {}", url);
270            assert!(url.starts_with("http://localhost:"), "URL should start with http://localhost:");
271        }
272        
273        // Test host_port_for
274        if let Some(host_port) = web_info.host_port_for(80) {
275            println!("   Host port for container port 80: {}", host_port);
276            assert!(host_port > 0, "Host port should be valid");
277        }
278        
279        // Test ports_summary
280        let summary = web_info.ports_summary();
281        println!("   Ports summary: {}", summary);
282        assert!(!summary.is_empty(), "Ports summary should not be empty");
283        
284        println!("✅ Container info methods test passed");
285        Ok(())
286    });
287    
288    println!("🚀 Running tests with auto-port functionality...");
289    println!();
290    
291    // Run the tests
292    let config = TestConfig {
293        html_report: Some("auto-port-demo-report.html".to_string()),
294        ..Default::default()
295    };
296    
297    let exit_code = run_tests_with_config(config);
298    
299    println!();
300    if exit_code == 0 {
301        println!("🎉 All tests passed! Auto-port functionality is working correctly.");
302        println!("📊 Check the HTML report for detailed results.");
303    } else {
304        println!("❌ Some tests failed. Check the output above for details.");
305    }
306    
307    std::process::exit(exit_code);
308}
examples/container_port_access.rs (line 130)
12fn main() {
13    println!("🌐 Container Port and URL Access Example");
14    println!("========================================");
15    println!();
16    
17    // Example 1: Web service with multiple auto-ports
18    let web_container = ContainerConfig::new("nginx:alpine")
19        .auto_port(80)      // Auto-assign port for HTTP
20        .auto_port(443)     // Auto-assign port for HTTPS
21        .env("NGINX_HOST", "localhost")
22        .name("web_service")
23        .ready_timeout(Duration::from_secs(15));
24    
25    // Example 2: Database with auto-port
26    let db_container = ContainerConfig::new("postgres:13-alpine")
27        .auto_port(5432)    // Auto-assign port for PostgreSQL
28        .env("POSTGRES_PASSWORD", "testpass")
29        .env("POSTGRES_DB", "testdb")
30        .name("test_database")
31        .ready_timeout(Duration::from_secs(20));
32    
33    // Example 3: Mixed configuration (manual + auto ports)
34    let api_container = ContainerConfig::new("httpd:alpine")
35        .port(8080, 80)     // Manual port mapping
36        .auto_port(9090)    // Auto-assign port for API
37        .auto_port(9091)    // Auto-assign port for metrics
38        .env("API_VERSION", "v1")
39        .name("api_service")
40        .ready_timeout(Duration::from_secs(15));
41    
42    println!("📋 Container Configurations:");
43    println!("1. Web Service:");
44    println!("   - Image: {}", web_container.image);
45    println!("   - Auto-ports: {:?}", web_container.auto_ports);
46    println!("   - Will auto-assign host ports for container ports 80 and 443");
47    
48    println!("2. Database:");
49    println!("   - Image: {}", db_container.image);
50    println!("   - Auto-ports: {:?}", db_container.auto_ports);
51    println!("   - Will auto-assign host port for container port 5432");
52    
53    println!("3. API Service:");
54    println!("   - Image: {}", api_container.image);
55    println!("   - Manual ports: {:?}", api_container.ports);
56    println!("   - Auto-ports: {:?}", api_container.auto_ports);
57    println!("   - Manual mapping: 8080 -> 80, Auto-assign: 9090, 9091");
58    println!();
59    
60    // Clone containers for hooks
61    let web_before = web_container.clone();
62    let db_before = db_container.clone();
63    let api_before = api_container.clone();
64    
65    // Start containers in before_each
66    before_each(move |ctx| {
67        println!("🚀 before_each: Starting containers and capturing port info...");
68        
69        // Start web container
70        let web_info = web_before.start()
71            .map_err(|e| format!("Failed to start web container: {}", e))?;
72        ctx.set_data("web_container_info", web_info.clone());
73        
74        println!("✅ Web container started: {}", web_info.container_id);
75        println!("   📍 Port mappings: {}", web_info.ports_summary());
76        println!("   🔗 Primary URL: {}", web_info.primary_url().unwrap_or("None"));
77        
78        // Show specific port access
79        if let Some(http_port) = web_info.host_port_for(80) {
80            println!("   🌐 HTTP accessible at: http://localhost:{}", http_port);
81        }
82        if let Some(https_port) = web_info.host_port_for(443) {
83            println!("   🔒 HTTPS accessible at: https://localhost:{}", https_port);
84        }
85        
86        // Start database container
87        let db_info = db_before.start()
88            .map_err(|e| format!("Failed to start db container: {}", e))?;
89        ctx.set_data("db_container_info", db_info.clone());
90        
91        println!("✅ Database container started: {}", db_info.container_id);
92        println!("   📍 Port mappings: {}", db_info.ports_summary());
93        if let Some(db_port) = db_info.host_port_for(5432) {
94            println!("   🗄️ PostgreSQL accessible at: localhost:{}", db_port);
95            println!("   📝 Connection string: postgresql://user:pass@localhost:{}/testdb", db_port);
96        }
97        
98        // Start API container
99        let api_info = api_before.start()
100            .map_err(|e| format!("Failed to start api container: {}", e))?;
101        ctx.set_data("api_container_info", api_info.clone());
102        
103        println!("✅ API container started: {}", api_info.container_id);
104        println!("   📍 Port mappings: {}", api_info.ports_summary());
105        
106        // Show both manual and auto ports
107        if let Some(http_port) = api_info.host_port_for(80) {
108            println!("   🌐 HTTP API at: http://localhost:{} (manual mapping)", http_port);
109        }
110        if let Some(api_port) = api_info.host_port_for(9090) {
111            println!("   🔧 API endpoint at: http://localhost:{} (auto-assigned)", api_port);
112        }
113        if let Some(metrics_port) = api_info.host_port_for(9091) {
114            println!("   📊 Metrics at: http://localhost:{} (auto-assigned)", metrics_port);
115        }
116        
117        println!("🎉 All containers started with auto-assigned ports!");
118        Ok(())
119    });
120    
121    // Cleanup containers in after_each
122    let web_after = web_container.clone();
123    let db_after = db_container.clone();
124    let api_after = api_container.clone();
125    
126    after_each(move |ctx| {
127        println!("🧹 after_each: Cleaning up containers...");
128        
129        if let Some(web_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info") {
130            let _ = web_after.stop(&web_info.container_id);
131            println!("🛑 Stopped web container: {}", web_info.container_id);
132        }
133        
134        if let Some(db_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info") {
135            let _ = db_after.stop(&db_info.container_id);
136            println!("🛑 Stopped database container: {}", db_info.container_id);
137        }
138        
139        if let Some(api_info) = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info") {
140            let _ = api_after.stop(&api_info.container_id);
141            println!("🛑 Stopped API container: {}", api_info.container_id);
142        }
143        
144        println!("✅ All containers cleaned up!");
145        Ok(())
146    });
147    
148    // Test 1: Web service port access
149    test("test_web_service_port_access", |ctx| {
150        println!("🧪 Testing web service port access...");
151        
152        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
153            .expect("Web container info should be available");
154        
155        println!("🔍 Demonstrating port access methods:");
156        
157        // Method 1: Get specific host port for container port
158        if let Some(http_port) = web_info.host_port_for(80) {
159            println!("   ✅ HTTP port 80 is mapped to host port: {}", http_port);
160            println!("      💡 Use this for HTTP client connections");
161        }
162        
163        if let Some(https_port) = web_info.host_port_for(443) {
164            println!("   ✅ HTTPS port 443 is mapped to host port: {}", https_port);
165            println!("      💡 Use this for HTTPS client connections");
166        }
167        
168        // Method 2: Get ready-to-use URLs
169        if let Some(http_url) = web_info.url_for_port(80) {
170            println!("   🔗 HTTP URL: {}", http_url);
171            println!("      💡 Ready to use in HTTP requests");
172        }
173        
174        if let Some(https_url) = web_info.url_for_port(443) {
175            println!("   🔗 HTTPS URL: {}", https_url);
176            println!("      💡 Ready to use in HTTPS requests (change http:// to https://)");
177        }
178        
179        // Method 3: Get all URLs
180        println!("   📋 All service URLs:");
181        for (i, url) in web_info.urls.iter().enumerate() {
182            println!("      {}. {}", i + 1, url);
183        }
184        
185        // Method 4: Get all port mappings
186        println!("   📊 All port mappings:");
187        for (host_port, container_port) in &web_info.port_mappings {
188            println!("      Host {} -> Container {}", host_port, container_port);
189        }
190        
191        // Verify ports are different (auto-assigned)
192        assert!(web_info.host_port_for(80).unwrap() != web_info.host_port_for(443).unwrap(), 
193                "Auto-assigned ports should be different");
194        
195        println!("✅ Web service port access test passed");
196        Ok(())
197    });
198    
199    // Test 2: Database connection string generation
200    test("test_database_connection_info", |ctx| {
201        println!("🧪 Testing database connection info generation...");
202        
203        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
204            .expect("Database container info should be available");
205        
206        println!("🗄️ Database connection information:");
207        
208        // Get the auto-assigned port for PostgreSQL
209        let db_port = db_info.host_port_for(5432)
210            .expect("PostgreSQL port should be exposed");
211        
212        println!("   📍 PostgreSQL running on: localhost:{}", db_port);
213        
214        // Generate connection strings using the auto-assigned port
215        let connection_string = format!("postgresql://admin:testpass@localhost:{}/testdb", db_port);
216        let jdbc_url = format!("jdbc:postgresql://localhost:{}/testdb", db_port);
217        let docker_internal = format!("postgresql://admin:testpass@{}:5432/testdb", db_info.container_id);
218        
219        println!("   🔗 Connection strings:");
220        println!("      Standard: {}", connection_string);
221        println!("      JDBC: {}", jdbc_url);
222        println!("      Docker internal: {}", docker_internal);
223        
224        // Show how to use this in real applications
225        println!("   💡 Usage examples:");
226        println!("      - Set DATABASE_URL={}", connection_string);
227        println!("      - Use in tests: connect to localhost:{}", db_port);
228        println!("      - Container-to-container: use port 5432");
229        
230        // Verify port is valid
231        assert!(db_port > 0, "Database port should be valid");
232        println!("✅ Database connection info test passed");
233        
234        Ok(())
235    });
236    
237    // Test 3: Mixed port configuration
238    test("test_mixed_port_configuration", |ctx| {
239        println!("🧪 Testing mixed port configuration (manual + auto)...");
240        
241        let api_info = ctx.get_data::<rust_test_harness::ContainerInfo>("api_container_info")
242            .expect("API container info should be available");
243        
244        println!("🔀 Mixed port configuration analysis:");
245        
246        // Manual port mapping
247        let http_port = api_info.host_port_for(80)
248            .expect("HTTP port should be mapped");
249        println!("   📌 Manual mapping - HTTP port 80 -> host port: {}", http_port);
250        assert_eq!(http_port, 8080, "Manual port should be exactly as specified");
251        
252        // Auto-assigned ports
253        let api_port = api_info.host_port_for(9090)
254            .expect("API port should be auto-assigned");
255        let metrics_port = api_info.host_port_for(9091)
256            .expect("Metrics port should be auto-assigned");
257        
258        println!("   🎲 Auto-assigned - API port 9090 -> host port: {}", api_port);
259        println!("   🎲 Auto-assigned - Metrics port 9091 -> host port: {}", metrics_port);
260        
261        // Verify auto-assigned ports are different from manual port
262        assert_ne!(api_port, 8080, "Auto-assigned port should be different from manual port");
263        assert_ne!(metrics_port, 8080, "Auto-assigned port should be different from manual port");
264        assert_ne!(api_port, metrics_port, "Auto-assigned ports should be different from each other");
265        
266        println!("   🌐 Service endpoints:");
267        println!("      Main API: http://localhost:{}/", http_port);
268        println!("      API v2: http://localhost:{}/", api_port);
269        println!("      Metrics: http://localhost:{}/metrics", metrics_port);
270        
271        // Show complete port summary
272        println!("   📋 Complete port summary: {}", api_info.ports_summary());
273        
274        println!("✅ Mixed port configuration test passed");
275        Ok(())
276    });
277    
278    // Test 4: Container info convenience methods
279    test("test_container_info_convenience_methods", |ctx| {
280        println!("🧪 Testing ContainerInfo convenience methods...");
281        
282        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
283            .expect("Web container info should be available");
284        
285        println!("🔧 Testing all ContainerInfo methods:");
286        
287        // Test primary_url()
288        if let Some(primary_url) = web_info.primary_url() {
289            println!("   ✅ primary_url(): {}", primary_url);
290            assert!(primary_url.starts_with("http://localhost:"), "Primary URL should be valid");
291        }
292        
293        // Test url_for_port()
294        if let Some(url_80) = web_info.url_for_port(80) {
295            println!("   ✅ url_for_port(80): {}", url_80);
296            assert!(url_80.contains("localhost:"), "URL should contain localhost");
297        }
298        
299        // Test host_port_for()
300        if let Some(port_80) = web_info.host_port_for(80) {
301            println!("   ✅ host_port_for(80): {}", port_80);
302            assert!(port_80 > 0, "Port should be positive");
303        }
304        
305        // Test ports_summary()
306        let summary = web_info.ports_summary();
307        println!("   ✅ ports_summary(): {}", summary);
308        assert!(summary.contains("->"), "Summary should contain port mappings");
309        
310        // Test direct field access
311        println!("   ✅ container_id: {}", web_info.container_id);
312        println!("   ✅ image: {}", web_info.image);
313        println!("   ✅ auto_cleanup: {}", web_info.auto_cleanup);
314        
315        println!("   📊 All URLs:");
316        for (i, url) in web_info.urls.iter().enumerate() {
317            println!("      {}. {}", i + 1, url);
318        }
319        
320        println!("   📊 All port mappings:");
321        for (host_port, container_port) in &web_info.port_mappings {
322            println!("      {} -> {}", host_port, container_port);
323        }
324        
325        println!("✅ Container info convenience methods test passed");
326        Ok(())
327    });
328    
329    // Test 5: Real-world usage patterns
330    test("test_real_world_usage_patterns", |ctx| {
331        println!("🧪 Testing real-world usage patterns...");
332        
333        let web_info = ctx.get_data::<rust_test_harness::ContainerInfo>("web_container_info")
334            .expect("Web container info should be available");
335        let db_info = ctx.get_data::<rust_test_harness::ContainerInfo>("db_container_info")
336            .expect("Database container info should be available");
337        
338        println!("🌍 Real-world usage examples:");
339        
340        // Pattern 1: HTTP client testing
341        if let Some(web_url) = web_info.primary_url() {
342            println!("   🌐 HTTP Client Testing:");
343            println!("      Base URL: {}", web_url);
344            println!("      GET {}/health", web_url);
345            println!("      POST {}/api/users", web_url);
346            println!("      Code: let response = reqwest::get(\"{}/health\").await?;", web_url);
347        }
348        
349        // Pattern 2: Database testing
350        if let Some(db_port) = db_info.host_port_for(5432) {
351            println!("   🗄️ Database Testing:");
352            println!("      Connection: localhost:{}", db_port);
353            println!("      Code: let conn = PgConnection::establish(\"postgresql://user:pass@localhost:{}/db\")?;", db_port);
354        }
355        
356        // Pattern 3: Environment variable setup
357        println!("   🔧 Environment Variables:");
358        if let Some(web_port) = web_info.host_port_for(80) {
359            println!("      export WEB_SERVICE_URL=http://localhost:{}", web_port);
360        }
361        if let Some(db_port) = db_info.host_port_for(5432) {
362            println!("      export DATABASE_URL=postgresql://localhost:{}/testdb", db_port);
363        }
364        
365        // Pattern 4: Docker-compose style networking
366        println!("   🐳 Container Networking:");
367        println!("      External: Use auto-assigned host ports");
368        println!("      Internal: Use original container ports");
369        println!("      Web -> DB: {}:5432 (container-to-container)", db_info.container_id);
370        
371        // Pattern 5: Health checks
372        println!("   ❤️ Health Checks:");
373        if let Some(web_url) = web_info.primary_url() {
374            println!("      Health endpoint: {}/health", web_url);
375            println!("      Ready endpoint: {}/ready", web_url);
376        }
377        
378        println!("✅ Real-world usage patterns test passed");
379        Ok(())
380    });
381    
382    println!("🚀 Running container port access tests...");
383    println!();
384    
385    // Run the tests
386    let config = TestConfig {
387        html_report: Some("container-port-access-report.html".to_string()),
388        ..Default::default()
389    };
390    
391    let exit_code = run_tests_with_config(config);
392    
393    println!();
394    if exit_code == 0 {
395        println!("🎉 All tests passed! Port access functionality is working correctly.");
396        println!("📊 Check the HTML report for detailed results.");
397        println!();
398        println!("💡 Key Takeaways:");
399        println!("   • Use auto_port() to avoid port conflicts");
400        println!("   • Access host ports with host_port_for(container_port)");
401        println!("   • Get ready-to-use URLs with url_for_port(container_port)");
402        println!("   • Use ports_summary() for human-readable port info");
403        println!("   • ContainerInfo provides complete access to all port information");
404    } else {
405        println!("❌ Some tests failed. Check the output above for details.");
406    }
407    
408    std::process::exit(exit_code);
409}

Trait Implementations§

Source§

impl Clone for ContainerConfig

Source§

fn clone(&self) -> ContainerConfig

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ContainerConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,