mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 03:10:42 +08:00
Fix credential cleanup and explicit tuning flags
This commit is contained in:
@@ -61,6 +61,8 @@ type AuthFunc func(ctx context.Context, cred Credential) *AuthResult
|
||||
// ErrorClassifier 错误分类函数
|
||||
type ErrorClassifier func(err error) ErrorType
|
||||
|
||||
var authCleanupWait = 2 * time.Second
|
||||
|
||||
// =============================================================================
|
||||
// 单凭据测试(解决 goroutine 泄漏)
|
||||
// =============================================================================
|
||||
@@ -79,12 +81,17 @@ func TestSingleCredential(ctx context.Context, cred Credential, authFn AuthFunc)
|
||||
case result := <-resultChan:
|
||||
return result
|
||||
case <-ctx.Done():
|
||||
// context 被取消,等待 authFn goroutine 返回并清理连接
|
||||
// 各插件的 authFn 应在 context 取消时关闭底层连接使 goroutine 快速退出
|
||||
// context 被取消后只做有界等待,避免 authFn 卡死时清理 goroutine 也永久泄漏。
|
||||
go func() {
|
||||
result := <-resultChan
|
||||
if result != nil && result.Conn != nil {
|
||||
_ = result.Conn.Close()
|
||||
timer := time.NewTimer(authCleanupWait)
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
if result != nil && result.Conn != nil {
|
||||
_ = result.Conn.Close()
|
||||
}
|
||||
case <-timer.C:
|
||||
}
|
||||
}()
|
||||
return &AuthResult{
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -401,6 +402,40 @@ func TestTestSingleCredential_ContextCancel(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTestSingleCredential_ContextCancelCleanupIsBounded(t *testing.T) {
|
||||
oldWait := authCleanupWait
|
||||
authCleanupWait = 20 * time.Millisecond
|
||||
defer func() { authCleanupWait = oldWait }()
|
||||
|
||||
authStarted := make(chan struct{})
|
||||
releaseAuth := make(chan struct{})
|
||||
authFn := func(ctx context.Context, cred Credential) *AuthResult {
|
||||
close(authStarted)
|
||||
<-releaseAuth
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
<-authStarted
|
||||
cancel()
|
||||
}()
|
||||
|
||||
before := runtime.NumGoroutine()
|
||||
result := TestSingleCredential(ctx, Credential{Username: "admin", Password: "admin"}, authFn)
|
||||
if result.Success {
|
||||
t.Error("context取消后不应该返回成功")
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
after := runtime.NumGoroutine()
|
||||
close(releaseAuth)
|
||||
|
||||
if after > before+1 {
|
||||
t.Fatalf("清理 goroutine 疑似泄漏: before=%d after=%d", before, after)
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 重试逻辑测试
|
||||
// =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user