Files
MyGoNavi/internal/app/app_keepalive_test.go
Syngnat e7935db84b feat(db-connection): 新增连接后台定时探活保活能力
- 为连接配置新增 keepAlive 开关与探活间隔
- 在后端缓存连接上增加后台定时 Ping 调度与失效剔除
- 补充前端表单、Wails 模型映射与定向测试覆盖

Close #579
2026-06-20 11:24:44 +08:00

150 lines
4.5 KiB
Go

package app
import (
"errors"
"testing"
"time"
"GoNavi-Wails/internal/connection"
)
type keepAliveRecordingDB struct {
closed int
pings int
pingErr error
}
func (f *keepAliveRecordingDB) Connect(config connection.ConnectionConfig) error { return nil }
func (f *keepAliveRecordingDB) Close() error {
f.closed++
return nil
}
func (f *keepAliveRecordingDB) Ping() error {
f.pings++
return f.pingErr
}
func (f *keepAliveRecordingDB) Query(query string) ([]map[string]interface{}, []string, error) {
return nil, nil, nil
}
func (f *keepAliveRecordingDB) Exec(query string) (int64, error) { return 0, nil }
func (f *keepAliveRecordingDB) GetDatabases() ([]string, error) { return nil, nil }
func (f *keepAliveRecordingDB) GetTables(dbName string) ([]string, error) { return nil, nil }
func (f *keepAliveRecordingDB) GetCreateStatement(dbName, tableName string) (string, error) {
return "", nil
}
func (f *keepAliveRecordingDB) GetColumns(dbName, tableName string) ([]connection.ColumnDefinition, error) {
return nil, nil
}
func (f *keepAliveRecordingDB) GetAllColumns(dbName string) ([]connection.ColumnDefinitionWithTable, error) {
return nil, nil
}
func (f *keepAliveRecordingDB) GetIndexes(dbName, tableName string) ([]connection.IndexDefinition, error) {
return nil, nil
}
func (f *keepAliveRecordingDB) GetForeignKeys(dbName, tableName string) ([]connection.ForeignKeyDefinition, error) {
return nil, nil
}
func (f *keepAliveRecordingDB) GetTriggers(dbName, tableName string) ([]connection.TriggerDefinition, error) {
return nil, nil
}
func TestRunConnectionKeepAliveTick_PingsDueCachedConnection(t *testing.T) {
app := NewApp()
config := connection.ConnectionConfig{Type: "postgres", Host: "db.local", Port: 5432, User: "postgres"}
key := getCacheKey(config)
dbInst := &keepAliveRecordingDB{}
app.dbCache[key] = cachedDatabase{
inst: dbInst,
lastPing: time.Now().Add(-5 * time.Hour),
config: normalizeCacheKeyConfig(config),
keepAliveEnabled: true,
keepAliveInterval: 4 * time.Hour,
}
app.runConnectionKeepAliveTick(time.Now())
if dbInst.pings != 1 {
t.Fatalf("expected keepalive ping once, got %d", dbInst.pings)
}
entry := app.dbCache[key]
if entry.keepAliveInFlight {
t.Fatal("expected keepalive in-flight flag to be cleared")
}
if entry.lastPing.IsZero() {
t.Fatal("expected keepalive success to update lastPing")
}
}
func TestRunConnectionKeepAliveTick_RemovesFailedCachedConnection(t *testing.T) {
app := NewApp()
config := connection.ConnectionConfig{Type: "postgres", Host: "db.local", Port: 5432, User: "postgres"}
key := getCacheKey(config)
dbInst := &keepAliveRecordingDB{pingErr: errors.New("token expired")}
app.dbCache[key] = cachedDatabase{
inst: dbInst,
lastPing: time.Now().Add(-5 * time.Hour),
config: normalizeCacheKeyConfig(config),
keepAliveEnabled: true,
keepAliveInterval: 4 * time.Hour,
}
app.runConnectionKeepAliveTick(time.Now())
if dbInst.pings != 1 {
t.Fatalf("expected keepalive ping once, got %d", dbInst.pings)
}
if dbInst.closed != 1 {
t.Fatalf("expected failed cached connection to be closed once, got %d", dbInst.closed)
}
if len(app.dbCache) != 0 {
t.Fatalf("expected failed cached connection to be evicted, got %d entries", len(app.dbCache))
}
}
func TestGetDatabaseWithPing_UpdatesCachedKeepAliveSettings(t *testing.T) {
originalDriverRuntimeSupportStatusFunc := driverRuntimeSupportStatusFunc
defer func() {
driverRuntimeSupportStatusFunc = originalDriverRuntimeSupportStatusFunc
}()
driverRuntimeSupportStatusFunc = func(dbType string) (bool, string) {
return true, ""
}
app := NewApp()
config := connection.ConnectionConfig{
Type: "postgres",
Host: "db.local",
Port: 5432,
User: "postgres",
KeepAliveEnabled: true,
KeepAliveIntervalMinutes: 15,
}
key := getCacheKey(config)
dbInst := &keepAliveRecordingDB{}
app.dbCache[key] = cachedDatabase{
inst: dbInst,
lastPing: time.Now(),
config: normalizeCacheKeyConfig(config),
}
inst, err := app.getDatabaseWithPing(config, false)
if err != nil {
t.Fatalf("expected cached database lookup to succeed, got %v", err)
}
if inst != dbInst {
t.Fatal("expected cached database instance to be reused")
}
entry := app.dbCache[key]
if !entry.keepAliveEnabled {
t.Fatal("expected cached keepalive to be enabled from config")
}
if entry.keepAliveInterval != 15*time.Minute {
t.Fatalf("expected keepalive interval 15m, got %s", entry.keepAliveInterval)
}
}