Skip to content

Commit f70c42c

Browse files
authored
Merge pull request #68 from dwelch0/metric-proxy-rw-lock
utilize rwlock to address race condition - add tests
2 parents ae92c78 + 320f9ce commit f70c42c

File tree

2 files changed

+107
-1
lines changed

2 files changed

+107
-1
lines changed

pkg/proxy.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type MetricProxyItem struct {
1414

1515
type MetricProxy struct {
1616
metrics map[string]*MetricProxyItem
17-
mutex sync.Mutex
17+
mutex sync.RWMutex
1818
}
1919

2020
func NewMetricProxy() *MetricProxy {
@@ -24,6 +24,8 @@ func NewMetricProxy() *MetricProxy {
2424
}
2525

2626
func (mp *MetricProxy) GetMetricById(id string) (*MetricProxyItem, error) {
27+
mp.mutex.RLock()
28+
defer mp.mutex.RUnlock()
2729
if m, ok := mp.metrics[id]; ok {
2830
if time.Since(m.creationTime).Seconds() > float64(m.ttl) {
2931
return nil, errors.New("metric ttl has expired")

pkg/proxy_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package pkg
2+
3+
import (
4+
"math"
5+
"reflect"
6+
"testing"
7+
"time"
8+
)
9+
10+
func TestGetMetricById(t *testing.T) {
11+
type args struct {
12+
mp *MetricProxy
13+
key string
14+
}
15+
now := time.Now()
16+
tests := []struct {
17+
name string
18+
args args
19+
want *MetricProxyItem
20+
}{
21+
{
22+
name: "Attempt retrieving value by providing valid id (key exists)",
23+
args: args{
24+
mp: &MetricProxy{
25+
metrics: map[string]*MetricProxyItem{
26+
"valid": &MetricProxyItem{
27+
value: "value",
28+
ttl: math.MaxInt32,
29+
creationTime: now,
30+
},
31+
},
32+
},
33+
key: "valid",
34+
},
35+
want: &MetricProxyItem{
36+
value: "value",
37+
ttl: math.MaxInt32,
38+
creationTime: now,
39+
},
40+
},
41+
{
42+
name: "Attempt retrieving value by providing valid id but ttl expired",
43+
args: args{
44+
mp: &MetricProxy{
45+
metrics: map[string]*MetricProxyItem{
46+
"expired": &MetricProxyItem{
47+
value: 100,
48+
ttl: 1,
49+
creationTime: now,
50+
},
51+
},
52+
},
53+
key: "expired",
54+
},
55+
want: nil,
56+
},
57+
}
58+
59+
time.Sleep(2 * time.Second) //ensure ttl for second test expires
60+
61+
for _, tt := range tests {
62+
t.Run(tt.name, func(t *testing.T) {
63+
if got, _ := tt.args.mp.GetMetricById(tt.args.key); !reflect.DeepEqual(got, tt.want) {
64+
t.Errorf("GetMetricById() = %v, want %v", got, tt.want)
65+
}
66+
})
67+
}
68+
}
69+
70+
func TestStoreMetricById(t *testing.T) {
71+
type args struct {
72+
mp *MetricProxy
73+
key string
74+
value interface{}
75+
ttl int
76+
}
77+
tests := []struct {
78+
name string
79+
args args
80+
want *MetricProxyItem
81+
}{
82+
{
83+
name: "Attempt storing new metric by id",
84+
args: args{
85+
mp: NewMetricProxy(),
86+
key: "new",
87+
value: 1,
88+
ttl: math.MaxInt32,
89+
},
90+
want: &MetricProxyItem{
91+
value: 1,
92+
},
93+
},
94+
}
95+
96+
for _, tt := range tests {
97+
t.Run(tt.name, func(t *testing.T) {
98+
tt.args.mp.StoreMetricById(tt.args.key, tt.args.value, tt.args.ttl)
99+
if got, err := tt.args.mp.GetMetricById(tt.args.key); got.value != tt.want.value || err != nil {
100+
t.Errorf("StoreMetricById() = %v, want %v", got.value, tt.want.value)
101+
}
102+
})
103+
}
104+
}

0 commit comments

Comments
 (0)