@@ -2,7 +2,12 @@ use scylla_proxy::{
2
2
Condition , Node , Proxy , Reaction as _, RequestFrame , RequestOpcode , RequestReaction ,
3
3
RequestRule , ResponseFrame , RunningProxy ,
4
4
} ;
5
- use std:: { collections:: HashMap , ffi:: c_char, net:: SocketAddr , sync:: Arc } ;
5
+ use std:: {
6
+ collections:: HashMap ,
7
+ ffi:: c_char,
8
+ net:: { IpAddr , SocketAddr } ,
9
+ sync:: Arc ,
10
+ } ;
6
11
7
12
use crate :: {
8
13
argconv:: { CMut , CassOwnedSharedPtr , ptr_to_cstr_n} ,
@@ -111,11 +116,12 @@ pub(crate) fn mock_init_rules() -> impl IntoIterator<Item = RequestRule> {
111
116
) ) )
112
117
}
113
118
114
- pub ( crate ) async fn test_with_one_proxy (
119
+ pub ( crate ) async fn test_with_one_proxy_at_ip (
115
120
test : impl FnOnce ( SocketAddr , RunningProxy ) -> RunningProxy + Send + ' static ,
116
121
rules : impl IntoIterator < Item = RequestRule > ,
122
+ ip : IpAddr ,
117
123
) {
118
- let proxy_addr = SocketAddr :: new ( scylla_proxy :: get_exclusive_local_address ( ) , 9042 ) ;
124
+ let proxy_addr = SocketAddr :: new ( ip , 9042 ) ;
119
125
120
126
let proxy = Proxy :: builder ( )
121
127
. with_node (
@@ -137,3 +143,107 @@ pub(crate) async fn test_with_one_proxy(
137
143
138
144
let _ = proxy. finish ( ) . await ;
139
145
}
146
+
147
+ pub ( crate ) async fn test_with_one_proxy (
148
+ test : impl FnOnce ( SocketAddr , RunningProxy ) -> RunningProxy + Send + ' static ,
149
+ rules : impl IntoIterator < Item = RequestRule > ,
150
+ ) {
151
+ test_with_one_proxy_at_ip ( test, rules, scylla_proxy:: get_exclusive_local_address ( ) ) . await
152
+ }
153
+
154
+ /// Run a Rust test in a subprocess, setting up the proxy
155
+ /// with a correct unique address.
156
+ ///
157
+ /// This is intended to coordinate in address allocation between
158
+ /// the parent process and the subprocesses, so that no address
159
+ /// collisions occur when tests are run in multiple processes.
160
+ ///
161
+ /// The basic usage is to simply put this macro around your `#[test]`
162
+ /// function and add one argument of type `IpAddr` to it, like so:
163
+ ///
164
+ /// ```rust,nocompile
165
+ /// use crate::testing::rusty_fork_test_with_proxy;
166
+ ///
167
+ /// rusty_fork_test_with_proxy! {
168
+ /// #[test]
169
+ /// fn my_test(ip: IpAddr) {
170
+ /// // Use the `ip` variable to set up the proxy.
171
+ /// let fut = test_with_one_proxy_at_ip(
172
+ /// test_body,
173
+ /// proxy_rules,
174
+ /// ip,
175
+ /// );
176
+ ///
177
+ /// // Run the future to completion.
178
+ /// }
179
+ /// }
180
+ /// ```
181
+ ///
182
+ /// The test will be run in its own process. If the subprocess exits
183
+ /// unsuccessfully for any reason, including due to signals, the test fails.
184
+ ///
185
+ /// It is also possible to specify a timeout which is applied to the test in
186
+ /// the block, by adding the following line straight before the test:
187
+ ///
188
+ /// ```rust,no_compile
189
+ /// #![rusty_fork(timeout_ms = 1000)]
190
+ /// ```
191
+ ///
192
+ /// For more details, see the documentation of the `rusty_fork_test` macro
193
+ /// in the [rusty_fork] crate.
194
+ /// ```
195
+ macro_rules! rusty_fork_test_with_proxy {
196
+ ( #![ rusty_fork( timeout_ms = $timeout: expr) ]
197
+ $( #[ $meta: meta] ) *
198
+ fn $test_name: ident( $ip: ident: IpAddr ) $body: block
199
+ ) => {
200
+ $( #[ $meta] ) *
201
+ fn $test_name( ) {
202
+ // Eagerly convert everything to function pointers so that all
203
+ // tests use the same instantiation of `fork`.
204
+ let supervise_fn = |child: & mut rusty_fork:: ChildWrapper , _file: & mut std:: fs:: File | {
205
+ rusty_fork:: fork_test:: supervise_child( child, $timeout) ;
206
+ } ;
207
+
208
+ const ENV_KEY : & str = "PROXY_RUSTY_FORK_IP" ;
209
+
210
+ let process_modifier = |child: & mut Command | {
211
+ child. env(
212
+ ENV_KEY ,
213
+ scylla_proxy:: get_exclusive_local_address( ) . to_string( ) ,
214
+ ) ;
215
+ } ;
216
+
217
+ let test = || {
218
+ // Body expects the ip variable in scope.
219
+ let $ip: :: std:: net:: IpAddr = std:: env:: var( ENV_KEY )
220
+ . expect( "Parent should have set the proxy address as an env variable." )
221
+ . parse( )
222
+ . expect( "Error parsing the proxy address from env variable." ) ;
223
+
224
+ $body
225
+ } ;
226
+
227
+ rusty_fork:: fork(
228
+ rusty_fork:: rusty_fork_test_name!( $test_name) ,
229
+ rusty_fork:: rusty_fork_id!( ) ,
230
+ process_modifier,
231
+ supervise_fn,
232
+ test,
233
+ )
234
+ . expect( "forking test failed" )
235
+ }
236
+ } ;
237
+
238
+ (
239
+ $( #[ $meta: meta] ) *
240
+ fn $test_name: ident( ) $body: block
241
+ ) => {
242
+ rusty_fork_test! {
243
+ #![ rusty_fork( timeout_ms = 0 ) ]
244
+
245
+ $( #[ $meta] ) * fn $test_name( ) $body
246
+ }
247
+ } ;
248
+ }
249
+ pub ( crate ) use rusty_fork_test_with_proxy;
0 commit comments