aodh/ceilometer/tests/storage/test_pymongo_base.py
ZhiQiang Fan 18eec72865 Fix hacking rule 302 and enable it
H302: import only modules.

Change-Id: I9f18abdc5f52f0a2ee3b8dbb7479dac8de3a0a7a
2014-06-19 16:46:58 +08:00

209 lines
8.7 KiB
Python

# 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.
"""Tests the mongodb and db2 common functionality
"""
import contextlib
import copy
import datetime
import mock
import pymongo
from ceilometer.openstack.common.gettextutils import _
from ceilometer.publisher import utils
from ceilometer import sample
from ceilometer.storage.mongo import utils as pymongo_utils
from ceilometer.tests import db as tests_db
from ceilometer.tests.storage import test_storage_scenarios
@tests_db.run_with('mongodb', 'db2')
class CompatibilityTest(test_storage_scenarios.DBTestBase,
tests_db.MixinTestsWithBackendScenarios):
def prepare_data(self):
def old_record_metering_data(self, data):
self.db.user.update(
{'_id': data['user_id']},
{'$addToSet': {'source': data['source'],
},
},
upsert=True,
)
self.db.project.update(
{'_id': data['project_id']},
{'$addToSet': {'source': data['source'],
},
},
upsert=True,
)
received_timestamp = datetime.datetime.utcnow()
self.db.resource.update(
{'_id': data['resource_id']},
{'$set': {'project_id': data['project_id'],
'user_id': data['user_id'],
# Current metadata being used and when it was
# last updated.
'timestamp': data['timestamp'],
'received_timestamp': received_timestamp,
'metadata': data['resource_metadata'],
'source': data['source'],
},
'$addToSet': {'meter': {'counter_name': data['counter_name'],
'counter_type': data['counter_type'],
},
},
},
upsert=True,
)
record = copy.copy(data)
self.db.meter.insert(record)
# Stubout with the old version DB schema, the one w/o 'counter_unit'
with mock.patch.object(self.conn, 'record_metering_data',
side_effect=old_record_metering_data):
self.counters = []
c = sample.Sample(
'volume.size',
'gauge',
'GiB',
5,
'user-id',
'project1',
'resource-id',
timestamp=datetime.datetime(2012, 9, 25, 10, 30),
resource_metadata={'display_name': 'test-volume',
'tag': 'self.counter',
},
source='test',
)
self.counters.append(c)
msg = utils.meter_message_from_counter(
c,
secret='not-so-secret')
self.conn.record_metering_data(self.conn, msg)
# Create the old format alarm with a dict instead of a
# array for matching_metadata
alarm = dict(alarm_id='0ld-4l3rt',
enabled=True,
name='old-alert',
description='old-alert',
timestamp=None,
meter_name='cpu',
user_id='me',
project_id='and-da-boys',
comparison_operator='lt',
threshold=36,
statistic='count',
evaluation_periods=1,
period=60,
state="insufficient data",
state_timestamp=None,
ok_actions=[],
alarm_actions=['http://nowhere/alarms'],
insufficient_data_actions=[],
repeat_actions=False,
matching_metadata={'key': 'value'})
self.conn.db.alarm.update(
{'alarm_id': alarm['alarm_id']},
{'$set': alarm},
upsert=True)
alarm['alarm_id'] = 'other-kind-of-0ld-4l3rt'
alarm['name'] = 'other-old-alaert'
alarm['matching_metadata'] = [{'key': 'key1', 'value': 'value1'},
{'key': 'key2', 'value': 'value2'}]
self.conn.db.alarm.update(
{'alarm_id': alarm['alarm_id']},
{'$set': alarm},
upsert=True)
def test_alarm_get_old_format_matching_metadata_dict(self):
old = list(self.conn.get_alarms(name='old-alert'))[0]
self.assertEqual('threshold', old.type)
self.assertEqual([{'field': 'key',
'op': 'eq',
'value': 'value',
'type': 'string'}],
old.rule['query'])
self.assertEqual(60, old.rule['period'])
self.assertEqual('cpu', old.rule['meter_name'])
self.assertEqual(1, old.rule['evaluation_periods'])
self.assertEqual('count', old.rule['statistic'])
self.assertEqual('lt', old.rule['comparison_operator'])
self.assertEqual(36, old.rule['threshold'])
def test_alarm_get_old_format_matching_metadata_array(self):
old = list(self.conn.get_alarms(name='other-old-alaert'))[0]
self.assertEqual('threshold', old.type)
self.assertEqual(sorted([{'field': 'key1',
'op': 'eq',
'value': 'value1',
'type': 'string'},
{'field': 'key2',
'op': 'eq',
'value': 'value2',
'type': 'string'}]),
sorted(old.rule['query']),)
self.assertEqual('cpu', old.rule['meter_name'])
self.assertEqual(60, old.rule['period'])
self.assertEqual(1, old.rule['evaluation_periods'])
self.assertEqual('count', old.rule['statistic'])
self.assertEqual('lt', old.rule['comparison_operator'])
self.assertEqual(36, old.rule['threshold'])
def test_counter_unit(self):
meters = list(self.conn.get_meters())
self.assertEqual(1, len(meters))
def test_mongodb_connect_raises_after_custom_number_of_attempts(self):
retry_interval = 13
max_retries = 37
self.CONF.set_override(
'retry_interval', retry_interval, group='database')
self.CONF.set_override(
'max_retries', max_retries, group='database')
# PyMongo is being used to connect even to DB2, but it only
# accepts URLs with the 'mongodb' scheme. This replacement is
# usually done in the DB2 connection implementation, but since
# we don't call that, we have to do it here.
self.CONF.set_override(
'connection', self.db_manager.url.replace('db2:', 'mongodb:', 1),
group='database')
pool = pymongo_utils.ConnectionPool()
with contextlib.nested(
mock.patch(
'pymongo.MongoClient',
side_effect=pymongo.errors.ConnectionFailure('foo')),
mock.patch.object(pymongo_utils.LOG, 'error'),
mock.patch.object(pymongo_utils.LOG, 'warn'),
mock.patch.object(pymongo_utils.time, 'sleep')
) as (MockMongo, MockLOGerror, MockLOGwarn, Mocksleep):
self.assertRaises(pymongo.errors.ConnectionFailure,
pool.connect, self.CONF.database.connection)
Mocksleep.assert_has_calls([mock.call(retry_interval)
for i in range(max_retries)])
MockLOGwarn.assert_any_call(
_('Unable to connect to the database server: %(errmsg)s.'
' Trying again in %(retry_interval)d seconds.') %
{'errmsg': 'foo',
'retry_interval': retry_interval})
MockLOGerror.assert_called_with(
_('Unable to connect to the database after '
'%(retries)d retries. Giving up.') %
{'retries': max_retries})