Structured code into files and added tests for hostname

This commit is contained in:
Sugui 2024-07-06 14:33:07 +02:00
parent f16a504bd9
commit e33b503159
6 changed files with 144 additions and 16 deletions

46
Cargo.lock generated
View File

@ -2,6 +2,15 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
@ -25,11 +34,19 @@ version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "minimon" name = "minimon"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ping", "ping",
"regex",
"thiserror",
] ]
[[package]] [[package]]
@ -97,6 +114,35 @@ dependencies = [
"getrandom", "getrandom",
] ]
[[package]]
name = "regex"
version = "1.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.4.10" version = "0.4.10"

View File

@ -5,3 +5,5 @@ edition = "2021"
[dependencies] [dependencies]
ping = "0.5.2" ping = "0.5.2"
regex = "1.10.5"
thiserror = "1.0.61"

69
src/hostname.rs Normal file
View File

@ -0,0 +1,69 @@
use ::thiserror::Error;
use regex::Regex;
const VALID_IP_ADDRESS_PATTERN: &str = r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";
const VALID_HOSTNAME_PATTERN: &str = r"^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$";
#[derive(Clone, Debug, Error)]
#[error("The hostname \"{0}\" is invalid")]
pub struct InvalidHostnameError(String);
pub struct Hostname {
hostname: String,
}
impl Hostname {
pub fn new(hostname: &str) -> Result<Hostname, InvalidHostnameError> {
if Self::is_valid_ip(&hostname) || Self::is_valid_hostname(&hostname) {
Ok(Hostname {
hostname: hostname.to_string(),
})
} else {
Err(InvalidHostnameError(hostname.to_string()))
}
}
fn is_valid_ip(ip: &str) -> bool {
let re = Regex::new(VALID_IP_ADDRESS_PATTERN).unwrap();
re.is_match(ip)
}
fn is_valid_hostname(hostname: &str) -> bool {
let re = Regex::new(VALID_HOSTNAME_PATTERN).unwrap();
re.is_match(hostname)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn valid_ip_adresses() {
assert!(Hostname::new("192.168.0.1").is_ok());
assert!(Hostname::new("255.127.63.31").is_ok());
assert!(Hostname::new("1.0.0.1").is_ok());
assert!(Hostname::new("10.1.10.47").is_ok());
}
#[test]
fn invalid_ip_adresses() {
assert!(Hostname::new("::1").is_err()); // We don't support IPv6 yet
}
#[test]
fn valid_hostnames() {
assert!(Hostname::new("mononobe.fai.st").is_ok());
assert!(Hostname::new("twink-pad").is_ok());
assert!(Hostname::new("is-42-the-response").is_ok());
assert!(Hostname::new("GoB.NaSa-42.eu").is_ok());
assert!(Hostname::new("256.127.63.31").is_ok());
}
#[test]
fn invalid_hostnames() {
assert!(Hostname::new("no..double.dots").is_err());
assert!(Hostname::new("#illegal-character").is_err()); // We don't support IPv6 yet
assert!(Hostname::new("").is_err());
assert!(Hostname::new("not-end-with-hyphen-").is_err());
}
}

View File

@ -1,38 +1,30 @@
use std::{collections::HashMap, net::IpAddr}; use crate::hostname::Hostname;
use std::collections::HashMap;
pub struct Machine { pub struct Machine {
name: String, name: String,
address: IpAddr, hostname: Hostname,
} }
enum Status { pub enum Status {
Unreachable, Unreachable,
Forbidden, Forbidden,
Success(HashMap<String, String>), Success(HashMap<String, String>),
} }
impl Machine { impl Machine {
fn new(name: &str, address: IpAddr) -> Machine { pub fn new(name: &str, hostname: Hostname) -> Machine {
Machine { Machine {
name: String::from(name), name: String::from(name),
address, hostname,
} }
} }
} }
trait Monitor { pub trait Monitor {
fn monitor(machine: &Machine) -> Status; fn monitor(machine: &Machine) -> Status;
} }
#[derive(Debug)]
struct PingMonitor {}
impl Monitor for PingMonitor {
fn monitor(machine: &Machine) -> Status {
todo!()
}
}
#[derive(Debug)] #[derive(Debug)]
struct SshMonitor {} struct SshMonitor {}

View File

@ -1,5 +1,6 @@
mod hostname;
mod machine; mod machine;
mod ping_monitor;
use machine::Machine; use machine::Machine;
fn main() { fn main() {

18
src/ping_monitor.rs Normal file
View File

@ -0,0 +1,18 @@
use crate::machine::{Machine, Monitor, Status};
#[derive(Debug)]
struct PingMonitor {}
impl Monitor for PingMonitor {
fn monitor(machine: &Machine) -> Status {
todo!()
}
}
#[cfg(test)]
mod test {
#[test]
fn monitor_works() {
assert!(true)
}
}