/provd/devices/tests/test_ident.py
Python | 362 lines | 258 code | 89 blank | 15 comment | 5 complexity | 558b63b9256d3b12d6df18f08d7456d2 MD5 | raw file
- # -*- coding: utf-8 -*-
- # Copyright (C) 2010-2016 Avencall
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>
- from hamcrest import assert_that, equal_to, has_entry
- from mock import Mock, patch
- from twisted.internet import defer
- from twisted.trial import unittest
- from provd.devices import ident
- from provd.devices.ident import LastSeenUpdater, VotingUpdater, _RequestHelper, \
- RemoveOutdatedIpDeviceUpdater, AddDeviceRetriever
- class TestAddDeviceRetriever(unittest.TestCase):
- def setUp(self):
- self.app = Mock()
- self.dev_retriever = AddDeviceRetriever(self.app)
- @patch('provd.devices.ident.log_security_msg')
- @defer.inlineCallbacks
- def test_retrieve_log_security_event(self, mock_log_security_msg):
- device_id = u'some-id'
- device_ip = u'169.254.1.1'
- dev_info = {
- u'ip': device_ip,
- }
- self.app.dev_insert.return_value = defer.succeed(device_id)
- device = yield self.dev_retriever.retrieve(dev_info)
- mock_log_security_msg.assert_called_once_with('New device created automatically from %s: %s', device_ip,
- device_id)
- expected_device = dict(dev_info)
- expected_device[u'added'] = u'auto'
- assert_that(device, equal_to(expected_device))
- class TestLastSeenUpdater(unittest.TestCase):
- def setUp(self):
- self.updater = LastSeenUpdater()
- def test_last_seen_updater_set_on_conflict(self):
- dev_infos = [
- {'k1': 'v1'},
- {'k1': 'v2'},
- ]
- for dev_info in dev_infos:
- self.updater.update(dev_info)
- self.assertEqual(self.updater.dev_info, {'k1': 'v2'})
- def test_last_seen_updater_noop_on_nonconflict(self):
- dev_infos = [
- {'k1': 'v1'},
- {'k2': 'v2'},
- ]
- for dev_info in dev_infos:
- self.updater.update(dev_info)
- self.assertEqual(self.updater.dev_info, {'k1': 'v1', 'k2': 'v2'})
- class TestVotingUpdater(unittest.TestCase):
- def setUp(self):
- self.updater = VotingUpdater()
- def test_voting_updater_votes_for_only_if_only_one(self):
- dev_infos = [
- {'k1': 'v1'},
- ]
- for dev_info in dev_infos:
- self.updater.update(dev_info)
- self.assertEqual(self.updater.dev_info, {'k1': 'v1'})
- def test_voting_updater_votes_for_highest_1(self):
- dev_infos = [
- {'k1': 'v1'},
- {'k1': 'v1'},
- {'k1': 'v2'},
- ]
- for dev_info in dev_infos:
- self.updater.update(dev_info)
- self.assertEqual(self.updater.dev_info, {'k1': 'v1'})
- def test_voting_updater_votes_for_highest_2(self):
- dev_infos = [
- {'k1': 'v2'},
- {'k1': 'v1'},
- {'k1': 'v1'},
- ]
- for dev_info in dev_infos:
- self.updater.update(dev_info)
- self.assertEqual(self.updater.dev_info, {'k1': 'v1'})
- class TestRemoveOutdatedIpDeviceUpdater(unittest.TestCase):
- def setUp(self):
- self.app = Mock()
- self.app.nat = 0
- self.dev_updater = RemoveOutdatedIpDeviceUpdater(self.app)
- @defer.inlineCallbacks
- def test_nat_disabled(self):
- device = {
- u'id': u'abc',
- }
- dev_info = {
- u'ip': u'1.1.1.1',
- }
- self.app.dev_find.return_value = defer.succeed([])
- yield self.dev_updater.update(device, dev_info, 'http', Mock())
- self.app.dev_find.assert_called_once_with({u'ip': u'1.1.1.1', u'id': {'$ne': u'abc'}})
- @defer.inlineCallbacks
- def test_nat_enabled(self):
- device = {
- u'id': u'abc',
- }
- dev_info = {
- u'ip': u'1.1.1.1',
- }
- self.app.nat = 1
- yield self.dev_updater.update(device, dev_info, 'http', Mock())
- self.assertFalse(self.app.dev_find.called)
- class TestRequestHelper(unittest.TestCase):
- def setUp(self):
- self.app = Mock()
- self.request = Mock()
- self.request_type = Mock()
- self.helper = _RequestHelper(self.app, self.request, self.request_type, 1)
- @defer.inlineCallbacks
- def test_extract_device_info_no_info(self):
- extractor = self._new_dev_info_extractor_mock(None)
- dev_info = yield self.helper.extract_device_info(extractor)
- extractor.extract.assert_called_once_with(self.request, self.request_type)
- assert_that(dev_info, equal_to({}))
- @defer.inlineCallbacks
- def test_extract_device_info_with_info(self):
- expected = {'a': 1}
- extractor = self._new_dev_info_extractor_mock(expected)
- dev_info = yield self.helper.extract_device_info(extractor)
- extractor.extract.assert_called_once_with(self.request, self.request_type)
- assert_that(dev_info, equal_to(expected))
- @defer.inlineCallbacks
- def test_retrieve_device_no_device(self):
- retriever = self._new_dev_retriever_mock(None)
- dev_info = {}
- device = yield self.helper.retrieve_device(retriever, dev_info)
- retriever.retrieve.assert_called_once_with(dev_info)
- assert_that(device, equal_to(None))
- @defer.inlineCallbacks
- def test_retrieve_device_with_device(self):
- expected = {u'id': u'a'}
- retriever = self._new_dev_retriever_mock(expected)
- dev_info = Mock()
- device = yield self.helper.retrieve_device(retriever, dev_info)
- retriever.retrieve.assert_called_once_with(dev_info)
- assert_that(device, equal_to(expected))
- @defer.inlineCallbacks
- def test_update_device_no_device(self):
- dev_updater = self._new_dev_updater_mock()
- device = None
- dev_info = {}
- yield self.helper.update_device(dev_updater, device, dev_info)
- self.assertFalse(dev_updater.update.called)
- @defer.inlineCallbacks
- def test_update_device_on_no_device_change_and_no_remote_state_update(self):
- dev_updater = self._new_dev_updater_mock()
- device = {u'id': u'a'}
- dev_info = {}
- yield self.helper.update_device(dev_updater, device, dev_info)
- dev_updater.update.assert_called_once_with(device, dev_info, self.request, self.request_type)
- self.assertFalse(self.app.cfg_retrieve.called)
- self.assertFalse(self.app.dev_update.called)
- @defer.inlineCallbacks
- def test_update_device_on_no_device_change_and_remote_state_update(self):
- dev_updater = self._new_dev_updater_mock()
- device = {
- u'id': u'a',
- u'configured': True,
- u'plugin': u'foo',
- u'config': u'a',
- }
- dev_info = {}
- self.request = Mock()
- self.request.path = '001122334455.cfg'
- self.request_type = 'http'
- plugin = Mock()
- plugin.get_remote_state_trigger_filename.return_value = '001122334455.cfg'
- self.app.pg_mgr.get.return_value = plugin
- self.app.cfg_retrieve.return_value = {
- u'raw_config': {
- u'sip_lines': {
- u'1': {
- u'username': 'foobar',
- }
- }
- }
- }
- self.helper = _RequestHelper(self.app, self.request, self.request_type, 1)
- yield self.helper.update_device(dev_updater, device, dev_info)
- dev_updater.update.assert_called_once_with(device, dev_info, self.request, self.request_type)
- self.app.cfg_retrieve.assert_called_once_with(device[u'config'])
- self.app.dev_update.assert_called_once_with(device)
- assert_that(device, has_entry(u'remote_state_sip_username', u'foobar'))
- @defer.inlineCallbacks
- def test_update_device_on_device_change_and_remote_state_update(self):
- dev_updater = self._new_dev_updater_mock({u'vendor': u'xivo'})
- device = {
- u'id': u'a',
- u'configured': True,
- u'plugin': u'foo',
- u'config': u'a',
- }
- dev_info = {}
- self.request = Mock()
- self.request.path = '001122334455.cfg'
- self.request_type = 'http'
- plugin = Mock()
- plugin.get_remote_state_trigger_filename.return_value = '001122334455.cfg'
- self.app.pg_mgr.get.return_value = plugin
- self.app.cfg_retrieve.return_value = {
- u'raw_config': {
- u'sip_lines': {
- u'1': {
- u'username': 'foobar',
- }
- }
- }
- }
- self.helper = _RequestHelper(self.app, self.request, self.request_type, 1)
- yield self.helper.update_device(dev_updater, device, dev_info)
- dev_updater.update.assert_called_once_with(device, dev_info, self.request, self.request_type)
- self.app.dev_update.assert_called_once_with(device, pre_update_hook=self.helper._pre_update_hook)
- def test_get_plugin_id_no_device(self):
- device = None
- pg_id = self.helper.get_plugin_id(device)
- assert_that(pg_id, equal_to(None))
- def test_get_plugin_id_no_plugin_key(self):
- device = {u'id': u'a'}
- pg_id = self.helper.get_plugin_id(device)
- assert_that(pg_id, equal_to(None))
- def test_get_plugin_id_ok(self):
- device = {u'id': u'a', u'plugin': u'xivo-foo'}
- pg_id = self.helper.get_plugin_id(device)
- assert_that(pg_id, equal_to(u'xivo-foo'))
- def _new_dev_info_extractor_mock(self, return_value):
- dev_info_extractor = Mock()
- dev_info_extractor.extract.return_value = defer.succeed(return_value)
- return dev_info_extractor
- def _new_dev_retriever_mock(self, return_value):
- dev_retriever = Mock()
- dev_retriever.retrieve.return_value = defer.succeed(return_value)
- return dev_retriever
- def _new_dev_updater_mock(self, device_update={}):
- dev_updater = Mock()
- def update_fun(device, dev_info, request, request_type):
- device.update(device_update)
- return defer.succeed(None)
- dev_updater.update.side_effect = update_fun
- return dev_updater
- class TestLogSensitiveRequest(unittest.TestCase):
- def setUp(self):
- self.ip = '169.254.0.1'
- self.filename = 'foobar.cfg'
- self.request_type = ident.REQUEST_TYPE_HTTP
- self.request = Mock()
- self.request.getClientIP.return_value = self.ip
- self.request.path = '/{}'.format(self.filename)
- self.plugin = Mock()
- @patch('provd.devices.ident.log_security_msg')
- def test_no_log_when_plugin_doesnt_have_method(self, mock_log_security_msg):
- del self.plugin.is_sensitive_filename
- ident._log_sensitive_request(self.plugin, self.request, self.request_type)
- assert_that(mock_log_security_msg.called, equal_to(False))
- @patch('provd.devices.ident.log_security_msg')
- def test_log_when_sensitive_filename(self, mock_log_security_msg):
- self.plugin.is_sensitive_filename.return_value = True
- ident._log_sensitive_request(self.plugin, self.request, self.request_type)
- self.plugin.is_sensitive_filename.assert_called_once_with(self.filename)
- mock_log_security_msg.assert_called_once_with('Sensitive file requested from %s: %s',
- self.ip, self.filename)