This repository has been archived by the owner on Feb 16, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
flap_guard_test.go
171 lines (137 loc) · 4.52 KB
/
flap_guard_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//+build test
package kafkalock
import (
"os"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/jonboulle/clockwork"
"github.com/spf13/afero"
"github.com/stretchr/testify/require"
"github.com/grongor/go-kafka-lock/kafkalock/mocks"
)
func TestFileFlapsStorage(t *testing.T) {
tests := []struct {
name string
times []time.Time
}{
{
"single time",
[]time.Time{time.Now().Truncate(-1)},
},
{
"multiple times",
[]time.Time{
time.Now().Add(time.Hour * -4).Truncate(-1),
time.Now().Truncate(-1),
time.Now().Add(time.Hour * 5).Truncate(-1),
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
fs := afero.NewMemMapFs()
file, _ := fs.OpenFile("some-file", os.O_RDWR|os.O_CREATE, 0600)
storage := NewFileFlapsStorage(file)
times, err := storage.Read()
require.NoError(t, err)
require.Empty(t, times)
err = storage.Store(test.times)
require.NoError(t, err)
stat, _ := file.Stat()
size := stat.Size()
require.NotEmpty(t, size)
storage.Close()
file, err = fs.OpenFile("some-file", os.O_RDWR|os.O_EXCL, 0600)
require.NoError(t, err)
storage = NewFileFlapsStorage(file)
times, err = storage.Read()
require.NoError(t, err)
require.Equal(t, test.times, times)
stat, _ = file.Stat()
require.Equal(t, size, stat.Size())
})
}
}
func TestFlapGuardError(t *testing.T) {
fakeClock := clockwork.NewFakeClock()
clock = fakeClock
delay := time.Second
ctrl := gomock.NewController(t)
storage := mocks.NewMockFlapsStorage(ctrl)
guard, err := NewFlapGuard(NewNopLogger(), storage, 2, false)
require.NoError(t, err)
time1 := clock.Now()
// first run, no flaps
storage.EXPECT().Read().Times(1).Return(make([]time.Time, 0), nil)
storage.EXPECT().Store([]time.Time{time1}).Times(1)
err = guard.Check(delay)
require.NoError(t, err)
// second run, single flap
storage.EXPECT().Store([]time.Time{time1, time1}).Times(1)
err = guard.Check(delay)
require.NoError(t, err)
fakeClock.Advance(time.Second * 2)
time2 := clock.Now()
// third run, single flap (this run is +2 seconds, so it's not considered as a flap)
storage.EXPECT().Store([]time.Time{time1, time1, time2}).Times(1)
err = guard.Check(delay)
require.NoError(t, err)
// forth run, two flaps (we tolerate two, so no error)
storage.EXPECT().Store([]time.Time{time1, time1, time2, time2}).Times(1)
err = guard.Check(delay)
require.NoError(t, err)
// fifth run, two flaps (first is gone, last just appeared - same situation as forth run)
storage.EXPECT().Store([]time.Time{time1, time2, time2, time2}).Times(1)
err = guard.Check(delay)
require.NoError(t, err)
// sixth run, three flaps: error is emitted as this run just exceeded our defined threshold
storage.EXPECT().Store([]time.Time{time2, time2, time2, time2}).Times(1)
err = guard.Check(delay)
require.EqualError(t, err, ErrLockIsFlapping.Error())
fakeClock.Advance(time.Second * 2)
time3 := clock.Now()
// seventh run, two flaps again (this run is +2 seconds, so not considered as a flap)
storage.EXPECT().Store([]time.Time{time2, time2, time2, time3}).Times(1)
err = guard.Check(delay)
require.NoError(t, err)
// eight run, two flaps (first is gone, last just appeared - same situation as seventh run)
storage.EXPECT().Store([]time.Time{time2, time2, time3, time3}).Times(1)
err = guard.Check(delay)
require.NoError(t, err)
storage.EXPECT().Close().Times(1)
err = guard.Close()
require.NoError(t, err)
}
func TestFlapGuardWaiting(t *testing.T) {
fakeClock := clockwork.NewFakeClock()
clock = fakeClock
delay := time.Second
ctrl := gomock.NewController(t)
storage := mocks.NewMockFlapsStorage(ctrl)
guard, err := NewFlapGuard(NewNopLogger(), storage, 0, true)
require.NoError(t, err)
time1 := clock.Now()
// first run, no flaps
storage.EXPECT().Read().Times(1).Return(make([]time.Time, 0), nil)
storage.EXPECT().Store([]time.Time{time1}).Times(1)
err = guard.Check(delay)
require.NoError(t, err)
// second run, single flap
storage.EXPECT().Store([]time.Time{time1, time1}).Times(1)
var checkFinishedAt time.Time
ch := async(func() {
err = guard.Check(delay)
checkFinishedAt = clock.Now()
})
fakeClock.BlockUntil(1)
fakeClock.Advance(time.Second * 10)
require.True(t, <-ch, "expected Check() to finish by now")
require.NotEmpty(t, checkFinishedAt)
require.True(t, checkFinishedAt.After(time1.Add(time.Second*2)))
require.NoError(t, err)
// third run, no flaps (first is gone)
storage.EXPECT().Store([]time.Time{time1, clock.Now()}).Times(1)
err = guard.Check(delay)
require.NoError(t, err)
}