feat: build Go-based SearXNG-compatible search service
Implement an API-first Go rewrite with local engine adapters, upstream fallback, and Nix-based tooling so searches can run without matching the original UI while preserving response compatibility. Made-with: Cursor
This commit is contained in:
parent
7783367c71
commit
dc44837219
32 changed files with 3330 additions and 0 deletions
94
internal/engines/qwant_test.go
Normal file
94
internal/engines/qwant_test.go
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
package engines
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/ashie/gosearch/internal/contracts"
|
||||
)
|
||||
|
||||
func TestQwantEngine_Web(t *testing.T) {
|
||||
transport := roundTripperFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method != http.MethodGet {
|
||||
return httpResponse(http.StatusMethodNotAllowed, "", ""), nil
|
||||
}
|
||||
if r.URL.Host != "api.qwant.com" {
|
||||
return httpResponse(http.StatusNotFound, "", ""), nil
|
||||
}
|
||||
if r.URL.Path != "/v3/search/web" {
|
||||
t.Fatalf("unexpected path: %s", r.URL.Path)
|
||||
}
|
||||
|
||||
q := r.URL.Query().Get("q")
|
||||
if q != "hugo" {
|
||||
t.Fatalf("unexpected q: %q", q)
|
||||
}
|
||||
if r.URL.Query().Get("count") != "10" {
|
||||
t.Fatalf("unexpected count: %q", r.URL.Query().Get("count"))
|
||||
}
|
||||
if r.URL.Query().Get("locale") != "en_US" {
|
||||
t.Fatalf("unexpected locale: %q", r.URL.Query().Get("locale"))
|
||||
}
|
||||
if r.URL.Query().Get("safesearch") != "0" {
|
||||
t.Fatalf("unexpected safesearch: %q", r.URL.Query().Get("safesearch"))
|
||||
}
|
||||
if r.URL.Query().Get("llm") != "false" {
|
||||
t.Fatalf("unexpected llm: %q", r.URL.Query().Get("llm"))
|
||||
}
|
||||
if r.URL.Query().Get("tgp") != "3" {
|
||||
t.Fatalf("unexpected tgp: %q", r.URL.Query().Get("tgp"))
|
||||
}
|
||||
if r.URL.Query().Get("offset") != "0" {
|
||||
t.Fatalf("unexpected offset: %q", r.URL.Query().Get("offset"))
|
||||
}
|
||||
|
||||
body := `{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"result": {
|
||||
"items": {
|
||||
"mainline": [
|
||||
{
|
||||
"type": "web",
|
||||
"items": [
|
||||
{ "title": "Qwant Title", "url": "https://example.com/q", "desc": "Qwant description" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
return httpResponse(http.StatusOK, body, "application/json"), nil
|
||||
})
|
||||
|
||||
client := &http.Client{Transport: transport}
|
||||
engine := &QwantEngine{client: client, category: "web", resultsPerPage: 10}
|
||||
|
||||
resp, err := engine.Search(context.Background(), contracts.SearchRequest{
|
||||
Query: "hugo",
|
||||
Pageno: 1,
|
||||
Safesearch: 0,
|
||||
Language: "en",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if len(resp.Results) != 1 {
|
||||
t.Fatalf("expected 1 result, got %d", len(resp.Results))
|
||||
}
|
||||
if resp.Results[0].Title != "Qwant Title" {
|
||||
t.Fatalf("unexpected title: %q", resp.Results[0].Title)
|
||||
}
|
||||
if resp.Results[0].Content != "Qwant description" {
|
||||
t.Fatalf("unexpected content: %q", resp.Results[0].Content)
|
||||
}
|
||||
if resp.Results[0].URL == nil || *resp.Results[0].URL != "https://example.com/q" {
|
||||
t.Fatalf("unexpected url: %v", resp.Results[0].URL)
|
||||
}
|
||||
if resp.Results[0].Engine != "qwant" {
|
||||
t.Fatalf("unexpected engine: %q", resp.Results[0].Engine)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue