Commit 1876c150 authored by Jérome Perrin's avatar Jérome Perrin

postgres recipe tests

tests with a real postgresql server, the mocked commands from 261a8e6b (test/recipe: update tests for postgres recipe regarding password update, 2021-11-11) were too unrealistic.

These tests with a real server revealed that the port option of the recipe was not used, this is fixed as well

See merge request nexedi/slapos!1083
parents dae1747d 32fbf0d4
Pipeline #18335 failed with stage
[buildout]
extends =
../postgresql/buildout.cfg
[psycopg2-env]
PATH = ${postgresql:location}/bin:%(PATH)s
[psycopg2]
recipe = zc.recipe.egg:custom
egg = psycopg2
define = PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,PSYCOPG_NEW_BOOLEAN,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3
environment = psycopg2-env
include-dirs =
${postgresql:location}/include
library-dirs =
${postgresql:location}/lib
rpath =
${postgresql:location}/lib
...@@ -39,6 +39,7 @@ extras_require = { ...@@ -39,6 +39,7 @@ extras_require = {
'test': ( 'test': (
'jsonschema', 'jsonschema',
'mock', 'mock',
'psycopg2',
'testfixtures', 'testfixtures',
'requests', 'requests',
), ),
......
...@@ -147,6 +147,7 @@ class Recipe(GenericBaseRecipe): ...@@ -147,6 +147,7 @@ class Recipe(GenericBaseRecipe):
with open(postgres_conf, 'w') as cfg: with open(postgres_conf, 'w') as cfg:
cfg.write(textwrap.dedent("""\ cfg.write(textwrap.dedent("""\
listen_addresses = '%s' listen_addresses = '%s'
port = %s
logging_collector = on logging_collector = on
log_rotation_size = 50MB log_rotation_size = 50MB
max_connections = 100 max_connections = 100
...@@ -162,6 +163,7 @@ class Recipe(GenericBaseRecipe): ...@@ -162,6 +163,7 @@ class Recipe(GenericBaseRecipe):
unix_socket_permissions = 0700 unix_socket_permissions = 0700
""" % ( """ % (
','.join(set(ipv4).union(ipv6)), ','.join(set(ipv4).union(ipv6)),
self.options['port'],
pgdata, pgdata,
))) )))
...@@ -215,6 +217,7 @@ class Recipe(GenericBaseRecipe): ...@@ -215,6 +217,7 @@ class Recipe(GenericBaseRecipe):
p = subprocess.Popen([ p = subprocess.Popen([
psql_binary, psql_binary,
'-h', pgdata, '-h', pgdata,
'-p', self.options['port'],
'-U', user, '-U', user,
'-d', self.options['dbname'], '-d', self.options['dbname'],
], ],
......
...@@ -2,12 +2,22 @@ import os ...@@ -2,12 +2,22 @@ import os
import shutil import shutil
import tempfile import tempfile
import textwrap import textwrap
import time
import unittest import unittest
try:
import subprocess32 as subprocess
except ImportError:
import subprocess
import psycopg2
import zc.buildout.testing import zc.buildout.testing
class PostgresTest(unittest.TestCase): class PostgresTest(unittest.TestCase):
ipv4 = os.environ['SLAPOS_TEST_IPV4']
ipv6 = os.environ['SLAPOS_TEST_IPV6']
port = 5432
def setUp(self): def setUp(self):
self.buildout = buildout = zc.buildout.testing.Buildout() self.buildout = buildout = zc.buildout.testing.Buildout()
...@@ -15,45 +25,14 @@ class PostgresTest(unittest.TestCase): ...@@ -15,45 +25,14 @@ class PostgresTest(unittest.TestCase):
self.addCleanup(shutil.rmtree, self.pgdata_directory) self.addCleanup(shutil.rmtree, self.pgdata_directory)
self.services_directory = tempfile.mkdtemp() self.services_directory = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, self.services_directory) self.addCleanup(shutil.rmtree, self.services_directory)
self.software_bin_dir = tempfile.mkdtemp()
# create fake programs
self.addCleanup(shutil.rmtree, self.software_bin_dir)
initdb = os.path.join(self.software_bin_dir, 'initdb')
with open(initdb, 'w') as f:
f.write(textwrap.dedent('''\
#!/bin/sh
if [ ! "$1" = -D ]
then
echo Wrong arguments, expecting -D datadir ... got: "$@"
exit 1
fi
mkdir "$2"
'''))
os.chmod(initdb, 0o775)
postgres = os.path.join(self.software_bin_dir, 'postgres')
with open(postgres, 'w') as f:
f.write(textwrap.dedent('''\
#!/bin/sh
exec cat > %s/postgres.sql
''') % os.path.join(self.pgdata_directory, 'pgdata'))
os.chmod(postgres, 0o775)
psql = os.path.join(self.software_bin_dir, 'psql')
with open(psql, 'w') as f:
f.write(textwrap.dedent('''\
#!/bin/sh -xe
exec cat > %s/psql.sql
''') % os.path.join(self.pgdata_directory, 'pgdata'))
os.chmod(psql, 0o775)
self.postgres_bin_directory = os.environ['SLAPOS_TEST_POSTGRESQL_PREFIX'] + '/bin'
buildout['postgres'] = { buildout['postgres'] = {
'bin': self.software_bin_dir, 'bin': self.postgres_bin_directory,
'dbname': 'dbname', 'dbname': 'dbname',
'ipv4': '127.0.0.1', 'ipv4': self.ipv4,
'ipv6': '::1', 'ipv6': self.ipv6,
'port': '5443', 'port': self.port,
'pgdata-directory': os.path.join(self.pgdata_directory, 'pgdata'), 'pgdata-directory': os.path.join(self.pgdata_directory, 'pgdata'),
'services': self.services_directory, 'services': self.services_directory,
'superuser': 'superuser', 'superuser': 'superuser',
...@@ -65,10 +44,30 @@ class PostgresTest(unittest.TestCase): ...@@ -65,10 +44,30 @@ class PostgresTest(unittest.TestCase):
'postgres', 'postgres',
buildout['postgres']) buildout['postgres'])
def start_postgres_server(self):
server_process = subprocess.Popen(
[ os.path.join(self.services_directory, 'postgres-start') ],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
self.addCleanup(server_process.wait)
self.addCleanup(server_process.terminate)
# wait for server to accept connections
for i in range(60):
time.sleep(i)
try:
psycopg2.connect(self.buildout['postgres']['url']).close()
except psycopg2.OperationalError as e:
pass
else:
break
def test_options(self): def test_options(self):
self.assertEqual( self.assertEqual(
'postgresql://superuser:secret@[::1]:5443/dbname', self.buildout['postgres']['url'],
self.buildout['postgres']['url']) 'postgresql://superuser:secret@[{self.ipv6}]:{self.port}/dbname'.format(self=self),
)
def test_install(self): def test_install(self):
installed = self.recipe.install() installed = self.recipe.install()
...@@ -78,11 +77,6 @@ class PostgresTest(unittest.TestCase): ...@@ -78,11 +77,6 @@ class PostgresTest(unittest.TestCase):
self.assertIn('pg_hba.conf', os.listdir(pgdata_directory)) self.assertIn('pg_hba.conf', os.listdir(pgdata_directory))
self.assertIn('postgres-start', os.listdir(self.services_directory)) self.assertIn('postgres-start', os.listdir(self.services_directory))
with open(os.path.join(pgdata_directory, 'postgres.sql')) as f:
self.assertEqual(
f.read(),
'ALTER USER "superuser" ENCRYPTED PASSWORD \'md53992d9240b8f81ebd7e1f9a9fafeb06b\'\n'
)
self.assertEqual( self.assertEqual(
sorted(installed), sorted(installed),
sorted([ sorted([
...@@ -90,19 +84,33 @@ class PostgresTest(unittest.TestCase): ...@@ -90,19 +84,33 @@ class PostgresTest(unittest.TestCase):
os.path.join(pgdata_directory, 'pg_hba.conf'), os.path.join(pgdata_directory, 'pg_hba.conf'),
os.path.join(self.services_directory, 'postgres-start')])) os.path.join(self.services_directory, 'postgres-start')]))
self.start_postgres_server()
with psycopg2.connect(self.buildout['postgres']['url']) as cnx:
with cnx.cursor() as cursor:
cursor.execute("SELECT 1+1")
self.assertEqual(cursor.fetchone(), (2,))
cnx.close()
def test_update_password(self): def test_update_password(self):
self.recipe.install() self.recipe.install()
self.start_postgres_server()
# simulate a running server
pgdata_directory = os.path.join(self.pgdata_directory, 'pgdata')
open(os.path.join(pgdata_directory, 'postmaster.pid'), 'w').close()
self.recipe.options['password'] = 'new' self.recipe.options['password'] = 'new'
self.recipe.install() self.recipe.install()
with open(os.path.join(pgdata_directory, 'psql.sql')) as f: dsn = self.buildout['postgres']['url']
self.assertEqual( with psycopg2.connect(psycopg2.extensions.make_dsn(dsn, password='new')) as cnx:
f.read(), with cnx.cursor() as cursor:
'ALTER USER "superuser" ENCRYPTED PASSWORD \'md5442311d398491b7f6b512757b51ae9d8\'\n' cursor.execute("SELECT 1+1")
) self.assertEqual(cursor.fetchone(), (2,))
cnx.close()
# old password can no longer connect
with self.assertRaisesRegexp(
psycopg2.OperationalError,
'password authentication failed'
):
psycopg2.connect(dsn)
class PostgresTestNonStandardPort(PostgresTest):
port = 5433
...@@ -15,4 +15,4 @@ ...@@ -15,4 +15,4 @@
[template] [template]
filename = instance.cfg filename = instance.cfg
md5sum = 84bd6729e9b299c457cea2d1be6d05a4 md5sum = 597c29546519aabe7259e416d0b92095
...@@ -92,6 +92,7 @@ template = inline: ...@@ -92,6 +92,7 @@ template = inline:
export SLAPOS_TEST_IPV6=$${slap-configuration:ipv6-random} export SLAPOS_TEST_IPV6=$${slap-configuration:ipv6-random}
export SLAPOS_TEST_EGGS_DIRECTORY=$${buildout:eggs-directory} export SLAPOS_TEST_EGGS_DIRECTORY=$${buildout:eggs-directory}
export SLAPOS_TEST_DEVELOP_EGGS_DIRECTORY=$${buildout:develop-eggs-directory} export SLAPOS_TEST_DEVELOP_EGGS_DIRECTORY=$${buildout:develop-eggs-directory}
export SLAPOS_TEST_POSTGRESQL_PREFIX=${postgresql:location}
[slapos-test-runner-dot-nxdtest] [slapos-test-runner-dot-nxdtest]
......
...@@ -17,6 +17,8 @@ extends = ...@@ -17,6 +17,8 @@ extends =
../../component/sed/buildout.cfg ../../component/sed/buildout.cfg
../../component/grep/buildout.cfg ../../component/grep/buildout.cfg
../../component/userhosts/buildout.cfg ../../component/userhosts/buildout.cfg
../../component/postgresql/buildout.cfg
../../component/psycopg2/buildout.cfg
../../stack/slapos.cfg ../../stack/slapos.cfg
../../stack/caucase/buildout.cfg ../../stack/caucase/buildout.cfg
../../stack/nxdtest.cfg ../../stack/nxdtest.cfg
...@@ -66,6 +68,7 @@ egg = slapos.cookbook[test] ...@@ -66,6 +68,7 @@ egg = slapos.cookbook[test]
setup = ${slapos.cookbook-repository:location} setup = ${slapos.cookbook-repository:location}
depends = depends =
${slapos.core-setup:egg} ${slapos.core-setup:egg}
${psycopg2:egg}
${slapos-cookbook-dependencies:eggs} ${slapos-cookbook-dependencies:eggs}
[slapos.core-setup] [slapos.core-setup]
...@@ -245,3 +248,4 @@ pyflakes = 2.0.0 ...@@ -245,3 +248,4 @@ pyflakes = 2.0.0
zope.testing = 4.6.2 zope.testing = 4.6.2
urllib3 = 1.24.1 urllib3 = 1.24.1
pathlib = 1.0.1 pathlib = 1.0.1
psycopg2 = 2.8.6
...@@ -36,6 +36,7 @@ extends = ...@@ -36,6 +36,7 @@ extends =
../../component/stunnel/buildout.cfg ../../component/stunnel/buildout.cfg
../../component/dropbear/buildout.cfg ../../component/dropbear/buildout.cfg
../../component/pycurl/buildout.cfg ../../component/pycurl/buildout.cfg
../../component/psycopg2/buildout.cfg
../slapos.cfg ../slapos.cfg
../resilient/buildout.cfg ../resilient/buildout.cfg
...@@ -127,26 +128,6 @@ md5sum = d95205a5fc2825e9709ed6db295111e2 ...@@ -127,26 +128,6 @@ md5sum = d95205a5fc2825e9709ed6db295111e2
mode = 0644 mode = 0644
#----------------
#-- Postgres driver for Python recipes.
[psycopg2-env]
PATH = ${postgresql:location}/bin:%(PATH)s
[psycopg2]
recipe = zc.recipe.egg:custom
egg = psycopg2
define = PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,PSYCOPG_NEW_BOOLEAN,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3
environment = psycopg2-env
include-dirs =
${postgresql:location}/include
library-dirs =
${postgresql:location}/lib
rpath =
${postgresql:location}/lib
#---------------- #----------------
#-- #--
#-- Optional part allowing applications using this stack to run a custom #-- Optional part allowing applications using this stack to run a custom
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment