@@ -0,0 +1,120 @@
|
||||
package versionser
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/common/localcache"
|
||||
)
|
||||
|
||||
func TestAdvVersionAnnounThreeServerCoalescesConcurrentMisses(t *testing.T) {
|
||||
var calls atomic.Int32
|
||||
var badRequest atomic.Bool
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
calls.Add(1)
|
||||
if r.Method != http.MethodPost || r.URL.Path != "/api/stat/all/app" {
|
||||
badRequest.Store(true)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
_, _ = w.Write([]byte(`{}`))
|
||||
return
|
||||
}
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
_ = json.NewEncoder(w).Encode(AppAllResp{
|
||||
VersionInfo: VersionInfo{ServerVersion: "9.9.9"},
|
||||
AnnouList: []AnnouInfo{{ID: "announcement-1"}},
|
||||
IosUrl: "ios-url",
|
||||
AndroidUrl: "android-url",
|
||||
ShopIosLink: "shop-ios-url",
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
setVersionTestConfig(t, server.URL)
|
||||
version := "singleflight-test"
|
||||
deleteVersionTestCache(t, "VerAnnInfo:"+version)
|
||||
|
||||
const concurrency = 20
|
||||
start := make(chan struct{})
|
||||
errs := make(chan error, concurrency)
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < concurrency; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-start
|
||||
ver, _, annou, iosURL, androidURL, shopURL, err := AdvVersionAnnounThreeServer(version, "android")
|
||||
if err == nil && (ver.ServerVersion != "9.9.9" || len(annou) != 1 || iosURL != "ios-url" || androidURL != "android-url" || shopURL != "shop-ios-url") {
|
||||
err = &unexpectedVersionResponseError{}
|
||||
}
|
||||
errs <- err
|
||||
}()
|
||||
}
|
||||
close(start)
|
||||
wg.Wait()
|
||||
close(errs)
|
||||
|
||||
for err := range errs {
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected result: %v", err)
|
||||
}
|
||||
}
|
||||
if got := calls.Load(); got != 1 {
|
||||
t.Fatalf("downstream calls = %d, want 1", got)
|
||||
}
|
||||
if badRequest.Load() {
|
||||
t.Fatal("downstream request used an unexpected method or path")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdvVersionAnnounThreeServerCachesFailureFallback(t *testing.T) {
|
||||
var calls atomic.Int32
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
calls.Add(1)
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
_, _ = w.Write([]byte(`{}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
setVersionTestConfig(t, server.URL)
|
||||
version := "failure-cache-test"
|
||||
deleteVersionTestCache(t, "VerAnnInfo:"+version)
|
||||
|
||||
if _, _, _, _, _, _, err := AdvVersionAnnounThreeServer(version, "android"); err == nil {
|
||||
t.Fatal("first request error = nil, want downstream status error")
|
||||
}
|
||||
if _, _, _, _, _, _, err := AdvVersionAnnounThreeServer(version, "android"); err != nil {
|
||||
t.Fatalf("cached fallback error = %v, want nil", err)
|
||||
}
|
||||
if got := calls.Load(); got != 1 {
|
||||
t.Fatalf("downstream calls = %d, want 1", got)
|
||||
}
|
||||
}
|
||||
|
||||
type unexpectedVersionResponseError struct{}
|
||||
|
||||
func (*unexpectedVersionResponseError) Error() string { return "unexpected version response" }
|
||||
|
||||
func setVersionTestConfig(t *testing.T, productURL string) {
|
||||
t.Helper()
|
||||
previous := appg.Conf
|
||||
conf := &appg.GlobalConfig{}
|
||||
conf.URL.ProductUrl = productURL
|
||||
appg.Conf = conf
|
||||
t.Cleanup(func() { appg.Conf = previous })
|
||||
}
|
||||
|
||||
func deleteVersionTestCache(t *testing.T, key string) {
|
||||
t.Helper()
|
||||
localcache.C.Delete(key)
|
||||
localcache.C.Delete(key + ":lastSuccess")
|
||||
t.Cleanup(func() {
|
||||
localcache.C.Delete(key)
|
||||
localcache.C.Delete(key + ":lastSuccess")
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user