mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-14 00:42:17 +08:00
322 lines
16 KiB
Go
322 lines
16 KiB
Go
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)
|
||
}
|
||
}
|