Add snapshot, signature, and drift guard support for Vertex AI, Cloudflare Workers AI, and Perplexity API, backed by a queryable audit table and recent-window view. This commit also wires the audit query layer into daily signal materialization and report generation so structure drift becomes a first-class signal instead of a log-only artifact.
105 lines
2.9 KiB
Go
105 lines
2.9 KiB
Go
//go:build llm_script
|
||
|
||
package main
|
||
|
||
import (
|
||
"bytes"
|
||
"errors"
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
func TestRunPricingSmokeChecksCollectsSummariesAndFailures(t *testing.T) {
|
||
checks := []pricingSmokeCheck{
|
||
{
|
||
Name: "Vertex",
|
||
URL: "https://vertex.example/pricing",
|
||
Run: func() (string, error) {
|
||
return "source=vertex-pricing-import models=4 operator=Google Cloud Vertex AI dry_run=true", nil
|
||
},
|
||
},
|
||
{
|
||
Name: "Cloudflare",
|
||
URL: "https://cloudflare.example/pricing",
|
||
Run: func() (string, error) {
|
||
return "", errors.New("fetch failed")
|
||
},
|
||
},
|
||
}
|
||
|
||
results := runPricingSmokeChecks(checks, func() time.Time {
|
||
return time.UnixMilli(1710000000000)
|
||
})
|
||
if len(results) != 2 {
|
||
t.Fatalf("期望 2 条结果,实际 %d", len(results))
|
||
}
|
||
if !results[0].Success {
|
||
t.Fatalf("期望 Vertex 成功,结果: %+v", results[0])
|
||
}
|
||
if results[0].ModelCount != 4 {
|
||
t.Fatalf("期望 Vertex 模型数为 4,实际 %d", results[0].ModelCount)
|
||
}
|
||
if results[0].Operator != "Google Cloud Vertex AI" {
|
||
t.Fatalf("期望 Vertex operator 解析成功,实际 %q", results[0].Operator)
|
||
}
|
||
if results[1].Success {
|
||
t.Fatalf("期望 Cloudflare 失败,结果: %+v", results[1])
|
||
}
|
||
if !strings.Contains(results[1].Error, "fetch failed") {
|
||
t.Fatalf("期望 Cloudflare 错误被透传,实际 %q", results[1].Error)
|
||
}
|
||
}
|
||
|
||
func TestRenderPricingSmokeTextReportPrintsSummary(t *testing.T) {
|
||
results := []pricingSmokeResult{
|
||
{
|
||
Name: "Vertex",
|
||
URL: "https://vertex.example/pricing",
|
||
Source: "vertex-pricing-import",
|
||
Operator: "Google Cloud Vertex AI",
|
||
ModelCount: 4,
|
||
Success: true,
|
||
DurationMS: 123,
|
||
},
|
||
{
|
||
Name: "Perplexity",
|
||
URL: "https://perplexity.example/models",
|
||
Success: false,
|
||
DurationMS: 456,
|
||
Error: "unexpected perplexity pricing content",
|
||
},
|
||
}
|
||
|
||
var out bytes.Buffer
|
||
renderPricingSmokeTextReport(&out, results, time.Date(2026, 5, 15, 16, 4, 0, 0, time.FixedZone("CST", 8*3600)))
|
||
text := out.String()
|
||
for _, want := range []string{
|
||
"=== Live Pricing Smoke Report (2026-05-15 16:04) ===",
|
||
"PASS Vertex source=vertex-pricing-import models=4 operator=Google Cloud Vertex AI duration_ms=123",
|
||
"FAIL Perplexity duration_ms=456 error=unexpected perplexity pricing content",
|
||
"Summary: 1 passed, 1 failed",
|
||
} {
|
||
if !strings.Contains(text, want) {
|
||
t.Fatalf("输出缺少 %q,实际: %q", want, text)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestParsePricingSmokeSummaryLine(t *testing.T) {
|
||
line := "source=cloudflare-pricing-import models=4 operator=Cloudflare Workers AI dry_run=true"
|
||
summary, ok := parsePricingSmokeSummaryLine(line)
|
||
if !ok {
|
||
t.Fatalf("期望成功解析 summary line")
|
||
}
|
||
if summary.Source != "cloudflare-pricing-import" {
|
||
t.Fatalf("source 错误: %q", summary.Source)
|
||
}
|
||
if summary.ModelCount != 4 {
|
||
t.Fatalf("models 错误: %d", summary.ModelCount)
|
||
}
|
||
if summary.Operator != "Cloudflare Workers AI" {
|
||
t.Fatalf("operator 错误: %q", summary.Operator)
|
||
}
|
||
}
|