1
0

test_loader.py 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355
  1. # -*- coding: utf-8 -*-
  2. '''
  3. unit.loader
  4. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  5. Test Salt's loader
  6. '''
  7. # Import Python libs
  8. from __future__ import absolute_import, print_function, unicode_literals
  9. import collections
  10. import compileall
  11. import copy
  12. import imp
  13. import inspect
  14. import logging
  15. import os
  16. import shutil
  17. import sys
  18. import tempfile
  19. import textwrap
  20. # Import Salt Testing libs
  21. from tests.support.runtime import RUNTIME_VARS
  22. from tests.support.case import ModuleCase
  23. from tests.support.unit import TestCase
  24. from tests.support.mock import patch
  25. # Import Salt libs
  26. import salt.config
  27. import salt.loader
  28. import salt.utils.files
  29. import salt.utils.stringutils
  30. # pylint: disable=import-error,no-name-in-module,redefined-builtin
  31. from salt.ext import six
  32. from salt.ext.six.moves import range
  33. # pylint: enable=no-name-in-module,redefined-builtin
  34. log = logging.getLogger(__name__)
  35. def remove_bytecode(module_path):
  36. paths = [module_path + 'c']
  37. if hasattr(imp, 'get_tag'):
  38. modname, ext = os.path.splitext(module_path.split(os.sep)[-1])
  39. paths.append(
  40. os.path.join(os.path.dirname(module_path),
  41. '__pycache__',
  42. '{}.{}.pyc'.format(modname, imp.get_tag())))
  43. for path in paths:
  44. if os.path.exists(path):
  45. os.unlink(path)
  46. loader_template = '''
  47. import os
  48. from salt.utils.decorators import depends
  49. @depends('os')
  50. def loaded():
  51. return True
  52. @depends('non_existantmodulename')
  53. def not_loaded():
  54. return True
  55. '''
  56. class LazyLoaderTest(TestCase):
  57. '''
  58. Test the loader
  59. '''
  60. module_name = 'lazyloadertest'
  61. @classmethod
  62. def setUpClass(cls):
  63. cls.opts = salt.config.minion_config(None)
  64. cls.opts['grains'] = salt.loader.grains(cls.opts)
  65. if not os.path.isdir(RUNTIME_VARS.TMP):
  66. os.makedirs(RUNTIME_VARS.TMP)
  67. cls.utils = salt.loader.utils(cls.opts)
  68. cls.proxy = salt.loader.proxy(cls.opts)
  69. cls.funcs = salt.loader.minion_mods(cls.opts, utils=cls.utils, proxy=cls.proxy)
  70. def setUp(self):
  71. # Setup the module
  72. self.module_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  73. self.addCleanup(shutil.rmtree, self.module_dir, ignore_errors=True)
  74. self.module_file = os.path.join(self.module_dir,
  75. '{0}.py'.format(self.module_name))
  76. with salt.utils.files.fopen(self.module_file, 'w') as fh:
  77. fh.write(salt.utils.stringutils.to_str(loader_template))
  78. fh.flush()
  79. os.fsync(fh.fileno())
  80. # Invoke the loader
  81. self.loader = salt.loader.LazyLoader([self.module_dir],
  82. copy.deepcopy(self.opts),
  83. pack={'__utils__': self.utils,
  84. '__salt__': self.funcs,
  85. '__proxy__': self.proxy},
  86. tag='module')
  87. def tearDown(self):
  88. del self.module_dir
  89. del self.module_file
  90. del self.loader
  91. @classmethod
  92. def tearDownClass(cls):
  93. del cls.opts
  94. del cls.funcs
  95. del cls.utils
  96. del cls.proxy
  97. def test_depends(self):
  98. '''
  99. Test that the depends decorator works properly
  100. '''
  101. # Make sure depends correctly allowed a function to load. If this
  102. # results in a KeyError, the decorator is broken.
  103. self.assertTrue(
  104. inspect.isfunction(
  105. self.loader[self.module_name + '.loaded']
  106. )
  107. )
  108. # Make sure depends correctly kept a function from loading
  109. self.assertTrue(self.module_name + '.not_loaded' not in self.loader)
  110. class LazyLoaderVirtualEnabledTest(TestCase):
  111. '''
  112. Test the base loader of salt.
  113. '''
  114. @classmethod
  115. def setUpClass(cls):
  116. cls.opts = salt.config.minion_config(None)
  117. cls.opts['disable_modules'] = ['pillar']
  118. cls.opts['grains'] = salt.loader.grains(cls.opts)
  119. cls.utils = salt.loader.utils(copy.deepcopy(cls.opts))
  120. cls.proxy = salt.loader.proxy(cls.opts)
  121. cls.funcs = salt.loader.minion_mods(cls.opts, utils=cls.utils, proxy=cls.proxy)
  122. def setUp(self):
  123. self.loader = salt.loader.LazyLoader(
  124. salt.loader._module_dirs(copy.deepcopy(self.opts), 'modules', 'module'),
  125. copy.deepcopy(self.opts),
  126. pack={'__utils__': self.utils,
  127. '__salt__': self.funcs,
  128. '__proxy__': self.proxy},
  129. tag='module')
  130. def tearDown(self):
  131. del self.loader
  132. @classmethod
  133. def tearDownClass(cls):
  134. del cls.opts
  135. del cls.funcs
  136. del cls.utils
  137. del cls.proxy
  138. def test_basic(self):
  139. '''
  140. Ensure that it only loads stuff when needed
  141. '''
  142. # make sure it starts empty
  143. self.assertEqual(self.loader._dict, {})
  144. # get something, and make sure its a func
  145. self.assertTrue(inspect.isfunction(self.loader['test.ping']))
  146. # make sure we only loaded "test" functions
  147. for key, val in six.iteritems(self.loader._dict):
  148. self.assertEqual(key.split('.', 1)[0], 'test')
  149. # make sure the depends thing worked (double check of the depends testing,
  150. # since the loader does the calling magically
  151. self.assertFalse('test.missing_func' in self.loader._dict)
  152. def test_badkey(self):
  153. with self.assertRaises(KeyError):
  154. self.loader[None] # pylint: disable=W0104
  155. with self.assertRaises(KeyError):
  156. self.loader[1] # pylint: disable=W0104
  157. def test_disable(self):
  158. self.assertNotIn('pillar.items', self.loader)
  159. def test_len_load(self):
  160. '''
  161. Since LazyLoader is a MutableMapping, if someone asks for len() we have
  162. to load all
  163. '''
  164. self.assertEqual(self.loader._dict, {})
  165. len(self.loader) # force a load all
  166. self.assertNotEqual(self.loader._dict, {})
  167. def test_iter_load(self):
  168. '''
  169. Since LazyLoader is a MutableMapping, if someone asks to iterate we have
  170. to load all
  171. '''
  172. self.assertEqual(self.loader._dict, {})
  173. # force a load all
  174. for key, func in six.iteritems(self.loader):
  175. break
  176. self.assertNotEqual(self.loader._dict, {})
  177. def test_context(self):
  178. '''
  179. Make sure context is shared across modules
  180. '''
  181. # make sure it starts empty
  182. self.assertEqual(self.loader._dict, {})
  183. # get something, and make sure its a func
  184. func = self.loader['test.ping']
  185. with patch.dict(func.__globals__['__context__'], {'foo': 'bar'}):
  186. self.assertEqual(self.loader['test.echo'].__globals__['__context__']['foo'], 'bar')
  187. self.assertEqual(self.loader['grains.get'].__globals__['__context__']['foo'], 'bar')
  188. def test_globals(self):
  189. func_globals = self.loader['test.ping'].__globals__
  190. self.assertEqual(func_globals['__grains__'], self.opts.get('grains', {}))
  191. self.assertEqual(func_globals['__pillar__'], self.opts.get('pillar', {}))
  192. # the opts passed into modules is at least a subset of the whole opts
  193. for key, val in six.iteritems(func_globals['__opts__']):
  194. if key in salt.config.DEFAULT_MASTER_OPTS and key not in salt.config.DEFAULT_MINION_OPTS:
  195. # We loaded the minion opts, but somewhere in the code, the master options got pulled in
  196. # Let's just not check for equality since the option won't even exist in the loaded
  197. # minion options
  198. continue
  199. if key not in salt.config.DEFAULT_MASTER_OPTS and key not in salt.config.DEFAULT_MINION_OPTS:
  200. # This isn't even a default configuration setting, lets carry on
  201. continue
  202. self.assertEqual(self.opts[key], val)
  203. def test_pack(self):
  204. self.loader.pack['__foo__'] = 'bar'
  205. func_globals = self.loader['test.ping'].__globals__
  206. self.assertEqual(func_globals['__foo__'], 'bar')
  207. def test_virtual(self):
  208. self.assertNotIn('test_virtual.ping', self.loader)
  209. class LazyLoaderVirtualDisabledTest(TestCase):
  210. '''
  211. Test the loader of salt without __virtual__
  212. '''
  213. @classmethod
  214. def setUpClass(cls):
  215. cls.opts = salt.config.minion_config(None)
  216. cls.opts['grains'] = salt.loader.grains(cls.opts)
  217. cls.utils = salt.loader.utils(copy.deepcopy(cls.opts))
  218. cls.proxy = salt.loader.proxy(cls.opts)
  219. cls.funcs = salt.loader.minion_mods(cls.opts, utils=cls.utils, proxy=cls.proxy)
  220. def setUp(self):
  221. self.loader = salt.loader.LazyLoader(
  222. salt.loader._module_dirs(copy.deepcopy(self.opts), 'modules', 'module'),
  223. copy.deepcopy(self.opts),
  224. tag='module',
  225. pack={'__utils__': self.utils,
  226. '__salt__': self.funcs,
  227. '__proxy__': self.proxy},
  228. virtual_enable=False)
  229. def tearDown(self):
  230. del self.loader
  231. @classmethod
  232. def tearDownClass(cls):
  233. del cls.opts
  234. del cls.utils
  235. del cls.funcs
  236. del cls.proxy
  237. def test_virtual(self):
  238. self.assertTrue(inspect.isfunction(self.loader['test_virtual.ping']))
  239. class LazyLoaderWhitelistTest(TestCase):
  240. '''
  241. Test the loader of salt with a whitelist
  242. '''
  243. @classmethod
  244. def setUpClass(cls):
  245. cls.opts = salt.config.minion_config(None)
  246. cls.opts['grains'] = salt.loader.grains(cls.opts)
  247. cls.utils = salt.loader.utils(copy.deepcopy(cls.opts))
  248. cls.proxy = salt.loader.proxy(cls.opts)
  249. cls.funcs = salt.loader.minion_mods(cls.opts, utils=cls.utils, proxy=cls.proxy)
  250. def setUp(self):
  251. self.loader = salt.loader.LazyLoader(
  252. salt.loader._module_dirs(copy.deepcopy(self.opts), 'modules', 'module'),
  253. copy.deepcopy(self.opts),
  254. tag='module',
  255. pack={'__utils__': self.utils,
  256. '__salt__': self.funcs,
  257. '__proxy__': self.proxy},
  258. whitelist=['test', 'pillar'])
  259. def tearDown(self):
  260. del self.loader
  261. @classmethod
  262. def tearDownClass(cls):
  263. del cls.opts
  264. del cls.funcs
  265. del cls.utils
  266. del cls.proxy
  267. def test_whitelist(self):
  268. self.assertTrue(inspect.isfunction(self.loader['test.ping']))
  269. self.assertTrue(inspect.isfunction(self.loader['pillar.get']))
  270. self.assertNotIn('grains.get', self.loader)
  271. class LazyLoaderGrainsBlacklistTest(TestCase):
  272. '''
  273. Test the loader of grains with a blacklist
  274. '''
  275. def setUp(self):
  276. self.opts = salt.config.minion_config(None)
  277. def tearDown(self):
  278. del self.opts
  279. def test_whitelist(self):
  280. opts = copy.deepcopy(self.opts)
  281. opts['grains_blacklist'] = [
  282. 'master',
  283. 'os*',
  284. 'ipv[46]'
  285. ]
  286. grains = salt.loader.grains(opts)
  287. self.assertNotIn('master', grains)
  288. self.assertNotIn('os', set([g[:2] for g in list(grains)]))
  289. self.assertNotIn('ipv4', grains)
  290. self.assertNotIn('ipv6', grains)
  291. class LazyLoaderSingleItem(TestCase):
  292. '''
  293. Test loading a single item via the _load() function
  294. '''
  295. @classmethod
  296. def setUpClass(cls):
  297. cls.opts = salt.config.minion_config(None)
  298. cls.opts['grains'] = salt.loader.grains(cls.opts)
  299. cls.utils = salt.loader.utils(copy.deepcopy(cls.opts))
  300. cls.proxy = salt.loader.proxy(cls.opts)
  301. cls.funcs = salt.loader.minion_mods(cls.opts, utils=cls.utils, proxy=cls.proxy)
  302. @classmethod
  303. def tearDownClass(cls):
  304. del cls.opts
  305. del cls.funcs
  306. del cls.utils
  307. del cls.proxy
  308. def setUp(self):
  309. self.loader = salt.loader.LazyLoader(
  310. salt.loader._module_dirs(copy.deepcopy(self.opts), 'modules', 'module'),
  311. copy.deepcopy(self.opts),
  312. pack={'__utils__': self.utils,
  313. '__salt__': self.funcs,
  314. '__proxy__': self.proxy},
  315. tag='module')
  316. def tearDown(self):
  317. del self.loader
  318. def test_single_item_no_dot(self):
  319. '''
  320. Checks that a KeyError is raised when the function key does not contain a '.'
  321. '''
  322. key = 'testing_no_dot'
  323. expected = "The key '{0}' should contain a '.'".format(key)
  324. with self.assertRaises(KeyError) as err:
  325. inspect.isfunction(self.loader['testing_no_dot'])
  326. result = err.exception.args[0]
  327. assert result == expected, result
  328. module_template = '''
  329. __load__ = ['test', 'test_alias']
  330. __func_alias__ = dict(test_alias='working_alias')
  331. from salt.utils.decorators import depends
  332. def test():
  333. return {count}
  334. def test_alias():
  335. return True
  336. def test2():
  337. return True
  338. @depends('non_existantmodulename')
  339. def test3():
  340. return True
  341. @depends('non_existantmodulename', fallback_function=test)
  342. def test4():
  343. return True
  344. '''
  345. class LazyLoaderReloadingTest(TestCase):
  346. '''
  347. Test the loader of salt with changing modules
  348. '''
  349. module_name = 'loadertest'
  350. module_key = 'loadertest.test'
  351. @classmethod
  352. def setUpClass(cls):
  353. cls.opts = salt.config.minion_config(None)
  354. cls.opts['grains'] = salt.loader.grains(cls.opts)
  355. if not os.path.isdir(RUNTIME_VARS.TMP):
  356. os.makedirs(RUNTIME_VARS.TMP)
  357. def setUp(self):
  358. self.tmp_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  359. self.addCleanup(shutil.rmtree, self.tmp_dir, ignore_errors=True)
  360. self.count = 0
  361. opts = copy.deepcopy(self.opts)
  362. dirs = salt.loader._module_dirs(opts, 'modules', 'module')
  363. dirs.append(self.tmp_dir)
  364. self.utils = salt.loader.utils(opts)
  365. self.proxy = salt.loader.proxy(opts)
  366. self.minion_mods = salt.loader.minion_mods(opts)
  367. self.loader = salt.loader.LazyLoader(
  368. dirs,
  369. opts,
  370. tag='module',
  371. pack={'__utils__': self.utils,
  372. '__proxy__': self.proxy,
  373. '__salt__': self.minion_mods})
  374. def tearDown(self):
  375. for attrname in ('tmp_dir', 'utils', 'proxy', 'loader', 'minion_mods', 'utils'):
  376. try:
  377. delattr(self, attrname)
  378. except AttributeError:
  379. continue
  380. @classmethod
  381. def tearDownClass(cls):
  382. del cls.opts
  383. def update_module(self):
  384. self.count += 1
  385. with salt.utils.files.fopen(self.module_path, 'wb') as fh:
  386. fh.write(
  387. salt.utils.stringutils.to_bytes(
  388. module_template.format(count=self.count)
  389. )
  390. )
  391. fh.flush()
  392. os.fsync(fh.fileno()) # flush to disk
  393. # pyc files don't like it when we change the original quickly
  394. # since the header bytes only contain the timestamp (granularity of seconds)
  395. # TODO: don't write them? Is *much* slower on re-load (~3x)
  396. # https://docs.python.org/2/library/sys.html#sys.dont_write_bytecode
  397. remove_bytecode(self.module_path)
  398. def rm_module(self):
  399. os.unlink(self.module_path)
  400. remove_bytecode(self.module_path)
  401. @property
  402. def module_path(self):
  403. return os.path.join(self.tmp_dir, '{0}.py'.format(self.module_name))
  404. def test_alias(self):
  405. '''
  406. Make sure that you can access alias-d modules
  407. '''
  408. # ensure it doesn't exist
  409. self.assertNotIn(self.module_key, self.loader)
  410. self.update_module()
  411. self.assertNotIn('{0}.test_alias'.format(self.module_name), self.loader)
  412. self.assertTrue(inspect.isfunction(self.loader['{0}.working_alias'.format(self.module_name)]))
  413. def test_clear(self):
  414. self.assertTrue(inspect.isfunction(self.loader['test.ping']))
  415. self.update_module() # write out out custom module
  416. self.loader.clear() # clear the loader dict
  417. # force a load of our module
  418. self.assertTrue(inspect.isfunction(self.loader[self.module_key]))
  419. # make sure we only loaded our custom module
  420. # which means that we did correctly refresh the file mapping
  421. for k, v in six.iteritems(self.loader._dict):
  422. self.assertTrue(k.startswith(self.module_name))
  423. def test_load(self):
  424. # ensure it doesn't exist
  425. self.assertNotIn(self.module_key, self.loader)
  426. self.update_module()
  427. self.assertTrue(inspect.isfunction(self.loader[self.module_key]))
  428. def test__load__(self):
  429. '''
  430. If a module specifies __load__ we should only load/expose those modules
  431. '''
  432. self.update_module()
  433. # ensure it doesn't exist
  434. self.assertNotIn(self.module_key + '2', self.loader)
  435. def test__load__and_depends(self):
  436. '''
  437. If a module specifies __load__ we should only load/expose those modules
  438. '''
  439. self.update_module()
  440. # ensure it doesn't exist
  441. self.assertNotIn(self.module_key + '3', self.loader)
  442. self.assertNotIn(self.module_key + '4', self.loader)
  443. def test_reload(self):
  444. # ensure it doesn't exist
  445. self.assertNotIn(self.module_key, self.loader)
  446. # make sure it updates correctly
  447. for x in range(1, 3):
  448. self.update_module()
  449. self.loader.clear()
  450. self.assertEqual(self.loader[self.module_key](), self.count)
  451. self.rm_module()
  452. # make sure that even if we remove the module, its still loaded until a clear
  453. self.assertEqual(self.loader[self.module_key](), self.count)
  454. self.loader.clear()
  455. self.assertNotIn(self.module_key, self.loader)
  456. virtual_aliases = ('loadertest2', 'loadertest3')
  457. virtual_alias_module_template = '''
  458. __virtual_aliases__ = {0}
  459. def test():
  460. return True
  461. '''.format(virtual_aliases)
  462. class LazyLoaderVirtualAliasTest(TestCase):
  463. '''
  464. Test the loader of salt with changing modules
  465. '''
  466. module_name = 'loadertest'
  467. @classmethod
  468. def setUpClass(cls):
  469. cls.opts = salt.config.minion_config(None)
  470. cls.opts['grains'] = salt.loader.grains(cls.opts)
  471. if not os.path.isdir(RUNTIME_VARS.TMP):
  472. os.makedirs(RUNTIME_VARS.TMP)
  473. def setUp(self):
  474. self.tmp_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  475. opts = copy.deepcopy(self.opts)
  476. dirs = salt.loader._module_dirs(opts, 'modules', 'module')
  477. dirs.append(self.tmp_dir)
  478. self.utils = salt.loader.utils(opts)
  479. self.proxy = salt.loader.proxy(opts)
  480. self.minion_mods = salt.loader.minion_mods(opts)
  481. self.loader = salt.loader.LazyLoader(
  482. dirs,
  483. opts,
  484. tag='module',
  485. pack={'__utils__': self.utils,
  486. '__proxy__': self.proxy,
  487. '__salt__': self.minion_mods})
  488. def tearDown(self):
  489. del self.tmp_dir
  490. del self.utils
  491. del self.proxy
  492. del self.minion_mods
  493. del self.loader
  494. @classmethod
  495. def tearDownClass(cls):
  496. del cls.opts
  497. def update_module(self):
  498. with salt.utils.files.fopen(self.module_path, 'wb') as fh:
  499. fh.write(salt.utils.stringutils.to_bytes(virtual_alias_module_template))
  500. fh.flush()
  501. os.fsync(fh.fileno()) # flush to disk
  502. # pyc files don't like it when we change the original quickly
  503. # since the header bytes only contain the timestamp (granularity of seconds)
  504. # TODO: don't write them? Is *much* slower on re-load (~3x)
  505. # https://docs.python.org/2/library/sys.html#sys.dont_write_bytecode
  506. remove_bytecode(self.module_path)
  507. @property
  508. def module_path(self):
  509. return os.path.join(self.tmp_dir, '{0}.py'.format(self.module_name))
  510. def test_virtual_alias(self):
  511. '''
  512. Test the __virtual_alias__ feature
  513. '''
  514. self.update_module()
  515. mod_names = [self.module_name] + list(virtual_aliases)
  516. for mod_name in mod_names:
  517. func_name = '.'.join((mod_name, 'test'))
  518. log.debug('Running %s (dict attribute)', func_name)
  519. self.assertTrue(self.loader[func_name]())
  520. log.debug('Running %s (loader attribute)', func_name)
  521. self.assertTrue(getattr(self.loader, mod_name).test())
  522. submodule_template = '''
  523. from __future__ import absolute_import
  524. import {0}.lib
  525. def test():
  526. return ({count}, {0}.lib.test())
  527. '''
  528. submodule_lib_template = '''
  529. def test():
  530. return {count}
  531. '''
  532. class LazyLoaderSubmodReloadingTest(TestCase):
  533. '''
  534. Test the loader of salt with changing modules
  535. '''
  536. module_name = 'loadertestsubmod'
  537. module_key = 'loadertestsubmod.test'
  538. @classmethod
  539. def setUpClass(cls):
  540. cls.opts = salt.config.minion_config(None)
  541. cls.opts['grains'] = salt.loader.grains(cls.opts)
  542. if not os.path.isdir(RUNTIME_VARS.TMP):
  543. os.makedirs(RUNTIME_VARS.TMP)
  544. def setUp(self):
  545. self.tmp_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  546. self.addCleanup(shutil.rmtree, self.tmp_dir, ignore_errors=True)
  547. os.makedirs(self.module_dir)
  548. self.count = 0
  549. self.lib_count = 0
  550. opts = copy.deepcopy(self.opts)
  551. dirs = salt.loader._module_dirs(opts, 'modules', 'module')
  552. dirs.append(self.tmp_dir)
  553. self.utils = salt.loader.utils(opts)
  554. self.proxy = salt.loader.proxy(opts)
  555. self.minion_mods = salt.loader.minion_mods(opts)
  556. self.loader = salt.loader.LazyLoader(
  557. dirs,
  558. opts,
  559. tag='module',
  560. pack={'__utils__': self.utils,
  561. '__proxy__': self.proxy,
  562. '__salt__': self.minion_mods})
  563. def tearDown(self):
  564. del self.tmp_dir
  565. del self.utils
  566. del self.proxy
  567. del self.minion_mods
  568. del self.loader
  569. @classmethod
  570. def tearDownClass(cls):
  571. del cls.opts
  572. def update_module(self):
  573. self.count += 1
  574. with salt.utils.files.fopen(self.module_path, 'wb') as fh:
  575. fh.write(
  576. salt.utils.stringutils.to_bytes(
  577. submodule_template.format(self.module_name, count=self.count)
  578. )
  579. )
  580. fh.flush()
  581. os.fsync(fh.fileno()) # flush to disk
  582. # pyc files don't like it when we change the original quickly
  583. # since the header bytes only contain the timestamp (granularity of seconds)
  584. # TODO: don't write them? Is *much* slower on re-load (~3x)
  585. # https://docs.python.org/2/library/sys.html#sys.dont_write_bytecode
  586. remove_bytecode(self.module_path)
  587. def rm_module(self):
  588. os.unlink(self.module_path)
  589. remove_bytecode(self.module_path)
  590. def update_lib(self):
  591. self.lib_count += 1
  592. for modname in list(sys.modules):
  593. if modname.startswith(self.module_name):
  594. del sys.modules[modname]
  595. with salt.utils.files.fopen(self.lib_path, 'wb') as fh:
  596. fh.write(
  597. salt.utils.stringutils.to_bytes(
  598. submodule_lib_template.format(count=self.lib_count)
  599. )
  600. )
  601. fh.flush()
  602. os.fsync(fh.fileno()) # flush to disk
  603. # pyc files don't like it when we change the original quickly
  604. # since the header bytes only contain the timestamp (granularity of seconds)
  605. # TODO: don't write them? Is *much* slower on re-load (~3x)
  606. # https://docs.python.org/2/library/sys.html#sys.dont_write_bytecode
  607. remove_bytecode(self.lib_path)
  608. def rm_lib(self):
  609. for modname in list(sys.modules):
  610. if modname.startswith(self.module_name):
  611. del sys.modules[modname]
  612. os.unlink(self.lib_path)
  613. remove_bytecode(self.lib_path)
  614. @property
  615. def module_dir(self):
  616. return os.path.join(self.tmp_dir, self.module_name)
  617. @property
  618. def module_path(self):
  619. return os.path.join(self.module_dir, '__init__.py')
  620. @property
  621. def lib_path(self):
  622. return os.path.join(self.module_dir, 'lib.py')
  623. def test_basic(self):
  624. # ensure it doesn't exist
  625. self.assertNotIn(self.module_key, self.loader)
  626. self.update_module()
  627. self.update_lib()
  628. self.loader.clear()
  629. self.assertIn(self.module_key, self.loader)
  630. def test_reload(self):
  631. # ensure it doesn't exist
  632. self.assertNotIn(self.module_key, self.loader)
  633. # update both the module and the lib
  634. for x in range(1, 3):
  635. self.update_lib()
  636. self.update_module()
  637. self.loader.clear()
  638. self.assertNotIn(self.module_key, self.loader._dict)
  639. self.assertIn(self.module_key, self.loader)
  640. self.assertEqual(self.loader[self.module_key](), (self.count, self.lib_count))
  641. # update just the module
  642. for x in range(1, 3):
  643. self.update_module()
  644. self.loader.clear()
  645. self.assertNotIn(self.module_key, self.loader._dict)
  646. self.assertIn(self.module_key, self.loader)
  647. self.assertEqual(self.loader[self.module_key](), (self.count, self.lib_count))
  648. # update just the lib
  649. for x in range(1, 3):
  650. self.update_lib()
  651. self.loader.clear()
  652. self.assertNotIn(self.module_key, self.loader._dict)
  653. self.assertIn(self.module_key, self.loader)
  654. self.assertEqual(self.loader[self.module_key](), (self.count, self.lib_count))
  655. self.rm_module()
  656. # make sure that even if we remove the module, its still loaded until a clear
  657. self.assertEqual(self.loader[self.module_key](), (self.count, self.lib_count))
  658. self.loader.clear()
  659. self.assertNotIn(self.module_key, self.loader)
  660. def test_reload_missing_lib(self):
  661. # ensure it doesn't exist
  662. self.assertNotIn(self.module_key, self.loader)
  663. # update both the module and the lib
  664. self.update_module()
  665. self.update_lib()
  666. self.loader.clear()
  667. self.assertEqual(self.loader[self.module_key](), (self.count, self.lib_count))
  668. # remove the lib, this means we should fail to load the module next time
  669. self.rm_lib()
  670. self.loader.clear()
  671. self.assertNotIn(self.module_key, self.loader)
  672. mod_template = '''
  673. def test():
  674. return ({val})
  675. '''
  676. class LazyLoaderModulePackageTest(TestCase):
  677. '''
  678. Test the loader of salt with changing modules
  679. '''
  680. module_name = 'loadertestmodpkg'
  681. module_key = 'loadertestmodpkg.test'
  682. @classmethod
  683. def setUpClass(cls):
  684. cls.opts = salt.config.minion_config(None)
  685. cls.opts['grains'] = salt.loader.grains(cls.opts)
  686. if not os.path.isdir(RUNTIME_VARS.TMP):
  687. os.makedirs(RUNTIME_VARS.TMP)
  688. cls.utils = salt.loader.utils(copy.deepcopy(cls.opts))
  689. cls.proxy = salt.loader.proxy(cls.opts)
  690. cls.funcs = salt.loader.minion_mods(cls.opts, utils=cls.utils, proxy=cls.proxy)
  691. def setUp(self):
  692. self.tmp_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  693. self.addCleanup(shutil.rmtree, self.tmp_dir, ignore_errors=True)
  694. dirs = salt.loader._module_dirs(copy.deepcopy(self.opts), 'modules', 'module')
  695. dirs.append(self.tmp_dir)
  696. self.loader = salt.loader.LazyLoader(
  697. dirs,
  698. copy.deepcopy(self.opts),
  699. pack={'__utils__': self.utils,
  700. '__salt__': self.funcs,
  701. '__proxy__': self.proxy},
  702. tag='module')
  703. def tearDown(self):
  704. del self.tmp_dir
  705. del self.loader
  706. @classmethod
  707. def tearDownClass(cls):
  708. del cls.opts
  709. del cls.funcs
  710. del cls.utils
  711. del cls.proxy
  712. def update_pyfile(self, pyfile, contents):
  713. dirname = os.path.dirname(pyfile)
  714. if not os.path.exists(dirname):
  715. os.makedirs(dirname)
  716. with salt.utils.files.fopen(pyfile, 'wb') as fh:
  717. fh.write(salt.utils.stringutils.to_bytes(contents))
  718. fh.flush()
  719. os.fsync(fh.fileno()) # flush to disk
  720. # pyc files don't like it when we change the original quickly
  721. # since the header bytes only contain the timestamp (granularity of seconds)
  722. # TODO: don't write them? Is *much* slower on re-load (~3x)
  723. # https://docs.python.org/2/library/sys.html#sys.dont_write_bytecode
  724. remove_bytecode(pyfile)
  725. def rm_pyfile(self, pyfile):
  726. os.unlink(pyfile)
  727. remove_bytecode(pyfile)
  728. def update_module(self, relative_path, contents):
  729. self.update_pyfile(os.path.join(self.tmp_dir, relative_path), contents)
  730. def rm_module(self, relative_path):
  731. self.rm_pyfile(os.path.join(self.tmp_dir, relative_path))
  732. def test_module(self):
  733. # ensure it doesn't exist
  734. self.assertNotIn('foo', self.loader)
  735. self.assertNotIn('foo.test', self.loader)
  736. self.update_module('foo.py', mod_template.format(val=1))
  737. self.loader.clear()
  738. self.assertIn('foo.test', self.loader)
  739. self.assertEqual(self.loader['foo.test'](), 1)
  740. def test_package(self):
  741. # ensure it doesn't exist
  742. self.assertNotIn('foo', self.loader)
  743. self.assertNotIn('foo.test', self.loader)
  744. self.update_module('foo/__init__.py', mod_template.format(val=2))
  745. self.loader.clear()
  746. self.assertIn('foo.test', self.loader)
  747. self.assertEqual(self.loader['foo.test'](), 2)
  748. def test_module_package_collision(self):
  749. # ensure it doesn't exist
  750. self.assertNotIn('foo', self.loader)
  751. self.assertNotIn('foo.test', self.loader)
  752. self.update_module('foo.py', mod_template.format(val=3))
  753. self.loader.clear()
  754. self.assertIn('foo.test', self.loader)
  755. self.assertEqual(self.loader['foo.test'](), 3)
  756. self.update_module('foo/__init__.py', mod_template.format(val=4))
  757. self.loader.clear()
  758. self.assertIn('foo.test', self.loader)
  759. self.assertEqual(self.loader['foo.test'](), 4)
  760. deep_init_base = '''
  761. from __future__ import absolute_import
  762. import {0}.top_lib
  763. import {0}.top_lib.mid_lib
  764. import {0}.top_lib.mid_lib.bot_lib
  765. def top():
  766. return {0}.top_lib.test()
  767. def mid():
  768. return {0}.top_lib.mid_lib.test()
  769. def bot():
  770. return {0}.top_lib.mid_lib.bot_lib.test()
  771. '''
  772. class LazyLoaderDeepSubmodReloadingTest(TestCase):
  773. module_name = 'loadertestsubmoddeep'
  774. libs = ('top_lib', 'mid_lib', 'bot_lib')
  775. @classmethod
  776. def setUpClass(cls):
  777. cls.opts = salt.config.minion_config(None)
  778. cls.opts['grains'] = salt.loader.grains(cls.opts)
  779. if not os.path.isdir(RUNTIME_VARS.TMP):
  780. os.makedirs(RUNTIME_VARS.TMP)
  781. def setUp(self):
  782. self.tmp_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  783. self.addCleanup(shutil.rmtree, self.tmp_dir, ignore_errors=True)
  784. os.makedirs(self.module_dir)
  785. self.lib_count = collections.defaultdict(int) # mapping of path -> count
  786. # bootstrap libs
  787. with salt.utils.files.fopen(os.path.join(self.module_dir, '__init__.py'), 'w') as fh:
  788. # No .decode() needed here as deep_init_base is defined as str and
  789. # not bytes.
  790. fh.write(
  791. salt.utils.stringutils.to_str(
  792. deep_init_base.format(self.module_name)
  793. )
  794. )
  795. fh.flush()
  796. os.fsync(fh.fileno()) # flush to disk
  797. self.lib_paths = {}
  798. dir_path = self.module_dir
  799. for lib_name in self.libs:
  800. dir_path = os.path.join(dir_path, lib_name)
  801. self.lib_paths[lib_name] = dir_path
  802. os.makedirs(dir_path)
  803. self.update_lib(lib_name)
  804. opts = copy.deepcopy(self.opts)
  805. dirs = salt.loader._module_dirs(opts, 'modules', 'module')
  806. dirs.append(self.tmp_dir)
  807. self.utils = salt.loader.utils(opts)
  808. self.proxy = salt.loader.proxy(opts)
  809. self.minion_mods = salt.loader.minion_mods(opts)
  810. self.loader = salt.loader.LazyLoader(
  811. dirs,
  812. copy.deepcopy(opts),
  813. tag='module',
  814. pack={'__utils__': self.utils,
  815. '__proxy__': self.proxy,
  816. '__salt__': self.minion_mods})
  817. self.assertIn('{0}.top'.format(self.module_name), self.loader)
  818. def tearDown(self):
  819. del self.tmp_dir
  820. del self.lib_paths
  821. del self.utils
  822. del self.proxy
  823. del self.minion_mods
  824. del self.loader
  825. del self.lib_count
  826. @classmethod
  827. def tearDownClass(cls):
  828. del cls.opts
  829. @property
  830. def module_dir(self):
  831. return os.path.join(self.tmp_dir, self.module_name)
  832. def update_lib(self, lib_name):
  833. for modname in list(sys.modules):
  834. if modname.startswith(self.module_name):
  835. del sys.modules[modname]
  836. path = os.path.join(self.lib_paths[lib_name], '__init__.py')
  837. self.lib_count[lib_name] += 1
  838. with salt.utils.files.fopen(path, 'wb') as fh:
  839. fh.write(
  840. salt.utils.stringutils.to_bytes(
  841. submodule_lib_template.format(count=self.lib_count[lib_name])
  842. )
  843. )
  844. fh.flush()
  845. os.fsync(fh.fileno()) # flush to disk
  846. # pyc files don't like it when we change the original quickly
  847. # since the header bytes only contain the timestamp (granularity of seconds)
  848. # TODO: don't write them? Is *much* slower on re-load (~3x)
  849. # https://docs.python.org/2/library/sys.html#sys.dont_write_bytecode
  850. remove_bytecode(path)
  851. def test_basic(self):
  852. self.assertIn('{0}.top'.format(self.module_name), self.loader)
  853. def _verify_libs(self):
  854. for lib in self.libs:
  855. self.assertEqual(self.loader['{0}.{1}'.format(self.module_name, lib.replace('_lib', ''))](),
  856. self.lib_count[lib])
  857. def test_reload(self):
  858. '''
  859. Make sure that we can reload all libraries of arbitrary depth
  860. '''
  861. self._verify_libs()
  862. # update them all
  863. for lib in self.libs:
  864. for x in range(5):
  865. self.update_lib(lib)
  866. self.loader.clear()
  867. self._verify_libs()
  868. class LoaderGlobalsTest(ModuleCase):
  869. '''
  870. Test all of the globals that the loader is responsible for adding to modules
  871. This shouldn't be done here, but should rather be done per module type (in the cases where they are used)
  872. so they can check ALL globals that they have (or should have) access to.
  873. This is intended as a shorter term way of testing these so we don't break the loader
  874. '''
  875. def _verify_globals(self, mod_dict):
  876. '''
  877. Verify that the globals listed in the doc string (from the test) are in these modules
  878. '''
  879. # find the globals
  880. global_vars = []
  881. for val in six.itervalues(mod_dict):
  882. # only find salty globals
  883. if val.__module__.startswith('salt.loaded'):
  884. if hasattr(val, '__globals__'):
  885. if hasattr(val, '__wrapped__') or '__wrapped__' in val.__globals__:
  886. global_vars.append(sys.modules[val.__module__].__dict__)
  887. else:
  888. global_vars.append(val.__globals__)
  889. # if we couldn't find any, then we have no modules -- so something is broken
  890. self.assertNotEqual(global_vars, [], msg='No modules were loaded.')
  891. # get the names of the globals you should have
  892. func_name = inspect.stack()[1][3]
  893. names = next(six.itervalues(salt.utils.yaml.safe_load(getattr(self, func_name).__doc__)))
  894. # Now, test each module!
  895. for item in global_vars:
  896. for name in names:
  897. self.assertIn(name, list(item.keys()))
  898. def test_auth(self):
  899. '''
  900. Test that auth mods have:
  901. - __pillar__
  902. - __grains__
  903. - __salt__
  904. - __context__
  905. '''
  906. self._verify_globals(salt.loader.auth(self.master_opts))
  907. def test_runners(self):
  908. '''
  909. Test that runners have:
  910. - __pillar__
  911. - __salt__
  912. - __opts__
  913. - __grains__
  914. - __context__
  915. '''
  916. self._verify_globals(salt.loader.runner(self.master_opts))
  917. def test_returners(self):
  918. '''
  919. Test that returners have:
  920. - __salt__
  921. - __opts__
  922. - __pillar__
  923. - __grains__
  924. - __context__
  925. '''
  926. self._verify_globals(salt.loader.returners(self.master_opts, {}))
  927. def test_pillars(self):
  928. '''
  929. Test that pillars have:
  930. - __salt__
  931. - __opts__
  932. - __pillar__
  933. - __grains__
  934. - __context__
  935. '''
  936. self._verify_globals(salt.loader.pillars(self.master_opts, {}))
  937. def test_tops(self):
  938. '''
  939. Test that tops have: []
  940. '''
  941. self._verify_globals(salt.loader.tops(self.master_opts))
  942. def test_outputters(self):
  943. '''
  944. Test that outputters have:
  945. - __opts__
  946. - __pillar__
  947. - __grains__
  948. - __context__
  949. '''
  950. self._verify_globals(salt.loader.outputters(self.master_opts))
  951. def test_serializers(self):
  952. '''
  953. Test that serializers have: []
  954. '''
  955. self._verify_globals(salt.loader.serializers(self.master_opts))
  956. def test_states(self):
  957. '''
  958. Test that states have:
  959. - __pillar__
  960. - __salt__
  961. - __opts__
  962. - __grains__
  963. - __context__
  964. '''
  965. opts = salt.config.minion_config(None)
  966. opts['grains'] = salt.loader.grains(opts)
  967. utils = salt.loader.utils(opts)
  968. proxy = salt.loader.proxy(opts)
  969. funcs = salt.loader.minion_mods(opts, utils=utils, proxy=proxy)
  970. self._verify_globals(salt.loader.states(opts, funcs, utils, {}, proxy=proxy))
  971. def test_renderers(self):
  972. '''
  973. Test that renderers have:
  974. - __salt__ # Execution functions (i.e. __salt__['test.echo']('foo'))
  975. - __grains__ # Grains (i.e. __grains__['os'])
  976. - __pillar__ # Pillar data (i.e. __pillar__['foo'])
  977. - __opts__ # Minion configuration options
  978. - __context__ # Context dict shared amongst all modules of the same type
  979. '''
  980. self._verify_globals(salt.loader.render(self.master_opts, {}))
  981. class RawModTest(TestCase):
  982. '''
  983. Test the interface of raw_mod
  984. '''
  985. def setUp(self):
  986. self.opts = salt.config.minion_config(None)
  987. def tearDown(self):
  988. del self.opts
  989. def test_basic(self):
  990. testmod = salt.loader.raw_mod(self.opts, 'test', None)
  991. for k, v in six.iteritems(testmod):
  992. self.assertEqual(k.split('.')[0], 'test')
  993. def test_bad_name(self):
  994. testmod = salt.loader.raw_mod(self.opts, 'module_we_do_not_have', None)
  995. self.assertEqual(testmod, {})
  996. class NetworkUtilsTestCase(ModuleCase):
  997. def test_is_private(self):
  998. mod = salt.loader.raw_mod(self.minion_opts, 'network', None)
  999. self.assertTrue(mod['network.is_private']('10.0.0.1'), True)
  1000. def test_is_loopback(self):
  1001. mod = salt.loader.raw_mod(self.minion_opts, 'network', None)
  1002. self.assertTrue(mod['network.is_loopback']('127.0.0.1'), True)
  1003. class LazyLoaderOptimizationOrderTest(TestCase):
  1004. '''
  1005. Test the optimization order priority in the loader (PY3)
  1006. '''
  1007. module_name = 'lazyloadertest'
  1008. module_content = textwrap.dedent('''\
  1009. # -*- coding: utf-8 -*-
  1010. from __future__ import absolute_import
  1011. def test():
  1012. return True
  1013. ''')
  1014. @classmethod
  1015. def setUpClass(cls):
  1016. cls.opts = salt.config.minion_config(None)
  1017. cls.opts['grains'] = salt.loader.grains(cls.opts)
  1018. cls.utils = salt.loader.utils(copy.deepcopy(cls.opts))
  1019. cls.proxy = salt.loader.proxy(cls.opts)
  1020. cls.funcs = salt.loader.minion_mods(cls.opts, utils=cls.utils, proxy=cls.proxy)
  1021. @classmethod
  1022. def tearDownClass(cls):
  1023. del cls.opts
  1024. del cls.funcs
  1025. del cls.utils
  1026. del cls.proxy
  1027. def setUp(self):
  1028. # Setup the module
  1029. self.module_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  1030. self.addCleanup(shutil.rmtree, self.module_dir, ignore_errors=True)
  1031. self.module_file = os.path.join(self.module_dir,
  1032. '{0}.py'.format(self.module_name))
  1033. def tearDown(self):
  1034. try:
  1035. delattr(self, 'loader')
  1036. except AttributeError:
  1037. pass
  1038. def _get_loader(self, order=None):
  1039. opts = copy.deepcopy(self.opts)
  1040. if order is not None:
  1041. opts['optimization_order'] = order
  1042. # Return a loader
  1043. return salt.loader.LazyLoader(
  1044. [self.module_dir],
  1045. opts,
  1046. pack={'__utils__': self.utils,
  1047. '__salt__': self.funcs,
  1048. '__proxy__': self.proxy},
  1049. tag='module')
  1050. def _get_module_filename(self):
  1051. # The act of referencing the loader entry forces the module to be
  1052. # loaded by the LazyDict.
  1053. mod_fullname = self.loader[next(iter(self.loader))].__module__
  1054. return sys.modules[mod_fullname].__file__
  1055. def _expected(self, optimize=0):
  1056. if six.PY3:
  1057. return 'lazyloadertest.cpython-{0}{1}{2}.pyc'.format(
  1058. sys.version_info[0],
  1059. sys.version_info[1],
  1060. '' if not optimize else '.opt-{0}'.format(optimize)
  1061. )
  1062. else:
  1063. return 'lazyloadertest.pyc'
  1064. def _write_module_file(self):
  1065. with salt.utils.files.fopen(self.module_file, 'w') as fh:
  1066. fh.write(self.module_content)
  1067. fh.flush()
  1068. os.fsync(fh.fileno())
  1069. def _byte_compile(self):
  1070. if salt.loader.USE_IMPORTLIB:
  1071. # Skip this check as "optimize" is unique to PY3's compileall
  1072. # module, and this will be a false error when Pylint is run on
  1073. # Python 2.
  1074. # pylint: disable=unexpected-keyword-arg
  1075. compileall.compile_file(self.module_file, quiet=1, optimize=0)
  1076. compileall.compile_file(self.module_file, quiet=1, optimize=1)
  1077. compileall.compile_file(self.module_file, quiet=1, optimize=2)
  1078. # pylint: enable=unexpected-keyword-arg
  1079. else:
  1080. compileall.compile_file(self.module_file, quiet=1)
  1081. def _test_optimization_order(self, order):
  1082. self._write_module_file()
  1083. self._byte_compile()
  1084. # Clean up the original file so that we can be assured we're only
  1085. # loading the byte-compiled files(s).
  1086. os.remove(self.module_file)
  1087. self.loader = self._get_loader(order)
  1088. filename = self._get_module_filename()
  1089. basename = os.path.basename(filename)
  1090. assert basename == self._expected(order[0]), basename
  1091. if not salt.loader.USE_IMPORTLIB:
  1092. # We are only testing multiple optimization levels on Python 3.5+
  1093. return
  1094. # Remove the file and make a new loader. We should now load the
  1095. # byte-compiled file with an optimization level matching the 2nd
  1096. # element of the order list.
  1097. os.remove(filename)
  1098. self.loader = self._get_loader(order)
  1099. filename = self._get_module_filename()
  1100. basename = os.path.basename(filename)
  1101. assert basename == self._expected(order[1]), basename
  1102. # Remove the file and make a new loader. We should now load the
  1103. # byte-compiled file with an optimization level matching the 3rd
  1104. # element of the order list.
  1105. os.remove(filename)
  1106. self.loader = self._get_loader(order)
  1107. filename = self._get_module_filename()
  1108. basename = os.path.basename(filename)
  1109. assert basename == self._expected(order[2]), basename
  1110. def test_optimization_order(self):
  1111. '''
  1112. Test the optimization_order config param
  1113. '''
  1114. self._test_optimization_order([0, 1, 2])
  1115. self._test_optimization_order([0, 2, 1])
  1116. if salt.loader.USE_IMPORTLIB:
  1117. # optimization_order only supported on Python 3.5+, earlier
  1118. # releases only support unoptimized .pyc files.
  1119. self._test_optimization_order([1, 2, 0])
  1120. self._test_optimization_order([1, 0, 2])
  1121. self._test_optimization_order([2, 0, 1])
  1122. self._test_optimization_order([2, 1, 0])
  1123. def test_load_source_file(self):
  1124. '''
  1125. Make sure that .py files are preferred over .pyc files
  1126. '''
  1127. self._write_module_file()
  1128. self._byte_compile()
  1129. self.loader = self._get_loader()
  1130. filename = self._get_module_filename()
  1131. basename = os.path.basename(filename)
  1132. expected = 'lazyloadertest.py' if six.PY3 else 'lazyloadertest.pyc'
  1133. assert basename == expected, basename