Package: gocept.testdb
Creates and drops temporary databases for testing purposes.This package has been tested with Python 3.8, 3.9, 3.10 and 3.11.Copyright (c) 2008-2015, 2020-2021 gocept gmbh & co. kg and contributors.All Rights Reserved.This software is subject to the provisions of the Zope Public License,
Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
THIS SOFTWARE IS PROVIDED “AS IS” AND ANY AND ALL EXPRESS OR IMPLIED
WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
FOR A PARTICULAR PURPOSE.ContentsMySQLPostgreSQLThedrop-allcommand-line scriptDevelopmentChangeloggocept.testdbprovides small helper classes that create and drop temporary
databases.>>> import gocept.testdb
>>> import os.path
>>> import shutil
>>> import sqlalchemy
>>> import tempfile
>>> sql_dir = tempfile.mkdtemp()
>>> schema = os.path.join(sql_dir, 'sample.sql')
>>> with open(schema, 'w') as f:
...     _ = f.write('CREATE TABLE foo (dummy int);')We’ll use a custom prefix specific to the current process whenever we create
fixed-name databases during this test, in order to allow concurrent test runs
on the same machine (such as a CI server):>>> import os
>>> pid_prefix = 'gocept.testdb.tests-PID%s-' % os.getpid()
>>> db_template = pid_prefix + 'templatetest'MySQLgocept.testdbexpects the usage ofPyMySQLas database driver.First, instantiate a test database object and have it create the database on
the server. You can specify the name or the prefix of the database:>>> gocept.testdb.MySQL(schema_path=schema, db_name='mytestdb').dsn
'mysql+pymysql://.../mytestdb'
>>> db = gocept.testdb.MySQL(schema_path=schema, prefix='my-tests')
>>> db.dsn
'mysql+pymysql://.../my-tests-...'
>>> db.create()This will use the appropriate command-line tools to create a database with a
random name.You can use the following environment variables to customize the DSN:MYSQL_HOSThostname, defaults tolocalhostMYSQL_PORTport of the database, defaults to use a socket when not setMYSQL_USERusername, defaults toNonewhich means to use the name of the
user logged into the operating system.MYSQL_PASSpassword, defaults toNonewhich means no password required.MYSQL_COMMAND_POSTFIXattach this postfix to MySQL commands, defaults to an empty string. You
need this variable if your MySQL commands are named likemysql5instead
ofmysql.The dbapi DSN can then be used to connect to the database:>>> engine = sqlalchemy.create_engine(db.dsn)The database is marked as a testing database by creating a table calledtmp_functestin it:>>> with engine.connect() as conn:
...     with conn.begin():
...         ignore = conn.execute(sqlalchemy.text('SELECT * from tmp_functest'))The database object also offers convenience methods for determining the status
of the database:>>> db.exists
True
>>> db.is_testing
TrueIf you passed aschema_pathto the constructor, the SQL code in this file
is executed, e. g. to set up tables:>>> with engine.connect() as conn:
...     with conn.begin():
...         ignore = conn.execute(sqlalchemy.text('SELECT * from foo'))When done, simply drop the database:>>> engine.dispose()
>>> db.drop()PostgreSQLGeneralThe same procedure also works for PostgreSQL.
You can use the following environment variables to customize the DSN:POSTGRES_HOSThostname, defaults tolocalhostPOSTGRES_PORTport of the database server, not used when not set, aka 5432POSTGRES_USERusername, defaults toNonewhich means to use the name of the
user logged into the operating system.POSTGRES_PASSpassword, defaults toNonewhich means no password required.Note:Instead of usingPOSTGRES_PASS, use the~/.pgpassmechanismprovided by postgresitself.>>> db = gocept.testdb.PostgreSQL(schema_path=schema)
>>> db.create()
>>> engine = sqlalchemy.create_engine(db.dsn)
>>> conn = engine.connect()
>>> ignore = conn.execute(sqlalchemy.text('SELECT * from tmp_functest'))
>>> ignore = conn.execute(sqlalchemy.text('SELECT * from foo'))
>>> conn.invalidate()
>>> db.drop()EncodingFor PostgreSQL an optional encoding, database name and database name prefix
parameters can be specified in the constructor. They are used when creating the
database.>>> gocept.testdb.PostgreSQL(encoding='UTF8', db_name='mytestdb').dsn
'postgresql://...localhost.../mytestdb'
>>> gocept.testdb.PostgreSQL(prefix='my-tests').dsn
'postgresql://...localhost.../my-tests-...'TemplatesFor PostgreSQL, an optional template parameter can be passed to the
constructor. It specifies the name of a template database which is used for the
creation of the test database. If the template database does not exist, it is
created with the specified schema.The first time you create the database with thedb_templateargument, the
template database is created (if it does not exist already) along with the
requested database:>>> db = gocept.testdb.PostgreSQL(schema_path=schema, db_template=db_template)Now with the template available, the schema is not used any more to create the
database (it’s copied from the template database).When creating the database, we can, however, force the template database to be
created afresh from the schema. Doing so now will leave us with both a test
database and a template database according to the modified schema:>>> db = gocept.testdb.PostgreSQL(
...     schema_path=schema, db_template=db_template, force_template=True)The template database (and with it, the test database) is also created anew if
the schema file is newer than the existing template database.If, however, the template database cannot be set up properly, it is removed
altogether to avoid a broken template database interfering with subsequent
tests.Thedrop-allcommand-line scriptThe Database classes’drop_allfunctionality is available independently
through a command-line script nameddrop-all. The script drops any test
databases from both the PostgreSQL and MySQL servers that match the
test-database naming convention with any of the prefixes passed as
command-line arguments. Usage:$ bin/drop-all "<prefix>"Test clean up:>>> shutil.rmtree(sql_dir)DevelopmentTo run thebuildoutof this package copylocal.cfg.exampletolocal.cfgand edit it to match your needs:MYSQL_COMMAND_POSTFIXis needed if your MySQL commands look likemysql5instead ofmysqlMySQL has to open a port for the tests to connect to. Configure this in yourmy.cnf.Running testsInstalltoxand run the tests callingtox.Using docker containers for the testsPrerequisitesmysqladminandmysqlhave to be on $PATH.createdbhas to be on $PATH.Run the follwing commands (you might change the passwords used):docker run --name mysql56 -e MYSQL_ROOT_PASSWORD=84_L224JF0GlTXcL -d -p 3307:3306 mysql:5.6
docker run --name postgres96 -e POSTGRES_PASSWORD=j§V7iJY@1xTG67J@ -d -p 5433:5432 postgres:9.6
echo "localhost:5433:*:postgres:j§V7iJY@1xTG67J@" >> ~/.pgpass
chmod 600 ~/.pgpassRun the testsMYSQL_PORT=3307 MYSQL_USER=root MYSQL_PASS=84_L224JF0GlTXcL POSTGRES_PORT=5433 POSTGRES_USER=postgres toxSource codeThe source code is available athttps://github.com/gocept/gocept.testdbBug reportsPlease report any bugs you find tohttps://github.com/gocept/gocept.testdb/issuesChangelog6.0 (2023-08-28)Backwards incompatible changesDrop support for Python 2.7, 3.6.Drop support for SQLAlchemy < 1.2.FeaturesAdd support for Python 3.10, 3.11.Add support for SQLAlchemy 2.x.5.2.1 (2023-03-16)Restrict supported SQLALchemy to < 2.5.2 (2021-04-26)Ensure compatibility withpytest > 6.0.Add support for Python 3.9.Switch CI to GHA.Fix PostgreSQLdrop_dbto be able to forcibly drop a data base with open
connections, even though there is no database with the same name as the user.5.1 (2020-07-06)Forcibly close connections to test database before dropping, so this does not
have to be done beforehand. (Ported from 4.x but missing in change log
there.)Calculate a random database name that is random enough for parallel
execution. (Ported from 4.2)5.0 (2020-07-02)Backwards incompatible changesCaution:This release is based on version 1.3 ignoring the changes made in
the 4.x releases! At least some of those changes will be added later on.Drop support for Python 2.6 and Python 3.3 up to 3.5.Remove modulegocept.testdb.dbcontaining only imports for backwards
compatibility, import now fromgocept.testdb.mysqlresp.gocept.testdb.postgres.FeaturesOfficially support Python 3.6 up to 3.8.Add support to specify the port to connect to the database, thus the
environment variablesMYSQL_PORTandPOSTGRES_PORTare taken into
account. This eases using docker containers on custom ports.Other changesMigrate code to Github.1.3 (2015-10-07)Drop support of Python 3.2.Streamline documentation.1.3a1 (2015-09-24)Officially support Python 3.2 up to Python 3.4.Switch PyMySQL driver to support Python 3 for MySQL.Add environment variableMYSQL_COMMAND_POSTFIXto use MySQL commands likemysql5instead ofmysql.1.2.1 (2013-09-03)Improve retry logic for dropping databases: ensure that db actually exists
before trying to drop it (#12706).1.2 (2013-06-21)Provisional compatibility to Python 3 (no compatible mysql driver exists yet,
though).Fixed test code that made implicit assumptions about existing databases on
the PostgreSQL server used or depended on timing conditions.1.1.1 (2013-03-19)Usetemplate0when changingLC_COLLATEwhich was introduced in v1.1.1.1 (2013-03-19)Add possibility to set theLC_COLLATEwhen creating a database.1.0 (2013-03-12)Allow a postfix for mysql-commands.1.0b5 (2011-12-22)Use timestamp for randomizing database names to avoid collisions.1.0b4 (2011-09-23)drop-allentry point now also works, if PostgreSQL or MySQL is not
installed/running.1.0b3 (2011-05-13)Addedconnectconvenience method.1.0b2 (2011-05-04)Addedis_testingproperty as a convenience API.Addedexistsproperty as a convenience API.1.0b1 (2011-04-12)Changed the protocol for using test databases: separated instantiating a
Database instance from creating the database on the server. Creating
Database instances is cheap now so they can be interacted with and passed
around, deferring the expensive database creation on the server to the
moment db.create() is called explicitly. This is also more symmetric with
respect to db.drop().Added functionality for dropping all databases matching the testdb naming
scheme which may have been left on the server by earlier test runs.
Optionally also drops the template db.Added option to specify the name of the database for MySQL and PostgreSQL.Added an option to specify a template database for PostgreSQL. If it does
not exist, it is created from the specified schema. It is also possible to
force the creation of the template even if it exists (dropping the current
template database). Whenever the schema has changed since the template db
was last created, the template db is updated automatically.0.4 (2010-12-15)Added option to specify the encoding for the PostgreSQL database.Updated PostgreSQL protocol frompostgres:topostgresql:as the
former one is deprecated in SQLAlchemy 0.6, thus requiring atleast version
0.5.6 of SQLAlchemy.Added documentation how to develop this package further.Added doumentation about usage ofDatabase prefix.0.3 (2010-10-15)PostgreSQL: Don’t call createdb/dropdb with--quitebut only psql.0.2 (2009-02-26)implemented authentication with password for mysql.
Passwords for postgres are still not supported, though.0.1 (2008-09-26)first release