mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-25 16:04:02 +08:00
349 lines
11 KiB
Go
349 lines
11 KiB
Go
package app
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"GoNavi-Wails/internal/connection"
|
|
datasync "GoNavi-Wails/internal/sync"
|
|
"GoNavi-Wails/shared/i18n"
|
|
)
|
|
|
|
func methodsSyncFunctionSource(t *testing.T, source string, signature string) string {
|
|
t.Helper()
|
|
start := strings.Index(source, signature)
|
|
if start < 0 {
|
|
t.Fatalf("methods_sync.go missing function signature %q", signature)
|
|
}
|
|
rest := source[start+len(signature):]
|
|
end := strings.Index(rest, "\nfunc ")
|
|
if end < 0 {
|
|
return source[start:]
|
|
}
|
|
return source[start : start+len(signature)+end]
|
|
}
|
|
|
|
func buildSavedDataSyncConfig(t *testing.T, app *App) datasync.SyncConfig {
|
|
t.Helper()
|
|
|
|
_, err := app.SaveConnection(connection.SavedConnectionInput{
|
|
ID: "source-pg",
|
|
Name: "Source PostgreSQL",
|
|
Config: connection.ConnectionConfig{
|
|
ID: "source-pg",
|
|
Type: "postgres",
|
|
Host: "source.local",
|
|
Port: 5432,
|
|
User: "postgres",
|
|
Password: "source-secret",
|
|
Database: "schedule",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("SaveConnection source returned error: %v", err)
|
|
}
|
|
_, err = app.SaveConnection(connection.SavedConnectionInput{
|
|
ID: "target-pg",
|
|
Name: "Target PostgreSQL",
|
|
Config: connection.ConnectionConfig{
|
|
ID: "target-pg",
|
|
Type: "postgres",
|
|
Host: "target.local",
|
|
Port: 5432,
|
|
User: "postgres",
|
|
Password: "target-secret",
|
|
Database: "warehouse",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("SaveConnection target returned error: %v", err)
|
|
}
|
|
|
|
return datasync.SyncConfig{
|
|
SourceConfig: connection.ConnectionConfig{
|
|
ID: "source-pg",
|
|
Type: "postgres",
|
|
Host: "source.local",
|
|
Port: 5432,
|
|
User: "postgres",
|
|
Database: "schedule",
|
|
},
|
|
TargetConfig: connection.ConnectionConfig{
|
|
ID: "target-pg",
|
|
Type: "postgres",
|
|
Host: "target.local",
|
|
Port: 5432,
|
|
User: "postgres",
|
|
Database: "warehouse",
|
|
},
|
|
Tables: []string{"jobs"},
|
|
}
|
|
}
|
|
|
|
func TestResolveDataSyncConfigSecretsRestoresSavedSourceAndTargetPasswords(t *testing.T) {
|
|
app := NewAppWithSecretStore(newFakeAppSecretStore())
|
|
app.configDir = t.TempDir()
|
|
|
|
_, err := app.SaveConnection(connection.SavedConnectionInput{
|
|
ID: "source-pg",
|
|
Name: "Source PostgreSQL",
|
|
Config: connection.ConnectionConfig{
|
|
ID: "source-pg",
|
|
Type: "postgres",
|
|
Host: "source.local",
|
|
Port: 5432,
|
|
User: "postgres",
|
|
Password: "source-secret",
|
|
Database: "schedule",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("SaveConnection source returned error: %v", err)
|
|
}
|
|
_, err = app.SaveConnection(connection.SavedConnectionInput{
|
|
ID: "target-pg",
|
|
Name: "Target PostgreSQL",
|
|
Config: connection.ConnectionConfig{
|
|
ID: "target-pg",
|
|
Type: "postgres",
|
|
Host: "target.local",
|
|
Port: 5432,
|
|
User: "postgres",
|
|
Password: "target-secret",
|
|
Database: "warehouse",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("SaveConnection target returned error: %v", err)
|
|
}
|
|
|
|
resolved, err := app.resolveDataSyncConfigSecrets(datasync.SyncConfig{
|
|
SourceConfig: connection.ConnectionConfig{
|
|
ID: "source-pg",
|
|
Type: "postgres",
|
|
Host: "source.local",
|
|
Port: 5432,
|
|
User: "postgres",
|
|
Database: "schedule",
|
|
},
|
|
TargetConfig: connection.ConnectionConfig{
|
|
ID: "target-pg",
|
|
Type: "postgres",
|
|
Host: "target.local",
|
|
Port: 5432,
|
|
User: "postgres",
|
|
Database: "warehouse",
|
|
},
|
|
Tables: []string{"jobs"},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("resolveDataSyncConfigSecrets returned error: %v", err)
|
|
}
|
|
if resolved.SourceConfig.Password != "source-secret" {
|
|
t.Fatalf("expected source password to be restored, got %q", resolved.SourceConfig.Password)
|
|
}
|
|
if resolved.TargetConfig.Password != "target-secret" {
|
|
t.Fatalf("expected target password to be restored, got %q", resolved.TargetConfig.Password)
|
|
}
|
|
if resolved.SourceConfig.Database != "schedule" || resolved.TargetConfig.Database != "warehouse" {
|
|
t.Fatalf("expected selected databases to be preserved, got source=%q target=%q", resolved.SourceConfig.Database, resolved.TargetConfig.Database)
|
|
}
|
|
}
|
|
|
|
func TestResolveDataSyncConfigSecretsRestoresOracleServiceNameFromSavedConnection(t *testing.T) {
|
|
app := NewAppWithSecretStore(newFakeAppSecretStore())
|
|
app.configDir = t.TempDir()
|
|
|
|
_, err := app.SaveConnection(connection.SavedConnectionInput{
|
|
ID: "source-oracle",
|
|
Name: "Source Oracle",
|
|
Config: connection.ConnectionConfig{
|
|
ID: "source-oracle",
|
|
Type: "oracle",
|
|
Host: "oracle.local",
|
|
Port: 1521,
|
|
User: "scott",
|
|
Password: "source-secret",
|
|
Database: "ORCLPDB1",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("SaveConnection source returned error: %v", err)
|
|
}
|
|
_, err = app.SaveConnection(connection.SavedConnectionInput{
|
|
ID: "target-mysql",
|
|
Name: "Target MySQL",
|
|
Config: connection.ConnectionConfig{
|
|
ID: "target-mysql",
|
|
Type: "mysql",
|
|
Host: "mysql.local",
|
|
Port: 3306,
|
|
User: "root",
|
|
Password: "target-secret",
|
|
Database: "warehouse",
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("SaveConnection target returned error: %v", err)
|
|
}
|
|
|
|
resolved, err := app.resolveDataSyncConfigSecrets(datasync.SyncConfig{
|
|
SourceConfig: connection.ConnectionConfig{
|
|
ID: "source-oracle",
|
|
Type: "oracle",
|
|
Host: "oracle.local",
|
|
Port: 1521,
|
|
User: "scott",
|
|
Database: "APP_SCHEMA",
|
|
},
|
|
TargetConfig: connection.ConnectionConfig{
|
|
ID: "target-mysql",
|
|
Type: "mysql",
|
|
Host: "mysql.local",
|
|
Port: 3306,
|
|
User: "root",
|
|
Database: "warehouse",
|
|
},
|
|
Tables: []string{"APP_SCHEMA.ORDERS"},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("resolveDataSyncConfigSecrets returned error: %v", err)
|
|
}
|
|
if resolved.SourceConfig.Database != "ORCLPDB1" {
|
|
t.Fatalf("expected Oracle service name to be restored, got %q", resolved.SourceConfig.Database)
|
|
}
|
|
if resolved.SourceDatabase != "APP_SCHEMA" {
|
|
t.Fatalf("expected legacy selected schema to move into SourceDatabase, got %q", resolved.SourceDatabase)
|
|
}
|
|
if resolved.SourceConfig.Password != "source-secret" || resolved.TargetConfig.Password != "target-secret" {
|
|
t.Fatalf("expected source and target passwords to be restored")
|
|
}
|
|
}
|
|
|
|
func TestMethodsSyncSecretRestoreMessagesUseLocalizedText(t *testing.T) {
|
|
sourceBytes, err := os.ReadFile("methods_sync.go")
|
|
if err != nil {
|
|
t.Fatalf("read methods_sync.go: %v", err)
|
|
}
|
|
source := string(sourceBytes)
|
|
functionSource := methodsSyncFunctionSource(t, source, "func (a *App) resolveDataSyncConfigSecrets")
|
|
|
|
for _, literal := range []string{
|
|
`"恢复源数据库连接密文失败: %w"`,
|
|
`"恢复目标数据库连接密文失败: %w"`,
|
|
} {
|
|
if strings.Contains(functionSource, literal) {
|
|
t.Fatalf("resolveDataSyncConfigSecrets still contains raw DataSync secret restore text %q", literal)
|
|
}
|
|
}
|
|
|
|
for _, key := range []string{
|
|
"data_sync.backend.error.restore_source_secret_failed",
|
|
"data_sync.backend.error.restore_target_secret_failed",
|
|
} {
|
|
if !strings.Contains(functionSource, key) {
|
|
t.Fatalf("resolveDataSyncConfigSecrets does not reference DataSync backend i18n key %q", key)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMethodsSyncSecretRestoreCatalogKeysExist(t *testing.T) {
|
|
catalogs, err := i18n.LoadCatalogs()
|
|
if err != nil {
|
|
t.Fatalf("LoadCatalogs() error = %v", err)
|
|
}
|
|
|
|
keys := []string{
|
|
"data_sync.backend.error.restore_source_secret_failed",
|
|
"data_sync.backend.error.restore_target_secret_failed",
|
|
}
|
|
for _, language := range i18n.SupportedLanguages() {
|
|
catalog := catalogs[language]
|
|
for _, key := range keys {
|
|
if strings.TrimSpace(catalog[key]) == "" {
|
|
t.Fatalf("%s catalog missing DataSync secret restore key %q", language, key)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestResolveDataSyncConfigSecretsSourceFailureUsesLocalizedMessage(t *testing.T) {
|
|
app := NewAppWithSecretStore(newFakeAppSecretStore())
|
|
app.configDir = t.TempDir()
|
|
app.SetLanguage(string(i18n.LanguageEnUS))
|
|
config := buildSavedDataSyncConfig(t, app)
|
|
repo := newSavedConnectionRepository(app.configDir, app.secretStore)
|
|
if err := repo.deleteSecretBundle("source-pg"); err != nil {
|
|
t.Fatalf("delete source secret bundle: %v", err)
|
|
}
|
|
|
|
_, err := app.resolveDataSyncConfigSecrets(config)
|
|
if err == nil {
|
|
t.Fatal("expected resolveDataSyncConfigSecrets to fail for source secret restore")
|
|
}
|
|
|
|
want := "Failed to restore source database connection secret: The saved secret for the current connection was not found. Re-enter the password, save, and try again."
|
|
if err.Error() != want {
|
|
t.Fatalf("expected localized source restore message %q, got %q", want, err.Error())
|
|
}
|
|
}
|
|
|
|
func TestResolveDataSyncConfigSecretsTargetFailureUsesLocalizedMessage(t *testing.T) {
|
|
app := NewAppWithSecretStore(newFakeAppSecretStore())
|
|
app.configDir = t.TempDir()
|
|
app.SetLanguage(string(i18n.LanguageEnUS))
|
|
config := buildSavedDataSyncConfig(t, app)
|
|
repo := newSavedConnectionRepository(app.configDir, app.secretStore)
|
|
if err := repo.deleteSecretBundle("target-pg"); err != nil {
|
|
t.Fatalf("delete target secret bundle: %v", err)
|
|
}
|
|
|
|
_, err := app.resolveDataSyncConfigSecrets(config)
|
|
if err == nil {
|
|
t.Fatal("expected resolveDataSyncConfigSecrets to fail for target secret restore")
|
|
}
|
|
|
|
want := "Failed to restore target database connection secret: The saved secret for the current connection was not found. Re-enter the password, save, and try again."
|
|
if err.Error() != want {
|
|
t.Fatalf("expected localized target restore message %q, got %q", want, err.Error())
|
|
}
|
|
}
|
|
|
|
func TestDataSyncPreviewSourceFailureUsesLocalizedMessage(t *testing.T) {
|
|
app := NewAppWithSecretStore(newFakeAppSecretStore())
|
|
app.configDir = t.TempDir()
|
|
app.SetLanguage(string(i18n.LanguageEnUS))
|
|
config := buildSavedDataSyncConfig(t, app)
|
|
repo := newSavedConnectionRepository(app.configDir, app.secretStore)
|
|
if err := repo.deleteSecretBundle("source-pg"); err != nil {
|
|
t.Fatalf("delete source secret bundle: %v", err)
|
|
}
|
|
|
|
result := app.DataSyncPreview(config, "jobs", 10)
|
|
if result.Success {
|
|
t.Fatalf("DataSyncPreview returned success: %+v", result)
|
|
}
|
|
|
|
want := "Failed to restore source database connection secret: The saved secret for the current connection was not found. Re-enter the password, save, and try again."
|
|
if result.Message != want {
|
|
t.Fatalf("expected localized preview source restore message %q, got %q", want, result.Message)
|
|
}
|
|
}
|
|
|
|
func TestMethodsSyncPreviewSuccessMessageUsesLocalizedText(t *testing.T) {
|
|
sourceBytes, err := os.ReadFile("methods_sync.go")
|
|
if err != nil {
|
|
t.Fatalf("read methods_sync.go: %v", err)
|
|
}
|
|
source := string(sourceBytes)
|
|
functionSource := methodsSyncFunctionSource(t, source, "func (a *App) DataSyncPreview")
|
|
|
|
if strings.Contains(functionSource, `Message: "OK"`) {
|
|
t.Fatal(`DataSyncPreview still returns raw success text "OK"`)
|
|
}
|
|
if !strings.Contains(functionSource, "data_sync.backend.result.preview_ready") {
|
|
t.Fatal("DataSyncPreview does not reference data_sync.backend.result.preview_ready")
|
|
}
|
|
}
|