@@ -3,6 +3,7 @@ package stats
33import (
44 "bytes"
55 "encoding/json"
6+ "fmt"
67 "net/http"
78 "net/http/httptest"
89 "path/filepath"
@@ -13,12 +14,22 @@ import (
1314 "github.com/AdguardTeam/AdGuardHome/internal/aghalg"
1415 "github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
1516 "github.com/AdguardTeam/golibs/logutil/slogutil"
17+ "github.com/AdguardTeam/golibs/netutil"
1618 "github.com/AdguardTeam/golibs/testutil"
1719 "github.com/AdguardTeam/golibs/timeutil"
1820 "github.com/stretchr/testify/assert"
1921 "github.com/stretchr/testify/require"
2022)
2123
24+ // testLogger is the common logger for tests.
25+ var testLogger = slogutil .NewDiscardLogger ()
26+
27+ // Common domain values for tests.
28+ const (
29+ TestDomain1 = "example.com"
30+ TestDomain2 = "example.org"
31+ )
32+
2233func TestHandleStatsConfig (t * testing.T ) {
2334 const (
2435 smallIvl = 1 * time .Minute
@@ -27,13 +38,13 @@ func TestHandleStatsConfig(t *testing.T) {
2738 )
2839
2940 conf := Config {
30- Logger : slogutil . NewDiscardLogger () ,
41+ Logger : testLogger ,
3142 UnitID : func () (id uint32 ) { return 0 },
3243 ConfigModifier : agh.EmptyConfigModifier {},
3344 ShouldCountClient : func ([]string ) bool { return true },
3445 HTTPReg : aghhttp.EmptyRegistrar {},
3546 Filename : filepath .Join (t .TempDir (), "stats.db" ),
36- Limit : time . Hour * 24 ,
47+ Limit : 24 * time . Hour ,
3748 Enabled : true ,
3849 }
3950
@@ -138,3 +149,117 @@ func TestHandleStatsConfig(t *testing.T) {
138149 })
139150 }
140151}
152+
153+ // populateTestData is a helper that creates test entries in db. s must not be
154+ // nil.
155+ func populateTestData (tb testing.TB , s * StatsCtx ) {
156+ tb .Helper ()
157+
158+ oldUnitID := newUnitID () - 1
159+ oldUnit := & unitDB {
160+ NResult : make ([]uint64 , resultLast ),
161+ Domains : []countPair {{Name : TestDomain1 , Count : 1 }},
162+ NTotal : 1 ,
163+ }
164+
165+ db := s .db .Load ()
166+ tx , err := db .Begin (true )
167+ require .NoError (tb , err )
168+
169+ err = s .flushUnitToDB (oldUnit , tx , uint32 (oldUnitID ))
170+ require .NoError (tb , err )
171+
172+ err = finishTxn (tx , true )
173+ require .NoError (tb , err )
174+
175+ s .Update (& Entry {
176+ Client : netutil .IPv4Localhost ().String (),
177+ Domain : TestDomain2 ,
178+ ProcessingTime : 3 * time .Minute ,
179+ Result : RNotFiltered ,
180+ })
181+ }
182+
183+ func TestStatsCtx_handleStats (t * testing.T ) {
184+ conf := Config {
185+ Logger : testLogger ,
186+ UnitID : newUnitID ,
187+ ConfigModifier : agh.EmptyConfigModifier {},
188+ ShouldCountClient : func ([]string ) bool { return true },
189+ HTTPReg : aghhttp.EmptyRegistrar {},
190+ Filename : filepath .Join (t .TempDir (), "stats.db" ),
191+ Limit : 24 * time .Hour ,
192+ Enabled : true ,
193+ }
194+
195+ testCases := []struct {
196+ name string
197+ wantErr string
198+ wantTopQueriedDomains []topAddrs
199+ wantDNSQueries uint64
200+ wantCode int
201+ recent int64
202+ }{{
203+ name : "short_interval" ,
204+ wantErr : "recent: out of range: must be no less than 3600000, got 240000\n " ,
205+ wantCode : http .StatusBadRequest ,
206+ recent : 4 * time .Minute .Milliseconds (),
207+ }, {
208+ name : "long_interval" ,
209+ wantErr : "recent: out of range: must be no greater than 86400000, got 259200000\n " ,
210+ wantCode : http .StatusBadRequest ,
211+ recent : 72 * time .Hour .Milliseconds (),
212+ }, {
213+ name : "no_interval" ,
214+ wantCode : http .StatusOK ,
215+ wantDNSQueries : 2 ,
216+ wantTopQueriedDomains : []topAddrs {{
217+ TestDomain1 : 1 ,
218+ }, {
219+ TestDomain2 : 1 ,
220+ }},
221+ }, {
222+ name : "valid_interval" ,
223+ wantCode : http .StatusOK ,
224+ wantDNSQueries : 1 ,
225+ wantTopQueriedDomains : []topAddrs {{
226+ TestDomain2 : 1 ,
227+ }},
228+ recent : time .Hour .Milliseconds (),
229+ }}
230+
231+ s , err := New (conf )
232+ require .NoError (t , err )
233+
234+ s .Start ()
235+ defer testutil .CleanupAndRequireSuccess (t , s .Close )
236+
237+ populateTestData (t , s )
238+ for _ , tc := range testCases {
239+ t .Run (tc .name , func (t * testing.T ) {
240+ url := "/control/stats"
241+ if tc .recent != 0 {
242+ url += fmt .Sprintf ("?recent=%d" , tc .recent )
243+ }
244+
245+ req := httptest .NewRequest (http .MethodGet , url , nil )
246+ rw := httptest .NewRecorder ()
247+
248+ s .handleStats (rw , req )
249+ require .Equal (t , tc .wantCode , rw .Code )
250+
251+ if rw .Code != http .StatusOK {
252+ require .Equal (t , tc .wantErr , rw .Body .String ())
253+
254+ return
255+ }
256+
257+ ans := StatsResp {}
258+ err = json .Unmarshal (rw .Body .Bytes (), & ans )
259+ require .NoError (t , err )
260+
261+ assert .Equal (t , tc .wantDNSQueries , ans .NumDNSQueries )
262+ assert .ElementsMatch (t , tc .wantTopQueriedDomains , ans .TopQueried )
263+ })
264+ }
265+ }
0 commit comments