-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tests for pyexasol with fingerprints and add a test which imports…
… all python modules.
- Loading branch information
Showing
2 changed files
with
269 additions
and
0 deletions.
There are no files selected for viewing
203 changes: 203 additions & 0 deletions
203
test_container/tests/test/standard-flavor/all/import_modules.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |