package integration import ( "bytes" "context" "encoding/json" "fmt" "net/http/httptest" "testing" "time" "github.com/break/junhong_cmp_fiber/internal/bootstrap" internalMiddleware "github.com/break/junhong_cmp_fiber/internal/middleware" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/routes" "github.com/break/junhong_cmp_fiber/pkg/auth" "github.com/break/junhong_cmp_fiber/pkg/config" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/queue" "github.com/break/junhong_cmp_fiber/pkg/response" "github.com/break/junhong_cmp_fiber/tests/testutil" "github.com/gofiber/fiber/v2" "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" ) type carrierTestEnv struct { db *gorm.DB rdb *redis.Client tokenManager *auth.TokenManager app *fiber.App adminToken string t *testing.T } func setupCarrierTestEnv(t *testing.T) *carrierTestEnv { t.Helper() t.Setenv("JUNHONG_DATABASE_HOST", "cxd.whcxd.cn") t.Setenv("JUNHONG_DATABASE_PORT", "16159") t.Setenv("JUNHONG_DATABASE_USER", "erp_pgsql") t.Setenv("JUNHONG_DATABASE_PASSWORD", "erp_2025") t.Setenv("JUNHONG_DATABASE_DBNAME", "junhong_cmp_test") t.Setenv("JUNHONG_REDIS_ADDRESS", "cxd.whcxd.cn") t.Setenv("JUNHONG_REDIS_PORT", "16299") t.Setenv("JUNHONG_REDIS_PASSWORD", "cpNbWtAaqgo1YJmbMp3h") t.Setenv("JUNHONG_JWT_SECRET_KEY", "test_secret_key_for_integration_tests") cfg, err := config.Load() require.NoError(t, err) err = config.Set(cfg) require.NoError(t, err) zapLogger, _ := zap.NewDevelopment() dsn := "host=cxd.whcxd.cn port=16159 user=erp_pgsql password=erp_2025 dbname=junhong_cmp_test sslmode=disable TimeZone=Asia/Shanghai" db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{ Logger: logger.Default.LogMode(logger.Silent), }) require.NoError(t, err) rdb := redis.NewClient(&redis.Options{ Addr: "cxd.whcxd.cn:16299", Password: "cpNbWtAaqgo1YJmbMp3h", DB: 15, }) ctx := context.Background() err = rdb.Ping(ctx).Err() require.NoError(t, err) testPrefix := fmt.Sprintf("test:%s:", t.Name()) keys, _ := rdb.Keys(ctx, testPrefix+"*").Result() if len(keys) > 0 { rdb.Del(ctx, keys...) } tokenManager := auth.NewTokenManager(rdb, 24*time.Hour, 7*24*time.Hour) superAdmin := testutil.CreateSuperAdmin(t, db) adminToken, _ := testutil.GenerateTestToken(t, rdb, superAdmin, "web") queueClient := queue.NewClient(rdb, zapLogger) deps := &bootstrap.Dependencies{ DB: db, Redis: rdb, Logger: zapLogger, TokenManager: tokenManager, QueueClient: queueClient, } result, err := bootstrap.Bootstrap(deps) require.NoError(t, err) app := fiber.New(fiber.Config{ ErrorHandler: internalMiddleware.ErrorHandler(zapLogger), }) routes.RegisterRoutes(app, result.Handlers, result.Middlewares) return &carrierTestEnv{ db: db, rdb: rdb, tokenManager: tokenManager, app: app, adminToken: adminToken, t: t, } } func (e *carrierTestEnv) teardown() { e.db.Exec("DELETE FROM tb_carrier WHERE carrier_code LIKE 'TEST%'") ctx := context.Background() testPrefix := fmt.Sprintf("test:%s:", e.t.Name()) keys, _ := e.rdb.Keys(ctx, testPrefix+"*").Result() if len(keys) > 0 { e.rdb.Del(ctx, keys...) } e.rdb.Close() } func TestCarrier_CRUD(t *testing.T) { env := setupCarrierTestEnv(t) defer env.teardown() var createdCarrierID uint t.Run("创建运营商", func(t *testing.T) { body := map[string]interface{}{ "carrier_code": "TEST_CMCC_001", "carrier_name": "测试中国移动", "carrier_type": constants.CarrierTypeCMCC, "description": "API集成测试创建的运营商", } jsonBody, _ := json.Marshal(body) req := httptest.NewRequest("POST", "/api/admin/carriers", bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+env.adminToken) resp, err := env.app.Test(req, -1) require.NoError(t, err) defer resp.Body.Close() assert.Equal(t, 200, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) dataMap, ok := result.Data.(map[string]interface{}) require.True(t, ok) assert.Equal(t, "TEST_CMCC_001", dataMap["carrier_code"]) assert.Equal(t, "测试中国移动", dataMap["carrier_name"]) assert.Equal(t, constants.CarrierTypeCMCC, dataMap["carrier_type"]) assert.Equal(t, float64(constants.StatusEnabled), dataMap["status"]) createdCarrierID = uint(dataMap["id"].(float64)) t.Logf("创建的运营商 ID: %d", createdCarrierID) }) t.Run("创建运营商-编码重复应失败", func(t *testing.T) { body := map[string]interface{}{ "carrier_code": "TEST_CMCC_001", "carrier_name": "重复编码测试", "carrier_type": constants.CarrierTypeCMCC, } jsonBody, _ := json.Marshal(body) req := httptest.NewRequest("POST", "/api/admin/carriers", bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+env.adminToken) resp, err := env.app.Test(req, -1) require.NoError(t, err) defer resp.Body.Close() var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.NotEqual(t, 0, result.Code, "编码重复应返回错误") }) t.Run("获取运营商详情", func(t *testing.T) { url := fmt.Sprintf("/api/admin/carriers/%d", createdCarrierID) req := httptest.NewRequest("GET", url, nil) req.Header.Set("Authorization", "Bearer "+env.adminToken) resp, err := env.app.Test(req, -1) require.NoError(t, err) defer resp.Body.Close() assert.Equal(t, 200, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) dataMap := result.Data.(map[string]interface{}) assert.Equal(t, "TEST_CMCC_001", dataMap["carrier_code"]) }) t.Run("获取不存在的运营商", func(t *testing.T) { req := httptest.NewRequest("GET", "/api/admin/carriers/99999", nil) req.Header.Set("Authorization", "Bearer "+env.adminToken) resp, err := env.app.Test(req, -1) require.NoError(t, err) defer resp.Body.Close() var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.NotEqual(t, 0, result.Code, "不存在的运营商应返回错误") }) t.Run("更新运营商", func(t *testing.T) { body := map[string]interface{}{ "carrier_name": "测试中国移动-更新", "description": "更新后的描述", } jsonBody, _ := json.Marshal(body) url := fmt.Sprintf("/api/admin/carriers/%d", createdCarrierID) req := httptest.NewRequest("PUT", url, bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+env.adminToken) resp, err := env.app.Test(req, -1) require.NoError(t, err) defer resp.Body.Close() assert.Equal(t, 200, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) dataMap := result.Data.(map[string]interface{}) assert.Equal(t, "测试中国移动-更新", dataMap["carrier_name"]) assert.Equal(t, "更新后的描述", dataMap["description"]) }) t.Run("更新运营商状态-禁用", func(t *testing.T) { body := map[string]interface{}{ "status": constants.StatusDisabled, } jsonBody, _ := json.Marshal(body) url := fmt.Sprintf("/api/admin/carriers/%d/status", createdCarrierID) req := httptest.NewRequest("PUT", url, bytes.NewReader(jsonBody)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+env.adminToken) resp, err := env.app.Test(req, -1) require.NoError(t, err) defer resp.Body.Close() assert.Equal(t, 200, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) var carrier model.Carrier env.db.First(&carrier, createdCarrierID) assert.Equal(t, constants.StatusDisabled, carrier.Status) }) t.Run("删除运营商", func(t *testing.T) { url := fmt.Sprintf("/api/admin/carriers/%d", createdCarrierID) req := httptest.NewRequest("DELETE", url, nil) req.Header.Set("Authorization", "Bearer "+env.adminToken) resp, err := env.app.Test(req, -1) require.NoError(t, err) defer resp.Body.Close() assert.Equal(t, 200, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) var carrier model.Carrier err = env.db.First(&carrier, createdCarrierID).Error assert.Error(t, err, "删除后应查不到运营商") }) } func TestCarrier_List(t *testing.T) { env := setupCarrierTestEnv(t) defer env.teardown() carriers := []*model.Carrier{ {CarrierCode: "TEST_LIST_001", CarrierName: "移动列表测试1", CarrierType: constants.CarrierTypeCMCC, Status: constants.StatusEnabled}, {CarrierCode: "TEST_LIST_002", CarrierName: "联通列表测试", CarrierType: constants.CarrierTypeCUCC, Status: constants.StatusEnabled}, {CarrierCode: "TEST_LIST_003", CarrierName: "电信列表测试", CarrierType: constants.CarrierTypeCTCC, Status: constants.StatusEnabled}, } for _, c := range carriers { require.NoError(t, env.db.Create(c).Error) } carriers[2].Status = constants.StatusDisabled require.NoError(t, env.db.Save(carriers[2]).Error) t.Run("获取运营商列表-无过滤", func(t *testing.T) { req := httptest.NewRequest("GET", "/api/admin/carriers?page=1&page_size=20", nil) req.Header.Set("Authorization", "Bearer "+env.adminToken) resp, err := env.app.Test(req, -1) require.NoError(t, err) defer resp.Body.Close() assert.Equal(t, 200, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) }) t.Run("获取运营商列表-按类型过滤", func(t *testing.T) { req := httptest.NewRequest("GET", "/api/admin/carriers?carrier_type=CMCC", nil) req.Header.Set("Authorization", "Bearer "+env.adminToken) resp, err := env.app.Test(req, -1) require.NoError(t, err) defer resp.Body.Close() assert.Equal(t, 200, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) }) t.Run("获取运营商列表-按名称模糊搜索", func(t *testing.T) { req := httptest.NewRequest("GET", "/api/admin/carriers?carrier_name=联通", nil) req.Header.Set("Authorization", "Bearer "+env.adminToken) resp, err := env.app.Test(req, -1) require.NoError(t, err) defer resp.Body.Close() assert.Equal(t, 200, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) }) t.Run("获取运营商列表-按状态过滤", func(t *testing.T) { req := httptest.NewRequest("GET", fmt.Sprintf("/api/admin/carriers?status=%d", constants.StatusDisabled), nil) req.Header.Set("Authorization", "Bearer "+env.adminToken) resp, err := env.app.Test(req, -1) require.NoError(t, err) defer resp.Body.Close() assert.Equal(t, 200, resp.StatusCode) var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.Equal(t, 0, result.Code) }) t.Run("未认证请求应返回错误", func(t *testing.T) { req := httptest.NewRequest("GET", "/api/admin/carriers", nil) resp, err := env.app.Test(req, -1) require.NoError(t, err) defer resp.Body.Close() var result response.Response err = json.NewDecoder(resp.Body).Decode(&result) require.NoError(t, err) assert.NotEqual(t, 0, result.Code, "未认证请求应返回错误码") }) }