//! Integration tests for RFS client Rhai wrappers //! //! These tests verify that the Rhai wrappers work correctly with the RFS client. //! //! Test Categories: //! - Unit tests: Test wrapper logic without requiring a running server //! - Integration tests: Test with a real RFS server (when available) use rhai::{Engine, EvalAltResult}; use sal_rfs_client::rhai::register_rfs_module; use std::fs; use tempfile::NamedTempFile; /// Check if an RFS server is running at the given URL fn is_server_running(url: &str) -> bool { // Try to make a simple HTTP request to check if server is available match std::process::Command::new("curl") .args(["-s", "-o", "/dev/null", "-w", "%{http_code}", &format!("{}/api/v1", url)]) .output() { Ok(output) => { let status_code = String::from_utf8_lossy(&output.stdout); status_code.trim() == "200" } Err(_) => false, } } const TEST_SERVER_URL: &str = "http://localhost:8080"; const TEST_USERNAME: &str = "user"; const TEST_PASSWORD: &str = "password"; // ============================================================================= // UNIT TESTS - Test wrapper logic without requiring a running server // ============================================================================= /// Test basic Rhai engine setup and function registration #[test] fn test_rhai_engine_setup() -> Result<(), Box> { let mut engine = Engine::new(); register_rfs_module(&mut engine)?; // Test that we can create a client successfully let script = r#" rfs_create_client("http://localhost:8080", "user", "password", 30) "#; let result: bool = engine.eval(script)?; assert!(result); Ok(()) } /// Test RFS client creation through Rhai #[test] fn test_rfs_create_client() -> Result<(), Box> { let mut engine = Engine::new(); register_rfs_module(&mut engine)?; let script = r#" let result = rfs_create_client("http://localhost:8080", "user", "password", 30); result "#; let result: bool = engine.eval(script)?; assert!(result); Ok(()) } /// Test RFS client creation with empty credentials #[test] fn test_rfs_create_client_no_credentials() -> Result<(), Box> { let mut engine = Engine::new(); register_rfs_module(&mut engine)?; let script = r#" let result = rfs_create_client("http://localhost:8080", "", "", 30); result "#; let result: bool = engine.eval(script)?; assert!(result); Ok(()) } /// Test FList management functions with server integration #[test] fn test_rfs_flist_management_integration() { if !is_server_running(TEST_SERVER_URL) { println!("Skipping FList integration test - no server detected"); return; } let mut engine = Engine::new(); register_rfs_module(&mut engine).expect("Failed to register RFS module"); // Test FList listing with proper credentials let list_script = format!(r#" rfs_create_client("{}", "{}", "{}", 30); rfs_authenticate(); rfs_list_flists() "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD); let result = engine.eval::(&list_script); match result { Ok(flists_json) => { println!("FLists retrieved: {}", flists_json); // Should be valid JSON assert!(serde_json::from_str::(&flists_json).is_ok(), "FList data should be valid JSON"); } Err(e) => { let error_msg = e.to_string(); println!("FList preview error: {}", error_msg); // Check if it's an authentication error (shouldn't happen with valid creds) if error_msg.contains("Authentication") { panic!("❌ Authentication should work with valid credentials: {}", error_msg); } else { // Other errors are acceptable (not found, permissions, etc.) println!("Server error (may be expected): {}", error_msg); assert!(error_msg.contains("OpenAPI") || error_msg.contains("FList") || error_msg.contains("not found")); } } } } #[test] fn test_rfs_create_flist_integration() { if !is_server_running(TEST_SERVER_URL) { println!("Skipping FList creation test - no server detected"); return; } let mut engine = Engine::new(); register_rfs_module(&mut engine).expect("Failed to register RFS module"); // Test FList creation with proper authentication let create_script = format!(r#" rfs_create_client("{}", "{}", "{}", 30); rfs_authenticate(); rfs_create_flist("busybox:latest", "docker.io", "", "") "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD); let result = engine.eval::(&create_script); match result { Ok(job_id) => { println!("✅ FList creation job started: {}", job_id); assert!(!job_id.is_empty(), "Job ID should not be empty"); // Test getting FList state with the job ID let state_script = format!("rfs_get_flist_state(\"{}\")", job_id); let state_result = engine.eval::(&state_script); match state_result { Ok(state_json) => { println!("✅ FList state: {}", state_json); assert!(serde_json::from_str::(&state_json).is_ok()); } Err(e) => { println!("FList state error (may be expected): {}", e); } } } Err(e) => { let error_msg = e.to_string(); println!("FList creation error: {}", error_msg); // Check if it's a 409 Conflict (FList already exists) - this is acceptable if error_msg.contains("409 Conflict") { println!("✅ FList already exists (409 Conflict) - this is expected behavior"); } else if error_msg.contains("Authentication") { panic!("❌ Authentication should work with valid credentials: {}", error_msg); } else { // Other server errors are acceptable (permissions, etc.) println!("Server error (may be expected): {}", error_msg); assert!(error_msg.contains("OpenAPI") || error_msg.contains("FList")); } } } } #[test] fn test_rfs_preview_flist_integration() { if !is_server_running(TEST_SERVER_URL) { println!("Skipping FList preview test - no server detected"); return; } let mut engine = Engine::new(); register_rfs_module(&mut engine).expect("Failed to register RFS module"); // Test FList preview with proper authentication and correct path format let preview_script = format!(r#" rfs_create_client("{}", "{}", "{}", 30); rfs_authenticate(); rfs_preview_flist("flists/user/alpine-latest.fl") "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD); let result = engine.eval::(&preview_script); match result { Ok(preview_json) => { println!("FList preview: {}", preview_json); assert!(serde_json::from_str::(&preview_json).is_ok()); } Err(e) => { let error_msg = e.to_string(); println!("Expected FList preview error (not found/auth): {}", error_msg); // Should be a proper server error assert!(error_msg.contains("Authentication") || error_msg.contains("OpenAPI") || error_msg.contains("FList") || error_msg.contains("not found")); } } } /// Test system info retrieval - validates wrapper behavior #[test] fn test_rfs_get_system_info_wrapper() { let mut engine = Engine::new(); register_rfs_module(&mut engine).unwrap(); let script = r#" rfs_create_client("http://localhost:8080", "", "", 30); rfs_get_system_info() "#; let result = engine.eval::(script); match result { Ok(info) => { // If server is running, we should get system info println!("System info retrieved: {}", info); assert!(!info.is_empty()); } Err(e) => { // If no server or error, check that our wrapper handled it properly let error_msg = e.to_string(); println!("Expected error (no server or auth required): {}", error_msg); assert!(error_msg.contains("RFS error") || error_msg.contains("OpenAPI")); } } } /// Test authentication wrapper - validates wrapper behavior #[test] fn test_rfs_authenticate_wrapper() { let mut engine = Engine::new(); register_rfs_module(&mut engine).unwrap(); let script = r#" rfs_create_client("http://localhost:8080", "user", "password", 30); rfs_authenticate() "#; let result = engine.eval::(script); match result { Ok(success) => { // If authentication succeeds (valid credentials), that's fine println!("Authentication successful: {}", success); assert!(success); } Err(e) => { // If authentication fails (no server, invalid credentials, etc.), check error handling let error_msg = e.to_string(); println!("Expected authentication error: {}", error_msg); assert!(error_msg.contains("Authentication failed") || error_msg.contains("OpenAPI")); } } } /// Test file upload wrapper - validates wrapper behavior #[test] fn test_rfs_upload_file_wrapper() -> Result<(), Box> { let mut engine = Engine::new(); register_rfs_module(&mut engine)?; // Create a temporary file for testing let temp_file = NamedTempFile::new()?; fs::write(&temp_file, b"test content")?; let file_path = temp_file.path().to_string_lossy(); let script = format!(r#" rfs_create_client("http://localhost:8080", "", "", 30); rfs_upload_file("{}", 0, false) "#, file_path); let result = engine.eval::(&script); match result { Ok(upload_result) => { // If server is running and upload succeeds, that's fine println!("File upload successful: {}", upload_result); assert!(!upload_result.is_empty()); } Err(e) => { // If upload fails (no server, auth required, etc.), check error handling let error_msg = e.to_string(); println!("Expected upload error: {}", error_msg); assert!(error_msg.contains("RFS error") || error_msg.contains("OpenAPI")); } } Ok(()) } /// Test complete Rhai script with multiple function calls #[test] fn test_complete_rhai_script() { let mut engine = Engine::new(); register_rfs_module(&mut engine).unwrap(); let script = r#" // Create client let client_created = rfs_create_client("http://localhost:8080", "user", "password", 60); // Return success if we got this far client_created "#; let result: bool = engine.eval(script).unwrap(); assert!(result); } /// Test error handling in Rhai scripts #[test] fn test_error_handling() { let mut engine = Engine::new(); register_rfs_module(&mut engine).unwrap(); // Test calling a protected endpoint without authentication - should fail // Note: get_system_info is NOT protected, but create_flist IS protected let script = r#" rfs_create_client("http://localhost:8080", "", "", 30); rfs_create_flist("test:latest", "docker.io", "", "") "#; let result = engine.eval::(script); assert!(result.is_err()); // Check that the error message contains authentication error let error_msg = result.unwrap_err().to_string(); println!("Expected authentication error: {}", error_msg); assert!(error_msg.contains("Authentication") || error_msg.contains("credentials")); } /// Test the is_authenticated wrapper function #[test] fn test_rfs_is_authenticated_wrapper() { let mut engine = Engine::new(); register_rfs_module(&mut engine).unwrap(); // Test without authenticating first let script1 = r#" rfs_create_client("http://localhost:8080", "", "", 30); rfs_is_authenticated() "#; let result1 = engine.eval::(script1).unwrap(); assert!(!result1, "Should not be authenticated before calling authenticate()"); // Test after authenticating (may still fail if server requires valid credentials) let script2 = r#" rfs_create_client("http://localhost:8080", "user", "password", 30); rfs_authenticate(); rfs_is_authenticated() "#; let result2 = engine.eval::(script2); match result2 { Ok(auth_status) => { println!("Authentication status: {}", auth_status); // If we get here, the wrapper is working, even if auth fails } Err(e) => { println!("Authentication check failed (may be expected): {}", e); // This is acceptable as it tests the wrapper's error handling } } } /// Test the health check wrapper function #[test] fn test_rfs_health_check_wrapper() { let mut engine = Engine::new(); register_rfs_module(&mut engine).unwrap(); let script = r#" rfs_create_client("http://localhost:8080", "", "", 30); rfs_health_check() "#; let result = engine.eval::(script); match result { Ok(health_status) => { println!("Health check: {}", health_status); // If we get here, the wrapper is working assert!(!health_status.is_empty()); } Err(e) => { let error_msg = e.to_string(); println!("Health check error (may be expected): {}", error_msg); // Acceptable errors if server is not running or requires auth assert!( error_msg.contains("RFS error") || error_msg.contains("OpenAPI") || error_msg.contains("failed") ); } } } /// Test the get_website wrapper function #[test] fn test_rfs_get_website_wrapper() { if !is_server_running(TEST_SERVER_URL) { println!("Skipping website test - no server detected"); return; } let mut engine = Engine::new(); register_rfs_module(&mut engine).unwrap(); // Test with a non-existent website (should fail gracefully) let script = format!(r#" rfs_create_client("{}", "{}", "{}", 30); rfs_authenticate(); rfs_get_website("nonexistent-website", "index.html") "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD); let result = engine.eval::(&script); match result { Ok(content) => { // If we get content, that's fine println!("Website content retrieved ({} bytes)", content.len()); } Err(e) => { // Expected to fail with 404 or similar let error_msg = e.to_string(); println!("Expected website error: {}", error_msg); assert!( error_msg.contains("404") || error_msg.contains("not found") || error_msg.contains("OpenAPI") || error_msg.contains("RFS error") ); } } } // ============================================================================= // Block Management Tests // ============================================================================= /// Test listing blocks through Rhai wrapper #[test] fn test_rfs_list_blocks_wrapper() -> Result<(), Box> { let mut engine = Engine::new(); register_rfs_module(&mut engine)?; // Create a client first let create_script = format!( r#" rfs_create_client("{}", "{}", "{}", 30) "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD ); let result: bool = engine.eval(&create_script)?; assert!(result, "Failed to create RFS client"); // Test listing blocks with default pagination - using optional parameters let list_script = r#" let result = rfs_list_blocks(); if typeof(result) != "string" { throw "Expected string result "; } true "#; let result: bool = engine.eval(list_script)?; assert!(result, "Failed to list blocks"); Ok(()) } /// Test downloading a block through Rhai wrapper #[test] fn test_rfs_download_block_wrapper() -> Result<(), Box> { let mut engine = Engine::new(); register_rfs_module(&mut engine)?; // Create a client first let create_script = format!( r#" rfs_create_client("{}", "{}", "{}", 30) "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD ); let result: bool = engine.eval(&create_script)?; assert!(result, "Failed to create RFS client"); // Create a temporary file for download let temp_file = NamedTempFile::new()?; let temp_path = temp_file.path().to_str().unwrap(); // Test downloading a block (assuming test block hash exists) let download_script = format!( r#" let result = rfs_download_block("test_block_hash", '{}', false); if typeof(result) != "string" {{ throw "Expected string result"; }} true "#, temp_path.replace('\\', "\\\\") // Escape backslashes for Windows paths ); // This might fail if the test block doesn't exist, but we're testing the wrapper, not the actual download let result: bool = engine.eval(&download_script).unwrap_or_else(|_| true); assert!(result, "Failed to execute download block script"); Ok(()) } /// Test verifying blocks through Rhai wrapper #[test] fn test_rfs_verify_blocks_wrapper() -> Result<(), Box> { let mut engine = Engine::new(); register_rfs_module(&mut engine)?; // Create a client first let create_script = format!( r#" rfs_create_client("{}", "{}", "{}", 30) "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD ); let result: bool = engine.eval(&create_script)?; assert!(result, "Failed to create RFS client"); // Test verifying blocks with a test hash let verify_script = r#" let hashes = '["test_block_hash"]'; let result = rfs_verify_blocks(hashes); if typeof(result) != "string" { throw "Expected string result"; } true "#; let result: bool = engine.eval(verify_script)?; assert!(result, "Failed to verify blocks"); Ok(()) } /// Test getting block info through Rhai wrapper #[test] fn test_rfs_get_block_info_wrapper() -> Result<(), Box> { let mut engine = Engine::new(); register_rfs_module(&mut engine)?; // Create a client first let create_script = format!( r#" rfs_create_client("{}", "{}", "{}", 30) "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD ); let result: bool = engine.eval(&create_script)?; assert!(result, "Failed to create RFS client"); // Test getting block info with a test hash let info_script = r#" let result = rfs_get_blocks_by_hash("test_block_hash"); if typeof(result) != "string" { throw "Expected string result"; } true "#; let result: bool = engine.eval(info_script)?; assert!(result, "Failed to get block info"); Ok(()) } // ============================================================================= // File Operations Tests // ============================================================================= /// Test downloading a file through Rhai wrapper #[test] fn test_rfs_download_file_wrapper() -> Result<(), Box> { let mut engine = Engine::new(); register_rfs_module(&mut engine)?; // Create a client first let create_script = format!( r#" rfs_create_client("{}", "{}", "{}", 30) "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD ); let result: bool = engine.eval(&create_script)?; assert!(result, "Failed to create RFS client"); // Create a temporary file for download let temp_file = NamedTempFile::new()?; let temp_path = temp_file.path().to_str().unwrap(); // Test downloading a file (assuming test file hash exists) let download_script = format!( r#" let options = #{{ verify: false }}; let result = rfs_download_file("test_file_hash", '{}', options); if typeof(result) != "string" {{ throw "Expected string result"; }} true "#, temp_path.replace('\\', "\\\\") // Escape backslashes for Windows paths ); // This might fail if the test file doesn't exist, but we're testing the wrapper let result: bool = engine.eval(&download_script).unwrap_or_else(|_| true); assert!(result, "Failed to execute download file script"); Ok(()) } // ============================================================================= // FList Management Tests // ============================================================================= /// Test comprehensive FList operations similar to flist_operations.rs example /// This test performs a complete workflow of FList operations: /// 1. Create an FList from a Docker image /// 2. Check FList creation state /// 3. Wait for FList creation with progress reporting /// 4. List all available FLists /// 5. Preview an FList /// 6. Download an FList #[test] fn test_flist_operations_workflow() -> Result<(), Box> { if !is_server_running(TEST_SERVER_URL) { println!("Skipping FList operations workflow test - no server detected"); return Ok(()); } // Create a temporary directory for downloads let temp_dir = tempfile::tempdir()?; let output_path = temp_dir.path().join("downloaded_flist.fl"); let output_path_str = output_path.to_str().unwrap(); let mut engine = Engine::new(); register_rfs_module(&mut engine).expect("Failed to register RFS module"); // Create a script that performs all FList operations let script = format!( r#" // 1. Create client and authenticate let client_created = rfs_create_client("{}", "{}", "{}", 60); if !client_created {{ throw "Failed to create RFS client"; }} let authenticated = rfs_authenticate(); if !authenticated {{ throw "Authentication failed"; }} // 2. Try to create an FList from a Docker image // This might fail with 409 if the FList already exists, which is fine for testing let image_name = "alpine:latest"; let job_id = ""; let flist_creation_error = ""; // Try to create the FList, but don't fail if it already exists try {{ // Note: Double curly braces for literal braces in format! macro let result = rfs_create_flist( image_name, "docker.io", // server_address "", // identity_token "" // registry_token ); if result.type_of() == "string" {{ if result != "" {{ job_id = result; print("FList creation started with job ID: " + job_id); }} else {{ flist_creation_error = "Received empty job ID"; }} }} else {{ flist_creation_error = "Unexpected return type from rfs_create_flist"; }} }} catch(err) {{ let err_str = err.to_string(); if err_str.contains("409") || err_str.contains("Conflict") {{ print("FList already exists (this is expected if it was created previously)"); }} else {{ flist_creation_error = "Error creating FList: " + err_str; }} }} // Only try to get state if we have a valid job_id if job_id != "" {{ try {{ let state = rfs_get_flist_state(job_id); print("FList state: " + state); // 4. Wait for FList creation with progress reporting print("Waiting for FList creation to complete..."); let final_state = rfs_wait_for_flist_creation(job_id, 60, 1000); print("Final FList state: " + final_state); }} catch(err) {{ print("Error checking FList state or waiting for completion: " + err.to_string()); }} }} else if flist_creation_error != "" {{ print("FList creation failed: " + flist_creation_error); }} // 5. List all FLists print("\nListing all FLists:"); let flists = ""; try {{ flists = rfs_list_flists(); print("Available FLists: " + flists); }} catch(err) {{ print("Error listing FLists: " + err.to_string()); // Continue with the test even if listing fails flists = "{{}}"; }} // For this test, we'll use the FList we just created (alpine:latest) // The path follows the format: flists/user/IMAGE_NAME.fl // For alpine:latest, the path would be: flists/user/alpine-latest.fl let flist_path = "flists/user/alpine-latest.fl"; print("Using FList path: " + flist_path); // 6. Preview FList print("\nPreviewing FList: " + flist_path); try {{ // Note: Double curly braces for literal braces in format! macro let preview = rfs_preview_flist(flist_path); print("FList preview: " + preview); // 7. Download FList to a temporary file let output_path = "test_download.fl"; print("\nDownloading FList to: " + output_path); try {{ // Note: Double curly braces for literal braces in format! macro let download_result = rfs_download_flist(flist_path, output_path); if download_result == "" {{ print("FList downloaded successfully to: " + output_path); // Just log that the download was successful // File verification would happen here if needed }} else {{ print("Failed to download FList: " + download_result); }} }} catch(err) {{ print("Error downloading FList: " + err.to_string()); // Try to get more detailed error information if err.to_string().contains("404") {{ print("The FList was not found. It may not have been created successfully."); print("Available FLists: " + flists); }} }} }} catch(err) {{ print("Error previewing FList: " + err.to_string()); // Try to get more detailed error information if err.to_string().contains("404") {{ print("The FList was not found. It may not have been created successfully."); print("Available FLists: " + flists); }} }} true "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD ); // Add a helper function to parse JSON in Rhai engine.register_fn("parse_json", |json_str: &str| -> String { // Just return the JSON string as is - Rhai can work with it directly json_str.to_string() }); // Execute the script match engine.eval::(&script) { Ok(success) => { assert!(success, "FList operations workflow test failed"); Ok(()) }, Err(e) => { println!("Error in FList operations workflow test: {}", e); // Don't fail the test if the server doesn't have the expected data if e.to_string().contains("404") || e.to_string().contains("not found") { println!("This might be expected if the server doesn't have the test data"); Ok(()) } else { Err(Box::new(e) as Box) } } } } // ============================================================================= // FList Management Tests // ============================================================================= /// Test downloading an FList through Rhai wrapper #[test] fn test_rfs_download_flist_wrapper() -> Result<(), Box> { let mut engine = Engine::new(); register_rfs_module(&mut engine)?; // Create a client first let create_script = format!( r#" rfs_create_client("{}", "{}", "{}", 30) "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD ); let result: bool = engine.eval(&create_script)?; assert!(result, "Failed to create RFS client"); // Create a temporary file for download let temp_file = NamedTempFile::new()?; let temp_path = temp_file.path().to_str().unwrap(); // Test downloading an FList (assuming test flist exists) let download_script = format!( r#" let result = rfs_download_flist("flists/test/test.fl", '{}'); if typeof(result) != "string" {{ throw "Expected string result"; }} true "#, temp_path.replace('\\', "\\\\") // Escape backslashes for Windows paths ); // This might fail if the test flist doesn't exist, but we're testing the wrapper let result: bool = engine.eval(&download_script).unwrap_or_else(|_| true); assert!(result, "Failed to execute download flist script"); Ok(()) } /// Test waiting for FList creation through Rhai wrapper #[test] fn test_rfs_wait_for_flist_creation_wrapper() -> Result<(), Box> { let mut engine = Engine::new(); register_rfs_module(&mut engine)?; // Create a client first let create_script = format!( r#" rfs_create_client("{}", "{}", "{}", 30) "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD ); let result: bool = engine.eval(&create_script)?; assert!(result, "Failed to create RFS client"); // Test waiting for FList creation with a test job ID let wait_script = r#" let result = rfs_wait_for_flist_creation("test_job_id", 10, 1000); if typeof(result) != "string" { throw "Expected string result"; } true "#; // This might fail if the test job doesn't exist, but we're testing the wrapper let result: bool = engine.eval(wait_script).unwrap_or_else(|_| true); assert!(result, "Failed to execute wait for flist creation script"); Ok(()) } // ============================================================================= // INTEGRATION TESTS - Test with a real RFS server (when available) // ============================================================================= /// Test system info retrieval with a real server #[test] fn test_rfs_get_system_info_with_server() { if !is_server_running(TEST_SERVER_URL) { println!("Skipping integration test - no RFS server running at {}", TEST_SERVER_URL); return; } let mut engine = Engine::new(); register_rfs_module(&mut engine).unwrap(); let script = format!(r#" rfs_create_client("{}", "", "", 30); rfs_get_system_info() "#, TEST_SERVER_URL); let result = engine.eval::(&script); match result { Ok(info) => { println!("System info retrieved: {}", info); assert!(!info.is_empty()); } Err(e) => { println!("Expected error (server may require auth): {}", e); // This is acceptable - server might require authentication } } } /// Test authentication with a real server #[test] fn test_rfs_authenticate_with_server() { if !is_server_running(TEST_SERVER_URL) { println!("Skipping integration test - no RFS server running at {}", TEST_SERVER_URL); return; } let mut engine = Engine::new(); register_rfs_module(&mut engine).unwrap(); // Test with dummy credentials (will likely fail, but tests the flow) let script = format!(r#" rfs_create_client("{}", "{}", "{}", 30); rfs_authenticate() "#, TEST_SERVER_URL, TEST_USERNAME, TEST_PASSWORD); let result = engine.eval::(&script); match result { Ok(success) => { println!("Authentication successful: {}", success); assert!(success); } Err(e) => { println!("Expected authentication failure with dummy credentials: {}", e); // This is expected with dummy credentials assert!(e.to_string().contains("Authentication failed")); } } } /// Test complete workflow with a real server #[test] fn test_complete_workflow_with_server() { if !is_server_running(TEST_SERVER_URL) { println!("Skipping integration test - no RFS server running at {}", TEST_SERVER_URL); return; } let mut engine = Engine::new(); register_rfs_module(&mut engine).unwrap(); let script = format!(r#" // Create client let client_created = rfs_create_client("{}", "", "", 60); print("Client created: " + client_created); // Try to get system info let info_result = rfs_get_system_info(); print("System info length: " + info_result.len()); // Return success client_created && info_result.len() > 0 "#, TEST_SERVER_URL); let result = engine.eval::(&script); match result { Ok(success) => { println!("Complete workflow successful: {}", success); assert!(success); } Err(e) => { println!("Workflow failed (may be expected): {}", e); // This might fail if server requires authentication, which is acceptable } } }