View | Details | Raw Unified | Return to bug 37402
Collapse All | Expand All

(-)a/branches/ucs-4.1/ucs-4.1-0/base/univention-config-registry/debian/changelog (+6 lines)
 Lines 1-3    Link Here 
1
univention-config-registry (11.0.0-2) unstable; urgency=low
2
3
  * Bug #37402: Make boolean handling more robust.
4
5
 -- Philipp Hahn <hahn@univention.de>  Wed, 21 Oct 2015 08:09:46 +0200
6
1
univention-config-registry (11.0.0-1) unstable; urgency=medium
7
univention-config-registry (11.0.0-1) unstable; urgency=medium
2
8
3
  * Bump version for UCS 4.1 (Bug #38011)
9
  * Bump version for UCS 4.1 (Bug #38011)
(-)a/branches/ucs-4.1/ucs-4.1-0/base/univention-config-registry/python/univention/config_registry/backend.py (-10 / +9 lines)
 Lines 245-265   class ConfigRegistry(dict): Link Here 
245
245
246
	def is_true(self, key=None, default=False, value=None):
246
	def is_true(self, key=None, default=False, value=None):
247
		"""Return if the strings value of key is considered as true."""
247
		"""Return if the strings value of key is considered as true."""
248
		if key:
248
		if value is None:
249
			if key in self:
249
			value = self.get(key)
250
				value = self.get(key).lower()  # pylint: disable-msg=E1103
250
			if value is None:
251
			else:
252
				return default
251
				return default
253
		return value in ('yes', 'true', '1', 'enable', 'enabled', 'on')
252
		return value.lower() in ('yes', 'true', '1', 'enable', 'enabled', 'on')
254
253
255
	def is_false(self, key=None, default=False, value=None):
254
	def is_false(self, key=None, default=False, value=None):
256
		"""Return if the strings value of key is considered as false."""
255
		"""Return if the strings value of key is considered as false."""
257
		if key:
256
		if value is None:
258
			if key in self:
257
			value = self.get(key)
259
				value = self.get(key).lower()  # pylint: disable-msg=E1103
258
			if value is None:
260
			else:
261
				return default
259
				return default
262
		return value in ('no', 'false', '0', 'disable', 'disabled', 'off')
260
		return value.lower() in ('no', 'false', '0', 'disable', 'disabled', 'off')
263
261
264
	def update(self, changes):
262
	def update(self, changes):
265
		"""
263
		"""
 Lines 281-286   class ConfigRegistry(dict): Link Here 
281
			changed[key] = (old_value, new_value)
279
			changed[key] = (old_value, new_value)
282
		return changed
280
		return changed
283
281
282
284
class _ConfigRegistry(dict):
283
class _ConfigRegistry(dict):
285
	"""
284
	"""
286
	Persistent value store.
285
	Persistent value store.
(-)a/branches/ucs-4.1/ucs-4.1-0/base/univention-config-registry/tests/test_backend.py (-14 / +13 lines)
 Lines 10-15   import time Link Here 
10
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.path.pardir, 'python'))
10
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.path.pardir, 'python'))
11
from univention.config_registry.backend import ConfigRegistry
11
from univention.config_registry.backend import ConfigRegistry
12
12
13
13
class TestConfigRegistry(unittest.TestCase):
14
class TestConfigRegistry(unittest.TestCase):
14
	"""Unit test for univention.config_registry.backend.ConfigRegistry"""
15
	"""Unit test for univention.config_registry.backend.ConfigRegistry"""
15
	def setUp(self):
16
	def setUp(self):
 Lines 219-243   class TestConfigRegistry(unittest.TestCase): Link Here 
219
		"""Test valid is_true()."""
220
		"""Test valid is_true()."""
220
		ucr = ConfigRegistry()
221
		ucr = ConfigRegistry()
221
		for ucr['foo'] in ('YES', 'yes', 'Yes', 'true', '1', 'enable', 'enabled', 'on'):
222
		for ucr['foo'] in ('YES', 'yes', 'Yes', 'true', '1', 'enable', 'enabled', 'on'):
222
			self.assertTrue(ucr.is_true('foo'))
