import json
import os
import subprocess
import tempfile
import unittest
from pathlib import Path
def get_denet_binary():
candidates = [
Path("target/debug/denet"),
Path("../target/debug/denet"),
Path("../../target/debug/denet"),
]
for path in candidates:
if path.exists():
return str(path)
candidates = [
Path("target/release/denet"),
Path("../target/release/denet"),
Path("../../target/release/denet"),
]
for path in candidates:
if path.exists():
return str(path)
raise FileNotFoundError("Could not find denet binary. Make sure to build it first with 'cargo build'")
class TestCliArgs(unittest.TestCase):
def setUp(self):
self.binary = get_denet_binary()
def test_help_flag(self):
result = subprocess.run([self.binary, "--help"], capture_output=True, text=True)
self.assertEqual(result.returncode, 0)
self.assertIn("Usage:", result.stdout)
self.assertIn("Options:", result.stdout)
def test_version_flag(self):
result = subprocess.run([self.binary, "--version"], capture_output=True, text=True)
self.assertEqual(result.returncode, 0)
self.assertIn("denet", result.stdout.lower())
def test_missing_command(self):
result = subprocess.run([self.binary], capture_output=True, text=True)
self.assertNotEqual(result.returncode, 0)
self.assertIn("usage", result.stderr.lower())
def test_json_flag(self):
cmd = [self.binary, "--json", "run", "sleep", "0.5"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=2)
lines = result.stdout.strip().split("\n")
json_found = False
metadata_found = False
for line in lines:
if (
line
and not line.startswith("Monitoring")
and not line.startswith("Press")
and not line.startswith("Collected")
):
try:
data = json.loads(line)
if "pid" in data and "cmd" in data and "aggregated" not in data:
self.assertIn("executable", data)
self.assertIn("t0_ms", data)
metadata_found = True
elif "aggregated" in data:
self.assertIn("cpu_usage", data["aggregated"])
self.assertIn("mem_rss_kb", data["aggregated"])
json_found = True
break
except json.JSONDecodeError:
continue
self.assertTrue(json_found or metadata_found, "No valid JSON output found")
def test_attach_pid(self):
import subprocess
proc = subprocess.Popen(["sleep", "2"])
pid = proc.pid
try:
cmd = [self.binary, "--json", "--duration", "1", "attach", str(pid)]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=3)
self.assertEqual(result.returncode, 0, f"Failed to attach to PID {pid}")
lines = result.stdout.strip().split("\n")
json_found = False
metadata_found = False
for line in lines:
if (
line
and not line.startswith("Monitoring")
and not line.startswith("Press")
and not line.startswith("Collected")
):
try:
data = json.loads(line)
if "pid" in data and "cmd" in data and "aggregated" not in data:
self.assertIn("executable", data)
self.assertIn("t0_ms", data)
metadata_found = True
elif "aggregated" in data:
self.assertIn("cpu_usage", data["aggregated"])
json_found = True
break
except json.JSONDecodeError:
continue
self.assertTrue(json_found or metadata_found, "No valid JSON output found for PID attachment")
finally:
try:
proc.terminate()
proc.wait(timeout=1)
except Exception:
proc.kill()
def test_attach_invalid_pid(self):
invalid_pid = 999999
cmd = [self.binary, "attach", str(invalid_pid)]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=2)
self.assertNotEqual(result.returncode, 0)
self.assertIn("Error attaching", result.stderr)
def test_stats_command(self):
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as tf:
tf.write('{"pid":1234,"cmd":["sleep","1"],"exe":"/bin/sleep","t0_ms":1600000000000}\n')
tf.write(
'{"ts_ms":1600000001000,"parent":{"ts_ms":1600000001000,"cpu_usage":1.0,"mem_rss_kb":1000,"mem_vms_kb":2000,"disk_read_bytes":100,"disk_write_bytes":200,"net_rx_bytes":300,"net_tx_bytes":400,"thread_count":1,"uptime_secs":1},"children":[],"aggregated":{"ts_ms":1600000001000,"cpu_usage":1.0,"mem_rss_kb":1000,"mem_vms_kb":2000,"disk_read_bytes":100,"disk_write_bytes":200,"net_rx_bytes":300,"net_tx_bytes":400,"thread_count":1,"process_count":1,"uptime_secs":1}}\n'
)
sample_file = tf.name
try:
cmd = [self.binary, "stats", sample_file]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=2)
self.assertEqual(result.returncode, 0, f"Stats command failed with error: {result.stderr}")
self.assertIn("STATISTICS", result.stdout)
cmd = [self.binary, "--json", "stats", sample_file]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=2)
self.assertEqual(result.returncode, 0)
try:
data = json.loads(result.stdout)
self.assertIn("total_time_secs", data)
self.assertIn("sample_count", data)
except json.JSONDecodeError:
self.fail("Stats command with --json did not produce valid JSON")
finally:
try:
os.unlink(sample_file)
except Exception:
pass
def test_quiet_flag(self):
cmd = [self.binary, "run", "sleep", "0.5"]
normal_result = subprocess.run(cmd, capture_output=True, text=True, timeout=2)
cmd = [self.binary, "--quiet", "run", "sleep", "0.5"]
quiet_result = subprocess.run(cmd, capture_output=True, text=True, timeout=2)
self.assertEqual(quiet_result.returncode, 0)
self.assertLess(
len(quiet_result.stdout),
len(normal_result.stdout) / 2,
f"Quiet mode didn't reduce output enough: {len(quiet_result.stdout)} vs {len(normal_result.stdout)}",
)
def test_no_default_output_file(self):
try:
os.unlink("out.json")
except Exception:
pass
cmd = [self.binary, "run", "sleep", "0.5"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=2)
self.assertEqual(result.returncode, 0)
self.assertFalse(os.path.exists("out.json"), "out.json was created but should not exist by default")
def test_custom_output_file(self):
with tempfile.NamedTemporaryFile(suffix=".json", delete=False) as tf:
custom_out = tf.name
try:
os.unlink(custom_out)
cmd = [self.binary, "--out", custom_out, "run", "sleep", "0.5"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=2)
self.assertEqual(result.returncode, 0)
self.assertTrue(os.path.exists(custom_out), f"Custom output file {custom_out} was not created")
with open(custom_out) as f:
lines = f.readlines()
self.assertTrue(len(lines) > 0, "Output file is empty")
found_metadata = False
found_metrics = False
for line in lines:
data = json.loads(line.strip())
if "pid" in data:
found_metadata = True
if "ts_ms" in data:
found_metrics = True
self.assertTrue(
found_metadata or found_metrics,
f"File doesn't contain valid metadata or metrics: {lines}",
)
finally:
try:
os.unlink(custom_out)
except Exception:
pass
if __name__ == "__main__":
unittest.main()