use crate::models::common::{IpAddress, MacAddress};
use serde::Deserialize;
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
pub enum PortConnector {
#[serde(rename = "RJ45")]
Rj45,
#[serde(rename = "SFP")]
Sfp,
#[serde(rename = "SFPPLUS")]
SfpPlus,
#[serde(rename = "SFP28")]
Sfp28,
#[serde(rename = "QSFP28")]
Qsfp28,
#[serde(other)]
Unknown,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum InterfaceState {
Up,
Down,
#[serde(other)]
Unknown,
}
#[derive(Clone, Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PoE {
#[serde(default)]
pub standard: Option<String>,
#[serde(default, rename = "type")]
pub r#type: Option<i32>,
#[serde(default)]
pub enabled: Option<bool>,
#[serde(default)]
pub state: Option<String>,
}
impl PoE {
pub fn is_enabled(&self) -> bool {
self.enabled.unwrap_or(false)
}
pub fn is_active(&self) -> bool {
self.is_enabled() && self.state.as_deref() == Some("UP")
}
}
#[derive(Clone, Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Port {
pub idx: i32,
pub state: InterfaceState,
pub connector: PortConnector,
pub max_speed_mbps: i32,
#[serde(default)]
pub speed_mbps: Option<i32>,
#[serde(default)]
pub poe: Option<PoE>,
}
impl Port {
pub fn has_poe(&self) -> bool {
self.poe.is_some()
}
pub fn is_poe_active(&self) -> bool {
self.poe.as_ref().map(|p| p.is_active()).unwrap_or(false)
}
pub fn is_poe_enabled(&self) -> bool {
self.poe.as_ref().map(|p| p.is_enabled()).unwrap_or(false)
}
pub fn is_up(&self) -> bool {
self.state == InterfaceState::Up
}
pub fn is_down(&self) -> bool {
self.state == InterfaceState::Down
}
pub fn speed_gbps(&self) -> Option<f64> {
self.speed_mbps.map(|s| s as f64 / 1000.0)
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
pub enum WirelessStandard {
#[serde(rename = "802.11a")]
Standard802_11a,
#[serde(rename = "802.11b")]
Standard802_11b,
#[serde(rename = "802.11g")]
Standard802_11g,
#[serde(rename = "802.11n")]
Standard802_11n,
#[serde(rename = "802.11ac")]
Standard802_11ac,
#[serde(rename = "802.11ax")]
Standard802_11ax,
#[serde(rename = "802.11be")]
Standard802_11be,
#[serde(other)]
Unknown,
}
#[derive(Clone, Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Radio {
pub wlan_standard: WirelessStandard,
#[serde(rename = "frequencyGHz")]
pub frequency_ghz: f64,
#[serde(rename = "channelWidthMHz")]
pub channel_width_mhz: i32,
#[serde(default)]
pub channel: Option<i32>,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct PhysicalInterfaces {
#[serde(default)]
pub ports: Vec<Port>,
#[serde(default)]
pub radios: Vec<Radio>,
}
#[derive(Clone, Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DeviceUplink {
pub device_id: String,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct SwitchingFeature {
}
#[derive(Clone, Debug, Deserialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct AccessPointFeature {
}
#[derive(Clone, Debug, Deserialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct DeviceFeatures {
#[serde(default)]
pub switching: Option<SwitchingFeature>,
#[serde(default)]
pub access_point: Option<AccessPointFeature>,
}
#[derive(Clone, Debug, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DeviceDetails {
pub id: String,
pub mac_address: MacAddress,
pub ip_address: IpAddress,
pub name: String,
pub model: String,
pub supported: bool,
pub state: String,
#[serde(default)]
pub firmware_version: Option<String>,
pub firmware_updatable: bool,
#[serde(default)]
pub adopted_at: Option<String>,
#[serde(default)]
pub provisioned_at: Option<String>,
pub configuration_id: String,
#[serde(default)]
pub uplink: Option<DeviceUplink>,
#[serde(default)]
pub features: DeviceFeatures,
#[serde(default)]
pub interfaces: PhysicalInterfaces,
}
impl DeviceDetails {
pub fn is_online(&self) -> bool {
self.state == "ONLINE"
}
pub fn is_offline(&self) -> bool {
self.state == "OFFLINE"
}
pub fn port_count(&self) -> usize {
self.interfaces.ports.len()
}
pub fn radio_count(&self) -> usize {
self.interfaces.radios.len()
}
pub fn has_switching(&self) -> bool {
self.features.switching.is_some()
}
pub fn has_access_point(&self) -> bool {
self.features.access_point.is_some()
}
pub fn active_ports(&self) -> Vec<&Port> {
self.interfaces
.ports
.iter()
.filter(|p| p.state == InterfaceState::Up)
.collect()
}
pub fn inactive_ports(&self) -> Vec<&Port> {
self.interfaces
.ports
.iter()
.filter(|p| p.state == InterfaceState::Down)
.collect()
}
pub fn is_switch(&self) -> bool {
self.has_switching()
}
pub fn poe_ports(&self) -> Vec<&Port> {
self.interfaces
.ports
.iter()
.filter(|p| p.has_poe())
.collect()
}
pub fn poe_enabled_ports(&self) -> Vec<&Port> {
self.interfaces
.ports
.iter()
.filter(|p| p.is_poe_enabled())
.collect()
}
pub fn poe_active_ports(&self) -> Vec<&Port> {
self.interfaces
.ports
.iter()
.filter(|p| p.is_poe_active())
.collect()
}
pub fn poe_port_count(&self) -> usize {
self.poe_ports().len()
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_radio_deserialization() {
let radio_json = json!({
"wlanStandard": "802.11a",
"frequencyGHz": 2.4,
"channelWidthMHz": 40,
"channel": 36
});
match serde_json::from_value::<Radio>(radio_json) {
Ok(radio) => assert_eq!(radio.frequency_ghz, 2.4),
Err(e) => panic!("Failed to deserialize radio: {}", e),
}
}
#[test]
fn test_device_details_deserialization() {
let radio_json = json!({
"wlanStandard": "802.11a",
"frequencyGHz": 2.4,
"channelWidthMHz": 40,
"channel": 36
});
match serde_json::from_value::<Radio>(radio_json) {
Ok(radio) => assert_eq!(radio.frequency_ghz, 2.4),
Err(e) => panic!("Failed to deserialize radio in device test: {}", e),
}
let json_data = json!({
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"macAddress": "94:2a:6f:26:c6:ca",
"ipAddress": "192.168.1.55",
"name": "IW HD",
"model": "UHDIW",
"supported": true,
"state": "ONLINE",
"firmwareVersion": "6.6.55",
"firmwareUpdatable": true,
"adoptedAt": "2019-08-24T14:15:22Z",
"provisionedAt": "2019-08-24T14:15:22Z",
"configurationId": "7596498d2f367dc2",
"uplink": {
"deviceId": "4de4adb9-21ee-47e3-aeb4-8cf8ed6c109a"
},
"features": {
"switching": null,
"accessPoint": null
},
"interfaces": {
"ports": [
{
"idx": 1,
"state": "UP",
"connector": "RJ45",
"maxSpeedMbps": 10000,
"speedMbps": 1000,
"poe": {
"standard": "802.3bt",
"type": 3,
"enabled": true,
"state": "UP"
}
}
],
"radios": [
{
"wlanStandard": "802.11a",
"frequencyGHz": 2.4,
"channelWidthMHz": 40,
"channel": 36
}
]
}
});
let device: DeviceDetails = serde_json::from_value(json_data).unwrap();
assert_eq!(device.id, "497f6eca-6276-4993-bfeb-53cbbbba6f08");
assert_eq!(device.mac_address.as_str(), "94:2a:6f:26:c6:ca");
assert_eq!(device.ip_address.to_string(), "192.168.1.55");
assert_eq!(device.name, "IW HD");
assert_eq!(device.model, "UHDIW");
assert!(device.supported);
assert_eq!(device.state, "ONLINE");
assert_eq!(device.firmware_version, Some("6.6.55".to_string()));
assert!(device.firmware_updatable);
assert_eq!(device.port_count(), 1);
assert_eq!(device.radio_count(), 1);
assert!(device.is_online());
}
#[test]
fn test_device_details_ports() {
let json_data = json!({
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"macAddress": "94:2a:6f:26:c6:ca",
"ipAddress": "192.168.1.55",
"name": "Test Switch",
"model": "USW-24",
"supported": true,
"state": "ONLINE",
"firmwareUpdatable": false,
"configurationId": "config123",
"uplink": {
"deviceId": "uplink-device"
},
"features": {},
"interfaces": {
"ports": [
{
"idx": 1,
"state": "UP",
"connector": "RJ45",
"maxSpeedMbps": 1000,
"speedMbps": 1000
},
{
"idx": 2,
"state": "DOWN",
"connector": "RJ45",
"maxSpeedMbps": 1000
}
],
"radios": []
}
});
let device: DeviceDetails = serde_json::from_value(json_data).unwrap();
assert_eq!(device.port_count(), 2);
assert_eq!(device.radio_count(), 0);
assert_eq!(device.active_ports().len(), 1);
assert_eq!(device.inactive_ports().len(), 1);
}
#[test]
fn test_device_details_features() {
let json_data = json!({
"id": "device-with-features",
"macAddress": "94:2a:6f:26:c6:ca",
"ipAddress": "192.168.1.55",
"name": "Multi-function Device",
"model": "UDM-Pro",
"supported": true,
"state": "ONLINE",
"firmwareUpdatable": false,
"configurationId": "config123",
"uplink": {
"deviceId": "uplink-device"
},
"features": {
"switching": {},
"accessPoint": {}
},
"interfaces": {
"ports": [],
"radios": []
}
});
let device: DeviceDetails = serde_json::from_value(json_data).unwrap();
assert!(device.has_switching());
assert!(device.has_access_point());
}
#[test]
fn test_wireless_standard_deserialization() {
let standards = vec![
("\"802.11a\"", WirelessStandard::Standard802_11a),
("\"802.11b\"", WirelessStandard::Standard802_11b),
("\"802.11g\"", WirelessStandard::Standard802_11g),
("\"802.11n\"", WirelessStandard::Standard802_11n),
("\"802.11ac\"", WirelessStandard::Standard802_11ac),
("\"802.11ax\"", WirelessStandard::Standard802_11ax),
("\"802.11be\"", WirelessStandard::Standard802_11be),
];
for (json_str, expected) in standards {
let standard: WirelessStandard = serde_json::from_str(json_str).unwrap();
assert_eq!(standard, expected);
}
}
#[test]
fn test_device_details_real_world_response() {
let json_data = json!({
"id": "device-0001-0000-0000-000000000001",
"macAddress": "00:00:5e:00:53:01",
"ipAddress": "198.51.100.1",
"name": "Test Device UX7",
"model": "Express 7",
"supported": true,
"state": "ONLINE",
"firmwareVersion": "5.0.10",
"firmwareUpdatable": false,
"provisionedAt": "2025-12-30T21:27:06Z",
"configurationId": "config-0001",
"uplink": {
"deviceId": "uplink-device-0001"
},
"features": {
"switching": {},
"accessPoint": {}
},
"interfaces": {
"ports": [
{
"idx": 1,
"state": "UP",
"connector": "RJ45",
"maxSpeedMbps": 2500,
"speedMbps": 1000
},
{
"idx": 2,
"state": "UP",
"connector": "RJ45",
"maxSpeedMbps": 10000,
"speedMbps": 1000
}
],
"radios": [
{
"wlanStandard": "802.11be",
"frequencyGHz": 2.4,
"channelWidthMHz": 20,
"channel": 1
},
{
"wlanStandard": "802.11be",
"frequencyGHz": 5,
"channelWidthMHz": 80,
"channel": 48
},
{
"wlanStandard": "802.11be",
"frequencyGHz": 6,
"channelWidthMHz": 160,
"channel": 37
}
]
}
});
let device: DeviceDetails =
serde_json::from_value(json_data).expect("Failed to deserialize real-world response");
assert_eq!(device.id, "device-0001-0000-0000-000000000001");
assert_eq!(device.name, "Test Device UX7");
assert_eq!(device.model, "Express 7");
assert!(device.supported);
assert_eq!(device.state, "ONLINE");
assert!(device.is_online());
assert_eq!(device.port_count(), 2);
assert_eq!(device.radio_count(), 3);
assert!(device.has_switching());
assert!(device.has_access_point());
assert_eq!(device.active_ports().len(), 2);
assert_eq!(device.inactive_ports().len(), 0);
let port1 = &device.interfaces.ports[0];
assert_eq!(port1.idx, 1);
assert_eq!(port1.max_speed_mbps, 2500);
assert_eq!(port1.speed_mbps, Some(1000));
let port2 = &device.interfaces.ports[1];
assert_eq!(port2.idx, 2);
assert_eq!(port2.max_speed_mbps, 10000);
let radio1 = &device.interfaces.radios[0];
assert_eq!(radio1.wlan_standard, WirelessStandard::Standard802_11be);
assert_eq!(radio1.frequency_ghz, 2.4);
assert_eq!(radio1.channel, Some(1));
let radio2 = &device.interfaces.radios[1];
assert_eq!(radio2.frequency_ghz, 5.0);
assert_eq!(radio2.channel, Some(48));
let radio3 = &device.interfaces.radios[2];
assert_eq!(radio3.frequency_ghz, 6.0);
assert_eq!(radio3.channel, Some(37));
}
#[test]
fn test_device_details_without_optional_fields() {
let json_data = json!({
"id": "minimal-device",
"macAddress": "1c:0b:8b:3e:5c:16",
"ipAddress": "192.168.1.100",
"name": "Minimal Device",
"model": "Test",
"supported": true,
"state": "ONLINE",
"firmwareUpdatable": false,
"configurationId": "config123",
"features": {},
"interfaces": {
"ports": [],
"radios": []
}
});
let device: DeviceDetails =
serde_json::from_value(json_data).expect("Failed to deserialize minimal response");
assert_eq!(device.id, "minimal-device");
assert_eq!(device.name, "Minimal Device");
assert!(device.is_online());
assert!(device.adopted_at.is_none());
assert!(device.uplink.is_none());
assert_eq!(device.port_count(), 0);
assert_eq!(device.radio_count(), 0);
}
#[test]
fn test_port_connector_deserialization() {
let connectors = vec![
("\"RJ45\"", PortConnector::Rj45),
("\"SFP\"", PortConnector::Sfp),
("\"SFPPLUS\"", PortConnector::SfpPlus),
("\"SFP28\"", PortConnector::Sfp28),
("\"QSFP28\"", PortConnector::Qsfp28),
];
for (json_str, expected) in connectors {
let connector: PortConnector = serde_json::from_str(json_str).unwrap();
assert_eq!(connector, expected);
}
}
#[test]
fn test_interface_state_deserialization() {
let up: InterfaceState = serde_json::from_str("\"UP\"").unwrap();
let down: InterfaceState = serde_json::from_str("\"DOWN\"").unwrap();
let unknown: InterfaceState = serde_json::from_str("\"UNKNOWN\"").unwrap();
assert_eq!(up, InterfaceState::Up);
assert_eq!(down, InterfaceState::Down);
assert_eq!(unknown, InterfaceState::Unknown);
}
#[test]
fn test_device_details_with_exact_api_response() {
let json_data = json!({
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"macAddress": "94:2a:6f:26:c6:ca",
"ipAddress": "192.168.1.55",
"name": "IW HD",
"model": "UHDIW",
"supported": true,
"state": "ONLINE",
"firmwareVersion": "6.6.55",
"firmwareUpdatable": true,
"adoptedAt": "2019-08-24T14:15:22Z",
"provisionedAt": "2019-08-24T14:15:22Z",
"configurationId": "7596498d2f367dc2",
"uplink": {
"deviceId": "4de4adb9-21ee-47e3-aeb4-8cf8ed6c109a"
},
"features": {
"switching": null,
"accessPoint": null
},
"interfaces": {
"ports": [
{
"idx": 1,
"state": "UP",
"connector": "RJ45",
"maxSpeedMbps": 10000,
"speedMbps": 1000,
"poe": {
"standard": "802.3bt",
"type": 3,
"enabled": true,
"state": "UP"
}
}
],
"radios": [
{
"wlanStandard": "802.11a",
"frequencyGHz": 2.4,
"channelWidthMHz": 40,
"channel": 36
}
]
}
});
let device: DeviceDetails =
serde_json::from_value(json_data).expect("Failed to deserialize exact API response");
assert_eq!(device.id, "497f6eca-6276-4993-bfeb-53cbbbba6f08");
assert_eq!(device.mac_address.as_str(), "94:2a:6f:26:c6:ca");
assert_eq!(device.ip_address.to_string(), "192.168.1.55");
assert_eq!(device.name, "IW HD");
assert_eq!(device.model, "UHDIW");
assert!(device.supported);
assert_eq!(device.state, "ONLINE");
assert_eq!(device.firmware_version, Some("6.6.55".to_string()));
assert!(device.firmware_updatable);
assert!(device.is_online());
assert_eq!(device.port_count(), 1);
assert_eq!(device.radio_count(), 1);
let port = &device.interfaces.ports[0];
assert_eq!(port.idx, 1);
assert_eq!(port.state, InterfaceState::Up);
assert_eq!(port.connector, PortConnector::Rj45);
assert_eq!(port.max_speed_mbps, 10000);
assert_eq!(port.speed_mbps, Some(1000));
assert!(port.poe.is_some());
let poe = port.poe.as_ref().unwrap();
assert_eq!(poe.standard, Some("802.3bt".to_string()));
assert_eq!(poe.r#type, Some(3));
assert_eq!(poe.enabled, Some(true));
let radio = &device.interfaces.radios[0];
assert_eq!(radio.wlan_standard, WirelessStandard::Standard802_11a);
assert_eq!(radio.frequency_ghz, 2.4);
assert_eq!(radio.channel_width_mhz, 40);
assert_eq!(radio.channel, Some(36));
}
#[test]
fn test_poe_methods() {
let poe_active = PoE {
standard: Some("802.3bt".to_string()),
r#type: Some(3),
enabled: Some(true),
state: Some("UP".to_string()),
};
assert!(poe_active.is_enabled());
assert!(poe_active.is_active());
let poe_enabled_down = PoE {
standard: Some("802.3at".to_string()),
r#type: Some(2),
enabled: Some(true),
state: Some("DOWN".to_string()),
};
assert!(poe_enabled_down.is_enabled());
assert!(!poe_enabled_down.is_active());
let poe_disabled = PoE {
standard: Some("802.3af".to_string()),
r#type: Some(1),
enabled: Some(false),
state: None,
};
assert!(!poe_disabled.is_enabled());
assert!(!poe_disabled.is_active());
let poe_none = PoE {
standard: None,
r#type: None,
enabled: None,
state: None,
};
assert!(!poe_none.is_enabled());
assert!(!poe_none.is_active());
}
#[test]
fn test_port_poe_methods() {
let port_with_poe = Port {
idx: 1,
state: InterfaceState::Up,
connector: PortConnector::Rj45,
max_speed_mbps: 1000,
speed_mbps: Some(1000),
poe: Some(PoE {
standard: Some("802.3bt".to_string()),
r#type: Some(3),
enabled: Some(true),
state: Some("UP".to_string()),
}),
};
assert!(port_with_poe.has_poe());
assert!(port_with_poe.is_poe_enabled());
assert!(port_with_poe.is_poe_active());
let port_poe_disabled = Port {
idx: 2,
state: InterfaceState::Up,
connector: PortConnector::Rj45,
max_speed_mbps: 1000,
speed_mbps: Some(1000),
poe: Some(PoE {
standard: Some("802.3at".to_string()),
r#type: Some(2),
enabled: Some(false),
state: None,
}),
};
assert!(port_poe_disabled.has_poe());
assert!(!port_poe_disabled.is_poe_enabled());
assert!(!port_poe_disabled.is_poe_active());
let port_no_poe = Port {
idx: 3,
state: InterfaceState::Up,
connector: PortConnector::Sfp,
max_speed_mbps: 10000,
speed_mbps: Some(10000),
poe: None,
};
assert!(!port_no_poe.has_poe());
assert!(!port_no_poe.is_poe_enabled());
assert!(!port_no_poe.is_poe_active());
}
#[test]
fn test_port_state_methods() {
let port_up = Port {
idx: 1,
state: InterfaceState::Up,
connector: PortConnector::Rj45,
max_speed_mbps: 1000,
speed_mbps: Some(1000),
poe: None,
};
assert!(port_up.is_up());
assert!(!port_up.is_down());
assert_eq!(port_up.speed_gbps(), Some(1.0));
let port_down = Port {
idx: 2,
state: InterfaceState::Down,
connector: PortConnector::Rj45,
max_speed_mbps: 1000,
speed_mbps: None,
poe: None,
};
assert!(!port_down.is_up());
assert!(port_down.is_down());
assert_eq!(port_down.speed_gbps(), None);
let port_10g = Port {
idx: 3,
state: InterfaceState::Up,
connector: PortConnector::SfpPlus,
max_speed_mbps: 10000,
speed_mbps: Some(10000),
poe: None,
};
assert_eq!(port_10g.speed_gbps(), Some(10.0));
}
#[test]
fn test_device_details_switch_methods() {
let json_data = json!({
"id": "switch-device-id",
"macAddress": "aa:bb:cc:dd:ee:ff",
"ipAddress": "192.168.1.100",
"name": "USW-24-PoE",
"model": "USW-24-PoE",
"supported": true,
"state": "ONLINE",
"firmwareUpdatable": false,
"configurationId": "config123",
"features": {
"switching": {},
"accessPoint": null
},
"interfaces": {
"ports": [
{
"idx": 1,
"state": "UP",
"connector": "RJ45",
"maxSpeedMbps": 1000,
"speedMbps": 1000,
"poe": {
"standard": "802.3at",
"type": 2,
"enabled": true,
"state": "UP"
}
},
{
"idx": 2,
"state": "UP",
"connector": "RJ45",
"maxSpeedMbps": 1000,
"speedMbps": 1000,
"poe": {
"standard": "802.3at",
"type": 2,
"enabled": true,
"state": "DOWN"
}
},
{
"idx": 3,
"state": "DOWN",
"connector": "RJ45",
"maxSpeedMbps": 1000,
"poe": {
"standard": "802.3at",
"type": 2,
"enabled": false,
"state": null
}
},
{
"idx": 25,
"state": "UP",
"connector": "SFP",
"maxSpeedMbps": 1000,
"speedMbps": 1000
}
],
"radios": []
}
});
let device: DeviceDetails = serde_json::from_value(json_data).unwrap();
assert!(device.is_switch());
assert!(device.has_switching());
assert!(!device.has_access_point());
assert_eq!(device.port_count(), 4);
assert_eq!(device.active_ports().len(), 3);
assert_eq!(device.inactive_ports().len(), 1);
assert_eq!(device.poe_port_count(), 3); assert_eq!(device.poe_ports().len(), 3);
assert_eq!(device.poe_enabled_ports().len(), 2); assert_eq!(device.poe_active_ports().len(), 1);
let active_poe = device.poe_active_ports();
assert_eq!(active_poe[0].idx, 1);
}
#[test]
fn test_device_details_access_point_not_switch() {
let json_data = json!({
"id": "ap-device-id",
"macAddress": "aa:bb:cc:dd:ee:ff",
"ipAddress": "192.168.1.101",
"name": "U6-Pro",
"model": "U6-Pro",
"supported": true,
"state": "ONLINE",
"firmwareUpdatable": false,
"configurationId": "config123",
"features": {
"switching": null,
"accessPoint": {}
},
"interfaces": {
"ports": [
{
"idx": 1,
"state": "UP",
"connector": "RJ45",
"maxSpeedMbps": 2500,
"speedMbps": 1000
}
],
"radios": [
{
"wlanStandard": "802.11ax",
"frequencyGHz": 5,
"channelWidthMHz": 80,
"channel": 36
}
]
}
});
let device: DeviceDetails = serde_json::from_value(json_data).unwrap();
assert!(!device.is_switch());
assert!(!device.has_switching());
assert!(device.has_access_point());
assert_eq!(device.poe_port_count(), 0);
assert_eq!(device.radio_count(), 1);
}
}