test

Function test 

Source
pub fn test<F>(name: &str, f: F)
where F: FnMut(&mut TestContext) -> TestResult + Send + 'static,
Examples found in repository?
examples/user_specified_ports.rs (lines 118-130)
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 (lines 132-169)
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/html_reporting.rs (line 28)
18fn main() {
19    println!("๐Ÿงช HTML Reporting Example");
20    println!("=========================");
21    println!();
22    
23    // Example 1: Basic HTML Report Generation
24    println!("๐Ÿ“Š Example 1: Basic HTML Report");
25    println!("Generating basic HTML report...");
26    
27    // Register some tests
28    test("basic_passing_test", |_| Ok(()));
29    test("another_passing_test", |_| Ok(()));
30    
31    let config = TestConfig {
32        html_report: Some("basic_report.html".to_string()),
33        skip_hooks: None,
34        ..Default::default()
35    };
36    
37    let result = run_tests_with_config(config);
38    println!("โœ… Basic report generated with exit code: {}", result);
39    println!();
40    
41    // Example 2: HTML Report with Mixed Results
42    println!("๐Ÿ“Š Example 2: Mixed Results Report");
43    println!("Generating report with pass/fail/skip results...");
44    
45    // Clear previous tests and register new ones
46    test("successful_test", |_| Ok(()));
47    test("failing_test", |_| Err("intentional failure".into()));
48    test("skipped_test", |_| Ok(()));
49    
50    let config = TestConfig {
51        html_report: Some("mixed_results_report.html".to_string()),
52        skip_hooks: None,
53        ..Default::default()
54    };
55    
56    let result = run_tests_with_config(config);
57    println!("โœ… Mixed results report generated with exit code: {}", result);
58    println!();
59    
60    // Example 3: HTML Report with Rich Metadata
61    println!("๐Ÿ“Š Example 3: Rich Metadata Report");
62    println!("Generating report with tags, timeouts, and Docker...");
63    
64    // Clear previous tests and register new ones with realistic scenarios
65    test("tagged_test", |_| Ok(()));
66    test("timeout_test", |_| Ok(()));
67    test("docker_integration_test", |_| Ok(()));
68    test("database_connection_test", |_| Ok(()));
69    test("api_endpoint_test", |_| Ok(()));
70    
71    // Note: In a real scenario, you'd use test_with_tags and test_with_docker
72    // For this example, we'll simulate the metadata by showing different test types
73    
74    let config = TestConfig {
75        html_report: Some("rich_metadata_report.html".to_string()),
76        skip_hooks: None,
77        ..Default::default()
78    };
79    
80    let result = run_tests_with_config(config);
81    println!("โœ… Rich metadata report generated with exit code: {}", result);
82    println!("   ๐Ÿ“Š 5 tests with different types (tags, timeouts, Docker, DB, API)");
83    println!();
84    
85    // Example 4: Large Test Suite Report
86    println!("๐Ÿ“Š Example 4: Large Test Suite Report");
87    println!("Generating report for many tests with realistic mixed results...");
88    
89    // Clear previous tests and register many tests with realistic scenarios
90    for i in 0..25 {
91        match i {
92            // Some tests pass normally
93            0..=15 => {
94                test(&format!("large_suite_test_{}", i), |_| Ok(()));
95            },
96            // Some tests fail with different error types
97            16..=19 => {
98                test(&format!("large_suite_test_{}", i), move |_| {
99                    Err(format!("Test {} failed due to assertion error", i).into())
100                });
101            },
102            // Some tests have timeouts
103            20..=22 => {
104                test(&format!("large_suite_test_{}", i), move |_| {
105                    // Simulate a test that takes too long and fails due to timeout
106                    std::thread::sleep(Duration::from_millis(50));
107                    Err(format!("Test {} failed due to timeout (exceeded 30ms limit)", i).into())
108                });
109            },
110            // Some tests panic
111            23 => {
112                test(&format!("large_suite_test_{}", i), move |_| {
113                    panic!("Test {} panicked due to unexpected condition", i);
114                });
115            },
116            // Some tests are skipped (simulated by returning error)
117            24 => {
118                test(&format!("large_suite_test_{}", i), |_| {
119                    Err("Test skipped due to missing dependencies".into())
120                });
121            },
122            _ => unreachable!(),
123        }
124    }
125    
126    let config = TestConfig {
127        html_report: Some("large_suite_report.html".to_string()),
128        skip_hooks: None,
129        ..Default::default()
130    };
131    
132    let result = run_tests_with_config(config);
133    println!("โœ… Large suite report generated with exit code: {}", result);
134    println!("   ๐Ÿ“Š 16 tests passed, 7 failed (4 errors + 3 timeouts), 1 panic, 1 skipped");
135    println!();
136    
137    // Example 5: Environment Variable Configuration
138    println!("๐Ÿ“Š Example 5: Environment Variable Configuration");
139    println!("Setting TEST_HTML_REPORT environment variable...");
140    
141    // Set environment variable
142    std::env::set_var("TEST_HTML_REPORT", "env_var_report.html");
143    
144    // Clear previous tests and register new ones
145    test("env_test", |_| Ok(()));
146    
147    let config = TestConfig::default();
148    println!("๐Ÿ“ Config HTML report path: {:?}", config.html_report);
149    
150    let result = run_tests_with_config(config);
151    println!("โœ… Environment variable report generated with exit code: {}", result);
152    println!();
153    
154    // Example 6: Performance Testing Report
155    println!("๐Ÿ“Š Example 6: Performance Testing Report");
156    println!("Generating report for performance tests with realistic scenarios...");
157    
158    // Clear previous tests and register performance tests with mixed results
159    for i in 0..15 {
160        match i {
161            // Fast tests that pass
162            0..=8 => {
163                test(&format!("perf_test_{}", i), |_| {
164                    // Simulate some work
165                    std::thread::sleep(Duration::from_millis(5));
166                    Ok(())
167                });
168            },
169            // Medium tests that pass
170            9..=11 => {
171                test(&format!("perf_test_{}", i), |_| {
172                    // Simulate medium work
173                    std::thread::sleep(Duration::from_millis(20));
174                    Ok(())
175                });
176            },
177            // Slow tests that pass
178            12..=13 => {
179                test(&format!("perf_test_{}", i), |_| {
180                    // Simulate slow but successful tests
181                    std::thread::sleep(Duration::from_millis(50));
182                    Ok(())
183                });
184            },
185            // One test that fails due to timeout
186            14 => {
187                test(&format!("perf_test_{}", i), |_| {
188                    // Simulate a test that takes too long and fails due to timeout
189                    std::thread::sleep(Duration::from_millis(100));
190                    Err("Performance test exceeded expected time limit (50ms)".into())
191                });
192            },
193            _ => unreachable!(),
194        }
195    }
196    
197    let config = TestConfig {
198        html_report: Some("performance_report.html".to_string()),
199        max_concurrency: Some(4),
200        skip_hooks: None,
201        ..Default::default()
202    };
203    
204    let result = run_tests_with_config(config);
205    println!("โœ… Performance report generated with exit code: {}", result);
206    println!("   ๐Ÿ“Š 14 tests passed, 1 failed (timeout)");
207    println!();
208    
209    // Summary
210    println!("๐ŸŽ‰ HTML Reporting Examples Complete!");
211    println!("=====================================");
212    println!();
213    println!("Generated HTML reports (stored in target/test-reports/):");
214    println!("  ๐Ÿ“„ basic_report.html - Basic functionality");
215    println!("  ๐Ÿ“„ mixed_results_report.html - Pass/fail/skip results");
216    println!("  ๐Ÿ“„ rich_metadata_report.html - Rich test metadata");
217    println!("  ๐Ÿ“„ large_suite_report.html - Large test suite");
218    println!("  ๐Ÿ“„ env_var_report.html - Environment variable config");
219    println!("  ๐Ÿ“„ performance_report.html - Performance testing");
220    println!();
221    println!("๐Ÿ“ All reports are automatically organized in target/test-reports/");
222    println!();
223    println!("๐Ÿ“– HTML Report Features:");
224    println!("  ๐Ÿ”ฝ Expandable test details - Click any test to expand");
225    println!("  ๐Ÿ” Real-time search - Search by name, status, or tags");
226    println!("  โŒจ๏ธ  Keyboard shortcuts - Ctrl+F (search), Ctrl+A (expand all)");
227    println!("  ๐Ÿšจ Auto-expand failed - Failed tests automatically expand");
228    println!("  ๐Ÿ“ฑ Responsive design - Works on all devices");
229    println!();
230    println!("๐Ÿ’ก Usage Tips:");
231    println!("  โ€ข Open any .html file in your web browser");
232    println!("  โ€ข Use Ctrl+F to search for specific tests");
233    println!("  โ€ข Click test headers to expand/collapse details");
234    println!("  โ€ข Failed tests are automatically expanded for visibility");
235    println!("  โ€ข Reports work great in CI/CD pipelines and team sharing");
236    println!("  โ€ข All reports are neatly organized in target/test-reports/");
237    println!();
238    println!("๐Ÿ”ง Configuration Options:");
239    println!("  โ€ข Set TEST_HTML_REPORT environment variable");
240    println!("  โ€ข Use TestConfig.html_report for programmatic control");
241    println!("  โ€ข Combine with other config options (filtering, concurrency)");
242    println!("  โ€ข Reports automatically go to target/test-reports/ for clean organization");
243}
examples/auto_port_demo.rs (lines 158-174)
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 (lines 149-197)
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}