Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tox for unit tests #1118

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/pyodbc.pyi
Expand Up @@ -293,6 +293,9 @@ SQL_XOPEN_CLI_YEAR: int

# pyodbc-specific constants
BinaryNull: Any # to distinguish binary NULL values from char NULL values
UNICODE_SIZE: int
SQLWCHAR_SIZE: int


# module attributes
# https://www.python.org/dev/peps/pep-0249/#globals
Expand Down
Empty file added tests3/__init__.py
Empty file.
69 changes: 44 additions & 25 deletions tests3/mysqltests.py 100755 → 100644
Expand Up @@ -22,7 +22,12 @@
from decimal import Decimal
from datetime import datetime, date, time
from os.path import join, getsize, dirname, abspath, basename
from testutils import *

if __name__ != '__main__':
import pyodbc

import testutils


_TESTSTR = '0123456789-abcdefghijklmnopqrstuvwxyz-'

Expand Down Expand Up @@ -54,9 +59,14 @@ class MySqlTestCase(unittest.TestCase):
STR_FENCEPOSTS = [ _generate_test_string(size) for size in SMALL_FENCEPOST_SIZES ]
BLOB_FENCEPOSTS = STR_FENCEPOSTS + [ _generate_test_string(size) for size in LARGE_FENCEPOST_SIZES ]

def __init__(self, method_name, connection_string):
def __init__(self, method_name, connection_string=None):
unittest.TestCase.__init__(self, method_name)
self.connection_string = connection_string
if connection_string is not None:
self.connection_string = connection_string
else:
# if the connection string cannot be provided directly here, it can be
# provided in an environment variable
self.connection_string = os.environ['PYODBC_CONN_STR']

def setUp(self):
self.cnxn = pyodbc.connect(self.connection_string)
Expand Down Expand Up @@ -752,42 +762,51 @@ def main():
parser.add_argument("-v", "--verbose", action="count", default=0, help="increment test verbosity (can be used multiple times)")
parser.add_argument("-d", "--debug", action="store_true", default=False, help="print debugging items")
parser.add_argument("-t", "--test", help="run only the named test")
parser.add_argument("conn_str", nargs="*", help="connection string for MySQL")

parser.add_argument("--mysql", nargs='*', help="connection string(s) for MySQL")
# typically, the connection string is provided as the only parameter, so handle this case
parser.add_argument('conn_str', nargs='*', help="connection string for MySQL")
args = parser.parse_args()

if len(args.conn_str) > 1:
parser.error('Only one argument is allowed. Do you need quotes around the connection string?')

if not args.conn_str:
filename = basename(sys.argv[0])
assert filename.endswith('.py')
connection_string = load_setup_connection_string(filename[:-3])

if not connection_string:
parser.print_help()
raise SystemExit()
if args.mysql is not None:
connection_strings = args.mysql
elif len(args.conn_str) == 1 and args.conn_str[0]:
connection_strings = [args.conn_str[0]]
else:
connection_string = args.conn_str[0]
config_conn_string = testutils.load_setup_connection_string('mysqltests')
if config_conn_string is None:
parser.print_help()
return True # no connection string, therefore nothing to do
else:
connection_strings = [config_conn_string]

if args.verbose:
cnxn = pyodbc.connect(connection_string)
print_library_info(cnxn)
cnxn = pyodbc.connect(connection_strings[0])
testutils.print_library_info(cnxn)
cnxn.close()

suite = load_tests(MySqlTestCase, args.test, connection_string)
overall_result = True
for connection_string in connection_strings:
print(f'Running tests with connection string: {connection_string}')
suite = testutils.load_tests(MySqlTestCase, args.test, connection_string)
testRunner = unittest.TextTestRunner(verbosity=args.verbose)
result = testRunner.run(suite)
if not result.wasSuccessful():
overall_result = False

testRunner = unittest.TextTestRunner(verbosity=args.verbose)
result = testRunner.run(suite)

return result
return overall_result


if __name__ == '__main__':

# Add the build directory to the path so we're testing the latest build, not the installed version.

add_to_path()
# add the build directory to the Python path so we're testing the latest
# build, not the pip-installed version
testutils.add_to_path()

# only after setting the Python path, import the pyodbc module
import pyodbc
sys.exit(0 if main().wasSuccessful() else 1)

