Pull request 2735: ADG-12585-imp-code

Squashed commit of the following:

commit 43ed1e377b74ea65d1bc6e1d811aaba9d8816d67
Author: Maksim Kazantsev <[email protected]>
Date:   Thu Jul 30 15:52:37 2026 +0300

    home: imp code;

commit 8d524f9c57d203263cb0f5c820e1a7c882d72b82
Merge: 384140ac5 66360530c
Author: Maksim Kazantsev <[email protected]>
Date:   Thu Jul 30 15:50:16 2026 +0300

    Merge branch 'master' into ADG-12585-imp-code

commit 384140ac57092d4f200114d4098789e1928a62ef
Author: Maksim Kazantsev <[email protected]>
Date:   Thu Jul 30 15:37:15 2026 +0300

    updater: fix race; filtering: imp tests; aghtest: fix docs;

commit b2194f76d4ddd992efc06ccc86525629b7191450
Author: Maksim Kazantsev <[email protected]>
Date:   Thu Jul 30 14:49:35 2026 +0300

    updater: imp tests; home: imp todo;

commit 2b88612d6716bede9b7edb5fe42051438507b4bb
Author: Maksim Kazantsev <[email protected]>
Date:   Thu Jul 30 13:39:49 2026 +0300

    all: imp code;

commit d4d52fb73adba9b8fe9c2602a28c6347309d3a41
Author: Maksim Kazantsev <[email protected]>
Date:   Wed Jul 29 15:43:54 2026 +0300

    home: imp contracts and fix potential panic;

commit 8212df493935010c94d52e73b9295b134b6b63c8
Author: Maksim Kazantsev <[email protected]>
Date:   Wed Jul 29 15:23:37 2026 +0300

    home: imp code;
