1import os 2 3import salt.config 4from tests.support.mock import patch 5from tests.support.runtests import RUNTIME_VARS 6 7try: 8 import cherrypy 9 10 HAS_CHERRYPY = True 11except ImportError: 12 HAS_CHERRYPY = False 13 14 15if HAS_CHERRYPY: 16 from tests.support.cptestcase import BaseCherryPyTestCase 17 from salt.netapi.rest_cherrypy import app 18else: 19 from tests.support.unit import TestCase, skipIf 20 21 @skipIf(HAS_CHERRYPY is False, "The CherryPy python package needs to be installed") 22 class BaseCherryPyTestCase(TestCase): 23 pass 24 25 class BaseToolsTest(BaseCherryPyTestCase): 26 pass 27 28 29class BaseRestCherryPyTest(BaseCherryPyTestCase): 30 """ 31 A base TestCase subclass for the rest_cherrypy module 32 33 This mocks all interactions with Salt-core and sets up a dummy 34 (unsubscribed) CherryPy web server. 35 """ 36 37 def __get_opts__(self): 38 return None 39 40 @classmethod 41 def setUpClass(cls): 42 master_conf = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "master") 43 cls.config = salt.config.client_config(master_conf) 44 cls.base_opts = {} 45 cls.base_opts.update(cls.config) 46 47 @classmethod 48 def tearDownClass(cls): 49 del cls.config 50 del cls.base_opts 51 52 def setUp(self): 53 # Make a local reference to the CherryPy app so we can mock attributes. 54 self.app = app 55 self.addCleanup(delattr, self, "app") 56 57 master_conf = os.path.join(RUNTIME_VARS.TMP_CONF_DIR, "master") 58 client_config = salt.config.client_config(master_conf) 59 base_opts = {} 60 base_opts.update(client_config) 61 62 base_opts.update( 63 self.__get_opts__() 64 or { 65 "external_auth": { 66 "auto": {"saltdev": ["@wheel", "@runner", ".*"]}, 67 "pam": {"saltdev": ["@wheel", "@runner", ".*"]}, 68 }, 69 "rest_cherrypy": {"port": 8000, "debug": True}, 70 } 71 ) 72 73 root, apiopts, conf = app.get_app(base_opts) 74 cherrypy.tree.mount(root, "/", conf) 75 cherrypy.server.unsubscribe() 76 cherrypy.engine.start() 77 78 # Make sure cherrypy does not memleak on its bus since it keeps 79 # adding handlers without cleaning the old ones each time we setup 80 # a new application 81 for value in cherrypy.engine.listeners.values(): 82 value.clear() 83 cherrypy.engine._priorities.clear() 84 85 self.addCleanup(cherrypy.engine.exit) 86 87 88class Root: 89 """ 90 The simplest CherryPy app needed to test individual tools 91 """ 92 93 exposed = True 94 95 _cp_config = {} 96 97 def GET(self): 98 return {"return": ["Hello world."]} 99 100 def POST(self, *args, **kwargs): 101 return {"return": [{"args": args}, {"kwargs": kwargs}]} 102 103 104if HAS_CHERRYPY: 105 106 class BaseToolsTest(BaseCherryPyTestCase): # pylint: disable=E0102 107 """ 108 A base class so tests can selectively turn individual tools on for testing 109 """ 110 111 def __get_conf__(self): 112 return { 113 "/": {"request.dispatch": cherrypy.dispatch.MethodDispatcher()}, 114 } 115 116 def __get_cp_config__(self): 117 return {} 118 119 def setUp(self): 120 root = Root() 121 patcher = patch.object(root, "_cp_config", self.__get_cp_config__()) 122 patcher.start() 123 self.addCleanup(patcher.stop) 124 125 # Make sure cherrypy does not memleak on its bus since it keeps 126 # adding handlers without cleaning the old ones each time we setup 127 # a new application 128 for value in cherrypy.engine.listeners.values(): 129 value.clear() 130 cherrypy.engine._priorities.clear() 131 132 app = cherrypy.tree.mount(root, "/", self.__get_conf__()) 133 cherrypy.server.unsubscribe() 134 cherrypy.engine.start() 135 self.addCleanup(cherrypy.engine.exit) 136