Skip to content

Commit

Permalink
Merge pull request #106 from jacek-kurlit/101-fixes-to-made
Browse files Browse the repository at this point in the history
Fix incorrect start time, enforce deterministic ports order
  • Loading branch information
jacek-kurlit authored Nov 26, 2024
2 parents 3b05e18 + cc928a8 commit cfa2690
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 26 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ directories = "5.0"
toml = "0.8"
serde = { version = "1.0", features = ["derive"] }
fuzzy-matcher = "0.3.7"
itertools = "0.13"

[dev-dependencies]
http-test-server = "2.1.1"
62 changes: 46 additions & 16 deletions src/processes.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::cmp::Ordering;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::time::SystemTime;

use anyhow::Result;
use itertools::Itertools;
use listeners::Listener;
use sysinfo::{Pid, System, Uid, Users};
use sysinfo::{ProcessRefreshKind, RefreshKind};

Expand All @@ -25,7 +27,7 @@ pub struct ProcessManager {

use self::filters::OptionsFilter;
use self::utils::{
find_current_process_user, get_process_args, process_run_time, process_start_time,
find_current_process_user, get_process_args, process_run_time, to_system_local_time,
};

pub trait ProcessInfo {
Expand Down Expand Up @@ -198,7 +200,9 @@ impl ProcessManager {
user_name,
ports: ports.cloned(),
memory: prc.memory(),
start_time: process_start_time(prc.start_time()),
start_time: to_system_local_time(prc.start_time())
.format("%H:%M:%S")
.to_string(),
run_time: process_run_time(prc.run_time(), SystemTime::now()),
}
}
Expand Down Expand Up @@ -227,21 +231,21 @@ fn process_refresh_kind() -> ProcessRefreshKind {
}

fn refresh_ports() -> HashMap<u32, String> {
listeners::get_all()
let ports = listeners::get_all()
//NOTE: we ignore errors comming from listeners
.unwrap_or_default()
.unwrap_or_default();
create_sorted_process_ports(ports)
}

//NOTE: we sort this so order of ports is deterministic and doesn't change durig refresh
fn create_sorted_process_ports(ports: HashSet<Listener>) -> ProcessPorts {
ports
.into_iter()
.fold(HashMap::new(), |mut acc: ProcessPorts, l| {
match acc.get_mut(&l.process.pid) {
Some(ports) => {
ports.push_str(&format!(", {}", l.socket.port()));
}
None => {
acc.insert(l.process.pid, format!("{}", l.socket.port()));
}
}
acc
})
.map(|l| (l.process.pid, l.socket.port()))
.into_group_map()
.into_iter()
.map(|(pid, ports)| (pid, ports.into_iter().sorted_by(|a, b| a.cmp(b)).join(", ")))
.collect()
}

#[derive(Debug)]
Expand Down Expand Up @@ -356,8 +360,24 @@ impl Ord for MatchType {

#[cfg(test)]
mod tests {
use listeners::{Listener, Process};

use super::*;

#[test]
fn should_create_sorted_process_ports() {
let value = [
create_listener(1, 8080),
create_listener(1, 100),
create_listener(1, 50),
create_listener(2, 1234),
];
let process_ports = create_sorted_process_ports(HashSet::from(value));
assert_eq!(process_ports.len(), 2);
assert_eq!(process_ports.get(&1).unwrap(), "50, 100, 8080");
assert_eq!(process_ports.get(&2).unwrap(), "1234");
}

#[test]
fn match_type_sort_in_correct_order() {
let mut vec_to_sort = vec![
Expand Down Expand Up @@ -399,4 +419,14 @@ mod tests {
]
);
}

fn create_listener(pid: u32, port: u16) -> Listener {
Listener {
process: Process {
pid,
name: format!("p1{pid}"),
},
socket: format!("127.0.0.1:{port}").parse().unwrap(),
}
}
}
23 changes: 13 additions & 10 deletions src/processes/utils.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::time::{Duration, SystemTime, UNIX_EPOCH};

use anyhow::{anyhow, Context, Result};
use chrono::{DateTime, Utc};
use chrono::{DateTime, Local};
use sysinfo::{System, Uid};

use super::ProcessInfo;
Expand Down Expand Up @@ -35,10 +35,9 @@ pub(super) fn process_run_time(run_duration_since_epoch: u64, now: SystemTime) -
format!("{}s", seconds)
}

pub(super) fn process_start_time(seconds_since_epoch: u64) -> String {
pub(super) fn to_system_local_time(seconds_since_epoch: u64) -> DateTime<Local> {
let system_time = UNIX_EPOCH + Duration::from_secs(seconds_since_epoch);
let datetime: DateTime<Utc> = system_time.into();
datetime.format("%H:%M:%S").to_string()
system_time.into()
}

pub(super) fn find_current_process_user(sys: &System) -> Result<Uid> {
Expand Down Expand Up @@ -170,14 +169,18 @@ pub mod tests {
}

#[test]
fn test_process_start_time() {
let start_time = |hours: u64, minutes: u64, seconds: u64| {
fn test_to_system_local_time() {
let system_time_utc = |hours: u64, minutes: u64, seconds: u64| {
let seconds_since_epoch = as_duration(hours, minutes, seconds).as_secs();
process_start_time(seconds_since_epoch)
to_system_local_time(seconds_since_epoch)
//NOTE: without this it will fail at CI/CD pipeline where local time is different
.to_utc()
.format("%H:%M:%S")
.to_string()
};
assert_eq!(start_time(0, 0, 0), "00:00:00");
assert_eq!(start_time(1, 45, 15), "01:45:15");
assert_eq!(start_time(5, 29, 59), "05:29:59");
assert_eq!(system_time_utc(0, 0, 0), "00:00:00");
assert_eq!(system_time_utc(1, 45, 15), "01:45:15");
assert_eq!(system_time_utc(5, 29, 59), "05:29:59");
}

fn as_duration(hours: u64, minutes: u64, seconds: u64) -> Duration {
Expand Down

0 comments on commit cfa2690

Please # to comment.