import json
import os
import time
import pytest
import denet
from tests.python.test_helpers import (
filter_metrics_samples,
assert_valid_metrics,
)
class TestProcessMonitorCreation:
def test_create_with_command(self):
monitor = denet.ProcessMonitor(cmd=["echo", "hello"], base_interval_ms=100, max_interval_ms=1000)
assert monitor is not None
def test_create_from_pid(self):
current_pid = os.getpid()
monitor = denet.ProcessMonitor.from_pid(pid=current_pid, base_interval_ms=100, max_interval_ms=1000)
assert monitor is not None
assert monitor.get_pid() == current_pid
def test_invalid_command_raises_error(self):
with pytest.raises(Exception):
denet.ProcessMonitor(cmd=[], base_interval_ms=100, max_interval_ms=1000)
def test_invalid_pid_raises_error(self):
with pytest.raises(Exception):
denet.ProcessMonitor.from_pid(
pid=999999, base_interval_ms=100,
max_interval_ms=1000,
)
class TestProcessMonitorSampling:
def test_sample_once_returns_data(self):
monitor = denet.ProcessMonitor(cmd=["sleep", "1"], base_interval_ms=100, max_interval_ms=1000)
sample = monitor.sample_once()
assert sample is not None
assert isinstance(sample, str)
data = json.loads(sample)
assert isinstance(data, dict)
def test_multiple_samples(self):
monitor = denet.ProcessMonitor(
cmd=["sleep", "0.5"], base_interval_ms=50, max_interval_ms=1000, store_in_memory=True
)
for _ in range(3):
monitor.sample_once()
time.sleep(0.05)
samples = monitor.get_samples()
assert len(samples) >= 2
for sample in samples:
json.loads(sample)
def test_sample_process_not_running(self):
monitor = denet.ProcessMonitor(cmd=["echo", "quick"], base_interval_ms=100, max_interval_ms=1000)
time.sleep(0.2)
_ = monitor.sample_once()
class TestProcessMonitorMemoryManagement:
def test_store_in_memory_true(self):
monitor = denet.ProcessMonitor(
cmd=["sleep", "0.3"], base_interval_ms=50, max_interval_ms=1000, store_in_memory=True
)
for _ in range(3):
monitor.sample_once()
time.sleep(0.05)
samples = monitor.get_samples()
assert len(samples) > 0
def test_store_in_memory_false(self):
monitor = denet.ProcessMonitor(
cmd=["sleep", "0.3"], base_interval_ms=50, max_interval_ms=1000, store_in_memory=False
)
for _ in range(3):
monitor.sample_once()
time.sleep(0.05)
samples = monitor.get_samples()
assert len(samples) == 0
def test_clear_samples(self):
monitor = denet.ProcessMonitor(
cmd=["sleep", "0.3"], base_interval_ms=50, max_interval_ms=1000, store_in_memory=True
)
monitor.sample_once()
assert len(monitor.get_samples()) > 0
monitor.clear_samples()
assert len(monitor.get_samples()) == 0
class TestProcessMonitorFileOutput:
def test_direct_file_output(self, tmp_path):
temp_file = tmp_path / "test_output.jsonl"
monitor = denet.ProcessMonitor(
cmd=["sleep", "0.2"], base_interval_ms=50, max_interval_ms=1000, output_file=str(temp_file)
)
for _ in range(3):
monitor.sample_once()
time.sleep(0.05)
assert temp_file.exists()
with open(temp_file, "r") as f:
lines = [line.strip() for line in f if line.strip()]
assert len(lines) > 0
for line in lines:
json.loads(line)
def test_save_samples_jsonl(self, tmp_path):
monitor = denet.ProcessMonitor(
cmd=["sleep", "0.2"], base_interval_ms=50, max_interval_ms=1000, store_in_memory=True
)
for _ in range(3):
monitor.sample_once()
time.sleep(0.05)
temp_file = tmp_path / "test_samples.jsonl"
monitor.save_samples(str(temp_file), "jsonl")
assert temp_file.exists()
with open(temp_file, "r") as f:
lines = [line.strip() for line in f if line.strip()]
assert len(lines) > 0
for line in lines:
json.loads(line)
def test_save_samples_json(self, tmp_path):
monitor = denet.ProcessMonitor(
cmd=["sleep", "0.2"], base_interval_ms=50, max_interval_ms=1000, store_in_memory=True
)
for _ in range(3):
monitor.sample_once()
time.sleep(0.05)
temp_file = tmp_path / "test_samples.json"
monitor.save_samples(str(temp_file), "json")
assert temp_file.exists()
with open(temp_file, "r") as f:
data = json.load(f)
assert isinstance(data, list)
assert len(data) > 0
class TestProcessMonitorSummary:
def test_get_summary_basic(self):
monitor = denet.ProcessMonitor(
cmd=["sleep", "0.2"], base_interval_ms=50, max_interval_ms=1000, store_in_memory=True
)
for _ in range(3):
monitor.sample_once()
time.sleep(0.05)
summary_json = monitor.get_summary()
assert isinstance(summary_json, str)
summary = json.loads(summary_json)
assert isinstance(summary, dict)
expected_fields = ["avg_cpu_usage", "peak_mem_rss_kb", "sample_count", "total_time_secs"]
for field in expected_fields:
assert field in summary
def test_summary_with_no_samples(self):
monitor = denet.ProcessMonitor(
cmd=["sleep", "0.1"], base_interval_ms=100, max_interval_ms=1000, store_in_memory=True
)
summary_json = monitor.get_summary()
summary = json.loads(summary_json)
assert isinstance(summary, dict)
class TestProcessMonitorMetadata:
def test_get_pid(self):
monitor = denet.ProcessMonitor(cmd=["sleep", "1"], base_interval_ms=100, max_interval_ms=1000)
pid = monitor.get_pid()
assert isinstance(pid, int)
assert pid > 0
def test_is_running(self):
monitor = denet.ProcessMonitor(cmd=["sleep", "0.1"], base_interval_ms=100, max_interval_ms=1000)
running = monitor.is_running()
assert isinstance(running, bool)
time.sleep(0.3)
running = monitor.is_running()
assert isinstance(running, bool)
def test_get_metadata(self):
monitor = denet.ProcessMonitor(cmd=["echo", "test"], base_interval_ms=100, max_interval_ms=1000)
metadata = monitor.get_metadata()
if metadata: if isinstance(metadata, str):
metadata_data = json.loads(metadata)
assert isinstance(metadata_data, dict)
class TestProcessMonitorRun:
def test_run_short_process(self):
monitor = denet.ProcessMonitor(
cmd=["echo", "hello"], base_interval_ms=100, max_interval_ms=1000, store_in_memory=True
)
monitor.run()
samples = monitor.get_samples()
assert isinstance(samples, list)
def test_run_with_monitoring(self):
monitor = denet.ProcessMonitor(
cmd=["python", "-c", "import time; time.sleep(0.3)"],
base_interval_ms=50,
max_interval_ms=1000,
store_in_memory=True,
)
monitor.run()
samples = monitor.get_samples()
metrics_list = filter_metrics_samples(samples)
if len(metrics_list) > 0:
for metrics in metrics_list[:3]: assert_valid_metrics(metrics)
class TestProcessMonitorEdgeCases:
def test_invalid_intervals(self):
monitor = denet.ProcessMonitor(
cmd=["echo", "test"],
base_interval_ms=1000,
max_interval_ms=100, )
assert monitor is not None
def test_zero_intervals(self):
try:
monitor = denet.ProcessMonitor(cmd=["echo", "test"], base_interval_ms=0, max_interval_ms=1000)
assert monitor is not None
except (ValueError, Exception):
pass
def test_very_high_frequency_sampling(self):
monitor = denet.ProcessMonitor(
cmd=["sleep", "0.1"],
base_interval_ms=1, max_interval_ms=10,
store_in_memory=True,
)
for _ in range(5):
monitor.sample_once()
time.sleep(0.01)
samples = monitor.get_samples()
assert len(samples) >= 0
def test_nonexistent_command(self):
with pytest.raises(Exception):
denet.ProcessMonitor(cmd=["nonexistent_command_12345"], base_interval_ms=100, max_interval_ms=1000)