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