Skip to content
This repository has been archived by the owner on Sep 18, 2018. It is now read-only.

Commit

Permalink
Merge pull request #170 from kblumke/fix/issue100
Browse files Browse the repository at this point in the history
Random port selection accept tuples refs #100
  • Loading branch information
fizyk committed Jul 25, 2016
2 parents c9477b0 + 572629a commit c5d6a9d
Show file tree
Hide file tree
Showing 17 changed files with 134 additions and 126 deletions.
1 change: 1 addition & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pytest-dbfixtures along it's history.
* Hans Duedal
* Domen Kožar
* Dwayne Litzenberger
* Karolina Blümke

Great thanks to `Clearcode <http://clearcode.cc>`_ for allowing releasing
pytest-dbfixtures as free software!
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ unreleased
------

- [fix] support for rabbitpy 0.27.x
- [feature] Random port selection ports accept tuples and sets. replace string representation [backward incompatible]


0.14.3
Expand Down
2 changes: 1 addition & 1 deletion src/pytest_dbfixtures/factories/dynamodb.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class JarPathException(Exception):
pass


def dynamodb_proc(dynamodb_dir=None, host='localhost', port='?', delay=False):
def dynamodb_proc(dynamodb_dir=None, host='localhost', port=None, delay=False):
"""
DynamoDB process factory.
Expand Down
11 changes: 6 additions & 5 deletions src/pytest_dbfixtures/factories/elasticsearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ def elasticsearch_proc(host='127.0.0.1', port=9201, cluster_name=None,
This fixture requires at least version 1.0 of elasticsearch to work.
:param str host: host that the instance listens on
:param int|str port: exact port that the instance listens on (e.g. 8000),
or randomly selected port:
'?' - any random available port
'2000-3000' - random available port from a given range
'4002,4003' - random of 4002 or 4003 ports
:param str|int|tuple|set|list port:
exact port (e.g. '8000', 8000)
randomly selected port (None) - any random available port
[(2000,3000)] or (2000,3000) - random available port from a given range
[{4002,4003}] or {4002,4003} - random of 4002 or 4003 ports
[(2000,3000), {4002,4003}] -random of given orange and set
:param str cluster_name: name of a cluser this node should work on.
Used for autodiscovery. By default each node is in it's own cluser.
:param str network_publish_host: host to publish itself within cluser
Expand Down
15 changes: 8 additions & 7 deletions src/pytest_dbfixtures/factories/mongo.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,20 @@
from pytest_dbfixtures.utils import get_config, try_import, get_process_fixture


def mongo_proc(executable=None, params=None, host=None, port=None,
def mongo_proc(executable=None, params=None, host=None, port=-1,
logs_prefix=''):
"""
Mongo process factory.
:param str executable: path to mongod
:param str params: params
:param str host: hostname
:param str port: exact port (e.g. '8000')
or randomly selected port:
'?' - any random available port
'2000-3000' - random available port from a given range
'4002,4003' - random of 4002 or 4003 ports
:param str|int|tuple|set|list port:
exact port (e.g. '8000', 8000)
randomly selected port (None) - any random available port
[(2000,3000)] or (2000,3000) - random available port from a given range
[{4002,4003}] or {4002,4003} - random of 4002 or 4003 ports
[(2000,3000), {4002,4003}] -random of given range and set
:param str logs_prefix: prefix for log filename
:rtype: func
:returns: function which makes a mongo process
Expand Down Expand Up @@ -69,7 +70,7 @@ def mongo_proc_fixture(request):
mongo_params = params or config.mongo.params

mongo_host = host or config.mongo.host
mongo_port = get_port(port or config.mongo.port)
mongo_port = get_port(port) or get_port(config.mongo.port)

