mirror of
https://github.com/karust/openserp.git
synced 2026-08-05 16:53:54 +08:00
288 lines
8.2 KiB
Go
288 lines
8.2 KiB
Go
package core
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestCacheProxyMarketFallback(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
q Query
|
|
country string
|
|
}{
|
|
{name: "proxy country wins", q: Query{ProxyCountry: "DE", Region: "RU", LangCode: "EN"}, country: "de"},
|
|
{name: "region country fallback", q: Query{Region: "RU", LangCode: "EN"}, country: "ru"},
|
|
{name: "region locale fallback", q: Query{Region: "en-GB", LangCode: "EN"}, country: "gb"},
|
|
{name: "lang code last resort", q: Query{LangCode: "EN"}, country: "en"},
|
|
{name: "yandex numeric region ignored for market", q: Query{Region: "213", LangCode: "RU"}, country: "ru"},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
country, _, _ := cacheProxyMarket(tt.q)
|
|
if country != tt.country {
|
|
t.Fatalf("cacheProxyMarket country = %q, want %q", country, tt.country)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestResponseCacheSetAndGet(t *testing.T) {
|
|
cache := NewResponseCache(5*time.Second, 10)
|
|
key := BuildCacheKey("google", "search", Query{Text: "golang", Limit: 10})
|
|
|
|
if _, ok := cache.Get(key); ok {
|
|
t.Fatal("expected initial cache miss")
|
|
}
|
|
|
|
data := []byte(`[{"rank":1}]`)
|
|
cache.Set(key, data)
|
|
|
|
got, ok := cache.Get(key)
|
|
if !ok {
|
|
t.Fatal("expected cache hit")
|
|
}
|
|
if string(got) != string(data) {
|
|
t.Fatalf("unexpected cached value: got %s want %s", got, data)
|
|
}
|
|
}
|
|
|
|
func TestResponseCacheExpiration(t *testing.T) {
|
|
cache := NewResponseCache(40*time.Millisecond, 10)
|
|
key := BuildCacheKey("google", "search", Query{Text: "expire"})
|
|
cache.Set(key, []byte(`[]`))
|
|
|
|
if _, ok := cache.Get(key); !ok {
|
|
t.Fatal("expected cache hit before expiration")
|
|
}
|
|
|
|
time.Sleep(60 * time.Millisecond)
|
|
|
|
if _, ok := cache.Get(key); ok {
|
|
t.Fatal("expected cache miss after expiration")
|
|
}
|
|
}
|
|
|
|
func TestResponseCacheEvictsOldestEntry(t *testing.T) {
|
|
cache := NewResponseCache(time.Minute, 2)
|
|
|
|
firstKey := BuildCacheKey("google", "search", Query{Text: "first"})
|
|
secondKey := BuildCacheKey("google", "search", Query{Text: "second"})
|
|
thirdKey := BuildCacheKey("google", "search", Query{Text: "third"})
|
|
|
|
cache.Set(firstKey, []byte(`["first"]`))
|
|
time.Sleep(10 * time.Millisecond)
|
|
cache.Set(secondKey, []byte(`["second"]`))
|
|
time.Sleep(10 * time.Millisecond)
|
|
cache.Set(thirdKey, []byte(`["third"]`))
|
|
|
|
if _, ok := cache.Get(firstKey); ok {
|
|
t.Fatal("expected oldest entry to be evicted")
|
|
}
|
|
if _, ok := cache.Get(secondKey); !ok {
|
|
t.Fatal("expected newer entry to remain cached")
|
|
}
|
|
if _, ok := cache.Get(thirdKey); !ok {
|
|
t.Fatal("expected newest entry to remain cached")
|
|
}
|
|
}
|
|
|
|
func TestResponseCacheStats(t *testing.T) {
|
|
cache := NewResponseCache(time.Minute, 2)
|
|
key := BuildCacheKey("google", "search", Query{Text: "stats"})
|
|
|
|
if _, ok := cache.Get(key); ok {
|
|
t.Fatal("expected miss for empty cache")
|
|
}
|
|
|
|
cache.Set(key, []byte(`[]`))
|
|
if _, ok := cache.Get(key); !ok {
|
|
t.Fatal("expected cache hit")
|
|
}
|
|
cache.RecordBypass()
|
|
|
|
stats := cache.Stats()
|
|
if got := stats["status"]; got != true {
|
|
t.Fatalf("expected enabled status, got %v", got)
|
|
}
|
|
if got := stats["entries"].(int); got != 1 {
|
|
t.Fatalf("expected 1 entry, got %d", got)
|
|
}
|
|
if got := stats["hits"].(int); got != 1 {
|
|
t.Fatalf("expected 1 hit, got %d", got)
|
|
}
|
|
if got := stats["misses"].(int); got != 1 {
|
|
t.Fatalf("expected 1 miss, got %d", got)
|
|
}
|
|
if got := stats["bypasses"].(int); got != 1 {
|
|
t.Fatalf("expected 1 bypass, got %d", got)
|
|
}
|
|
}
|
|
|
|
func TestBuildCacheKeyChangesWithPaginationAndFlags(t *testing.T) {
|
|
base := Query{
|
|
Text: "golang",
|
|
LangCode: "EN",
|
|
Limit: 10,
|
|
Start: 0,
|
|
Filter: true,
|
|
Answers: false,
|
|
}
|
|
|
|
baseKey := BuildCacheKey("google", "search", base)
|
|
|
|
if same := BuildCacheKey("google", "search", base); same != baseKey {
|
|
t.Fatal("expected deterministic key for same query")
|
|
}
|
|
if changed := BuildCacheKey("google", "search", Query{
|
|
Text: "golang",
|
|
LangCode: "EN",
|
|
Region: "US",
|
|
Limit: 10,
|
|
Start: 0,
|
|
Filter: true,
|
|
Answers: false,
|
|
}); changed == baseKey {
|
|
t.Fatal("expected region to affect cache key")
|
|
}
|
|
if changed := BuildCacheKey("google", "search", Query{
|
|
Text: "golang",
|
|
LangCode: "EN",
|
|
Limit: 20,
|
|
Start: 0,
|
|
Filter: true,
|
|
Answers: false,
|
|
}); changed == baseKey {
|
|
t.Fatal("expected limit to affect cache key")
|
|
}
|
|
if changed := BuildCacheKey("google", "search", Query{
|
|
Text: "golang",
|
|
LangCode: "EN",
|
|
Limit: 10,
|
|
Start: 10,
|
|
Filter: true,
|
|
Answers: false,
|
|
}); changed == baseKey {
|
|
t.Fatal("expected start to affect cache key")
|
|
}
|
|
if changed := BuildCacheKey("google", "search", Query{
|
|
Text: "golang",
|
|
LangCode: "EN",
|
|
Limit: 10,
|
|
Start: 0,
|
|
Filter: false,
|
|
Answers: false,
|
|
}); changed == baseKey {
|
|
t.Fatal("expected filter to affect cache key")
|
|
}
|
|
if changed := BuildCacheKey("google", "search", Query{
|
|
Text: "golang",
|
|
LangCode: "EN",
|
|
Limit: 10,
|
|
Start: 0,
|
|
Filter: true,
|
|
Answers: true,
|
|
}); changed == baseKey {
|
|
t.Fatal("expected answers to affect cache key")
|
|
}
|
|
}
|
|
|
|
func TestBuildCacheKeyNormalizesStableFields(t *testing.T) {
|
|
base := BuildCacheKey("google", "search", Query{
|
|
Text: " golang ",
|
|
LangCode: "EN",
|
|
Region: " us ",
|
|
Filetype: "PDF",
|
|
Site: "EXAMPLE.COM",
|
|
Limit: 10,
|
|
ProxyCountry: " US ",
|
|
ProxyClass: " Residential ",
|
|
})
|
|
same := BuildCacheKey("Google", "Search", Query{
|
|
Text: "golang",
|
|
LangCode: "en",
|
|
Region: "US",
|
|
Filetype: "pdf",
|
|
Site: "example.com",
|
|
Limit: 10,
|
|
ProxyCountry: "us",
|
|
ProxyClass: "residential",
|
|
})
|
|
if same != base {
|
|
t.Fatal("expected cache key to normalize engine/action, locale, filters, and proxy market fields")
|
|
}
|
|
}
|
|
|
|
func TestBuildCacheKeyUsesProxyMarketNotSessionOrURL(t *testing.T) {
|
|
base := Query{
|
|
Text: "golang",
|
|
LangCode: "EN",
|
|
Limit: 10,
|
|
ProxyURL: "http://user:password-a@proxy-a:8080",
|
|
ProxyCountry: " US ",
|
|
ProxyClass: " Residential ",
|
|
ProxyProvider: " WebShare ",
|
|
ProxySessionID: "sid-a",
|
|
}
|
|
baseKey := BuildCacheKey("google", "search", base)
|
|
|
|
sameMarket := base
|
|
sameMarket.ProxyURL = "http://user:password-b@proxy-b:8080"
|
|
sameMarket.ProxySessionID = "sid-b"
|
|
if got := BuildCacheKey("google", "search", sameMarket); got != baseKey {
|
|
t.Fatal("expected proxy URL and session id not to affect cache key")
|
|
}
|
|
|
|
differentCountry := base
|
|
differentCountry.ProxyCountry = "de"
|
|
if got := BuildCacheKey("google", "search", differentCountry); got == baseKey {
|
|
t.Fatal("expected proxy country to affect cache key")
|
|
}
|
|
|
|
differentClass := base
|
|
differentClass.ProxyClass = "datacenter"
|
|
if got := BuildCacheKey("google", "search", differentClass); got == baseKey {
|
|
t.Fatal("expected proxy class to affect cache key")
|
|
}
|
|
|
|
differentProvider := base
|
|
differentProvider.ProxyProvider = "brightdata"
|
|
if got := BuildCacheKey("google", "search", differentProvider); got == baseKey {
|
|
t.Fatal("expected proxy provider to affect cache key")
|
|
}
|
|
}
|
|
|
|
func TestBuildCacheKeyFallsBackToLanguageWhenCountryAbsent(t *testing.T) {
|
|
base := Query{Text: "golang", LangCode: "en", Limit: 10}
|
|
baseKey := BuildCacheKey("google", "search", base)
|
|
|
|
changed := base
|
|
changed.LangCode = "de"
|
|
if got := BuildCacheKey("google", "search", changed); got == baseKey {
|
|
t.Fatal("expected language fallback to affect cache key when proxy country is absent")
|
|
}
|
|
|
|
withCountry := base
|
|
withCountry.ProxyCountry = "us"
|
|
changedWithCountry := withCountry
|
|
changedWithCountry.LangCode = "de"
|
|
if got := BuildCacheKey("google", "search", changedWithCountry); got == BuildCacheKey("google", "search", withCountry) {
|
|
t.Fatal("expected language itself to remain part of the cache key")
|
|
}
|
|
}
|
|
|
|
func TestShouldBypassCacheForProxyMarket(t *testing.T) {
|
|
if !ShouldBypassCacheForProxyMarket(Query{ProxyURL: "http://proxy.example:8080"}) {
|
|
t.Fatal("expected request proxy without market metadata to bypass cache")
|
|
}
|
|
if !ShouldBypassCacheForProxyMarket(Query{ProxyOverride: "us"}) {
|
|
t.Fatal("expected tag override without market metadata to bypass cache")
|
|
}
|
|
if ShouldBypassCacheForProxyMarket(Query{ProxyURL: "http://proxy.example:8080", ProxyCountry: "us"}) {
|
|
t.Fatal("expected explicit country market metadata to allow cache")
|
|
}
|
|
if ShouldBypassCacheForProxyMarket(Query{Text: "golang"}) {
|
|
t.Fatal("expected direct query without proxy override to allow cache")
|
|
}
|
|
}
|