@@ -435,3 +435,93 @@ def tearDown(self):
435
435
self .con = None
436
436
finally :
437
437
super ().tearDown ()
438
+
439
+
440
+ class HotStandbyTestCase (ClusterTestCase ):
441
+
442
+ @classmethod
443
+ def setup_cluster (cls ):
444
+ cls .master_cluster = cls .new_cluster (pg_cluster .TempCluster )
445
+ cls .start_cluster (
446
+ cls .master_cluster ,
447
+ server_settings = {
448
+ 'max_wal_senders' : 10 ,
449
+ 'wal_level' : 'hot_standby'
450
+ }
451
+ )
452
+
453
+ con = None
454
+
455
+ try :
456
+ con = cls .loop .run_until_complete (
457
+ cls .master_cluster .connect (
458
+ database = 'postgres' , user = 'postgres' , loop = cls .loop ))
459
+
460
+ cls .loop .run_until_complete (
461
+ con .execute ('''
462
+ CREATE ROLE replication WITH LOGIN REPLICATION
463
+ ''' ))
464
+
465
+ cls .master_cluster .trust_local_replication_by ('replication' )
466
+
467
+ conn_spec = cls .master_cluster .get_connection_spec ()
468
+
469
+ cls .standby_cluster = cls .new_cluster (
470
+ pg_cluster .HotStandbyCluster ,
471
+ cluster_kwargs = {
472
+ 'master' : conn_spec ,
473
+ 'replication_user' : 'replication'
474
+ }
475
+ )
476
+ cls .start_cluster (
477
+ cls .standby_cluster ,
478
+ server_settings = {
479
+ 'hot_standby' : True
480
+ }
481
+ )
482
+
483
+ finally :
484
+ if con is not None :
485
+ cls .loop .run_until_complete (con .close ())
486
+
487
+ @classmethod
488
+ def get_cluster_connection_spec (cls , cluster , kwargs = {}):
489
+ conn_spec = cluster .get_connection_spec ()
490
+ if kwargs .get ('dsn' ):
491
+ conn_spec .pop ('host' )
492
+ conn_spec .update (kwargs )
493
+ if not os .environ .get ('PGHOST' ) and not kwargs .get ('dsn' ):
494
+ if 'database' not in conn_spec :
495
+ conn_spec ['database' ] = 'postgres'
496
+ if 'user' not in conn_spec :
497
+ conn_spec ['user' ] = 'postgres'
498
+ return conn_spec
499
+
500
+ @classmethod
501
+ def get_connection_spec (cls , kwargs = {}):
502
+ primary_spec = cls .get_cluster_connection_spec (
503
+ cls .master_cluster , kwargs
504
+ )
505
+ standby_spec = cls .get_cluster_connection_spec (
506
+ cls .standby_cluster , kwargs
507
+ )
508
+ return {
509
+ 'host' : [primary_spec ['host' ], standby_spec ['host' ]],
510
+ 'port' : [primary_spec ['port' ], standby_spec ['port' ]],
511
+ 'database' : primary_spec ['database' ],
512
+ 'user' : primary_spec ['user' ],
513
+ ** kwargs
514
+ }
515
+
516
+ @classmethod
517
+ def connect_primary (cls , ** kwargs ):
518
+ conn_spec = cls .get_cluster_connection_spec (cls .master_cluster , kwargs )
519
+ return pg_connection .connect (** conn_spec , loop = cls .loop )
520
+
521
+ @classmethod
522
+ def connect_standby (cls , ** kwargs ):
523
+ conn_spec = cls .get_cluster_connection_spec (
524
+ cls .standby_cluster ,
525
+ kwargs
526
+ )
527
+ return pg_connection .connect (** conn_spec , loop = cls .loop )
0 commit comments