| Crates.io | freenet-test-network |
| lib.rs | freenet-test-network |
| version | 0.1.21 |
| created_at | 2025-11-01 04:27:07.882951+00 |
| updated_at | 2026-01-13 05:30:44.07576+00 |
| description | Reliable test network infrastructure for Freenet |
| homepage | |
| repository | https://github.com/freenet/freenet-test-network |
| max_upload_size | |
| id | 1911683 |
| size | 331,684 |
Reliable test network infrastructure for Freenet integration testing.
Testing Freenet requires spinning up multiple local peers, which has been unreliable and flaky. This crate provides a simple, reliable way to create test networks.
use freenet_test_network::TestNetwork;
use std::sync::LazyLock;
// Shared network for all tests (starts once)
static NETWORK: LazyLock<TestNetwork> = LazyLock::new(|| {
TestNetwork::builder()
.gateways(1)
.peers(5)
.build_sync()
.unwrap()
});
#[tokio::test]
async fn my_test() -> anyhow::Result<()> {
let network = &*NETWORK;
// Each test gets its own WebSocket connection
let ws_url = network.gateway(0).ws_url();
// Use freenet_stdlib::client_api::WebApi to connect
// ...
Ok(())
}
Alpha - Core functionality working, including remote SSH peer support for realistic NAT/firewall testing.
When a network fails to reach the desired connectivity threshold the builder now:
peer.log, configs, and keys) for later inspectionEnable preservation with:
let network = TestNetwork::builder()
.gateways(1)
.peers(2)
.preserve_temp_dirs_on_failure(true)
.build()
.await?;
If startup fails, the preserved artifacts are placed under /tmp/freenet-test-network-<timestamp>/.
New: Test Freenet peers behind simulated NAT routers using Docker containers.
Testing on localhost can't catch bugs related to:
use freenet_test_network::{TestNetwork, Backend, DockerNatConfig};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let network = TestNetwork::builder()
.gateways(1) // Gateway on public network
.peers(2) // Peers behind NAT
.backend(Backend::DockerNat(DockerNatConfig::default()))
.build()
.await?;
// Each peer runs in its own container behind a NAT router
println!("Gateway: {}", network.gateway(0).ws_url());
println!("Peer 0 (NAT): {}", network.peer(0).ws_url());
Ok(())
}
The Docker NAT backend automatically cleans up resources:
Resource names include timestamps (e.g., freenet-nat-20251126-211500-13135) for easy identification.
If resources are somehow left behind, you can manually clean them:
# List freenet-nat resources
docker ps -a | grep freenet-nat
docker network ls | grep freenet-nat
# Remove all freenet-nat containers
docker ps -a | grep freenet-nat | awk '{print $1}' | xargs -r docker rm -f
# Remove all freenet-nat networks
docker network ls | grep freenet-nat | awk '{print $1}' | xargs -r docker network rm
See examples/docker_nat.rs for a complete example:
cargo run --example docker_nat
# Or with custom peer count:
PEER_COUNT=4 cargo run --example docker_nat
New in v0.2: Spawn peers on remote Linux machines via SSH for realistic NAT/firewall testing.
Testing on localhost (127.0.0.1) can't catch bugs related to:
use freenet_test_network::{TestNetwork, PeerLocation, RemoteMachine};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Configure remote machine
let remote = RemoteMachine::new("192.168.1.100")
.user("testuser")
.identity_file("/home/user/.ssh/id_rsa");
// Build network with remote peer
let network = TestNetwork::builder()
.gateways(1) // Local gateway
.peers(2) // 2 regular peers
.peer_location(2, PeerLocation::Remote(remote)) // Make peer #2 remote
.build()
.await?;
// Use network as normal
let ws_url = network.peer(1).ws_url();
Ok(())
}
let remote = RemoteMachine::new("example.com")
.user("testuser") // SSH username (default: current user)
.port(2222) // SSH port (default: 22)
.identity_file("/path/to/key") // SSH private key
.freenet_binary("/usr/local/bin/freenet") // Pre-installed binary path (optional)
.work_dir("/tmp/freenet-tests"); // Working directory (default: /tmp/freenet-test-network)
let remote1 = RemoteMachine::new("192.168.1.100");
let remote2 = RemoteMachine::new("192.168.1.101");
let network = TestNetwork::builder()
.gateways(1)
.peers(3)
.peer_location(1, PeerLocation::Remote(remote1))
.peer_location(2, PeerLocation::Remote(remote2))
// peer 0 and gateway remain local
.build()
.await?;
Round-robin distribution across multiple machines:
let machines = vec![
RemoteMachine::new("192.168.1.100"),
RemoteMachine::new("192.168.1.101"),
];
let network = TestNetwork::builder()
.gateways(2)
.peers(4)
.distribute_across_remotes(machines) // Alternates peers across machines
.build()
.await?;
nohup over SSH, PID capturedSee examples/remote_peer.rs for a complete example.
export REMOTE_HOST=192.168.1.100
export REMOTE_USER=testuser
export SSH_KEY_PATH=$HOME/.ssh/id_rsa
cargo run --example remote_peer
LGPL-3.0-only