use factorio_rcon::{RconClient, RconError};
use std::time::Duration;
const TEST_ADDR: &str = "127.0.0.1:27015";
const TEST_PASSWORD: &str = "password";
#[tokio::test]
#[ignore] async fn test_real_factorio_connection() {
let mut client = RconClient::connect(TEST_ADDR, TEST_PASSWORD)
.await
.expect("Failed to connect - is Factorio running as multiplayer host?");
let version = client
.execute("/version")
.await
.expect("Failed to execute /version");
println!("Factorio version: {}", version);
assert!(!version.is_empty());
assert!(version.contains("Factorio") || version.contains("Version"));
}
#[tokio::test]
#[ignore] async fn test_lua_execution() {
let mut client = RconClient::connect(TEST_ADDR, TEST_PASSWORD)
.await
.expect("Failed to connect");
let tick = client
.execute("/c rcon.print(game.tick)")
.await
.expect("Failed to execute Lua command");
println!("Current game tick: {}", tick);
let _tick_num: u64 = tick.trim().parse().expect("Tick should be a valid number");
}
#[tokio::test]
#[ignore] async fn test_auth_failure() {
let result = RconClient::connect(TEST_ADDR, "wrong_password").await;
match result {
Err(RconError::AuthFailed) => {
println!("Auth correctly failed with wrong password");
}
Ok(_) => panic!("Should have failed authentication with wrong password"),
Err(e) => panic!("Wrong error type: expected AuthFailed, got {:?}", e),
}
}
#[tokio::test]
#[ignore] async fn test_connection_refused() {
let result = RconClient::connect("127.0.0.1:9999", TEST_PASSWORD).await;
match result {
Err(RconError::ConnectionFailed(_)) => {
println!("Connection correctly failed for invalid address");
}
Ok(_) => panic!("Should have failed to connect to non-existent server"),
Err(e) => panic!("Wrong error type: expected ConnectionFailed, got {:?}", e),
}
}
#[tokio::test]
#[ignore] async fn test_large_response() {
let mut client = RconClient::connect(TEST_ADDR, TEST_PASSWORD)
.await
.expect("Failed to connect");
let surfaces = client
.execute("/c rcon.print(serpent.line(game.surfaces))")
.await
.expect("Failed to query surfaces");
println!("Surfaces response length: {} bytes", surfaces.len());
assert!(!surfaces.is_empty());
let entities = client
.execute_with_timeout(
"/c rcon.print(serpent.line(game.surfaces[1].find_entities()))",
Duration::from_secs(10),
)
.await
.expect("Failed to query entities");
println!("Entities response length: {} bytes", entities.len());
assert!(!entities.is_empty());
if entities.len() > 65536 {
println!("✅ Successfully handled fragmented response (>64KB)");
}
}
#[tokio::test]
#[ignore] async fn test_timeout() {
let mut client = RconClient::connect(TEST_ADDR, TEST_PASSWORD)
.await
.expect("Failed to connect");
client.set_timeout(Duration::from_millis(1));
let result = client.execute("/c rcon.print(game.tick)").await;
match result {
Err(RconError::Timeout(ms)) => {
println!("Command correctly timed out after {}ms", ms);
assert!(ms <= 10); }
Ok(_) => {
println!("Warning: Command completed faster than timeout - this is rare but possible");
}
Err(e) => panic!("Wrong error type: expected Timeout, got {:?}", e),
}
}
#[tokio::test]
#[ignore] async fn test_multiple_commands() {
let mut client = RconClient::connect(TEST_ADDR, TEST_PASSWORD)
.await
.expect("Failed to connect");
for i in 1..=5 {
let result = client
.execute(&format!("/c rcon.print('Command {}')", i))
.await
.expect("Failed to execute command");
println!("Command {} result: {}", i, result);
assert_eq!(result.trim(), format!("Command {}", i));
}
}
#[tokio::test]
#[ignore] async fn test_serpent_serialization() {
let mut client = RconClient::connect(TEST_ADDR, TEST_PASSWORD)
.await
.expect("Failed to connect");
let player_count = client
.execute("/c rcon.print(serpent.line(#game.connected_players))")
.await
.expect("Failed to query player count");
println!("Connected players: {}", player_count);
let count: usize = player_count
.trim()
.parse()
.expect("Player count should be a number");
if count > 0 {
let player_name = client
.execute("/c rcon.print(serpent.line(game.connected_players[1].name))")
.await
.expect("Failed to query player name");
println!("First player name: {}", player_name);
assert!(!player_name.trim().is_empty());
}
}