223
			self.assertTrue(ucr.is_true('foo'), 'is_true(%(foo)r)' % ucr)
223
224
224
	def test_is_true_invalid(self):
225
	def test_is_true_invalid(self):
225
		"""Test invalid is_true()."""
226
		"""Test invalid is_true()."""
226
		ucr = ConfigRegistry()
227
		ucr = ConfigRegistry()
227
		for ucr['foo'] in ('yes ', ' yes', ''):
228
		for ucr['foo'] in ('yes ', ' yes', ''):
228
			self.assertFalse(ucr.is_true('foo'))
229
			self.assertFalse(ucr.is_true('foo'), 'is_true(%(foo)r)' % ucr)
229
230
230
	def test_is_true_valid_direct(self):
231
	def test_is_true_valid_direct(self):
231
		"""Test valid is_true(value)."""
232
		"""Test valid is_true(value)."""
232
		ucr = ConfigRegistry()
233
		ucr = ConfigRegistry()
233
		for value in ('yes', 'true', '1', 'enable', 'enabled', 'on'):
234
		for value in ('YES', 'Yes', 'yes', 'true', '1', 'enable', 'enabled', 'on'):
234
			self.assertTrue(ucr.is_true(value=value))
235
			self.assertTrue(ucr.is_true(value=value), 'is_true(v=%r)' % value)
235
236
236
	def test_is_true_invalid_direct(self):
237
	def test_is_true_invalid_direct(self):
237
		"""Test invalid is_true(value)."""
238
		"""Test invalid is_true(value)."""
238
		ucr = ConfigRegistry()
239
		ucr = ConfigRegistry()
239
		for value in ('YES', 'Yes', 'yes ', ' yes', ''):
240
		for value in ('yes ', ' yes', ''):
240
			self.assertFalse(ucr.is_true(value=value))
241
			self.assertFalse(ucr.is_true(value=value), 'is_true(v=%r)' % value)
241
242
242
	def test_is_false_unset(self):
243
	def test_is_false_unset(self):
243
		"""Test unset is_false()."""
244
		"""Test unset is_false()."""
 Lines 254-278   class TestConfigRegistry(unittest.TestCase): Link Here 
254
		"""Test valid is_false()."""
255
		"""Test valid is_false()."""
255
		ucr = ConfigRegistry()
256
		ucr = ConfigRegistry()
256
		for ucr['foo'] in ('NO', 'no', 'No', 'false', '0', 'disable', 'disabled', 'off'):
257
		for ucr['foo'] in ('NO', 'no', 'No', 'false', '0', 'disable', 'disabled', 'off'):
257
			self.assertTrue(ucr.is_false('foo'))
258
			self.assertTrue(ucr.is_false('foo'), 'is_false(%(foo)r)' % ucr)
258
259
259
	def test_is_false_invalid(self):
260
	def test_is_false_invalid(self):
260
		"""Test invalid is_false()."""
261
		"""Test invalid is_false()."""
261
		ucr = ConfigRegistry()
262
		ucr = ConfigRegistry()
262
		for ucr['foo'] in ('no ', ' no', ''):
263
		for ucr['foo'] in ('no ', ' no', ''):
263
			self.assertFalse(ucr.is_false('foo'))
264
			self.assertFalse(ucr.is_false('foo'), 'is_false(%(foo)r)' % ucr)
264
265
265
	def test_is_false_valid_direct(self):
266
	def test_is_false_valid_direct(self):
266
		"""Test valid is_false(value)."""
267
		"""Test valid is_false(value)."""
267
		ucr = ConfigRegistry()
268
		ucr = ConfigRegistry()
268
		for value in ('no', 'false', '0', 'disable', 'disabled', 'off'):
269
		for value in ('NO', 'No', 'no', 'false', '0', 'disable', 'disabled', 'off'):
269
			self.assertTrue(ucr.is_false(value=value))
270
			self.assertTrue(ucr.is_false(value=value), 'is_false(v=%r)' % value)
270
271
271
	def test_is_false_invalid_direct(self):
272
	def test_is_false_invalid_direct(self):
272
		"""Test valid is_false(value)."""
273
		"""Test valid is_false(value)."""
273
		ucr = ConfigRegistry()
