Skip to content

Commit

Permalink
Add tests for pyexasol with fingerprints and add a test which imports…
Browse files Browse the repository at this point in the history
… all python modules.
  • Loading branch information
tkilias committed Oct 31, 2023
1 parent fc742ec commit 3b05fb9
Show file tree
Hide file tree
Showing 2 changed files with 269 additions and 0 deletions.
203 changes: 203 additions & 0 deletions test_container/tests/test/standard-flavor/all/import_modules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
#!/usr/bin/env python3


from exasol_python_test_framework import udf
from exasol_python_test_framework.udf.udf_debug import UdfDebugger

class ScikitLearnTest(udf.TestCase):

def setUp(self):
self.query('create schema scikit_learn', ignore_errors=True)

def test_import_scikit_learn_bug_836(self):
self.query(udf.fixindent('''
CREATE OR REPLACE PYTHON3 SCALAR SCRIPT scikit_learn.import_scikit_learn()
EMITS (module_name VARCHAR(200000), exception_str VARCHAR(200000), status VARCHAR(10)) AS
import sys
import os
import pkgutil
import importlib
from typing import List
module_limit = 10000
error_limit = 100
excluded_modules = {
"turtle",
"py310compat",
"urllib3.contrib.socks",
"urllib3.contrib.securetransport",
"urllib3.contrib.ntlmpool",
"simplejson.ordered_dict",
"pymemcache.test",
"sagemaker.feature_store.feature_processor",
"sagemaker.remote_function.runtime_environment.spark_app",
"pyftpdlib.test",
"paramiko.win_pageant",
"pandas.core.arrays.arrow",
"msal_extensions.windows",
"msal_extensions.osx",
"msal_extensions.libsecret",
"lxml.usedoctest",
"lxml.html.usedoctest",
"lxml.html.soupparser",
"lxml.html.html5parser",
"lxml.html.ElementSoup",
"lxml.cssselect",
"jsonschema.benchmarks",
"numpy.f2py.setup",
"numpy.distutils.msvc9compiler",
"numpy.core.setup_common",
"numpy.core.setup",
"numpy.core.generate_numpy_api",
"numpy.core.cversions",
"multiprocess.popen_spawn_win32",
"msal.broker",
"joblib.externals.loky.backend.popen_loky_win32",
"ijson.backends.yajl2_cffi",
"ijson.backends.yajl2",
"ijson.backends.yajl",
"docutils.parsers",
"dateutil.tzwin",
"dateutil.tz.win",
"botocore.docs",
"boto.roboto.awsqueryrequest",
"boto.roboto.awsqueryservice",
"boto.s3.resumable_download_handler",
"boto.manage.test_manage",
"boto.gs.resumable_upload_handler",
"boto.mashups.order",
"boto.pyami.copybot",
"boto.requestlog",
"boto.gs.resumable_upload_handler",
"sagemaker.content_types",
"pyarrow.libarrow_python_flight",
"pyarrow.libarrow_python",
"pyarrow.cuda",
"numba.testing.notebook",
"numba.np.ufunc.tbbpool",
"numba.misc.gdb_print_extension",
"numba.misc.dump_style",
"martian.testing_compat3",
"llvmlite.binding.libllvmlite",
"docutils.writers.odf_odt.pygmentsformatter",
"debugpy.launcher.winapi",
"bitsets.visualize",
"aiohttp.worker",
"test.libregrtest.win_utils",
"multiprocessing.popen_spawn_win32",
"lib2to3.pgen2.conv",
"encodings.oem",
"encodings.mbcs",
"distutils.msvc9compiler",
"dbm.gnu",
"asyncio.windows_utils",
"asyncio.windows_events",
"Cython.Debugger",
"Cython.Build.Tests",
"Cython.Build.IpythonMagic",
"Cython.Coverage"
}
excluded_submodules = (
"sphinxext",
"tests",
"conftest",
)
def get_module_names(path):
modules = list(module for _, module, _ in pkgutil.iter_modules(path))
return modules
class Importer:
def __init__(
self, ctx, error_limit: int, module_limit: int,
excluded_modules: List[str], excluded_submodules: List[str]):
self.ctx = ctx
self.error_count = 0
self.module_count = 0
self.error_limit = error_limit
self.module_limit = module_limit
self.excluded_modules = excluded_modules
self.excluded_submodules = excluded_submodules
self.modules = []
def module_limit_reached(self) -> bool:
self.module_count += 1
return self.module_count > self.module_limit
def error_limit_reached(self) -> bool:
self.error_count += 1
return self.error_count > self.error_limit
def import_modules(self):
self.modules = get_module_names(sys.path)
while len(self.modules) > 0:
module = self.modules.pop()
limit_reached = self.import_module(module)
if limit_reached:
break
def add_submodules(self, module, module_import):
if hasattr(module_import,"__path__"):
submodule_names = get_module_names(module_import.__path__)
self.modules.extend([
f"{module}.{submodule}"
for submodule in submodule_names
if not submodule.startswith("_") and submodule not in self.excluded_submodules
])
def import_module(self, module: str) -> bool:
print("========================================================")
print("========================================================")
print("========================================================")
print("modules left: ", len(self.modules))
print("current module: ", module)
print("========================================================")
print("========================================================")
print("========================================================", flush=True)
if module in self.excluded_modules or module.startswith("_"):
self.ctx.emit(module, None, "SKIPPED")
return self.module_limit_reached()
try:
module_import = importlib.import_module(module)
self.ctx.emit(module, None, "OK")
self.add_submodules(module=module, module_import=module_import)
return self.module_limit_reached()
except BaseException as e:
import traceback
if hasattr(e,"msg") and e.msg == "No module named 'pytest'":
self.ctx.emit(module, None, "IGNORED")
return self.module_limit_reached()
else:
self.ctx.emit(module, traceback.format_exc(), "ERROR")
return self.error_limit_reached()
def run(ctx):
importer = Importer(
ctx=ctx,
error_limit = error_limit,
module_limit = module_limit,
excluded_modules = excluded_modules,
excluded_submodules = excluded_submodules)
importer.import_modules()
/
'''))
with UdfDebugger(test_case=self):
rows = self.query('''SELECT scikit_learn.import_scikit_learn() FROM dual''')
print("Number of modules:",len(rows))
failed_imports = [(row[0],row[1]) for row in rows if row[2] == "ERROR"]
for i in failed_imports:
print(i[0])
for i in failed_imports:
print(i[0], i[1])
self.assertEqual(failed_imports,[])


