]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/tests/__init__.py
import quincy beta 17.1.0
[ceph.git] / ceph / src / pybind / mgr / tests / __init__.py
CommitLineData
9f95a23c 1# type: ignore
9f95a23c 2
f6b5b4d7
TL
3import json
4import logging
9f95a23c
TL
5import os
6
7if 'UNITTEST' in os.environ:
8
9 # Mock ceph_module. Otherwise every module that is involved in a testcase and imports it will
10 # raise an ImportError
11
12 import sys
13
14 try:
15 from unittest import mock
16 except ImportError:
17 import mock
18
e306af50
TL
19 M_classes = set()
20
9f95a23c 21 class M(object):
f6b5b4d7
TL
22 """
23 Note that:
e306af50 24
f6b5b4d7
TL
25 * self.set_store() populates self._store
26 * self.set_module_option() populates self._store[module_name]
27 * self.get(thing) comes from self._store['_ceph_get' + thing]
28
29 """
30
31 def mock_store_get(self, kind, key, default):
32 if not hasattr(self, '_store'):
33 self._store = {}
34 return self._store.get(f'mock_store/{kind}/{key}', default)
35
36 def mock_store_set(self, kind, key, value):
37 if not hasattr(self, '_store'):
38 self._store = {}
39 k = f'mock_store/{kind}/{key}'
40 if value is None:
e306af50
TL
41 if k in self._store:
42 del self._store[k]
43 else:
f6b5b4d7 44 self._store[k] = value
e306af50 45
522d829b 46 def mock_store_prefix(self, kind, prefix):
f6b5b4d7
TL
47 if not hasattr(self, '_store'):
48 self._store = {}
49 full_prefix = f'mock_store/{kind}/{prefix}'
50 kind_len = len(f'mock_store/{kind}/')
e306af50 51 return {
f6b5b4d7
TL
52 k[kind_len:]: v for k, v in self._store.items()
53 if k.startswith(full_prefix)
e306af50
TL
54 }
55
f6b5b4d7
TL
56 def _ceph_get_store(self, k):
57 return self.mock_store_get('store', k, None)
58
59 def _ceph_set_store(self, k, v):
60 self.mock_store_set('store', k, v)
61
62 def _ceph_get_store_prefix(self, prefix):
522d829b 63 return self.mock_store_prefix('store', prefix)
f6b5b4d7
TL
64
65 def _ceph_get_module_option(self, module, key, localized_prefix= None):
66 try:
67 _, val, _ = self.check_mon_command({
68 'prefix': 'config get',
69 'who': 'mgr',
70 'key': f'mgr/{module}/{key}'
71 })
72 except FileNotFoundError:
73 val = None
74 mo = [o for o in self.MODULE_OPTIONS if o['name'] == key]
f67539c2
TL
75 if len(mo) >= 1: # >= 1, cause self.MODULE_OPTIONS. otherwise it
76 # fails when importing multiple modules.
77 if 'default' in mo and val is None:
78 val = mo[0]['default']
f91f0fd5
TL
79 if val is not None:
80 cls = {
81 'str': str,
82 'secs': int,
83 'bool': lambda s: bool(s) and s != 'false' and s != 'False',
84 'int': int,
85 }[mo[0].get('type', 'str')]
86 return cls(val)
87 return val
88 else:
89 return val if val is not None else ''
e306af50
TL
90
91 def _ceph_set_module_option(self, module, key, val):
f6b5b4d7
TL
92 _, _, _ = self.check_mon_command({
93 'prefix': 'config set',
94 'who': 'mgr',
95 'name': f'mgr/{module}/{key}',
96 'value': val
97 })
98 return val
99
100 def _ceph_get(self, data_name):
101 return self.mock_store_get('_ceph_get', data_name, mock.MagicMock())
102
cd265ab1 103 def _ceph_send_command(self, res, svc_type, svc_id, command, tag, inbuf):
f67539c2 104
f6b5b4d7 105 cmd = json.loads(command)
f67539c2 106 getattr(self, '_mon_commands_sent', []).append(cmd)
f6b5b4d7
TL
107
108 # Mocking the config store is handy sometimes:
109 def config_get():
110 who = cmd['who'].split('.')
111 whos = ['global'] + ['.'.join(who[:i+1]) for i in range(len(who))]
112 for attepmt in reversed(whos):
113 val = self.mock_store_get('config', f'{attepmt}/{cmd["key"]}', None)
114 if val is not None:
115 return val
116 return None
117
118 def config_set():
119 self.mock_store_set('config', f'{cmd["who"]}/{cmd["name"]}', cmd['value'])
120 return ''
121
f67539c2
TL
122 def config_rm():
123 self.mock_store_set('config', f'{cmd["who"]}/{cmd["name"]}', None)
124 return ''
125
f6b5b4d7
TL
126 def config_dump():
127 r = []
522d829b 128 for prefix, value in self.mock_store_prefix('config', '').items():
f6b5b4d7
TL
129 section, name = prefix.split('/', 1)
130 r.append({
131 'name': name,
132 'section': section,
133 'value': value
134 })
135 return json.dumps(r)
136
137 outb = ''
138 if cmd['prefix'] == 'config get':
139 outb = config_get()
140 elif cmd['prefix'] == 'config set':
141 outb = config_set()
142 elif cmd['prefix'] == 'config dump':
143 outb = config_dump()
f67539c2
TL
144 elif cmd['prefix'] == 'config rm':
145 outb = config_rm()
f6b5b4d7
TL
146 elif hasattr(self, '_mon_command_mock_' + cmd['prefix'].replace(' ', '_')):
147 a = getattr(self, '_mon_command_mock_' + cmd['prefix'].replace(' ', '_'))
148 outb = a(cmd)
149
150 res.complete(0, outb, '')
151
f67539c2
TL
152 def _ceph_get_foreign_option(self, entity, name):
153 who = entity.split('.')
154 whos = ['global'] + ['.'.join(who[:i+1]) for i in range(len(who))]
155 for attepmt in reversed(whos):
156 val = self.mock_store_get('config', f'{attepmt}/{name}', None)
157 if val is not None:
158 return val
159 return None
160
161 def assert_issued_mon_command(self, command):
162 assert command in self._mon_commands_sent, self._mon_commands_sent
163
f6b5b4d7
TL
164 @property
165 def _logger(self):
166 return logging.getLogger(__name__)
167
168 @_logger.setter
169 def _logger(self, _):
170 pass
e306af50 171
9f95a23c 172 def __init__(self, *args):
f67539c2 173 self._mon_commands_sent = []
f6b5b4d7
TL
174 if not hasattr(self, '_store'):
175 self._store = {}
176
e306af50 177
a4b75251 178 if self.__class__ not in M_classes:
cd265ab1 179 # call those only once.
e306af50
TL
180 self._register_commands('')
181 self._register_options('')
a4b75251 182 M_classes.add(self.__class__)
e306af50 183
9f95a23c
TL
184 super(M, self).__init__()
185 self._ceph_get_version = mock.Mock()
b3b6e05e 186 self._ceph_get_ceph_conf_path = mock.MagicMock()
9f95a23c 187 self._ceph_get_option = mock.MagicMock()
e306af50
TL
188 self._ceph_get_context = mock.MagicMock()
189 self._ceph_register_client = mock.MagicMock()
f6b5b4d7 190 self._ceph_set_health_checks = mock.MagicMock()
9f95a23c
TL
191 self._configure_logging = lambda *_: None
192 self._unconfigure_logging = mock.MagicMock()
193 self._ceph_log = mock.MagicMock()
9f95a23c 194 self._ceph_dispatch_remote = lambda *_: None
f91f0fd5 195 self._ceph_get_mgr_id = mock.MagicMock()
9f95a23c
TL
196
197
198 cm = mock.Mock()
199 cm.BaseMgrModule = M
200 cm.BaseMgrStandbyModule = M
201 sys.modules['ceph_module'] = cm
e306af50
TL
202
203 def mock_ceph_modules():
204 class MockRadosError(Exception):
205 def __init__(self, message, errno=None):
206 super(MockRadosError, self).__init__(message)
207 self.errno = errno
208
209 def __str__(self):
210 msg = super(MockRadosError, self).__str__()
211 if self.errno is None:
212 return msg
213 return '[errno {0}] {1}'.format(self.errno, msg)
214
a4b75251
TL
215 class MockObjectNotFound(Exception):
216 pass
e306af50
TL
217
218 sys.modules.update({
a4b75251
TL
219 'rados': mock.MagicMock(
220 Error=MockRadosError,
221 OSError=MockRadosError,
222 ObjectNotFound=MockObjectNotFound),
e306af50
TL
223 'rbd': mock.Mock(),
224 'cephfs': mock.Mock(),
f67539c2
TL
225 })
226
227 # Unconditionally mock the rados objects when we're imported
228 mock_ceph_modules() # type: ignore