103 lines
3.5 KiB
Go
103 lines
3.5 KiB
Go
package controller
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"ezops/config"
|
|
"ezops/model"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/glebarez/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// TestCurrencyExpression 验证 CNY 与 USD 报告币种使用同一组可逆汇率。 // Logan.Li
|
|
func TestCurrencyExpression(t *testing.T) {
|
|
handler := NewBillingHandler(nil, &config.BillingConfig{
|
|
BaseCurrency: "CNY",
|
|
ExchangeRates: map[string]float64{"cny": 1, "usd": 7.2},
|
|
})
|
|
_, cnyArgs, ok := handler.currencyExpression("CNY")
|
|
if !ok || len(cnyArgs) != 2 {
|
|
t.Fatalf("CNY 汇率表达式无效: ok=%v args=%v", ok, cnyArgs)
|
|
}
|
|
metadata := handler.reportCurrencyMetadata("USD")
|
|
rates := metadata["exchange_rates"].(map[string]float64)
|
|
if rates["USD"] != 1 || rates["CNY"] != 0.138889 {
|
|
t.Fatalf("USD 折算汇率错误: %+v", rates)
|
|
}
|
|
if _, _, supported := handler.currencyExpression("EUR"); supported {
|
|
t.Fatal("未配置币种不应被接受")
|
|
}
|
|
}
|
|
|
|
// TestBillingCurrencyConversionAPI 验证统计接口不会直接混加不同原币金额。 // Logan.Li
|
|
func TestBillingCurrencyConversionAPI(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := db.AutoMigrate(&model.CloudBilling{}, &model.BillingAlertRule{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
today := time.Now().Format("2006-01-02")
|
|
records := []model.CloudBilling{
|
|
{Provider: "tencent", BillingDate: today, Cost: 100, Currency: "CNY", Service: "CVM"},
|
|
{Provider: "aws", BillingDate: today, Cost: 10, Currency: "USD", Service: "EC2"},
|
|
}
|
|
if err := db.Create(&records).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
handler := NewBillingHandler(db, &config.BillingConfig{BaseCurrency: "CNY", ExchangeRates: map[string]float64{"CNY": 1, "USD": 7.2}})
|
|
|
|
assertMonthCost := func(currency string, expected float64) {
|
|
t.Helper()
|
|
recorder := httptest.NewRecorder()
|
|
context, _ := gin.CreateTestContext(recorder)
|
|
context.Request = httptest.NewRequest("GET", "/?currency="+currency, nil)
|
|
handler.GetBillingStats(context)
|
|
var response struct {
|
|
Code int `json:"code"`
|
|
Data struct {
|
|
MonthCost float64 `json:"month_cost"`
|
|
} `json:"data"`
|
|
}
|
|
if err := json.Unmarshal(recorder.Body.Bytes(), &response); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if response.Code != 200 || mathRound(response.Data.MonthCost, 2) != expected {
|
|
t.Fatalf("%s 月费用错误: code=%d cost=%f", currency, response.Code, response.Data.MonthCost)
|
|
}
|
|
}
|
|
assertMonthCost("CNY", 172)
|
|
assertMonthCost("USD", 23.89)
|
|
}
|
|
|
|
// TestBuildBillingAnalysisMonths 验证空月份补齐和非 Top 分类合并。 // Logan.Li
|
|
func TestBuildBillingAnalysisMonths(t *testing.T) {
|
|
start, _ := time.Parse("2006-01", "2026-03")
|
|
end, _ := time.Parse("2006-01", "2026-04")
|
|
costs := map[string]map[string]float64{
|
|
"2026-03": {"CVM": 100, "TCR": 20},
|
|
}
|
|
months := buildBillingAnalysisMonths(start, end, costs, []string{"CVM", "其他"})
|
|
if len(months) != 2 || months[0].Total != 120 || months[0].Items[1].Cost != 20 {
|
|
t.Fatalf("月度聚合错误: %+v", months)
|
|
}
|
|
if months[1].Month != "2026-04" || months[1].Total != 0 {
|
|
t.Fatalf("空月份未正确补齐: %+v", months[1])
|
|
}
|
|
}
|
|
|
|
// TestBuildBillingAttributions 验证归因变化额与贡献度。 // Logan.Li
|
|
func TestBuildBillingAttributions(t *testing.T) {
|
|
items := buildBillingAttributions(map[string]float64{"CVM": 100}, map[string]float64{"CVM": 180, "TCR": 20})
|
|
if len(items) != 2 || items[0].Name != "CVM" || items[0].Delta != 80 || items[0].Contribution != 80 {
|
|
t.Fatalf("费用归因错误: %+v", items)
|
|
}
|
|
}
|