@@ -362,62 +362,125 @@ mod tests {
362362 CreateProject , Layer , LayerUpdate , OrderBy , Plot , PlotUpdate , PointSymbology , ProjectDb ,
363363 ProjectFilter , ProjectId , ProjectListOptions , ProjectListing , STRectangle , UpdateProject ,
364364 } ;
365+ use crate :: util:: config:: { get_config_element, Postgres } ;
365366 use crate :: util:: user_input:: UserInput ;
366367 use crate :: workflows:: registry:: WorkflowRegistry ;
367368 use crate :: workflows:: workflow:: Workflow ;
368- use bb8_postgres:: tokio_postgres;
369- use bb8_postgres:: tokio_postgres:: NoTls ;
369+ use bb8_postgres:: bb8:: ManageConnection ;
370+ use bb8_postgres:: tokio_postgres:: { self , NoTls } ;
371+ use futures:: Future ;
370372 use geoengine_datatypes:: primitives:: Coordinate2D ;
371373 use geoengine_datatypes:: spatial_reference:: { SpatialReference , SpatialReferenceOption } ;
372374 use geoengine_operators:: engine:: {
373375 MultipleRasterSources , PlotOperator , TypedOperator , VectorOperator ,
374376 } ;
375377 use geoengine_operators:: mock:: { MockPointSource , MockPointSourceParams } ;
376378 use geoengine_operators:: plot:: { Statistics , StatisticsParams } ;
377- use std:: str:: FromStr ;
379+ use rand:: RngCore ;
380+ use tokio:: runtime:: Handle ;
378381
379- #[ tokio:: test]
380- async fn test ( ) {
381- // TODO: load from test config
382- let config = tokio_postgres:: config:: Config :: from_str (
383- "postgresql://geoengine:geoengine@localhost:5432" ,
384- )
385- . unwrap ( ) ;
382+ /// Setup database schema and return its name.
383+ async fn setup_db ( ) -> ( tokio_postgres:: Config , String ) {
384+ let mut db_config = get_config_element :: < Postgres > ( ) . unwrap ( ) ;
385+ db_config. schema = format ! ( "geoengine_test_{}" , rand:: thread_rng( ) . next_u64( ) ) ; // generate random temp schema
386386
387- // TODO: clean schema before test
387+ let mut pg_config = tokio_postgres:: Config :: new ( ) ;
388+ pg_config
389+ . user ( & db_config. user )
390+ . password ( & db_config. password )
391+ . host ( & db_config. host )
392+ . dbname ( & db_config. database ) ;
388393
389- let ctx = PostgresContext :: new ( config, tokio_postgres:: NoTls )
394+ // generate schema with prior connection
395+ PostgresConnectionManager :: new ( pg_config. clone ( ) , NoTls )
396+ . connect ( )
397+ . await
398+ . unwrap ( )
399+ . batch_execute ( & format ! ( "CREATE SCHEMA {};" , & db_config. schema) )
390400 . await
391401 . unwrap ( ) ;
392402
393- anonymous ( & ctx) . await ;
403+ // fix schema by providing `search_path` option
404+ pg_config. options ( & format ! ( "-c search_path={}" , db_config. schema) ) ;
394405
395- let _user_id = user_reg_login ( & ctx) . await ;
406+ ( pg_config, db_config. schema )
407+ }
396408
397- let session = ctx
398- . user_db ( )
399- . write ( )
409+ /// Tear down database schema.
410+ async fn tear_down_db ( pg_config : tokio_postgres:: Config , schema : & str ) {
411+ // generate schema with prior connection
412+ PostgresConnectionManager :: new ( pg_config, NoTls )
413+ . connect ( )
400414 . await
401- . login ( UserCredentials {
402- email : "[email protected] " . into ( ) , 403- password : "secret123" . into ( ) ,
404- } )
415+ . unwrap ( )
416+ . batch_execute ( & format ! ( "DROP SCHEMA {} CASCADE;" , schema) )
405417 . await
406418 . unwrap ( ) ;
419+ }
420+
421+ async fn with_temp_context < F , Fut > ( f : F )
422+ where
423+ F : FnOnce ( PostgresContext < NoTls > ) -> Fut + std:: panic:: UnwindSafe + Send + ' static ,
424+ Fut : Future < Output = ( ) > + Send ,
425+ {
426+ let ( pg_config, schema) = setup_db ( ) . await ;
427+
428+ // catch all panics and clean up first…
429+ let executed_fn = {
430+ let pg_config = pg_config. clone ( ) ;
431+ std:: panic:: catch_unwind ( move || {
432+ tokio:: task:: block_in_place ( move || {
433+ Handle :: current ( ) . block_on ( async move {
434+ let ctx = PostgresContext :: new ( pg_config, tokio_postgres:: NoTls )
435+ . await
436+ . unwrap ( ) ;
437+ f ( ctx) . await
438+ } )
439+ } )
440+ } )
441+ } ;
442+
443+ tear_down_db ( pg_config, & schema) . await ;
444+
445+ // then throw errors afterwards
446+ if let Err ( err) = executed_fn {
447+ std:: panic:: resume_unwind ( err) ;
448+ }
449+ }
450+
451+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
452+ async fn test ( ) {
453+ with_temp_context ( |ctx| async move {
454+ anonymous ( & ctx) . await ;
455+
456+ let _user_id = user_reg_login ( & ctx) . await ;
457+
458+ let session = ctx
459+ . user_db ( )
460+ . write ( )
461+ . await
462+ . login ( UserCredentials {
463+ email : "[email protected] " . into ( ) , 464+ password : "secret123" . into ( ) ,
465+ } )
466+ . await
467+ . unwrap ( ) ;
407468
408- create_projects ( & ctx, & session) . await ;
469+ create_projects ( & ctx, & session) . await ;
409470
410- let projects = list_projects ( & ctx, & session) . await ;
471+ let projects = list_projects ( & ctx, & session) . await ;
411472
412- set_session ( & ctx, & projects) . await ;
473+ set_session ( & ctx, & projects) . await ;
413474
414- let project_id = projects[ 0 ] . id ;
475+ let project_id = projects[ 0 ] . id ;
415476
416- update_projects ( & ctx, & session, project_id) . await ;
477+ update_projects ( & ctx, & session, project_id) . await ;
417478
418- add_permission ( & ctx, & session, project_id) . await ;
479+ add_permission ( & ctx, & session, project_id) . await ;
419480
420- delete_project ( ctx, & session, project_id) . await ;
481+ delete_project ( & ctx, & session, project_id) . await ;
482+ } )
483+ . await ;
421484 }
422485
423486 async fn set_session ( ctx : & PostgresContext < NoTls > , projects : & [ ProjectListing ] ) {
@@ -426,47 +489,30 @@ mod tests {
426489 password : "secret123" . into ( ) ,
427490 } ;
428491
429- let session = ctx
430- . user_db_ref_mut ( )
431- . await
432- . login ( credentials)
433- . await
434- . unwrap ( ) ;
492+ let mut user_db = ctx. user_db_ref_mut ( ) . await ;
435493
436- ctx. user_db_ref_mut ( )
437- . await
494+ let session = user_db. login ( credentials) . await . unwrap ( ) ;
495+
496+ user_db
438497 . set_session_project ( & session, projects[ 0 ] . id )
439498 . await
440499 . unwrap ( ) ;
500+
441501 assert_eq ! (
442- ctx. user_db_ref( )
443- . await
444- . session( session. id)
445- . await
446- . unwrap( )
447- . project,
502+ user_db. session( session. id) . await . unwrap( ) . project,
448503 Some ( projects[ 0 ] . id)
449504 ) ;
450505
451506 let rect = STRectangle :: new_unchecked ( SpatialReference :: epsg_4326 ( ) , 0. , 1. , 2. , 3. , 1 , 2 ) ;
452- ctx. user_db_ref_mut ( )
453- . await
507+ user_db
454508 . set_session_view ( & session, rect. clone ( ) )
455509 . await
456510 . unwrap ( ) ;
457- assert_eq ! (
458- ctx. user_db_ref( )
459- . await
460- . session( session. id)
461- . await
462- . unwrap( )
463- . view,
464- Some ( rect)
465- ) ;
511+ assert_eq ! ( user_db. session( session. id) . await . unwrap( ) . view, Some ( rect) ) ;
466512 }
467513
468514 async fn delete_project (
469- ctx : PostgresContext < NoTls > ,
515+ ctx : & PostgresContext < NoTls > ,
470516 session : & UserSession ,
471517 project_id : ProjectId ,
472518 ) {
0 commit comments