1
1
package toxiproxy_test
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
6
+ _ "embed"
7
+ "fmt"
5
8
"testing"
9
+ "time"
6
10
11
+ toxiproxy "github.com/Shopify/toxiproxy/v2/client"
12
+ "github.com/go-redis/redis/v8"
13
+ "github.com/google/uuid"
7
14
"github.com/stretchr/testify/require"
8
15
9
16
"github.com/testcontainers/testcontainers-go"
10
- "github.com/testcontainers/testcontainers-go/modules/toxiproxy"
17
+ tcredis "github.com/testcontainers/testcontainers-go/modules/redis"
18
+ tctoxiproxy "github.com/testcontainers/testcontainers-go/modules/toxiproxy"
19
+ "github.com/testcontainers/testcontainers-go/network"
11
20
)
12
21
13
22
func TestRun (t * testing.T ) {
14
23
ctx := context .Background ()
15
24
16
- ctr , err := toxiproxy .Run (ctx , "ghcr.io/shopify/toxiproxy:2.12.0" )
25
+ ctr , err := tctoxiproxy .Run (ctx , "ghcr.io/shopify/toxiproxy:2.12.0" )
17
26
testcontainers .CleanupContainer (t , ctr )
18
27
require .NoError (t , err )
19
28
@@ -26,7 +35,7 @@ func TestRun_withPortRange(t *testing.T) {
26
35
t .Run ("no-port-range" , func (t * testing.T ) {
27
36
portsCount := 31 // default port range is 31 (not exposed)
28
37
29
- ctr , err := toxiproxy .Run (ctx , "ghcr.io/shopify/toxiproxy:2.12.0" )
38
+ ctr , err := tctoxiproxy .Run (ctx , "ghcr.io/shopify/toxiproxy:2.12.0" )
30
39
testcontainers .CleanupContainer (t , ctr )
31
40
require .NoError (t , err )
32
41
jsonInspect , err := ctr .Inspect (ctx )
@@ -37,7 +46,7 @@ func TestRun_withPortRange(t *testing.T) {
37
46
t .Run ("negative-port" , func (t * testing.T ) {
38
47
portsCount := - 1
39
48
40
- ctr , err := toxiproxy .Run (ctx , "ghcr.io/shopify/toxiproxy:2.12.0" , toxiproxy .WithPortRange (portsCount ))
49
+ ctr , err := tctoxiproxy .Run (ctx , "ghcr.io/shopify/toxiproxy:2.12.0" , tctoxiproxy .WithPortRange (portsCount ))
41
50
testcontainers .CleanupContainer (t , ctr )
42
51
require .Error (t , err )
43
52
require .Nil (t , ctr )
@@ -46,7 +55,7 @@ func TestRun_withPortRange(t *testing.T) {
46
55
t .Run ("zero-port" , func (t * testing.T ) {
47
56
portsCount := 0
48
57
49
- ctr , err := toxiproxy .Run (ctx , "ghcr.io/shopify/toxiproxy:2.12.0" , toxiproxy .WithPortRange (portsCount ))
58
+ ctr , err := tctoxiproxy .Run (ctx , "ghcr.io/shopify/toxiproxy:2.12.0" , tctoxiproxy .WithPortRange (portsCount ))
50
59
testcontainers .CleanupContainer (t , ctr )
51
60
require .Error (t , err )
52
61
require .Nil (t , ctr )
@@ -55,7 +64,7 @@ func TestRun_withPortRange(t *testing.T) {
55
64
t .Run ("one-port" , func (t * testing.T ) {
56
65
portsCount := 1
57
66
58
- ctr , err := toxiproxy .Run (ctx , "ghcr.io/shopify/toxiproxy:2.12.0" , toxiproxy .WithPortRange (portsCount ))
67
+ ctr , err := tctoxiproxy .Run (ctx , "ghcr.io/shopify/toxiproxy:2.12.0" , tctoxiproxy .WithPortRange (portsCount ))
59
68
testcontainers .CleanupContainer (t , ctr )
60
69
require .NoError (t , err )
61
70
@@ -67,7 +76,7 @@ func TestRun_withPortRange(t *testing.T) {
67
76
t .Run ("more-than-default-port" , func (t * testing.T ) {
68
77
portsCount := 75
69
78
70
- ctr , err := toxiproxy .Run (ctx , "ghcr.io/shopify/toxiproxy:2.12.0" , toxiproxy .WithPortRange (portsCount ))
79
+ ctr , err := tctoxiproxy .Run (ctx , "ghcr.io/shopify/toxiproxy:2.12.0" , tctoxiproxy .WithPortRange (portsCount ))
71
80
testcontainers .CleanupContainer (t , ctr )
72
81
require .NoError (t , err )
73
82
@@ -76,3 +85,99 @@ func TestRun_withPortRange(t *testing.T) {
76
85
require .Len (t , jsonInspect .HostConfig .PortBindings , portsCount + 1 )
77
86
})
78
87
}
88
+
89
+ //go:embed testdata/toxiproxy.json
90
+ var configFile []byte
91
+
92
+ func TestRun_withConfigFile (t * testing.T ) {
93
+ ctx := context .Background ()
94
+
95
+ nw , err := network .New (ctx )
96
+ require .NoError (t , err )
97
+ t .Cleanup (func () {
98
+ require .NoError (t , nw .Remove (ctx ))
99
+ })
100
+
101
+ redisContainer , err := tcredis .Run (
102
+ ctx ,
103
+ "redis:6-alpine" ,
104
+ network .WithNetwork ([]string {"redis" }, nw ),
105
+ )
106
+ testcontainers .CleanupContainer (t , redisContainer )
107
+ require .NoError (t , err )
108
+
109
+ toxiproxyContainer , err := tctoxiproxy .Run (
110
+ ctx ,
111
+ "ghcr.io/shopify/toxiproxy:2.12.0" ,
112
+ tctoxiproxy .WithPortRange (31 ),
113
+ tctoxiproxy .WithConfigFile (bytes .NewReader (configFile )),
114
+ network .WithNetwork ([]string {"toxiproxy" }, nw ),
115
+ )
116
+ testcontainers .CleanupContainer (t , toxiproxyContainer )
117
+ require .NoError (t , err )
118
+
119
+ toxiURI , err := toxiproxyContainer .URI (ctx )
120
+ require .NoError (t , err )
121
+
122
+ toxiproxyClient := toxiproxy .NewClient (toxiURI )
123
+
124
+ toxiproxyProxyPort , err := toxiproxyContainer .MappedPort (ctx , "8666/tcp" )
125
+ require .NoError (t , err )
126
+
127
+ toxiproxyProxyHostIP , err := toxiproxyContainer .Host (ctx )
128
+ require .NoError (t , err )
129
+
130
+ // Create a redis client that connects to the toxiproxy container.
131
+ // We are defining a read timeout of 2 seconds, because we are adding
132
+ // a latency toxic of 1 second to the request, +/- 100ms jitter.
133
+ redisURI := fmt .Sprintf ("redis://%s:%s?read_timeout=2s" , toxiproxyProxyHostIP , toxiproxyProxyPort .Port ())
134
+
135
+ options , err := redis .ParseURL (redisURI )
136
+ require .NoError (t , err )
137
+
138
+ redisCli := redis .NewClient (options )
139
+ t .Cleanup (func () {
140
+ require .NoError (t , redisCli .FlushAll (ctx ).Err ())
141
+ })
142
+
143
+ key := fmt .Sprintf ("{user.%s}.favoritefood" , uuid .NewString ())
144
+ value := "Cabbage Biscuits"
145
+ ttl , err := time .ParseDuration ("2h" )
146
+ require .NoError (t , err )
147
+
148
+ err = redisCli .Set (ctx , key , value , ttl ).Err ()
149
+ require .NoError (t , err )
150
+
151
+ // Add a latency toxic to the proxy
152
+ toxicOptions := & toxiproxy.ToxicOptions {
153
+ ProxyName : "redis" , // name of the proxy in the config file
154
+ ToxicName : "latency_down" ,
155
+ ToxicType : "latency" ,
156
+ Toxicity : 1.0 ,
157
+ Stream : "downstream" ,
158
+ Attributes : map [string ]interface {}{
159
+ "latency" : 1_000 ,
160
+ "jitter" : 100 ,
161
+ },
162
+ }
163
+ _ , err = toxiproxyClient .AddToxic (toxicOptions )
164
+ require .NoError (t , err )
165
+
166
+ start := time .Now ()
167
+ // Get data
168
+ savedValue , err := redisCli .Get (ctx , key ).Result ()
169
+ require .NoError (t , err )
170
+
171
+ duration := time .Since (start )
172
+
173
+ t .Logf ("Duration: %s\n " , duration )
174
+
175
+ // The value is retrieved successfully
176
+ require .Equal (t , value , savedValue )
177
+
178
+ // Check that latency is within expected range (900ms-1100ms)
179
+ // The latency toxic adds 1000ms (1000ms +/- 100ms jitter)
180
+ minDuration := 900 * time .Millisecond
181
+ maxDuration := 1100 * time .Millisecond
182
+ require .True (t , duration >= minDuration && duration <= maxDuration )
183
+ }
0 commit comments