Files
fscan/core/alive_scanner_test.go
ZacharyZcR 71b92d4408 feat: v2.1.0 核心重构与功能增强
## 架构重构
- 全局变量消除,迁移至 Config/State 对象
- SMB 插件融合(smb/smb2/smbghost/smbinfo)
- 服务探测重构,实现 Nmap 风格 fallback 机制
- 输出系统重构,TXT 实时刷盘 + 双写机制
- i18n 框架升级至 go-i18n

## 性能优化
- 正则表达式预编译
- 内存优化 map[string]struct{}
- 并发指纹匹配
- SOCKS5 连接复用
- 滑动窗口调度 + 自适应线程池

## 新功能
- Web 管理界面
- 多格式 POC 适配(xray/afrog)
- 增强指纹库(3139条)
- Favicon hash 指纹识别
- 插件选择性编译(Build Tags)
- fscan-lab 靶场环境
- 默认端口扩展(62→133)

## 构建系统
- 添加 no_local tag 支持排除本地插件
- 多版本构建:fscan/fscan-nolocal/fscan-web
- CI 添加 snapshot 模式支持仅测试构建

## Bug 修复
- 修复 120+ 个问题,包括 RDP panic、批量扫描漏报、
  JSON 输出格式、Redis 检测、Context 超时等

## 测试增强
- 单元测试覆盖率 74-100%
- 并发安全测试
- 集成测试(Web/端口/服务/SSH/ICMP)
2026-01-11 20:16:23 +08:00

121 lines
2.9 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package core
import (
"testing"
"time"
"github.com/shadow1ng/fscan/common"
)
// TestNewAliveScanStrategy 测试构造函数
func TestNewAliveScanStrategy(t *testing.T) {
strategy := NewAliveScanStrategy()
if strategy == nil {
t.Fatal("NewAliveScanStrategy 返回 nil")
}
if strategy.BaseScanStrategy == nil {
t.Error("BaseScanStrategy 未初始化")
}
// 验证起始时间已设置
if strategy.startTime.IsZero() {
t.Error("startTime 未初始化")
}
// 验证时间在合理范围内过去1秒内
if time.Since(strategy.startTime) > time.Second {
t.Error("startTime 时间戳异常")
}
}
// TestAliveScanStrategy_PrepareTargets 测试PrepareTargets
func TestAliveScanStrategy_PrepareTargets(t *testing.T) {
strategy := NewAliveScanStrategy()
// 存活探测不需要返回目标列表
targets := strategy.PrepareTargets(common.HostInfo{})
if targets != nil {
t.Errorf("PrepareTargets 应返回 nil, 实际: %v", targets)
}
}
// TestAliveScanStrategy_GetPlugins 测试GetPlugins
func TestAliveScanStrategy_GetPlugins(t *testing.T) {
strategy := NewAliveScanStrategy()
plugins, customMode := strategy.GetPlugins(nil)
if len(plugins) != 0 {
t.Errorf("GetPlugins 应返回空列表, 实际长度: %d", len(plugins))
}
if customMode {
t.Error("customMode 应为 false")
}
}
// TestAliveStats_SuccessRateCalculation 测试成功率计算逻辑
func TestAliveStats_SuccessRateCalculation(t *testing.T) {
tests := []struct {
name string
totalHosts int
aliveHosts int
expectedRate float64
}{
{"全部存活", 10, 10, 100.0},
{"一半存活", 10, 5, 50.0},
{"无存活", 10, 0, 0.0},
{"单主机存活", 1, 1, 100.0},
{"单主机死亡", 1, 0, 0.0},
{"三分之一存活", 3, 1, 100.0 / 3.0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 模拟统计计算逻辑(来自 alive_scanner.go:108-110
var successRate float64
if tt.totalHosts > 0 {
successRate = float64(tt.aliveHosts) / float64(tt.totalHosts) * 100
}
// 浮点数比较使用小容忍度
const epsilon = 1e-9
diff := successRate - tt.expectedRate
if diff < -epsilon || diff > epsilon {
t.Errorf("成功率计算错误: 期望 %.10f%%, 实际 %.10f%%, 差值 %.10f",
tt.expectedRate, successRate, diff)
}
})
}
}
// TestAliveStats_DeadHostsCalculation 测试死亡主机数计算
func TestAliveStats_DeadHostsCalculation(t *testing.T) {
tests := []struct {
name string
totalHosts int
aliveHosts int
expectedDead int
}{
{"全部存活", 10, 10, 0},
{"一半存活", 10, 5, 5},
{"全部死亡", 10, 0, 10},
{"单主机", 1, 0, 1},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// 模拟死亡主机计算逻辑(来自 alive_scanner.go:104
deadHosts := tt.totalHosts - tt.aliveHosts
if deadHosts != tt.expectedDead {
t.Errorf("死亡主机数错误: 期望 %d, 实际 %d",
tt.expectedDead, deadHosts)
}
})
}
}