6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-22 13:33:07 +01:00

Release 0.17.0 - Mapping + test globals

This commit is contained in:
Pavel Císař 2022-06-30 17:37:21 +02:00
parent c767ef8b4a
commit 3f86f45e5d
6 changed files with 178 additions and 11 deletions

View File

@ -4,11 +4,17 @@ Changelog
.. currentmodule:: firebird.qa.plugin
Version 0.17.0
==============
* Variable `test_cfg` renamed to `.QA_GLOBALS`.
* Added `.Mapping` and `.mapping_factory`.
Version 0.16.0
==============
* Added support for configuration of tests. A `~configparser.ConfigParser` instance is
available as `.test_cfg`. This instance is initialized with values from file `test_config.ini`
available as `test_cfg`. This instance is initialized with values from file `test_config.ini`
located in `files` subdirectory.
Version 0.15.2

View File

@ -23,10 +23,10 @@ copyright = '2022, Pavel Cisar'
author = 'Pavel Císař'
# The short X.Y version
version = '0.16.0'
version = '0.17.0'
# The full version, including alpha/beta/rc tags
release = '0.16.0'
release = '0.17.0'
# -- General configuration ---------------------------------------------------

View File

@ -8,9 +8,9 @@ Firebird-QA plugin Reference
Objects for use in tests
========================
test_cfg
--------
.. autodata:: test_cfg
QA_GLOBALS
----------
.. autodata:: QA_GLOBALS
Functions and classes for use in tests
======================================
@ -31,6 +31,10 @@ envar_factory
-------------
.. autofunction:: envar_factory
mapping_factory
---------------
.. autofunction:: mapping_factory
temp_file
---------
.. autofunction:: temp_file
@ -63,6 +67,10 @@ Envar
-----
.. autoclass:: Envar
Mapping
-------
.. autoclass:: Mapping
ServerKeeper
------------
.. autoclass:: ServerKeeper

View File

