test(acceptance): 在单窗口验证厂商额度峰值
厂商额度验收此前复用了多图与超大图容量素材,3 Worker 的下载和预处理使 24 个任务跨越多个固定分钟窗口,无法精确证明 RPM 与 TPM 上限。\n\n额度场景固定使用三张正常尺寸引用图并为每个任务增加唯一 URL 变体,使请求满足视频协议且能在单窗口完成;6、9 图和超大图转换继续由独立视频容量 profile 覆盖。\n\n验证:\n- go test ./cmd/acceptance-load ./internal/acceptanceworkload -count=1\n- go vet ./cmd/acceptance-load ./internal/acceptanceworkload\n- gofmt -l cmd/acceptance-load/main.go cmd/acceptance-load/main_test.go
This commit is contained in:
@@ -640,6 +640,13 @@ func runVideo(
|
|||||||
combinationCount = 1
|
combinationCount = 1
|
||||||
}
|
}
|
||||||
combinations := videoCombinations(imageURLs, combinationCount)
|
combinations := videoCombinations(imageURLs, combinationCount)
|
||||||
|
if name == "video-provider-quota" {
|
||||||
|
// The quota profile must complete in one fixed rate-limit window so
|
||||||
|
// RPM and TPM can be proven at their exact configured ceilings. Use
|
||||||
|
// three distinct normal-sized references per task; larger multi-image
|
||||||
|
// and oversized conversion remain covered by video capacity profiles.
|
||||||
|
combinations = videoProviderQuotaCombinations(imageURLs, combinationCount)
|
||||||
|
}
|
||||||
var taskIDs = make([]string, requestCount)
|
var taskIDs = make([]string, requestCount)
|
||||||
latencies := make([]time.Duration, requestCount)
|
latencies := make([]time.Duration, requestCount)
|
||||||
startedTasks := make([]time.Time, requestCount)
|
startedTasks := make([]time.Time, requestCount)
|
||||||
@@ -658,7 +665,7 @@ func runVideo(
|
|||||||
logicalIndex := requestOffset + index*requestStride
|
logicalIndex := requestOffset + index*requestStride
|
||||||
requestStarted := time.Now()
|
requestStarted := time.Now()
|
||||||
startedTasks[index] = requestStarted
|
startedTasks[index] = requestStarted
|
||||||
imageCount := acceptanceworkload.VideoImageCount(logicalIndex)
|
imageCount := videoImageCountForProfile(name, logicalIndex)
|
||||||
combo := append([]string(nil), combinations[logicalIndex%len(combinations)]...)
|
combo := append([]string(nil), combinations[logicalIndex%len(combinations)]...)
|
||||||
if len(combo) > imageCount {
|
if len(combo) > imageCount {
|
||||||
combo = combo[:imageCount]
|
combo = combo[:imageCount]
|
||||||
@@ -784,6 +791,7 @@ func runVideo(
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
uniqueImageCombinations := requestedVideoCombinationCount(
|
uniqueImageCombinations := requestedVideoCombinationCount(
|
||||||
combinations,
|
combinations,
|
||||||
|
name,
|
||||||
requestCount,
|
requestCount,
|
||||||
requestOffset,
|
requestOffset,
|
||||||
requestStride,
|
requestStride,
|
||||||
@@ -1180,8 +1188,46 @@ func videoCombinations(images []string, count int) [][]string {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func videoProviderQuotaCombinations(images []string, count int) [][]string {
|
||||||
|
if len(images) == 0 || count <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fixtureCount := min(len(images), 4)
|
||||||
|
if fixtureCount < 3 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make([][]string, 0, count)
|
||||||
|
for index := 0; index < count; index++ {
|
||||||
|
combination := make([]string, 0, 3)
|
||||||
|
for imageIndex := 0; imageIndex < 3; imageIndex++ {
|
||||||
|
imageURL := images[(index+imageIndex)%fixtureCount]
|
||||||
|
separator := "?"
|
||||||
|
if strings.Contains(imageURL, "?") {
|
||||||
|
separator = "&"
|
||||||
|
}
|
||||||
|
combination = append(combination, fmt.Sprintf(
|
||||||
|
"%s%sacceptance_quota_variant=%d-%d",
|
||||||
|
imageURL,
|
||||||
|
separator,
|
||||||
|
index,
|
||||||
|
imageIndex,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
out = append(out, combination)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func videoImageCountForProfile(profile string, index int) int {
|
||||||
|
if profile == "video-provider-quota" {
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
return acceptanceworkload.VideoImageCount(index)
|
||||||
|
}
|
||||||
|
|
||||||
func requestedVideoCombinationCount(
|
func requestedVideoCombinationCount(
|
||||||
combinations [][]string,
|
combinations [][]string,
|
||||||
|
profile string,
|
||||||
requestCount int,
|
requestCount int,
|
||||||
requestOffset int,
|
requestOffset int,
|
||||||
requestStride int,
|
requestStride int,
|
||||||
@@ -1195,7 +1241,7 @@ func requestedVideoCombinationCount(
|
|||||||
seen := map[string]struct{}{}
|
seen := map[string]struct{}{}
|
||||||
for index := 0; index < requestCount; index++ {
|
for index := 0; index < requestCount; index++ {
|
||||||
logicalIndex := requestOffset + index*requestStride
|
logicalIndex := requestOffset + index*requestStride
|
||||||
imageCount := acceptanceworkload.VideoImageCount(logicalIndex)
|
imageCount := videoImageCountForProfile(profile, logicalIndex)
|
||||||
combo := combinations[logicalIndex%len(combinations)]
|
combo := combinations[logicalIndex%len(combinations)]
|
||||||
if len(combo) > imageCount {
|
if len(combo) > imageCount {
|
||||||
combo = combo[:imageCount]
|
combo = combo[:imageCount]
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -172,11 +173,34 @@ func TestVideoCombinationsProvide128UniqueInputs(t *testing.T) {
|
|||||||
if len(seen) != 128 {
|
if len(seen) != 128 {
|
||||||
t.Fatalf("unique combinations=%d", len(seen))
|
t.Fatalf("unique combinations=%d", len(seen))
|
||||||
}
|
}
|
||||||
if got := requestedVideoCombinationCount(combinations, 144, 0, 1); got != 131 {
|
if got := requestedVideoCombinationCount(combinations, "video-capacity", 144, 0, 1); got != 131 {
|
||||||
t.Fatalf("requested combinations=%d, want 131", got)
|
t.Fatalf("requested combinations=%d, want 131", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVideoProviderQuotaCombinationsUseDistinctNormalSizedImages(t *testing.T) {
|
||||||
|
images := []string{
|
||||||
|
"https://fixtures.example/image-00.png",
|
||||||
|
"https://fixtures.example/image-01.png",
|
||||||
|
"https://fixtures.example/image-02.png",
|
||||||
|
"https://fixtures.example/image-03.png",
|
||||||
|
}
|
||||||
|
combinations := videoProviderQuotaCombinations(images, 24)
|
||||||
|
if got := requestedVideoCombinationCount(combinations, "video-provider-quota", 24, 0, 1); got != 24 {
|
||||||
|
t.Fatalf("quota combinations=%d, want 24", got)
|
||||||
|
}
|
||||||
|
for _, combination := range combinations {
|
||||||
|
if len(combination) != 3 {
|
||||||
|
t.Fatalf("invalid quota combination: %v", combination)
|
||||||
|
}
|
||||||
|
for _, imageURL := range combination {
|
||||||
|
if !strings.Contains(imageURL, "acceptance_quota_variant=") {
|
||||||
|
t.Fatalf("quota image lacks unique variant: %s", imageURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGeminiLoadIsSplitAcrossTwoGatewayAPIs(t *testing.T) {
|
func TestGeminiLoadIsSplitAcrossTwoGatewayAPIs(t *testing.T) {
|
||||||
output := paddedPNG(256 << 10)
|
output := paddedPNG(256 << 10)
|
||||||
encoded := base64.StdEncoding.EncodeToString(output)
|
encoded := base64.StdEncoding.EncodeToString(output)
|
||||||
|
|||||||
Reference in New Issue
Block a user