157 lines
7.3 KiB
Python
157 lines
7.3 KiB
Python
# All Rights Reserved.
|
|
#
|
|
# 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 neutron_lib import context
|
|
|
|
from neutron.agent import resource_cache
|
|
from neutron.api.rpc.callbacks import events as events_rpc
|
|
from neutron.callbacks import events
|
|
from neutron.callbacks import registry
|
|
from neutron.tests import base
|
|
|
|
|
|
class OVOLikeThing(object):
|
|
def __init__(self, id, revision_number=10, **kwargs):
|
|
self.id = id
|
|
self.fields = ['id', 'revision_number']
|
|
self.revision_number = revision_number
|
|
for k, v in kwargs.items():
|
|
self.fields.append(k)
|
|
setattr(self, k, v)
|
|
|
|
def to_dict(self):
|
|
return {f: getattr(self, f) for f in self.fields}
|
|
|
|
def get(self, k):
|
|
return getattr(self, k, None)
|
|
|
|
|
|
class RemoteResourceCacheTestCase(base.BaseTestCase):
|
|
def setUp(self):
|
|
super(RemoteResourceCacheTestCase, self).setUp()
|
|
rtypes = ['duck', 'goose']
|
|
self.goose = OVOLikeThing(1)
|
|
self.duck = OVOLikeThing(2)
|
|
self.ctx = context.get_admin_context()
|
|
self.rcache = resource_cache.RemoteResourceCache(rtypes)
|
|
self._pullmock = mock.patch.object(self.rcache, '_puller').start()
|
|
|
|
def test_get_resource_by_id(self):
|
|
self.rcache.record_resource_update(self.ctx, 'goose', self.goose)
|
|
self.assertEqual(self.goose,
|
|
self.rcache.get_resource_by_id('goose', 1))
|
|
self.assertIsNone(self.rcache.get_resource_by_id('goose', 2))
|
|
|
|
def test__flood_cache_for_query_pulls_once(self):
|
|
self.rcache._flood_cache_for_query('goose', id=66)
|
|
self._pullmock.bulk_pull.assert_called_once_with(
|
|
mock.ANY, 'goose', filter_kwargs={'id': 66})
|
|
self._pullmock.bulk_pull.reset_mock()
|
|
self.rcache._flood_cache_for_query('goose', id=66)
|
|
self.assertFalse(self._pullmock.called)
|
|
self.rcache._flood_cache_for_query('goose', id=67)
|
|
self._pullmock.bulk_pull.assert_called_once_with(
|
|
mock.ANY, 'goose', filter_kwargs={'id': 67})
|
|
|
|
def test_get_resources(self):
|
|
geese = [OVOLikeThing(3, size='large'), OVOLikeThing(5, size='medium'),
|
|
OVOLikeThing(4, size='large'), OVOLikeThing(6, size='small')]
|
|
for goose in geese:
|
|
self.rcache.record_resource_update(self.ctx, 'goose', goose)
|
|
is_large = {'size': 'large'}
|
|
is_small = {'size': 'small'}
|
|
self.assertItemsEqual([geese[0], geese[2]],
|
|
self.rcache.get_resources('goose', is_large))
|
|
self.assertItemsEqual([geese[3]],
|
|
self.rcache.get_resources('goose', is_small))
|
|
|
|
def test_match_resources_with_func(self):
|
|
geese = [OVOLikeThing(3, size='large'), OVOLikeThing(5, size='medium'),
|
|
OVOLikeThing(4, size='xlarge'), OVOLikeThing(6, size='small')]
|
|
for goose in geese:
|
|
self.rcache.record_resource_update(self.ctx, 'goose', goose)
|
|
has_large = lambda o: 'large' in o.size
|
|
self.assertItemsEqual([geese[0], geese[2]],
|
|
self.rcache.match_resources_with_func('goose',
|
|
has_large))
|
|
|
|
def test__is_stale(self):
|
|
goose = OVOLikeThing(3, size='large')
|
|
self.rcache.record_resource_update(self.ctx, 'goose', goose)
|
|
# same revision id is not considered stale
|
|
updated = OVOLikeThing(3, size='large')
|
|
self.assertFalse(self.rcache._is_stale('goose', updated))
|
|
updated.revision_number = 0
|
|
self.assertTrue(self.rcache._is_stale('goose', updated))
|
|
updated.revision_number = 200
|
|
self.assertFalse(self.rcache._is_stale('goose', updated))
|
|
# once deleted, all updates are stale
|
|
self.rcache.record_resource_delete(self.ctx, 'goose', 3)
|
|
self.assertTrue(self.rcache._is_stale('goose', updated))
|
|
|
|
def test_record_resource_update(self):
|
|
received_kw = []
|
|
receiver = lambda *a, **k: received_kw.append(k)
|
|
registry.subscribe(receiver, 'goose', events.AFTER_UPDATE)
|
|
self.rcache.record_resource_update(self.ctx, 'goose',
|
|
OVOLikeThing(3, size='large'))
|
|
self.assertEqual(1, len(received_kw))
|
|
self.assertIsNone(received_kw[0]['existing'])
|
|
# another update with no changed fields results in no callback
|
|
self.rcache.record_resource_update(self.ctx, 'goose',
|
|
OVOLikeThing(3, size='large',
|
|
revision_number=100))
|
|
self.assertEqual(1, len(received_kw))
|
|
self.rcache.record_resource_update(self.ctx, 'goose',
|
|
OVOLikeThing(3, size='small',
|
|
revision_number=101))
|
|
self.assertEqual(2, len(received_kw))
|
|
self.assertEqual('large', received_kw[1]['existing'].size)
|
|
self.assertEqual('small', received_kw[1]['updated'].size)
|
|
self.assertEqual(set(['size']), received_kw[1]['changed_fields'])
|
|
|
|
def test_record_resource_delete(self):
|
|
received_kw = []
|
|
receiver = lambda *a, **k: received_kw.append(k)
|
|
registry.subscribe(receiver, 'goose', events.AFTER_DELETE)
|
|
self.rcache.record_resource_update(self.ctx, 'goose',
|
|
OVOLikeThing(3, size='large'))
|
|
self.rcache.record_resource_delete(self.ctx, 'goose', 3)
|
|
self.assertEqual(1, len(received_kw))
|
|
self.assertEqual(3, received_kw[0]['existing'].id)
|
|
self.assertEqual(3, received_kw[0]['resource_id'])
|
|
# deletes of non-existing cache items are still honored
|
|
self.rcache.record_resource_delete(self.ctx, 'goose', 4)
|
|
self.assertEqual(2, len(received_kw))
|
|
self.assertIsNone(received_kw[1]['existing'])
|
|
self.assertEqual(4, received_kw[1]['resource_id'])
|
|
|
|
def test_resource_change_handler(self):
|
|
with mock.patch.object(resource_cache.RemoteResourceWatcher,
|
|
'_init_rpc_listeners'):
|
|
watch = resource_cache.RemoteResourceWatcher(self.rcache)
|
|
geese = [OVOLikeThing(3, size='large'), OVOLikeThing(5, size='medium'),
|
|
OVOLikeThing(4, size='large'), OVOLikeThing(6, size='small')]
|
|
watch.resource_change_handler(self.ctx, 'goose', geese,
|
|
events_rpc.UPDATED)
|
|
for goose in geese:
|
|
self.assertEqual(goose,
|
|
self.rcache.get_resource_by_id('goose', goose.id))
|
|
watch.resource_change_handler(self.ctx, 'goose', geese,
|
|
events_rpc.DELETED)
|
|
for goose in geese:
|
|
self.assertIsNone(
|
|
self.rcache.get_resource_by_id('goose', goose.id))
|