fscan/mysql_tests/mysql_connection_test.go
ZacharyZcR 43f210ffc6 feat: 实现新一代插件注册系统完全替代传统手动注册模式
- 重构插件注册架构采用现代工厂模式和自动发现机制
- 新增完整的插件元数据管理系统支持版本能力标签等信息
- 实现智能插件适配器提供向后兼容的桥接功能
- 建立MySQL Redis SSH三个标准插件作为新架构参考实现
- 优化插件扫描逻辑支持按端口按类型的智能查询和过滤
- 添加国际化支持和完善的文档体系
- 代码量减少67%维护成本大幅降低扩展性显著提升

新架构特点:
- 零配置插件注册import即用
- 工厂模式延迟初始化和依赖注入
- 丰富元数据系统和能力声明
- 完全解耦的模块化设计
- 面向未来的可扩展架构

测试验证: MySQL和Redis插件功能完整包括弱密码检测未授权访问检测和自动利用攻击
2025-08-07 11:28:34 +08:00

268 lines
7.6 KiB
Go
Raw 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 main
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
_ "github.com/go-sql-driver/mysql"
)
// TestMySQLConnection 测试MySQL连接字符串的各种格式
func TestMySQLConnection() {
// 测试参数
host := "127.0.0.1"
port := 3306
username := "root"
password := "123456"
timeoutDuration := 3 * time.Second
timeoutStr := timeoutDuration.String() // "3s"
fmt.Println("=== MySQL连接字符串测试 ===")
fmt.Printf("目标: %s:%d\n", host, port)
fmt.Printf("用户: %s\n", username)
fmt.Printf("超时: %s\n", timeoutStr)
fmt.Println()
// 测试不同的连接字符串格式
testConfigs := []struct {
name string
dsn string
desc string
}{
{
name: "当前fscan格式",
dsn: fmt.Sprintf("%s:%s@tcp(%s:%d)/mysql?charset=utf8&timeout=%s", username, password, host, port, timeoutStr),
desc: "fscan当前使用的格式包含数据库名mysql",
},
{
name: "不指定数据库",
dsn: fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=utf8&timeout=%s", username, password, host, port, timeoutStr),
desc: "不指定具体数据库,连接到默认数据库",
},
{
name: "无数据库名",
dsn: fmt.Sprintf("%s:%s@tcp(%s:%d)?charset=utf8&timeout=%s", username, password, host, port, timeoutStr),
desc: "完全不指定数据库名",
},
{
name: "标准格式+readTimeout",
dsn: fmt.Sprintf("%s:%s@tcp(%s:%d)/mysql?charset=utf8&timeout=%s&readTimeout=%s&writeTimeout=%s", username, password, host, port, timeoutStr, timeoutStr, timeoutStr),
desc: "添加读写超时参数",
},
{
name: "使用parseTime",
dsn: fmt.Sprintf("%s:%s@tcp(%s:%d)/mysql?charset=utf8&timeout=%s&parseTime=true", username, password, host, port, timeoutStr),
desc: "添加parseTime参数处理时间类型",
},
{
name: "最小参数",
dsn: fmt.Sprintf("%s:%s@tcp(%s:%d)/", username, password, host, port),
desc: "最简单的连接字符串",
},
}
for i, config := range testConfigs {
fmt.Printf("[%d] %s\n", i+1, config.name)
fmt.Printf("描述: %s\n", config.desc)
fmt.Printf("DSN: %s\n", config.dsn)
// 测试连接
success := testConnection(config.dsn, timeoutDuration)
if success {
fmt.Printf("结果: ✅ 连接成功\n")
} else {
fmt.Printf("结果: ❌ 连接失败\n")
}
fmt.Println(strings.Repeat("-", 80))
}
// 测试context超时的影响
fmt.Println("\n=== Context超时测试 ===")
testContextTimeout()
}
// testConnection 测试指定DSN的连接
func testConnection(dsn string, timeout time.Duration) bool {
// 创建context设置超时时间
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
// 尝试连接
db, err := sql.Open("mysql", dsn)
if err != nil {
fmt.Printf(" Open失败: %v\n", err)
return false
}
defer db.Close()
// 设置连接池参数
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(1)
db.SetConnMaxLifetime(timeout)
// 测试ping - 这是实际建立连接的地方
err = db.PingContext(ctx)
if err != nil {
fmt.Printf(" Ping失败: %v\n", err)
return false
}
// 执行简单查询测试
var version string
err = db.QueryRowContext(ctx, "SELECT VERSION()").Scan(&version)
if err != nil {
fmt.Printf(" 查询失败: %v\n", err)
return false
}
fmt.Printf(" MySQL版本: %s\n", version)
return true
}
// testContextTimeout 测试context超时对连接的影响
func testContextTimeout() {
host := "127.0.0.1"
port := 3306
username := "root"
password := "123456"
// 基础连接字符串不设置timeout参数
baseDSN := fmt.Sprintf("%s:%s@tcp(%s:%d)/mysql?charset=utf8", username, password, host, port)
timeoutTests := []struct {
name string
dsn string
contextTimeout time.Duration
desc string
}{
{
name: "仅Context超时3s",
dsn: baseDSN,
contextTimeout: 3 * time.Second,
desc: "只使用context超时不在DSN中设置timeout",
},
{
name: "DSN超时3s + Context超时3s",
dsn: baseDSN + "&timeout=3s",
contextTimeout: 3 * time.Second,
desc: "同时设置DSN和context超时",
},
{
name: "DSN超时10s + Context超时3s",
dsn: baseDSN + "&timeout=10s",
contextTimeout: 3 * time.Second,
desc: "DSN超时更长context超时更短",
},
{
name: "DSN超时3s + Context超时10s",
dsn: baseDSN + "&timeout=3s",
contextTimeout: 10 * time.Second,
desc: "DSN超时更短context超时更长",
},
}
for i, test := range timeoutTests {
fmt.Printf("[%d] %s\n", i+1, test.name)
fmt.Printf("描述: %s\n", test.desc)
fmt.Printf("DSN: %s\n", test.dsn)
fmt.Printf("Context超时: %v\n", test.contextTimeout)
start := time.Now()
success := testConnectionWithTiming(test.dsn, test.contextTimeout)
elapsed := time.Since(start)
if success {
fmt.Printf("结果: ✅ 连接成功,耗时: %v\n", elapsed)
} else {
fmt.Printf("结果: ❌ 连接失败,耗时: %v\n", elapsed)
}
fmt.Println(strings.Repeat("-", 80))
}
}
// testConnectionWithTiming 带时间统计的连接测试
func testConnectionWithTiming(dsn string, contextTimeout time.Duration) bool {
ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
defer cancel()
db, err := sql.Open("mysql", dsn)
if err != nil {
fmt.Printf(" Open失败: %v\n", err)
return false
}
defer db.Close()
db.SetMaxOpenConns(1)
db.SetMaxIdleConns(1)
err = db.PingContext(ctx)
if err != nil {
fmt.Printf(" Ping失败: %v\n", err)
return false
}
return true
}
// 优化建议和分析
func printOptimizationSuggestions() {
fmt.Println("\n=== MySQL连接字符串优化建议 ===")
suggestions := []string{
"1. 连接字符串格式建议:",
" 推荐: user:pass@tcp(host:port)/dbname?charset=utf8mb4&parseTime=true&timeout=3s",
"",
"2. 超时参数优化:",
" - 使用charset=utf8mb4而不是utf8支持完整的UTF-8字符集",
" - 添加parseTime=true自动解析时间类型",
" - 分别设置timeout、readTimeout、writeTimeout更精细控制",
"",
"3. Context vs DSN超时",
" - Context超时控制整个操作的最大时间",
" - DSN timeout参数控制连接建立的超时",
" - 建议Context超时 >= DSN timeout + 额外处理时间",
"",
"4. 连接池优化:",
" - SetMaxOpenConns(1) 对于扫描场景是合适的",
" - SetConnMaxLifetime应该设置适当的值避免连接泄露",
" - 使用defer db.Close()确保连接被释放",
"",
"5. 错误处理:",
" - 'context deadline exceeded' 通常表示网络问题或超时设置过短",
" - 检查防火墙设置和网络连接",
" - 确认MySQL服务器配置允许远程连接",
}
for _, suggestion := range suggestions {
fmt.Println(suggestion)
}
}
func main() {
fmt.Println("MySQL连接字符串测试工具")
fmt.Println("作者: Go语言代码优化专家")
fmt.Println("目的: 验证fscan中MySQL连接字符串格式的正确性")
fmt.Println("=" + strings.Repeat("=", 60))
// 检查必要的包
fmt.Println("\n检查依赖...")
fmt.Println("✅ github.com/go-sql-driver/mysql 已导入")
// 执行测试
TestMySQLConnection()
// 打印优化建议
printOptimizationSuggestions()
fmt.Println("\n测试完成")
fmt.Println("\n使用方法:")
fmt.Println("1. 确保MySQL服务器运行在127.0.0.1:3306")
fmt.Println("2. 创建用户: CREATE USER 'root'@'%' IDENTIFIED BY '123456';")
fmt.Println("3. 授权: GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';")
fmt.Println("4. 刷新权限: FLUSH PRIVILEGES;")
fmt.Println("5. 运行: go run mysql_connection_test.go")
}