Files
overlord/Overlord-Client/cmd/agent/handlers/processes_test.go
T
2026-03-05 00:04:26 -06:00

261 lines
6.2 KiB
Go

package handlers
import (
"context"
"testing"
"overlord-client/cmd/agent/config"
rt "overlord-client/cmd/agent/runtime"
"overlord-client/cmd/agent/wire"
"github.com/vmihailenco/msgpack/v5"
)
func TestHandleProcessList(t *testing.T) {
writer := &testWriter{}
env := &rt.Env{
Conn: writer,
Cfg: config.Config{},
}
ctx := context.Background()
cmdID := "test-cmd-proc-1"
if err := HandleProcessList(ctx, env, cmdID); err != nil {
t.Fatalf("HandleProcessList failed: %v", err)
}
if len(writer.msgs) != 1 {
t.Fatalf("Expected 1 message, got %d", len(writer.msgs))
}
var result wire.ProcessListResult
if err := msgpack.Unmarshal(writer.msgs[0], &result); err != nil {
t.Fatalf("Failed to unmarshal result: %v", err)
}
if result.Type != "process_list_result" {
t.Errorf("Expected type 'process_list_result', got '%s'", result.Type)
}
if result.CommandID != cmdID {
t.Errorf("Expected CommandID '%s', got '%s'", cmdID, result.CommandID)
}
if len(result.Processes) == 0 {
t.Log("WARNING: No processes returned (may indicate platform issue)")
} else {
t.Logf("Found %d processes", len(result.Processes))
for i, proc := range result.Processes {
if proc.PID <= 0 {
t.Errorf("Process %d has invalid PID: %d", i, proc.PID)
}
if proc.Name == "" {
t.Errorf("Process %d has empty name", i)
}
if proc.Memory < 0 {
t.Errorf("Process %d has negative memory: %d", i, proc.Memory)
}
if proc.CPU < 0 {
t.Errorf("Process %d has negative CPU: %f", i, proc.CPU)
}
validTypes := map[string]bool{
"system": true,
"service": true,
"own": true,
"other": true,
"": true,
}
if !validTypes[proc.Type] {
t.Errorf("Process %d has invalid type: %s", i, proc.Type)
}
}
pidExists := make(map[int32]bool)
for _, proc := range result.Processes {
pidExists[proc.PID] = true
}
for _, proc := range result.Processes {
if proc.PPID != 0 && !pidExists[proc.PPID] {
t.Logf("INFO: Process %d (%s) has PPID %d which is not in the list (may have exited)",
proc.PID, proc.Name, proc.PPID)
}
}
}
}
func TestHandleProcessList_ProcessTypes(t *testing.T) {
writer := &testWriter{}
env := &rt.Env{
Conn: writer,
Cfg: config.Config{},
}
ctx := context.Background()
cmdID := "test-cmd-proc-2"
if err := HandleProcessList(ctx, env, cmdID); err != nil {
t.Fatalf("HandleProcessList failed: %v", err)
}
if len(writer.msgs) != 1 {
t.Fatalf("Expected 1 message, got %d", len(writer.msgs))
}
var result wire.ProcessListResult
if err := msgpack.Unmarshal(writer.msgs[0], &result); err != nil {
t.Fatalf("Failed to unmarshal result: %v", err)
}
typeCounts := make(map[string]int)
for _, proc := range result.Processes {
typeCounts[proc.Type]++
}
t.Logf("Process type distribution:")
for typ, count := range typeCounts {
label := typ
if label == "" {
label = "uncategorized"
}
t.Logf(" %s: %d", label, count)
}
if typeCounts["system"] == 0 {
t.Log("WARNING: No system processes detected")
}
examples := make(map[string][]string)
for _, proc := range result.Processes {
if len(examples[proc.Type]) < 3 {
examples[proc.Type] = append(examples[proc.Type], proc.Name)
}
}
t.Log("Example processes by type:")
for typ, procs := range examples {
label := typ
if label == "" {
label = "uncategorized"
}
t.Logf(" %s: %v", label, procs)
}
}
func TestProcessInfoFields(t *testing.T) {
proc := wire.ProcessInfo{
PID: 1234,
PPID: 1,
Name: "test.exe",
CPU: 25.5,
Memory: 1048576,
Username: "testuser",
Type: "own",
}
data, err := msgpack.Marshal(proc)
if err != nil {
t.Fatalf("Failed to marshal ProcessInfo: %v", err)
}
var decoded wire.ProcessInfo
if err := msgpack.Unmarshal(data, &decoded); err != nil {
t.Fatalf("Failed to unmarshal ProcessInfo: %v", err)
}
if decoded.PID != proc.PID {
t.Errorf("PID mismatch: got %d, want %d", decoded.PID, proc.PID)
}
if decoded.PPID != proc.PPID {
t.Errorf("PPID mismatch: got %d, want %d", decoded.PPID, proc.PPID)
}
if decoded.Name != proc.Name {
t.Errorf("Name mismatch: got %s, want %s", decoded.Name, proc.Name)
}
if decoded.CPU != proc.CPU {
t.Errorf("CPU mismatch: got %f, want %f", decoded.CPU, proc.CPU)
}
if decoded.Memory != proc.Memory {
t.Errorf("Memory mismatch: got %d, want %d", decoded.Memory, proc.Memory)
}
if decoded.Username != proc.Username {
t.Errorf("Username mismatch: got %s, want %s", decoded.Username, proc.Username)
}
if decoded.Type != proc.Type {
t.Errorf("Type mismatch: got %s, want %s", decoded.Type, proc.Type)
}
}
func TestListProcesses_PlatformSpecific(t *testing.T) {
processes, err := listProcesses()
if err != nil {
t.Fatalf("listProcesses failed: %v", err)
}
if len(processes) == 0 {
t.Log("WARNING: No processes returned from listProcesses()")
return
}
t.Logf("Retrieved %d processes from system", len(processes))
for i, proc := range processes {
if i < 10 {
t.Logf("Process: PID=%d PPID=%d Name=%s CPU=%.2f%% Mem=%d User=%s Type=%s",
proc.PID, proc.PPID, proc.Name, proc.CPU, proc.Memory, proc.Username, proc.Type)
}
if proc.PID <= 0 {
t.Errorf("Process %d has invalid PID: %d", i, proc.PID)
}
}
}
func TestProcessTypeClassification(t *testing.T) {
processes, err := listProcesses()
if err != nil {
t.Fatalf("listProcesses failed: %v", err)
}
if len(processes) == 0 {
t.Skip("No processes available for testing")
}
var foundSystem, foundService, foundOwn bool
for _, proc := range processes {
switch proc.Type {
case "system":
foundSystem = true
t.Logf("System process example: PID=%d Name=%s User=%s",
proc.PID, proc.Name, proc.Username)
case "service":
foundService = true
t.Logf("Service process example: PID=%d Name=%s User=%s",
proc.PID, proc.Name, proc.Username)
case "own":
foundOwn = true
t.Logf("Own process example: PID=%d Name=%s User=%s",
proc.PID, proc.Name, proc.Username)
}
if foundSystem && foundService && foundOwn {
break
}
}
if !foundSystem {
t.Log("INFO: No system processes detected in classification")
}
if !foundService {
t.Log("INFO: No service processes detected in classification")
}
if !foundOwn {
t.Log("INFO: No own processes detected in classification")
}
}