adguardhome/context_test.go
Rama main · réplica de lectura del repositorio original.
package adguardhome
import (
"context"
"errors"
"io"
"net/http"
"net/http/httptest"
"strings"
"sync/atomic"
"testing"
"time"
)
func TestProviderConstructionDoesNotMakeHTTPRequests(t *testing.T) {
var requests atomic.Int32
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
requests.Add(1)
http.Error(w, "unavailable", http.StatusServiceUnavailable)
}))
defer s.Close()
t.Setenv(envURL, s.URL)
t.Setenv(envUser, "test-user")
t.Setenv(envPassword, "test-password")
t.Setenv(envUseDNSRewrite, "true")
p, err := NewAdguardHomeProvider(context.Background(), false)
if err != nil {
t.Fatalf("construction must not depend on AdGuard availability: %v", err)
}
if requests.Load() != 0 {
t.Fatalf("constructor made %d HTTP requests", requests.Load())
}
if err = p.Initialize(context.Background()); err == nil {
t.Fatal("explicit initialization must report the HTTP failure")
}
if requests.Load() != 1 {
t.Fatalf("initialization made %d HTTP requests, want 1", requests.Load())
}
}
func TestInitializationCancellation(t *testing.T) {
started := make(chan struct{})
cancelled := make(chan struct{})
s := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
close(started)
<-r.Context().Done()
close(cancelled)
}))
defer s.Close()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
p := &AdguardHomeProvider{client: newAdguardHomeClient(context.Background(), s.URL+"/", "test", "test", false), ruleFormat: rewriteRuleFormat()}
result := make(chan error, 1)
go func() { result <- p.Initialize(ctx) }()
select {
case <-started:
case <-time.After(5 * time.Second):
t.Fatal("initialization request did not start")
}
cancel()
select {
case err := <-result:
if !errors.Is(err, context.Canceled) {
t.Fatalf("initialization error=%v, want context cancellation", err)
}
case <-time.After(5 * time.Second):
t.Fatal("initialization ignored cancellation")
}
select {
case <-cancelled:
case <-time.After(5 * time.Second):
t.Fatal("outgoing HTTP request ignored cancellation")
}
}
type contextTestTransport func(*http.Request) (*http.Response, error)
func (f contextTestTransport) RoundTrip(r *http.Request) (*http.Response, error) {
return f(r)
}
func TestClientPropagatesRequestContext(t *testing.T) {
for _, method := range []string{http.MethodGet, http.MethodPost} {
t.Run(method, func(t *testing.T) {
type contextKey struct{}
ctx, cancel := context.WithTimeout(context.WithValue(context.Background(), contextKey{}, "request-value"), 5*time.Second)
defer cancel()
wantDeadline, _ := ctx.Deadline()
requests := 0
c := newAdguardHomeClient(context.Background(), "http://adguard.test/control/", "test", "test", false)
c.hc.Transport = contextTestTransport(func(r *http.Request) (*http.Response, error) {
requests++
deadline, ok := r.Context().Deadline()
if r.Method != method || r.Context().Value(contextKey{}) != "request-value" || !ok || deadline != wantDeadline {
t.Errorf("HTTP request did not inherit method, deadline and values")
}
return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(strings.NewReader(`{"user_rules":[]}`))}, nil
})
var err error
if method == http.MethodGet {
_, err = c.GetFilteringRules(ctx)
} else {
err = c.SaveFilteringRules(ctx, []string{"# test rule"})
}
if err != nil || requests != 1 {
t.Fatalf("HTTP request error=%v, count=%d", err, requests)
}
})
}
}
func TestInitializeCancelledBeforeRequest(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
p := &AdguardHomeProvider{}
if err := p.Initialize(ctx); !errors.Is(err, context.Canceled) {
t.Fatalf("initialization error=%v, want context cancellation", err)
}
}