274
		ucr = ConfigRegistry()
274
		for value in ('NO', 'No', 'no ', ' no', ''):
275
		for value in ('no ', ' no', ''):
275
			self.assertFalse(ucr.is_false(value=value))
276
			self.assertFalse(ucr.is_false(value=value), 'is_false(v=%r)' % value)
276
277
277
	def test_update(self):
278
	def test_update(self):
278
		"""Test update()."""
279
		"""Test update()."""
279
- 
280
  - UMC doesn't do the locking, but even with it it fails.
280
  - UMC doesn't do the locking, but even with it it fails.
281
  - moving the "assertEqual()" inside the locks makes the problem go
281
  - moving the "assertEqual()" inside the locks makes the problem go
282
    away, as then a concurrent "clear()" can not get in between.
282
    away, as then a concurrent "clear()" can not get in between.
283
--
284
.../base/univention-config-registry/debian/rules   |  1 +
283
.../base/univention-config-registry/debian/rules   |  1 +
285
.../python/univention/config_registry/backend.py   | 27 ++++----
284
.../python/univention/config_registry/backend.py   | 27 ++++----
286
.../tests/test_backend_threading.py                | 78 ++++++++++++++++++++++
285
.../tests/test_backend_threading.py                | 78 ++++++++++++++++++++++
287
3 files changed, 92 insertions(+), 14 deletions(-)
286
3 files changed, 92 insertions(+), 14 deletions(-)
288
create mode 100644 branches/ucs-4.1/ucs-4.1-0/base/univention-config-registry/tests/test_backend_threading.py
287
create mode 100644 branches/ucs-4.1/ucs-4.1-0/base/univention-config-registry/tests/test_backend_threading.py
(-)a/branches/ucs-4.1/ucs-4.1-0/base/univention-config-registry/debian/rules (+1 lines)
 Lines 50-55   override_dh_auto_test: Link Here 
50
	ucslint
50
	ucslint
51
	python tests/test_info_tools.py
51
	python tests/test_info_tools.py
52
	python tests/test_backend.py
52
	python tests/test_backend.py
53
	python tests/test_backend_threading.py
53
	python python/univention/debhelper.py
54
	python python/univention/debhelper.py
54
	python python/univention/config_registry/misc.py
55
	python python/univention/config_registry/misc.py
55
	UNIVENTION_BASECONF=tests/base.conf python python/univention/config_registry/interfaces.py
56
	UNIVENTION_BASECONF=tests/base.conf python python/univention/config_registry/interfaces.py
(-)a/branches/ucs-4.1/ucs-4.1-0/base/univention-config-registry/python/univention/config_registry/backend.py (-14 / +13 lines)
 Lines 302-316   class _ConfigRegistry(dict): Link Here 
302
302
303
	def load(self):
303
	def load(self):
304
		"""Load sub registry from file."""
304
		"""Load sub registry from file."""
305
		self.clear()
306
		import_failed = False
305
		import_failed = False
307
		try:
306
		try:
308
			reg_file = open(self.file, 'r')
307
			reg_file = open(self.file, 'r')
309
		except EnvironmentError:
308
		except EnvironmentError:
310
			import_failed = True
309
			import_failed = True
311
		else:
310
		else:
312
			if len(reg_file.readlines()) < 2:  # comment or nothing
311
			import_failed = reg_file.read() == '' and reg_file.read() == ''
313
				import_failed = True
314
312
315
		if import_failed:
313
		if import_failed:
316
			try:
314
			try:
 Lines 319-325   class _ConfigRegistry(dict): Link Here 
319
				return
317
				return
320
318
321
		reg_file.seek(0)
319
		reg_file.seek(0)
322
		for line in reg_file.readlines():
320
		new = {}
321
		for line in reg_file:
323
			line = re.sub(r'^[^:]*#.*$', "", line)
322
			line = re.sub(r'^[^:]*#.*$', "", line)
324
			if line == '':
323
			if line == '':
325
				continue
324
				continue
 Lines 327-349   class _ConfigRegistry(dict): Link Here 
327
				continue
326
				continue
328
327
329
			key, value = line.split(': ', 1)
328
			key, value = line.split(': ', 1)