@ -37,5 +37,5 @@
"""
from .plugin import db_factory, Database, user_factory, User, isql_act, python_act, Action, \
temp_file, temp_files, role_factory, Role, envar_factory, Envar, ServerKeeper, \
ExecutionError, test_cfg
temp_file, temp_files, role_factory, Role, envar_factory, Envar, Mapping, mapping_factory, \
ServerKeeper, ExecutionError, QA_GLOBALS

View File

@ -73,7 +73,7 @@ _platform = platform.system()
_nodemap = {}
#: Configuration for tests
test_cfg: ConfigParser = ConfigParser(interpolation=ExtendedInterpolation())
QA_GLOBALS: ConfigParser = ConfigParser(interpolation=ExtendedInterpolation())
FIELD_ID = 'ID:'
FIELD_ISSUE = 'ISSUE:'
@ -337,7 +337,7 @@ def pytest_configure(config):
for tool in ['isql', 'gbak', 'nbackup', 'gstat', 'gfix', 'gsec', 'fbsvcmgr']:
set_tool(tool)
# Load test_config.ini
test_cfg.read(_vars_['files'] / 'test_config.ini')
QA_GLOBALS.read(_vars_['files'] / 'test_config.ini')
# Driver encoding for NONE charset
CHARSET_MAP['NONE'] = 'utf-8'
CHARSET_MAP[None] = 'utf-8'
@ -1346,6 +1346,159 @@ def role_factory(db_fixture_name: str, *, name: str, charset: str='utf8', do_not
return role_fixture
class Mapping:
"""Object to access and manage Firebird mapping.
Arguments:
database: Database used to manage mapping.
name: Mapping name.
charset: Firebird CHARACTER SET used for connections that manage this mapping.
do_not_create: When `True`, the mapping is not created when `with` context is entered.
is_global: Whether mapping is global or not.
source: Authentication plugin name, `ANY` for any plugin, `-` for mapping or `*` for
any method.
source_db: Database where authentication succeeded.
serverwide: Work only with server-wide plugins or not.
from_name: The name of the object from which mapping is performed. Could be `None`
for any value of given type.
from_type: The type of that name user name, role or OS groupdepending upon the
plug-in that added that name during authentication.
to_name: The name of the object TO which mapping is performed.
to_type: The type, for which only `USER` or `ROLE` is valid.
.. note::
Mappings are managed through SQL commands executed on connection to specified test
database.
.. important::
It's NOT RECOMMENDED to create instances of this class directly! The preffered way
is to use fixtures created by `mapping_factory`.
As test databases are managed by fixtures, it's necessary to ensure that mappings are
created after database initialization, and removed before test database is removed.
So, mapping `setup` and `teardown` is managed via context manager protocol and the
:ref:`with <with>` statement that must be executed within scope of used database.
Fixture created by `mapping_factory` does this automatically.
"""
def __init__(self, database: Database, name: str, charset: str, do_not_create: bool,
is_global: bool, source: Database, source_db: str, serverwide: bool,
from_name: str, from_type: str, to_name: Optional[str], to_type: str):
#: Database used to manage mapping.
self.db: Database = database
#: Mapping name.
self.name: str = name if name.startswith('"') else name.upper()
#: Firebird CHARACTER SET used for connections that manage this mapping.
self.charset = charset
#: When `True`, the mapping is not created when `with` context is entered.
self.do_not_create: bool = do_not_create
#: Whether mapping is global or not.
self.is_global = is_global
#: Authentication plugin name, `ANY` for any plugin, `-` for mapping or `*` for any method.
self.source: str = source
#: Database where authentication succeeded.
self.source_db: Database = source_db
#: Work only with server-wide plugins or not.
self.serverwide: bool = serverwide
#: The name of the object from which mapping is performed. Could be `None` for any value of given type.
self.from_name: str = from_name
#: The type of that name — user name, role or OS group—depending upon the plug-in that added that name during authentication.
self.from_type: str = from_type
#: The name of the object TO which mapping is performed.
self.to_name: str = to_name if to_name.startswith('"') else to_name.upper()
#: Target type, for which only `USER` or `ROLE` is valid.
self.to_type: str = to_type
def __enter__(self) -> Role:
if not self.do_not_create:
self.create()
return self
def __exit__(self, exc_type, exc_value, traceback) -> None:
self.drop()
def create(self) -> None:
"""Creates mapping. Called automatically when `with` context is entered.
"""
__tracebackhide__ = True
with self.db.connect(charset=self.charset) as con:
if self.source == '*':
using = "'*'"
elif self.source == '-':
using = 'MAPPING'
elif self.source == 'ANY':
using = 'ANY PLUGIN'
if self.serverwide:
using += ' SERVERWIDE'
else:
using = f'PLUGIN {self.source}'
if self.source_db is not None:
using += f' IN "{self.source_db.db_path}"'
if self.from_name is None:
from_spec = f'ANY {self.from_type}'
else:
from_spec = f'{self.from_type} {self.from_name}'
cmd = f'''CREATE {"GLOBAL " if self.is_global else " "}MAPPING {self.name}
USING {using}
FROM {from_spec}
TO {self.to_type} {self.to_name}
'''
con.execute_immediate(cmd)
con.commit()
print(f"CREATE mapping: {self.name}")
def drop(self) -> None:
"""Drop role in defined test database. Called automatically on `with` context exit.
"""
__tracebackhide__ = True
with self.db.connect(charset=self.charset) as con:
con.execute_immediate(f'DROP {"GLOBAL " if self.is_global else " "}MAPPING {self.name}')
con.commit()
print(f"DROP mapping: {self.name}")
def mapping_factory(db_fixture_name: str, *, name: str, is_global: bool, source: str,
from_name: str, from_type: str, to_name: Optional[str], to_type: str,
source_db_fixture_name: str=None, serverwide: bool=False,
charset: str='utf8', do_not_create: bool=False):
"""Factory function that returns :doc:`fixture <pytest:explanation/fixtures>` providing
the `Mapping` instance.
Arguments:
db_fixture_name: Name of database fixture used to manage mapping.
name: Mapping name.
is_global: Whether mapping is global or not.
source: Authentication plugin name, `ANY` for any plugin, `-` for mapping or `*` for
any method.
from_name: The name of the object from which mapping is performed. Could be `None`
for any value of given type.
from_type: The type of that name user name, role or OS groupdepending upon the
plug-in that added that name during authentication.
to_name: The name of the object TO which mapping is performed.
to_type: The type, for which only `USER` or `ROLE` is valid.
source_db_fixture_name: Name of database fixture for database where authentication succeeded.
serverwide: Work only with server-wide plugins or not.
charset: Firebird CHARACTER SET used for connections that manage this mapping.
do_not_create: When `True`, the mapping is not created when `with` context is entered.
.. important::
The `db_fixture_name` and `source_db_fixture_name` must be names of variable that
holds the fixture created by `db_factory` function.
**Test must use both, mapping and database fixtures!**
.. note::
Database must exists before mapping is created by fixture, so you cannot use database
fixtures created with `do_not_create` option, unless also the mapping is created with it!
"""
@pytest.fixture
def mapping_fixture(request: pytest.FixtureRequest) -> Mapping:
source_db = request.getfixturevalue(source_db_fixture_name)
with Mapping(request.getfixturevalue(db_fixture_name), name, charset, do_not_create,
is_global, source, source_db, serverwide, from_name, from_type,
to_name, to_type) as mapping:
yield mapping
return mapping_fixture
class Action:
"""Class to manage and execute Firebird tests.

View File

@ -5,7 +5,7 @@ all-files=True
[metadata]
name = firebird-qa
version = 0.16.0
version = 0.17.0
description = pytest plugin for Firebird QA
long_description = file: README.rst
long_description_content_type = text/x-rst; charset=UTF-8