mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-05 02:30:26 +08:00
解决的测试盲点: 1. getProcessStartTime (Unix) 0% → 77.3% - 新增 process_check_test.go - 测试 /proc/<pid>/stat 解析 - 覆盖失败路径和边界情况 2. getBootTime (Unix) 0% → 91.7% - 测试 /proc/stat btime 解析 - 覆盖缺失和格式错误场景 3. isPIDReused 60% → 100% - 新增表驱动测试覆盖所有分支 - file_stat_fails, old_file, new_file, pid_reused, pid_not_reused 4. isUnsafeFile 82.4% → 88.2% - 符号链接检测测试 - 路径遍历攻击测试 - TempDir 外文件测试 5. parsePIDFromLog 86.7% → 100% - 补充边界测试:负数、零、超大 PID 测试质量改进: - 新增 stubFileStat 和 stubEvalSymlinks 辅助函数 - 新增 fakeFileInfo 用于文件信息模拟 - 所有测试独立不依赖真实系统状态 - 表驱动测试模式提升可维护性 覆盖率统计: - 整体覆盖率: 85.5% → 89.3% (+3.8%) - 新增测试代码: ~150 行 - 测试/代码比例: 1.08 (健康水平) Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
218 lines
5.1 KiB
Go
218 lines
5.1 KiB
Go
//go:build unix || darwin || linux
|
|
// +build unix darwin linux
|
|
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestIsProcessRunning(t *testing.T) {
|
|
t.Run("current process", func(t *testing.T) {
|
|
if !isProcessRunning(os.Getpid()) {
|
|
t.Fatalf("expected current process (pid=%d) to be running", os.Getpid())
|
|
}
|
|
})
|
|
|
|
t.Run("fake pid", func(t *testing.T) {
|
|
const nonexistentPID = 1 << 30
|
|
if isProcessRunning(nonexistentPID) {
|
|
t.Fatalf("expected pid %d to be reported as not running", nonexistentPID)
|
|
}
|
|
})
|
|
|
|
t.Run("terminated process", func(t *testing.T) {
|
|
pid := exitedProcessPID(t)
|
|
if isProcessRunning(pid) {
|
|
t.Fatalf("expected exited child process (pid=%d) to be reported as not running", pid)
|
|
}
|
|
})
|
|
|
|
t.Run("boundary values", func(t *testing.T) {
|
|
if isProcessRunning(0) {
|
|
t.Fatalf("pid 0 should never be treated as running")
|
|
}
|
|
if isProcessRunning(-42) {
|
|
t.Fatalf("negative pid should never be treated as running")
|
|
}
|
|
})
|
|
|
|
t.Run("find process error", func(t *testing.T) {
|
|
original := findProcess
|
|
defer func() { findProcess = original }()
|
|
|
|
mockErr := errors.New("findProcess failure")
|
|
findProcess = func(pid int) (*os.Process, error) {
|
|
return nil, mockErr
|
|
}
|
|
|
|
if isProcessRunning(1234) {
|
|
t.Fatalf("expected false when os.FindProcess fails")
|
|
}
|
|
})
|
|
}
|
|
|
|
func exitedProcessPID(t *testing.T) int {
|
|
t.Helper()
|
|
|
|
var cmd *exec.Cmd
|
|
if runtime.GOOS == "windows" {
|
|
cmd = exec.Command("cmd", "/c", "exit 0")
|
|
} else {
|
|
cmd = exec.Command("sh", "-c", "exit 0")
|
|
}
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
t.Fatalf("failed to start helper process: %v", err)
|
|
}
|
|
pid := cmd.Process.Pid
|
|
|
|
if err := cmd.Wait(); err != nil {
|
|
t.Fatalf("helper process did not exit cleanly: %v", err)
|
|
}
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
return pid
|
|
}
|
|
|
|
func TestRunProcessCheckSmoke(t *testing.T) {
|
|
t.Run("current process", func(t *testing.T) {
|
|
if !isProcessRunning(os.Getpid()) {
|
|
t.Fatalf("expected current process (pid=%d) to be running", os.Getpid())
|
|
}
|
|
})
|
|
|
|
t.Run("fake pid", func(t *testing.T) {
|
|
const nonexistentPID = 1 << 30
|
|
if isProcessRunning(nonexistentPID) {
|
|
t.Fatalf("expected pid %d to be reported as not running", nonexistentPID)
|
|
}
|
|
})
|
|
|
|
t.Run("boundary values", func(t *testing.T) {
|
|
if isProcessRunning(0) {
|
|
t.Fatalf("pid 0 should never be treated as running")
|
|
}
|
|
if isProcessRunning(-42) {
|
|
t.Fatalf("negative pid should never be treated as running")
|
|
}
|
|
})
|
|
|
|
t.Run("find process error", func(t *testing.T) {
|
|
original := findProcess
|
|
defer func() { findProcess = original }()
|
|
|
|
mockErr := errors.New("findProcess failure")
|
|
findProcess = func(pid int) (*os.Process, error) {
|
|
return nil, mockErr
|
|
}
|
|
|
|
if isProcessRunning(1234) {
|
|
t.Fatalf("expected false when os.FindProcess fails")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGetProcessStartTimeReadsProcStat(t *testing.T) {
|
|
pid := 4321
|
|
boot := time.Unix(1_710_000_000, 0)
|
|
startTicks := uint64(4500)
|
|
|
|
statFields := make([]string, 25)
|
|
for i := range statFields {
|
|
statFields[i] = strconv.Itoa(i + 1)
|
|
}
|
|
statFields[19] = strconv.FormatUint(startTicks, 10)
|
|
statContent := fmt.Sprintf("%d (%s) %s", pid, "cmd with space", strings.Join(statFields, " "))
|
|
|
|
stubReadFile(t, func(path string) ([]byte, error) {
|
|
switch path {
|
|
case fmt.Sprintf("/proc/%d/stat", pid):
|
|
return []byte(statContent), nil
|
|
case "/proc/stat":
|
|
return []byte(fmt.Sprintf("cpu 0 0 0 0\nbtime %d\n", boot.Unix())), nil
|
|
default:
|
|
return nil, os.ErrNotExist
|
|
}
|
|
})
|
|
|
|
got := getProcessStartTime(pid)
|
|
want := boot.Add(time.Duration(startTicks/100) * time.Second)
|
|
if !got.Equal(want) {
|
|
t.Fatalf("getProcessStartTime() = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestGetProcessStartTimeInvalidData(t *testing.T) {
|
|
pid := 99
|
|
stubReadFile(t, func(path string) ([]byte, error) {
|
|
switch path {
|
|
case fmt.Sprintf("/proc/%d/stat", pid):
|
|
return []byte("garbage"), nil
|
|
case "/proc/stat":
|
|
return []byte("btime not-a-number\n"), nil
|
|
default:
|
|
return nil, os.ErrNotExist
|
|
}
|
|
})
|
|
|
|
if got := getProcessStartTime(pid); !got.IsZero() {
|
|
t.Fatalf("invalid /proc data should return zero time, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestGetBootTimeParsesBtime(t *testing.T) {
|
|
const bootSec = 1_711_111_111
|
|
stubReadFile(t, func(path string) ([]byte, error) {
|
|
if path != "/proc/stat" {
|
|
return nil, os.ErrNotExist
|
|
}
|
|
content := fmt.Sprintf("intr 0\nbtime %d\n", bootSec)
|
|
return []byte(content), nil
|
|
})
|
|
|
|
got := getBootTime()
|
|
want := time.Unix(bootSec, 0)
|
|
if !got.Equal(want) {
|
|
t.Fatalf("getBootTime() = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestGetBootTimeInvalidData(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
content string
|
|
}{
|
|
{"missing", "cpu 0 0 0 0"},
|
|
{"malformed", "btime abc"},
|
|
}
|
|
|
|
for _, tt := range cases {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
stubReadFile(t, func(string) ([]byte, error) {
|
|
return []byte(tt.content), nil
|
|
})
|
|
if got := getBootTime(); !got.IsZero() {
|
|
t.Fatalf("getBootTime() unexpected value for %s: %v", tt.name, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func stubReadFile(t *testing.T, fn func(string) ([]byte, error)) {
|
|
t.Helper()
|
|
original := readFileFn
|
|
readFileFn = fn
|
|
t.Cleanup(func() {
|
|
readFileFn = original
|
|
})
|
|
}
|