release: NX9-WG v1.0.0

This commit is contained in:
thakares committed 2026-08-18 17:32:56 +05:30
1 parent c8a9b7cde6
commit 4dfe42fe68
42 files changed
+4689 -336

No files matched your search

+175
View File
@@ -234,3 +234,178 @@ async fn test_networks_and_firewall_rest_lifecycle() {
assert_eq!(rule_val["name"], "Allow HTTPS");
assert_eq!(rule_val["priority"], 10);
}
#[tokio::test]
async fn test_list_all_peers_collection_endpoint() {
let (app, cookie) = setup_test_app().await;
// 1. Verify unauthenticated GET /api/v1/peers returns 401 Unauthorized
let unauth_req = Request::builder()
.uri("/api/v1/peers")
.body(Body::empty())
.unwrap();
let unauth_resp = app.clone().oneshot(unauth_req).await.unwrap();
assert_eq!(unauth_resp.status(), StatusCode::UNAUTHORIZED);
// 2. Create first interface (wg0)
let iface0_req = Request::builder()
.method("POST")
.uri("/api/v1/interfaces")
.header(header::COOKIE, &cookie)
.header(header::CONTENT_TYPE, "application/json")
.body(Body::from(
json!({
"name": "wg0",
"listen_port": 51820,
"address_v4": "10.100.0.1/24"
})
.to_string(),
))
.unwrap();
let iface0_resp = app.clone().oneshot(iface0_req).await.unwrap();
assert_eq!(iface0_resp.status(), StatusCode::OK);
let iface0_val: Value =
serde_json::from_slice(&to_bytes(iface0_resp.into_body(), usize::MAX).await.unwrap())
.unwrap();
let iface0_id = iface0_val["id"].as_str().unwrap();
// 3. Create second interface (wg1)
let iface1_req = Request::builder()
.method("POST")
.uri("/api/v1/interfaces")
.header(header::COOKIE, &cookie)
.header(header::CONTENT_TYPE, "application/json")
.body(Body::from(
json!({
"name": "wg1",
"listen_port": 51821,
"address_v4": "10.200.0.1/24"
})
.to_string(),
))
.unwrap();
let iface1_resp = app.clone().oneshot(iface1_req).await.unwrap();
assert_eq!(iface1_resp.status(), StatusCode::OK);
let iface1_val: Value =
serde_json::from_slice(&to_bytes(iface1_resp.into_body(), usize::MAX).await.unwrap())
.unwrap();
let iface1_id = iface1_val["id"].as_str().unwrap();
// 4. Create 2 peers under wg0
let peer_alice_req = Request::builder()
.method("POST")
.uri(format!("/api/v1/interfaces/{iface0_id}/peers"))
.header(header::COOKIE, &cookie)
.header(header::CONTENT_TYPE, "application/json")
.body(Body::from(
json!({
"name": "peer-alice",
"allowed_ips": "10.100.0.2/32"
})
.to_string(),
))
.unwrap();
let resp_alice = app.clone().oneshot(peer_alice_req).await.unwrap();
assert_eq!(resp_alice.status(), StatusCode::OK);
let peer_bob_req = Request::builder()
.method("POST")
.uri(format!("/api/v1/interfaces/{iface0_id}/peers"))
.header(header::COOKIE, &cookie)
.header(header::CONTENT_TYPE, "application/json")
.body(Body::from(
json!({
"name": "peer-bob",
"allowed_ips": "10.100.0.3/32"
})
.to_string(),
))
.unwrap();
let resp_bob = app.clone().oneshot(peer_bob_req).await.unwrap();
assert_eq!(resp_bob.status(), StatusCode::OK);
// 5. Create 1 peer under wg1
let peer_charlie_req = Request::builder()
.method("POST")
.uri(format!("/api/v1/interfaces/{iface1_id}/peers"))
.header(header::COOKIE, &cookie)
.header(header::CONTENT_TYPE, "application/json")
.body(Body::from(
json!({
"name": "peer-charlie",
"allowed_ips": "10.200.0.2/32"
})
.to_string(),
))
.unwrap();
let resp_charlie = app.clone().oneshot(peer_charlie_req).await.unwrap();
assert_eq!(resp_charlie.status(), StatusCode::OK);
// 6. Test GET /api/v1/peers (All peers across all interfaces)
let list_all_req = Request::builder()
.uri("/api/v1/peers")
.header(header::COOKIE, &cookie)
.body(Body::empty())
.unwrap();
let list_all_resp = app.clone().oneshot(list_all_req).await.unwrap();
assert_eq!(list_all_resp.status(), StatusCode::OK);
let all_peers_bytes = to_bytes(list_all_resp.into_body(), usize::MAX)
.await
.unwrap();
let all_peers: Vec<Value> = serde_json::from_slice(&all_peers_bytes).unwrap();
assert_eq!(
all_peers.len(),
3,
"GET /api/v1/peers must return all 3 peers across both interfaces"
);
let peer_names: Vec<&str> = all_peers
.iter()
.map(|p| p["name"].as_str().unwrap())
.collect();
assert!(peer_names.contains(&"peer-alice"));
assert!(peer_names.contains(&"peer-bob"));
assert!(peer_names.contains(&"peer-charlie"));
// Verify representative fields are present and valid
for p in &all_peers {
assert!(p["id"].is_string());
assert!(p["public_key"].is_string());
assert!(p["interface_id"].is_string());
assert!(p["state"].is_string());
assert!(p["allowed_ips"].is_string());
}
// 7. Verify interface-scoped endpoint still works and returns only that interface's peers
let list_iface0_req = Request::builder()
.uri(format!("/api/v1/interfaces/{iface0_id}/peers"))
.header(header::COOKIE, &cookie)
.body(Body::empty())
.unwrap();
let iface0_peers_resp = app.clone().oneshot(list_iface0_req).await.unwrap();
assert_eq!(iface0_peers_resp.status(), StatusCode::OK);
let iface0_peers: Vec<Value> = serde_json::from_slice(
&to_bytes(iface0_peers_resp.into_body(), usize::MAX)
.await
.unwrap(),
)
.unwrap();
assert_eq!(iface0_peers.len(), 2, "wg0 must return exactly 2 peers");
let list_iface1_req = Request::builder()
.uri(format!("/api/v1/interfaces/{iface1_id}/peers"))
.header(header::COOKIE, &cookie)
.body(Body::empty())
.unwrap();
let iface1_peers_resp = app.oneshot(list_iface1_req).await.unwrap();
assert_eq!(iface1_peers_resp.status(), StatusCode::OK);
let iface1_peers: Vec<Value> = serde_json::from_slice(
&to_bytes(iface1_peers_resp.into_body(), usize::MAX)
.await
.unwrap(),
)
.unwrap();
assert_eq!(iface1_peers.len(), 1, "wg1 must return exactly 1 peer");
assert_eq!(iface1_peers[0]["name"], "peer-charlie");
}