Files
fscan/common/state_test.go
T
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

247 lines
5.7 KiB
Go

package common
import (
"sync"
"testing"
)
/*
state_test.go - State 并发安全测试
测试重点:
1. 并发安全性 - 多goroutine同时操作计数器
2. 原子操作一致性 - 增减计数正确
3. Reset功能 - 重置后计数器归零
不测试:
- 限速器(需要复杂的时间模拟)
- 简单getter/setter
*/
// TestState_ConcurrentPacketCount 测试并发包计数
func TestState_ConcurrentPacketCount(t *testing.T) {
s := NewState()
const goroutines = 100
const incrementsPerGoroutine = 1000
var wg sync.WaitGroup
wg.Add(goroutines)
for i := 0; i < goroutines; i++ {
go func() {
defer wg.Done()
for j := 0; j < incrementsPerGoroutine; j++ {
s.IncrementPacketCount()
}
}()
}
wg.Wait()
expected := int64(goroutines * incrementsPerGoroutine)
actual := s.GetPacketCount()
if actual != expected {
t.Errorf("并发计数不一致: 期望 %d, 实际 %d", expected, actual)
}
}
// TestState_ConcurrentTCPCount 测试并发TCP计数
func TestState_ConcurrentTCPCount(t *testing.T) {
s := NewState()
const goroutines = 50
const operationsPerGoroutine = 500
var wg sync.WaitGroup
wg.Add(goroutines * 2) // 成功和失败各一半
// 成功连接
for i := 0; i < goroutines; i++ {
go func() {
defer wg.Done()
for j := 0; j < operationsPerGoroutine; j++ {
s.IncrementTCPSuccessPacketCount()
}
}()
}
// 失败连接
for i := 0; i < goroutines; i++ {
go func() {
defer wg.Done()
for j := 0; j < operationsPerGoroutine; j++ {
s.IncrementTCPFailedPacketCount()
}
}()
}
wg.Wait()
expectedTotal := int64(goroutines * operationsPerGoroutine * 2)
expectedSuccess := int64(goroutines * operationsPerGoroutine)
expectedFailed := int64(goroutines * operationsPerGoroutine)
if s.GetPacketCount() != expectedTotal {
t.Errorf("总包计数不一致: 期望 %d, 实际 %d", expectedTotal, s.GetPacketCount())
}
if s.GetTCPPacketCount() != expectedTotal {
t.Errorf("TCP包计数不一致: 期望 %d, 实际 %d", expectedTotal, s.GetTCPPacketCount())
}
if s.GetTCPSuccessPacketCount() != expectedSuccess {
t.Errorf("TCP成功计数不一致: 期望 %d, 实际 %d", expectedSuccess, s.GetTCPSuccessPacketCount())
}
if s.GetTCPFailedPacketCount() != expectedFailed {
t.Errorf("TCP失败计数不一致: 期望 %d, 实际 %d", expectedFailed, s.GetTCPFailedPacketCount())
}
}
// TestState_Reset 测试重置功能
func TestState_Reset(t *testing.T) {
s := NewState()
// 增加一些计数
for i := 0; i < 100; i++ {
s.IncrementTCPSuccessPacketCount()
s.IncrementTCPFailedPacketCount()
s.IncrementUDPPacketCount()
s.IncrementHTTPPacketCount()
s.IncrementResourceExhaustedCount()
}
// 验证有值
if s.GetPacketCount() == 0 {
t.Fatal("重置前计数应该非零")
}
// 重置
s.ResetPacketCounters()
// 验证全部归零
if s.GetPacketCount() != 0 {
t.Errorf("重置后PacketCount应该为0, 实际 %d", s.GetPacketCount())
}
if s.GetTCPPacketCount() != 0 {
t.Errorf("重置后TCPPacketCount应该为0, 实际 %d", s.GetTCPPacketCount())
}
if s.GetTCPSuccessPacketCount() != 0 {
t.Errorf("重置后TCPSuccessPacketCount应该为0, 实际 %d", s.GetTCPSuccessPacketCount())
}
if s.GetTCPFailedPacketCount() != 0 {
t.Errorf("重置后TCPFailedPacketCount应该为0, 实际 %d", s.GetTCPFailedPacketCount())
}
if s.GetUDPPacketCount() != 0 {
t.Errorf("重置后UDPPacketCount应该为0, 实际 %d", s.GetUDPPacketCount())
}
if s.GetHTTPPacketCount() != 0 {
t.Errorf("重置后HTTPPacketCount应该为0, 实际 %d", s.GetHTTPPacketCount())
}
if s.GetResourceExhaustedCount() != 0 {
t.Errorf("重置后ResourceExhaustedCount应该为0, 实际 %d", s.GetResourceExhaustedCount())
}
}
// TestState_TaskCounters 测试任务计数器
func TestState_TaskCounters(t *testing.T) {
s := NewState()
// 初始值应该为0
if s.GetEnd() != 0 || s.GetNum() != 0 {
t.Error("初始任务计数器应该为0")
}
// 设置值
s.SetEnd(100)
s.SetNum(50)
if s.GetEnd() != 100 {
t.Errorf("End应该为100, 实际 %d", s.GetEnd())
}
if s.GetNum() != 50 {
t.Errorf("Num应该为50, 实际 %d", s.GetNum())
}
// 增加值
s.IncrementEnd()
s.IncrementNum()
if s.GetEnd() != 101 {
t.Errorf("IncrementEnd后应该为101, 实际 %d", s.GetEnd())
}
if s.GetNum() != 51 {
t.Errorf("IncrementNum后应该为51, 实际 %d", s.GetNum())
}
}
// TestState_ConcurrentTaskCounters 测试并发任务计数
func TestState_ConcurrentTaskCounters(t *testing.T) {
s := NewState()
const goroutines = 100
const incrementsPerGoroutine = 100
var wg sync.WaitGroup
wg.Add(goroutines * 2)
// 并发增加End
for i := 0; i < goroutines; i++ {
go func() {
defer wg.Done()
for j := 0; j < incrementsPerGoroutine; j++ {
s.IncrementEnd()
}
}()
}
// 并发增加Num
for i := 0; i < goroutines; i++ {
go func() {
defer wg.Done()
for j := 0; j < incrementsPerGoroutine; j++ {
s.IncrementNum()
}
}()
}
wg.Wait()
expected := int64(goroutines * incrementsPerGoroutine)
if s.GetEnd() != expected {
t.Errorf("End并发计数不一致: 期望 %d, 实际 %d", expected, s.GetEnd())
}
if s.GetNum() != expected {
t.Errorf("Num并发计数不一致: 期望 %d, 实际 %d", expected, s.GetNum())
}
}
// TestState_OutputMutex 测试输出互斥锁
func TestState_OutputMutex(t *testing.T) {
s := NewState()
counter := 0
const goroutines = 100
const incrementsPerGoroutine = 100
var wg sync.WaitGroup
wg.Add(goroutines)
for i := 0; i < goroutines; i++ {
go func() {
defer wg.Done()
for j := 0; j < incrementsPerGoroutine; j++ {
s.LockOutput()
counter++
s.UnlockOutput()
}
}()
}
wg.Wait()
expected := goroutines * incrementsPerGoroutine
if counter != expected {
t.Errorf("输出互斥锁保护失败: 期望 %d, 实际 %d", expected, counter)
}
}