#![cfg(feature = "agent")]
mod common;
use async_snmp::transport::UdpTransport;
use async_snmp::{Auth, Client, Error, Retry, Value, oid};
use common::TestAgent;
use std::time::Duration;
#[tokio::test]
async fn get_returns_value() {
let agent = TestAgent::new().await;
let client = Client::builder(agent.addr().to_string(), Auth::v2c("public"))
.connect()
.await
.unwrap();
let result = client.get(&oid!(1, 3, 6, 1, 2, 1, 1, 1, 0)).await.unwrap();
assert_eq!(result.value.as_str(), Some("Test SNMP Agent"));
}
#[tokio::test]
async fn get_missing_oid_returns_no_such_instance() {
let agent = TestAgent::new().await;
let client = Client::builder(agent.addr().to_string(), Auth::v2c("public"))
.connect()
.await
.unwrap();
let result = client.get(&oid!(1, 3, 6, 1, 99, 99, 99)).await.unwrap();
assert_eq!(result.value, Value::NoSuchInstance);
}
#[tokio::test]
async fn get_many_returns_all_values() {
let agent = TestAgent::new().await;
let client = Client::builder(agent.addr().to_string(), Auth::v2c("public"))
.connect()
.await
.unwrap();
let oids = [
oid!(1, 3, 6, 1, 2, 1, 1, 1, 0), oid!(1, 3, 6, 1, 2, 1, 1, 3, 0), oid!(1, 3, 6, 1, 2, 1, 1, 5, 0), ];
let results = client.get_many(&oids).await.unwrap();
assert_eq!(results.len(), 3);
assert_eq!(results[0].value.as_str(), Some("Test SNMP Agent"));
assert!(matches!(results[1].value, Value::TimeTicks(_)));
assert_eq!(results[2].value.as_str(), Some("test-agent"));
}
#[tokio::test]
async fn get_timeout_when_agent_stopped() {
let agent = TestAgent::new().await;
let addr = agent.addr();
agent.stop();
tokio::time::sleep(Duration::from_millis(10)).await;
let client = Client::builder(addr.to_string(), Auth::v2c("public"))
.timeout(Duration::from_millis(100))
.retry(Retry::none()) .connect()
.await
.unwrap();
let result = client.get(&oid!(1, 3, 6, 1, 2, 1, 1, 1, 0)).await;
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("timeout"));
}
#[tokio::test]
async fn set_modifies_value() {
let agent = TestAgent::new().await;
let client = Client::builder(agent.addr().to_string(), Auth::v2c("public"))
.connect()
.await
.unwrap();
let new_value = Value::OctetString("Modified Name".into());
let result = client
.set(&oid!(1, 3, 6, 1, 2, 1, 1, 5, 0), new_value.clone())
.await
.unwrap();
assert_eq!(result.value, new_value);
let get_result = client.get(&oid!(1, 3, 6, 1, 2, 1, 1, 5, 0)).await.unwrap();
assert_eq!(get_result.value, new_value);
}
#[tokio::test]
async fn set_many_modifies_values() {
let agent = TestAgent::new().await;
let client = Client::builder(agent.addr().to_string(), Auth::v2c("public"))
.connect()
.await
.unwrap();
let varbinds = [
(
oid!(1, 3, 6, 1, 2, 1, 1, 4, 0),
Value::OctetString("new-contact".into()),
),
(
oid!(1, 3, 6, 1, 2, 1, 1, 6, 0),
Value::OctetString("new-location".into()),
),
];
for (oid, value) in &varbinds {
client.set(oid, value.clone()).await.unwrap();
}
for (oid, expected) in &varbinds {
let result = client.get(oid).await.unwrap();
assert_eq!(&result.value, expected);
}
}
#[tokio::test]
async fn set_many_rejects_oversized_request() {
let agent = TestAgent::new().await;
let client = Client::builder(agent.addr().to_string(), Auth::v2c("public"))
.max_oids_per_request(2)
.connect()
.await
.unwrap();
let varbinds = [
(
oid!(1, 3, 6, 1, 2, 1, 1, 4, 0),
Value::OctetString("a".into()),
),
(
oid!(1, 3, 6, 1, 2, 1, 1, 5, 0),
Value::OctetString("b".into()),
),
(
oid!(1, 3, 6, 1, 2, 1, 1, 6, 0),
Value::OctetString("c".into()),
),
];
let err = client.set_many(&varbinds).await.unwrap_err();
assert!(
matches!(*err, Error::Config(ref msg) if msg.contains("set_many") && msg.contains("atomic")),
"expected Config error about atomicity, got: {err}"
);
}
#[tokio::test]
async fn v1_get_works() {
let agent = TestAgent::new().await;
let client = Client::builder(agent.addr().to_string(), Auth::v1("public"))
.connect()
.await
.unwrap();
let result = client.get(&oid!(1, 3, 6, 1, 2, 1, 1, 1, 0)).await.unwrap();
assert_eq!(result.value.as_str(), Some("Test SNMP Agent"));
}
#[tokio::test]
async fn getnext_returns_next_oid() {
let agent = TestAgent::new().await;
let client = Client::builder(agent.addr().to_string(), Auth::v2c("public"))
.connect()
.await
.unwrap();
let result = client
.get_next(&oid!(1, 3, 6, 1, 2, 1, 1, 1, 0))
.await
.unwrap();
assert_eq!(result.oid, oid!(1, 3, 6, 1, 2, 1, 1, 2, 0));
}
#[tokio::test]
async fn getnext_past_end_returns_end_of_mib_view() {
let agent = TestAgent::new().await;
let client = Client::builder(agent.addr().to_string(), Auth::v2c("public"))
.connect()
.await
.unwrap();
let result = client
.get_next(&oid!(1, 3, 6, 1, 2, 1, 1, 7, 0))
.await
.unwrap();
assert_eq!(result.value, Value::EndOfMibView);
}
#[tokio::test]
async fn ipv6_transport_reaches_ipv4_agent() {
let agent = TestAgent::new().await;
assert!(agent.addr().is_ipv4(), "TestAgent should bind to IPv4");
let transport = UdpTransport::bind("[::]:0").await.unwrap();
let client = Client::builder(agent.addr().to_string(), Auth::v2c("public"))
.timeout(Duration::from_secs(2))
.build_with(&transport)
.await
.unwrap();
let result = client.get(&oid!(1, 3, 6, 1, 2, 1, 1, 1, 0)).await.unwrap();
assert_eq!(result.value.as_str(), Some("Test SNMP Agent"));
}