mirror of
https://github.com/rzuasti/oott.git
synced 2026-07-08 19:21:54 +02:00
enhanced device database structure, added methods to device db module
and unit tests
This commit is contained in:
@@ -2,7 +2,10 @@ CREATE TABLE devices(
|
||||
mac_address TEXT PRIMARY KEY,
|
||||
ipv4_address TEXT NOT NULL,
|
||||
vendor TEXT,
|
||||
last_seen TEXT NOT NULL
|
||||
last_seen TEXT NOT NULL,
|
||||
is_registered INTEGER NOT NULL,
|
||||
owner TEXT,
|
||||
device_type TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE notifications(
|
||||
|
||||
+144
-5
@@ -11,7 +11,7 @@ pub fn read(mac_address: String) -> Option<Device> {
|
||||
let conn = db::get_db_connection();
|
||||
|
||||
let result: Result<Device, rusqlite::Error> = conn.query_one(
|
||||
"SELECT mac_address, ipv4_address, vendor, last_seen FROM devices WHERE mac_address=?1",
|
||||
"SELECT mac_address, ipv4_address, vendor, last_seen, is_registered, owner, device_type FROM devices WHERE mac_address=?1",
|
||||
params![mac_address],
|
||||
|row| {
|
||||
Ok(Device {
|
||||
@@ -19,6 +19,9 @@ pub fn read(mac_address: String) -> Option<Device> {
|
||||
ipv4_address: row.get(1)?,
|
||||
vendor: row.get(2)?,
|
||||
last_seen: row.get(3)?,
|
||||
is_registered: row.get(4)?,
|
||||
owner: row.get(5)?,
|
||||
device_type: row.get(6)?,
|
||||
})
|
||||
},
|
||||
);
|
||||
@@ -41,8 +44,8 @@ pub fn insert(device: Device) -> Result<(), DbError> {
|
||||
let conn = db::get_db_connection();
|
||||
|
||||
match conn.execute(
|
||||
"INSERT INTO devices (mac_address, ipv4_address, vendor, last_seen) VALUES (?1, ?2, ?3, ?4)",
|
||||
params![device.mac_address, device.ipv4_address, device.vendor, device.last_seen]) {
|
||||
"INSERT INTO devices (mac_address, ipv4_address, vendor, last_seen, is_registered, owner, device_type) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
|
||||
params![device.mac_address, device.ipv4_address, device.vendor, device.last_seen, device.is_registered, device.owner, device.device_type]) {
|
||||
Ok(_) => {
|
||||
debug!("Device inserted into database: {}", device);
|
||||
Ok(())
|
||||
@@ -57,12 +60,15 @@ pub fn insert(device: Device) -> Result<(), DbError> {
|
||||
pub fn update(device: Device) -> Result<(), DbError> {
|
||||
let conn = db::get_db_connection();
|
||||
match conn.execute(
|
||||
"UPDATE devices SET ipv4_address=?1, vendor=?2, last_seen=?3 WHERE mac_address=?4",
|
||||
"UPDATE devices SET ipv4_address=?1, vendor=?2, last_seen=?3, is_registered=?4, owner=?5, device_type=?6 WHERE mac_address=?7",
|
||||
params![
|
||||
device.ipv4_address,
|
||||
device.vendor,
|
||||
device.last_seen,
|
||||
device.mac_address
|
||||
device.is_registered,
|
||||
device.owner,
|
||||
device.device_type,
|
||||
device.mac_address,
|
||||
],
|
||||
) {
|
||||
Ok(_) => {
|
||||
@@ -75,3 +81,136 @@ pub fn update(device: Device) -> Result<(), DbError> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use chrono::{TimeZone, Utc};
|
||||
|
||||
use super::*;
|
||||
use crate::tests_common;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_read() {
|
||||
tests_common::setup().await;
|
||||
// Read a non-existant device and validate for None
|
||||
assert!(
|
||||
read("zz:zz:zz:zz:zz:zz".to_string()).is_none(),
|
||||
"Device with MAC zz:zz:zz:zz:zz:zz should not exist"
|
||||
);
|
||||
|
||||
// Read all testing devices and validate their values
|
||||
// 'aa:aa:aa:aa:aa:aa', '192.168.0.1', 'Vendor 1', '2026-01-01 11:11:11', 0, '', ''
|
||||
let device1 = read("aa:aa:aa:aa:aa:aa".to_string()).unwrap();
|
||||
assert_eq!(
|
||||
device1.mac_address, "aa:aa:aa:aa:aa:aa",
|
||||
"Invalid MAC address for device aa:aa:aa:aa:aa:aa"
|
||||
);
|
||||
assert_eq!(
|
||||
device1.device_type, "",
|
||||
"Device type should be empty for device {}",
|
||||
device1.mac_address
|
||||
);
|
||||
assert_eq!(
|
||||
device1.ipv4_address, "192.168.0.1",
|
||||
"Invalid IP address for device {}",
|
||||
device1.mac_address
|
||||
);
|
||||
assert!(
|
||||
!device1.is_registered,
|
||||
"Device {} should not be registered",
|
||||
device1.mac_address
|
||||
);
|
||||
assert_eq!(
|
||||
device1.last_seen,
|
||||
Utc.with_ymd_and_hms(2026, 1, 1, 11, 11, 11).unwrap(),
|
||||
"Invalid last_seen for device {}",
|
||||
device1.mac_address
|
||||
);
|
||||
assert_eq!(
|
||||
device1.owner, "",
|
||||
"Invalid owner for device {}",
|
||||
device1.mac_address
|
||||
);
|
||||
assert_eq!(
|
||||
device1.vendor, "Vendor 1",
|
||||
"Invalid vendor for device {}",
|
||||
device1.mac_address
|
||||
);
|
||||
|
||||
// 'bb:bb:bb:bb:bb:bb', '192.168.0.2', 'Vendor 2', '2026-02-03 13:14:15', 1, 'John', 'Phone'
|
||||
let device2 = read("bb:bb:bb:bb:bb:bb".to_string()).unwrap();
|
||||
assert_eq!(
|
||||
device2.mac_address, "bb:bb:bb:bb:bb:bb",
|
||||
"Invalid MAC address for device bb:bb:bb:bb:bb:bb"
|
||||
);
|
||||
assert_eq!(
|
||||
device2.device_type, "Phone",
|
||||
"Device type should be 'Phone' for device {}",
|
||||
device2.mac_address
|
||||
);
|
||||
assert_eq!(
|
||||
device2.ipv4_address, "192.168.0.2",
|
||||
"Invalid IP address for device {}",
|
||||
device2.mac_address
|
||||
);
|
||||
assert!(
|
||||
device2.is_registered,
|
||||
"Device {} should not be registered",
|
||||
device2.mac_address
|
||||
);
|
||||
assert_eq!(
|
||||
device2.last_seen,
|
||||
Utc.with_ymd_and_hms(2026, 2, 3, 13, 14, 15).unwrap(),
|
||||
"Invalid last_seen for device {}",
|
||||
device2.mac_address
|
||||
);
|
||||
assert_eq!(
|
||||
device2.owner, "John",
|
||||
"Invalid owner for device {}",
|
||||
device2.mac_address
|
||||
);
|
||||
assert_eq!(
|
||||
device2.vendor, "Vendor 2",
|
||||
"Invalid vendor for device {}",
|
||||
device2.mac_address
|
||||
);
|
||||
|
||||
// 'cc:cc:cc:cc:cc:cc', '192.168.0.3', 'Vendor 3', '2026-02-17 20:11:00', 1, 'Sarah', 'Laptop'
|
||||
let device3 = read("cc:cc:cc:cc:cc:cc".to_string()).unwrap();
|
||||
assert_eq!(
|
||||
device3.mac_address, "cc:cc:cc:cc:cc:cc",
|
||||
"Invalid MAC address for device cc:cc:cc:cc:cc:cc"
|
||||
);
|
||||
assert_eq!(
|
||||
device3.device_type, "Laptop",
|
||||
"Device type should be 'Laptop' for device {}",
|
||||
device3.mac_address
|
||||
);
|
||||
assert_eq!(
|
||||
device3.ipv4_address, "192.168.0.3",
|
||||
"Invalid IP address for device {}",
|
||||
device3.mac_address
|
||||
);
|
||||
assert!(
|
||||
device3.is_registered,
|
||||
"Device {} should not be registered",
|
||||
device3.mac_address
|
||||
);
|
||||
assert_eq!(
|
||||
device3.last_seen,
|
||||
Utc.with_ymd_and_hms(2026, 2, 17, 20, 11, 00).unwrap(),
|
||||
"Invalid last_seen for device {}",
|
||||
device3.mac_address
|
||||
);
|
||||
assert_eq!(
|
||||
device3.owner, "Sarah",
|
||||
"Invalid owner for device {}",
|
||||
device3.mac_address
|
||||
);
|
||||
assert_eq!(
|
||||
device3.vendor, "Vendor 3",
|
||||
"Invalid vendor for device {}",
|
||||
device3.mac_address
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,12 +106,12 @@ pub async fn listen_for_packets(
|
||||
"Found online device - IP addr={} - MAC addr={} - vendor={}",
|
||||
packet_ip_address, packet_mac_address, packet_vendor
|
||||
);
|
||||
devices.push(Device {
|
||||
mac_address: packet_mac_address,
|
||||
ipv4_address: packet_ip_address,
|
||||
vendor: packet_vendor,
|
||||
last_seen: Local::now().to_utc(),
|
||||
});
|
||||
devices.push(Device::new(
|
||||
packet_mac_address,
|
||||
packet_ip_address,
|
||||
packet_vendor,
|
||||
Local::now().to_utc(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,48 @@ pub struct Device {
|
||||
pub vendor: String,
|
||||
#[serde(with = "ts_seconds")]
|
||||
pub last_seen: DateTime<Utc>,
|
||||
pub is_registered: bool,
|
||||
pub owner: String,
|
||||
pub device_type: String,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
pub fn new(
|
||||
mac_address: String,
|
||||
ipv4_address: String,
|
||||
vendor: String,
|
||||
last_seen: DateTime<Utc>,
|
||||
) -> Self {
|
||||
Self {
|
||||
mac_address: mac_address,
|
||||
ipv4_address: ipv4_address,
|
||||
vendor: vendor,
|
||||
last_seen: last_seen,
|
||||
is_registered: false,
|
||||
owner: "".to_string(),
|
||||
device_type: "".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Device {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"mac={}, ip={}, vendor={}, last_seen={}",
|
||||
self.mac_address, self.ipv4_address, self.vendor, self.last_seen
|
||||
"mac={}, ip={}, vendor={}, last_seen={}, is_registered={}, owner={}, device_type={}",
|
||||
self.mac_address,
|
||||
self.ipv4_address,
|
||||
self.vendor,
|
||||
self.last_seen,
|
||||
self.is_registered,
|
||||
self.owner,
|
||||
self.device_type
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Device {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.mac_address == other.mac_address
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
INSERT INTO DEVICES (mac_address, ipv4_address, vendor, last_seen, is_registered, owner, device_type)
|
||||
VALUES ('aa:aa:aa:aa:aa:aa', '192.168.0.1', 'Vendor 1', '2026-01-01 11:11:11', 0, '', '');
|
||||
INSERT INTO DEVICES (mac_address, ipv4_address, vendor, last_seen, is_registered, owner, device_type)
|
||||
VALUES ('bb:bb:bb:bb:bb:bb', '192.168.0.2', 'Vendor 2', '2026-02-03 13:14:15', 1, 'John', 'Phone');
|
||||
INSERT INTO DEVICES (mac_address, ipv4_address, vendor, last_seen, is_registered, owner, device_type)
|
||||
VALUES ('cc:cc:cc:cc:cc:cc', '192.168.0.3', 'Vendor 3', '2026-02-17 20:11:00', 1, 'Sarah', 'Laptop');
|
||||
Reference in New Issue
Block a user