diff --git a/.travis.yml b/.travis.yml index 0e7a3701..c06cab3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ -sudo: required +os: linux + +dist: bionic language: python @@ -18,14 +20,15 @@ notifications: on_failure: always env: - - PYTHON_VERSION=2 PG_VERSION=10 - - PYTHON_VERSION=2 PG_VERSION=9.6 - - PYTHON_VERSION=2 PG_VERSION=9.5 - - PYTHON_VERSION=2 PG_VERSION=9.4 + - PYTHON_VERSION=3 PG_VERSION=14 - PYTHON_VERSION=3 PG_VERSION=13 - PYTHON_VERSION=3 PG_VERSION=12 - PYTHON_VERSION=3 PG_VERSION=11 - PYTHON_VERSION=3 PG_VERSION=10 - - PYTHON_VERSION=3 PG_VERSION=9.6 - - PYTHON_VERSION=3 PG_VERSION=9.5 - - PYTHON_VERSION=3 PG_VERSION=9.4 +# - PYTHON_VERSION=3 PG_VERSION=9.6 +# - PYTHON_VERSION=3 PG_VERSION=9.5 +# - PYTHON_VERSION=3 PG_VERSION=9.4 +# - PYTHON_VERSION=2 PG_VERSION=10 +# - PYTHON_VERSION=2 PG_VERSION=9.6 +# - PYTHON_VERSION=2 PG_VERSION=9.5 +# - PYTHON_VERSION=2 PG_VERSION=9.4 diff --git a/testgres/backup.py b/testgres/backup.py index d9865c1e..a725a1df 100644 --- a/testgres/backup.py +++ b/testgres/backup.py @@ -29,7 +29,6 @@ class NodeBackup(object): """ Smart object responsible for backups """ - @property def log_file(self): return os.path.join(self.base_dir, BACKUP_LOG_FILE) diff --git a/testgres/cache.py b/testgres/cache.py index 36d6e768..c3cd9971 100644 --- a/testgres/cache.py +++ b/testgres/cache.py @@ -25,7 +25,6 @@ def cached_initdb(data_dir, logfile=None, params=None): """ Perform initdb or use cached node files. """ - def call_initdb(initdb_dir, log=None): try: _params = [get_bin_path("initdb"), "-D", initdb_dir, "-N"] diff --git a/testgres/config.py b/testgres/config.py index d1f853c0..cfcdadc2 100644 --- a/testgres/config.py +++ b/testgres/config.py @@ -43,7 +43,6 @@ class GlobalConfig(object): _cached_initdb_dir = None """ underlying class attribute for cached_initdb_dir property """ - @property def cached_initdb_dir(self): """ path to a temp directory for cached initdb. """ diff --git a/testgres/connection.py b/testgres/connection.py index ab846a14..ee2a2128 100644 --- a/testgres/connection.py +++ b/testgres/connection.py @@ -28,7 +28,6 @@ class NodeConnection(object): """ Transaction wrapper returned by Node """ - def __init__(self, node, dbname=None, @@ -42,12 +41,11 @@ def __init__(self, self._node = node - self._connection = pglib.connect( - database=dbname, - user=username, - password=password, - host=node.host, - port=node.port) + self._connection = pglib.connect(database=dbname, + user=username, + password=password, + host=node.host, + port=node.port) self._connection.autocommit = autocommit self._cursor = self.connection.cursor() diff --git a/testgres/decorators.py b/testgres/decorators.py index 2a57b83d..7f383ae7 100644 --- a/testgres/decorators.py +++ b/testgres/decorators.py @@ -50,7 +50,6 @@ def method_decorator(decorator): """ Convert a function decorator into a method decorator. """ - def _dec(func): def _wrapper(self, *args, **kwargs): @decorator diff --git a/testgres/logger.py b/testgres/logger.py index 820998a6..b4648f44 100644 --- a/testgres/logger.py +++ b/testgres/logger.py @@ -10,7 +10,6 @@ class TestgresLogger(threading.Thread): """ Helper class to implement reading from log files. """ - def __init__(self, node_name, log_file_name): threading.Thread.__init__(self) diff --git a/testgres/node.py b/testgres/node.py index 8e64da01..646a5b2f 100644 --- a/testgres/node.py +++ b/testgres/node.py @@ -91,7 +91,6 @@ class ProcessProxy(object): process: wrapped psutill.Process object ptype: instance of ProcessType """ - def __init__(self, process, ptype=None): self.process = process self.ptype = ptype or ProcessType.from_process(process) @@ -196,7 +195,6 @@ def auxiliary_processes(self): Returns a list of auxiliary processes. Each process is represented by :class:`.ProcessProxy` object. """ - def is_aux(process): return process.ptype != ProcessType.Unknown @@ -430,10 +428,9 @@ def init(self, initdb_params=None, **kwargs): """ # initialize this PostgreSQL node - cached_initdb( - data_dir=self.data_dir, - logfile=self.utils_log_file, - params=initdb_params) + cached_initdb(data_dir=self.data_dir, + logfile=self.utils_log_file, + params=initdb_params) # initialize default config files self.default_conf(**kwargs) @@ -480,8 +477,8 @@ def default_conf(self, if allow_streaming: # get auth method for host or local users def get_auth_method(t): - return next((s.split()[-1] for s in lines - if s.startswith(t)), 'trust') + return next((s.split()[-1] + for s in lines if s.startswith(t)), 'trust') # get auth methods auth_local = get_auth_method('local') @@ -760,12 +757,11 @@ def promote(self, dbname=None, username=None): if self._pg_version < '10': check_query = "SELECT pg_is_in_recovery()" - self.poll_query_until( - query=check_query, - expected=False, - dbname=dbname, - username=username, - max_attempts=0) # infinite + self.poll_query_until(query=check_query, + expected=False, + dbname=dbname, + username=username, + max_attempts=0) # infinite # node becomes master itself self._master = None @@ -884,11 +880,10 @@ def psql(self, psql_params.append(dbname) # start psql process - process = subprocess.Popen( - psql_params, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + process = subprocess.Popen(psql_params, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) # wait until it finishes and get stdout and stderr out, err = process.communicate(input=input) @@ -1043,11 +1038,10 @@ def poll_query_until(self, attempts = 0 while max_attempts == 0 or attempts < max_attempts: try: - res = self.execute( - dbname=dbname, - query=query, - username=username, - commit=commit) + res = self.execute(dbname=dbname, + query=query, + username=username, + commit=commit) if expected is None and res is None: return # done @@ -1165,8 +1159,8 @@ def set_synchronous_standbys(self, standbys): standbys = First(1, standbys) else: if isinstance(standbys, Iterable): - standbys = u", ".join( - u"\"{}\"".format(r.name) for r in standbys) + standbys = u", ".join(u"\"{}\"".format(r.name) + for r in standbys) else: raise TestgresException("Feature isn't supported in " "Postgres 9.5 and below") @@ -1195,11 +1189,10 @@ def catchup(self, dbname=None, username=None): username=username)[0][0] # yapf: disable # wait until this LSN reaches replica - self.poll_query_until( - query=wait_lsn.format(lsn), - dbname=dbname, - username=username, - max_attempts=0) # infinite + self.poll_query_until(query=wait_lsn.format(lsn), + dbname=dbname, + username=username, + max_attempts=0) # infinite except Exception as e: raise_from(CatchUpException("Failed to catch up", poll_lsn), e) @@ -1215,7 +1208,11 @@ def publish(self, name, **kwargs): """ return Publication(name=name, node=self, **kwargs) - def subscribe(self, publication, name, dbname=None, username=None, + def subscribe(self, + publication, + name, + dbname=None, + username=None, **params): """ Create subscription for logical replication diff --git a/testgres/pubsub.py b/testgres/pubsub.py index 07b83543..da85caac 100644 --- a/testgres/pubsub.py +++ b/testgres/pubsub.py @@ -77,10 +77,9 @@ def drop(self, dbname=None, username=None): """ Drop publication """ - self.node.execute( - "drop publication {}".format(self.name), - dbname=dbname, - username=username) + self.node.execute("drop publication {}".format(self.name), + dbname=dbname, + username=username) def add_tables(self, tables, dbname=None, username=None): """ @@ -94,10 +93,9 @@ def add_tables(self, tables, dbname=None, username=None): raise ValueError("Tables list is empty") query = "alter publication {} add table {}" - self.node.execute( - query.format(self.name, ", ".join(tables)), - dbname=dbname or self.dbname, - username=username or self.username) + self.node.execute(query.format(self.name, ", ".join(tables)), + dbname=dbname or self.dbname, + username=username or self.username) class Subscription(object): @@ -165,19 +163,17 @@ def refresh(self, copy_data=True, dbname=None, username=None): Disables the running subscription. """ query = "alter subscription {} refresh publication with (copy_data={})" - self.node.execute( - query.format(self.name, copy_data), - dbname=dbname, - username=username) + self.node.execute(query.format(self.name, copy_data), + dbname=dbname, + username=username) def drop(self, dbname=None, username=None): """ Drops subscription """ - self.node.execute( - "drop subscription {}".format(self.name), - dbname=dbname, - username=username) + self.node.execute("drop subscription {}".format(self.name), + dbname=dbname, + username=username) def catchup(self, username=None): """ @@ -191,7 +187,9 @@ def catchup(self, username=None): dbname=None, username=None)[0][0] # yapf: disable # create dummy xact, as LR replicates only on commit. - self.pub.node.execute(query="select txid_current()", dbname=None, username=None) + self.pub.node.execute(query="select txid_current()", + dbname=None, + username=None) query = """ select '{}'::pg_lsn - replay_lsn <= 0 from pg_catalog.pg_stat_replication where application_name = '{}' diff --git a/testgres/standby.py b/testgres/standby.py index e7ce408d..859f874e 100644 --- a/testgres/standby.py +++ b/testgres/standby.py @@ -16,14 +16,14 @@ class First: standbys (:obj:`list` of :class:`.PostgresNode`): the list of standby nodes """ - def __init__(self, sync_num, standbys): self.sync_num = sync_num self.standbys = standbys def __str__(self): - return u"{} ({})".format(self.sync_num, u", ".join( - u"\"{}\"".format(r.name) for r in self.standbys)) + return u"{} ({})".format( + self.sync_num, + u", ".join(u"\"{}\"".format(r.name) for r in self.standbys)) @six.python_2_unicode_compatible @@ -39,11 +39,11 @@ class Any: standbys (:obj:`list` of :class:`.PostgresNode`): the list of standby nodes """ - def __init__(self, sync_num, standbys): self.sync_num = sync_num self.standbys = standbys def __str__(self): - return u"ANY {} ({})".format(self.sync_num, u", ".join( - u"\"{}\"".format(r.name) for r in self.standbys)) + return u"ANY {} ({})".format( + self.sync_num, + u", ".join(u"\"{}\"".format(r.name) for r in self.standbys)) diff --git a/testgres/utils.py b/testgres/utils.py index a33f49b6..84b17a6d 100644 --- a/testgres/utils.py +++ b/testgres/utils.py @@ -67,8 +67,7 @@ def execute_utility(args, logfile=None): process = subprocess.Popen( args, # util + params stdout=buf, - stderr=subprocess.STDOUT - ) + stderr=subprocess.STDOUT) process.communicate() # get result @@ -110,8 +109,10 @@ def execute_utility(args, logfile=None): exit_code = process.returncode if exit_code: message = 'Utility exited with non-zero code' - raise ExecUtilException( - message=message, command=command, exit_code=exit_code, out=out) + raise ExecUtilException(message=message, + command=command, + exit_code=exit_code, + out=out) return out @@ -150,7 +151,6 @@ def get_pg_config(pg_config_path=None): Return output of pg_config (provided that it is installed). NOTE: this fuction caches the result by default (see GlobalConfig). """ - def cache_pg_config_data(cmd): # execute pg_config and get the output out = subprocess.check_output([cmd]).decode('utf-8') diff --git a/tests/test_simple.py b/tests/test_simple.py index 219d2f19..00a50f5b 100755 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -131,8 +131,8 @@ def test_init_unique_system_id(self): with get_new_node().init().start() as node0: id0 = node0.execute(query)[0] - with scoped_config( - cache_initdb=True, cached_initdb_unique=True) as config: + with scoped_config(cache_initdb=True, + cached_initdb_unique=True) as config: self.assertTrue(config.cache_initdb) self.assertTrue(config.cached_initdb_unique) @@ -276,8 +276,8 @@ def test_psql(self): # check feeding input node.safe_psql('create table horns (w int)') - node.safe_psql( - 'copy horns from stdin (format csv)', input=b"1\n2\n3\n\\.\n") + node.safe_psql('copy horns from stdin (format csv)', + input=b"1\n2\n3\n\\.\n") _sum = node.safe_psql('select sum(w) from horns') self.assertEqual(_sum, b'6\n') @@ -383,8 +383,8 @@ def test_backup_wrong_xlog_method(self): with get_new_node() as node: node.init(allow_streaming=True).start() - with self.assertRaises( - BackupException, msg='Invalid xlog_method "wrong"'): + with self.assertRaises(BackupException, + msg='Invalid xlog_method "wrong"'): node.backup(xlog_method='wrong') def test_pg_ctl_wait_option(self): @@ -637,8 +637,8 @@ def test_poll_query_until(self): node.poll_query_until(query='create table abc (val int)') # check None, ok - node.poll_query_until( - query='create table def()', expected=None) # returns nothing + node.poll_query_until(query='create table def()', + expected=None) # returns nothing # check 0 rows equivalent to expected=None node.poll_query_until( @@ -647,19 +647,19 @@ def test_poll_query_until(self): # check arbitrary expected value, fail with self.assertRaises(TimeoutException): - node.poll_query_until( - query='select 3', - expected=1, - max_attempts=3, - sleep_time=0.01) + node.poll_query_until(query='select 3', + expected=1, + max_attempts=3, + sleep_time=0.01) # check arbitrary expected value, ok node.poll_query_until(query='select 2', expected=2) # check timeout with self.assertRaises(TimeoutException): - node.poll_query_until( - query='select 1 > 2', max_attempts=3, sleep_time=0.01) + node.poll_query_until(query='select 1 > 2', + max_attempts=3, + sleep_time=0.01) # check ProgrammingError, fail with self.assertRaises(testgres.ProgrammingError): @@ -667,11 +667,10 @@ def test_poll_query_until(self): # check ProgrammingError, ok with self.assertRaises(TimeoutException): - node.poll_query_until( - query='dummy2', - max_attempts=3, - sleep_time=0.01, - suppress={testgres.ProgrammingError}) + node.poll_query_until(query='dummy2', + max_attempts=3, + sleep_time=0.01, + suppress={testgres.ProgrammingError}) # check 1 arg, ok node.poll_query_until('select true') @@ -732,14 +731,13 @@ def test_pgbench(self): with get_new_node().init().start() as node: # initialize pgbench DB and run benchmarks - node.pgbench_init( - scale=2, foreign_keys=True, options=['-q']).pgbench_run(time=2) + node.pgbench_init(scale=2, foreign_keys=True, + options=['-q']).pgbench_run(time=2) # run TPC-B benchmark - proc = node.pgbench( - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - options=['-T3']) + proc = node.pgbench(stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + options=['-T3']) out, _ = proc.communicate() out = out.decode('utf-8')