@@ -3,24 +3,51 @@ package etcd
33import (
44 "context"
55 "os"
6+ "sync"
67 "testing"
78 "time"
89
910 "github.com/stretchr/testify/require"
11+
12+ "github.com/testcontainers/testcontainers-go"
13+ "github.com/testcontainers/testcontainers-go/modules/etcd"
1014)
1115
12- var testStore * Storage
16+ const (
17+ // etcdImage is the default image used for running etcd in tests.
18+ etcdImage = "gcr.io/etcd-development/etcd:v3.6.6"
19+ etcdImageEnvVar string = "TEST_ETCD_IMAGE"
20+ )
1321
14- func TestMain (m * testing.M ) {
15- testStore = New (Config {
16- Endpoints : []string {"localhost:2379" },
17- })
22+ func newTestStore (t testing.TB ) * Storage {
23+ t .Helper ()
24+
25+ img := etcdImage
26+ if imgFromEnv := os .Getenv (etcdImageEnvVar ); imgFromEnv != "" {
27+ img = imgFromEnv
28+ }
29+
30+ ctx := context .Background ()
31+
32+ // create a 1-node cluster
33+ c , err := etcd .Run (ctx , img )
34+
35+ // for benchmarks, we do not want to cleanup the container
36+ switch t .(type ) {
37+ case * testing.B :
38+ // do not cleanup the container for benchmarks
39+ default :
40+ testcontainers .CleanupContainer (t , c )
41+ }
1842
19- code := m .Run ()
43+ require .NoError (t , err )
44+
45+ hostPort , err := c .ClientEndpoint (ctx )
46+ require .NoError (t , err )
2047
21- _ = testStore . Reset ()
22- _ = testStore . Close ()
23- os . Exit ( code )
48+ return New ( Config {
49+ Endpoints : [] string { hostPort },
50+ } )
2451}
2552
2653func TestSetEtcd_ShouldReturnNoError (t * testing.T ) {
@@ -29,18 +56,27 @@ func TestSetEtcd_ShouldReturnNoError(t *testing.T) {
2956 val = []byte ("doe" )
3057 )
3158
59+ testStore := newTestStore (t )
60+ defer testStore .Close ()
61+
3262 err := testStore .Set (key , val , 0 )
3363 require .NoError (t , err )
3464}
3565
3666func TestGetEtcd_ShouldReturnNil_WhenDocumentNotFound (t * testing.T ) {
67+ testStore := newTestStore (t )
68+ defer testStore .Close ()
69+
3770 val , err := testStore .Get ("not_found_key" )
3871
3972 require .NoError (t , err )
4073 require .Zero (t , len (val ))
4174}
4275
4376func TestSetAndGet_GetShouldReturn_SettedValueWithoutError (t * testing.T ) {
77+ testStore := newTestStore (t )
78+ defer testStore .Close ()
79+
4480 err := testStore .Set ("test" , []byte ("fiber_test_value" ), 0 )
4581 require .NoError (t , err )
4682
@@ -56,6 +92,9 @@ func TestSetWithContext(t *testing.T) {
5692 val = []byte ("doe" )
5793 )
5894
95+ testStore := newTestStore (t )
96+ defer testStore .Close ()
97+
5998 ctx , cancel := context .WithCancel (context .Background ())
6099 cancel ()
61100
@@ -69,6 +108,9 @@ func TestSetAndGetWithContext(t *testing.T) {
69108 val = []byte ("doe" )
70109 )
71110
111+ testStore := newTestStore (t )
112+ defer testStore .Close ()
113+
72114 ctx , cancel := context .WithCancel (context .Background ())
73115 cancel ()
74116
@@ -81,6 +123,9 @@ func TestSetAndGetWithContext(t *testing.T) {
81123}
82124
83125func TestSetAndGet_GetShouldReturnNil_WhenTTLExpired (t * testing.T ) {
126+ testStore := newTestStore (t )
127+ defer testStore .Close ()
128+
84129 err := testStore .Set ("test" , []byte ("fiber_test_value" ), 3 * time .Second )
85130 require .NoError (t , err )
86131
@@ -93,6 +138,9 @@ func TestSetAndGet_GetShouldReturnNil_WhenTTLExpired(t *testing.T) {
93138}
94139
95140func TestSetAndDelete_DeleteShouldReturn_NoError (t * testing.T ) {
141+ testStore := newTestStore (t )
142+ defer testStore .Close ()
143+
96144 err := testStore .Set ("test" , []byte ("fiber_test_value" ), 0 )
97145 require .NoError (t , err )
98146
@@ -104,6 +152,9 @@ func TestSetAndDelete_DeleteShouldReturn_NoError(t *testing.T) {
104152}
105153
106154func TestDeleteWithContext (t * testing.T ) {
155+ testStore := newTestStore (t )
156+ defer testStore .Close ()
157+
107158 err := testStore .Set ("test" , []byte ("fiber_test_value" ), 0 )
108159 require .NoError (t , err )
109160
@@ -119,6 +170,9 @@ func TestDeleteWithContext(t *testing.T) {
119170}
120171
121172func TestSetAndReset_ResetShouldReturn_NoError (t * testing.T ) {
173+ testStore := newTestStore (t )
174+ defer testStore .Close ()
175+
122176 err := testStore .Set ("test" , []byte ("fiber_test_value" ), 0 )
123177 require .NoError (t , err )
124178
@@ -130,6 +184,9 @@ func TestSetAndReset_ResetShouldReturn_NoError(t *testing.T) {
130184}
131185
132186func TestResetWithContext (t * testing.T ) {
187+ testStore := newTestStore (t )
188+ defer testStore .Close ()
189+
133190 err := testStore .Set ("test" , []byte ("fiber_test_value" ), 0 )
134191 require .NoError (t , err )
135192
@@ -145,49 +202,94 @@ func TestResetWithContext(t *testing.T) {
145202}
146203
147204func TestClose_CloseShouldReturn_NoError (t * testing.T ) {
205+ testStore := newTestStore (t )
148206 err := testStore .Close ()
149207 require .NoError (t , err )
150208}
151209
152210func TestGetConn_ReturnsNotNill (t * testing.T ) {
211+ testStore := newTestStore (t )
212+ defer testStore .Close ()
213+
153214 require .True (t , testStore .Conn () != nil )
154215}
155216
217+ //
218+ // Benchmarking
219+ //
220+ // Please note that this is not thread-safe:
221+ // Each benchmark reuses the same etcd store instance,
222+ // setting and deleting keys between benchmarks.
223+ // If you add more benchmarks, make sure to delete the key after the benchmark.
224+
225+ var (
226+ benchmarkStore * Storage
227+ benchmarkOnce sync.Once
228+ )
229+
230+ func getBenchmarkStore (b * testing.B ) * Storage {
231+ benchmarkOnce .Do (func () {
232+ benchmarkStore = newTestStore (b )
233+ })
234+
235+ return benchmarkStore
236+ }
237+
156238func Benchmark_Etcd_Set (b * testing.B ) {
239+ key := "john1"
240+ testStore := getBenchmarkStore (b )
241+
157242 b .ReportAllocs ()
158243 b .ResetTimer ()
159244
160245 var err error
161246 for i := 0 ; i < b .N ; i ++ {
162- err = testStore .Set ("john" , []byte ("doe" ), 0 )
247+ err = testStore .Set (key , []byte ("doe" ), 0 )
163248 }
164249
165250 require .NoError (b , err )
251+
252+ // Clean up the key after benchmark
253+ require .NoError (b , testStore .Delete (key ))
166254}
167255
168256func Benchmark_Etcd_Get (b * testing.B ) {
169- err := testStore .Set ("john" , []byte ("doe" ), 0 )
257+ key := "john2"
258+ testStore := getBenchmarkStore (b )
259+
260+ err := testStore .Set (key , []byte ("doe" ), 0 )
170261 require .NoError (b , err )
171262
172263 b .ReportAllocs ()
173264 b .ResetTimer ()
174265
175266 for i := 0 ; i < b .N ; i ++ {
176- _ , err = testStore .Get ("john" )
267+ _ , err = testStore .Get (key )
177268 }
178269
179270 require .NoError (b , err )
271+
272+ // Clean up after benchmark
273+ require .NoError (b , testStore .Delete (key ))
180274}
181275
182276func Benchmark_Etcd_SetAndDelete (b * testing.B ) {
277+ key := "john3"
278+ testStore := getBenchmarkStore (b )
279+
183280 b .ReportAllocs ()
184281 b .ResetTimer ()
185282
186283 var err error
187284 for i := 0 ; i < b .N ; i ++ {
188- _ = testStore .Set ("john" , []byte ("doe" ), 0 )
189- err = testStore .Delete ("john" )
285+ _ = testStore .Set (key , []byte ("doe" ), 0 )
286+ err = testStore .Delete (key )
190287 }
191288
192289 require .NoError (b , err )
290+
291+ // Clean up after benchmark
292+ b .StopTimer ()
293+ _ = testStore .Delete (key )
294+ b .StartTimer ()
193295}
0 commit comments