Giuseppe Lavagetto has submitted this change and it was merged.
Change subject: Add unit tests for FileConfigurationObserver
......................................................................
Add unit tests for FileConfigurationObserver
Change-Id: I526d573716ba668c9b8b7eb585daab6d9402c64e
---
M pybal/config.py
M pybal/pybal.py
M pybal/test/fixtures.py
M pybal/test/test_config.py
M tox.ini
5 files changed, 91 insertions(+), 3 deletions(-)
Approvals:
Giuseppe Lavagetto: Looks good to me, approved
diff --git a/pybal/config.py b/pybal/config.py
index 7e3a43b..3172cf6 100644
--- a/pybal/config.py
+++ b/pybal/config.py
@@ -69,7 +69,6 @@
self.lastFileStat = None
self.lastConfig = None
self.reloadTask = task.LoopingCall(self.reloadConfig)
- self.startObserving()
def startObserving(self):
"""Start (or re-start) watching the configuration file for changes."""
@@ -95,7 +94,8 @@
continue
server = ast.literal_eval(line)
host = server.pop('host')
- config[host] = server
+ config[host] = {'enabled': server['enabled'],
+ 'weight': server['weight']}
except (KeyError, SyntaxError, TypeError, ValueError) as ex:
# We catch exceptions here (rather than simply allow them to
# bubble up to FileConfigurationObserver.logError) because we
diff --git a/pybal/pybal.py b/pybal/pybal.py
old mode 100644
new mode 100755
index 0ae9df6..f39816c
--- a/pybal/pybal.py
+++ b/pybal/pybal.py
@@ -278,6 +278,7 @@
self.serverConfigUrl = configUrl
self.serverInitDeferredList = defer.Deferred()
self.configObserver = config.ConfigurationObserver.fromUrl(self,
configUrl)
+ self.configObserver.startObserving()
def __str__(self):
return "[%s]" % self.lvsservice.name
diff --git a/pybal/test/fixtures.py b/pybal/test/fixtures.py
index 1fe18e2..ab480f8 100644
--- a/pybal/test/fixtures.py
+++ b/pybal/test/fixtures.py
@@ -47,6 +47,9 @@
self.up = False
self.reason = reason
+ def onConfigUpdate(self, config):
+ self.config = config
+
class StubLVSService(object):
"""Test stub for `pybal.ipvs.LVSService`."""
diff --git a/pybal/test/test_config.py b/pybal/test/test_config.py
index 5fd9db1..2e77801 100644
--- a/pybal/test/test_config.py
+++ b/pybal/test/test_config.py
@@ -6,12 +6,13 @@
This module contains tests for `pybal.config`.
"""
-import unittest
+import mock
import tempfile
import os
import pybal
import pybal.config
+
from .fixtures import PyBalTestCase
@@ -32,3 +33,85 @@
pybal.config.ConfigurationObserver.fromUrl(None, 'dummy://'),
DummyConfigurationObserver
)
+
+
+class FileConfigurationObserverTestCase(PyBalTestCase):
+ """Test case for `pybal.config.FileConfigurationObserver`."""
+
+ def setUp(self):
+ super(FileConfigurationObserverTestCase, self).setUp()
+ self.observer = self.getObserver()
+
+ def getObserver(self, filename='file:///something/here'):
+ return pybal.config.FileConfigurationObserver(
+ self.coordinator, filename)
+
+ def testInit(self):
+ """Test `FileConfigurationObserver.__init__`"""
+ self.assertEquals(self.observer.filePath, '/something/here')
+ self.assertEquals(self.observer.reloadIntervalSeconds, 1)
+
+ @mock.patch('os.stat')
+ def testReloadConfig(self, mock_stat):
+ """Test `FileConfigurationObserver.reloadConfig`"""
+ self.observer.lastFileStat = 'WMF'
+ mock_stat.return_value = 'WMF'
+ self.observer.parseConfig = mock.MagicMock(return_value="some_config")
+ # No stat changes mean no config parsing
+ self.observer.reloadConfig()
+ mock_stat.assert_called_with('/something/here')
+ self.observer.parseConfig.assert_not_called()
+ # Stat change means we open the file and parse the configuration
+ mock_stat.reset_mock()
+ mock_stat.return_value = 'WMF!'
+ m = mock.mock_open(read_data="123")
+ with mock.patch('__builtin__.open', m, True) as mock_open:
+ self.observer.reloadConfig()
+ mock_stat.assert_called_with('/something/here')
+ mock_open.assert_called_with('/something/here', 'rt')
+ self.observer.parseConfig.assert_called_with('123')
+ self.assertEquals(self.observer.lastConfig, 'some_config')
+ self.assertEquals(self.observer.coordinator.config, 'some_config')
+
+ def testParseConfig(self):
+ """Test `FileConfigurationObserver.parseConfig`"""
+ self.observer.parseLegacyConfig =
mock.MagicMock(return_value='legacy_config')
+ self.observer.parseJsonConfig =
mock.MagicMock(return_value='json_config')
+ self.assertEquals(self.observer.parseConfig("I am legacy"),
'legacy_config')
+ self.observer.parseLegacyConfig.assert_called_with("I am legacy")
+ self.observer.configUrl += '.json'
+ self.assertEquals(self.observer.parseConfig("I am json"),
'json_config')
+ self.observer.parseJsonConfig.assert_called_with("I am json")
+
+ def testParseJsonConfig(self):
+ """Test `FileConfigurationObserver.parseJsonConfig`"""
+ json_config = """
+ {
+ "mw1200": { "enabled": true, "weight": 10 },
+ "mw1201": {"enabled": false, "weight": 1 }
+ }
+ """
+ expected_config = {'mw1200': {'enabled': True, 'weight': 10},
+ 'mw1201': {'enabled': False, 'weight': 1}}
+ self.assertEquals(self.observer.parseJsonConfig(json_config),
+ expected_config)
+ invalid_config = "{[]"
+ self.assertRaises(Exception, self.observer.parseJsonConfig,
+ invalid_config)
+
+ def testParseLegacyConfig(self):
+ """Test `FileConfigurationObserver.parseLegacyConfig`"""
+ legacy_config = """
+{'host': 'mw1200', 'weight': 10, 'enabled': True }
+{'host': 'mw1201', 'weight': 1, 'enabled': False }
+ """
+ expected_config = {'mw1200': {'enabled': True, 'weight': 10},
+ 'mw1201': {'enabled': False, 'weight': 1}}
+ self.assertEquals(self.observer.parseLegacyConfig(legacy_config),
+ expected_config)
+ invalid_config="""
+{'host': 'something'}
+ """
+ # Needed for nose to pass... it doesn't really get raised
+ self.assertEquals(self.observer.parseLegacyConfig(invalid_config), {})
+ self.flushLoggedErrors(KeyError)
diff --git a/tox.ini b/tox.ini
index e20b77e..6d034ee 100644
--- a/tox.ini
+++ b/tox.ini
@@ -5,6 +5,7 @@
commands = trial pybal
deps =
twisted
+ mock
[testenv:cover]
commands =
--
To view, visit https://gerrit.wikimedia.org/r/234008
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I526d573716ba668c9b8b7eb585daab6d9402c64e
Gerrit-PatchSet: 2
Gerrit-Project: operations/debs/pybal
Gerrit-Branch: master
Gerrit-Owner: Giuseppe Lavagetto <[email protected]>
Gerrit-Reviewer: Giuseppe Lavagetto <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits