diff --git a/.gitignore b/.gitignore index bdc4c29f..e5124973 100644 --- a/.gitignore +++ b/.gitignore @@ -16,10 +16,13 @@ /dist/ /filtering/tests/filtering.TestLotsOfRules*.pprof /filtering/tests/top-1m.csv +/internal/next/AdGuardHome.yaml /launchpad_credentials /querylog.json* /snapcraft_login -AdGuardHome* +AdGuardHome +AdGuardHome.exe +AdGuardHome.yaml* coverage.txt node_modules/ diff --git a/internal/next/AdGuardHome.example.yaml b/internal/next/AdGuardHome.example.yaml new file mode 100644 index 00000000..537467b6 --- /dev/null +++ b/internal/next/AdGuardHome.example.yaml @@ -0,0 +1,26 @@ +# This is a file showing example configuration for AdGuard Home. +# +# TODO(a.garipov): Move to the top level once the rewrite is over. + +dns: + addresses: + - '0.0.0.0:53' + bootstrap_dns: + - '9.9.9.10' + - '149.112.112.10' + - '2620:fe::10' + - '2620:fe::fe:10' + upstream_dns: + - '8.8.8.8' + dns64_prefixes: + - '1234::/64' + upstream_timeout: 1s + bootstrap_prefer_ipv6: true + use_dns64: true +http: + addresses: + - '0.0.0.0:3000' + secure_addresses: [] + timeout: 5s + force_https: true +verbose: true diff --git a/internal/next/cmd/opt.go b/internal/next/cmd/opt.go index 5bbed703..94767607 100644 --- a/internal/next/cmd/opt.go +++ b/internal/next/cmd/opt.go @@ -129,8 +129,8 @@ type commandLineOption struct { // AdGuard Home. var commandLineOptions = []*commandLineOption{ confFileIdx: { - // TODO(a.garipov): Remove the ".1" when the new code is ready. - defaultValue: "AdGuardHome.1.yaml", + // TODO(a.garipov): Remove the directory when the new code is ready. + defaultValue: "internal/next/AdGuardHome.yaml", description: "Path to the config file.", long: "config", short: "c", diff --git a/internal/next/configmgr/config.go b/internal/next/configmgr/config.go index d11d8c1a..993bc596 100644 --- a/internal/next/configmgr/config.go +++ b/internal/next/configmgr/config.go @@ -23,10 +23,13 @@ type config struct { // // TODO(a.garipov): Validate. type dnsConfig struct { - Addresses []netip.AddrPort `yaml:"addresses"` - BootstrapDNS []string `yaml:"bootstrap_dns"` - UpstreamDNS []string `yaml:"upstream_dns"` - UpstreamTimeout timeutil.Duration `yaml:"upstream_timeout"` + Addresses []netip.AddrPort `yaml:"addresses"` + BootstrapDNS []string `yaml:"bootstrap_dns"` + UpstreamDNS []string `yaml:"upstream_dns"` + DNS64Prefixes []netip.Prefix `yaml:"dns64_prefixes"` + UpstreamTimeout timeutil.Duration `yaml:"upstream_timeout"` + BootstrapPreferIPv6 bool `yaml:"bootstrap_prefer_ipv6"` + UseDNS64 bool `yaml:"use_dns64"` } // httpConfig is the on-disk web API configuration. diff --git a/internal/next/configmgr/configmgr.go b/internal/next/configmgr/configmgr.go index 95088b96..70f93bb5 100644 --- a/internal/next/configmgr/configmgr.go +++ b/internal/next/configmgr/configmgr.go @@ -14,7 +14,6 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc" "github.com/AdguardTeam/AdGuardHome/internal/next/websvc" "github.com/AdguardTeam/golibs/errors" - "github.com/AdguardTeam/golibs/log" "gopkg.in/yaml.v3" ) @@ -64,12 +63,6 @@ func New( return nil, err } - // TODO(a.garipov): Move into a separate function and add other logging - // settings. - if conf.Verbose { - log.SetLevel(log.DEBUG) - } - // TODO(a.garipov): Validate the configuration structure. Return an error // if it's incorrect. @@ -102,10 +95,13 @@ func (m *Manager) assemble( start time.Time, ) (err error) { dnsConf := &dnssvc.Config{ - Addresses: conf.DNS.Addresses, - BootstrapServers: conf.DNS.BootstrapDNS, - UpstreamServers: conf.DNS.UpstreamDNS, - UpstreamTimeout: conf.DNS.UpstreamTimeout.Duration, + Addresses: conf.DNS.Addresses, + BootstrapServers: conf.DNS.BootstrapDNS, + UpstreamServers: conf.DNS.UpstreamDNS, + DNS64Prefixes: conf.DNS.DNS64Prefixes, + UpstreamTimeout: conf.DNS.UpstreamTimeout.Duration, + BootstrapPreferIPv6: conf.DNS.BootstrapPreferIPv6, + UseDNS64: conf.DNS.UseDNS64, } err = m.updateDNS(ctx, dnsConf) if err != nil { diff --git a/internal/next/dnssvc/config.go b/internal/next/dnssvc/config.go new file mode 100644 index 00000000..57818c20 --- /dev/null +++ b/internal/next/dnssvc/config.go @@ -0,0 +1,35 @@ +package dnssvc + +import ( + "net/netip" + "time" +) + +// Config is the AdGuard Home DNS service configuration structure. +// +// TODO(a.garipov): Add timeout for incoming requests. +type Config struct { + // Addresses are the addresses on which to serve plain DNS queries. + Addresses []netip.AddrPort + + // BootstrapServers are the addresses of DNS servers used for bootstrapping + // the upstream DNS server addresses. + BootstrapServers []string + + // UpstreamServers are the upstream DNS server addresses to use. + UpstreamServers []string + + // DNS64Prefixes is a slice of NAT64 prefixes to be used for DNS64. See + // also [Config.UseDNS64]. + DNS64Prefixes []netip.Prefix + + // UpstreamTimeout is the timeout for upstream requests. + UpstreamTimeout time.Duration + + // BootstrapPreferIPv6, if true, instructs the bootstrapper to prefer IPv6 + // addresses to IPv4 ones when bootstrapping. + BootstrapPreferIPv6 bool + + // UseDNS64, if true, enables DNS64 protection for incoming requests. + UseDNS64 bool +} diff --git a/internal/next/dnssvc/dnssvc.go b/internal/next/dnssvc/dnssvc.go index a00f0295..07ce4096 100644 --- a/internal/next/dnssvc/dnssvc.go +++ b/internal/next/dnssvc/dnssvc.go @@ -19,40 +19,20 @@ import ( "github.com/AdguardTeam/dnsproxy/upstream" ) -// Config is the AdGuard Home DNS service configuration structure. -// -// TODO(a.garipov): Add timeout for incoming requests. -type Config struct { - // Addresses are the addresses on which to serve plain DNS queries. - Addresses []netip.AddrPort - - // Upstreams are the DNS upstreams to use. If not set, upstreams are - // created using data from BootstrapServers, UpstreamServers, and - // UpstreamTimeout. - // - // TODO(a.garipov): Think of a better scheme. Those other three parameters - // are here only to make Config work properly. - Upstreams []upstream.Upstream - - // BootstrapServers are the addresses for bootstrapping the upstream DNS - // server addresses. - BootstrapServers []string - - // UpstreamServers are the upstream DNS server addresses to use. - UpstreamServers []string - - // UpstreamTimeout is the timeout for upstream requests. - UpstreamTimeout time.Duration -} - // Service is the AdGuard Home DNS service. A nil *Service is a valid // [agh.Service] that does nothing. +// +// TODO(a.garipov): Consider saving a [*proxy.Config] instance for those +// fields that are only used in [New] and [Service.Config]. type Service struct { - proxy *proxy.Proxy - bootstraps []string - upstreams []string - upsTimeout time.Duration - running atomic.Bool + proxy *proxy.Proxy + bootstraps []string + upstreams []string + dns64Prefixes []netip.Prefix + upsTimeout time.Duration + running atomic.Bool + bootstrapPreferIPv6 bool + useDNS64 bool } // New returns a new properly initialized *Service. If c is nil, svc is a nil @@ -64,23 +44,22 @@ func New(c *Config) (svc *Service, err error) { } svc = &Service{ - bootstraps: c.BootstrapServers, - upstreams: c.UpstreamServers, - upsTimeout: c.UpstreamTimeout, + bootstraps: c.BootstrapServers, + upstreams: c.UpstreamServers, + dns64Prefixes: c.DNS64Prefixes, + upsTimeout: c.UpstreamTimeout, + bootstrapPreferIPv6: c.BootstrapPreferIPv6, + useDNS64: c.UseDNS64, } - var upstreams []upstream.Upstream - if len(c.Upstreams) > 0 { - upstreams = c.Upstreams - } else { - upstreams, err = addressesToUpstreams( - c.UpstreamServers, - c.BootstrapServers, - c.UpstreamTimeout, - ) - if err != nil { - return nil, fmt.Errorf("converting upstreams: %w", err) - } + upstreams, err := addressesToUpstreams( + c.UpstreamServers, + c.BootstrapServers, + c.UpstreamTimeout, + c.BootstrapPreferIPv6, + ) + if err != nil { + return nil, fmt.Errorf("converting upstreams: %w", err) } svc.proxy = &proxy.Proxy{ @@ -90,6 +69,8 @@ func New(c *Config) (svc *Service, err error) { UpstreamConfig: &proxy.UpstreamConfig{ Upstreams: upstreams, }, + UseDNS64: c.UseDNS64, + DNS64Prefs: c.DNS64Prefixes, }, } @@ -108,12 +89,14 @@ func addressesToUpstreams( upsStrs []string, bootstraps []string, timeout time.Duration, + preferIPv6 bool, ) (upstreams []upstream.Upstream, err error) { upstreams = make([]upstream.Upstream, len(upsStrs)) for i, upsStr := range upsStrs { upstreams[i], err = upstream.AddressToUpstream(upsStr, &upstream.Options{ - Bootstrap: bootstraps, - Timeout: timeout, + Bootstrap: bootstraps, + Timeout: timeout, + PreferIPv6: preferIPv6, }) if err != nil { return nil, fmt.Errorf("upstream at index %d: %w", i, err) @@ -206,10 +189,13 @@ func (svc *Service) Config() (c *Config) { } c = &Config{ - Addresses: addrs, - BootstrapServers: svc.bootstraps, - UpstreamServers: svc.upstreams, - UpstreamTimeout: svc.upsTimeout, + Addresses: addrs, + BootstrapServers: svc.bootstraps, + UpstreamServers: svc.upstreams, + DNS64Prefixes: svc.dns64Prefixes, + UpstreamTimeout: svc.upsTimeout, + BootstrapPreferIPv6: svc.bootstrapPreferIPv6, + UseDNS64: svc.useDNS64, } return c diff --git a/internal/next/dnssvc/dnssvc_test.go b/internal/next/dnssvc/dnssvc_test.go index 5e53ba49..48f49b8d 100644 --- a/internal/next/dnssvc/dnssvc_test.go +++ b/internal/next/dnssvc/dnssvc_test.go @@ -6,10 +6,7 @@ import ( "testing" "time" - "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/AdGuardHome/internal/next/dnssvc" - "github.com/AdguardTeam/dnsproxy/upstream" - "github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/testutil" "github.com/miekg/dns" "github.com/stretchr/testify/assert" @@ -21,36 +18,55 @@ func TestMain(m *testing.M) { } // testTimeout is the common timeout for tests. -const testTimeout = 100 * time.Millisecond +const testTimeout = 1 * time.Second func TestService(t *testing.T) { const ( - bootstrapAddr = "bootstrap.example" + listenAddr = "127.0.0.1:0" + bootstrapAddr = "127.0.0.1:0" upstreamAddr = "upstream.example" - - closeErr errors.Error = "closing failed" ) - ups := &aghtest.UpstreamMock{ - OnAddress: func() (addr string) { - return upstreamAddr - }, - OnExchange: func(req *dns.Msg) (resp *dns.Msg, err error) { - resp = (&dns.Msg{}).SetReply(req) + upstreamErrCh := make(chan error, 1) + upstreamStartedCh := make(chan struct{}) + upstreamSrv := &dns.Server{ + Addr: bootstrapAddr, + Net: "udp", + Handler: dns.HandlerFunc(func(w dns.ResponseWriter, req *dns.Msg) { + pt := testutil.PanicT{} - return resp, nil - }, - OnClose: func() (err error) { - return closeErr - }, + resp := (&dns.Msg{}).SetReply(req) + resp.Answer = append(resp.Answer, &dns.A{ + Hdr: dns.RR_Header{}, + A: netip.MustParseAddrPort(bootstrapAddr).Addr().AsSlice(), + }) + + writeErr := w.WriteMsg(resp) + require.NoError(pt, writeErr) + }), + NotifyStartedFunc: func() { close(upstreamStartedCh) }, } + go func() { + listenErr := upstreamSrv.ListenAndServe() + if listenErr != nil { + // Log these immediately to see what happens. + t.Logf("upstream listen error: %s", listenErr) + } + + upstreamErrCh <- listenErr + }() + + _, _ = testutil.RequireReceive(t, upstreamStartedCh, testTimeout) + c := &dnssvc.Config{ - Addresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:0")}, - Upstreams: []upstream.Upstream{ups}, - BootstrapServers: []string{bootstrapAddr}, - UpstreamServers: []string{upstreamAddr}, - UpstreamTimeout: testTimeout, + Addresses: []netip.AddrPort{netip.MustParseAddrPort(listenAddr)}, + BootstrapServers: []string{upstreamSrv.PacketConn.LocalAddr().String()}, + UpstreamServers: []string{upstreamAddr}, + DNS64Prefixes: nil, + UpstreamTimeout: testTimeout, + BootstrapPreferIPv6: false, + UseDNS64: false, } svc, err := dnssvc.New(c) @@ -82,8 +98,14 @@ func TestService(t *testing.T) { defer cancel() cli := &dns.Client{} - resp, _, excErr := cli.ExchangeContext(ctx, req, addr.String()) - require.NoError(t, excErr) + + var resp *dns.Msg + require.Eventually(t, func() (ok bool) { + var excErr error + resp, _, excErr = cli.ExchangeContext(ctx, req, addr.String()) + + return excErr == nil + }, testTimeout, testTimeout/10) assert.NotNil(t, resp) }) @@ -92,5 +114,12 @@ func TestService(t *testing.T) { defer cancel() err = svc.Shutdown(ctx) - require.ErrorIs(t, err, closeErr) + require.NoError(t, err) + + err = upstreamSrv.Shutdown() + require.NoError(t, err) + + err, ok := testutil.RequireReceive(t, upstreamErrCh, testTimeout) + require.True(t, ok) + require.NoError(t, err) } diff --git a/internal/next/websvc/dns.go b/internal/next/websvc/dns.go index 8846813d..34cf9a15 100644 --- a/internal/next/websvc/dns.go +++ b/internal/next/websvc/dns.go @@ -17,10 +17,13 @@ import ( type ReqPatchSettingsDNS struct { // TODO(a.garipov): Add more as we go. - Addresses []netip.AddrPort `json:"addresses"` - BootstrapServers []string `json:"bootstrap_servers"` - UpstreamServers []string `json:"upstream_servers"` - UpstreamTimeout JSONDuration `json:"upstream_timeout"` + Addresses []netip.AddrPort `json:"addresses"` + BootstrapServers []string `json:"bootstrap_servers"` + UpstreamServers []string `json:"upstream_servers"` + DNS64Prefixes []netip.Prefix `json:"dns64_prefixes"` + UpstreamTimeout JSONDuration `json:"upstream_timeout"` + BootstrapPreferIPv6 bool `json:"bootstrap_prefer_ipv6"` + UseDNS64 bool `json:"use_dns64"` } // HTTPAPIDNSSettings are the DNS settings as used by the HTTP API. See the @@ -28,10 +31,13 @@ type ReqPatchSettingsDNS struct { type HTTPAPIDNSSettings struct { // TODO(a.garipov): Add more as we go. - Addresses []netip.AddrPort `json:"addresses"` - BootstrapServers []string `json:"bootstrap_servers"` - UpstreamServers []string `json:"upstream_servers"` - UpstreamTimeout JSONDuration `json:"upstream_timeout"` + Addresses []netip.AddrPort `json:"addresses"` + BootstrapServers []string `json:"bootstrap_servers"` + UpstreamServers []string `json:"upstream_servers"` + DNS64Prefixes []netip.Prefix `json:"dns64_prefixes"` + UpstreamTimeout JSONDuration `json:"upstream_timeout"` + BootstrapPreferIPv6 bool `json:"bootstrap_prefer_ipv6"` + UseDNS64 bool `json:"use_dns64"` } // handlePatchSettingsDNS is the handler for the PATCH /api/v1/settings/dns HTTP @@ -53,10 +59,13 @@ func (svc *Service) handlePatchSettingsDNS(w http.ResponseWriter, r *http.Reques } newConf := &dnssvc.Config{ - Addresses: req.Addresses, - BootstrapServers: req.BootstrapServers, - UpstreamServers: req.UpstreamServers, - UpstreamTimeout: time.Duration(req.UpstreamTimeout), + Addresses: req.Addresses, + BootstrapServers: req.BootstrapServers, + UpstreamServers: req.UpstreamServers, + DNS64Prefixes: req.DNS64Prefixes, + UpstreamTimeout: time.Duration(req.UpstreamTimeout), + BootstrapPreferIPv6: req.BootstrapPreferIPv6, + UseDNS64: req.UseDNS64, } ctx := r.Context() @@ -76,9 +85,12 @@ func (svc *Service) handlePatchSettingsDNS(w http.ResponseWriter, r *http.Reques } writeJSONOKResponse(w, r, &HTTPAPIDNSSettings{ - Addresses: newConf.Addresses, - BootstrapServers: newConf.BootstrapServers, - UpstreamServers: newConf.UpstreamServers, - UpstreamTimeout: JSONDuration(newConf.UpstreamTimeout), + Addresses: newConf.Addresses, + BootstrapServers: newConf.BootstrapServers, + UpstreamServers: newConf.UpstreamServers, + DNS64Prefixes: newConf.DNS64Prefixes, + UpstreamTimeout: JSONDuration(newConf.UpstreamTimeout), + BootstrapPreferIPv6: newConf.BootstrapPreferIPv6, + UseDNS64: newConf.UseDNS64, }) } diff --git a/internal/next/websvc/dns_test.go b/internal/next/websvc/dns_test.go index 23cc02cb..c39ba1ab 100644 --- a/internal/next/websvc/dns_test.go +++ b/internal/next/websvc/dns_test.go @@ -20,10 +20,13 @@ import ( 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), + Addresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.1.1:53")}, + BootstrapServers: []string{"1.0.0.1"}, + UpstreamServers: []string{"1.1.1.1"}, + DNS64Prefixes: []netip.Prefix{netip.MustParsePrefix("1234::/64")}, + UpstreamTimeout: websvc.JSONDuration(2 * time.Second), + BootstrapPreferIPv6: true, + UseDNS64: true, } var started atomic.Bool @@ -51,10 +54,13 @@ func TestService_HandlePatchSettingsDNS(t *testing.T) { } req := jobj{ - "addresses": wantDNS.Addresses, - "bootstrap_servers": wantDNS.BootstrapServers, - "upstream_servers": wantDNS.UpstreamServers, - "upstream_timeout": wantDNS.UpstreamTimeout, + "addresses": wantDNS.Addresses, + "bootstrap_servers": wantDNS.BootstrapServers, + "upstream_servers": wantDNS.UpstreamServers, + "dns64_prefixes": wantDNS.DNS64Prefixes, + "upstream_timeout": wantDNS.UpstreamTimeout, + "bootstrap_prefer_ipv6": wantDNS.BootstrapPreferIPv6, + "use_dns64": wantDNS.UseDNS64, } respBody := httpPatch(t, u, req, http.StatusOK) diff --git a/internal/next/websvc/settings.go b/internal/next/websvc/settings.go index b6c5a80a..ab308836 100644 --- a/internal/next/websvc/settings.go +++ b/internal/next/websvc/settings.go @@ -27,10 +27,13 @@ func (svc *Service) handleGetSettingsAll(w http.ResponseWriter, r *http.Request) // TODO(a.garipov): Add all currently supported parameters. writeJSONOKResponse(w, r, &RespGetV1SettingsAll{ DNS: &HTTPAPIDNSSettings{ - Addresses: dnsConf.Addresses, - BootstrapServers: dnsConf.BootstrapServers, - UpstreamServers: dnsConf.UpstreamServers, - UpstreamTimeout: JSONDuration(dnsConf.UpstreamTimeout), + Addresses: dnsConf.Addresses, + BootstrapServers: dnsConf.BootstrapServers, + UpstreamServers: dnsConf.UpstreamServers, + DNS64Prefixes: dnsConf.DNS64Prefixes, + UpstreamTimeout: JSONDuration(dnsConf.UpstreamTimeout), + BootstrapPreferIPv6: dnsConf.BootstrapPreferIPv6, + UseDNS64: dnsConf.UseDNS64, }, HTTP: &HTTPAPIHTTPSettings{ Addresses: httpConf.Addresses, diff --git a/internal/next/websvc/settings_test.go b/internal/next/websvc/settings_test.go index e147a5c5..fc086524 100644 --- a/internal/next/websvc/settings_test.go +++ b/internal/next/websvc/settings_test.go @@ -20,10 +20,11 @@ func TestService_HandleGetSettingsAll(t *testing.T) { // TODO(a.garipov): Add all currently supported parameters. wantDNS := &websvc.HTTPAPIDNSSettings{ - Addresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:53")}, - BootstrapServers: []string{"94.140.14.140", "94.140.14.141"}, - UpstreamServers: []string{"94.140.14.14", "1.1.1.1"}, - UpstreamTimeout: websvc.JSONDuration(1 * time.Second), + Addresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:53")}, + BootstrapServers: []string{"94.140.14.140", "94.140.14.141"}, + UpstreamServers: []string{"94.140.14.14", "1.1.1.1"}, + UpstreamTimeout: websvc.JSONDuration(1 * time.Second), + BootstrapPreferIPv6: true, } wantWeb := &websvc.HTTPAPIHTTPSettings{ @@ -36,10 +37,11 @@ func TestService_HandleGetSettingsAll(t *testing.T) { confMgr := newConfigManager() confMgr.onDNS = func() (s agh.ServiceWithConfig[*dnssvc.Config]) { c, err := dnssvc.New(&dnssvc.Config{ - Addresses: wantDNS.Addresses, - UpstreamServers: wantDNS.UpstreamServers, - BootstrapServers: wantDNS.BootstrapServers, - UpstreamTimeout: time.Duration(wantDNS.UpstreamTimeout), + Addresses: wantDNS.Addresses, + UpstreamServers: wantDNS.UpstreamServers, + BootstrapServers: wantDNS.BootstrapServers, + UpstreamTimeout: time.Duration(wantDNS.UpstreamTimeout), + BootstrapPreferIPv6: true, }) require.NoError(t, err) diff --git a/internal/next/websvc/waitlistener_internal_test.go b/internal/next/websvc/waitlistener_internal_test.go index d7cc69f3..6911d137 100644 --- a/internal/next/websvc/waitlistener_internal_test.go +++ b/internal/next/websvc/waitlistener_internal_test.go @@ -6,7 +6,6 @@ import ( "sync/atomic" "testing" - "github.com/AdguardTeam/AdGuardHome/internal/aghchan" "github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/stretchr/testify/assert" ) @@ -26,9 +25,6 @@ func TestWaitListener_Accept(t *testing.T) { wg := &sync.WaitGroup{} wg.Add(1) - done := make(chan struct{}) - go aghchan.MustReceive(done, testTimeout) - go func() { var wrapper net.Listener = &waitListener{ Listener: l, @@ -39,7 +35,6 @@ func TestWaitListener_Accept(t *testing.T) { }() wg.Wait() - close(done) - assert.True(t, accepted.Load()) + assert.Eventually(t, accepted.Load, testTimeout, testTimeout/10) }