# Copyright 2019 Canonical Ltd # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import mock from lib import ovsdb import charms_openstack.test_utils as test_utils _hook_args = {} class TestOVSDBLib(test_utils.PatchHelper): def setUp(self): super().setUp() self.target = ovsdb.OVSDB('some-relation', []) self._patches = {} self._patches_start = {} def tearDown(self): self.target = None for k, v in self._patches.items(): v.stop() setattr(self, k, None) self._patches = None self._patches_start = None def patch_target(self, attr, return_value=None): mocked = mock.patch.object(self.target, attr) self._patches[attr] = mocked started = mocked.start() started.return_value = return_value self._patches_start[attr] = started setattr(self, attr, started) def patch_topublish(self): self.patch_target('_relations') relation = mock.MagicMock() to_publish = mock.PropertyMock() type(relation).to_publish = to_publish self._relations.__iter__.return_value = [relation] return relation.to_publish def pmock(self, return_value=None): p = mock.PropertyMock().return_value = return_value return p def test__format_addr(self): self.assertEquals('1.2.3.4', self.target._format_addr('1.2.3.4')) self.assertEquals( '[2001:db8::42]', self.target._format_addr('2001:db8::42')) with self.assertRaises(ValueError): self.target._format_addr('999.999.999.999') with self.assertRaises(ValueError): self.target._format_addr('2001:db8::g') def test__endpoint_local_bound_addr(self): relation = mock.MagicMock() relation.relation_id = 'some-endpoint:42' self.patch_target('_relations') self._relations.__iter__.return_value = [relation] self.patch_target('expand_name') self.expand_name.return_value = 'some-relation' self.patch_object(ovsdb.ch_core.hookenv, 'network_get') self.network_get.return_value = { 'bind-addresses': [ { 'macaddress': '', 'interfacename': '', 'addresses': [ { 'hostname': '', 'address': '42.42.42.42', 'cidr': '' }, ], }, ], 'egress-subnets': ['42.42.42.42/32'], 'ingress-addresses': ['42.42.42.42'], } self.assertEquals(self.target._endpoint_local_bound_addr(), '42.42.42.42') self.network_get.assert_called_once_with( 'some-relation', relation_id='some-endpoint:42') def test_cluster_local_addr(self): self.patch_target('_endpoint_local_bound_addr') self.target.cluster_local_addr self._endpoint_local_bound_addr.assert_called_once_with() def test__remote_addrs(self): relation = mock.MagicMock() relation.relation_id = 'some-endpoint:42' unit4 = mock.MagicMock() unit4.received = {'bound-address': '1.2.3.4'} unit6 = mock.MagicMock() unit6.received = {'bound-address': '2001:db8::42'} relation.units.__iter__.return_value = [unit4, unit6] self.patch_target('_relations') self._relations.__iter__.return_value = [relation] self.assertEquals( sorted(self.target._remote_addrs('bound-address')), ['1.2.3.4', '[2001:db8::42]']) def test_cluster_remote_addrs(self): self.patch_target('_remote_addrs') self.target.cluster_remote_addrs self._remote_addrs.assert_called_once_with('bound-address') def test_db_nb_port(self): self.assertEquals(self.target.db_nb_port, self.target.DB_NB_PORT) def test_db_sb_port(self): self.assertEquals(self.target.db_sb_port, self.target.DB_SB_PORT) def test_db_connection_strs(self): self.assertEquals( sorted(self.target.db_connection_strs(['a', 'b', 'c'], 123)), ['ssl:a:123', 'ssl:b:123', 'ssl:c:123']) self.assertEquals( sorted(self.target.db_connection_strs(['a', None, 'c', ''], 123)), ['ssl:a:123', 'ssl:c:123']) def test_db_nb_connection_strs(self): relation = mock.MagicMock() unit = mock.MagicMock() unit.received = {'bound-address': '1.2.3.4'} unit2 = mock.MagicMock() unit2.received = {'bound-address': '2.3.4.5'} relation.units.__iter__.return_value = [unit, unit2] self.patch_target('_relations') self._relations.__iter__.return_value = [relation] self.assertEquals( list(self.target.db_nb_connection_strs), ['ssl:1.2.3.4:6641', 'ssl:2.3.4.5:6641']) def test_db_sb_connection_strs(self): relation = mock.MagicMock() unit = mock.MagicMock() unit.received = {'bound-address': '1.2.3.4'} unit2 = mock.MagicMock() unit2.received = {'bound-address': '2.3.4.5'} relation.units.__iter__.return_value = [unit, unit2] self.patch_target('_relations') self._relations.__iter__.return_value = [relation] self.assertEquals( list(self.target.db_sb_connection_strs), ['ssl:1.2.3.4:6642', 'ssl:2.3.4.5:6642']) def test_expected_units_available(self): self.patch_object(ovsdb.ch_core.hookenv, 'expected_related_units') self.expected_related_units.return_value = [ 'unit/0', 'unit/1', 'unit/2'] self.assertEquals(self.target.expected_units_available(), False) relation = mock.MagicMock() relation.relation_id = 'some-endpoint:42' unit = mock.MagicMock() unit.received = {'bound-address': '1.2.3.4'} unit2 = mock.MagicMock() unit2.received = {'bound-address': '2.3.4.5'} unit3 = mock.MagicMock() unit3.received = {} relation.units.__iter__.return_value = [unit, unit2, unit3] self.patch_target('_relations') self._relations.__iter__.return_value = [relation] self.target._all_joined_units = [ 'unit/0', 'unit/1', 'unit/2'] self.assertEquals(self.target.expected_units_available(), False) unit3.received = {'bound-address': '6.7.8.9'} self.assertEquals(self.target.expected_units_available(), True) # when related to ovn-central through CMR expected_related_units # will always be 1. check that this works self.expected_related_units.return_value = [ 'controller:user/offer.name', ] self.target._all_joined_units = [ 'unit/0', 'unit/1'] self.assertEquals(self.target.expected_units_available(), False) self.target._all_joined_units = [ 'unit/0', 'unit/1', 'unit/2'] self.assertEquals(self.target.expected_units_available(), True) def test_publish_cluster_local_addr(self): to_publish = self.patch_topublish() self.target.publish_cluster_local_addr() to_publish.__setitem__.assert_called_once_with('bound-address', None) def test_joined(self): self.patch_object(ovsdb.reactive, 'set_flag') self.target.joined() self.set_flag.assert_called_once_with('some-relation.connected') def test_broken(self): self.patch_object(ovsdb.reactive, 'clear_flag') self.target.broken() self.clear_flag.assert_has_calls([ mock.call('some-relation.available'), mock.call('some-relation.connected'), ])