all: add tests; imp errors
This commit is contained in:
@@ -33,5 +33,5 @@ func Error(r *http.Request, w http.ResponseWriter, code int, format string, args
|
|||||||
// UserAgent returns the ID of the service as a User-Agent string. It can also
|
// UserAgent returns the ID of the service as a User-Agent string. It can also
|
||||||
// be used as the value of the Server HTTP header.
|
// be used as the value of the Server HTTP header.
|
||||||
func UserAgent() (ua string) {
|
func UserAgent() (ua string) {
|
||||||
return fmt.Sprintf("AdGuardDNS/%s", version.Version())
|
return fmt.Sprintf("AdGuardHome/%s", version.Version())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package aghtest
|
package aghtest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
@@ -15,6 +16,8 @@ import (
|
|||||||
|
|
||||||
// Standard Library
|
// Standard Library
|
||||||
|
|
||||||
|
// Package fs
|
||||||
|
|
||||||
// type check
|
// type check
|
||||||
var _ fs.FS = &FS{}
|
var _ fs.FS = &FS{}
|
||||||
|
|
||||||
@@ -58,6 +61,8 @@ func (fsys *StatFS) Stat(name string) (fs.FileInfo, error) {
|
|||||||
return fsys.OnStat(name)
|
return fsys.OnStat(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Package net
|
||||||
|
|
||||||
// type check
|
// type check
|
||||||
var _ net.Listener = (*Listener)(nil)
|
var _ net.Listener = (*Listener)(nil)
|
||||||
|
|
||||||
@@ -83,32 +88,10 @@ func (l *Listener) Close() (err error) {
|
|||||||
return l.OnClose()
|
return l.OnClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Module dnsproxy
|
|
||||||
|
|
||||||
// type check
|
|
||||||
var _ upstream.Upstream = (*UpstreamMock)(nil)
|
|
||||||
|
|
||||||
// UpstreamMock is a mock [upstream.Upstream] implementation for tests.
|
|
||||||
//
|
|
||||||
// TODO(a.garipov): Replace with all uses of Upstream with UpstreamMock and
|
|
||||||
// rename it to just Upstream.
|
|
||||||
type UpstreamMock struct {
|
|
||||||
OnAddress func() (addr string)
|
|
||||||
OnExchange func(req *dns.Msg) (resp *dns.Msg, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Address implements the [upstream.Upstream] interface for *UpstreamMock.
|
|
||||||
func (u *UpstreamMock) Address() (addr string) {
|
|
||||||
return u.OnAddress()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exchange implements the [upstream.Upstream] interface for *UpstreamMock.
|
|
||||||
func (u *UpstreamMock) Exchange(req *dns.Msg) (resp *dns.Msg, err error) {
|
|
||||||
return u.OnExchange(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Module AdGuardHome
|
// Module AdGuardHome
|
||||||
|
|
||||||
|
// Package aghos
|
||||||
|
|
||||||
// type check
|
// type check
|
||||||
var _ aghos.FSWatcher = (*FSWatcher)(nil)
|
var _ aghos.FSWatcher = (*FSWatcher)(nil)
|
||||||
|
|
||||||
@@ -133,3 +116,57 @@ func (w *FSWatcher) Add(name string) (err error) {
|
|||||||
func (w *FSWatcher) Close() (err error) {
|
func (w *FSWatcher) Close() (err error) {
|
||||||
return w.OnClose()
|
return w.OnClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Package websvc
|
||||||
|
|
||||||
|
// ServiceWithConfig is a mock [websvc.ServiceWithConfig] implementation for
|
||||||
|
// tests.
|
||||||
|
type ServiceWithConfig[ConfigType any] struct {
|
||||||
|
OnStart func() (err error)
|
||||||
|
OnShutdown func(ctx context.Context) (err error)
|
||||||
|
OnConfig func() (c ConfigType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start implements the [websvc.ServiceWithConfig] interface for
|
||||||
|
// *ServiceWithConfig.
|
||||||
|
func (s *ServiceWithConfig[_]) Start() (err error) {
|
||||||
|
return s.OnStart()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown implements the [websvc.ServiceWithConfig] interface for
|
||||||
|
// *ServiceWithConfig.
|
||||||
|
func (s *ServiceWithConfig[_]) Shutdown(ctx context.Context) (err error) {
|
||||||
|
return s.OnShutdown(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config implements the [websvc.ServiceWithConfig] interface for
|
||||||
|
// *ServiceWithConfig.
|
||||||
|
func (s *ServiceWithConfig[ConfigType]) Config() (c ConfigType) {
|
||||||
|
return s.OnConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Module dnsproxy
|
||||||
|
|
||||||
|
// Package upstream
|
||||||
|
|
||||||
|
// type check
|
||||||
|
var _ upstream.Upstream = (*UpstreamMock)(nil)
|
||||||
|
|
||||||
|
// UpstreamMock is a mock [upstream.Upstream] implementation for tests.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Replace with all uses of Upstream with UpstreamMock and
|
||||||
|
// rename it to just Upstream.
|
||||||
|
type UpstreamMock struct {
|
||||||
|
OnAddress func() (addr string)
|
||||||
|
OnExchange func(req *dns.Msg) (resp *dns.Msg, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address implements the [upstream.Upstream] interface for *UpstreamMock.
|
||||||
|
func (u *UpstreamMock) Address() (addr string) {
|
||||||
|
return u.OnAddress()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exchange implements the [upstream.Upstream] interface for *UpstreamMock.
|
||||||
|
func (u *UpstreamMock) Exchange(req *dns.Msg) (resp *dns.Msg, err error) {
|
||||||
|
return u.OnExchange(req)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package aghtest_test
|
package aghtest_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// type check
|
// type check
|
||||||
var _ aghos.FSWatcher = (*aghtest.FSWatcher)(nil)
|
var _ websvc.ServiceWithConfig[struct{}] = (*aghtest.ServiceWithConfig[struct{}])(nil)
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import (
|
|||||||
|
|
||||||
// DNS Settings Handlers
|
// DNS Settings Handlers
|
||||||
|
|
||||||
// TODO(a.garipov): !! Write tests!
|
|
||||||
|
|
||||||
// ReqPatchSettingsDNS describes the request to the PATCH /api/v1/settings/dns
|
// ReqPatchSettingsDNS describes the request to the PATCH /api/v1/settings/dns
|
||||||
// HTTP API.
|
// HTTP API.
|
||||||
type ReqPatchSettingsDNS struct {
|
type ReqPatchSettingsDNS struct {
|
||||||
@@ -49,7 +47,7 @@ func (svc *Service) handlePatchSettingsDNS(w http.ResponseWriter, r *http.Reques
|
|||||||
|
|
||||||
err := json.NewDecoder(r.Body).Decode(&req)
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeHTTPError(w, r, fmt.Errorf("decoding: %w", err))
|
writeJSONErrorResponse(w, r, fmt.Errorf("decoding: %w", err))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -64,7 +62,7 @@ func (svc *Service) handlePatchSettingsDNS(w http.ResponseWriter, r *http.Reques
|
|||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
err = svc.confMgr.UpdateDNS(ctx, newConf)
|
err = svc.confMgr.UpdateDNS(ctx, newConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeHTTPError(w, r, fmt.Errorf("updating: %w", err))
|
writeJSONErrorResponse(w, r, fmt.Errorf("updating: %w", err))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -72,12 +70,12 @@ func (svc *Service) handlePatchSettingsDNS(w http.ResponseWriter, r *http.Reques
|
|||||||
newSvc := svc.confMgr.DNS()
|
newSvc := svc.confMgr.DNS()
|
||||||
err = newSvc.Start()
|
err = newSvc.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeHTTPError(w, r, fmt.Errorf("starting new service: %w", err))
|
writeJSONErrorResponse(w, r, fmt.Errorf("starting new service: %w", err))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
writeJSONResponse(w, r, &HTTPAPIDNSSettings{
|
writeJSONOKResponse(w, r, &HTTPAPIDNSSettings{
|
||||||
Addresses: newConf.Addresses,
|
Addresses: newConf.Addresses,
|
||||||
BootstrapServers: newConf.BootstrapServers,
|
BootstrapServers: newConf.BootstrapServers,
|
||||||
UpstreamServers: newConf.UpstreamServers,
|
UpstreamServers: newConf.UpstreamServers,
|
||||||
|
|||||||
68
internal/next/websvc/dns_test.go
Normal file
68
internal/next/websvc/dns_test.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package websvc_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/netip"
|
||||||
|
"net/url"
|
||||||
|
"sync/atomic"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc"
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/next/websvc"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestService_HandlePatchSettingsDNS(t *testing.T) {
|
||||||
|
wantDNS := &websvc.HTTPAPIDNSSettings{
|
||||||
|
Addresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.1.1:53")},
|
||||||
|
BootstrapServers: []string{"1.0.0.1"},
|
||||||
|
UpstreamServers: []string{"1.1.1.1"},
|
||||||
|
UpstreamTimeout: websvc.JSONDuration(2 * time.Second),
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(a.garipov): Use [atomic.Bool] in Go 1.19.
|
||||||
|
var numStarted uint64
|
||||||
|
confMgr := newConfigManager()
|
||||||
|
confMgr.onDNS = func() (s websvc.ServiceWithConfig[*dnssvc.Config]) {
|
||||||
|
return &aghtest.ServiceWithConfig[*dnssvc.Config]{
|
||||||
|
OnStart: func() (err error) {
|
||||||
|
atomic.AddUint64(&numStarted, 1)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
OnShutdown: func(_ context.Context) (err error) { panic("not implemented") },
|
||||||
|
OnConfig: func() (c *dnssvc.Config) { panic("not implemented") },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
confMgr.onUpdateDNS = func(ctx context.Context, c *dnssvc.Config) (err error) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, addr := newTestServer(t, confMgr)
|
||||||
|
u := &url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: addr.String(),
|
||||||
|
Path: websvc.PathV1SettingsDNS,
|
||||||
|
}
|
||||||
|
|
||||||
|
req := jobj{
|
||||||
|
"addresses": wantDNS.Addresses,
|
||||||
|
"bootstrap_servers": wantDNS.BootstrapServers,
|
||||||
|
"upstream_servers": wantDNS.UpstreamServers,
|
||||||
|
"upstream_timeout": wantDNS.UpstreamTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
respBody := httpPatch(t, u, req, http.StatusOK)
|
||||||
|
resp := &websvc.HTTPAPIDNSSettings{}
|
||||||
|
err := json.Unmarshal(respBody, resp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, uint64(1), numStarted)
|
||||||
|
assert.Equal(t, wantDNS, resp)
|
||||||
|
assert.Equal(t, wantDNS, resp)
|
||||||
|
}
|
||||||
@@ -45,7 +45,7 @@ func (svc *Service) handlePatchSettingsHTTP(w http.ResponseWriter, r *http.Reque
|
|||||||
|
|
||||||
err := json.NewDecoder(r.Body).Decode(&req)
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeHTTPError(w, r, fmt.Errorf("decoding: %w", err))
|
writeJSONErrorResponse(w, r, fmt.Errorf("decoding: %w", err))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ func (svc *Service) handlePatchSettingsHTTP(w http.ResponseWriter, r *http.Reque
|
|||||||
ForceHTTPS: svc.forceHTTPS,
|
ForceHTTPS: svc.forceHTTPS,
|
||||||
}
|
}
|
||||||
|
|
||||||
writeJSONResponse(w, r, &HTTPAPIHTTPSettings{
|
writeJSONOKResponse(w, r, &HTTPAPIHTTPSettings{
|
||||||
Addresses: newConf.Addresses,
|
Addresses: newConf.Addresses,
|
||||||
SecureAddresses: newConf.SecureAddresses,
|
SecureAddresses: newConf.SecureAddresses,
|
||||||
Timeout: JSONDuration(newConf.Timeout),
|
Timeout: JSONDuration(newConf.Timeout),
|
||||||
@@ -81,13 +81,13 @@ func (svc *Service) handlePatchSettingsHTTP(w http.ResponseWriter, r *http.Reque
|
|||||||
|
|
||||||
updErr := svc.confMgr.UpdateWeb(updCtx, newConf)
|
updErr := svc.confMgr.UpdateWeb(updCtx, newConf)
|
||||||
if updErr != nil {
|
if updErr != nil {
|
||||||
writeHTTPError(w, r, fmt.Errorf("updating: %w", updErr))
|
writeJSONErrorResponse(w, r, fmt.Errorf("updating: %w", updErr))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(a.garipov): !! Add some kind of timeout? Context?
|
// TODO(a.garipov): !! Add some kind of timeout? Context?
|
||||||
var newSvc *Service
|
var newSvc ServiceWithConfig[*Config]
|
||||||
for newSvc = svc.confMgr.Web(); newSvc == svc; {
|
for newSvc = svc.confMgr.Web(); newSvc == svc; {
|
||||||
log.Debug("websvc: waiting for new websvc to be configured")
|
log.Debug("websvc: waiting for new websvc to be configured")
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ func TestService_HandlePatchSettingsHTTP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
confMgr := newConfigManager()
|
confMgr := newConfigManager()
|
||||||
confMgr.onWeb = func() (c *websvc.Service) {
|
confMgr.onWeb = func() (s websvc.ServiceWithConfig[*websvc.Config]) {
|
||||||
return websvc.New(&websvc.Config{
|
return websvc.New(&websvc.Config{
|
||||||
TLS: &tls.Config{
|
TLS: &tls.Config{
|
||||||
Certificates: []tls.Certificate{{}},
|
Certificates: []tls.Certificate{{}},
|
||||||
@@ -50,7 +50,7 @@ func TestService_HandlePatchSettingsHTTP(t *testing.T) {
|
|||||||
"addresses": wantWeb.Addresses,
|
"addresses": wantWeb.Addresses,
|
||||||
"secure_addresses": wantWeb.SecureAddresses,
|
"secure_addresses": wantWeb.SecureAddresses,
|
||||||
"timeout": wantWeb.Timeout,
|
"timeout": wantWeb.Timeout,
|
||||||
"ForceHTTPS": wantWeb.ForceHTTPS,
|
"force_https": wantWeb.ForceHTTPS,
|
||||||
}
|
}
|
||||||
|
|
||||||
respBody := httpPatch(t, u, req, http.StatusOK)
|
respBody := httpPatch(t, u, req, http.StatusOK)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package websvc
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@@ -87,29 +86,58 @@ func (t *JSONTime) UnmarshalJSON(b []byte) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeJSONResponse encodes v into w and logs any errors it encounters. r is
|
// writeJSONOKResponse writes headers with the code 200 OK, encodes v into w,
|
||||||
// used to get additional information from the request.
|
// and logs any errors it encounters. r is used to get additional information
|
||||||
func writeJSONResponse(w http.ResponseWriter, r *http.Request, v any) {
|
// from the request.
|
||||||
|
func writeJSONOKResponse(w http.ResponseWriter, r *http.Request, v any) {
|
||||||
|
writeJSONResponse(w, r, v, http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeJSONResponse writes headers with code, encodes v into w, and logs any
|
||||||
|
// errors it encounters. r is used to get additional information from the
|
||||||
|
// request.
|
||||||
|
func writeJSONResponse(w http.ResponseWriter, r *http.Request, v any, code int) {
|
||||||
// TODO(a.garipov): Put some of these to a middleware.
|
// TODO(a.garipov): Put some of these to a middleware.
|
||||||
h := w.Header()
|
h := w.Header()
|
||||||
h.Set(aghhttp.HdrNameContentType, aghhttp.HdrValApplicationJSON)
|
h.Set(aghhttp.HdrNameContentType, aghhttp.HdrValApplicationJSON)
|
||||||
h.Set(aghhttp.HdrNameServer, aghhttp.UserAgent())
|
h.Set(aghhttp.HdrNameServer, aghhttp.UserAgent())
|
||||||
|
|
||||||
|
w.WriteHeader(code)
|
||||||
|
|
||||||
err := json.NewEncoder(w).Encode(v)
|
err := json.NewEncoder(w).Encode(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("websvc: writing resp to %s %s: %s", r.Method, r.URL.Path, err)
|
log.Error("websvc: writing resp to %s %s: %s", r.Method, r.URL.Path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeHTTPError is a helper for logging and writing HTTP errors.
|
// ErrorCode is the error code as used by the HTTP API. See the ErrorCode
|
||||||
|
// definition in the OpenAPI specification.
|
||||||
|
type ErrorCode string
|
||||||
|
|
||||||
|
// ErrorCode constants.
|
||||||
//
|
//
|
||||||
// TODO(a.garipov): Improve codes, and add JSON error codes.
|
// TODO(a.garipov): Expand and document codes.
|
||||||
func writeHTTPError(w http.ResponseWriter, r *http.Request, err error) {
|
const (
|
||||||
|
// ErrorCodeTMP000 is the temporary error code used for all errors.
|
||||||
|
ErrorCodeTMP000 = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
// HTTPAPIErrorResp is the error response as used by the HTTP API. See the
|
||||||
|
// BadRequestResp, InternalServerErrorResp, and similar objects in the OpenAPI
|
||||||
|
// specification.
|
||||||
|
type HTTPAPIErrorResp struct {
|
||||||
|
Code ErrorCode `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeJSONErrorResponse encodes err as a JSON error into w, and logs any
|
||||||
|
// errors it encounters. r is used to get additional information from the
|
||||||
|
// request.
|
||||||
|
func writeJSONErrorResponse(w http.ResponseWriter, r *http.Request, err error) {
|
||||||
log.Error("websvc: %s %s: %s", r.Method, r.URL.Path, err)
|
log.Error("websvc: %s %s: %s", r.Method, r.URL.Path, err)
|
||||||
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
writeJSONResponse(w, r, &HTTPAPIErrorResp{
|
||||||
_, werr := io.WriteString(w, err.Error())
|
Code: ErrorCodeTMP000,
|
||||||
if werr != nil {
|
Msg: err.Error(),
|
||||||
log.Debug("websvc: writing error resp to %s %s: %s", r.Method, r.URL.Path, werr)
|
}, http.StatusUnprocessableEntity)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func (svc *Service) handleGetSettingsAll(w http.ResponseWriter, r *http.Request)
|
|||||||
httpConf := webSvc.Config()
|
httpConf := webSvc.Config()
|
||||||
|
|
||||||
// TODO(a.garipov): Add all currently supported parameters.
|
// TODO(a.garipov): Add all currently supported parameters.
|
||||||
writeJSONResponse(w, r, &RespGetV1SettingsAll{
|
writeJSONOKResponse(w, r, &RespGetV1SettingsAll{
|
||||||
DNS: &HTTPAPIDNSSettings{
|
DNS: &HTTPAPIDNSSettings{
|
||||||
Addresses: dnsConf.Addresses,
|
Addresses: dnsConf.Addresses,
|
||||||
BootstrapServers: dnsConf.BootstrapServers,
|
BootstrapServers: dnsConf.BootstrapServers,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func TestService_HandleGetSettingsAll(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
confMgr := newConfigManager()
|
confMgr := newConfigManager()
|
||||||
confMgr.onDNS = func() (c *dnssvc.Service) {
|
confMgr.onDNS = func() (s websvc.ServiceWithConfig[*dnssvc.Config]) {
|
||||||
c, err := dnssvc.New(&dnssvc.Config{
|
c, err := dnssvc.New(&dnssvc.Config{
|
||||||
Addresses: wantDNS.Addresses,
|
Addresses: wantDNS.Addresses,
|
||||||
UpstreamServers: wantDNS.UpstreamServers,
|
UpstreamServers: wantDNS.UpstreamServers,
|
||||||
@@ -45,7 +45,7 @@ func TestService_HandleGetSettingsAll(t *testing.T) {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
confMgr.onWeb = func() (c *websvc.Service) {
|
confMgr.onWeb = func() (s websvc.ServiceWithConfig[*websvc.Config]) {
|
||||||
return websvc.New(&websvc.Config{
|
return websvc.New(&websvc.Config{
|
||||||
TLS: &tls.Config{
|
TLS: &tls.Config{
|
||||||
Certificates: []tls.Certificate{{}},
|
Certificates: []tls.Certificate{{}},
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ type RespGetV1SystemInfo struct {
|
|||||||
// handleGetV1SystemInfo is the handler for the GET /api/v1/system/info HTTP
|
// handleGetV1SystemInfo is the handler for the GET /api/v1/system/info HTTP
|
||||||
// API.
|
// API.
|
||||||
func (svc *Service) handleGetV1SystemInfo(w http.ResponseWriter, r *http.Request) {
|
func (svc *Service) handleGetV1SystemInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
writeJSONResponse(w, r, &RespGetV1SystemInfo{
|
writeJSONOKResponse(w, r, &RespGetV1SystemInfo{
|
||||||
Arch: runtime.GOARCH,
|
Arch: runtime.GOARCH,
|
||||||
Channel: version.Channel(),
|
Channel: version.Channel(),
|
||||||
OS: runtime.GOOS,
|
OS: runtime.GOOS,
|
||||||
|
|||||||
@@ -24,10 +24,21 @@ import (
|
|||||||
httptreemux "github.com/dimfeld/httptreemux/v5"
|
httptreemux "github.com/dimfeld/httptreemux/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ServiceWithConfig is an extension of the [agh.Service] interface for services
|
||||||
|
// that can return their configuration.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Consider removing this generic interface if we figure out
|
||||||
|
// how to make it testable in a better way.
|
||||||
|
type ServiceWithConfig[ConfigType any] interface {
|
||||||
|
agh.Service
|
||||||
|
|
||||||
|
Config() (c ConfigType)
|
||||||
|
}
|
||||||
|
|
||||||
// ConfigManager is the configuration manager interface.
|
// ConfigManager is the configuration manager interface.
|
||||||
type ConfigManager interface {
|
type ConfigManager interface {
|
||||||
DNS() (svc *dnssvc.Service)
|
DNS() (svc ServiceWithConfig[*dnssvc.Config])
|
||||||
Web() (svc *Service)
|
Web() (svc ServiceWithConfig[*Config])
|
||||||
|
|
||||||
UpdateDNS(ctx context.Context, c *dnssvc.Config) (err error)
|
UpdateDNS(ctx context.Context, c *dnssvc.Config) (err error)
|
||||||
UpdateWeb(ctx context.Context, c *Config) (err error)
|
UpdateWeb(ctx context.Context, c *Config) (err error)
|
||||||
|
|||||||
@@ -34,20 +34,20 @@ var _ websvc.ConfigManager = (*configManager)(nil)
|
|||||||
|
|
||||||
// configManager is a [websvc.ConfigManager] for tests.
|
// configManager is a [websvc.ConfigManager] for tests.
|
||||||
type configManager struct {
|
type configManager struct {
|
||||||
onDNS func() (svc *dnssvc.Service)
|
onDNS func() (svc websvc.ServiceWithConfig[*dnssvc.Config])
|
||||||
onWeb func() (svc *websvc.Service)
|
onWeb func() (svc websvc.ServiceWithConfig[*websvc.Config])
|
||||||
|
|
||||||
onUpdateDNS func(ctx context.Context, c *dnssvc.Config) (err error)
|
onUpdateDNS func(ctx context.Context, c *dnssvc.Config) (err error)
|
||||||
onUpdateWeb func(ctx context.Context, c *websvc.Config) (err error)
|
onUpdateWeb func(ctx context.Context, c *websvc.Config) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DNS implements the [websvc.ConfigManager] interface for *configManager.
|
// DNS implements the [websvc.ConfigManager] interface for *configManager.
|
||||||
func (m *configManager) DNS() (svc *dnssvc.Service) {
|
func (m *configManager) DNS() (svc websvc.ServiceWithConfig[*dnssvc.Config]) {
|
||||||
return m.onDNS()
|
return m.onDNS()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Web implements the [websvc.ConfigManager] interface for *configManager.
|
// Web implements the [websvc.ConfigManager] interface for *configManager.
|
||||||
func (m *configManager) Web() (svc *websvc.Service) {
|
func (m *configManager) Web() (svc websvc.ServiceWithConfig[*websvc.Config]) {
|
||||||
return m.onWeb()
|
return m.onWeb()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,8 +64,8 @@ func (m *configManager) UpdateWeb(ctx context.Context, c *websvc.Config) (err er
|
|||||||
// newConfigManager returns a *configManager all methods of which panic.
|
// newConfigManager returns a *configManager all methods of which panic.
|
||||||
func newConfigManager() (m *configManager) {
|
func newConfigManager() (m *configManager) {
|
||||||
return &configManager{
|
return &configManager{
|
||||||
onDNS: func() (svc *dnssvc.Service) { panic("not implemented") },
|
onDNS: func() (svc websvc.ServiceWithConfig[*dnssvc.Config]) { panic("not implemented") },
|
||||||
onWeb: func() (svc *websvc.Service) { panic("not implemented") },
|
onWeb: func() (svc websvc.ServiceWithConfig[*websvc.Config]) { panic("not implemented") },
|
||||||
onUpdateDNS: func(_ context.Context, _ *dnssvc.Config) (err error) {
|
onUpdateDNS: func(_ context.Context, _ *dnssvc.Config) (err error) {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user