152 lines
4.3 KiB
Go
152 lines
4.3 KiB
Go
|
|
package whois
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"net/http"
|
||
|
|
"net/http/httptest"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
"sync/atomic"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestRDAPClientQueryDomain(t *testing.T) {
|
||
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
|
|
if r.URL.Path != "/rdap/domain/example.com" {
|
||
|
|
http.NotFound(w, r)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
w.Header().Set("Content-Type", "application/rdap+json")
|
||
|
|
_, _ = w.Write([]byte(`{"objectClassName":"domain","ldhName":"example.com"}`))
|
||
|
|
}))
|
||
|
|
defer srv.Close()
|
||
|
|
|
||
|
|
boot := &RDAPBootstrap{
|
||
|
|
Version: "1.0",
|
||
|
|
Services: []RDAPService{
|
||
|
|
{
|
||
|
|
TLDs: []string{"com"},
|
||
|
|
URLs: []string{srv.URL + "/rdap/"},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
c, err := NewRDAPClientWithBootstrap(boot)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("NewRDAPClientWithBootstrap() error: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
resp, err := c.QueryDomain(context.Background(), "example.com")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("QueryDomain() error: %v", err)
|
||
|
|
}
|
||
|
|
if resp.StatusCode != http.StatusOK {
|
||
|
|
t.Fatalf("unexpected status: %d", resp.StatusCode)
|
||
|
|
}
|
||
|
|
if !strings.Contains(string(resp.Body), `"ldhName":"example.com"`) {
|
||
|
|
t.Fatalf("unexpected body: %s", string(resp.Body))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRDAPClientQueryDomainJSON(t *testing.T) {
|
||
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
|
|
if r.URL.Path != "/domain/example.org" {
|
||
|
|
http.NotFound(w, r)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
_, _ = w.Write([]byte(`{"ldhName":"example.org","status":["active"]}`))
|
||
|
|
}))
|
||
|
|
defer srv.Close()
|
||
|
|
|
||
|
|
c, err := NewRDAPClientWithBootstrap(&RDAPBootstrap{
|
||
|
|
Version: "1.0",
|
||
|
|
Services: []RDAPService{
|
||
|
|
{TLDs: []string{"org"}, URLs: []string{srv.URL}},
|
||
|
|
},
|
||
|
|
})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("NewRDAPClientWithBootstrap() error: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
var out map[string]any
|
||
|
|
_, err = c.QueryDomainJSON(context.Background(), "example.org", &out)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("QueryDomainJSON() error: %v", err)
|
||
|
|
}
|
||
|
|
if out["ldhName"] != "example.org" {
|
||
|
|
t.Fatalf("unexpected json field: %#v", out)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestNewRDAPClientWithLayeredBootstrap(t *testing.T) {
|
||
|
|
rdapSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
|
|
if r.URL.Path != "/rdap/domain/example.dev" {
|
||
|
|
http.NotFound(w, r)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
_, _ = w.Write([]byte(`{"objectClassName":"domain","ldhName":"example.dev"}`))
|
||
|
|
}))
|
||
|
|
defer rdapSrv.Close()
|
||
|
|
|
||
|
|
localRaw := `{"version":"1.0","services":[[["dev"],["` + rdapSrv.URL + `/rdap/"]]]}`
|
||
|
|
localPath := filepath.Join(t.TempDir(), "rdap_local.json")
|
||
|
|
if err := os.WriteFile(localPath, []byte(localRaw), 0644); err != nil {
|
||
|
|
t.Fatalf("write local bootstrap failed: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
c, err := NewRDAPClientWithLayeredBootstrap(context.Background(), RDAPBootstrapLoadOptions{
|
||
|
|
LocalFiles: []string{localPath},
|
||
|
|
})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("NewRDAPClientWithLayeredBootstrap() error: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
resp, err := c.QueryDomain(context.Background(), "example.dev")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("QueryDomain() error: %v", err)
|
||
|
|
}
|
||
|
|
if resp.StatusCode != http.StatusOK || !strings.Contains(string(resp.Body), `"example.dev"`) {
|
||
|
|
t.Fatalf("unexpected response: status=%d body=%s", resp.StatusCode, string(resp.Body))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestNewRDAPClientWithLayeredBootstrapCacheTTL(t *testing.T) {
|
||
|
|
cacheKey := t.Name() + "-cache"
|
||
|
|
ClearRDAPBootstrapLayeredCache(cacheKey)
|
||
|
|
|
||
|
|
var bootstrapHit int32
|
||
|
|
bootstrapRaw := `{"version":"2.0","services":[[["dev"],["https://rdap.example.dev/rdap/"]]]}`
|
||
|
|
bootstrapSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
|
|
atomic.AddInt32(&bootstrapHit, 1)
|
||
|
|
w.Header().Set("Content-Type", "application/json")
|
||
|
|
_, _ = w.Write([]byte(bootstrapRaw))
|
||
|
|
}))
|
||
|
|
defer bootstrapSrv.Close()
|
||
|
|
|
||
|
|
loadOpt := RDAPBootstrapLoadOptions{
|
||
|
|
RefreshRemote: true,
|
||
|
|
RemoteURL: bootstrapSrv.URL,
|
||
|
|
CacheTTL: time.Minute,
|
||
|
|
CacheKey: cacheKey,
|
||
|
|
}
|
||
|
|
|
||
|
|
c1, err := NewRDAPClientWithLayeredBootstrap(context.Background(), loadOpt)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("first NewRDAPClientWithLayeredBootstrap() error: %v", err)
|
||
|
|
}
|
||
|
|
if c1 == nil {
|
||
|
|
t.Fatal("first client should not be nil")
|
||
|
|
}
|
||
|
|
c2, err := NewRDAPClientWithLayeredBootstrap(context.Background(), loadOpt)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("second NewRDAPClientWithLayeredBootstrap() error: %v", err)
|
||
|
|
}
|
||
|
|
if c2 == nil {
|
||
|
|
t.Fatal("second client should not be nil")
|
||
|
|
}
|
||
|
|
if got := atomic.LoadInt32(&bootstrapHit); got != 1 {
|
||
|
|
t.Fatalf("expected cached bootstrap to fetch remote once, got=%d", got)
|
||
|
|
}
|
||
|
|
}
|