diff --git a/frontend/src/components/DriverManagerModal.test.tsx b/frontend/src/components/DriverManagerModal.test.tsx index 8033330..a039e05 100644 --- a/frontend/src/components/DriverManagerModal.test.tsx +++ b/frontend/src/components/DriverManagerModal.test.tsx @@ -230,4 +230,62 @@ describe('DriverManagerModal toolbar actions', () => { vi.useRealTimers(); } }); + + it('reinstalls stale MongoDB v2 drivers with the v1 compatibility default', async () => { + vi.useFakeTimers({ shouldAdvanceTime: true }); + try { + vi.setSystemTime(new Date(Date.now() + 2 * 60 * 1000)); + backendApp.GetDriverStatusList.mockResolvedValue({ + success: true, + data: { + downloadDir: 'D:/drivers', + drivers: [ + { + type: 'mongodb', + name: 'MongoDB', + builtIn: false, + pinnedVersion: '1.17.9', + installedVersion: '2.5.0', + runtimeAvailable: true, + packageInstalled: true, + connectable: true, + needsUpdate: true, + defaultDownloadUrl: 'builtin://activate/mongodb', + message: '建议重装', + }, + ], + }, + }); + backendApp.GetDriverVersionList.mockResolvedValue({ + success: true, + data: { + versions: [ + { version: '2.5.0', downloadUrl: 'builtin://activate/mongodb?version=2.5.0' }, + { version: '1.17.9', downloadUrl: 'builtin://activate/mongodb', recommended: true }, + ], + }, + }); + backendApp.DownloadDriverPackage.mockResolvedValue({ success: true }); + + let renderer: ReactTestRenderer; + await act(async () => { + renderer = create(); + }); + await flushPromises(); + + const reinstallButton = findButton(renderer!, '重装驱动'); + await act(async () => { + await reinstallButton.props.onClick(); + }); + + expect(backendApp.DownloadDriverPackage).toHaveBeenCalledWith( + 'mongodb', + '1.17.9', + 'builtin://activate/mongodb', + 'D:/drivers', + ); + } finally { + vi.useRealTimers(); + } + }); }); diff --git a/frontend/src/components/DriverManagerModal.tsx b/frontend/src/components/DriverManagerModal.tsx index ca1550b..f303a23 100644 --- a/frontend/src/components/DriverManagerModal.tsx +++ b/frontend/src/components/DriverManagerModal.tsx @@ -525,6 +525,8 @@ const DriverManagerModal: React.FC<{ open: boolean; onClose: () => void; onOpenG return prev; } const preferred = + (row.needsUpdate ? options.find((option) => option.version === row.pinnedVersion) : undefined) || + (row.needsUpdate ? options.find((option) => option.recommended) : undefined) || options.find((option) => option.version === row.installedVersion) || options.find((option) => option.version === row.pinnedVersion) || options.find((option) => option.recommended) || @@ -712,6 +714,8 @@ const DriverManagerModal: React.FC<{ open: boolean; onClose: () => void; onOpenG } const selectedKey = selectedVersionMap[row.type]; const selectedOption = + (row.needsUpdate ? versionOptions.find((item) => item.version === row.pinnedVersion) : undefined) || + (row.needsUpdate ? versionOptions.find((item) => item.recommended) : undefined) || versionOptions.find((item) => buildVersionOptionKey(item) === selectedKey) || versionOptions.find((item) => item.recommended) || versionOptions[0]; @@ -1033,7 +1037,7 @@ const DriverManagerModal: React.FC<{ open: boolean; onClose: () => void; onOpenG const selectedKey = selectedVersionMap[row.type]; const selectOptions = buildVersionSelectOptions(options); const mongoHint = row.type === 'mongodb' - ? '当前仅支持 MongoDB 1.17.x 和 2.x;更老 1.x 暂不提供安装。' + ? 'MongoDB 4.0 请使用 1.17.x 兼容驱动;2.x 驱动要求 MongoDB 4.2+。' : ''; return (
diff --git a/internal/app/methods_driver.go b/internal/app/methods_driver.go index fc9a33f..fb480b1 100644 --- a/internal/app/methods_driver.go +++ b/internal/app/methods_driver.go @@ -352,7 +352,7 @@ const builtinDriverManifestJSON = `{ "vastbase": { "engine": "go", "version": "1.11.1", "checksumPolicy": "off", "downloadUrl": "builtin://activate/vastbase" }, "opengauss": { "engine": "go", "version": "1.11.1", "checksumPolicy": "off", "downloadUrl": "builtin://activate/opengauss" }, "iris": { "engine": "go", "version": "0.2.1", "checksumPolicy": "off", "downloadUrl": "builtin://activate/iris" }, - "mongodb": { "engine": "go", "version": "2.5.0", "checksumPolicy": "off", "downloadUrl": "builtin://activate/mongodb" }, + "mongodb": { "engine": "go", "version": "1.17.9", "checksumPolicy": "off", "downloadUrl": "builtin://activate/mongodb" }, "tdengine": { "engine": "go", "version": "3.7.8", "checksumPolicy": "off", "downloadUrl": "builtin://activate/tdengine" }, "clickhouse": { "engine": "go", "version": "2.43.1", "checksumPolicy": "off", "downloadUrl": "builtin://activate/clickhouse" }, "elasticsearch": { "engine": "go", "version": "8.19.6", "checksumPolicy": "off", "downloadUrl": "builtin://activate/elasticsearch" } @@ -821,7 +821,7 @@ func (a *App) GetDriverStatusList(downloadDir string, manifestURL string) connec engine := effectiveDriverEngine(definition) runtimeAvailable, runtimeReason := db.DriverRuntimeSupportStatus(definition.Type) pkg, packageMetaExists := readInstalledDriverPackage(resolvedDir, definition.Type) - needsUpdate, updateReason, expectedRevision := optionalDriverAgentRevisionStatus(definition.Type, pkg, packageMetaExists) + needsUpdate, updateReason, expectedRevision := optionalDriverPackageUpdateStatus(definition, pkg, packageMetaExists) packageInstalled := definition.BuiltIn || packageMetaExists if runtimeAvailable && db.IsOptionalGoDriver(definition.Type) { packageInstalled = true @@ -2828,6 +2828,31 @@ func optionalDriverAgentRevisionStatus(driverType string, pkg installedDriverPac return true, fmt.Sprintf("原因:%s。影响:%s(已安装标记:%s,当前需要:%s)", updateReason, impact, actual, expected), expected } +func optionalDriverPackageUpdateStatus(definition driverDefinition, pkg installedDriverPackage, packageMetaExists bool) (bool, string, string) { + needsUpdate, reason, expected := optionalDriverAgentRevisionStatus(definition.Type, pkg, packageMetaExists) + if needsUpdate { + return true, reason, expected + } + if mongoDriverNeedsLegacyCompatibilityUpdate(definition, pkg, packageMetaExists) { + pinned := strings.TrimSpace(definition.PinnedVersion) + installed := strings.TrimSpace(pkg.Version) + return true, fmt.Sprintf("原因:当前推荐 MongoDB 兼容驱动版本为 %s,已安装版本为 %s。影响:MongoDB 2.x driver-agent 使用官方 v2 驱动,要求服务端 MongoDB 4.2+;连接 MongoDB 4.0 会出现 wire version 7 不兼容。强烈建议重装对应驱动代理", pinned, installed), expected + } + return false, "", expected +} + +func mongoDriverNeedsLegacyCompatibilityUpdate(definition driverDefinition, pkg installedDriverPackage, packageMetaExists bool) bool { + if normalizeDriverType(definition.Type) != "mongodb" || !packageMetaExists { + return false + } + pinned := normalizeVersion(strings.TrimSpace(definition.PinnedVersion)) + installed := normalizeVersion(strings.TrimSpace(pkg.Version)) + if pinned == "" || installed == "" { + return false + } + return resolveMongoDriverMajorFromVersion(installed) == 2 && resolveMongoDriverMajorFromVersion(pinned) == 1 +} + func optionalDriverAgentRevisionCurrent(driverType string, executablePath string) (string, bool, error) { expected := strings.TrimSpace(db.OptionalDriverAgentRevision(driverType)) if expected == "" { @@ -3967,28 +3992,8 @@ func resolveMongoDriverMajorFromVersion(version string) int { return 2 } -func shouldForceSourceBuildForVersion(driverType string, selectedVersion string) bool { - if normalizeDriverType(driverType) != "mongodb" { - return false - } - return resolveMongoDriverMajorFromVersion(selectedVersion) == 1 -} - -func shouldForceSourceBuildForResolvedDownload(driverType string, selectedVersion string, downloadURL string) bool { - if !shouldForceSourceBuildForVersion(driverType, selectedVersion) { - return false - } - - parsed, err := url.Parse(strings.TrimSpace(downloadURL)) - if err != nil || parsed == nil { - return true - } - switch strings.ToLower(strings.TrimSpace(parsed.Scheme)) { - case "http", "https": - return false - default: - return true - } +func shouldForceSourceBuildForResolvedDownload(_ string, _ string, _ string) bool { + return false } func shouldPreferSourceBuildBeforeDownload(driverType string, selectedVersion string) bool { @@ -4878,7 +4883,7 @@ func resolveOptionalDriverAgentDownloadURLs(definition driverDefinition, rawURL appendURL(publishedURL) } } - if publishedURL, ok := resolveLatestPublishedDriverDownloadURL(definition); ok { + if publishedURL, ok := resolveLatestPublishedDriverDownloadURLForVersion(definition, selectedVersion); ok { appendURL(publishedURL) } } @@ -5510,6 +5515,10 @@ func fetchLatestReleaseForDriverAssets() (*githubRelease, error) { } func resolveLatestPublishedDriverDownloadURL(definition driverDefinition) (string, bool) { + return resolveLatestPublishedDriverDownloadURLForVersion(definition, "") +} + +func resolveLatestPublishedDriverDownloadURLForVersion(definition driverDefinition, selectedVersion string) (string, bool) { driverType := normalizeDriverType(definition.Type) if driverType == "" { return "", false @@ -5542,7 +5551,7 @@ func resolveLatestPublishedDriverDownloadURL(definition driverDefinition) (strin return "", false } - assetNames := optionalDriverReleaseAssetNames(driverType) + assetNames := optionalDriverReleaseAssetNamesForVersion(driverType, selectedVersion) if len(assetNames) == 0 { return "", false } diff --git a/internal/app/methods_driver_agent_revision_test.go b/internal/app/methods_driver_agent_revision_test.go index 243e8ef..a7f773b 100644 --- a/internal/app/methods_driver_agent_revision_test.go +++ b/internal/app/methods_driver_agent_revision_test.go @@ -33,6 +33,25 @@ func TestOptionalDriverAgentRevisionStatusDetectsStaleClickHouseAgent(t *testing } } +func TestOptionalDriverPackageUpdateStatusDetectsMongoV2WhenLegacyDefault(t *testing.T) { + definition, ok := resolveDriverDefinition("mongodb") + if !ok { + t.Fatal("expected mongodb driver definition") + } + meta := installedDriverPackage{ + Version: "2.5.0", + AgentRevision: db.OptionalDriverAgentRevision("mongodb"), + } + + needsUpdate, reason, _ := optionalDriverPackageUpdateStatus(definition, meta, true) + if !needsUpdate { + t.Fatal("expected installed MongoDB v2 driver to require reinstall when v1 is the compatibility default") + } + if !strings.Contains(reason, "MongoDB 4.0") || !strings.Contains(reason, "wire version 7") { + t.Fatalf("expected reason to explain MongoDB 4.0 compatibility, got %q", reason) + } +} + func TestOptionalDriverAgentRevisionCurrentRejectsStaleMetadata(t *testing.T) { originalProbe := optionalDriverAgentMetadataProbe t.Cleanup(func() { diff --git a/internal/app/methods_driver_version_test.go b/internal/app/methods_driver_version_test.go index 3ead1f6..af992a4 100644 --- a/internal/app/methods_driver_version_test.go +++ b/internal/app/methods_driver_version_test.go @@ -44,6 +44,20 @@ func TestResolveVersionedDriverOptionUsesPublishedMongoV1Release(t *testing.T) { } } +func TestMongoDBDefaultDriverVersionUsesLegacyCompatibleLine(t *testing.T) { + definition, ok := resolveDriverDefinition("mongodb") + if !ok { + t.Fatal("expected mongodb driver definition") + } + + if definition.PinnedVersion != "1.17.9" { + t.Fatalf("expected MongoDB default driver version 1.17.9, got %q", definition.PinnedVersion) + } + if got := resolveDriverInstallVersion("", definition.DefaultDownloadURL, definition); got != "1.17.9" { + t.Fatalf("expected builtin MongoDB install to resolve version 1.17.9, got %q", got) + } +} + func TestCurrentDriverReleaseTagUsesDevLatestForDevBuild(t *testing.T) { originalVersion := AppVersion AppVersion = "dev-abc1234" @@ -220,6 +234,38 @@ func TestResolveOptionalDriverAgentDownloadURLsDoesNotFallbackForHistoricalVersi } } +func TestResolveOptionalDriverAgentDownloadURLsUsesMongoV1AssetForCompatibleDefault(t *testing.T) { + definition, ok := resolveDriverDefinition("mongodb") + if !ok { + t.Fatal("expected mongodb driver definition") + } + + originalVersion := AppVersion + AppVersion = "0.7.9" + t.Cleanup(func() { + AppVersion = originalVersion + }) + + assetName := mongoVersionedReleaseAssetName(1) + seedReleaseAssetSizeCache(t, "tag:v0.7.9", map[string]int64{ + assetName: 24 << 20, + }) + seedReleaseAssetSizeCache(t, "latest", map[string]int64{}) + + urls := resolveOptionalDriverAgentDownloadURLs( + definition, + "builtin://activate/mongodb", + "1.17.9", + ) + want := driverReleaseDownloadURL("v0.7.9", assetName) + for _, got := range urls { + if got == want { + return + } + } + t.Fatalf("expected MongoDB v1 release asset %q in candidates, got %v", want, urls) +} + func TestResolveOptionalDriverAgentDownloadURLsSkipsBundleOnlyDamengAsset(t *testing.T) { definition, ok := resolveDriverDefinition("dameng") if !ok { @@ -662,8 +708,8 @@ func TestResolveRecentDriverVersionMetasFallsBackToHistoricalTDengineMatrix(t *t } func TestShouldForceSourceBuildForResolvedDownload(t *testing.T) { - if !shouldForceSourceBuildForResolvedDownload("mongodb", "1.17.4", "builtin://activate/mongodb?channel=history&version=1.17.4") { - t.Fatal("expected mongodb v1 builtin install to keep source build mode") + if shouldForceSourceBuildForResolvedDownload("mongodb", "1.17.4", "builtin://activate/mongodb?channel=history&version=1.17.4") { + t.Fatal("expected mongodb v1 builtin install to try published assets before source build") } explicitURL := driverReleaseDownloadURL("v1.17.4", mongoVersionedReleaseAssetName(1))