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