logsdir = path(request.config.getvalue('logsdir'))
mongo_logpath = logsdir / '{prefix}mongo.{port}.log'.format(
Expand Down
15 changes: 8 additions & 7 deletions src/pytest_dbfixtures/factories/mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,20 @@ def init_mysql_directory(mysql_init, datadir):


def mysql_proc(executable=None, admin_executable=None, init_executable=None,
host=None, port=None, params=None, logs_prefix=''):
host=None, port=-1, params=None, logs_prefix=''):
"""
Mysql server process factory.
:param str executable: path to mysql executable
:param str admin_executable: path to mysql_admin executable
:param str init_executable: path to mysql_init executable
:param str host: hostname
:param str port: exact port (e.g. '8000')
or randomly selected port:
'?' - any random available port
'2000-3000' - random available port from a given range
'4002,4003' - random of 4002 or 4003 ports
:param str|int|tuple|set|list port:
exact port (e.g. '8000', 8000)
randomly selected port (None) - any random available port
[(2000,3000)] or (2000,3000) - random available port from a given range
[{4002,4003}] or {4002,4003} - random of 4002 or 4003 ports
[(2000,3000), {4002,4003}] -random of given range and set
:param str params: additional command-line mysqld parameters
:param str logs_prefix: prefix for log filename
:rtype: func
Expand All @@ -98,7 +99,7 @@ def mysql_proc_fixture(request):
mysql_exec = executable or config.mysql.mysql_server
mysql_admin_exec = admin_executable or config.mysql.mysql_admin
mysql_init = init_executable or config.mysql.mysql_init
mysql_port = get_port(port or config.mysql.port)
mysql_port = get_port(port) or get_port(config.mysql.port)
mysql_host = host or config.mysql.host
mysql_params = params or config.mysql.params

Expand Down
15 changes: 8 additions & 7 deletions src/pytest_dbfixtures/factories/postgresql.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,18 @@ def drop_postgresql_database(psycopg2, user, host, port, db):
conn.close()


def postgresql_proc(executable=None, host=None, port=None, logs_prefix=''):
def postgresql_proc(executable=None, host=None, port=-1, logs_prefix=''):
"""
postgresql process factory.
:param str executable: path to postgresql_ctl
:param str host: hostname
:param str port: exact port (e.g. '8000')
or randomly selected port:
'?' - any random available port
'2000-3000' - random available port from a given range
'4002,4003' - random of 4002 or 4003 ports
:param str|int|tuple|set|list port:
exact port (e.g. '8000', 8000)
randomly selected port (None) - any random available port
[(2000,3000)] or (2000,3000) - random available port from a given range
[{4002,4003}] or {4002,4003} - random of 4002 or 4003 ports
[(2000,3000), {4002,4003}] - random of given range and set
:param str logs_prefix: prefix for log filename
:rtype: func
:returns: function which makes a postgresql process
Expand Down Expand Up @@ -166,7 +167,7 @@ def postgresql_proc_fixture(request):
postgresql_ctl = os.path.join(pg_bindir, 'pg_ctl')

