Skip to content

Commit 3601b98

Browse files
committed
add threshold alerting based on dynamic configuration
1 parent 727ca52 commit 3601b98

File tree

9 files changed

+139
-24
lines changed

9 files changed

+139
-24
lines changed

mocks/add_metrics.go

+8-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/config/config.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,8 @@ type Static struct {
2323
}
2424

2525
type Dynamic struct {
26-
Test string
26+
Threshold struct {
27+
Min float64
28+
Max float64
29+
}
2730
}

pkg/config/dynamic.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"github.com/fsnotify/fsnotify"
66
"github.com/prometheus/common/log"
77
"github.com/spf13/viper"
8+
"iot-demo/pkg/metrics/alert"
89
"sync"
910
)
1011

@@ -15,8 +16,8 @@ type DynamicGetter struct {
1516
}
1617

1718

18-
func (dg *DynamicGetter) GetMessage() string {
19-
return dg.getCurrent().Test
19+
func (dg *DynamicGetter) GetThreshold() alert.Threshold {
20+
return dg.getCurrent().Threshold
2021
}
2122

2223
func NewDynamicGetter(s Selection) (*DynamicGetter, error) {

pkg/http/docs/docs.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
22
// This file was generated by swaggo/swag at
3-
// 2020-02-21 08:47:45.733339 +0300 +03 m=+3.843943819
3+
// 2020-02-21 11:58:17.562006 +0300 +03 m=+3.916537146
44

55
package docs
66

+23-6
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,48 @@
11
package add_metrics
22

33
import (
4+
"iot-demo/pkg/metrics/alert"
45
"iot-demo/pkg/metrics/ingestion"
56
)
67

8+
type ResponseToken string
9+
const (
10+
Alert ResponseToken = "ALERT"
11+
Ok ResponseToken = "OK"
12+
)
13+
714
type Inserter interface {
815
Insert(deviceID int, metricsToInsert []*ingestion.DecimalMetricValue) error
916
}
1017

1118
type ConfigGetter interface {
12-
GetMessage() string
19+
GetThreshold() alert.Threshold
1320
}
1421

1522
type Service struct {
1623
inserter Inserter
17-
getter ConfigGetter
24+
config ConfigGetter
1825
}
1926

20-
func (s *Service) Add(deviceID int, metricsToInsert []*ingestion.DecimalMetricValue) (string, error) {
27+
func (s *Service) Add(deviceID int, metricsToInsert []*ingestion.DecimalMetricValue) (ResponseToken, error) {
2128
err := s.inserter.Insert(deviceID, metricsToInsert)
2229
if err != nil {
2330
return "", err
2431
}
2532

26-
return s.getter.GetMessage(), nil
33+
threshold := s.config.GetThreshold()
34+
return getMessage(threshold, metricsToInsert), nil
35+
}
36+
37+
func getMessage(threshold alert.Threshold, metrics []*ingestion.DecimalMetricValue) ResponseToken {
38+
for _, metric := range metrics {
39+
if threshold.DoesMatch(metric.Value) {
40+
return Alert
41+
}
42+
}
43+
return Ok
2744
}
2845

29-
func NewService(inserter Inserter, getter ConfigGetter) *Service {
30-
return &Service{inserter: inserter, getter: getter}
46+
func NewService(inserter Inserter, config ConfigGetter) *Service {
47+
return &Service{inserter: inserter, config: config}
3148
}

pkg/metrics/add-metrics/add_metrics_test.go

+51-6
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import (
66
"github.com/stretchr/testify/assert"
77
"iot-demo/mocks"
88
add_metrics "iot-demo/pkg/metrics/add-metrics"
9+
"iot-demo/pkg/metrics/alert"
910
"iot-demo/pkg/metrics/ingestion"
1011
"testing"
12+
"time"
1113
)
1214

1315
//go:generate mockgen -package mocks -destination ../../../mocks/add_metrics.go iot-demo/pkg/metrics/add-metrics Inserter,ConfigGetter
@@ -33,7 +35,7 @@ func TestAdd_Should_Fail_If_Insert_Fails(t *testing.T) {
3335

3436
getter.
3537
EXPECT().
36-
GetMessage().
38+
GetThreshold().
3739
Times(0)
3840

3941
// Act
@@ -44,13 +46,16 @@ func TestAdd_Should_Fail_If_Insert_Fails(t *testing.T) {
4446
assert.Equal(t, err, expectedErr)
4547
}
4648

47-
func TestAdd_Should_Succeed_And_Return_Get_Message(t *testing.T) {
49+
func TestAdd_Should_Succeed_And_Return_Ok(t *testing.T) {
4850
ctrl := gomock.NewController(t)
4951
defer ctrl.Finish()
5052

5153
// Arrange
5254
deviceID, metricsToInsert := 52, []*ingestion.DecimalMetricValue(nil)
53-
expectedMessage := "get-message-result"
55+
threshold := alert.Threshold{
56+
Min: 0,
57+
Max: 0,
58+
}
5459

5560
inserter := mocks.NewMockInserter(ctrl)
5661
getter := mocks.NewMockConfigGetter(ctrl)
@@ -65,14 +70,54 @@ func TestAdd_Should_Succeed_And_Return_Get_Message(t *testing.T) {
6570

6671
getter.
6772
EXPECT().
68-
GetMessage().
69-
Return(expectedMessage).
73+
GetThreshold().
74+
Return(threshold).
7075
Times(1)
7176

7277
// Act
7378
res, err := addMetrics.Add(deviceID, metricsToInsert)
7479

7580
// Assert
7681
assert.Nil(t, err)
77-
assert.Equal(t, res, expectedMessage)
82+
assert.Equal(t, res, add_metrics.Ok)
83+
}
84+
85+
86+
func TestAdd_Should_Alert_And_Return_Alert(t *testing.T) {
87+
ctrl := gomock.NewController(t)
88+
defer ctrl.Finish()
89+
90+
// Arrange
91+
deviceID, metricsToInsert := 52, []*ingestion.DecimalMetricValue{{
92+
Value: 5,
93+
Time: ingestion.Time(time.Now()),
94+
}}
95+
threshold := alert.Threshold{
96+
Min: 1,
97+
Max: 10,
98+
}
99+
100+
inserter := mocks.NewMockInserter(ctrl)
101+
getter := mocks.NewMockConfigGetter(ctrl)
102+
103+
addMetrics := add_metrics.NewService(inserter, getter)
104+
105+
inserter.
106+
EXPECT().
107+
Insert(deviceID, metricsToInsert).
108+
Return(nil).
109+
Times(1)
110+
111+
getter.
112+
EXPECT().
113+
GetThreshold().
114+
Return(threshold).
115+
Times(1)
116+
117+
// Act
118+
res, err := addMetrics.Add(deviceID, metricsToInsert)
119+
120+
// Assert
121+
assert.Nil(t, err)
122+
assert.Equal(t, res, add_metrics.Alert)
78123
}

pkg/metrics/alert/alert.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package alert
2+
3+
type Threshold struct {
4+
Min float64
5+
Max float64
6+
}
7+
8+
func (t *Threshold) DoesMatch(value float64) bool {
9+
return value >= t.Min && value <= t.Max
10+
}

pkg/metrics/alert/alert_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package alert
2+
3+
import "testing"
4+
5+
func TestThreshold_DoesMatch(t1 *testing.T) {
6+
type fields struct {
7+
Min float64
8+
Max float64
9+
}
10+
type args struct {
11+
value float64
12+
}
13+
tests := []struct {
14+
name string
15+
fields fields
16+
args args
17+
want bool
18+
}{
19+
{"does match if min", fields{5, 10}, args{5}, true},
20+
{"does match if max", fields{5, 10}, args{10}, true},
21+
{"does match if between", fields{5, 10}, args{7}, true},
22+
{"does not match if lesser than min", fields{5, 10}, args{4}, false},
23+
{"does not match if bigger than max", fields{5, 10}, args{11}, false},
24+
}
25+
for _, tt := range tests {
26+
t1.Run(tt.name, func(t1 *testing.T) {
27+
t := &Threshold{
28+
Min: tt.fields.Min,
29+
Max: tt.fields.Max,
30+
}
31+
if got := t.DoesMatch(tt.args.value); got != tt.want {
32+
t1.Errorf("DoesMatch() = %v, want %v", got, tt.want)
33+
}
34+
})
35+
}
36+
}

resources/config_dynamic.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
test: 'this is dynamic'
1+
threshold:
2+
Min: 74
3+
Max: 100

0 commit comments

Comments
 (0)