mirror of
https://github.com/karust/openserp.git
synced 2026-08-05 16:53:54 +08:00
Add URL builder edge-case tests and server endpoint coverage
This commit is contained in:
@@ -7,41 +7,164 @@ import (
|
||||
"github.com/karust/openserp/core"
|
||||
)
|
||||
|
||||
var testQuery = core.Query{Text: "go", Site: "tutorialspoint.com", DateInterval: "20140101..20230101", Limit: 10}
|
||||
|
||||
func TestUrlBuild(t *testing.T) {
|
||||
res, err := BuildURL(testQuery)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
func TestBuildURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
query core.Query
|
||||
wantErr bool
|
||||
check func(*testing.T, url.Values, string)
|
||||
}{
|
||||
{
|
||||
name: "combined params with unicode and start zero",
|
||||
query: core.Query{
|
||||
Text: "go 搜索",
|
||||
Site: "tutorialspoint.com",
|
||||
Filetype: "pdf",
|
||||
DateInterval: "20140101..20230101",
|
||||
Limit: 10,
|
||||
Start: 0,
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, host string) {
|
||||
t.Helper()
|
||||
if host != "www.baidu.com" {
|
||||
t.Fatalf("unexpected host: %s", host)
|
||||
}
|
||||
if got := params.Get("wd"); got != "go 搜索 site:tutorialspoint.com filetype:pdf" {
|
||||
t.Fatalf("unexpected wd value: %q", got)
|
||||
}
|
||||
if got := params.Get("gpc"); got != "stf=1388534400,1672531200|stftype=2" {
|
||||
t.Fatalf("unexpected gpc value: %q", got)
|
||||
}
|
||||
if got := params.Get("rn"); got != "10" {
|
||||
t.Fatalf("unexpected rn value: %q", got)
|
||||
}
|
||||
if got := params.Get("pn"); got != "" {
|
||||
t.Fatalf("pn should be omitted when Start=0, got %q", got)
|
||||
}
|
||||
if got := params.Get("f"); got != "8" {
|
||||
t.Fatalf("unexpected f value: %q", got)
|
||||
}
|
||||
if got := params.Get("ie"); got != "utf-8" {
|
||||
t.Fatalf("unexpected ie value: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "very large start",
|
||||
query: core.Query{
|
||||
Text: "golang",
|
||||
Start: 2147483647,
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, _ string) {
|
||||
t.Helper()
|
||||
if got := params.Get("pn"); got != "2147483647" {
|
||||
t.Fatalf("unexpected pn value: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "negative start returns error",
|
||||
query: core.Query{
|
||||
Text: "golang",
|
||||
Start: -1,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty fields return error",
|
||||
query: core.Query{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
want := "https://www.baidu.com/s?f=8&gpc=stf%3D1388534400%2C1672531200%7Cstftype%3D2&ie=utf-8&rn=10&wd=go+site%3Atutorialspoint.com"
|
||||
|
||||
if want != res {
|
||||
t.Fatalf("Wanted result `%s` doesn't match to resulted `%s`", want, res)
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := BuildURL(tt.query)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Fatalf("BuildURL() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageUrlBuild(t *testing.T) {
|
||||
query := core.Query{Text: "金毛猎犬"}
|
||||
|
||||
got, err := BuildImageURL(query, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
if tt.wantErr {
|
||||
return
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(got)
|
||||
if err != nil {
|
||||
t.Fatalf("invalid URL returned: %v", err)
|
||||
}
|
||||
if parsed.Host != "image.baidu.com" {
|
||||
t.Fatalf("unexpected host: %s", parsed.Host)
|
||||
if tt.check != nil {
|
||||
tt.check(t, parsed.Query(), parsed.Host)
|
||||
}
|
||||
q := parsed.Query()
|
||||
if q.Get("word") != "金毛猎犬" {
|
||||
t.Fatalf("expected word query to be preserved, got %q", q.Get("word"))
|
||||
}
|
||||
if q.Get("tn") != "resultjson_com" {
|
||||
t.Fatalf("expected tn=resultjson_com, got %q", q.Get("tn"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildImageURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
query core.Query
|
||||
pageNum int
|
||||
wantErr bool
|
||||
check func(*testing.T, url.Values, string)
|
||||
}{
|
||||
{
|
||||
name: "unicode query",
|
||||
query: core.Query{Text: "金毛猎犬"},
|
||||
pageNum: 0,
|
||||
check: func(t *testing.T, params url.Values, host string) {
|
||||
t.Helper()
|
||||
if host != "image.baidu.com" {
|
||||
t.Fatalf("unexpected host: %s", host)
|
||||
}
|
||||
if got := params.Get("word"); got != "金毛猎犬" {
|
||||
t.Fatalf("expected unicode query, got %q", got)
|
||||
}
|
||||
if got := params.Get("tn"); got != "resultjson_com" {
|
||||
t.Fatalf("unexpected tn value: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "combined params with pagination",
|
||||
query: core.Query{
|
||||
Text: "golang",
|
||||
Limit: 25,
|
||||
},
|
||||
pageNum: 3,
|
||||
check: func(t *testing.T, params url.Values, _ string) {
|
||||
t.Helper()
|
||||
if got := params.Get("rn"); got != "30" {
|
||||
t.Fatalf("unexpected rn value: %q", got)
|
||||
}
|
||||
if got := params.Get("pn"); got != "90" {
|
||||
t.Fatalf("unexpected pn value: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty fields return error",
|
||||
query: core.Query{},
|
||||
pageNum: 0,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := BuildImageURL(tt.query, tt.pageNum)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Fatalf("BuildImageURL() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
if tt.wantErr {
|
||||
return
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(got)
|
||||
if err != nil {
|
||||
t.Fatalf("invalid URL returned: %v", err)
|
||||
}
|
||||
if tt.check != nil {
|
||||
tt.check(t, parsed.Query(), parsed.Host)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,69 +2,183 @@ package bing
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/karust/openserp/core"
|
||||
)
|
||||
|
||||
func TestBuildURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
query core.Query
|
||||
wantErr bool
|
||||
check func(*testing.T, url.Values, string)
|
||||
}{
|
||||
{
|
||||
name: "combined params with unicode and start zero",
|
||||
query: core.Query{
|
||||
Text: "golang тест",
|
||||
Site: "example.com",
|
||||
Filetype: "pdf",
|
||||
DateInterval: "20240101..20240131",
|
||||
LangCode: "RU",
|
||||
Limit: 30,
|
||||
Start: 0,
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, host string) {
|
||||
t.Helper()
|
||||
if host != "www.bing.com" {
|
||||
t.Fatalf("unexpected host: %s", host)
|
||||
}
|
||||
if got := params.Get("q"); got != "golang тест site:example.com filetype:pdf after:2024-01-01 before:2024-01-31" {
|
||||
t.Fatalf("unexpected q value: %q", got)
|
||||
}
|
||||
if got := params.Get("pq"); got != params.Get("q") {
|
||||
t.Fatalf("pq should match q, got %q vs %q", got, params.Get("q"))
|
||||
}
|
||||
if got := params.Get("setlang"); got != "ru" {
|
||||
t.Fatalf("unexpected setlang value: %q", got)
|
||||
}
|
||||
if got := params.Get("count"); got != "30" {
|
||||
t.Fatalf("unexpected count value: %q", got)
|
||||
}
|
||||
if got := params.Get("first"); got != "" {
|
||||
t.Fatalf("first should be omitted when Start=0, got %q", got)
|
||||
}
|
||||
if got := params.Get("form"); got != "QBLH" {
|
||||
t.Fatalf("unexpected form value: %q", got)
|
||||
}
|
||||
if got := params.Get("qs"); got != "HS" {
|
||||
t.Fatalf("unexpected qs value: %q", got)
|
||||
}
|
||||
if got := params.Get("sp"); got != "-1" {
|
||||
t.Fatalf("unexpected sp value: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "very large start",
|
||||
query: core.Query{
|
||||
Text: "golang",
|
||||
Start: 2147483647,
|
||||
Limit: 20,
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, _ string) {
|
||||
t.Helper()
|
||||
if got := params.Get("first"); got != "2147483648" {
|
||||
t.Fatalf("unexpected first value: %q", got)
|
||||
}
|
||||
if got := params.Get("count"); got != "" {
|
||||
t.Fatalf("count should be omitted when first is used, got %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "negative start returns error",
|
||||
query: core.Query{
|
||||
Text: "golang",
|
||||
Start: -1,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty fields return error",
|
||||
query: core.Query{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := BuildURL(tt.query)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Fatalf("BuildURL() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
if tt.wantErr {
|
||||
return
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(got)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildURL() returned invalid URL: %v", err)
|
||||
}
|
||||
if tt.check != nil {
|
||||
tt.check(t, parsed.Query(), parsed.Host)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildImageURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
query core.Query
|
||||
wantErr bool
|
||||
wantCont string
|
||||
check func(*testing.T, url.Values, string)
|
||||
}{
|
||||
{
|
||||
name: "basic image query",
|
||||
query: core.Query{Text: "test"},
|
||||
wantErr: false,
|
||||
wantCont: "q=test",
|
||||
check: func(t *testing.T, params url.Values, host string) {
|
||||
t.Helper()
|
||||
if host != "www.bing.com" {
|
||||
t.Fatalf("unexpected host: %s", host)
|
||||
}
|
||||
if got := params.Get("q"); got != "test" {
|
||||
t.Fatalf("unexpected q value: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "image query with site",
|
||||
query: core.Query{Text: "cats", Site: "example.com"},
|
||||
wantErr: false,
|
||||
wantCont: "q=cats+site%3Aexample.com",
|
||||
name: "combined params with unicode",
|
||||
query: core.Query{
|
||||
Text: "коты",
|
||||
Site: "example.com",
|
||||
Filetype: "png",
|
||||
LangCode: "EN",
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, _ string) {
|
||||
t.Helper()
|
||||
if got := params.Get("q"); got != "коты site:example.com" {
|
||||
t.Fatalf("unexpected q value: %q", got)
|
||||
}
|
||||
if got := params.Get("setlang"); got != "en" {
|
||||
t.Fatalf("unexpected setlang value: %q", got)
|
||||
}
|
||||
if got := params.Get("form"); got != "HDRSC2" {
|
||||
t.Fatalf("unexpected form value: %q", got)
|
||||
}
|
||||
if got := params.Get("first"); got != "1" {
|
||||
t.Fatalf("unexpected first value: %q", got)
|
||||
}
|
||||
if got := params.Get("scenario"); got != "ImageBasicHover" {
|
||||
t.Fatalf("unexpected scenario value: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "image query with filetype",
|
||||
query: core.Query{Text: "dogs", Filetype: "png"},
|
||||
wantErr: false,
|
||||
wantCont: "q=dogs",
|
||||
},
|
||||
{
|
||||
name: "empty query",
|
||||
query: core.Query{Text: ""},
|
||||
name: "empty fields return error",
|
||||
query: core.Query{},
|
||||
wantErr: true,
|
||||
wantCont: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := BuildImageURL(tt.query)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("BuildImageURL() error = %v, wantErr %v", err, tt.wantErr)
|
||||
t.Fatalf("BuildImageURL() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
if tt.wantErr {
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr && got != "" {
|
||||
if !strings.Contains(got, tt.wantCont) {
|
||||
t.Errorf("BuildImageURL() = %v, should contain %v", got, tt.wantCont)
|
||||
}
|
||||
|
||||
// Test that URL is valid
|
||||
_, err := url.Parse(got)
|
||||
parsed, err := url.Parse(got)
|
||||
if err != nil {
|
||||
t.Errorf("BuildImageURL() returned invalid URL: %v", err)
|
||||
}
|
||||
|
||||
// Should be a Bing images URL
|
||||
if !strings.Contains(got, "bing.com/images/search") {
|
||||
t.Errorf("BuildImageURL() should return Bing images URL, got: %v", got)
|
||||
t.Fatalf("BuildImageURL() returned invalid URL: %v", err)
|
||||
}
|
||||
if tt.check != nil {
|
||||
tt.check(t, parsed.Query(), parsed.Host)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -71,6 +72,223 @@ func requestWithHeader(t *testing.T, s *Server, path string, header string, valu
|
||||
return resp
|
||||
}
|
||||
|
||||
func TestInvalidQueryParametersReturnJSONError(t *testing.T) {
|
||||
engine := &engineMock{name: "google", initialized: true}
|
||||
srv := NewServerWithOptions("127.0.0.1", 7104, DefaultServerOptions(), engine)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
path string
|
||||
message string
|
||||
}{
|
||||
{
|
||||
name: "invalid limit",
|
||||
path: "/google/search?text=golang&limit=abc",
|
||||
message: "invalid syntax",
|
||||
},
|
||||
{
|
||||
name: "negative start",
|
||||
path: "/google/search?text=golang&start=-1",
|
||||
message: "start must be >= 0",
|
||||
},
|
||||
{
|
||||
name: "invalid filter flag",
|
||||
path: "/google/search?text=golang&filter=notabool",
|
||||
message: "invalid syntax",
|
||||
},
|
||||
{
|
||||
name: "invalid answers flag on mega endpoint",
|
||||
path: "/mega/search?text=golang&answers=notabool",
|
||||
message: "invalid syntax",
|
||||
},
|
||||
{
|
||||
name: "empty text query",
|
||||
path: "/google/search?text=",
|
||||
message: "Query cannot be empty",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
resp := request(t, srv, tt.path)
|
||||
if resp.StatusCode != http.StatusInternalServerError {
|
||||
t.Fatalf("expected 500 for invalid query params, got %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var payload JSONErrorResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
|
||||
t.Fatalf("decode error response: %v", err)
|
||||
}
|
||||
if payload.Code != http.StatusInternalServerError {
|
||||
t.Fatalf("expected code=500, got %d", payload.Code)
|
||||
}
|
||||
if payload.Error != "server_error" {
|
||||
t.Fatalf("expected error=server_error, got %q", payload.Error)
|
||||
}
|
||||
if payload.Message == "" {
|
||||
t.Fatal("expected error message to be present")
|
||||
}
|
||||
if tt.message != "" && !strings.Contains(payload.Message, tt.message) {
|
||||
t.Fatalf("expected message to contain %q, got %q", tt.message, payload.Message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMegaEnginesEndpointResponseFormat(t *testing.T) {
|
||||
google := &engineMock{name: "google", initialized: true}
|
||||
yandex := &engineMock{name: "yandex", initialized: false}
|
||||
srv := NewServerWithOptions("127.0.0.1", 7105, DefaultServerOptions(), google, yandex)
|
||||
|
||||
// Prime circuit breaker stats so circuit_state is populated for both engines.
|
||||
_ = request(t, srv, "/google/search?text=golang")
|
||||
_ = request(t, srv, "/yandex/search?text=golang")
|
||||
|
||||
resp := request(t, srv, "/mega/engines")
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("expected /mega/engines to return 200, got %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var payload map[string]interface{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
|
||||
t.Fatalf("decode /mega/engines response: %v", err)
|
||||
}
|
||||
|
||||
total, ok := payload["total"].(float64)
|
||||
if !ok {
|
||||
t.Fatalf("expected numeric total field, got %T", payload["total"])
|
||||
}
|
||||
if total != 2 {
|
||||
t.Fatalf("expected total=2, got %v", total)
|
||||
}
|
||||
|
||||
engines, ok := payload["engines"].([]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("expected engines array, got %T", payload["engines"])
|
||||
}
|
||||
if len(engines) != 2 {
|
||||
t.Fatalf("expected 2 engines in payload, got %d", len(engines))
|
||||
}
|
||||
|
||||
byName := map[string]map[string]interface{}{}
|
||||
for _, entry := range engines {
|
||||
engineData, ok := entry.(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("expected engine object, got %T", entry)
|
||||
}
|
||||
name, _ := engineData["name"].(string)
|
||||
if name == "" {
|
||||
t.Fatalf("expected non-empty engine name, got %#v", engineData["name"])
|
||||
}
|
||||
if _, ok := engineData["initialized"].(bool); !ok {
|
||||
t.Fatalf("expected initialized bool for engine %s, got %T", name, engineData["initialized"])
|
||||
}
|
||||
state, ok := engineData["circuit_state"].(string)
|
||||
if !ok || state == "" {
|
||||
t.Fatalf("expected non-empty circuit_state for engine %s, got %#v", name, engineData["circuit_state"])
|
||||
}
|
||||
byName[name] = engineData
|
||||
}
|
||||
|
||||
if _, ok := byName["google"]; !ok {
|
||||
t.Fatal("expected google engine in response")
|
||||
}
|
||||
if _, ok := byName["yandex"]; !ok {
|
||||
t.Fatal("expected yandex engine in response")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatsEndpointStructure(t *testing.T) {
|
||||
engine := &engineMock{name: "google", initialized: true}
|
||||
srv := NewServerWithOptions("127.0.0.1", 7106, DefaultServerOptions(), engine)
|
||||
|
||||
// Ensure circuit breaker stats are initialized.
|
||||
_ = request(t, srv, "/google/search?text=golang")
|
||||
|
||||
resp := request(t, srv, "/stats")
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("expected /stats to return 200, got %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var payload map[string]interface{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
|
||||
t.Fatalf("decode /stats response: %v", err)
|
||||
}
|
||||
|
||||
cache, ok := payload["cache"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("expected cache object, got %T", payload["cache"])
|
||||
}
|
||||
if _, ok := cache["status"].(bool); !ok {
|
||||
t.Fatalf("expected cache.status bool, got %T", cache["status"])
|
||||
}
|
||||
if _, ok := cache["entries"].(float64); !ok {
|
||||
t.Fatalf("expected cache.entries number, got %T", cache["entries"])
|
||||
}
|
||||
if _, ok := cache["hits"].(float64); !ok {
|
||||
t.Fatalf("expected cache.hits number, got %T", cache["hits"])
|
||||
}
|
||||
if _, ok := cache["misses"].(float64); !ok {
|
||||
t.Fatalf("expected cache.misses number, got %T", cache["misses"])
|
||||
}
|
||||
if _, ok := cache["bypasses"].(float64); !ok {
|
||||
t.Fatalf("expected cache.bypasses number, got %T", cache["bypasses"])
|
||||
}
|
||||
|
||||
proxy, ok := payload["proxy"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("expected proxy object, got %T", payload["proxy"])
|
||||
}
|
||||
if _, ok := proxy["configured_count"].(float64); !ok {
|
||||
t.Fatalf("expected proxy.configured_count number, got %T", proxy["configured_count"])
|
||||
}
|
||||
if _, ok := proxy["healthy_count"].(float64); !ok {
|
||||
t.Fatalf("expected proxy.healthy_count number, got %T", proxy["healthy_count"])
|
||||
}
|
||||
if _, ok := proxy["unhealthy_count"].(float64); !ok {
|
||||
t.Fatalf("expected proxy.unhealthy_count number, got %T", proxy["unhealthy_count"])
|
||||
}
|
||||
if _, ok := proxy["tags"].(map[string]interface{}); !ok {
|
||||
t.Fatalf("expected proxy.tags object, got %T", proxy["tags"])
|
||||
}
|
||||
if _, ok := proxy["entries"].([]interface{}); !ok {
|
||||
t.Fatalf("expected proxy.entries array, got %T", proxy["entries"])
|
||||
}
|
||||
|
||||
engines, ok := proxy["engines"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("expected proxy.engines object, got %T", proxy["engines"])
|
||||
}
|
||||
googleStats, ok := engines["google"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("expected proxy.engines.google object, got %T", engines["google"])
|
||||
}
|
||||
if got := googleStats["selected_proxy"]; got != "direct" {
|
||||
t.Fatalf("expected proxy.engines.google.selected_proxy=direct, got %#v", got)
|
||||
}
|
||||
|
||||
breakers, ok := payload["circuit_breakers"].([]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("expected circuit_breakers array, got %T", payload["circuit_breakers"])
|
||||
}
|
||||
if len(breakers) == 0 {
|
||||
t.Fatal("expected at least one circuit breaker entry")
|
||||
}
|
||||
first, ok := breakers[0].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("expected circuit breaker object, got %T", breakers[0])
|
||||
}
|
||||
if _, ok := first["engine"].(string); !ok {
|
||||
t.Fatalf("expected circuit_breakers[0].engine string, got %T", first["engine"])
|
||||
}
|
||||
if _, ok := first["state"].(string); !ok {
|
||||
t.Fatalf("expected circuit_breakers[0].state string, got %T", first["state"])
|
||||
}
|
||||
if _, ok := first["failure_count"].(float64); !ok {
|
||||
t.Fatalf("expected circuit_breakers[0].failure_count number, got %T", first["failure_count"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealthEndpointStatusSemantics(t *testing.T) {
|
||||
ready := &engineMock{name: "google", initialized: true, limiter: rate.NewLimiter(rate.Every(time.Second), 1)}
|
||||
notReady := &engineMock{name: "yandex", initialized: false, limiter: rate.NewLimiter(rate.Every(time.Second), 1)}
|
||||
|
||||
@@ -11,30 +11,98 @@ func TestBuildURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
query core.Query
|
||||
page int
|
||||
wantErr bool
|
||||
check func(*testing.T, url.Values, string)
|
||||
}{
|
||||
{
|
||||
name: "basic search",
|
||||
query: core.Query{Text: "golang programming"},
|
||||
page: 0,
|
||||
check: func(t *testing.T, params url.Values, host string) {
|
||||
t.Helper()
|
||||
if host != "duckduckgo.com" {
|
||||
t.Fatalf("unexpected host: %s", host)
|
||||
}
|
||||
if got := params.Get("q"); got != "golang programming" {
|
||||
t.Fatalf("unexpected q value: %q", got)
|
||||
}
|
||||
if got := params.Get("ia"); got != "web" {
|
||||
t.Fatalf("unexpected ia value: %q", got)
|
||||
}
|
||||
if got := params.Get("t"); got != "h" {
|
||||
t.Fatalf("unexpected t value: %q", got)
|
||||
}
|
||||
if got := params.Get("s"); got != "" {
|
||||
t.Fatalf("s should be omitted on first page, got %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "search with site filter",
|
||||
query: core.Query{Text: "golang", Site: "github.com"},
|
||||
name: "combined params with unicode",
|
||||
query: core.Query{
|
||||
Text: "поиск",
|
||||
Site: "github.com",
|
||||
Filetype: "pdf",
|
||||
LangCode: "RU-ru",
|
||||
DateInterval: "20240101..20240131",
|
||||
},
|
||||
page: 0,
|
||||
check: func(t *testing.T, params url.Values, _ string) {
|
||||
t.Helper()
|
||||
if got := params.Get("q"); got != "поиск site:github.com filetype:pdf" {
|
||||
t.Fatalf("unexpected q value: %q", got)
|
||||
}
|
||||
if got := params.Get("df"); got != "2024-01-01..2024-01-31" {
|
||||
t.Fatalf("unexpected df value: %q", got)
|
||||
}
|
||||
if got := params.Get("kl"); got != "ru-ru" {
|
||||
t.Fatalf("unexpected kl value: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "search with filetype",
|
||||
query: core.Query{Text: "documentation", Filetype: "pdf"},
|
||||
name: "very large page offset",
|
||||
query: core.Query{Text: "golang"},
|
||||
page: 100000,
|
||||
check: func(t *testing.T, params url.Values, _ string) {
|
||||
t.Helper()
|
||||
if got := params.Get("s"); got != "2500000" {
|
||||
t.Fatalf("unexpected pagination offset: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty query",
|
||||
query: core.Query{Text: ""},
|
||||
name: "negative page does not add offset",
|
||||
query: core.Query{Text: "golang"},
|
||||
page: -1,
|
||||
check: func(t *testing.T, params url.Values, _ string) {
|
||||
t.Helper()
|
||||
if got := params.Get("s"); got != "" {
|
||||
t.Fatalf("expected empty offset for negative page, got %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid date interval returns error",
|
||||
query: core.Query{
|
||||
Text: "golang",
|
||||
DateInterval: "invalid",
|
||||
},
|
||||
page: 0,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty query returns error",
|
||||
query: core.Query{},
|
||||
page: 0,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := BuildURL(tt.query, 0)
|
||||
got, err := BuildURL(tt.query, tt.page)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Fatalf("BuildURL() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
@@ -46,15 +114,8 @@ func TestBuildURL(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("BuildURL() returned invalid URL: %v", err)
|
||||
}
|
||||
params := parsed.Query()
|
||||
if params.Get("q") == "" {
|
||||
t.Fatalf("BuildURL() should include q parameter, got %s", got)
|
||||
}
|
||||
if params.Get("ia") != "web" {
|
||||
t.Fatalf("BuildURL() should include ia=web, got %s", got)
|
||||
}
|
||||
if params.Get("t") != "h" {
|
||||
t.Fatalf("BuildURL() should include t=h, got %s", got)
|
||||
if tt.check != nil {
|
||||
tt.check(t, parsed.Query(), parsed.Host)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -65,14 +126,47 @@ func TestBuildImageURL(t *testing.T) {
|
||||
name string
|
||||
query core.Query
|
||||
wantErr bool
|
||||
check func(*testing.T, url.Values, string)
|
||||
}{
|
||||
{
|
||||
name: "basic image search",
|
||||
query: core.Query{Text: "golang logo"},
|
||||
name: "combined params with unicode",
|
||||
query: core.Query{
|
||||
Text: "горы",
|
||||
Site: "example.com",
|
||||
Filetype: "jpg",
|
||||
LangCode: "RU",
|
||||
DateInterval: "20240201..20240229",
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, host string) {
|
||||
t.Helper()
|
||||
if host != "duckduckgo.com" {
|
||||
t.Fatalf("unexpected host: %s", host)
|
||||
}
|
||||
if got := params.Get("q"); got != "горы site:example.com filetype:jpg" {
|
||||
t.Fatalf("unexpected q value: %q", got)
|
||||
}
|
||||
if got := params.Get("iax"); got != "images" || params.Get("ia") != "images" {
|
||||
t.Fatalf("expected image mode params, got iax=%q ia=%q", params.Get("iax"), params.Get("ia"))
|
||||
}
|
||||
if got := params.Get("df"); got != "2024-02-01..2024-02-29" {
|
||||
t.Fatalf("unexpected df value: %q", got)
|
||||
}
|
||||
if got := params.Get("kl"); got != "ru" {
|
||||
t.Fatalf("unexpected kl value: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty query",
|
||||
query: core.Query{Text: ""},
|
||||
name: "invalid date interval returns error",
|
||||
query: core.Query{
|
||||
Text: "golang",
|
||||
DateInterval: "202401",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty query returns error",
|
||||
query: core.Query{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
@@ -91,12 +185,8 @@ func TestBuildImageURL(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("BuildImageURL() returned invalid URL: %v", err)
|
||||
}
|
||||
params := parsed.Query()
|
||||
if params.Get("q") == "" {
|
||||
t.Fatalf("BuildImageURL() should include q parameter, got %s", got)
|
||||
}
|
||||
if params.Get("iax") != "images" || params.Get("ia") != "images" {
|
||||
t.Fatalf("BuildImageURL() should target image mode, got %s", got)
|
||||
if tt.check != nil {
|
||||
tt.check(t, parsed.Query(), parsed.Host)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,11 +1,218 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/karust/openserp/core"
|
||||
)
|
||||
|
||||
func TestBuildSearchURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
query core.Query
|
||||
wantErr bool
|
||||
check func(*testing.T, url.Values, string)
|
||||
}{
|
||||
{
|
||||
name: "combined params with unicode and start zero",
|
||||
query: core.Query{
|
||||
Text: "golang тест",
|
||||
Site: "example.com",
|
||||
Filetype: "pdf",
|
||||
DateInterval: "20240101..20240131",
|
||||
Limit: 50,
|
||||
Start: 0,
|
||||
Filter: false,
|
||||
LangCode: "RU",
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, host string) {
|
||||
t.Helper()
|
||||
if host != "www.google.ru" {
|
||||
t.Fatalf("unexpected host: %s", host)
|
||||
}
|
||||
if got := params.Get("q"); got != "golang тест site:example.com filetype:pdf" {
|
||||
t.Fatalf("unexpected q value: %q", got)
|
||||
}
|
||||
if got := params.Get("oq"); got != params.Get("q") {
|
||||
t.Fatalf("oq should match q, got %q vs %q", got, params.Get("q"))
|
||||
}
|
||||
if got := params.Get("tbs"); got != "cdr:1,cd_min:20240101,cd_max:20240131" {
|
||||
t.Fatalf("unexpected tbs: %q", got)
|
||||
}
|
||||
if got := params.Get("num"); got != "50" {
|
||||
t.Fatalf("unexpected num: %q", got)
|
||||
}
|
||||
if got := params.Get("start"); got != "" {
|
||||
t.Fatalf("start should be omitted when Start=0, got %q", got)
|
||||
}
|
||||
if got := params.Get("filter"); got != "0" {
|
||||
t.Fatalf("unexpected filter value: %q", got)
|
||||
}
|
||||
if got := params.Get("hl"); got != "RU" {
|
||||
t.Fatalf("unexpected hl value: %q", got)
|
||||
}
|
||||
if got := params.Get("lr"); got != "lang_ru" {
|
||||
t.Fatalf("unexpected lr value: %q", got)
|
||||
}
|
||||
if got := params.Get("pws"); got != "0" {
|
||||
t.Fatalf("unexpected pws value: %q", got)
|
||||
}
|
||||
if got := params.Get("nfpr"); got != "1" {
|
||||
t.Fatalf("unexpected nfpr value: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "site and filetype without text",
|
||||
query: core.Query{
|
||||
Site: "example.com",
|
||||
Filetype: "txt",
|
||||
Filter: true,
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, _ string) {
|
||||
t.Helper()
|
||||
if got := params.Get("q"); got != " site:example.com filetype:txt" {
|
||||
t.Fatalf("unexpected q value: %q", got)
|
||||
}
|
||||
if got := params.Get("filter"); got != "" {
|
||||
t.Fatalf("filter should be omitted when Filter=true, got %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "very large start",
|
||||
query: core.Query{
|
||||
Text: "golang",
|
||||
Start: 2147483647,
|
||||
Filter: true,
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, _ string) {
|
||||
t.Helper()
|
||||
if got := params.Get("start"); got != "2147483647" {
|
||||
t.Fatalf("unexpected start value: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "negative start returns error",
|
||||
query: core.Query{
|
||||
Text: "golang",
|
||||
Start: -1,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty query returns error",
|
||||
query: core.Query{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := BuildURL(tt.query)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Fatalf("BuildURL() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
if tt.wantErr {
|
||||
return
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(got)
|
||||
if err != nil {
|
||||
t.Fatalf("invalid URL returned: %v", err)
|
||||
}
|
||||
if tt.check != nil {
|
||||
tt.check(t, parsed.Query(), parsed.Host)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildImageSearchURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
query core.Query
|
||||
wantErr bool
|
||||
check func(*testing.T, url.Values, string)
|
||||
}{
|
||||
{
|
||||
name: "combined params with unicode",
|
||||
query: core.Query{
|
||||
Text: "горы",
|
||||
Site: "example.com",
|
||||
Filetype: "jpg",
|
||||
DateInterval: "20240301..20240315",
|
||||
Limit: 25,
|
||||
LangCode: "EN",
|
||||
},
|
||||
check: func(t *testing.T, params url.Values, host string) {
|
||||
t.Helper()
|
||||
if host != "www.google.com" {
|
||||
t.Fatalf("unexpected host: %s", host)
|
||||
}
|
||||
if got := params.Get("tbm"); got != "isch" {
|
||||
t.Fatalf("unexpected tbm: %q", got)
|
||||
}
|
||||
if got := params.Get("q"); got != "горы site:example.com filetype:jpg" {
|
||||
t.Fatalf("unexpected q value: %q", got)
|
||||
}
|
||||
if got := params.Get("oq"); got != params.Get("q") {
|
||||
t.Fatalf("oq should match q, got %q vs %q", got, params.Get("q"))
|
||||
}
|
||||
if got := params.Get("num"); got != "25" {
|
||||
t.Fatalf("unexpected num value: %q", got)
|
||||
}
|
||||
if got := params.Get("tbs"); got != "cdr:1,cd_min:20240301,cd_max:20240315" {
|
||||
t.Fatalf("unexpected tbs value: %q", got)
|
||||
}
|
||||
if got := params.Get("hl"); got != "EN" {
|
||||
t.Fatalf("unexpected hl value: %q", got)
|
||||
}
|
||||
if got := params.Get("lr"); got != "lang_en" {
|
||||
t.Fatalf("unexpected lr value: %q", got)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid date interval returns error",
|
||||
query: core.Query{
|
||||
Text: "golang",
|
||||
DateInterval: "20240101",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty query returns error",
|
||||
query: core.Query{
|
||||
Text: "",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := BuildImageURL(tt.query)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Fatalf("BuildImageURL() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
if tt.wantErr {
|
||||
return
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(got)
|
||||
if err != nil {
|
||||
t.Fatalf("invalid URL returned: %v", err)
|
||||
}
|
||||
if tt.check != nil {
|
||||
tt.check(t, parsed.Query(), parsed.Host)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSourceImageURL(t *testing.T) {
|
||||
//href1 := `/imgres?imgurl=https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2F2%2F26%2FMarmota_marmota_Alpes2.jpg&tbnid=Be_RycOe8xzlpM&vet=12ahUKEwjkh6WzwIeAAxWV_yoKHRzHC9wQMygAegUIARD0AQ..i&imgrefurl=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FAlpine_marmot&docid=7miWbc2QiSw9uM&w=801&h=599&q=alpine%20marmot&ved=2ahUKEwjkh6WzwIeAAxWV_yoKHRzHC9wQMygAegUIARD0AQ`
|
||||
href2 := `/imgres?imgurl=https%3A%2F%2Fstatic.wikia.nocookie.net%2Fnaturerules1%2Fimages%2Ff%2Ff2%2F13d79d934ccf6f7919777fcb6dbb6e6c.jpg%2Frevision%2Flatest%3Fcb%3D20210218225522&tbnid=JxC8NUyBjdNbdM&vet=12ahUKEwiHrJnN1YeAAxXvEBAIHfRADAAQMygCegUIARD4AQ..i&imgrefurl=https%3A%2F%2Fnaturerules1.fandom.com%2Fwiki%2FAlpine_Marmot&docid=XXYeDjL67badNM&w=1600&h=1200&q=alpine%20marmot&ved=2ahUKEwiHrJnN1YeAAxXvEBAIHfRADAAQMygCegUIARD4AQ`
|
||||
|
||||
Reference in New Issue
Block a user