This commit is contained in:
Maksim Kazantsev
2026-07-30 14:34:38 +00:00
parent 66360530c3
commit 6f4120483b
9 changed files with 248 additions and 175 deletions
+4 -5
View File
@@ -33,13 +33,12 @@ func HostToIPs(host string) (ipv4, ipv6 netip.Addr) {
}
// StartHTTPServer is a helper that starts the HTTP server, which is configured
// to return data on every request, and returns the client and server URL.
func StartHTTPServer(tb testing.TB, data []byte) (c *http.Client, u *url.URL) {
// to handle HTTP requests with the given handler. It then returns the client
// and server URL.
func StartHTTPServer(tb testing.TB, handler http.Handler) (c *http.Client, u *url.URL) {
tb.Helper()
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_, _ = w.Write(data)
}))
srv := httptest.NewServer(handler)
tb.Cleanup(srv.Close)
u, err := url.Parse(srv.URL)
+201 -141
View File
@@ -8,8 +8,10 @@ import (
"io"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"github.com/AdguardTeam/AdGuardHome/internal/agh"
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
@@ -39,44 +41,49 @@ type rewriteUpdateJSON struct {
Update rewriteJSON `json:"update"`
}
// URLs for the rewrite HTTP API.
const (
listURL = "/control/rewrite/list"
addURL = "/control/rewrite/add"
deleteURL = "/control/rewrite/delete"
updateURL = "/control/rewrite/update"
)
// Messages for the rewrite HTTP API.
const (
decodeMsg = "json.Decode: json: cannot unmarshal string into Go value of type"
decodeErrorMsg = decodeMsg + " filtering.rewriteEntryJSON\n"
decodeUpdateErrorMsg = decodeMsg + " filtering.rewriteUpdateJSON\n"
)
// TODO(m.kazantsev): Improve maintainability.
// Test domains.
const (
exampleDomain = "example.local"
exampleAnswer = "example.rewrite"
oneDomain = "one.local"
oneAnswer = "one.rewrite"
disabledDomain = "disabled.local"
disabledAnswer = "disabled.rewrite"
addDomain = "add.local"
addAnswer = "add.rewrite"
updDomain = "upd.local"
updAnswer = "upd.rewrite"
invDomain = "inv.local"
invAnswer = "inv.rewrite"
invalidDomain = "invalid_domain"
)
// testRewrites is a common rewrites list for tests.
var testRewrites = []*rewriteJSON{
newRewriteJSON(exampleDomain, exampleAnswer, aghalg.NBTrue),
newRewriteJSON(oneDomain, oneAnswer, aghalg.NBTrue),
newRewriteJSON(disabledDomain, disabledAnswer, aghalg.NBFalse),
}
func TestDNSFilter_HandleRewriteHTTP(t *testing.T) {
t.Parallel()
const (
exampleDomain = "example.local"
exampleAnswer = "example.rewrite"
oneDomain = "one.local"
oneAnswer = "one.rewrite"
disabledDomain = "disabled.local"
disabledAnswer = "disabled.rewrite"
addDomain = "add.local"
addAnswer = "add.rewrite"
updDomain = "upd.local"
updAnswer = "upd.rewrite"
invDomain = "inv.local"
invAnswer = "inv.rewrite"
invalidDomain = "invalid_domain"
)
testRewrites := []*rewriteJSON{
newRewriteJSON(exampleDomain, exampleAnswer, aghalg.NBTrue),
newRewriteJSON(oneDomain, oneAnswer, aghalg.NBTrue),
newRewriteJSON(disabledDomain, disabledAnswer, aghalg.NBFalse),
}
testRewritesJSON, mErr := json.Marshal(testRewrites)
rewritesJSON, mErr := json.Marshal(testRewrites)
require.NoError(t, mErr)
testCases := []struct {
@@ -85,7 +92,7 @@ func TestDNSFilter_HandleRewriteHTTP(t *testing.T) {
url string
method string
wantList []*rewriteJSON
wantBody string
wantBody []byte
wantConfMod bool
wantStatus int
}{{
@@ -95,7 +102,7 @@ func TestDNSFilter_HandleRewriteHTTP(t *testing.T) {
reqData: nil,
wantConfMod: false,
wantStatus: http.StatusOK,
wantBody: string(testRewritesJSON) + "\n",
wantBody: append(rewritesJSON, '\n'),
wantList: testRewrites,
}, {
name: "add_enabled_null",
@@ -104,7 +111,7 @@ func TestDNSFilter_HandleRewriteHTTP(t *testing.T) {
reqData: rewriteJSON{Domain: addDomain, Answer: addAnswer},
wantConfMod: true,
wantStatus: http.StatusOK,
wantBody: "",
wantBody: []byte{},
wantList: append(
testRewrites,
newRewriteJSON(addDomain, addAnswer, aghalg.NBTrue),
@@ -120,7 +127,7 @@ func TestDNSFilter_HandleRewriteHTTP(t *testing.T) {
},
wantConfMod: true,
wantStatus: http.StatusOK,
wantBody: "",
wantBody: []byte{},
wantList: append(
testRewrites,
newRewriteJSON(addDomain, addAnswer, aghalg.NBFalse),
@@ -136,35 +143,11 @@ func TestDNSFilter_HandleRewriteHTTP(t *testing.T) {
},
wantConfMod: true,
wantStatus: http.StatusOK,
wantBody: "",
wantBody: []byte{},
wantList: append(
testRewrites,
newRewriteJSON(addDomain, addAnswer, aghalg.NBTrue),
),
}, {
name: "add_error",
url: addURL,
method: http.MethodPost,
reqData: "invalid_json",
wantConfMod: false,
wantStatus: http.StatusBadRequest,
wantBody: decodeErrorMsg,
wantList: testRewrites,
}, {
name: "add_error_invalid_cname",
url: addURL,
method: http.MethodPost,
reqData: rewriteJSON{
Domain: addDomain,
Answer: invalidDomain,
Enabled: aghalg.NBTrue,
},
wantConfMod: false,
wantStatus: http.StatusBadRequest,
wantBody: `normalizing: invalid CNAME target "` + invalidDomain + `": bad domain name ` +
`"` + invalidDomain + `": bad top-level domain name label "` + invalidDomain +
`": bad top-level domain name label rune '_'` + "\n",
wantList: testRewrites,
}, {
name: "delete",
url: deleteURL,
@@ -172,20 +155,11 @@ func TestDNSFilter_HandleRewriteHTTP(t *testing.T) {
reqData: rewriteJSON{Domain: oneDomain, Answer: oneAnswer},
wantConfMod: true,
wantStatus: http.StatusOK,
wantBody: "",
wantBody: []byte{},
wantList: []*rewriteJSON{
newRewriteJSON(exampleDomain, exampleAnswer, aghalg.NBTrue),
newRewriteJSON(disabledDomain, disabledAnswer, aghalg.NBFalse),
},
}, {
name: "delete_error",
url: deleteURL,
method: http.MethodPost,
reqData: "invalid_json",
wantConfMod: false,
wantStatus: http.StatusBadRequest,
wantBody: decodeErrorMsg,
wantList: testRewrites,
}, {
name: "update_enabled_null",
url: updateURL,
@@ -196,7 +170,7 @@ func TestDNSFilter_HandleRewriteHTTP(t *testing.T) {
},
wantConfMod: true,
wantStatus: http.StatusOK,
wantBody: "",
wantBody: []byte{},
wantList: []*rewriteJSON{
newRewriteJSON(exampleDomain, exampleAnswer, aghalg.NBTrue),
newRewriteJSON(updDomain, updAnswer, aghalg.NBTrue),
@@ -216,7 +190,7 @@ func TestDNSFilter_HandleRewriteHTTP(t *testing.T) {
},
wantConfMod: true,
wantStatus: http.StatusOK,
wantBody: "",
wantBody: []byte{},
wantList: []*rewriteJSON{
newRewriteJSON(exampleDomain, exampleAnswer, aghalg.NBTrue),
newRewriteJSON(updDomain, updAnswer, aghalg.NBFalse),
@@ -232,21 +206,86 @@ func TestDNSFilter_HandleRewriteHTTP(t *testing.T) {
},
wantConfMod: true,
wantStatus: http.StatusOK,
wantBody: "",
wantBody: []byte{},
wantList: []*rewriteJSON{
newRewriteJSON(exampleDomain, exampleAnswer, aghalg.NBTrue),
newRewriteJSON(updDomain, updAnswer, aghalg.NBTrue),
newRewriteJSON(disabledDomain, disabledAnswer, aghalg.NBFalse),
},
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
confModCh := make(chan struct{}, 1)
pt := testutil.NewPanicT(t)
confModifier := &aghtest.ConfigModifier{}
confModifier.OnApply = func(_ context.Context) {
require.Truef(pt, tc.wantConfMod, "config modified has been fired")
testutil.RequireSend(pt, confModCh, struct{}{}, testTimeout)
}
cl, baseURL := setupTestFiltering(t, confModifier)
respBody, status := executeRequest(t, cl, baseURL, tc.method, tc.url, tc.reqData)
if tc.wantConfMod {
testutil.RequireReceive(t, confModCh, testTimeout)
}
assert.Equal(t, tc.wantStatus, status)
assert.Equal(t, tc.wantBody, respBody)
assertRewritesList(t, cl, baseURL, tc.wantList)
})
}
}
func TestDNSFilter_HandleRewriteHTTP_errors(t *testing.T) {
t.Parallel()
pt := testutil.NewPanicT(t)
confModifier := &aghtest.ConfigModifier{}
confModifier.OnApply = func(_ context.Context) {
require.Truef(pt, false, "config modified has been fired")
}
testCases := []struct {
reqData any
name string
url string
method string
wantBody []byte
}{{
name: "add_error",
url: addURL,
method: http.MethodPost,
reqData: "invalid_json",
wantBody: []byte(decodeErrorMsg),
}, {
name: "update_error",
url: updateURL,
method: http.MethodPut,
reqData: "invalid_json",
wantConfMod: false,
wantStatus: http.StatusBadRequest,
wantBody: decodeUpdateErrorMsg,
wantList: testRewrites,
name: "add_error_invalid_cname",
url: addURL,
method: http.MethodPost,
reqData: rewriteJSON{
Domain: addDomain,
Answer: invalidDomain,
Enabled: aghalg.NBTrue,
},
wantBody: []byte(`normalizing: invalid CNAME target "` + invalidDomain + `": bad domain name ` +
`"` + invalidDomain + `": bad top-level domain name label "` + invalidDomain +
`": bad top-level domain name label rune '_'` + "\n"),
}, {
name: "delete_error",
url: deleteURL,
method: http.MethodPost,
reqData: "invalid_json",
wantBody: []byte(decodeErrorMsg),
}, {
name: "update_error",
url: updateURL,
method: http.MethodPut,
reqData: "invalid_json",
wantBody: []byte(decodeUpdateErrorMsg),
}, {
name: "update_error_target",
url: updateURL,
@@ -255,96 +294,117 @@ func TestDNSFilter_HandleRewriteHTTP(t *testing.T) {
Target: rewriteJSON{Domain: invDomain, Answer: invAnswer},
Update: rewriteJSON{Domain: updDomain, Answer: updAnswer},
},
wantConfMod: false,
wantStatus: http.StatusBadRequest,
wantBody: "target rule not found\n",
wantList: testRewrites,
wantBody: []byte("target rule not found\n"),
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
confModCh := make(chan struct{})
reqCh := make(chan struct{})
cl, base := setupTestFiltering(t, confModifier)
respBody, status := executeRequest(t, cl, base, tc.method, tc.url, tc.reqData)
pt := testutil.NewPanicT(t)
handlers := make(map[string]http.Handler)
confModifier := &aghtest.ConfigModifier{}
confModifier.OnApply = func(_ context.Context) {
require.Truef(pt, tc.wantConfMod, "config modified has been fired")
testutil.RequireSend(pt, confModCh, struct{}{}, testTimeout)
}
d, err := filtering.New(&filtering.Config{
Logger: testLogger,
ConfModifier: confModifier,
HTTPReg: &aghtest.Registrar{
OnRegister: func(_, url string, handler http.HandlerFunc) {
handlers[url] = handler
},
},
Rewrites: rewriteEntriesToLegacyRewrites(testRewrites),
}, nil)
require.NoError(t, err)
t.Cleanup(d.Close)
d.RegisterFilteringHandlers()
require.NotEmpty(t, handlers)
require.Contains(t, handlers, listURL)
require.Contains(t, handlers, tc.url)
var body io.Reader
if tc.reqData != nil {
data, rErr := json.Marshal(tc.reqData)
require.NoError(t, rErr)
body = bytes.NewReader(data)
}
r := httptest.NewRequest(tc.method, tc.url, body)
w := httptest.NewRecorder()
go func() {
handlers[tc.url].ServeHTTP(w, r)
testutil.RequireSend(pt, reqCh, struct{}{}, testTimeout)
}()
if tc.wantConfMod {
testutil.RequireReceive(t, confModCh, testTimeout)
}
testutil.RequireReceive(t, reqCh, testTimeout)
assert.Equal(t, tc.wantStatus, w.Code)
respBody, err := io.ReadAll(w.Body)
require.NoError(t, err)
assert.Equal(t, []byte(tc.wantBody), respBody)
assertRewritesList(t, handlers[listURL], tc.wantList)
assert.Equal(t, http.StatusBadRequest, status)
assert.Equal(t, tc.wantBody, respBody)
assertRewritesList(t, cl, base, testRewrites)
})
}
}
// assertRewritesList checks if rewrites list equals the list received from the
// handler by listURL.
func assertRewritesList(tb testing.TB, handler http.Handler, wantList []*rewriteJSON) {
func assertRewritesList(tb testing.TB, cl *http.Client, base *url.URL, wantList []*rewriteJSON) {
tb.Helper()
r := httptest.NewRequest(http.MethodGet, listURL, nil)
w := httptest.NewRecorder()
full := base.ResolveReference(&url.URL{Path: listURL})
ctx := testutil.ContextWithTimeout(tb, testTimeout)
r, err := http.NewRequestWithContext(ctx, http.MethodGet, full.String(), nil)
require.NoError(tb, err)
handler.ServeHTTP(w, r)
require.Equal(tb, http.StatusOK, w.Code)
resp, err := cl.Do(r)
require.NoError(tb, err)
defer func() {
require.NoError(tb, resp.Body.Close())
}()
require.Equal(tb, http.StatusOK, resp.StatusCode)
var actual []*rewriteJSON
err := json.NewDecoder(w.Body).Decode(&actual)
err = json.NewDecoder(resp.Body).Decode(&actual)
require.NoError(tb, err)
assert.Equal(tb, wantList, actual)
}
// setupTestFiltering creates the test environment with the filtering DNS filter
// and returns the HTTP client and server URL for making requests.
func setupTestFiltering(
tb testing.TB,
confModifier agh.ConfigModifier,
) (cl *http.Client, base *url.URL) {
tb.Helper()
mux := http.NewServeMux()
d, err := filtering.New(&filtering.Config{
Logger: testLogger,
ConfModifier: confModifier,
HTTPReg: &aghtest.Registrar{
OnRegister: func(_, urlPath string, handler http.HandlerFunc) {
mux.Handle(urlPath, handler)
},
},
Rewrites: rewriteEntriesToLegacyRewrites(testRewrites),
}, nil)
require.NoError(tb, err)
tb.Cleanup(d.Close)
d.RegisterFilteringHandlers()
cl, base = aghtest.StartHTTPServer(tb, mux)
return cl, base
}
// executeRequest prepares and executes an HTTP request against the given
// client and base URL, returning the response body and status code.
func executeRequest(
tb testing.TB,
client *http.Client,
base *url.URL,
method string,
path string,
reqData any,
) (respBody []byte, status int) {
tb.Helper()
var body io.Reader
if reqData != nil {
data, rErr := json.Marshal(reqData)
require.NoError(tb, rErr)
body = bytes.NewReader(data)
}
fullURL := base.ResolveReference(&url.URL{Path: path})
ctx := testutil.ContextWithTimeout(tb, testTimeout)
r, err := http.NewRequestWithContext(ctx, method, fullURL.String(), body)
require.NoError(tb, err)
resp, err := client.Do(r)
require.NoError(tb, err)
defer func() {
require.NoError(tb, resp.Body.Close())
}()
respBody, err = io.ReadAll(resp.Body)
require.NoError(tb, err)
status = resp.StatusCode
return respBody, status
}
// rewriteEntriesToLegacyRewrites gets legacy rewrites from json entries.
func rewriteEntriesToLegacyRewrites(entries []*rewriteJSON) (rw []*filtering.LegacyRewrite) {
for _, entry := range entries {
+4
View File
@@ -179,6 +179,10 @@ func (web *webAPI) handleStatus(w http.ResponseWriter, r *http.Request) {
func (web *webAPI) registerControlHandlers() {
mux := web.conf.mux
web.httpReg.Register(http.MethodGet, "/control/tls/status", web.handleTLSStatus)
web.httpReg.Register(http.MethodPost, "/control/tls/configure", web.handleTLSConfigure)
web.httpReg.Register(http.MethodPost, "/control/tls/validate", web.handleTLSValidate)
mux.Handle(
"/control/version.json",
web.postInstallHandler(http.HandlerFunc(web.handleVersionJSON)),
-1
View File
@@ -570,7 +570,6 @@ func (web *webAPI) finalizeInstall(
web.conf.BindAddr = netip.AddrPortFrom(req.Web.IP, req.Web.Port)
web.registerControlHandlers()
web.registerTLSHandlers()
aghhttp.OK(ctx, l, w)
+12 -10
View File
@@ -109,7 +109,6 @@ func initDNS(
err = initDNSServer(
ctx,
baseLogger,
dnsforward.DNSCreateParams{
Logger: baseLogger,
DNSFilter: globalContext.filters,
@@ -135,26 +134,28 @@ func initDNS(
return nil
}
// initDNSServer initializes the [context.dnsServer]. tlsMgr and l must not be
// nil. Other arguments, including params fields, are allowed to be nil if you
// want to use only the internal proxy. It also must not be called unless
// [config] and [globalContext] are initialized.
// initDNSServer initializes the [context.dnsServer]. To only use the internal
// proxy, none of the arguments are required, but params must be valid and
// tlsMgr must not be nil. In other cases all the arguments also must not be
// nil. It also must not be called unless [config] and [globalContext] are
// initialized.
func initDNSServer(
ctx context.Context,
l *slog.Logger,
params dnsforward.DNSCreateParams,
httpReg aghhttp.Registrar,
tlsMgr *tlsManager,
confModifier agh.ConfigModifier,
) (err error) {
globalContext.dnsServer, err = dnsforward.NewServer(params)
// TODO(m.kazantsev): Investigate if the server should be closed in case of
// error and consider removing this defer.
defer func() {
if err != nil {
closeDNSServer(ctx)
}
}()
if err != nil {
return fmt.Errorf("dnsforward.NewServer: %w", err)
return fmt.Errorf("creating new dns server: %w", err)
}
globalContext.clients.clientChecker = globalContext.dnsServer
@@ -164,26 +165,27 @@ func initDNSServer(
config.Clients.Sources,
tlsMgr.extendedTLSConfig(),
config.HTTPConfig.DoH,
tlsMgr,
params.TLSConfigProvider,
httpReg,
globalContext.clients.storage,
confModifier,
)
if err != nil {
return fmt.Errorf("newServerConfig: %w", err)
return fmt.Errorf("creating new dns server config: %w", err)
}
// Try to prepare the server with disabled private RDNS resolution if it
// failed to prepare as is. See TODO on [dnsforward.PrivateRDNSError].
err = globalContext.dnsServer.Prepare(ctx, dnsConf)
if _, ok := errors.AsType[*dnsforward.PrivateRDNSError](err); ok {
l := params.Logger
l.WarnContext(ctx, "private rdns resolution failed; disabling", slogutil.KeyError, err)
dnsConf.UsePrivateRDNS = false
err = globalContext.dnsServer.Prepare(ctx, dnsConf)
}
if err != nil {
return fmt.Errorf("dnsServer.Prepare: %w", err)
return fmt.Errorf("preparing dns server: %w", err)
}
return nil
+10 -6
View File
@@ -1408,12 +1408,16 @@ func cmdlineUpdate(
//
// TODO(e.burkov): We could probably initialize the internal resolver
// separately.
params := dnsforward.DNSCreateParams{
Logger: l,
TLSConfigProvider: tlsMgr,
}
err := initDNSServer(ctx, l, params, nil, tlsMgr, agh.EmptyConfigModifier{})
err := initDNSServer(
ctx,
dnsforward.DNSCreateParams{
Logger: l,
TLSConfigProvider: tlsMgr,
},
nil,
tlsMgr,
agh.EmptyConfigModifier{},
)
fatalOnError(err)
l.InfoContext(ctx, "performing update via cli")
-10
View File
@@ -291,7 +291,6 @@ func newWebAPI(ctx context.Context, conf *webAPIConfig) (w *webAPI) {
mux.Handle("/install.html", w.preInstallHandler(clientFS))
w.registerInstallHandlers()
} else {
w.registerTLSHandlers()
w.registerControlHandlers()
}
@@ -558,15 +557,6 @@ func startPprof(baseLogger *slog.Logger, port uint16) {
}()
}
// registerTLSHandlers registers HTTP handlers for TLS configuration.
//
// TODO(m.kazantsev): Consider uniting with registerControlHandlers.
func (web *webAPI) registerTLSHandlers() {
web.httpReg.Register(http.MethodGet, "/control/tls/status", web.handleTLSStatus)
web.httpReg.Register(http.MethodPost, "/control/tls/configure", web.handleTLSConfigure)
web.httpReg.Register(http.MethodPost, "/control/tls/validate", web.handleTLSValidate)
}
// handleTLSStatus is the handler for the GET /control/tls/status HTTP API.
func (web *webAPI) handleTLSStatus(w http.ResponseWriter, r *http.Request) {
tlsConf := web.tlsManager.extendedTLSConfig()
+8 -1
View File
@@ -111,7 +111,14 @@ func TestUpdater_VersionInfo_others(t *testing.T) {
"download_linux_mips_softfloat": "https://static.adtidy.org/adguardhome/beta/AdGuardHome_linux_mips_softfloat.tar.gz"
}`
fakeClient, fakeURL := aghtest.StartHTTPServer(t, []byte(jsonData))
handler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
pt := testutil.NewPanicT(t)
_, err := w.Write([]byte(jsonData))
require.NoError(pt, err)
})
fakeClient, fakeURL := aghtest.StartHTTPServer(t, handler)
fakeURL = fakeURL.JoinPath("adguardhome", version.ChannelBeta, "version.json")
testCases := []struct {
+9 -1
View File
@@ -2,6 +2,7 @@ package updater
import (
"context"
"net/http"
"net/url"
"os"
"path/filepath"
@@ -55,7 +56,14 @@ func TestUpdater_internal(t *testing.T) {
pkgData, err := os.ReadFile(filepath.Join("testdata", tc.archiveName))
require.NoError(t, err)
fakeClient, fakeURL := aghtest.StartHTTPServer(t, pkgData)
handler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
pt := testutil.NewPanicT(t)
_, werr := w.Write(pkgData)
require.NoError(pt, werr)
})
fakeClient, fakeURL := aghtest.StartHTTPServer(t, handler)
fakeURL = fakeURL.JoinPath(tc.archiveName)
u := NewUpdater(&Config{