def tearDown(self):
self.query("drop schema scikit_learn cascade")


if __name__ == '__main__':
udf.main()
66 changes: 66 additions & 0 deletions test_container/tests/test/standard-flavor/all/pyexasol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env python3


from exasol_python_test_framework import udf


class PyexsolConnectionTest(udf.TestCase):
# TODO use dsn and credentials injected into the testcase
host = "localhost"
port = "8888"
user = "sys"
pwd = "exasol"

def setUp(self):
self.query('create schema pyexasol', ignore_errors=True)

def run_secure_pyexasol_connection(self, python_version):
self.query(udf.fixindent('''
CREATE OR REPLACE {python} SCALAR SCRIPT pyexasol.connect_secure() returns int AS
import pyexasol
import ssl
import os
def run(ctx):
os.environ["USER"]="exasolution"
with pyexasol.connect(
dsn='{host}:{port}', user='{user}', password='{pwd}',
websocket_sslopt={{"cert_reqs": ssl.CERT_NONE}}, encryption=True) as connection:
result_set = connection.execute('SELECT 1 FROM dual')
for row in result_set:
pass
/
'''.format(python=python_version, host=self.host, port=self.port, user=self.user, pwd=self.pwd)))
self.query('''SELECT pyexasol.connect_secure() FROM dual''')

def run_fingerprint_pyexasol_connection(self, python_version):
self.query(udf.fixindent('''
CREATE OR REPLACE {python} SCALAR SCRIPT pyexasol.connect_secure() returns VARCHAR(2000000) AS
import pyexasol
import ssl
import os
def run(ctx):
os.environ["USER"]="exasolution"
try:
with pyexasol.connect(
dsn='{host}/135a1d2dce102de866f58267521f4232153545a075dc85f8f7596f57e588a181:{port}',
user='{user}', password='{pwd}') as connection:
pass
except pyexasol.ExaConnectionFailedError as e:
return e.message
/
'''.format(python=python_version, host=self.host, port=self.port, user=self.user, pwd=self.pwd)))
rows=self.query('''SELECT pyexasol.connect_secure() FROM dual''')
self.assertRegex(rows[0][0], r"Provided fingerprint.*did not match server fingerprint")

def test_secure_pyexasol_connection_python3(self):
self.run_secure_pyexasol_connection("PYTHON3")

def test_fingerprint_pyexasol_connection_python3(self):
self.run_fingerprint_pyexasol_connection("PYTHON3")

def tearDown(self):
self.query("drop schema pyexasol cascade")


if __name__ == '__main__':
udf.main()

0 comments on commit 3b05fb9

Please sign in to comment.