- Add import_cucloud_pricing.go for 联通云 payg 公开价抓取 - Add import_bytedance_pricing.go for 火山引擎/ByteDance Ark 定价导入 - Include test files and sample testdata for both importers - Update plan catalog inventory docs and seeds - Add cucloud pricing importer implementation plan - Align pipeline scripts and smoke gate tests
154 lines
7.5 KiB
Go
154 lines
7.5 KiB
Go
//go:build llm_script
|
||
|
||
package main
|
||
|
||
import (
|
||
"bytes"
|
||
"path/filepath"
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
func TestBuildPlanCatalogRows(t *testing.T) {
|
||
envelope, err := loadPlanCatalogSeeds([]string{
|
||
filepath.Join("..", "seeds", "plan_catalog_inventory_seed.json"),
|
||
filepath.Join("..", "seeds", "plan_catalog_inventory_seed_cn_vendors_top20.json"),
|
||
filepath.Join("..", "seeds", "plan_catalog_inventory_seed_cn_relays_top20plus.json"),
|
||
filepath.Join("..", "seeds", "plan_catalog_inventory_seed_web_research.json"),
|
||
})
|
||
if err != nil {
|
||
t.Fatalf("loadPlanCatalogSeeds 失败: %v", err)
|
||
}
|
||
|
||
rows, err := buildPlanCatalogRows(envelope)
|
||
if err != nil {
|
||
t.Fatalf("buildPlanCatalogRows 失败: %v", err)
|
||
}
|
||
if len(rows) != 71 {
|
||
t.Fatalf("期望 71 条基础目录记录,实际 %d", len(rows))
|
||
}
|
||
|
||
foundVendorTop20 := false
|
||
foundRelayTop20Plus := false
|
||
wantImporterKeys := map[string]string{
|
||
"tencent-cloud-token-plan-enterprise-pro": "tencent_catalog",
|
||
"tencent-cloud-token-plan-enterprise-lite": "tencent_catalog",
|
||
"tencent-cloud-coding-plan": "tencent_catalog",
|
||
"aliyun-bailian-token-plan-team": "import_aliyun_subscription.go",
|
||
"aliyun-bailian-coding-plan": "import_aliyun_subscription.go",
|
||
"baidu-qianfan-token-benefit-pack": "import_baidu_subscription.go",
|
||
"baidu-qianfan-coding-plan": "import_baidu_subscription.go",
|
||
"bytedance-doubao-api-payg": "import_bytedance_pricing.go",
|
||
"zhipu-glm-coding-plan": "import_zhipu_coding_plan.go",
|
||
"minimax-token-plan": "import_minimax_subscription.go",
|
||
"volcengine-ark-coding-plan": "import_bytedance_subscription.go",
|
||
"huawei-cloud-maas-package-plan": "import_huawei_package.go",
|
||
"ctyun-token-plan": "import_ctyun_subscription.go",
|
||
"ctyun-coding-plan": "import_ctyun_subscription.go",
|
||
"cucloud-aicp-platform": "import_cucloud_catalog.go",
|
||
"cucloud-ai-app-platform": "import_cucloud_catalog.go",
|
||
"cucloud-aisp-token-plan-pricing": "import_cucloud_pricing.go",
|
||
"mobile-cloud-ai-market": "import_mobile_cloud_pricing.go",
|
||
"aliyun-modelscope-api-inference": "import_catalog_seed_verification.go",
|
||
"youdao-zhiyun-maas": "import_youdao_pricing.go",
|
||
"ctyun-model-inference-payg": "import_catalog_seed_verification.go",
|
||
"360-open-platform": "import_360_pricing.go",
|
||
"siliconflow-siliconcloud": "import_siliconflow_pricing.go",
|
||
"ppio-model-api": "import_ppio_pricing.go",
|
||
"ucloud-umodelverse": "import_ucloud_pricing.go",
|
||
"anthropic-api-payg": "import_catalog_seed_verification.go",
|
||
"xai-api-payg": "import_catalog_seed_verification.go",
|
||
"alibaba-qwen-api-payg": "import_qwen_pricing.go",
|
||
"tencent-hunyuan-api-payg": "import_hunyuan_pricing.go",
|
||
"huawei-pangu-api-payg": "import_huawei_maas_pricing.go",
|
||
"baichuan-api-payg": "import_catalog_seed_verification.go",
|
||
"01ai-api-payg": "import_catalog_seed_verification.go",
|
||
"sensenova-api-payg": "import_catalog_seed_verification.go",
|
||
"xfyun-spark-api-payg": "import_catalog_seed_verification.go",
|
||
"360-zhinao-api-payg": "import_catalog_seed_verification.go",
|
||
"youdao-ziyue-api-payg": "import_catalog_seed_verification.go",
|
||
"modelbest-minicpm-api-payg": "import_catalog_seed_verification.go",
|
||
"baai-flagopen-api-payg": "import_catalog_seed_verification.go",
|
||
"skywork-api-payg": "import_catalog_seed_verification.go",
|
||
"infinigence-api-payg": "import_catalog_seed_verification.go",
|
||
"qingcloud-coreshub": "import_coreshub_pricing.go",
|
||
"ksyun-xingliu-platform": "import_catalog_seed_verification.go",
|
||
"google-gemini-api-payg": "import_catalog_seed_verification.go",
|
||
"mistral-api-payg": "import_catalog_seed_verification.go",
|
||
"cohere-api-payg": "import_catalog_seed_verification.go",
|
||
"openrouter-api-payg": "fetch_openrouter.go",
|
||
"together-ai-api-payg": "import_catalog_seed_verification.go",
|
||
"fireworks-ai-api-payg": "import_catalog_seed_verification.go",
|
||
"deepinfra-api-payg": "import_catalog_seed_verification.go",
|
||
"groq-api-payg": "import_catalog_seed_verification.go",
|
||
"replicate-api-payg": "import_catalog_seed_verification.go",
|
||
"hyperbolic-api-payg": "import_catalog_seed_verification.go",
|
||
"novita-ai-api-payg": "import_catalog_seed_verification.go",
|
||
"azure-openai-service-payg": "import_azure_openai_pricing.go",
|
||
"amazon-bedrock-payg": "import_bedrock_pricing.go",
|
||
"google-vertex-ai-genai-payg": "import_vertex_pricing.go",
|
||
"cloudflare-workers-ai-payg": "import_cloudflare_pricing.go",
|
||
"baseten-inference-payg": "import_catalog_seed_verification.go",
|
||
"cerebras-inference-payg": "import_catalog_seed_verification.go",
|
||
"perplexity-agent-api-payg": "import_perplexity_pricing.go",
|
||
"sambanova-cloud-payg": "import_catalog_seed_verification.go",
|
||
"jdcloud-joybuilder-payg": "import_catalog_seed_verification.go",
|
||
}
|
||
for _, row := range rows {
|
||
if row.CatalogCode == "zhipu-glm-coding-plan" {
|
||
if row.CatalogSegment != "vendor_top20" || row.MarketRank != 5 {
|
||
t.Fatalf("智谱榜单字段错误: segment=%q rank=%d", row.CatalogSegment, row.MarketRank)
|
||
}
|
||
foundVendorTop20 = true
|
||
}
|
||
if row.CatalogCode == "ctyun-coding-plan" {
|
||
if row.CatalogSegment != "relay_top20plus" || row.MarketRank != 9 {
|
||
t.Fatalf("天翼云编码套餐榜单字段错误: segment=%q rank=%d", row.CatalogSegment, row.MarketRank)
|
||
}
|
||
foundRelayTop20Plus = true
|
||
}
|
||
if wantImporterKey, ok := wantImporterKeys[row.CatalogCode]; ok && row.ImporterKey != wantImporterKey {
|
||
t.Fatalf("%s importerKey 错误: got=%q want=%q", row.CatalogCode, row.ImporterKey, wantImporterKey)
|
||
}
|
||
}
|
||
if !foundVendorTop20 {
|
||
t.Fatalf("缺少 vendor_top20 覆盖记录")
|
||
}
|
||
if !foundRelayTop20Plus {
|
||
t.Fatalf("缺少 relay_top20plus 覆盖记录")
|
||
}
|
||
}
|
||
|
||
func TestRunPlanCatalogImportDryRunPrintsSummary(t *testing.T) {
|
||
var out bytes.Buffer
|
||
err := runPlanCatalogImport(importPlanCatalogConfig{
|
||
SeedPaths: strings.Join([]string{
|
||
filepath.Join("..", "seeds", "plan_catalog_inventory_seed.json"),
|
||
filepath.Join("..", "seeds", "plan_catalog_inventory_seed_cn_vendors_top20.json"),
|
||
filepath.Join("..", "seeds", "plan_catalog_inventory_seed_cn_relays_top20plus.json"),
|
||
filepath.Join("..", "seeds", "plan_catalog_inventory_seed_web_research.json"),
|
||
}, ","),
|
||
DryRun: true,
|
||
}, nil, &out)
|
||
if err != nil {
|
||
t.Fatalf("runPlanCatalogImport 失败: %v", err)
|
||
}
|
||
|
||
output := out.String()
|
||
for _, want := range []string{
|
||
"source=plan-catalog-import",
|
||
"rows=71",
|
||
"coding_plan:7",
|
||
"package_plan:1",
|
||
"pay_as_you_go:52",
|
||
"token_plan:8",
|
||
"unknown:3",
|
||
"confirmed:71",
|
||
"dry_run=true",
|
||
} {
|
||
if !strings.Contains(output, want) {
|
||
t.Fatalf("输出缺少 %q,实际: %q", want, output)
|
||
}
|
||
}
|
||
}
|