Fix generate_asn mask and add unit tests

Change-Id: I18776f026ba288a150e783e4102006e690572d6f
This commit is contained in:
Frode Nordahl 2018-05-09 11:09:53 +02:00
parent 1ff8ee74a1
commit 3eca0062fd
No known key found for this signature in database
GPG Key ID: 6A5D59A3BA48373F
8 changed files with 239 additions and 4 deletions

3
.stestr.conf Normal file
View File

@ -0,0 +1,3 @@
[DEFAULT]
test_path=./unit_tests
top_dir=./

View File

@ -2,3 +2,8 @@ name: bgp
summary: BGP interface
version: 1
repo: https://github.com/openstack-charmers/charm-interface-bgp.git
ignore:
- 'unit_tests'
- '.stestr.conf'
- 'test-requirements.txt'
- 'tox.ini'

View File

@ -45,16 +45,13 @@ class BGPEndpoint(reactive.Endpoint):
4 200 000 000 - 4 211 081 214
"""
asn_base = 4211081215
mask = netaddr.IPAddress('5.255.255.255')
mask = netaddr.IPAddress('4.255.255.255')
unit_ip = netaddr.IPAddress(
ch_core.hookenv.unit_get('private-address'))
masked_ip = unit_ip & mask
asn = asn_base + int(masked_ip)
# XXX: This assert should be removed from code and put in a unit test
assert asn <= 4294967294
return asn
def publish_info(self, asn=None, passive=False, bindings=None):

6
test-requirements.txt Normal file
View File

@ -0,0 +1,6 @@
# Lint and unit test requirements
flake8
os-testr>=0.4.1
charms.reactive
mock>=1.2
coverage>=3.6

23
tox.ini Normal file
View File

@ -0,0 +1,23 @@
[tox]
skipsdist = True
envlist = pep8,py35
[testenv]
setenv = VIRTUAL_ENV={envdir}
PYTHONHASHSEED=0
TERM=linux
install_command =
pip install {opts} {packages}
[testenv:py35]
basepython = python3
deps = -r{toxinidir}/test-requirements.txt
commands = ostestr {posargs}
[testenv:pep8]
basepython = python3
deps = -r{toxinidir}/test-requirements.txt
commands = flake8 {posargs} . unit_tests
[testenv:venv]
commands = {posargs}

87
unit_tests/__init__.py Normal file
View File

@ -0,0 +1,87 @@
# Copyright 2016 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 sys
import mock
# mock out some charmhelpers libraries as they have apt install side effects
apt_pkg = mock.MagicMock()
charmhelpers = mock.MagicMock()
sys.modules['apt_pkg'] = apt_pkg
sys.modules['charmhelpers'] = charmhelpers
sys.modules['charmhelpers.core'] = charmhelpers.core
sys.modules['charmhelpers.core.decorators'] = charmhelpers.core.decorators
sys.modules['charmhelpers.core.hookenv'] = charmhelpers.core.hookenv
sys.modules['charmhelpers.core.host'] = charmhelpers.core.host
sys.modules['charmhelpers.core.templating'] = charmhelpers.core.templating
sys.modules['charmhelpers.core.unitdata'] = charmhelpers.core.unitdata
sys.modules['charmhelpers.contrib'] = charmhelpers.contrib
sys.modules['charmhelpers.contrib.openstack'] = charmhelpers.contrib.openstack
sys.modules['charmhelpers.contrib.openstack.ha'] = (
charmhelpers.contrib.openstack.ha)
sys.modules['charmhelpers.contrib.openstack.utils'] = (
charmhelpers.contrib.openstack.utils)
sys.modules['charmhelpers.contrib.openstack.templating'] = (
charmhelpers.contrib.openstack.templating)
sys.modules['charmhelpers.contrib.openstack.context'] = (
charmhelpers.contrib.openstack.context)
sys.modules['charmhelpers.contrib.network'] = charmhelpers.contrib.network
sys.modules['charmhelpers.contrib.network.ip'] = (
charmhelpers.contrib.network.ip)
sys.modules['charmhelpers.fetch'] = charmhelpers.fetch
sys.modules['charmhelpers.cli'] = charmhelpers.cli
sys.modules['charmhelpers.contrib.hahelpers'] = charmhelpers.contrib.hahelpers
sys.modules['charmhelpers.contrib.hahelpers.cluster'] = (
charmhelpers.contrib.hahelpers.cluster)
# mock in the openstack releases so that the tests can run
# Note that these don't need to be maintained UNLESS new functionality is for
# later OpenStack releases.
charmhelpers.contrib.openstack.utils.OPENSTACK_RELEASES = (
'diablo',
'essex',
'folsom',
'grizzly',
'havana',
'icehouse',
'juno',
'kilo',
'liberty',
'mitaka',
'newton',
'ocata',
'pike',
)
def _fake_retry(num_retries, base_delay=0, exc_type=Exception):
def _retry_on_exception_inner_1(f):
def _retry_on_exception_inner_2(*args, **kwargs):
return f(*args, **kwargs)
return _retry_on_exception_inner_2
return _retry_on_exception_inner_1
mock.patch(
'charmhelpers.core.decorators.retry_on_exception',
_fake_retry).start()
def _fake_cached(f):
return f
mock.patch(
'charmhelpers.core.hookenv.cached',
_fake_cached).start()

View File

@ -0,0 +1,32 @@
# Copyright 2018 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 unit_tests.utils as ut_utils
import provides
class TestBGPProvides(ut_utils.BaseTestCase):
def test_generate_asn_min(self):
self.patch_object(provides, 'ch_core')
self.ch_core.hookenv.unit_get.return_value = '0.0.0.0'
endpoint = provides.BGPEndpoint('bgpserver')
asn = endpoint.generate_asn()
self.assertEqual(asn, 4211081215)
def test_generate_asn_max(self):
self.patch_object(provides, 'ch_core')
self.ch_core.hookenv.unit_get.return_value = '255.255.255.255'
endpoint = provides.BGPEndpoint('bgpserver')
asn = endpoint.generate_asn()
self.assertEqual(asn, 4294967294)

82
unit_tests/utils.py Normal file
View File

@ -0,0 +1,82 @@
# 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.
# Note that the unit_tests/__init__.py also mocks out two charmhelpers imports
# that have side effects that try to apt install modules:
# sys.modules['charmhelpers.contrib.openstack.utils'] = mock.MagicMock()
# sys.modules['charmhelpers.contrib.network.ip'] = mock.MagicMock()
import contextlib
import io
import mock
import unittest
@contextlib.contextmanager
def patch_open():
'''Patch open() to allow mocking both open() itself and the file that is
yielded.
Yields the mock for "open" and "file", respectively.'''
mock_open = mock.MagicMock(spec=open)
mock_file = mock.MagicMock(spec=io.FileIO)
@contextlib.contextmanager
def stub_open(*args, **kwargs):
mock_open(*args, **kwargs)
yield mock_file
with mock.patch('builtins.open', stub_open):
yield mock_open, mock_file
class BaseTestCase(unittest.TestCase):
def setUp(self):
self._patches = {}
self._patches_start = {}
def tearDown(self):
for k, v in self._patches.items():
v.stop()
setattr(self, k, None)
self._patches = None
self._patches_start = None
def patch_object(self, obj, attr, return_value=None, name=None, new=None,
**kwargs):
if name is None:
name = attr
if new is not None:
mocked = mock.patch.object(obj, attr, new=new, **kwargs)
else:
mocked = mock.patch.object(obj, attr, **kwargs)
self._patches[name] = mocked
started = mocked.start()
if new is None:
started.return_value = return_value
self._patches_start[name] = started
setattr(self, name, started)
def patch(self, item, return_value=None, name=None, new=None, **kwargs):
if name is None:
raise RuntimeError("Must pass 'name' to .patch()")
if new is not None:
mocked = mock.patch(item, new=new, **kwargs)
else:
mocked = mock.patch(item, **kwargs)
self._patches[name] = mocked
started = mocked.start()
if new is None:
started.return_value = return_value
self._patches_start[name] = started
setattr(self, name, started)