mirror of
https://github.com/AdguardTeam/AdGuardDNS.git
synced 2025-02-20 11:23:36 +08:00
196 lines
5.3 KiB
Go
196 lines
5.3 KiB
Go
package debugsvc_test
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/AdguardTeam/AdGuardDNS/internal/agdcache"
|
|
"github.com/AdguardTeam/AdGuardDNS/internal/agdhttp"
|
|
"github.com/AdguardTeam/AdGuardDNS/internal/agdtest"
|
|
"github.com/AdguardTeam/AdGuardDNS/internal/debugsvc"
|
|
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
|
"github.com/AdguardTeam/golibs/netutil/httputil"
|
|
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
|
"github.com/AdguardTeam/golibs/testutil"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TODO(a.garipov): Improve and split tests.
|
|
|
|
// testTimeout is a common timeout for tests.
|
|
const testTimeout = 1 * time.Second
|
|
|
|
func TestService_Start(t *testing.T) {
|
|
// TODO(a.garipov): Consider adding an HTTP server constructor as a part of
|
|
// the configuration structure to use net/http/httptest's server in tests.
|
|
const addr = "127.0.0.1:8082"
|
|
h := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
pt := testutil.PanicT{}
|
|
|
|
_, err := w.Write([]byte("[]"))
|
|
require.NoError(pt, err)
|
|
})
|
|
|
|
var refreshed []string
|
|
refreshers := debugsvc.Refreshers{
|
|
"test": &agdtest.Refresher{
|
|
OnRefresh: func(_ context.Context) (err error) {
|
|
refreshed = append(refreshed, "test")
|
|
|
|
return nil
|
|
},
|
|
},
|
|
"parent/first": &agdtest.Refresher{
|
|
OnRefresh: func(_ context.Context) (err error) {
|
|
refreshed = append(refreshed, "parent/first")
|
|
|
|
return nil
|
|
},
|
|
},
|
|
"parent/second": &agdtest.Refresher{
|
|
OnRefresh: func(_ context.Context) (err error) {
|
|
refreshed = append(refreshed, "parent/second")
|
|
|
|
return nil
|
|
},
|
|
},
|
|
}
|
|
|
|
cacheManager := agdcache.NewDefaultManager()
|
|
cacheManager.Add("test", agdcache.Empty[any, any]{})
|
|
|
|
c := &debugsvc.Config{
|
|
Logger: slogutil.NewDiscardLogger(),
|
|
DNSDBAddr: addr,
|
|
DNSDBHandler: h,
|
|
Manager: cacheManager,
|
|
Refreshers: refreshers,
|
|
APIAddr: addr,
|
|
PprofAddr: addr,
|
|
PrometheusAddr: addr,
|
|
}
|
|
|
|
svc := debugsvc.New(c)
|
|
require.NotNil(t, svc)
|
|
|
|
var err error
|
|
require.NotPanics(t, func() {
|
|
err = svc.Start(testutil.ContextWithTimeout(t, testTimeout))
|
|
})
|
|
require.NoError(t, err)
|
|
testutil.CleanupAndRequireSuccess(t, func() (err error) {
|
|
return svc.Shutdown(testutil.ContextWithTimeout(t, testTimeout))
|
|
})
|
|
|
|
client := agdhttp.NewClient(&agdhttp.ClientConfig{
|
|
Timeout: testTimeout,
|
|
})
|
|
|
|
srvURL := &url.URL{
|
|
Scheme: urlutil.SchemeHTTP,
|
|
Host: addr,
|
|
}
|
|
|
|
// Use a context without a timeout, since it is used with agdhttp.Client,
|
|
// which already has a timeout.
|
|
ctx := context.Background()
|
|
|
|
// First check health-check service URL. As the service could not be ready
|
|
// yet, check for it in periodically.
|
|
var resp *http.Response
|
|
healthCheckURL := srvURL.JoinPath(debugsvc.PathPatternHealthCheck)
|
|
require.Eventually(t, func() (ok bool) {
|
|
resp, err = client.Get(ctx, healthCheckURL)
|
|
|
|
return err == nil
|
|
}, testTimeout, testTimeout/10)
|
|
|
|
body := readRespBody(t, resp)
|
|
assert.Equal(t, "OK\n", body)
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
// Check pprof service URL.
|
|
resp, err = client.Get(ctx, srvURL.JoinPath(httputil.PprofBasePath))
|
|
require.NoError(t, err)
|
|
|
|
body = readRespBody(t, resp)
|
|
assert.True(t, len(body) > 0)
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
// Check prometheus service URL.
|
|
resp, err = client.Get(ctx, srvURL.JoinPath(debugsvc.PathPatternMetrics))
|
|
require.NoError(t, err)
|
|
|
|
body = readRespBody(t, resp)
|
|
assert.True(t, len(body) > 0)
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
// Check refresh API.
|
|
|
|
reqBody := strings.NewReader(`{"ids":["test"]}`)
|
|
refreshURL := srvURL.JoinPath(debugsvc.PathPatternDebugAPIRefresh)
|
|
resp, err = client.Post(ctx, refreshURL, agdhttp.HdrValApplicationJSON, reqBody)
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, refreshed, 1)
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
respBody := readRespBody(t, resp)
|
|
assert.JSONEq(t, `{"results":{"test":"ok"}}`, respBody)
|
|
|
|
refreshed = []string{}
|
|
|
|
reqBody = strings.NewReader(`{"ids":["parent/*"]}`)
|
|
resp, err = client.Post(ctx, refreshURL, agdhttp.HdrValApplicationJSON, reqBody)
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, refreshed, 2)
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
respBody = readRespBody(t, resp)
|
|
assert.JSONEq(t, `{"results":{"parent/first":"ok","parent/second":"ok"}}`, respBody)
|
|
|
|
refreshed = []string{}
|
|
|
|
reqBody = strings.NewReader(`{"ids":["test","*"]}`)
|
|
resp, err = client.Post(ctx, refreshURL, agdhttp.HdrValApplicationJSON, reqBody)
|
|
require.NoError(t, err)
|
|
|
|
assert.Empty(t, refreshed)
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
|
|
respBody = readRespBody(t, resp)
|
|
assert.Equal(t, `"*" cannot be used with other ids`+"\n", respBody)
|
|
|
|
// Check cache purge API.
|
|
|
|
const (
|
|
clearReq = `{"ids":["test"]}`
|
|
clearResp = `{"results":{"test":"ok"}}`
|
|
)
|
|
|
|
reqBody = strings.NewReader(clearReq)
|
|
cacheURL := srvURL.JoinPath(debugsvc.PathPatternDebugAPICache)
|
|
resp, err = client.Post(ctx, cacheURL, agdhttp.HdrValApplicationJSON, reqBody)
|
|
require.NoError(t, err)
|
|
|
|
respBody = readRespBody(t, resp)
|
|
assert.JSONEq(t, clearResp, respBody)
|
|
}
|
|
|
|
// readRespBody is a helper function that reads and returns body from response.
|
|
func readRespBody(t testing.TB, resp *http.Response) (body string) {
|
|
t.Helper()
|
|
|
|
buf, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
|
|
return string(buf)
|
|
}
|