1
+ use std:: { borrow:: Cow , collections:: BTreeMap } ;
2
+
1
3
use testcontainers:: {
2
4
core:: { ContainerPort , WaitFor } ,
3
- Image ,
5
+ CopyDataSource , CopyToContainer , Image ,
4
6
} ;
5
7
6
8
const NAME : & str = "valkey/valkey" ;
7
- const TAG : & str = "8.0.1 -alpine" ;
9
+ const TAG : & str = "8.0.2 -alpine" ;
8
10
9
11
/// Default port (6379) on which Valkey is exposed
10
12
pub const VALKEY_PORT : ContainerPort = ContainerPort :: Tcp ( 6379 ) ;
@@ -42,10 +44,83 @@ pub const VALKEY_PORT: ContainerPort = ContainerPort::Tcp(6379);
42
44
/// [`VALKEY_PORT`]: super::VALKEY_PORT
43
45
#[ derive( Debug , Default , Clone ) ]
44
46
pub struct Valkey {
45
- /// (remove if there is another variable)
46
- /// Field is included to prevent this struct to be a unit struct.
47
- /// This allows extending functionality (and thus further variables) without breaking changes
48
- _priv : ( ) ,
47
+ env_vars : BTreeMap < String , String > ,
48
+ tag : Option < String > ,
49
+ copy_to_container : Vec < CopyToContainer > ,
50
+ }
51
+
52
+ impl Valkey {
53
+ /// Create a new Valkey instance with the latest image.
54
+ ///
55
+ /// # Example
56
+ /// ```
57
+ /// use testcontainers_modules::{
58
+ /// testcontainers::runners::SyncRunner,
59
+ /// valkey::{Valkey, VALKEY_PORT},
60
+ /// };
61
+ ///
62
+ /// let valkey_instance = Valkey::latest().start().unwrap();
63
+ /// ```
64
+ pub fn latest ( ) -> Self {
65
+ Self {
66
+ tag : Some ( "latest" . to_string ( ) ) ,
67
+ ..Default :: default ( )
68
+ }
69
+ }
70
+
71
+ /// Add extra flags by passing additional start arguments.
72
+ ///
73
+ /// # Example
74
+ /// ```
75
+ /// use testcontainers_modules::{
76
+ /// testcontainers::runners::SyncRunner,
77
+ /// valkey::{Valkey, VALKEY_PORT},
78
+ /// };
79
+ ///
80
+ /// let valkey_instance = Valkey::default()
81
+ /// .with_valkey_extra_flags("--maxmemory 2mb")
82
+ /// .start()
83
+ /// .unwrap();
84
+ /// ```
85
+ pub fn with_valkey_extra_flags ( self , valkey_extra_flags : & str ) -> Self {
86
+ let mut env_vars = self . env_vars ;
87
+ env_vars. insert (
88
+ "VALKEY_EXTRA_FLAGS" . to_string ( ) ,
89
+ valkey_extra_flags. to_string ( ) ,
90
+ ) ;
91
+ Self {
92
+ env_vars,
93
+ tag : self . tag ,
94
+ copy_to_container : self . copy_to_container ,
95
+ }
96
+ }
97
+
98
+ /// Add custom valkey configuration.
99
+ ///
100
+ /// # Example
101
+ /// ```
102
+ /// use testcontainers_modules::{
103
+ /// testcontainers::runners::SyncRunner,
104
+ /// valkey::{Valkey, VALKEY_PORT},
105
+ /// };
106
+ ///
107
+ /// let valkey_instance = Valkey::default()
108
+ /// .with_valkey_conf("maxmemory 2mb".to_string().into_bytes())
109
+ /// .start()
110
+ /// .unwrap();
111
+ /// ```
112
+ pub fn with_valkey_conf ( self , valky_conf : impl Into < CopyDataSource > ) -> Self {
113
+ let mut copy_to_container = self . copy_to_container ;
114
+ copy_to_container. push ( CopyToContainer :: new (
115
+ valky_conf. into ( ) ,
116
+ "/usr/local/etc/valkey/valkey.conf" ,
117
+ ) ) ;
118
+ Self {
119
+ env_vars : self . env_vars ,
120
+ tag : self . tag ,
121
+ copy_to_container,
122
+ }
123
+ }
49
124
}
50
125
51
126
impl Image for Valkey {
@@ -54,28 +129,81 @@ impl Image for Valkey {
54
129
}
55
130
56
131
fn tag ( & self ) -> & str {
57
- TAG
132
+ self . tag . as_deref ( ) . unwrap_or ( TAG )
58
133
}
59
134
60
135
fn ready_conditions ( & self ) -> Vec < WaitFor > {
61
136
vec ! [ WaitFor :: message_on_stdout( "Ready to accept connections" ) ]
62
137
}
138
+
139
+ fn env_vars (
140
+ & self ,
141
+ ) -> impl IntoIterator < Item = ( impl Into < Cow < ' _ , str > > , impl Into < Cow < ' _ , str > > ) > {
142
+ & self . env_vars
143
+ }
144
+
145
+ fn copy_to_sources ( & self ) -> impl IntoIterator < Item = & CopyToContainer > {
146
+ & self . copy_to_container
147
+ }
148
+
149
+ fn cmd ( & self ) -> impl IntoIterator < Item = impl Into < Cow < ' _ , str > > > {
150
+ if !self . copy_to_container . is_empty ( ) {
151
+ vec ! [ "valkey-server" , "/usr/local/etc/valkey/valkey.conf" ]
152
+ } else {
153
+ Vec :: new ( )
154
+ }
155
+ }
63
156
}
64
157
65
158
#[ cfg( test) ]
66
159
mod tests {
160
+ use std:: collections:: HashMap ;
161
+
67
162
use redis:: Commands ;
163
+ use testcontainers:: Image ;
68
164
69
- use crate :: { testcontainers:: runners:: SyncRunner , valkey:: Valkey } ;
165
+ use crate :: {
166
+ testcontainers:: runners:: SyncRunner ,
167
+ valkey:: { Valkey , TAG , VALKEY_PORT } ,
168
+ } ;
70
169
71
170
#[ test]
72
171
fn valkey_fetch_an_integer ( ) -> Result < ( ) , Box < dyn std:: error:: Error + ' static > > {
73
172
let _ = pretty_env_logger:: try_init ( ) ;
74
173
let node = Valkey :: default ( ) . start ( ) ?;
174
+
175
+ let tag = node. image ( ) . tag . clone ( ) ;
176
+ assert_eq ! ( None , tag) ;
177
+ let tag_from_method = node. image ( ) . tag ( ) ;
178
+ assert_eq ! ( TAG , tag_from_method) ;
179
+ assert_eq ! ( 0 , node. image( ) . copy_to_container. len( ) ) ;
180
+
75
181
let host_ip = node. get_host ( ) ?;
76
- let host_port = node. get_host_port_ipv4 ( 6379 ) ?;
182
+ let host_port = node. get_host_port_ipv4 ( VALKEY_PORT ) ?;
77
183
let url = format ! ( "redis://{host_ip}:{host_port}" ) ;
184
+ let client = redis:: Client :: open ( url. as_ref ( ) ) . unwrap ( ) ;
185
+ let mut con = client. get_connection ( ) . unwrap ( ) ;
78
186
187
+ con. set :: < _ , _ , ( ) > ( "my_key" , 42 ) . unwrap ( ) ;
188
+ let result: i64 = con. get ( "my_key" ) . unwrap ( ) ;
189
+ assert_eq ! ( 42 , result) ;
190
+ Ok ( ( ) )
191
+ }
192
+
193
+ #[ test]
194
+ fn valkey_latest ( ) -> Result < ( ) , Box < dyn std:: error:: Error + ' static > > {
195
+ let _ = pretty_env_logger:: try_init ( ) ;
196
+ let node = Valkey :: latest ( ) . start ( ) ?;
197
+
198
+ let tag = node. image ( ) . tag . clone ( ) ;
199
+ assert_eq ! ( Some ( "latest" . to_string( ) ) , tag) ;
200
+ let tag_from_method = node. image ( ) . tag ( ) ;
201
+ assert_eq ! ( "latest" , tag_from_method) ;
202
+ assert_eq ! ( 0 , node. image( ) . copy_to_container. len( ) ) ;
203
+
204
+ let host_ip = node. get_host ( ) ?;
205
+ let host_port = node. get_host_port_ipv4 ( VALKEY_PORT ) ?;
206
+ let url = format ! ( "redis://{host_ip}:{host_port}" ) ;
79
207
let client = redis:: Client :: open ( url. as_ref ( ) ) . unwrap ( ) ;
80
208
let mut con = client. get_connection ( ) . unwrap ( ) ;
81
209
@@ -84,4 +212,60 @@ mod tests {
84
212
assert_eq ! ( 42 , result) ;
85
213
Ok ( ( ) )
86
214
}
215
+
216
+ #[ test]
217
+ fn valkey_extra_flags ( ) -> Result < ( ) , Box < dyn std:: error:: Error + ' static > > {
218
+ let _ = pretty_env_logger:: try_init ( ) ;
219
+ let node = Valkey :: default ( )
220
+ . with_valkey_extra_flags ( "--maxmemory 2mb" )
221
+ . start ( ) ?;
222
+ let tag = node. image ( ) . tag . clone ( ) ;
223
+ assert_eq ! ( None , tag) ;
224
+ let tag_from_method = node. image ( ) . tag ( ) ;
225
+ assert_eq ! ( TAG , tag_from_method) ;
226
+ assert_eq ! ( 0 , node. image( ) . copy_to_container. len( ) ) ;
227
+
228
+ let host_ip = node. get_host ( ) ?;
229
+ let host_port = node. get_host_port_ipv4 ( VALKEY_PORT ) ?;
230
+ let url = format ! ( "redis://{host_ip}:{host_port}" ) ;
231
+
232
+ let client = redis:: Client :: open ( url. as_ref ( ) ) . unwrap ( ) ;
233
+ let mut con = client. get_connection ( ) . unwrap ( ) ;
234
+ let max_memory: HashMap < String , isize > = redis:: cmd ( "CONFIG" )
235
+ . arg ( "GET" )
236
+ . arg ( "maxmemory" )
237
+ . query ( & mut con)
238
+ . unwrap ( ) ;
239
+ let max = * max_memory. get ( "maxmemory" ) . unwrap ( ) ;
240
+ assert_eq ! ( 2097152 , max) ;
241
+ Ok ( ( ) )
242
+ }
243
+
244
+ #[ test]
245
+ fn valkey_conf ( ) -> Result < ( ) , Box < dyn std:: error:: Error + ' static > > {
246
+ let _ = pretty_env_logger:: try_init ( ) ;
247
+ let node = Valkey :: default ( )
248
+ . with_valkey_conf ( "maxmemory 2mb" . to_string ( ) . into_bytes ( ) )
249
+ . start ( ) ?;
250
+ let tag = node. image ( ) . tag . clone ( ) ;
251
+ assert_eq ! ( None , tag) ;
252
+ let tag_from_method = node. image ( ) . tag ( ) ;
253
+ assert_eq ! ( TAG , tag_from_method) ;
254
+ assert_eq ! ( 1 , node. image( ) . copy_to_container. len( ) ) ;
255
+
256
+ let host_ip = node. get_host ( ) ?;
257
+ let host_port = node. get_host_port_ipv4 ( VALKEY_PORT ) ?;
258
+ let url = format ! ( "redis://{host_ip}:{host_port}" ) ;
259
+
260
+ let client = redis:: Client :: open ( url. as_ref ( ) ) . unwrap ( ) ;
261
+ let mut con = client. get_connection ( ) . unwrap ( ) ;
262
+ let max_memory: HashMap < String , isize > = redis:: cmd ( "CONFIG" )
263
+ . arg ( "GET" )
264
+ . arg ( "maxmemory" )
265
+ . query ( & mut con)
266
+ . unwrap ( ) ;
267
+ let max = * max_memory. get ( "maxmemory" ) . unwrap ( ) ;
268
+ assert_eq ! ( 2097152 , max) ;
269
+ Ok ( ( ) )
270
+ }
87
271
}
0 commit comments