Files
MyGoNavi/internal/jvm/connection_error_message_test.go
2026-06-22 15:12:42 +08:00

322 lines
16 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 jvm
import (
"errors"
"os"
"strings"
"testing"
"GoNavi-Wails/internal/connection"
"GoNavi-Wails/shared/i18n"
)
func TestConnectionErrorMessageSourceUsesLocalizedTextForGenericWrapperAndEndpoint(t *testing.T) {
sourceBytes, err := os.ReadFile("connection_error_message.go")
if err != nil {
t.Fatalf("read connection_error_message.go: %v", err)
}
source := string(sourceBytes)
for _, rawText := range []string{
`return "JVM 连接失败"`,
`return "Endpoint 连接失败:未填写 Endpoint Base URL。"`,
`"Endpoint 连接失败Endpoint Base URL 格式不合法。"`,
`"请填写完整的 ` + "`http://` 或 `https://` 地址,并指向实现 GoNavi JVM HTTP 合约的管理接口根路径,例如 `http://127.0.0.1:19090/manage/jvm`。" + ``,
`"Endpoint 连接失败:当前只支持 HTTP 或 HTTPS 协议。"`,
`"请把 Endpoint Base URL 改成 ` + "`http://` 或 `https://` 开头的地址。" + ``,
`"Endpoint 连接失败:目标地址已响应,但没有找到 GoNavi JVM 管理接口。"`,
`"请确认 Base URL 指向的是 JVM 管理接口根路径,而不是普通业务接口、健康检查地址或网关首页。"`,
`"Endpoint 连接失败:目标管理接口未监听,或当前地址不可达。"`,
`"请确认 Base URL 指向实现 GoNavi JVM HTTP 合约的管理接口,并检查服务监听、端口映射和防火墙。"`,
`"Endpoint 连接失败:目标管理接口已响应,但当前 API Key 无效或缺失。"`,
`"请检查连接中的 Endpoint API Key 是否与目标服务配置一致。"`,
`"Endpoint 连接失败:当前请求被目标管理接口拒绝。"`,
`"请确认当前客户端来源、鉴权配置和访问策略允许 GoNavi 访问该管理接口。"`,
`"Endpoint 连接失败:访问目标管理接口超时。"`,
`"请确认 Base URL 可达、目标服务已完成启动,并适当增加连接超时时间。"`,
`"建议:"+trimmed`,
`"技术细节:"+trimmed`,
} {
if strings.Contains(source, rawText) {
t.Fatalf("connection_error_message.go still contains raw localized endpoint text %q", rawText)
}
}
for _, key := range []string{
"jvm.backend.connection_error.generic",
"jvm.backend.connection_error.suggestion",
"jvm.backend.connection_error.technical_detail",
"jvm.backend.connection_error.endpoint.base_url_required",
"jvm.backend.connection_error.endpoint.base_url_invalid.summary",
"jvm.backend.connection_error.endpoint.base_url_invalid.help",
"jvm.backend.connection_error.endpoint.scheme_unsupported.summary",
"jvm.backend.connection_error.endpoint.scheme_unsupported.help",
"jvm.backend.connection_error.endpoint.not_found.summary",
"jvm.backend.connection_error.endpoint.not_found.help",
"jvm.backend.connection_error.endpoint.connection_refused.summary",
"jvm.backend.connection_error.endpoint.connection_refused.help",
"jvm.backend.connection_error.endpoint.unauthorized.summary",
"jvm.backend.connection_error.endpoint.unauthorized.help",
"jvm.backend.connection_error.endpoint.forbidden.summary",
"jvm.backend.connection_error.endpoint.forbidden.help",
"jvm.backend.connection_error.endpoint.timeout.summary",
"jvm.backend.connection_error.endpoint.timeout.help",
} {
if !strings.Contains(source, key) {
t.Fatalf("connection_error_message.go does not reference i18n key %q", key)
}
}
}
func TestConnectionErrorMessageSourceUsesLocalizedTextForAgent(t *testing.T) {
sourceBytes, err := os.ReadFile("connection_error_message.go")
if err != nil {
t.Fatalf("read connection_error_message.go: %v", err)
}
source := string(sourceBytes)
for _, rawText := range []string{
`return "Agent 连接失败:未填写 Agent Base URL。"`,
`"Agent 连接失败Agent Base URL 格式不合法。"`,
`"请填写完整的 ` + "`http://` 或 `https://` 地址,例如 `http://127.0.0.1:19090/gonavi/agent/jvm`。" + ``,
`"Agent 连接失败:当前只支持 HTTP 或 HTTPS 协议。"`,
`"请把 Agent Base URL 改成 ` + "`http://` 或 `https://` 开头的地址。" + ``,
`"Agent 连接失败:目标 Agent 管理端口未监听,或当前地址不可达。"`,
`"请确认 Java 服务已通过 ` + "`-javaagent`" + ` 启动 GoNavi Agent并检查 Base URL、端口映射和防火墙。"`,
`"Agent 连接失败Agent 已响应,但当前 API Key 无效或缺失。"`,
`"请检查连接中的 Agent API Key 是否与目标服务启动参数一致。"`,
`"Agent 连接失败:当前请求被 Agent 拒绝。"`,
`"请确认当前客户端来源、鉴权配置和 Agent 访问策略允许 GoNavi 访问。"`,
`"Agent 连接失败:访问 Agent 管理端口超时。"`,
`"请确认目标地址可达、Agent 已完成启动,并适当增加连接超时时间。"`,
} {
if strings.Contains(source, rawText) {
t.Fatalf("connection_error_message.go still contains raw localized agent text %q", rawText)
}
}
for _, key := range []string{
"jvm.backend.connection_error.agent.base_url_required",
"jvm.backend.connection_error.agent.base_url_invalid.summary",
"jvm.backend.connection_error.agent.base_url_invalid.help",
"jvm.backend.connection_error.agent.scheme_unsupported.summary",
"jvm.backend.connection_error.agent.scheme_unsupported.help",
"jvm.backend.connection_error.agent.connection_refused.summary",
"jvm.backend.connection_error.agent.connection_refused.help",
"jvm.backend.connection_error.agent.unauthorized.summary",
"jvm.backend.connection_error.agent.unauthorized.help",
"jvm.backend.connection_error.agent.forbidden.summary",
"jvm.backend.connection_error.agent.forbidden.help",
"jvm.backend.connection_error.agent.timeout.summary",
"jvm.backend.connection_error.agent.timeout.help",
} {
if !strings.Contains(source, key) {
t.Fatalf("connection_error_message.go does not reference i18n key %q", key)
}
}
}
func TestConnectionErrorMessageSourceUsesLocalizedTextForJMX(t *testing.T) {
sourceBytes, err := os.ReadFile("connection_error_message.go")
if err != nil {
t.Fatalf("read connection_error_message.go: %v", err)
}
source := string(sourceBytes)
for _, rawText := range []string{
`return "JMX 连接失败:未填写主机地址。"`,
`return "JMX 连接失败:端口无效,请填写 1-65535 之间的有效端口。"`,
`"JMX 连接失败:当前机器未找到 ` + "`java`" + ` 运行时GoNavi 无法启动 JMX helper。"`,
`"请先安装 JRE/JDK或通过环境变量 ` + "`GONAVI_JMX_JAVA_BIN`" + ` 指向正确的 ` + "`java`" + ` 可执行文件。"`,
`fmt.Sprintf("JMX 连接失败:%s 不是标准 JMX 远程管理端口,当前更像普通业务端口或 HTTP 端口。", target)`,
`"请改填应用实际暴露的 JMX 端口,而不是业务 ` + "`server.port`" + `。如果服务只开启了 ` + "`-Dcom.sun.management.jmxremote`" + `,但没有配置 ` + "`jmxremote.port`" + `,也无法直接远程连接。"`,
`fmt.Sprintf("JMX 连接失败:%s 上虽然有 RMI 服务,但不是可用的 JMX RMIServer 端口。", target)`,
`"这通常意味着填到了 RMI 注册端口、调试端口或其他 Java 服务端口。请检查 ` + "`jmxremote.port`" + `` + "`jmxremote.rmi.port`" + ` 配置是否正确。"`,
`fmt.Sprintf("JMX 连接失败:%s 上的服务主动断开了连接,当前端口不是兼容的标准 JMX RMI 端口。", target)`,
`"请确认填写的是 JVM 真正对外暴露的 JMX 端口,而不是业务端口、调试端口或被代理转发的端口。"`,
`fmt.Sprintf("JMX 连接失败:无法连接到 %s对应端口没有监听或当前网络不可达。", target)`,
`"请确认目标 JVM 已开启远程 JMX并检查主机、防火墙、端口映射和 SSH/代理配置。"`,
`fmt.Sprintf("JMX 连接失败:%s 需要认证,或当前凭据不可用。", target)`,
`"请确认目标 JMX 是否关闭认证;如果必须认证,需要补充用户名/密码后再连接。"`,
`fmt.Sprintf("JMX 连接失败:连接 %s 超时。", target)`,
`"请确认端口可达、网络未被拦截,并适当增加连接超时时间。"`,
} {
if strings.Contains(source, rawText) {
t.Fatalf("connection_error_message.go still contains raw localized JMX text %q", rawText)
}
}
for _, key := range []string{
"jvm.backend.connection_error.jmx.host_required",
"jvm.backend.connection_error.jmx.port_invalid",
"jvm.backend.connection_error.jmx.java_missing.summary",
"jvm.backend.connection_error.jmx.java_missing.help",
"jvm.backend.connection_error.jmx.non_jrmp.summary",
"jvm.backend.connection_error.jmx.non_jrmp.help",
"jvm.backend.connection_error.jmx.no_such_object.summary",
"jvm.backend.connection_error.jmx.no_such_object.help",
"jvm.backend.connection_error.jmx.connection_reset.summary",
"jvm.backend.connection_error.jmx.connection_reset.help",
"jvm.backend.connection_error.jmx.connection_refused.summary",
"jvm.backend.connection_error.jmx.connection_refused.help",
"jvm.backend.connection_error.jmx.auth.summary",
"jvm.backend.connection_error.jmx.auth.help",
"jvm.backend.connection_error.jmx.timeout.summary",
"jvm.backend.connection_error.jmx.timeout.help",
} {
if !strings.Contains(source, key) {
t.Fatalf("connection_error_message.go does not reference i18n key %q", key)
}
}
}
func TestConnectionErrorMessageCatalogKeysExist(t *testing.T) {
catalogs, err := i18n.LoadCatalogs()
if err != nil {
t.Fatalf("LoadCatalogs() error = %v", err)
}
keys := []string{
"jvm.backend.connection_error.generic",
"jvm.backend.connection_error.suggestion",
"jvm.backend.connection_error.technical_detail",
"jvm.backend.connection_error.endpoint.base_url_required",
"jvm.backend.connection_error.endpoint.base_url_invalid.summary",
"jvm.backend.connection_error.endpoint.base_url_invalid.help",
"jvm.backend.connection_error.endpoint.scheme_unsupported.summary",
"jvm.backend.connection_error.endpoint.scheme_unsupported.help",
"jvm.backend.connection_error.endpoint.not_found.summary",
"jvm.backend.connection_error.endpoint.not_found.help",
"jvm.backend.connection_error.endpoint.connection_refused.summary",
"jvm.backend.connection_error.endpoint.connection_refused.help",
"jvm.backend.connection_error.endpoint.unauthorized.summary",
"jvm.backend.connection_error.endpoint.unauthorized.help",
"jvm.backend.connection_error.endpoint.forbidden.summary",
"jvm.backend.connection_error.endpoint.forbidden.help",
"jvm.backend.connection_error.endpoint.timeout.summary",
"jvm.backend.connection_error.endpoint.timeout.help",
"jvm.backend.connection_error.agent.base_url_required",
"jvm.backend.connection_error.agent.base_url_invalid.summary",
"jvm.backend.connection_error.agent.base_url_invalid.help",
"jvm.backend.connection_error.agent.scheme_unsupported.summary",
"jvm.backend.connection_error.agent.scheme_unsupported.help",
"jvm.backend.connection_error.agent.connection_refused.summary",
"jvm.backend.connection_error.agent.connection_refused.help",
"jvm.backend.connection_error.agent.unauthorized.summary",
"jvm.backend.connection_error.agent.unauthorized.help",
"jvm.backend.connection_error.agent.forbidden.summary",
"jvm.backend.connection_error.agent.forbidden.help",
"jvm.backend.connection_error.agent.timeout.summary",
"jvm.backend.connection_error.agent.timeout.help",
"jvm.backend.connection_error.jmx.host_required",
"jvm.backend.connection_error.jmx.port_invalid",
"jvm.backend.connection_error.jmx.java_missing.summary",
"jvm.backend.connection_error.jmx.java_missing.help",
"jvm.backend.connection_error.jmx.non_jrmp.summary",
"jvm.backend.connection_error.jmx.non_jrmp.help",
"jvm.backend.connection_error.jmx.no_such_object.summary",
"jvm.backend.connection_error.jmx.no_such_object.help",
"jvm.backend.connection_error.jmx.connection_reset.summary",
"jvm.backend.connection_error.jmx.connection_reset.help",
"jvm.backend.connection_error.jmx.connection_refused.summary",
"jvm.backend.connection_error.jmx.connection_refused.help",
"jvm.backend.connection_error.jmx.auth.summary",
"jvm.backend.connection_error.jmx.auth.help",
"jvm.backend.connection_error.jmx.timeout.summary",
"jvm.backend.connection_error.jmx.timeout.help",
}
for _, language := range i18n.SupportedLanguages() {
catalog := catalogs[language]
for _, key := range keys {
if strings.TrimSpace(catalog[key]) == "" {
t.Fatalf("%s catalog missing jvm connection error key %q", language, key)
}
}
}
}
func TestDescribeConnectionTestErrorLocalizesAgentMessagesInEnglish(t *testing.T) {
SetBackendLanguage(i18n.LanguageEnUS)
t.Cleanup(func() {
SetBackendLanguage(i18n.LanguageZhCN)
})
cfg := connection.ConnectionConfig{
Type: "jvm",
JVM: connection.JVMConfig{
PreferredMode: ModeAgent,
AllowedModes: []string{ModeAgent},
},
}
raw := `agent baseurl is invalid: parse ":bad-url": missing protocol scheme`
got := DescribeConnectionTestError(cfg, errors.New(raw))
want := strings.Join([]string{
"Agent connection failed: Agent Base URL is invalid.",
"Suggestion: Enter a full http:// or https:// URL, for example http://127.0.0.1:19090/gonavi/agent/jvm.",
`Technical detail: agent baseurl is invalid: parse ":bad-url": missing protocol scheme`,
}, "\n")
if got != want {
t.Fatalf("expected English agent message %q, got %q", want, got)
}
}
func TestDescribeConnectionTestErrorLocalizesGenericAndEndpointMessagesInEnglish(t *testing.T) {
SetBackendLanguage(i18n.LanguageEnUS)
t.Cleanup(func() {
SetBackendLanguage(i18n.LanguageZhCN)
})
cfg := connection.ConnectionConfig{
Type: "jvm",
JVM: connection.JVMConfig{
PreferredMode: ModeEndpoint,
AllowedModes: []string{ModeEndpoint},
},
}
if got := DescribeConnectionTestError(cfg, errors.New(" ")); got != "JVM connection failed" {
t.Fatalf("expected English generic message, got %q", got)
}
raw := `endpoint baseurl is invalid: parse ":bad-url": missing protocol scheme`
got := DescribeConnectionTestError(cfg, errors.New(raw))
want := strings.Join([]string{
"Endpoint connection failed: Endpoint Base URL is invalid.",
"Suggestion: Enter a full http:// or https:// URL that points to the management API root implementing the GoNavi JVM HTTP contract, for example http://127.0.0.1:19090/manage/jvm.",
`Technical detail: endpoint baseurl is invalid: parse ":bad-url": missing protocol scheme`,
}, "\n")
if got != want {
t.Fatalf("expected English endpoint message %q, got %q", want, got)
}
}
func TestDescribeConnectionTestErrorLocalizesJMXMessagesInEnglish(t *testing.T) {
SetBackendLanguage(i18n.LanguageEnUS)
t.Cleanup(func() {
SetBackendLanguage(i18n.LanguageZhCN)
})
cfg := connection.ConnectionConfig{
Type: "jvm",
Host: "localhost",
Port: 18080,
JVM: connection.JVMConfig{
PreferredMode: ModeJMX,
AllowedModes: []string{ModeJMX},
},
}
raw := `jmx helper ping failed for localhost:18080: JMX command ping failed for localhost:18080: Failed to retrieve RMIServer stub: javax.naming.CommunicationException [Root exception is java.rmi.ConnectIOException: non-JRMP server at remote endpoint]; details={"exception":"java.lang.IllegalStateException"}`
got := DescribeConnectionTestError(cfg, errors.New(raw))
want := strings.Join([]string{
"JMX connection failed: localhost:18080 is not a standard JMX remote management port; it looks like a business or HTTP port.",
"Suggestion: Use the actual JMX port exposed by the application, not the business `server.port`. If the service only enables `-Dcom.sun.management.jmxremote` without `jmxremote.port`, it cannot be connected remotely.",
`Technical detail: jmx helper ping failed for localhost:18080: JMX command ping failed for localhost:18080: Failed to retrieve RMIServer stub: javax.naming.CommunicationException [Root exception is java.rmi.ConnectIOException: non-JRMP server at remote endpoint]; details={"exception":"java.lang.IllegalStateException"}`,
}, "\n")
if got != want {
t.Fatalf("expected English JMX message %q, got %q", want, got)
}
}