all: fix tests
This commit is contained in:
parent
6eff44311c
commit
78914a0632
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -32,6 +32,31 @@ NOTE: Add new changes BELOW THIS COMMENT.
|
||||||
control/querylog/config` accept and return query log config JSON file. The
|
control/querylog/config` accept and return query log config JSON file. The
|
||||||
format of request body is described in `openapi/openapi.yaml`.
|
format of request body is described in `openapi/openapi.yaml`.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
#### Configuration Changes
|
||||||
|
|
||||||
|
In this release, the schema version has changed from 16 to 17.
|
||||||
|
|
||||||
|
- Property `statistics.interval`, which in schema versions 16 and earlier used
|
||||||
|
to be an integer number of days, is now a string with a human-readable
|
||||||
|
duration:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# BEFORE:
|
||||||
|
'statistics':
|
||||||
|
# …
|
||||||
|
'interval': 1
|
||||||
|
|
||||||
|
# AFTER:
|
||||||
|
'statistics':
|
||||||
|
# …
|
||||||
|
'interval': '24h'
|
||||||
|
```
|
||||||
|
|
||||||
|
To rollback this change, convert the property back into days and change the
|
||||||
|
`schema_version` back to `16`.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Failing service installation via script on FreeBSD ([#5431]).
|
- Failing service installation via script on FreeBSD ([#5431]).
|
||||||
|
|
|
@ -486,7 +486,7 @@ func (c *configuration) write() (err error) {
|
||||||
if Context.stats != nil {
|
if Context.stats != nil {
|
||||||
statsConf := stats.Config{}
|
statsConf := stats.Config{}
|
||||||
Context.stats.WriteDiskConfig(&statsConf)
|
Context.stats.WriteDiskConfig(&statsConf)
|
||||||
config.Stats.Interval = timeutil.Duration{Duration: statsConf.LimitIvl}
|
config.Stats.Interval = timeutil.Duration{Duration: statsConf.Limit}
|
||||||
config.Stats.Enabled = statsConf.Enabled
|
config.Stats.Enabled = statsConf.Enabled
|
||||||
config.Stats.Ignored = statsConf.Ignored.Values()
|
config.Stats.Ignored = statsConf.Ignored.Values()
|
||||||
sort.Strings(config.Stats.Ignored)
|
sort.Strings(config.Stats.Ignored)
|
||||||
|
|
|
@ -51,7 +51,7 @@ func initDNS() (err error) {
|
||||||
|
|
||||||
statsConf := stats.Config{
|
statsConf := stats.Config{
|
||||||
Filename: filepath.Join(baseDir, "stats.db"),
|
Filename: filepath.Join(baseDir, "stats.db"),
|
||||||
LimitIvl: config.Stats.Interval.Duration,
|
Limit: config.Stats.Interval.Duration,
|
||||||
ConfigModified: onConfigModified,
|
ConfigModified: onConfigModified,
|
||||||
HTTPRegister: httpRegister,
|
HTTPRegister: httpRegister,
|
||||||
Enabled: config.Stats.Enabled,
|
Enabled: config.Stats.Enabled,
|
||||||
|
|
|
@ -38,16 +38,19 @@ type configJSON struct {
|
||||||
|
|
||||||
// configJSONv2 is the JSON structure for the querylog configuration.
|
// configJSONv2 is the JSON structure for the querylog configuration.
|
||||||
type configJSONv2 struct {
|
type configJSONv2 struct {
|
||||||
// Enabled shows if the querylog is enabled. It is an [aghalg.NullBool]
|
// Enabled shows if the querylog is enabled. It is an
|
||||||
// to be able to tell when it's set without using pointers.
|
// [aghalg.NullBool] to be able to tell when it's set without using
|
||||||
|
// pointers.
|
||||||
Enabled aghalg.NullBool `json:"enabled"`
|
Enabled aghalg.NullBool `json:"enabled"`
|
||||||
|
|
||||||
// AnonymizeClientIP shows if the clients' IP addresses must be anonymized.
|
// AnonymizeClientIP shows if the clients' IP addresses must be
|
||||||
// It is an [aghalg.NullBool] to be able to tell when it's set without using
|
// anonymized. It is an [aghalg.NullBool] to be able to tell when it's
|
||||||
// pointers.
|
// set without using pointers.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Consider using separate setting for statistics.
|
||||||
AnonymizeClientIP aghalg.NullBool `json:"anonymize_client_ip"`
|
AnonymizeClientIP aghalg.NullBool `json:"anonymize_client_ip"`
|
||||||
|
|
||||||
// Interval is the querylog rotation interval.
|
// Interval is the querylog rotation interval in milliseconds
|
||||||
Interval float64 `json:"interval"`
|
Interval float64 `json:"interval"`
|
||||||
|
|
||||||
// Ignored is the list of host names, which should not be written to
|
// Ignored is the list of host names, which should not be written to
|
||||||
|
|
|
@ -47,7 +47,7 @@ func (s *StatsCtx) handleStats(w http.ResponseWriter, r *http.Request) {
|
||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
resp, ok := s.getData(uint32(s.limitIvl.Hours()))
|
resp, ok := s.getData(uint32(s.limit.Hours()))
|
||||||
log.Debug("stats: prepared data in %v", time.Since(start))
|
log.Debug("stats: prepared data in %v", time.Since(start))
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -72,7 +72,7 @@ type configRespV2 struct {
|
||||||
// to be able to tell when it's set without using pointers.
|
// to be able to tell when it's set without using pointers.
|
||||||
Enabled aghalg.NullBool `json:"enabled"`
|
Enabled aghalg.NullBool `json:"enabled"`
|
||||||
|
|
||||||
// Interval is the statistics rotation interval.
|
// Interval is the statistics rotation interval in milliseconds.
|
||||||
Interval float64 `json:"interval"`
|
Interval float64 `json:"interval"`
|
||||||
|
|
||||||
// Ignored is the list of host names, which should not be counted.
|
// Ignored is the list of host names, which should not be counted.
|
||||||
|
@ -86,7 +86,7 @@ func (s *StatsCtx) handleStatsInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
days := uint32(s.limitIvl.Hours() / 24)
|
days := uint32(s.limit.Hours() / 24)
|
||||||
|
|
||||||
ok := checkInterval(days)
|
ok := checkInterval(days)
|
||||||
if !ok || (s.enabled && days == 0) {
|
if !ok || (s.enabled && days == 0) {
|
||||||
|
@ -107,7 +107,7 @@ func (s *StatsCtx) handleStatsInfoV2(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
resp := configRespV2{
|
resp := configRespV2{
|
||||||
Enabled: aghalg.BoolToNullBool(s.enabled),
|
Enabled: aghalg.BoolToNullBool(s.enabled),
|
||||||
Interval: float64(s.limitIvl.Milliseconds()),
|
Interval: float64(s.limit.Milliseconds()),
|
||||||
Ignored: s.ignored.Values(),
|
Ignored: s.ignored.Values(),
|
||||||
}
|
}
|
||||||
err := aghhttp.WriteJSONResponse(w, r, resp)
|
err := aghhttp.WriteJSONResponse(w, r, resp)
|
||||||
|
@ -169,7 +169,7 @@ func (s *StatsCtx) handleStatsConfigV2(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
s.enabled = reqData.Enabled == aghalg.NBTrue
|
s.enabled = reqData.Enabled == aghalg.NBTrue
|
||||||
|
|
||||||
s.limitIvl = ivl
|
s.limit = ivl
|
||||||
|
|
||||||
if len(reqData.Ignored) > 0 {
|
if len(reqData.Ignored) > 0 {
|
||||||
set, serr := aghnet.NewDomainNameSet(reqData.Ignored)
|
set, serr := aghnet.NewDomainNameSet(reqData.Ignored)
|
||||||
|
|
|
@ -27,6 +27,7 @@ func TestHandleStatsV2(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
body configRespV2
|
body configRespV2
|
||||||
wantCode int
|
wantCode int
|
||||||
|
wantErr string
|
||||||
}{{
|
}{{
|
||||||
name: "set_ivl_1_hour",
|
name: "set_ivl_1_hour",
|
||||||
body: configRespV2{
|
body: configRespV2{
|
||||||
|
@ -35,6 +36,7 @@ func TestHandleStatsV2(t *testing.T) {
|
||||||
Ignored: nil,
|
Ignored: nil,
|
||||||
},
|
},
|
||||||
wantCode: http.StatusOK,
|
wantCode: http.StatusOK,
|
||||||
|
wantErr: "",
|
||||||
}, {
|
}, {
|
||||||
name: "small_interval",
|
name: "small_interval",
|
||||||
body: configRespV2{
|
body: configRespV2{
|
||||||
|
@ -43,6 +45,7 @@ func TestHandleStatsV2(t *testing.T) {
|
||||||
Ignored: []string{},
|
Ignored: []string{},
|
||||||
},
|
},
|
||||||
wantCode: http.StatusBadRequest,
|
wantCode: http.StatusBadRequest,
|
||||||
|
wantErr: "unsupported interval\n",
|
||||||
}, {
|
}, {
|
||||||
name: "big_interval",
|
name: "big_interval",
|
||||||
body: configRespV2{
|
body: configRespV2{
|
||||||
|
@ -51,6 +54,7 @@ func TestHandleStatsV2(t *testing.T) {
|
||||||
Ignored: []string{},
|
Ignored: []string{},
|
||||||
},
|
},
|
||||||
wantCode: http.StatusBadRequest,
|
wantCode: http.StatusBadRequest,
|
||||||
|
wantErr: "unsupported interval\n",
|
||||||
}, {
|
}, {
|
||||||
name: "set_ignored_ivl_1_year",
|
name: "set_ignored_ivl_1_year",
|
||||||
body: configRespV2{
|
body: configRespV2{
|
||||||
|
@ -58,10 +62,11 @@ func TestHandleStatsV2(t *testing.T) {
|
||||||
Interval: float64(year.Milliseconds()),
|
Interval: float64(year.Milliseconds()),
|
||||||
Ignored: []string{
|
Ignored: []string{
|
||||||
"ignor.ed",
|
"ignor.ed",
|
||||||
"ignor.ed",
|
"ignored.to",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantCode: http.StatusBadRequest,
|
wantCode: http.StatusOK,
|
||||||
|
wantErr: "",
|
||||||
}, {
|
}, {
|
||||||
name: "ignored_duplicate",
|
name: "ignored_duplicate",
|
||||||
body: configRespV2{
|
body: configRespV2{
|
||||||
|
@ -73,6 +78,7 @@ func TestHandleStatsV2(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantCode: http.StatusBadRequest,
|
wantCode: http.StatusBadRequest,
|
||||||
|
wantErr: "ignored: duplicate host name \"ignor.ed\"\n",
|
||||||
}, {
|
}, {
|
||||||
name: "ignored_empty",
|
name: "ignored_empty",
|
||||||
body: configRespV2{
|
body: configRespV2{
|
||||||
|
@ -83,6 +89,7 @@ func TestHandleStatsV2(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantCode: http.StatusBadRequest,
|
wantCode: http.StatusBadRequest,
|
||||||
|
wantErr: "ignored: host name is empty\n",
|
||||||
}}
|
}}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
@ -91,7 +98,7 @@ func TestHandleStatsV2(t *testing.T) {
|
||||||
|
|
||||||
conf := Config{
|
conf := Config{
|
||||||
Filename: filepath.Join(t.TempDir(), "stats.db"),
|
Filename: filepath.Join(t.TempDir(), "stats.db"),
|
||||||
LimitIvl: time.Hour * 24,
|
Limit: time.Hour * 24,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
UnitID: func() (id uint32) { return 0 },
|
UnitID: func() (id uint32) { return 0 },
|
||||||
HTTPRegister: func(
|
HTTPRegister: func(
|
||||||
|
@ -106,6 +113,7 @@ func TestHandleStatsV2(t *testing.T) {
|
||||||
|
|
||||||
s, err := New(conf)
|
s, err := New(conf)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
s.Start()
|
s.Start()
|
||||||
testutil.CleanupAndRequireSuccess(t, s.Close)
|
testutil.CleanupAndRequireSuccess(t, s.Close)
|
||||||
|
|
||||||
|
@ -119,22 +127,27 @@ func TestHandleStatsV2(t *testing.T) {
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPut, configPut, bytes.NewReader(buf))
|
req := httptest.NewRequest(http.MethodPut, configPut, bytes.NewReader(buf))
|
||||||
rw := httptest.NewRecorder()
|
rw := httptest.NewRecorder()
|
||||||
|
|
||||||
handlers[configPut].ServeHTTP(rw, req)
|
handlers[configPut].ServeHTTP(rw, req)
|
||||||
require.Equal(t, tc.wantCode, rw.Code)
|
require.Equal(t, tc.wantCode, rw.Code)
|
||||||
|
|
||||||
if tc.wantCode == http.StatusOK {
|
if tc.wantCode != http.StatusOK {
|
||||||
|
assert.Equal(t, tc.wantErr, rw.Body.String())
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
resp := httptest.NewRequest(http.MethodGet, configGet, nil)
|
resp := httptest.NewRequest(http.MethodGet, configGet, nil)
|
||||||
rw = httptest.NewRecorder()
|
rw = httptest.NewRecorder()
|
||||||
|
|
||||||
handlers[configGet].ServeHTTP(rw, resp)
|
handlers[configGet].ServeHTTP(rw, resp)
|
||||||
require.Equal(t, http.StatusOK, rw.Code)
|
require.Equal(t, http.StatusOK, rw.Code)
|
||||||
data := rw.Body.Bytes()
|
|
||||||
|
|
||||||
ans := configRespV2{}
|
ans := configRespV2{}
|
||||||
jerr := json.Unmarshal(data, &ans)
|
jerr := json.Unmarshal(rw.Body.Bytes(), &ans)
|
||||||
require.NoError(t, jerr)
|
require.NoError(t, jerr)
|
||||||
|
|
||||||
assert.Equal(t, tc.body, ans)
|
assert.Equal(t, tc.body, ans)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,9 +43,9 @@ type Config struct {
|
||||||
// Filename is the name of the database file.
|
// Filename is the name of the database file.
|
||||||
Filename string
|
Filename string
|
||||||
|
|
||||||
// LimitIvl is the interval for collecting statistics into the current
|
// Limit is an upper limit for collecting statistics into the
|
||||||
// unit.
|
// current unit.
|
||||||
LimitIvl time.Duration
|
Limit time.Duration
|
||||||
|
|
||||||
// Enabled tells if the statistics are enabled.
|
// Enabled tells if the statistics are enabled.
|
||||||
Enabled bool
|
Enabled bool
|
||||||
|
@ -106,9 +106,9 @@ type StatsCtx struct {
|
||||||
// enabled tells if the statistics are enabled.
|
// enabled tells if the statistics are enabled.
|
||||||
enabled bool
|
enabled bool
|
||||||
|
|
||||||
// limitIvl is the interval for collecting statistics into the current
|
// limit is an upper limit for collecting statistics into the
|
||||||
// unit.
|
// current unit.
|
||||||
limitIvl time.Duration
|
limit time.Duration
|
||||||
|
|
||||||
// ignored is the list of host names, which should not be counted.
|
// ignored is the list of host names, which should not be counted.
|
||||||
ignored *stringutil.Set
|
ignored *stringutil.Set
|
||||||
|
@ -128,15 +128,15 @@ func New(conf Config) (s *StatsCtx, err error) {
|
||||||
ignored: conf.Ignored,
|
ignored: conf.Ignored,
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.LimitIvl < time.Hour {
|
if conf.Limit < time.Hour {
|
||||||
return nil, errors.Error("interval: less than an hour")
|
return nil, errors.Error("interval: less than an hour")
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.LimitIvl > timeutil.Day*365 {
|
if conf.Limit > timeutil.Day*365 {
|
||||||
return nil, errors.Error("interval: more than a year")
|
return nil, errors.Error("interval: more than a year")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.limitIvl = conf.LimitIvl
|
s.limit = conf.Limit
|
||||||
|
|
||||||
if s.unitIDGen = newUnitID; conf.UnitID != nil {
|
if s.unitIDGen = newUnitID; conf.UnitID != nil {
|
||||||
s.unitIDGen = conf.UnitID
|
s.unitIDGen = conf.UnitID
|
||||||
|
@ -157,7 +157,7 @@ func New(conf Config) (s *StatsCtx, err error) {
|
||||||
return nil, fmt.Errorf("stats: opening a transaction: %w", err)
|
return nil, fmt.Errorf("stats: opening a transaction: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
deleted := deleteOldUnits(tx, id-uint32(s.limitIvl.Hours())-1)
|
deleted := deleteOldUnits(tx, id-uint32(s.limit.Hours())-1)
|
||||||
udb = loadUnitFromDB(tx, id)
|
udb = loadUnitFromDB(tx, id)
|
||||||
|
|
||||||
err = finishTxn(tx, deleted > 0)
|
err = finishTxn(tx, deleted > 0)
|
||||||
|
@ -238,7 +238,7 @@ func (s *StatsCtx) Update(e Entry) {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
if !s.enabled || s.limitIvl == 0 {
|
if !s.enabled || s.limit == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ func (s *StatsCtx) WriteDiskConfig(dc *Config) {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
dc.LimitIvl = s.limitIvl
|
dc.Limit = s.limit
|
||||||
dc.Enabled = s.enabled
|
dc.Enabled = s.enabled
|
||||||
dc.Ignored = s.ignored
|
dc.Ignored = s.ignored
|
||||||
}
|
}
|
||||||
|
@ -280,7 +280,7 @@ func (s *StatsCtx) TopClientsIP(maxCount uint) (ips []netip.Addr) {
|
||||||
s.lock.Lock()
|
s.lock.Lock()
|
||||||
defer s.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
limit := uint32(s.limitIvl.Hours())
|
limit := uint32(s.limit.Hours())
|
||||||
if !s.enabled || limit == 0 {
|
if !s.enabled || limit == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -384,7 +384,7 @@ func (s *StatsCtx) flush() (cont bool, sleepFor time.Duration) {
|
||||||
return false, 0
|
return false, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
limit := uint32(s.limitIvl.Hours())
|
limit := uint32(s.limit.Hours())
|
||||||
if limit == 0 || ptr.id == id {
|
if limit == 0 || ptr.id == id {
|
||||||
return true, time.Second
|
return true, time.Second
|
||||||
}
|
}
|
||||||
|
@ -450,7 +450,7 @@ func (s *StatsCtx) periodicFlush() {
|
||||||
func (s *StatsCtx) setLimitLocked(limitDays int) {
|
func (s *StatsCtx) setLimitLocked(limitDays int) {
|
||||||
if limitDays != 0 {
|
if limitDays != 0 {
|
||||||
s.enabled = true
|
s.enabled = true
|
||||||
s.limitIvl = time.Duration(int(timeutil.Day) * limitDays)
|
s.limit = time.Duration(int(timeutil.Day) * limitDays)
|
||||||
log.Debug("stats: set limit: %d days", limitDays)
|
log.Debug("stats: set limit: %d days", limitDays)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
|
"github.com/AdguardTeam/golibs/timeutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -37,7 +38,7 @@ func TestStats_races(t *testing.T) {
|
||||||
conf := Config{
|
conf := Config{
|
||||||
UnitID: idGen,
|
UnitID: idGen,
|
||||||
Filename: filepath.Join(t.TempDir(), "./stats.db"),
|
Filename: filepath.Join(t.TempDir(), "./stats.db"),
|
||||||
LimitIvl: time.Hour * 24,
|
Limit: timeutil.Day,
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := New(conf)
|
s, err := New(conf)
|
||||||
|
|
|
@ -9,11 +9,11 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/stats"
|
"github.com/AdguardTeam/AdGuardHome/internal/stats"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
"github.com/AdguardTeam/golibs/testutil"
|
"github.com/AdguardTeam/golibs/testutil"
|
||||||
|
"github.com/AdguardTeam/golibs/timeutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -53,7 +53,7 @@ func TestStats(t *testing.T) {
|
||||||
handlers := map[string]http.Handler{}
|
handlers := map[string]http.Handler{}
|
||||||
conf := stats.Config{
|
conf := stats.Config{
|
||||||
Filename: filepath.Join(t.TempDir(), "stats.db"),
|
Filename: filepath.Join(t.TempDir(), "stats.db"),
|
||||||
LimitIvl: time.Hour * 24,
|
Limit: timeutil.Day,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
UnitID: constUnitID,
|
UnitID: constUnitID,
|
||||||
HTTPRegister: func(_, url string, handler http.HandlerFunc) {
|
HTTPRegister: func(_, url string, handler http.HandlerFunc) {
|
||||||
|
@ -159,7 +159,7 @@ func TestLargeNumbers(t *testing.T) {
|
||||||
|
|
||||||
conf := stats.Config{
|
conf := stats.Config{
|
||||||
Filename: filepath.Join(t.TempDir(), "stats.db"),
|
Filename: filepath.Join(t.TempDir(), "stats.db"),
|
||||||
LimitIvl: time.Hour * 24,
|
Limit: timeutil.Day,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
UnitID: func() (id uint32) { return atomic.LoadUint32(&curHour) },
|
UnitID: func() (id uint32) { return atomic.LoadUint32(&curHour) },
|
||||||
HTTPRegister: func(_, url string, handler http.HandlerFunc) { handlers[url] = handler },
|
HTTPRegister: func(_, url string, handler http.HandlerFunc) { handlers[url] = handler },
|
||||||
|
|
Loading…
Reference in New Issue