143 lines
6.0 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 config 验证 room-service 本地 YAML 配置契约。
package config
import (
"testing"
"time"
)
// TestLoad 验证 room-service 的本地 config.yaml 能被正常读取。
func TestLoad(t *testing.T) {
// 读取真实本地配置,确保端口和关键下游地址没有漂移。
cfg, err := Load("../../configs/config.yaml")
if err != nil {
t.Fatalf("Load failed: %v", err)
}
// room-service 业务只走 gRPCHTTP health 仅服务 CLB 探活,端口必须保持 13xxx 约束。
if cfg.GRPCAddr != ":13001" {
t.Fatalf("unexpected grpc addr: %s", cfg.GRPCAddr)
}
if cfg.HealthHTTPAddr != ":13101" {
t.Fatalf("unexpected health http addr: %s", cfg.HealthHTTPAddr)
}
if cfg.AdvertiseAddr != "127.0.0.1:13001" || cfg.NodeRegistryTTL != 30*time.Second || cfg.NodeRegistryHeartbeatInterval != 10*time.Second || cfg.OwnerForwardTimeout != 2*time.Second {
t.Fatalf("unexpected owner routing config: advertise=%s ttl=%s heartbeat=%s timeout=%s", cfg.AdvertiseAddr, cfg.NodeRegistryTTL, cfg.NodeRegistryHeartbeatInterval, cfg.OwnerForwardTimeout)
}
// lease TTL 是故障接管抖动窗口的基础参数。
if cfg.LeaseTTL != 10*time.Second {
t.Fatalf("unexpected lease ttl: %s", cfg.LeaseTTL)
}
// SendGift 主链路依赖 wallet-service默认地址必须与本地编排一致。
if cfg.WalletServiceAddr != "127.0.0.1:13004" {
t.Fatalf("unexpected wallet addr: %s", cfg.WalletServiceAddr)
}
if !cfg.OutboxWorker.Enabled || cfg.OutboxWorker.PublishMode != OutboxPublishModeDirect || cfg.OutboxWorker.PollInterval != time.Second || cfg.OutboxWorker.BatchSize != 100 || cfg.OutboxWorker.PublishTimeout != 3*time.Second || cfg.OutboxWorker.RetryStrategy != "exponential_backoff" || cfg.OutboxWorker.MaxRetryCount != 10 || cfg.OutboxWorker.InitialBackoff != 5*time.Second || cfg.OutboxWorker.MaxBackoff != 5*time.Minute {
t.Fatalf("unexpected outbox worker config: %+v", cfg.OutboxWorker)
}
if cfg.RocketMQ.Enabled || cfg.RocketMQ.RoomOutbox.Enabled || cfg.RocketMQ.RocketLaunch.Enabled {
t.Fatalf("local config must not require RocketMQ: %+v", cfg.RocketMQ)
}
}
// TestLoadTencentExample 验证线上腾讯云 IM 模板能覆盖本地默认配置。
func TestLoadTencentExample(t *testing.T) {
cfg, err := Load("../../configs/config.tencent.example.yaml")
if err != nil {
t.Fatalf("Load tencent example failed: %v", err)
}
if !cfg.TencentIM.Enabled {
t.Fatalf("tencent example should enable Tencent IM bridge")
}
if cfg.TencentIM.SDKAppID == 0 || cfg.TencentIM.SecretKey == "" {
t.Fatalf("sdk_app_id and secret_key templates must be present")
}
if cfg.TencentIM.AdminIdentifier == "" {
t.Fatalf("admin_identifier template must be present")
}
if cfg.TencentIM.Endpoint == "" || cfg.TencentIM.GroupType == "" {
t.Fatalf("endpoint and group_type templates must be present")
}
if cfg.TencentIM.RequestTimeout != 5*time.Second {
t.Fatalf("unexpected request timeout: %s", cfg.TencentIM.RequestTimeout)
}
if cfg.AdvertiseAddr == "" || cfg.AdvertiseAddr == "room-service.internal:13001" {
t.Fatalf("tencent example must use per-instance advertise_addr, got %q", cfg.AdvertiseAddr)
}
if !cfg.OutboxWorker.Enabled || cfg.OutboxWorker.RetryStrategy != "exponential_backoff" || cfg.OutboxWorker.MaxRetryCount != 10 {
t.Fatalf("tencent example must configure outbox worker: %+v", cfg.OutboxWorker)
}
if cfg.OutboxWorker.PublishMode != OutboxPublishModeMQ || !cfg.RocketMQ.RoomOutbox.Enabled || !cfg.RocketMQ.RocketLaunch.Enabled {
t.Fatalf("tencent example must route room outbox and rocket launch through RocketMQ: mode=%s mq=%+v", cfg.OutboxWorker.PublishMode, cfg.RocketMQ)
}
}
func TestLoadDockerConfigStartsRoomIMBridgeWhenOutboxUsesMQ(t *testing.T) {
cfg, err := Load("../../configs/config.docker.yaml")
if err != nil {
t.Fatalf("Load docker config failed: %v", err)
}
if cfg.OutboxWorker.PublishMode != OutboxPublishModeMQ {
t.Fatalf("docker config should publish room outbox through MQ, got %q", cfg.OutboxWorker.PublishMode)
}
if !cfg.RocketMQ.RoomOutbox.Enabled {
t.Fatalf("docker config must enable room outbox MQ")
}
if !cfg.RocketMQ.RoomOutbox.TencentIMConsumerEnabled {
t.Fatalf("docker mq room outbox must start Tencent IM bridge consumer")
}
if !cfg.TencentIM.Enabled {
t.Fatalf("Tencent IM bridge consumer requires tencent_im.enabled")
}
}
func TestNormalizeRejectsUnknownOutboxRetryStrategy(t *testing.T) {
cfg := Default()
cfg.OutboxWorker.RetryStrategy = "exponential"
if _, err := Normalize(cfg); err == nil {
t.Fatal("Normalize should reject unsupported outbox retry_strategy")
}
}
func TestNormalizeRejectsUnknownOutboxPublishMode(t *testing.T) {
cfg := Default()
cfg.OutboxWorker.PublishMode = "random"
if _, err := Normalize(cfg); err == nil {
t.Fatal("Normalize should reject unsupported outbox publish_mode")
}
}
func TestNormalizeRejectsMQPublishModeWithoutRoomOutboxMQ(t *testing.T) {
cfg := Default()
cfg.OutboxWorker.PublishMode = OutboxPublishModeMQ
if _, err := Normalize(cfg); err == nil {
t.Fatal("Normalize should reject mq publish_mode without rocketmq.room_outbox.enabled")
}
}
func TestNormalizeOutboxWorkerKeepsSafeDefaults(t *testing.T) {
cfg := Default()
cfg.OutboxWorker.PollInterval = 0
cfg.OutboxWorker.BatchSize = 0
cfg.OutboxWorker.PublishTimeout = 0
cfg.OutboxWorker.RetryStrategy = ""
cfg.OutboxWorker.MaxRetryCount = 0
cfg.OutboxWorker.InitialBackoff = 0
cfg.OutboxWorker.MaxBackoff = 0
normalized, err := Normalize(cfg)
if err != nil {
t.Fatalf("Normalize failed: %v", err)
}
if normalized.OutboxWorker.PublishMode != OutboxPublishModeDirect || normalized.OutboxWorker.PollInterval != time.Second || normalized.OutboxWorker.BatchSize != 100 || normalized.OutboxWorker.PublishTimeout != 3*time.Second || normalized.OutboxWorker.RetryStrategy != "exponential_backoff" || normalized.OutboxWorker.MaxRetryCount != 10 || normalized.OutboxWorker.InitialBackoff != 5*time.Second || normalized.OutboxWorker.MaxBackoff != 5*time.Minute {
t.Fatalf("outbox worker defaults not restored: %+v", normalized.OutboxWorker)
}
}