# run the tests
sys.exit(0 if main() else 1)
91 changes: 59 additions & 32 deletions tests3/pgtests.py 100755 → 100644
Expand Up @@ -19,11 +19,17 @@
Note: Be sure to use the "Unicode" (not the "ANSI") version of the PostgreSQL ODBC driver.
"""

import os
import sys
import uuid
import unittest
from decimal import Decimal
from testutils import *

if __name__ != '__main__':
import pyodbc

import testutils


_TESTSTR = '0123456789-abcdefghijklmnopqrstuvwxyz-'

Expand Down Expand Up @@ -59,9 +65,14 @@ class PGTestCase(unittest.TestCase):
SMALL_BYTES = bytes(SMALL_STRING, 'utf-8')
LARGE_BYTES = bytes(LARGE_STRING, 'utf-8')

def __init__(self, connection_string, ansi, method_name):
def __init__(self, method_name, connection_string=None, ansi=False):
unittest.TestCase.__init__(self, method_name)
self.connection_string = connection_string
if connection_string is not None:
self.connection_string = connection_string
else:
# if the connection string cannot be provided directly here, it can be
# provided in an environment variable
self.connection_string = os.environ['PYODBC_CONN_STR']
self.ansi = ansi

def setUp(self):
Expand Down Expand Up @@ -712,52 +723,68 @@ def main():
parser.add_argument("-v", "--verbose", action="count", default=0, help="increment test verbosity (can be used multiple times)")
parser.add_argument("-d", "--debug", action="store_true", default=False, help="print debugging items")
parser.add_argument("-t", "--test", help="run only the named test")
parser.add_argument("-a", "--ansi", help="ANSI only", default=False, action="store_true")
parser.add_argument("conn_str", nargs="*", help="connection string for PostgreSQL")

parser.add_argument("-a", "--ansi", action="store_true", default=False, help="ANSI only")
parser.add_argument("--postgresql", nargs='*', help="connection string(s) for PostgreSQL")
# typically, the connection string is provided as the only parameter, so handle this case
parser.add_argument('conn_str', nargs='*', help="connection string for PostgreSQL")
args = parser.parse_args()

if len(args.conn_str) > 1:
parser.error('Only one argument is allowed. Do you need quotes around the connection string?')

if not args.conn_str:
connection_string = load_setup_connection_string('pgtests')

if not connection_string:
parser.print_help()
raise SystemExit()
if args.postgresql is not None:
connection_strings = args.postgresql
elif len(args.conn_str) == 1 and args.conn_str[0]:
connection_strings = [args.conn_str[0]]
else:
connection_string = args.conn_str[0]
config_conn_string = testutils.load_setup_connection_string('pgtests')
if config_conn_string is None:
parser.print_help()
return True # no connection string, therefore nothing to do
else:
connection_strings = [config_conn_string]

if args.verbose:
cnxn = pyodbc.connect(connection_string, ansi=args.ansi)
print_library_info(cnxn)
cnxn = pyodbc.connect(connection_strings[0], ansi=args.ansi)
testutils.print_library_info(cnxn)
cnxn.close()

if args.test:
# Run a single test
if not args.test.startswith('test_'):
args.test = 'test_%s' % (args.test)
overall_result = True
for connection_string in connection_strings:
print(f'Running tests with connection string: {connection_string}')

s = unittest.TestSuite([ PGTestCase(connection_string, args.ansi, args.test) ])
else:
# Run all tests in the class
if args.test:
# Run a single test
if not args.test.startswith('test_'):
args.test = 'test_%s' % (args.test)

methods = [ m for m in dir(PGTestCase) if m.startswith('test_') ]
methods.sort()
s = unittest.TestSuite([ PGTestCase(connection_string, args.ansi, m) for m in methods ])
suite = unittest.TestSuite([
PGTestCase(method_name=args.test, connection_string=connection_string, ansi=args.ansi)
])
else:
# Run all tests in the class
methods = [ m for m in dir(PGTestCase) if m.startswith('test_') ]
methods.sort()
suite = unittest.TestSuite([
PGTestCase( method_name=m, connection_string=connection_string, ansi=args.ansi) for m in methods
])

testRunner = unittest.TextTestRunner(verbosity=args.verbose)
result = testRunner.run(s)
testRunner = unittest.TextTestRunner(verbosity=args.verbose)
result = testRunner.run(suite)
if not result.wasSuccessful():
overall_result = False

return result
return overall_result


if __name__ == '__main__':

# Add the build directory to the path so we're testing the latest build, not the installed version.

add_to_path()
# add the build directory to the Python path so we're testing the latest
# build, not the pip-installed version
testutils.add_to_path()

# only after setting the Python path, import the pyodbc module
import pyodbc
sys.exit(0 if main().wasSuccessful() else 1)

# run the tests
sys.exit(0 if main() else 1)
77 changes: 77 additions & 0 deletions tests3/run_tests.py
@@ -0,0 +1,77 @@
#!/usr/bin/python
import os
import sys

import testutils


def main(sqlserver=None, postgresql=None, mysql=None, verbose=0):

# there is an assumption here about where this file is located
pyodbc_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

databases = {
'SQL Server': {
'conn_strs': sqlserver or [],
'discovery_start_dir': os.path.join(pyodbc_dir, 'tests3'),
'discovery_pattern': 'sqlservertests.py',
},
'PostgreSQL': {
'conn_strs': postgresql or [],
'discovery_start_dir': os.path.join(pyodbc_dir, 'tests3'),
'discovery_pattern': 'pgtests.py',
},
'MySQL': {
'conn_strs': mysql or [],
'discovery_start_dir': os.path.join(pyodbc_dir, 'tests3'),
'discovery_pattern': 'mysqltests.py',
},
}

overall_result = True
for db_name, db_attrs in databases.items():

for db_conn_str in db_attrs['conn_strs']:
print(f'Running tests against {db_name} with connection string: {db_conn_str}')

if verbose > 0:
cnxn = pyodbc.connect(db_conn_str)
testutils.print_library_info(cnxn)
cnxn.close()

# it doesn't seem to be possible to pass test parameters into the test
# discovery process, so the connection string will have to be passed to
# the test cases via an environment variable
os.environ['PYODBC_CONN_STR'] = db_conn_str

result = testutils.discover_and_run(
top_level_dir=pyodbc_dir,
start_dir=db_attrs['discovery_start_dir'],
pattern=db_attrs['discovery_pattern'],
verbosity=verbose,
)
if not result.wasSuccessful():
overall_result = False

return overall_result


if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument("--sqlserver", nargs='*', help="connection string(s) for SQL Server")
parser.add_argument("--postgresql", nargs='*', help="connection string(s) for PostgreSQL")
parser.add_argument("--mysql", nargs='*', help="connection string(s) for MySQL")
parser.add_argument("-v", "--verbose", action="count", default=0, help="increment test verbosity (can be used multiple times)")
args = parser.parse_args()

# add the build directory to the Python path so we're testing the latest
# build, not the pip-installed version
testutils.add_to_path()

# only after setting the Python path, import the pyodbc module
import pyodbc

# run the tests
passed = main(**vars(args))
sys.exit(0 if passed else 1)