330
			value = value.strip()
329
			new[key] = value.strip()
331
			if len(value) == 0:  # if variable was set without an value
332
				value = ''
333
334
			self[key] = value
335
		reg_file.close()
330
		reg_file.close()
336
331
332
		self.update(new)
333
		for key in set(self.keys()) - set(new.keys()):
334
			self.pop(key, None)
335
337
		if import_failed:
336
		if import_failed:
338
			self.__save_file(self.file)
337
			self.__save_file(self.file)
339
338
340
	def __create_base_conf(self):
339
	def __create_base_conf(self):
341
		"""Create sub registry file."""
340
		"""Create sub registry file."""
342
		if not os.path.exists(self.file):
341
		try:
343
			try:
342
			reg_file = os.open(self.file, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0644)
344
				reg_file = os.open(self.file, os.O_CREAT | os.O_RDONLY, 0644)
343
			os.close(reg_file)
345
				os.close(reg_file)
344
		except EnvironmentError as ex:
346
			except EnvironmentError:
345
			if ex.errno != errno.EEXIST:
347
				msg = "E: file '%s' does not exist and could not be created"
346
				msg = "E: file '%s' does not exist and could not be created"
348
				print >> sys.stderr, msg % (self.file,)
347
				print >> sys.stderr, msg % (self.file,)
349
				exception_occured()
348
				exception_occured()
(-)a/branches/ucs-4.1/ucs-4.1-0/base/univention-config-registry/tests/test_backend_threading.py (-1 / +78 lines)
Line 0    Link Here 
0
- 
1
#!/usr/bin/python
2
"""Unit test for univention.config_registry.backend."""
3
# pylint: disable-msg=C0103,E0611,R0904
4
import unittest
5
import os
6
import sys
7
from tempfile import mkdtemp
8
from shutil import rmtree
9
from threading import Thread, Lock
10
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.path.pardir, 'python'))
11
from univention.config_registry.backend import ConfigRegistry
12
13
14
class DummyLock(object):
15
	def __enter__(self):
16
		pass
17
18
	def __exit__(self, exc_type, exc_value, traceback):
19
		pass
20
21
22
class TestConfigRegistry(unittest.TestCase):
23
	"""Unit test for univention.config_registry.backend.ConfigRegistry"""
24
	def setUp(self):
25
		"""Create object."""
26
		self.work_dir = mkdtemp()
27
		ConfigRegistry.PREFIX = self.work_dir
28
29
	def tearDown(self):
30
		"""Destroy object."""
31
		# os.kill(os.getpid(), 19)  # signal.SIGSTOP
32
		rmtree(self.work_dir)
33
34
	def test_threading(self):
35
		"""Multiple threads accessing same registry."""
36
		DO_LOCKING = True
37
		THREADS = 10
38
		ITERATIONS = 1000
39
		BASE, PRIME = 7, 23
40
		KEY = 'x' * PRIME
41
42
		SKEY, SVALUE = 'always', 'there'
43
		ucr = ConfigRegistry()
44
		ucr[SKEY] = SVALUE
45
		ucr.save()
46
47
		lock = Lock() if DO_LOCKING else DummyLock()
48
49
		def run(tid):
50
			for iteration in xrange(ITERATIONS):
51
				i = tid + iteration
52
				random = pow(BASE, i, PRIME)
53
				key = KEY[:random + 1]
54
55
				with lock:
56
					ucr.load()
57
				self.assertEqual(ucr[SKEY], SVALUE, 'tid=%d iter=%d %r' % (tid, iteration, ucr.items()))
58
59
				try:
60
					del ucr[key]
61
				except LookupError:
62
					ucr[key] = '%d %d' % (tid, iteration)
63
				if i % 10 == 0 and tid % 10 == 0:
64
					with lock:
65
						ucr.save()
66
67
		threads = []
68
		for tid in xrange(THREADS):
69
			thread = Thread(target=run, name='%d' % tid, args=(tid,))
70
			threads.append(thread)
71
		for thread in threads:
72
			thread.start()
73
		for thread in threads:
74
			thread.join()
75
76
77
if __name__ == '__main__':
78
	unittest.main()

Return to bug 37402