topfans/backend/gateway/config/port_test.go
zerosaturation a337f43f86 fix(config): port alignment + service test doubles (batch 4.1/4.5)
- gateway/config Dubbo URL 默认端口修正(原 20004/20005 与服务实际 20001/20004 不符);
- userService main.go 硬编码 WithPort(20000) 修死码, -port flag / PORT env 真正生效;
- .env.example 11 个 DUBBO URL 同步(对齐 serviceDefaultPorts map + 实际服务 bind);
- 删除 DUBBO_STARBOOK_SERVICE_URL 死引用(starbookService 已在 batch 4.2 删除);
- .env.example Service Ports 注释块补全 10 行, 与网关 Dubbo URL + port_test 三方一致;
- 10 个 service 各加 port_test.go, 断言 flag 默认与 serviceDefaultPorts map 一致;
- 11 个 port_test 总计 13 测试覆盖(网关 + 10 service);
- .gitignore 加 userService/main.go.bak 排除(临时备份)。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-24 14:02:14 +08:00

107 lines
3.8 KiB
Go

package config
import (
"regexp"
"strconv"
"testing"
)
// serviceDefaultPorts 各服务 main.go 顶部 flag.Int("port", ...) 默认端口
//
// 单一事实源:必须与 backend/services/<svc>/main.go 中
//
// flag.Int("port", getEnvInt("PORT", <这里>), "Dubbo service port")
//
// 的硬编码回退值一致。漂移会让网关 Dubbo URL 默认指向错误端口(本目录 DubboConfig)。
//
// ★ 批次 4.2:starbookService 已删除,故此处不含。
var serviceDefaultPorts = map[string]int{
"user": 20000,
"social": 20002,
"asset": 20003,
"gallery": 20001,
"activity": 20004,
"task": 20006,
"aiChat": 20008,
"statistic": 20009,
"notification": 20010,
"moderation": 20011,
}
// TestGateway_DefaultDubboURL_MatchesServiceBinds 校验 Load() 返回的 Dubbo URL
// 默认端口 == 各服务 main.go 的默认绑定端口。
//
// 该测试是 4.1 端口对齐的回归保险:任一服务修改了 main.go 的 flag 默认值但忘了
// 同步 gateway/config 默认(或反之),会立即失败。
func TestGateway_DefaultDubboURL_MatchesServiceBinds(t *testing.T) {
cfg := Load()
cases := map[string]string{
"user": cfg.Dubbo.UserServiceURL,
"social": cfg.Dubbo.SocialServiceURL,
"asset": cfg.Dubbo.AssetServiceURL,
"gallery": cfg.Dubbo.GalleryServiceURL,
"activity": cfg.Dubbo.ActivityServiceURL,
"task": cfg.Dubbo.TaskServiceURL,
"aiChat": cfg.Dubbo.AIChatServiceURL,
"statistic": cfg.Dubbo.StatisticServiceURL,
"notification": cfg.Dubbo.NotificationServiceURL,
"moderation": cfg.Dubbo.ModerationServiceURL,
}
re := regexp.MustCompile(`:(\d+)$`)
for name, url := range cases {
m := re.FindStringSubmatch(url)
if len(m) != 2 {
t.Fatalf("%s: URL %q 缺端口", name, url)
}
got, _ := strconv.Atoi(m[1])
want, ok := serviceDefaultPorts[name]
if !ok {
t.Fatalf("%s: 在 serviceDefaultPorts 中未声明默认端口", name)
}
if got != want {
t.Errorf("%s: 网关默认 Dubbo URL 端口=%d, 服务实际默认绑定=%d", name, got, want)
}
}
}
// TestServiceDefaultPorts_AllListed 防止后续新增服务但忘记在本表声明默认端口,
// 进而让 TestGateway_DefaultDubboURL_MatchesServiceBinds 漏掉校验。
func TestServiceDefaultPorts_AllListed(t *testing.T) {
// 与 DubboConfig 字段对齐的 10 个常驻服务(批次 4.2 starbookService 已删除)
want := []string{
"user", "social", "asset", "gallery", "activity",
"task", "aiChat", "statistic", "notification", "moderation",
}
if got := len(serviceDefaultPorts); got != len(want) {
t.Errorf("serviceDefaultPorts 数量=%d, 期望=%d (新增/删除服务需同步此表)", got, len(want))
}
for _, name := range want {
if _, ok := serviceDefaultPorts[name]; !ok {
t.Errorf("service %q 缺失默认端口声明", name)
}
}
}
// TestDubboConfig_AllURLsHavePort 防 Load() 后 DubboConfig 任一 URL 解析失败(空串/格式错)。
func TestDubboConfig_AllURLsHavePort(t *testing.T) {
cfg := Load()
urls := map[string]string{
"UserServiceURL": cfg.Dubbo.UserServiceURL,
"SocialServiceURL": cfg.Dubbo.SocialServiceURL,
"AssetServiceURL": cfg.Dubbo.AssetServiceURL,
"GalleryServiceURL": cfg.Dubbo.GalleryServiceURL,
"ActivityServiceURL": cfg.Dubbo.ActivityServiceURL,
"TaskServiceURL": cfg.Dubbo.TaskServiceURL,
"AIChatServiceURL": cfg.Dubbo.AIChatServiceURL,
"StatisticServiceURL": cfg.Dubbo.StatisticServiceURL,
"NotificationServiceURL": cfg.Dubbo.NotificationServiceURL,
"ModerationServiceURL": cfg.Dubbo.ModerationServiceURL,
}
re := regexp.MustCompile(`tri://[^:]+:(\d+)$`)
for name, url := range urls {
if !re.MatchString(url) {
t.Errorf("%s=%q 不符合 tri://host:port 格式", name, url)
}
}
}