test_loader.py (salt-3002.1) | : | test_loader.py (salt-3002.2) | ||
---|---|---|---|---|
""" | """ | |||
unit.loader | unit.loader | |||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
Test Salt's loader | Test Salt's loader | |||
""" | """ | |||
import collections | import collections | |||
import compileall | import compileall | |||
import copy | import copy | |||
import gc | ||||
import imp | import imp | |||
import inspect | import inspect | |||
import logging | import logging | |||
import os | import os | |||
import shutil | import shutil | |||
import sys | import sys | |||
import tempfile | import tempfile | |||
import textwrap | import textwrap | |||
import salt.config | import salt.config | |||
skipping to change at line 1227 | skipping to change at line 1226 | |||
Tests when using multiple lazyloaders | Tests when using multiple lazyloaders | |||
""" | """ | |||
def setUp(self): | def setUp(self): | |||
opts = salt.config.minion_config(None) | opts = salt.config.minion_config(None) | |||
self.loader1 = salt.loader.LazyLoader( | self.loader1 = salt.loader.LazyLoader( | |||
salt.loader._module_dirs(copy.deepcopy(opts), "modules", "module"), | salt.loader._module_dirs(copy.deepcopy(opts), "modules", "module"), | |||
copy.deepcopy(opts), | copy.deepcopy(opts), | |||
pack={}, | pack={}, | |||
tag="module", | tag="module", | |||
loaded_base_name="salt.loader1", | ||||
) | ) | |||
self.loader2 = salt.loader.LazyLoader( | self.loader2 = salt.loader.LazyLoader( | |||
salt.loader._module_dirs(copy.deepcopy(opts), "modules", "module"), | salt.loader._module_dirs(copy.deepcopy(opts), "modules", "module"), | |||
copy.deepcopy(opts), | copy.deepcopy(opts), | |||
pack={}, | pack={}, | |||
tag="module", | tag="module", | |||
loaded_base_name="salt.loader2", | ||||
) | ) | |||
def tearDown(self): | def tearDown(self): | |||
del self.loader1 | del self.loader1 | |||
del self.loader2 | del self.loader2 | |||
def test_loader_globals(self): | def test_loader_globals(self): | |||
""" | """ | |||
Test to ensure loaders do not edit | Test to ensure loaders do not edit | |||
each others loader's namespace | each others loader's namespace | |||
skipping to change at line 1265 | skipping to change at line 1266 | |||
Tests the loader cleanup procedures | Tests the loader cleanup procedures | |||
""" | """ | |||
def setUp(self): | def setUp(self): | |||
opts = salt.config.minion_config(None) | opts = salt.config.minion_config(None) | |||
self.loader1 = salt.loader.LazyLoader( | self.loader1 = salt.loader.LazyLoader( | |||
salt.loader._module_dirs(copy.deepcopy(opts), "modules", "module"), | salt.loader._module_dirs(copy.deepcopy(opts), "modules", "module"), | |||
copy.deepcopy(opts), | copy.deepcopy(opts), | |||
pack={}, | pack={}, | |||
tag="module", | tag="module", | |||
loaded_base_name="salt.test", | ||||
) | ) | |||
def tearDown(self): | def tearDown(self): | |||
del self.loader1 | del self.loader1 | |||
def test_loader_gc_cleanup(self): | ||||
loaded_base_name = self.loader1.loaded_base_name | ||||
for name in list(sys.modules): | ||||
if name.startswith(loaded_base_name): | ||||
break | ||||
else: | ||||
self.fail( | ||||
"Did not find any modules in sys.modules matching {!r}".format( | ||||
loaded_base_name | ||||
) | ||||
) | ||||
# Assert that the weakref.finalizer is alive | ||||
assert self.loader1._gc_finalizer.alive is True | ||||
gc.collect() | ||||
# Even after a gc.collect call, we should still have our module in sys.m | ||||
odules | ||||
for name in list(sys.modules): | ||||
if name.startswith(loaded_base_name): | ||||
if sys.modules[name] is None: | ||||
self.fail( | ||||
"Found at least one module in sys.modules matching {!r} | ||||
prematurely set to None".format( | ||||
loaded_base_name | ||||
) | ||||
) | ||||
break | ||||
else: | ||||
self.fail( | ||||
"Did not find any modules in sys.modules matching {!r}".format( | ||||
loaded_base_name | ||||
) | ||||
) | ||||
# Should still be true because there's still at least one reference to s | ||||
elf.loader1 | ||||
assert self.loader1._gc_finalizer.alive is True | ||||
# Now we remove our refence to loader and trigger GC, thus triggering th | ||||
e loader weakref finalizer | ||||
self.loader1 = None | ||||
gc.collect() | ||||
for name in list(sys.modules): | ||||
if name.startswith(loaded_base_name): | ||||
if sys.modules[name] is not None: | ||||
self.fail( | ||||
"Found a real module reference in sys.modules matching { | ||||
!r}.".format( | ||||
loaded_base_name, | ||||
) | ||||
) | ||||
break | ||||
else: | ||||
self.fail( | ||||
"Did not find any modules in sys.modules matching {!r}".format( | ||||
loaded_base_name | ||||
) | ||||
) | ||||
def test_loader_clean_modules(self): | def test_loader_clean_modules(self): | |||
loaded_base_name = self.loader1.loaded_base_name | loaded_base_name = self.loader1.loaded_base_name | |||
self.loader1.clean_modules() | self.loader1.clean_modules() | |||
for name in list(sys.modules): | for name in list(sys.modules): | |||
if name.startswith(loaded_base_name): | if name.startswith(loaded_base_name): | |||
self.fail( | self.fail( | |||
"Found a real module reference in sys.modules matching {!r}" .format( | "Found a real module reference in sys.modules matching {!r}" .format( | |||
loaded_base_name | loaded_base_name | |||
) | ) | |||
) | ) | |||
break | break | |||
# Additionally, assert that the weakref.finalizer is now dead | ||||
assert self.loader1._gc_finalizer.alive is False | ||||
class LoaderGlobalsTest(ModuleCase): | class LoaderGlobalsTest(ModuleCase): | |||
""" | """ | |||
Test all of the globals that the loader is responsible for adding to modules | Test all of the globals that the loader is responsible for adding to modules | |||
This shouldn't be done here, but should rather be done per module type (in t he cases where they are used) | This shouldn't be done here, but should rather be done per module type (in t he cases where they are used) | |||
so they can check ALL globals that they have (or should have) access to. | so they can check ALL globals that they have (or should have) access to. | |||
This is intended as a shorter term way of testing these so we don't break th e loader | This is intended as a shorter term way of testing these so we don't break th e loader | |||
""" | """ | |||
skipping to change at line 1586 | skipping to change at line 1530 | |||
"" if not optimize else ".opt-{}".format(optimize), | "" if not optimize else ".opt-{}".format(optimize), | |||
) | ) | |||
def _write_module_file(self): | def _write_module_file(self): | |||
with salt.utils.files.fopen(self.module_file, "w") as fh: | with salt.utils.files.fopen(self.module_file, "w") as fh: | |||
fh.write(self.module_content) | fh.write(self.module_content) | |||
fh.flush() | fh.flush() | |||
os.fsync(fh.fileno()) | os.fsync(fh.fileno()) | |||
def _byte_compile(self): | def _byte_compile(self): | |||
if salt.loader.USE_IMPORTLIB: | compileall.compile_file(self.module_file, quiet=1, optimize=0) | |||
# Skip this check as "optimize" is unique to PY3's compileall | compileall.compile_file(self.module_file, quiet=1, optimize=1) | |||
# module, and this will be a false error when Pylint is run on | compileall.compile_file(self.module_file, quiet=1, optimize=2) | |||
# Python 2. | ||||
# pylint: disable=unexpected-keyword-arg | ||||
compileall.compile_file(self.module_file, quiet=1, optimize=0) | ||||
compileall.compile_file(self.module_file, quiet=1, optimize=1) | ||||
compileall.compile_file(self.module_file, quiet=1, optimize=2) | ||||
# pylint: enable=unexpected-keyword-arg | ||||
else: | ||||
compileall.compile_file(self.module_file, quiet=1) | ||||
def _test_optimization_order(self, order): | def _test_optimization_order(self, order): | |||
self._write_module_file() | self._write_module_file() | |||
self._byte_compile() | self._byte_compile() | |||
# Clean up the original file so that we can be assured we're only | # Clean up the original file so that we can be assured we're only | |||
# loading the byte-compiled files(s). | # loading the byte-compiled files(s). | |||
os.remove(self.module_file) | os.remove(self.module_file) | |||
self.loader = self._get_loader(order) | self.loader = self._get_loader(order) | |||
filename = self._get_module_filename() | filename = self._get_module_filename() | |||
basename = os.path.basename(filename) | basename = os.path.basename(filename) | |||
assert basename == self._expected(order[0]), basename | assert basename == self._expected(order[0]), basename | |||
if not salt.loader.USE_IMPORTLIB: | ||||
# We are only testing multiple optimization levels on Python 3.5+ | ||||
return | ||||
# Remove the file and make a new loader. We should now load the | # Remove the file and make a new loader. We should now load the | |||
# byte-compiled file with an optimization level matching the 2nd | # byte-compiled file with an optimization level matching the 2nd | |||
# element of the order list. | # element of the order list. | |||
os.remove(filename) | os.remove(filename) | |||
self.loader = self._get_loader(order) | self.loader = self._get_loader(order) | |||
filename = self._get_module_filename() | filename = self._get_module_filename() | |||
basename = os.path.basename(filename) | basename = os.path.basename(filename) | |||
assert basename == self._expected(order[1]), basename | assert basename == self._expected(order[1]), basename | |||
# Remove the file and make a new loader. We should now load the | # Remove the file and make a new loader. We should now load the | |||
skipping to change at line 1639 | skipping to change at line 1571 | |||
filename = self._get_module_filename() | filename = self._get_module_filename() | |||
basename = os.path.basename(filename) | basename = os.path.basename(filename) | |||
assert basename == self._expected(order[2]), basename | assert basename == self._expected(order[2]), basename | |||
def test_optimization_order(self): | def test_optimization_order(self): | |||
""" | """ | |||
Test the optimization_order config param | Test the optimization_order config param | |||
""" | """ | |||
self._test_optimization_order([0, 1, 2]) | self._test_optimization_order([0, 1, 2]) | |||
self._test_optimization_order([0, 2, 1]) | self._test_optimization_order([0, 2, 1]) | |||
if salt.loader.USE_IMPORTLIB: | self._test_optimization_order([1, 2, 0]) | |||
# optimization_order only supported on Python 3.5+, earlier | self._test_optimization_order([1, 0, 2]) | |||
# releases only support unoptimized .pyc files. | self._test_optimization_order([2, 0, 1]) | |||
self._test_optimization_order([1, 2, 0]) | self._test_optimization_order([2, 1, 0]) | |||
self._test_optimization_order([1, 0, 2]) | ||||
self._test_optimization_order([2, 0, 1]) | ||||
self._test_optimization_order([2, 1, 0]) | ||||
def test_load_source_file(self): | def test_load_source_file(self): | |||
""" | """ | |||
Make sure that .py files are preferred over .pyc files | Make sure that .py files are preferred over .pyc files | |||
""" | """ | |||
self._write_module_file() | self._write_module_file() | |||
self._byte_compile() | self._byte_compile() | |||
self.loader = self._get_loader() | self.loader = self._get_loader() | |||
filename = self._get_module_filename() | filename = self._get_module_filename() | |||
basename = os.path.basename(filename) | basename = os.path.basename(filename) | |||
End of changes. 9 change blocks. | ||||
86 lines changed or deleted | 10 lines changed or added |