@@ -507,3 +507,233 @@ def test_postgrest_ending_empty_key_query_parameter_is_removed(host):
507507 },
508508 )
509509 assert res .ok
510+
511+
512+ def test_postgresql_version (host ):
513+ """Print the PostgreSQL version being tested and ensure it's >= 14."""
514+ result = run_ssh_command (host ['ssh' ], "sudo -u postgres psql -c 'SELECT version();'" )
515+ if result ['succeeded' ]:
516+ print (f"\n PostgreSQL Version:\n { result ['stdout' ]} " )
517+ # Extract version number from the output
518+ version_line = result ['stdout' ].strip ().split ('\n ' )[2 ] # Skip header and get the actual version
519+ # Extract major version number (e.g., "15.8" -> 15)
520+ import re
521+ version_match = re .search (r'PostgreSQL (\d+)\.' , version_line )
522+ if version_match :
523+ major_version = int (version_match .group (1 ))
524+ print (f"PostgreSQL major version: { major_version } " )
525+ assert major_version >= 14 , f"PostgreSQL version { major_version } is less than 14"
526+ else :
527+ assert False , "Could not parse PostgreSQL version number"
528+ else :
529+ print (f"\n Failed to get PostgreSQL version: { result ['stderr' ]} " )
530+ assert False , "Failed to get PostgreSQL version"
531+
532+ # Also get the version from the command line
533+ result = run_ssh_command (host ['ssh' ], "sudo -u postgres psql --version" )
534+ if result ['succeeded' ]:
535+ print (f"PostgreSQL Client Version: { result ['stdout' ].strip ()} " )
536+ else :
537+ print (f"Failed to get PostgreSQL client version: { result ['stderr' ]} " )
538+
539+ print ("✓ PostgreSQL version is >= 14" )
540+
541+
542+ def test_libpq5_version (host ):
543+ """Print the libpq5 version installed and ensure it's >= 14."""
544+ # Try different package managers to find libpq5
545+ result = run_ssh_command (host ['ssh' ], "dpkg -l | grep libpq5 || true" )
546+ if result ['succeeded' ] and result ['stdout' ].strip ():
547+ print (f"\n libpq5 package info:\n { result ['stdout' ]} " )
548+ # Extract version from dpkg output (format: ii libpq5:arm64 17.5-1.pgdg20.04+1)
549+ import re
550+ version_match = re .search (r'libpq5[^ ]* +(\d+)\.' , result ['stdout' ])
551+ if version_match :
552+ major_version = int (version_match .group (1 ))
553+ print (f"libpq5 major version: { major_version } " )
554+ assert major_version >= 14 , f"libpq5 version { major_version } is less than 14"
555+ else :
556+ print ("Could not parse libpq5 version from dpkg output" )
557+ else :
558+ print ("\n libpq5 not found via dpkg" )
559+
560+ # Also try to find libpq.so files
561+ result = run_ssh_command (host ['ssh' ], "find /usr -name '*libpq*' -type f 2>/dev/null | head -10" )
562+ if result ['succeeded' ] and result ['stdout' ].strip ():
563+ print (f"\n libpq files found:\n { result ['stdout' ]} " )
564+ else :
565+ print ("\n No libpq files found" )
566+
567+ # Check if we can get version from a libpq file
568+ result = run_ssh_command (host ['ssh' ], "ldd /usr/bin/psql | grep libpq || true" )
569+ if result ['succeeded' ] and result ['stdout' ].strip ():
570+ print (f"\n psql libpq dependency:\n { result ['stdout' ]} " )
571+ else :
572+ print ("\n Could not find libpq dependency for psql" )
573+
574+ # Try to get version from libpq directly
575+ result = run_ssh_command (host ['ssh' ], "psql --version 2>&1 | head -1" )
576+ if result ['succeeded' ] and result ['stdout' ].strip ():
577+ print (f"\n psql version output: { result ['stdout' ].strip ()} " )
578+ # The psql version should match the libpq version
579+ import re
580+ version_match = re .search (r'psql \(PostgreSQL\) (\d+)\.' , result ['stdout' ])
581+ if version_match :
582+ major_version = int (version_match .group (1 ))
583+ print (f"psql/libpq major version: { major_version } " )
584+ assert major_version >= 14 , f"psql/libpq version { major_version } is less than 14"
585+ else :
586+ print ("Could not parse psql version" )
587+
588+ print ("✓ libpq5 version is >= 14" )
589+
590+
591+ def test_postgrest_read_only_session_attrs (host ):
592+ """Test PostgREST with target_session_attrs=read-only and check for session errors."""
593+ # First, check if PostgreSQL is configured for read-only mode
594+ result = run_ssh_command (host ['ssh' ], "sudo -u postgres psql -c \" SHOW default_transaction_read_only;\" " )
595+ if result ['succeeded' ]:
596+ default_read_only = result ['stdout' ].strip ()
597+ print (f"PostgreSQL default_transaction_read_only: { default_read_only } " )
598+ else :
599+ print ("Could not check PostgreSQL read-only setting" )
600+ default_read_only = "unknown"
601+
602+ # Check if PostgreSQL is in recovery mode (standby)
603+ result = run_ssh_command (host ['ssh' ], "sudo -u postgres psql -c \" SELECT pg_is_in_recovery();\" " )
604+ if result ['succeeded' ]:
605+ in_recovery = result ['stdout' ].strip ()
606+ print (f"PostgreSQL pg_is_in_recovery: { in_recovery } " )
607+ else :
608+ print ("Could not check PostgreSQL recovery status" )
609+ in_recovery = "unknown"
610+
611+ # Find PostgreSQL configuration file
612+ result = run_ssh_command (host ['ssh' ], "sudo -u postgres psql -c \" SHOW config_file;\" " )
613+ if result ['succeeded' ]:
614+ config_file = result ['stdout' ].strip ().split ('\n ' )[2 ].strip () # Skip header and get the actual path
615+ print (f"PostgreSQL config file: { config_file } " )
616+ else :
617+ print ("Could not find PostgreSQL config file" )
618+ config_file = "/etc/postgresql/15/main/postgresql.conf" # Default fallback
619+
620+ # Backup PostgreSQL config
621+ result = run_ssh_command (host ['ssh' ], f"sudo cp { config_file } { config_file } .backup" )
622+ assert result ['succeeded' ], "Failed to backup PostgreSQL config"
623+
624+ # Add read-only setting to PostgreSQL config
625+ result = run_ssh_command (host ['ssh' ], f"echo 'default_transaction_read_only = on' | sudo tee -a { config_file } " )
626+ assert result ['succeeded' ], "Failed to add read-only setting to PostgreSQL config"
627+
628+ # Restart PostgreSQL to apply the new configuration
629+ result = run_ssh_command (host ['ssh' ], "sudo systemctl restart postgresql" )
630+ assert result ['succeeded' ], "Failed to restart PostgreSQL"
631+
632+ # Wait for PostgreSQL to start up
633+ sleep (5 )
634+
635+ # Verify the change took effect
636+ result = run_ssh_command (host ['ssh' ], "sudo -u postgres psql -c \" SHOW default_transaction_read_only;\" " )
637+ if result ['succeeded' ]:
638+ new_default_read_only = result ['stdout' ].strip ()
639+ print (f"PostgreSQL default_transaction_read_only after change: { new_default_read_only } " )
640+ else :
641+ print ("Could not verify PostgreSQL read-only setting change" )
642+
643+ # First, backup the current PostgREST config
644+ result = run_ssh_command (host ['ssh' ], "sudo cp /etc/postgrest/base.conf /etc/postgrest/base.conf.backup" )
645+ assert result ['succeeded' ], "Failed to backup PostgREST config"
646+
647+ try :
648+ # Read the current config to get the db-uri
649+ result = run_ssh_command (host ['ssh' ], "sudo cat /etc/postgrest/base.conf | grep '^db-uri'" )
650+ assert result ['succeeded' ], "Failed to read current db-uri"
651+
652+ current_db_uri = result ['stdout' ].strip ()
653+ print (f"Current db-uri: { current_db_uri } " )
654+
655+ # Extract just the URI part (remove the db-uri = " prefix and trailing quote)
656+ uri_start = current_db_uri .find ('"' ) + 1
657+ uri_end = current_db_uri .rfind ('"' )
658+ base_uri = current_db_uri [uri_start :uri_end ]
659+
660+ # Modify the URI to add target_session_attrs=read-only
661+ if '?' in base_uri :
662+ # URI already has parameters, add target_session_attrs
663+ modified_uri = base_uri + "&target_session_attrs=read-only"
664+ else :
665+ # URI has no parameters, add target_session_attrs
666+ modified_uri = base_uri + "?target_session_attrs=read-only"
667+
668+ print (f"Modified URI: { modified_uri } " )
669+
670+ # Use awk to replace the db-uri line more reliably
671+ result = run_ssh_command (host ['ssh' ], f"sudo awk '{{if ($1 == \" db-uri\" ) print \" db-uri = \\ \" { modified_uri } \\ \" \" ; else print $0}}' /etc/postgrest/base.conf > /tmp/new_base.conf && sudo mv /tmp/new_base.conf /etc/postgrest/base.conf" )
672+ assert result ['succeeded' ], "Failed to update db-uri in config"
673+
674+ # Verify the change was made correctly
675+ result = run_ssh_command (host ['ssh' ], "sudo cat /etc/postgrest/base.conf | grep '^db-uri'" )
676+ print (f"Updated db-uri line: { result ['stdout' ].strip ()} " )
677+
678+ # Also show the full config to debug
679+ result = run_ssh_command (host ['ssh' ], "sudo cat /etc/postgrest/base.conf" )
680+ print (f"Full config after change:\n { result ['stdout' ]} " )
681+
682+ # Restart PostgREST to apply the new configuration
683+ result = run_ssh_command (host ['ssh' ], "sudo systemctl restart postgrest" )
684+ assert result ['succeeded' ], "Failed to restart PostgREST"
685+
686+ # Wait a moment for PostgREST to start up
687+ sleep (5 )
688+
689+ # Check if PostgREST is running
690+ result = run_ssh_command (host ['ssh' ], "sudo systemctl is-active postgrest" )
691+ if not (result ['succeeded' ] and result ['stdout' ].strip () == 'active' ):
692+ # If PostgREST failed to start, check the logs to see why
693+ log_result = run_ssh_command (host ['ssh' ], "sudo journalctl -u postgrest --since '5 seconds ago' --no-pager" )
694+ print (f"PostgREST failed to start. Recent logs:\n { log_result ['stdout' ]} " )
695+ assert False , "PostgREST failed to start after config change"
696+
697+ # Make a test request to trigger any potential session errors
698+ try :
699+ response = requests .get (
700+ f"http://{ host ['ip' ]} /rest/v1/" ,
701+ headers = {"apikey" : anon_key , "authorization" : f"Bearer { anon_key } " },
702+ timeout = 10
703+ )
704+ print (f"Test request status: { response .status_code } " )
705+ except Exception as e :
706+ print (f"Test request failed: { str (e )} " )
707+
708+ # Check PostgREST logs for "session is not read-only" errors
709+ result = run_ssh_command (host ['ssh' ], "sudo journalctl -u postgrest --since '5 seconds ago' | grep -i 'session is not read-only' || true" )
710+
711+ if result ['stdout' ].strip ():
712+ print (f"\n Found 'session is not read-only' errors in PostgREST logs:\n { result ['stdout' ]} " )
713+ assert False , "PostgREST logs contain 'session is not read-only' errors even though PostgreSQL is configured for read-only mode"
714+ else :
715+ print ("\n No 'session is not read-only' errors found in PostgREST logs" )
716+
717+ finally :
718+ # Restore the original configuration
719+ result = run_ssh_command (host ['ssh' ], "sudo cp /etc/postgrest/base.conf.backup /etc/postgrest/base.conf" )
720+ if result ['succeeded' ]:
721+ result = run_ssh_command (host ['ssh' ], "sudo systemctl restart postgrest" )
722+ if result ['succeeded' ]:
723+ print ("Restored original PostgREST configuration" )
724+ else :
725+ print ("Warning: Failed to restart PostgREST after restoring config" )
726+ else :
727+ print ("Warning: Failed to restore original PostgREST configuration" )
728+
729+ # Restore PostgreSQL to original configuration
730+ result = run_ssh_command (host ['ssh' ], f"sudo cp { config_file } .backup { config_file } " )
731+ if result ['succeeded' ]:
732+ result = run_ssh_command (host ['ssh' ], "sudo systemctl restart postgresql" )
733+ if result ['succeeded' ]:
734+ print ("Restored PostgreSQL to original configuration" )
735+ else :
736+ print ("Warning: Failed to restart PostgreSQL after restoring config" )
737+ else :
738+ print ("Warning: Failed to restore PostgreSQL configuration" )
739+
0 commit comments