@@ -10,6 +10,7 @@ import (
10
10
"strings"
11
11
"sync"
12
12
"testing"
13
+ "time"
13
14
14
15
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
15
16
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
@@ -65,6 +66,7 @@ func armMonitorMetricsClientFuncMock(string, azcore.TokenCredential, *arm.Client
65
66
66
67
func TestAzureScraperStart (t * testing.T ) {
67
68
cfg := createDefaultConfig ().(* Config )
69
+ timeMock := getTimeMock ()
68
70
69
71
tests := []struct {
70
72
name string
@@ -76,6 +78,7 @@ func TestAzureScraperStart(t *testing.T) {
76
78
testFunc : func (t * testing.T ) {
77
79
s := & azureScraper {
78
80
cfg : cfg ,
81
+ time : timeMock ,
79
82
azIDCredentialsFunc : azIDCredentialsFuncMock ,
80
83
azIDWorkloadFunc : azIDWorkloadFuncMock ,
81
84
armClientFunc : armClientFuncMock ,
@@ -104,6 +107,7 @@ func TestAzureScraperStart(t *testing.T) {
104
107
}
105
108
s := & azureScraper {
106
109
cfg : customCfg ,
110
+ time : timeMock ,
107
111
azIDCredentialsFunc : azIDCredentialsFuncMock ,
108
112
azIDWorkloadFunc : azIDWorkloadFuncMock ,
109
113
armClientFunc : armClientFuncMock ,
@@ -132,6 +136,7 @@ func TestAzureScraperStart(t *testing.T) {
132
136
}
133
137
s := & azureScraper {
134
138
cfg : customCfg ,
139
+ time : timeMock ,
135
140
azIDCredentialsFunc : azIDCredentialsFuncMock ,
136
141
azIDWorkloadFunc : azIDWorkloadFuncMock ,
137
142
armClientFunc : armClientFuncMock ,
@@ -160,6 +165,7 @@ func TestAzureScraperStart(t *testing.T) {
160
165
}
161
166
s := & azureScraper {
162
167
cfg : customCfg ,
168
+ time : timeMock ,
163
169
azIDCredentialsFunc : azIDCredentialsFuncMock ,
164
170
azManagedIdentityFunc : azManagedIdentityFuncMock ,
165
171
armClientFunc : armClientFuncMock ,
@@ -188,6 +194,7 @@ func TestAzureScraperStart(t *testing.T) {
188
194
}
189
195
s := & azureScraper {
190
196
cfg : customCfg ,
197
+ time : timeMock ,
191
198
azIDCredentialsFunc : azIDCredentialsFuncMock ,
192
199
azDefaultCredentialsFunc : azDefaultCredentialsFuncMock ,
193
200
armClientFunc : armClientFuncMock ,
@@ -319,6 +326,7 @@ func TestAzureScraperScrape(t *testing.T) {
319
326
clientMetricsValues : metricsValuesClientMock ,
320
327
mb : metadata .NewMetricsBuilder (metadata .DefaultMetricsBuilderConfig (), settings ),
321
328
mutex : & sync.Mutex {},
329
+ time : getTimeMock (),
322
330
}
323
331
s .resources = map [string ]* azureResource {}
324
332
@@ -342,6 +350,95 @@ func TestAzureScraperScrape(t *testing.T) {
342
350
}
343
351
}
344
352
353
+ func TestAzureScraperScrapeHonorTimeGrain (t * testing.T ) {
354
+ getTestScraper := func () * azureScraper {
355
+ armClientMock := & armClientMock {
356
+ current : 0 ,
357
+ pages : getResourcesMockData (false ),
358
+ }
359
+ counters , pages := getMetricsDefinitionsMockData ()
360
+ metricsDefinitionsClientMock := & metricsDefinitionsClientMock {
361
+ current : counters ,
362
+ pages : pages ,
363
+ }
364
+ metricsValuesClientMock := & metricsValuesClientMock {
365
+ lists : getMetricsValuesMockData (),
366
+ }
367
+
368
+ return & azureScraper {
369
+ cfg : createDefaultConfig ().(* Config ),
370
+ clientResources : armClientMock ,
371
+ clientMetricsDefinitions : metricsDefinitionsClientMock ,
372
+ clientMetricsValues : metricsValuesClientMock ,
373
+ mb : metadata .NewMetricsBuilder (
374
+ metadata .DefaultMetricsBuilderConfig (),
375
+ receivertest .NewNopSettings (),
376
+ ),
377
+ mutex : & sync.Mutex {},
378
+ resources : map [string ]* azureResource {},
379
+ time : getTimeMock (),
380
+ }
381
+ }
382
+
383
+ ctx := context .Background ()
384
+
385
+ t .Run ("do_not_fetch_in_same_interval" , func (t * testing.T ) {
386
+ s := getTestScraper ()
387
+
388
+ metrics , err := s .scrape (ctx )
389
+
390
+ require .NoError (t , err , "should not fail" )
391
+ require .Positive (t , metrics .MetricCount (), "should return metrics on first call" )
392
+
393
+ metrics , err = s .scrape (ctx )
394
+
395
+ require .NoError (t , err , "should not fail" )
396
+ require .Equal (t , 0 , metrics .MetricCount (), "should not return metrics on second call" )
397
+ })
398
+
399
+ t .Run ("fetch_each_new_interval" , func (t * testing.T ) {
400
+ timeJitter := time .Second
401
+ timeInterval := 50 * time .Second
402
+ timeIntervals := []time.Time {
403
+ time .Now ().Add (time .Minute ),
404
+ time .Now ().Add (time .Minute + 1 * timeInterval - timeJitter ),
405
+ time .Now ().Add (time .Minute + 2 * timeInterval + timeJitter ),
406
+ time .Now ().Add (time .Minute + 3 * timeInterval - timeJitter ),
407
+ time .Now ().Add (time .Minute + 4 * timeInterval + timeJitter ),
408
+ }
409
+ s := getTestScraper ()
410
+ mockedTime := s .time .(* timeMock )
411
+
412
+ for _ , timeNowNew := range timeIntervals {
413
+ // implementation uses time.Sub to check if timeWrapper.Now satisfy time grain
414
+ // we can travel in time by adjusting result of timeWrapper.Now
415
+ prevTime := mockedTime .time
416
+ mockedTime .time = timeNowNew
417
+
418
+ metrics , err := s .scrape (ctx )
419
+
420
+ require .NoError (t , err , "should not fail" )
421
+ if prevTime .Minute () == timeNowNew .Minute () {
422
+ require .Equal (t , 0 , metrics .MetricCount (), "should not fetch metrics in the same minute" )
423
+ } else {
424
+ require .Positive (t , metrics .MetricCount (), "should fetch metrics in a new minute" )
425
+ }
426
+ }
427
+ })
428
+ }
429
+
430
+ type timeMock struct {
431
+ time time.Time
432
+ }
433
+
434
+ func (t * timeMock ) Now () time.Time {
435
+ return t .time
436
+ }
437
+
438
+ func getTimeMock () timeNowIface {
439
+ return & timeMock {time : time .Now ()}
440
+ }
441
+
345
442
func getResourcesMockData (tags bool ) []armresources.ClientListResponse {
346
443
id1 , id2 , id3 , location1 , name1 , type1 := "/resourceGroups/group1/resourceId1" ,
347
444
"/resourceGroups/group1/resourceId2" , "/resourceGroups/group1/resourceId3" , "location1" , "name1" , "type1"
0 commit comments