pg_host = host or config.postgresql.host
pg_port = get_port(port or config.postgresql.port)
pg_port = get_port(port) or get_port(config.postgresql.port)
datadir = '/tmp/postgresqldata.{0}'.format(pg_port)
logsdir = path(request.config.getvalue('logsdir'))
logfile_path = logsdir / '{prefix}postgresql.{port}.log'.format(
Expand Down
41 changes: 21 additions & 20 deletions src/pytest_dbfixtures/factories/rabbitmq.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,27 +128,28 @@ def rabbit_path(name):
return path(env)


def rabbitmq_proc(config_file=None, server=None, host=None, port=None,
def rabbitmq_proc(config_file=None, server=None, host=None, port=-1,
node_name=None, rabbit_ctl_file=None, logs_prefix=''):
'''
Starts RabbitMQ as a subprocess.
:param str config_file: path to config file
:param str server: path to rabbitmq-server command
:param str host: server host
:param int|str port: exact server port (e.g. '8000')
or randomly selected port:
'?' - any random available port
'2000-3000' - random available port from a given range
'4002,4003' - random of 4002 or 4003 ports
:param str node_name: RabbitMQ node name used for setting environment
variable RABBITMQ_NODENAME (the default depends
on the port number, so multiple nodes are not
clustered)
:param str rabbit_ctl_file: path to rabbitmqctl file
:param str logs_prefix: prefix for log directory
:returns pytest fixture with RabbitMQ process executor
Starts RabbitMQ as a subprocess.
:param str config_file: path to config file
:param str server: path to rabbitmq-server command
:param str host: server host
:param str|int|tuple|set|list port:
exact port (e.g. '8000', 8000)
randomly selected port (None) - any random available port
[(2000,3000)] or (2000,3000) - random available port from a given range
[{4002,4003}] or {4002,4003} - random of 4002 or 4003 ports
[(2000,3000), {4002,4003}] -random of given range and set
:param str node_name: RabbitMQ node name used for setting environment
variable RABBITMQ_NODENAME (the default depends
on the port number, so multiple nodes are not
clustered)
:param str rabbit_ctl_file: path to rabbitmqctl file
:param str logs_prefix: prefix for log directory
:returns pytest fixture with RabbitMQ process executor
'''

@pytest.fixture(scope='session')
Expand Down Expand Up @@ -182,7 +183,7 @@ def rabbitmq_proc_fixture(request):
rabbit_ctl = rabbit_ctl_file or config.rabbit.rabbit_ctl
rabbit_server = server or config.rabbit.rabbit_server
rabbit_host = host or config.rabbit.host
rabbit_port = get_port(port or config.rabbit.port)
rabbit_port = get_port(port) or get_port(config.rabbit.port)

rabbit_path = path('/tmp/rabbitmq.{0}/'.format(rabbit_port))

Expand Down
15 changes: 8 additions & 7 deletions src/pytest_dbfixtures/factories/redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,20 @@


def redis_proc(executable=None, params=None, config_file=None,
host=None, port=None, logs_prefix=''):
host=None, port=-1, logs_prefix=''):
"""
Redis process factory.
:param str executable: path to redis-server
:param str params: params
:param str config_file: path to config file
:param str host: hostname
:param str port: exact port (e.g. '8000')
or randomly selected port:
'?' - any random available port
'2000-3000' - random available port from a given range
'4002,4003' - random of 4002 or 4003 ports
:param str|int|tuple|set|list port:
exact port (e.g. '8000', 8000)
randomly selected port (None) - any random available port
[(2000,3000)] or (2000,3000) - random available port from a given range
[{4002,4003}] or {4002,4003} - random of 4002 or 4003 ports
[(2000,3000), {4002,4003}] -random of given orange and set
:param str logs_prefix: prefix for log filename
:rtype: func
:returns: function which makes a redis process
Expand All @@ -67,7 +68,7 @@ def redis_proc_fixture(request):
redis_params = params or config.redis.params
redis_conf = config_file or request.config.getvalue('redis_conf')
redis_host = host or config.redis.host
redis_port = get_port(port or config.redis.port)
redis_port = get_port(port) or get_port(config.redis.port)

pidfile = 'redis-server.{port}.pid'.format(port=redis_port)
unixsocket = 'redis.{port}.sock'.format(port=redis_port)
Expand Down
74 changes: 36 additions & 38 deletions src/pytest_dbfixtures/port.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,70 +15,68 @@

# You should have received a copy of the GNU Lesser General Public License
# along with pytest-dbfixtures. If not, see <http://www.gnu.org/licenses/>.
import port_for
from itertools import chain

import port_for

class InvalidPortsDefinition(Exception):

"""
Exception raised if ports definition is not a valid string.
"""
class InvalidPortsDefinition(ValueError):
"""Exception raised if ports definition is not a valid string."""

def __init__(self, ports):
self.ports = ports

def __str__(self):
return ('Unknown format of ports: %s.\n'
'You should provide an exact port, ports range "4000-5000"'
'or a comma-separated ports list "4000,5000,6000-8000".'
'You should provide a ports range "[(4000,5000)]"'
'or "(4000,5000)" or a comma-separated ports set'
'"[{4000,5000,6000}]" or list of ints "[400,5000,6000,8000]"'
'or all of them "[(20000, 30000), {48889, 50121}, 4000, 4004]"'
% self.ports)


def get_port(ports):
"""
Retuns a random available port. If there's only one port passed
(e.g. 5000 or '5000') function does not check if port is available.
it there's -1 passed as an argument, function returns None.
When a range or list of ports is passed `port_for` external package
is used in order to find a free port.
:param int|str ports: e.g. 3000, '3000', '3000-3100', '3000,3002', '?'
:param str|int|tuple|set|list port:
exact port (e.g. '8000', 8000)
randomly selected port (None) - any random available port
[(2000,3000)] or (2000,3000) - random available port from a given range
[{4002,4003}] or {4002,4003} - random of 4002 or 4003 ports
[(2000,3000), {4002,4003}] -random of given orange and set
:returns: a random free port
:raises: ValueError
"""
if ports == -1:
return None
elif not ports:
return port_for.select_random(None)

try:
return int(ports)
except ValueError:
except TypeError:
pass

return port_for.select_random(parse_ports(ports))
ports_set = set()

try:
if not isinstance(ports, list):
ports = [ports]
ranges = port_for.utils.ranges_to_set(filter_by_type(ports, tuple))
nums = set(filter_by_type(ports, int))
sets = set(chain(*filter_by_type(ports, (set, frozenset))))
ports_set = ports_set.union(ranges, sets, nums)
except ValueError:
raise InvalidPortsDefinition

def parse_ports(ports):
"""
:param str ports: e.g. '3000', '3000-3100', '3000,3002', '?'
:returns: ports set reflecting specifified ports list/range.
:rtype set
"""
return port_for.select_random(ports_set)

if ports == '?':
return None

port_set = set()

for p in ports.split(','):
if '-' not in p:
# single, comma-separated port:
try:
port_set.add(int(p))
except ValueError:
raise InvalidPortsDefinition(ports)
else:
# range of ports:
try:
start, end = p.split('-')
except ValueError:
raise InvalidPortsDefinition(ports)
if end < start:
raise InvalidPortsDefinition(ports)
port_set.update(range(int(start), int(end) + 1))

return port_set
def filter_by_type(lst, type_of):
"""Returns a list of elements with given type."""
return [e for e in lst if isinstance(e, type_of)]
2 changes: 1 addition & 1 deletion tests/test_elastic.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def test_elasticsarch(elasticsearch):
assert info['status'] == 200


elasticsearch_proc_random = factories.elasticsearch_proc(port='?')
elasticsearch_proc_random = factories.elasticsearch_proc(port=None)
elasticsearch_random = factories.elasticsearch('elasticsearch_proc_random')


Expand Down
2 changes: 1 addition & 1 deletion tests/test_mongo.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def test_mongo_proc(mongo_proc, mongo_proc2, mongo_proc3):
assert path('/tmp/mongo.{port}.log'.format(port=m.port)).isfile()


mongo_proc_rand = factories.mongo_proc(port='?', params=mongo_params)
mongo_proc_rand = factories.mongo_proc(port=None, params=mongo_params)
mongodb_rand = factories.mongodb('mongo_proc_rand')


Expand Down
2 changes: 1 addition & 1 deletion tests/test_mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test_mysql_newfixture(mysql, mysql2):
cursor.close()


mysql_rand_proc = factories.mysql_proc(port='?', params='--skip-sync-frm')
mysql_rand_proc = factories.mysql_proc(port=None, params='--skip-sync-frm')
mysql_rand = factories.mysql('mysql_proc2')


Expand Down
Loading

0 comments on commit c5d6a9d

Please sign in to comment.