2026-05-15 22:32:57 +08:00
|
|
|
//go:build llm_script
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
2026-05-27 17:23:08 +08:00
|
|
|
"fmt"
|
2026-05-15 22:32:57 +08:00
|
|
|
"net/http"
|
|
|
|
|
"net/http/httptest"
|
2026-05-27 17:23:08 +08:00
|
|
|
"strings"
|
2026-05-15 22:32:57 +08:00
|
|
|
"testing"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type assertiveError string
|
|
|
|
|
|
|
|
|
|
func (e assertiveError) Error() string {
|
|
|
|
|
return string(e)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestFetchSubscriptionPageRetriesForbiddenThenSucceeds(t *testing.T) {
|
|
|
|
|
attempts := 0
|
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
attempts++
|
|
|
|
|
if attempts == 1 {
|
|
|
|
|
w.WriteHeader(http.StatusForbidden)
|
|
|
|
|
_, _ = w.Write([]byte("blocked"))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
_, _ = w.Write([]byte("<html><body>套餐价格</body></html>"))
|
|
|
|
|
}))
|
|
|
|
|
defer server.Close()
|
|
|
|
|
|
|
|
|
|
client := &http.Client{Timeout: 2 * time.Second}
|
|
|
|
|
body, err := fetchSubscriptionPage(server.URL, "", client)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("fetchSubscriptionPage 返回错误: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if body != "套餐价格" {
|
|
|
|
|
t.Fatalf("返回体归一化错误: %q", body)
|
|
|
|
|
}
|
|
|
|
|
if attempts != 2 {
|
|
|
|
|
t.Fatalf("期望重试 1 次后成功,实际请求 %d 次", attempts)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestIsRetriableSubscriptionFetchErrorRecognizesForbidden(t *testing.T) {
|
|
|
|
|
if !isRetriableSubscriptionFetchError(assertiveError("unexpected status 403")) {
|
|
|
|
|
t.Fatalf("403 应被视作可重试错误")
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-05-27 17:23:08 +08:00
|
|
|
|
|
|
|
|
func TestFetchSubscriptionPageFallsBackToMarkdownSuffixOnForbidden(t *testing.T) {
|
|
|
|
|
attempts := map[string]int{}
|
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
attempts[r.URL.Path]++
|
|
|
|
|
switch r.URL.Path {
|
|
|
|
|
case "/cn/update/promotion":
|
|
|
|
|
http.Error(w, "forbidden", http.StatusForbidden)
|
|
|
|
|
case "/cn/update/promotion.md":
|
|
|
|
|
_, _ = w.Write([]byte("# 上新活动\nGLM Coding Plan 低至20元/月"))
|
|
|
|
|
default:
|
|
|
|
|
http.Error(w, fmt.Sprintf("unexpected path %s", r.URL.Path), http.StatusNotFound)
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
defer server.Close()
|
|
|
|
|
|
|
|
|
|
client := &http.Client{Timeout: 2 * time.Second}
|
|
|
|
|
body, err := fetchSubscriptionPage(server.URL+"/cn/update/promotion", "", client)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("fetchSubscriptionPage 返回错误: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if !strings.Contains(body, "GLM Coding Plan 低至20元/月") {
|
|
|
|
|
t.Fatalf("返回体缺少 markdown fallback 内容: %q", body)
|
|
|
|
|
}
|
|
|
|
|
if attempts["/cn/update/promotion"] != subscriptionFetchMaxAttempts {
|
|
|
|
|
t.Fatalf("期望原始路径按重试上限请求 %d 次,实际 %d", subscriptionFetchMaxAttempts, attempts["/cn/update/promotion"])
|
|
|
|
|
}
|
|
|
|
|
if attempts["/cn/update/promotion.md"] != 1 {
|
|
|
|
|
t.Fatalf("期望 .md 路径请求 1 次,实际 %d", attempts["/cn/update/promotion.md"])
|
|
|
|
|
}
|
|
|
|
|
}
|