@@ -184,38 +184,81 @@ mod integration {
184
184
use reqwest:: { Client , ClientBuilder , Error , Response } ;
185
185
use testcontainers_modules:: redis:: Redis ;
186
186
use testcontainers_modules:: testcontainers:: clients:: Cli ;
187
+ use tokio:: sync:: OnceCell as AsyncOnceCell ;
187
188
188
189
use super :: * ;
189
190
190
191
static TESTS_TIMEOUT : Lazy < Duration > = Lazy :: new ( || Duration :: from_secs ( 20 ) ) ;
191
192
static WAIT_SERVICE_INTERVAL : Lazy < Duration > = Lazy :: new ( || Duration :: from_secs ( 3 ) ) ;
193
+ static DIRECTORY_PORT : Lazy < u16 > = Lazy :: new ( find_free_port) ;
194
+ static OHTTP_RELAY_PORT : Lazy < u16 > = Lazy :: new ( find_free_port) ;
195
+ // Shared test infrastructure
196
+ static TEST_INFRASTRUCTURE : AsyncOnceCell < TestInfrastructure > = AsyncOnceCell :: const_new ( ) ;
197
+
198
+ struct TestInfrastructure {
199
+ directory : Url ,
200
+ ohttp_relay : Url ,
201
+ agent : Arc < Client > ,
202
+ cert : Vec < u8 > ,
203
+ }
204
+
205
+ impl TestInfrastructure {
206
+ async fn new ( ) -> Result < Self , BoxError > {
207
+ let ( cert, key) = local_cert_key ( ) ;
208
+ let directory = Url :: parse ( & format ! ( "https://localhost:{}" , * DIRECTORY_PORT ) ) ?;
209
+ let ohttp_relay = Url :: parse ( & format ! ( "http://localhost:{}" , * OHTTP_RELAY_PORT ) ) ?;
210
+ let gateway_origin = http:: Uri :: from_str ( directory. as_str ( ) ) ?;
211
+
212
+ // Start services in background tasks
213
+ let _directory_handle =
214
+ tokio:: spawn ( init_directory ( * DIRECTORY_PORT , ( cert. clone ( ) , key) ) ) ;
215
+ let _relay_handle =
216
+ tokio:: spawn ( ohttp_relay:: listen_tcp ( * OHTTP_RELAY_PORT , gateway_origin) ) ;
217
+
218
+ // Create HTTP agent
219
+ let agent = Arc :: new ( http_agent ( cert. clone ( ) ) ?) ;
220
+
221
+ // Wait for services to be ready
222
+ wait_for_service_ready ( ohttp_relay. clone ( ) , agent. clone ( ) ) . await ?;
223
+ wait_for_service_ready ( directory. clone ( ) , agent. clone ( ) ) . await ?;
224
+
225
+ Ok ( Self { directory, ohttp_relay, agent, cert } )
226
+ }
227
+ }
228
+
229
+ async fn init_infrastructure ( ) -> & ' static TestInfrastructure {
230
+ TEST_INFRASTRUCTURE
231
+ . get_or_init ( || async {
232
+ TestInfrastructure :: new ( )
233
+ . await
234
+ . expect ( "Failed to initialize test infrastructure" )
235
+ } )
236
+ . await
237
+ }
192
238
193
239
#[ tokio:: test]
194
240
async fn test_bad_ohttp_keys ( ) {
195
241
let bad_ohttp_keys =
196
242
OhttpKeys :: from_str ( "AQO6SMScPUqSo60A7MY6Ak2hDO0CGAxz7BLYp60syRu0gw" )
197
243
. expect ( "Invalid OhttpKeys" ) ;
198
-
199
- let ( cert, key) = local_cert_key ( ) ;
200
- let port = find_free_port ( ) ;
201
- let directory = Url :: parse ( & format ! ( "https://localhost:{}" , port) ) . unwrap ( ) ;
202
- tokio:: select!(
203
- err = init_directory( port, ( cert. clone( ) , key) ) => panic!( "Directory server exited early: {:?}" , err) ,
204
- res = try_request_with_bad_keys( directory, bad_ohttp_keys, cert) => {
205
- assert_eq!(
206
- res. unwrap( ) . headers( ) . get( "content-type" ) . unwrap( ) ,
207
- "application/problem+json"
208
- ) ;
209
- }
244
+ let infra = init_infrastructure ( ) . await ;
245
+ let res = try_request_with_bad_keys (
246
+ infra. directory . clone ( ) ,
247
+ bad_ohttp_keys,
248
+ infra. cert . clone ( ) ,
249
+ )
250
+ . await ;
251
+ assert_eq ! (
252
+ res. unwrap( ) . headers( ) . get( "content-type" ) . unwrap( ) ,
253
+ "application/problem+json"
210
254
) ;
211
255
212
256
async fn try_request_with_bad_keys (
213
257
directory : Url ,
214
258
bad_ohttp_keys : OhttpKeys ,
215
259
cert_der : Vec < u8 > ,
216
260
) -> Result < Response , Error > {
217
- let agent = Arc :: new ( http_agent ( cert_der. clone ( ) ) . unwrap ( ) ) ;
218
- wait_for_service_ready ( directory. clone ( ) , agent. clone ( ) ) . await . unwrap ( ) ;
261
+ let agent = Arc :: new ( http_agent ( cert_der) . unwrap ( ) ) ;
219
262
let mock_ohttp_relay = directory. clone ( ) ; // pass through to directory
220
263
let mock_address = Address :: from_str ( "tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4" )
221
264
. unwrap ( )
@@ -230,18 +273,14 @@ mod integration {
230
273
#[ tokio:: test]
231
274
async fn test_session_expiration ( ) {
232
275
init_tracing ( ) ;
233
- let ( cert, key) = local_cert_key ( ) ;
234
- let ohttp_relay_port = find_free_port ( ) ;
235
- let ohttp_relay =
236
- Url :: parse ( & format ! ( "http://localhost:{}" , ohttp_relay_port) ) . unwrap ( ) ;
237
- let directory_port = find_free_port ( ) ;
238
- let directory = Url :: parse ( & format ! ( "https://localhost:{}" , directory_port) ) . unwrap ( ) ;
239
- let gateway_origin = http:: Uri :: from_str ( directory. as_str ( ) ) . unwrap ( ) ;
240
- tokio:: select!(
241
- err = ohttp_relay:: listen_tcp( ohttp_relay_port, gateway_origin) => panic!( "Ohttp relay exited early: {:?}" , err) ,
242
- err = init_directory( directory_port, ( cert. clone( ) , key) ) => panic!( "Directory server exited early: {:?}" , err) ,
243
- res = do_expiration_tests( ohttp_relay, directory, cert) => assert!( res. is_ok( ) , "v2 send receive failed: {:#?}" , res)
244
- ) ;
276
+ let infra = init_infrastructure ( ) . await ;
277
+ let res = do_expiration_tests (
278
+ infra. ohttp_relay . clone ( ) ,
279
+ infra. directory . clone ( ) ,
280
+ infra. cert . clone ( ) ,
281
+ )
282
+ . await ;
283
+ assert ! ( res. is_ok( ) , "v2 send receive failed: {:#?}" , res) ;
245
284
246
285
async fn do_expiration_tests (
247
286
ohttp_relay : Url ,
@@ -250,8 +289,6 @@ mod integration {
250
289
) -> Result < ( ) , BoxError > {
251
290
let ( _bitcoind, sender, receiver) = init_bitcoind_sender_receiver ( None , None ) ?;
252
291
let agent = Arc :: new ( http_agent ( cert_der. clone ( ) ) ?) ;
253
- wait_for_service_ready ( ohttp_relay. clone ( ) , agent. clone ( ) ) . await . unwrap ( ) ;
254
- wait_for_service_ready ( directory. clone ( ) , agent. clone ( ) ) . await . unwrap ( ) ;
255
292
let ohttp_keys =
256
293
payjoin:: io:: fetch_ohttp_keys ( ohttp_relay, directory. clone ( ) , cert_der. clone ( ) )
257
294
. await ?;
@@ -298,18 +335,14 @@ mod integration {
298
335
#[ tokio:: test]
299
336
async fn v2_to_v2 ( ) {
300
337
init_tracing ( ) ;
301
- let ( cert, key) = local_cert_key ( ) ;
302
- let ohttp_relay_port = find_free_port ( ) ;
303
- let ohttp_relay =
304
- Url :: parse ( & format ! ( "http://localhost:{}" , ohttp_relay_port) ) . unwrap ( ) ;
305
- let directory_port = find_free_port ( ) ;
306
- let directory = Url :: parse ( & format ! ( "https://localhost:{}" , directory_port) ) . unwrap ( ) ;
307
- let gateway_origin = http:: Uri :: from_str ( directory. as_str ( ) ) . unwrap ( ) ;
308
- tokio:: select!(
309
- err = ohttp_relay:: listen_tcp( ohttp_relay_port, gateway_origin) => panic!( "Ohttp relay exited early: {:?}" , err) ,
310
- err = init_directory( directory_port, ( cert. clone( ) , key) ) => panic!( "Directory server exited early: {:?}" , err) ,
311
- res = do_v2_send_receive( ohttp_relay, directory, cert) => assert!( res. is_ok( ) , "v2 send receive failed: {:#?}" , res)
312
- ) ;
338
+ let infra = init_infrastructure ( ) . await ;
339
+ let res = do_v2_send_receive (
340
+ infra. ohttp_relay . clone ( ) ,
341
+ infra. directory . clone ( ) ,
342
+ infra. cert . clone ( ) ,
343
+ )
344
+ . await ;
345
+ assert ! ( res. is_ok( ) , "v2 send receive failed: {:#?}" , res) ;
313
346
314
347
async fn do_v2_send_receive (
315
348
ohttp_relay : Url ,
@@ -318,8 +351,6 @@ mod integration {
318
351
) -> Result < ( ) , BoxError > {
319
352
let ( _bitcoind, sender, receiver) = init_bitcoind_sender_receiver ( None , None ) ?;
320
353
let agent = Arc :: new ( http_agent ( cert_der. clone ( ) ) ?) ;
321
- wait_for_service_ready ( ohttp_relay. clone ( ) , agent. clone ( ) ) . await . unwrap ( ) ;
322
- wait_for_service_ready ( directory. clone ( ) , agent. clone ( ) ) . await . unwrap ( ) ;
323
354
let ohttp_keys =
324
355
payjoin:: io:: fetch_ohttp_keys ( ohttp_relay, directory. clone ( ) , cert_der. clone ( ) )
325
356
. await ?;
@@ -430,18 +461,14 @@ mod integration {
430
461
#[ tokio:: test]
431
462
async fn v2_to_v2_mixed_input_script_types ( ) {
432
463
init_tracing ( ) ;
433
- let ( cert, key) = local_cert_key ( ) ;
434
- let ohttp_relay_port = find_free_port ( ) ;
435
- let ohttp_relay =
436
- Url :: parse ( & format ! ( "http://localhost:{}" , ohttp_relay_port) ) . unwrap ( ) ;
437
- let directory_port = find_free_port ( ) ;
438
- let directory = Url :: parse ( & format ! ( "https://localhost:{}" , directory_port) ) . unwrap ( ) ;
439
- let gateway_origin = http:: Uri :: from_str ( directory. as_str ( ) ) . unwrap ( ) ;
440
- tokio:: select!(
441
- err = ohttp_relay:: listen_tcp( ohttp_relay_port, gateway_origin) => panic!( "Ohttp relay exited early: {:?}" , err) ,
442
- err = init_directory( directory_port, ( cert. clone( ) , key) ) => panic!( "Directory server exited early: {:?}" , err) ,
443
- res = do_v2_send_receive( ohttp_relay, directory, cert) => assert!( res. is_ok( ) , "v2 send receive failed: {:#?}" , res)
444
- ) ;
464
+ let infra = init_infrastructure ( ) . await ;
465
+ let res = do_v2_send_receive (
466
+ infra. ohttp_relay . clone ( ) ,
467
+ infra. directory . clone ( ) ,
468
+ infra. cert . clone ( ) ,
469
+ )
470
+ . await ;
471
+ assert ! ( res. is_ok( ) , "v2 send receive failed: {:#?}" , res) ;
445
472
446
473
async fn do_v2_send_receive (
447
474
ohttp_relay : Url ,
@@ -450,15 +477,12 @@ mod integration {
450
477
) -> Result < ( ) , BoxError > {
451
478
let ( bitcoind, sender, receiver) = init_bitcoind_sender_receiver ( None , None ) ?;
452
479
let agent = Arc :: new ( http_agent ( cert_der. clone ( ) ) ?) ;
453
- wait_for_service_ready ( ohttp_relay. clone ( ) , agent. clone ( ) ) . await . unwrap ( ) ;
454
- wait_for_service_ready ( directory. clone ( ) , agent. clone ( ) ) . await . unwrap ( ) ;
455
480
let ohttp_keys =
456
481
payjoin:: io:: fetch_ohttp_keys ( ohttp_relay, directory. clone ( ) , cert_der. clone ( ) )
457
482
. await ?;
458
483
// **********************
459
484
// Inside the Receiver:
460
485
// make utxos with different script types
461
-
462
486
let legacy_address =
463
487
receiver. get_new_address ( None , Some ( AddressType :: Legacy ) ) ?. assume_checked ( ) ;
464
488
let nested_segwit_address =
@@ -647,18 +671,11 @@ mod integration {
647
671
#[ tokio:: test]
648
672
async fn v1_to_v2 ( ) {
649
673
init_tracing ( ) ;
650
- let ( cert, key) = local_cert_key ( ) ;
651
- let ohttp_relay_port = find_free_port ( ) ;
652
- let ohttp_relay =
653
- Url :: parse ( & format ! ( "http://localhost:{}" , ohttp_relay_port) ) . unwrap ( ) ;
654
- let directory_port = find_free_port ( ) ;
655
- let directory = Url :: parse ( & format ! ( "https://localhost:{}" , directory_port) ) . unwrap ( ) ;
656
- let gateway_origin = http:: Uri :: from_str ( directory. as_str ( ) ) . unwrap ( ) ;
657
- tokio:: select!(
658
- err = ohttp_relay:: listen_tcp( ohttp_relay_port, gateway_origin) => panic!( "Ohttp relay exited early: {:?}" , err) ,
659
- err = init_directory( directory_port, ( cert. clone( ) , key) ) => panic!( "Directory server exited early: {:?}" , err) ,
660
- res = do_v1_to_v2( ohttp_relay, directory, cert) => assert!( res. is_ok( ) ) ,
661
- ) ;
674
+ let infra = init_infrastructure ( ) . await ;
675
+ let res =
676
+ do_v1_to_v2 ( infra. ohttp_relay . clone ( ) , infra. directory . clone ( ) , infra. cert . clone ( ) )
677
+ . await ;
678
+ assert ! ( res. is_ok( ) ) ;
662
679
663
680
async fn do_v1_to_v2 (
664
681
ohttp_relay : Url ,
@@ -667,8 +684,6 @@ mod integration {
667
684
) -> Result < ( ) , BoxError > {
668
685
let ( _bitcoind, sender, receiver) = init_bitcoind_sender_receiver ( None , None ) ?;
669
686
let agent: Arc < Client > = Arc :: new ( http_agent ( cert_der. clone ( ) ) ?) ;
670
- wait_for_service_ready ( ohttp_relay. clone ( ) , agent. clone ( ) ) . await ?;
671
- wait_for_service_ready ( directory. clone ( ) , agent. clone ( ) ) . await ?;
672
687
let ohttp_keys =
673
688
payjoin:: io:: fetch_ohttp_keys ( ohttp_relay, directory. clone ( ) , cert_der. clone ( ) )
674
689
. await ?;
@@ -780,13 +795,19 @@ mod integration {
780
795
async fn init_directory (
781
796
port : u16 ,
782
797
local_cert_key : ( Vec < u8 > , Vec < u8 > ) ,
783
- ) -> Result < ( ) , BoxError > {
798
+ ) -> Result < ( ) , Box < dyn std :: error :: Error + Send + Sync + ' static > > {
784
799
let docker: Cli = Cli :: default ( ) ;
785
800
let timeout = Duration :: from_secs ( 2 ) ;
786
801
let db = docker. run ( Redis ) ;
787
802
let db_host = format ! ( "127.0.0.1:{}" , db. get_host_port_ipv4( 6379 ) ) ;
788
803
println ! ( "Database running on {}" , db. get_host_port_ipv4( 6379 ) ) ;
789
- payjoin_directory:: listen_tcp_with_tls ( port, db_host, timeout, local_cert_key) . await
804
+ payjoin_directory:: listen_tcp_with_tls ( port, db_host, timeout, local_cert_key)
805
+ . await
806
+ . map_err ( |e| {
807
+ let err_string = e. to_string ( ) ;
808
+ Box :: new ( std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , err_string) )
809
+ as Box < dyn std:: error:: Error + Send + Sync + ' static >
810
+ } )
790
811
}
791
812
792
813
// generates or gets a DER encoded localhost cert and key.
0 commit comments